Skip to content

Instantly share code, notes, and snippets.

@AlbertoBarrago
Created March 13, 2026 14:21
Show Gist options
  • Select an option

  • Save AlbertoBarrago/fedd6d8e60c7c347c8742867b7a48600 to your computer and use it in GitHub Desktop.

Select an option

Save AlbertoBarrago/fedd6d8e60c7c347c8742867b7a48600 to your computer and use it in GitHub Desktop.
Script for automate release on node bump command.
#!/usr/bin/env node
/**
* Usage summary:
* npm run bump # auto-detect from commits → commit + tag
* npm run bump patch # force patch → commit + tag
* npm run bump minor # force minor → commit + tag
* npm run bump major # force major → commit + tag
* npm run bump 1.5.0 # exact version → commit + tag
*
* how to use: "bump": "node scripts/bump-version.js"
*/
// biome-ignore assist/source/organizeImports: Needed for our build purpose used internally
import { readFileSync, writeFileSync } from 'fs';
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
import { execSync } from 'child_process';
const __dir = dirname(fileURLToPath(import.meta.url));
const root = resolve(__dir, '..');
const pkgPath = resolve(root, 'package.json');
const indexPath = resolve(root, 'index.html');
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
const current = pkg.version;
const [major, minor, patch] = current.split('.').map(Number);
const arg = process.argv[2];
/**
* Detect a bump type from conventional commits since the last git tag.
* - feat! / BREAKING CHANGE → major
* - feat → minor
* - anything else → patch
*/
function detectBumpType() {
let lastTag;
try {
lastTag = execSync('git describe --tags --abbrev=0', { cwd: root, stdio: ['pipe', 'pipe', 'pipe'] })
.toString()
.trim();
} catch {
// No tags yet — default to patch
return 'patch';
}
let log;
try {
log = execSync(`git log ${lastTag}..HEAD --pretty=format:"%s%n%b"`, {
cwd: root,
stdio: ['pipe', 'pipe', 'pipe'],
}).toString();
} catch {
return 'patch';
}
if (/BREAKING[- ]CHANGE|^.+!:/m.test(log)) return 'major';
if (/^feat(\(.+\))?:/m.test(log)) return 'minor';
return 'patch';
}
let next;
if (!arg) {
const detected = detectBumpType();
console.log(`Auto-detected bump type: ${detected}`);
switch (detected) {
case 'major':
next = `${major + 1}.0.0`;
break;
case 'minor':
next = `${major}.${minor + 1}.0`;
break;
default:
next = `${major}.${minor}.${patch + 1}`;
break;
}
} else if (/^\d+\.\d+\.\d+$/.test(arg)) {
next = arg;
} else {
switch (arg) {
case 'major':
next = `${major + 1}.0.0`;
break;
case 'minor':
next = `${major}.${minor + 1}.0`;
break;
case 'patch':
next = `${major}.${minor}.${patch + 1}`;
break;
default:
console.error(`Unknown argument: "${arg}". Use major | minor | patch | x.y.z`);
process.exit(1);
}
}
// Update package.json
pkg.version = next;
writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
// Update index.html meta tag
const html = readFileSync(indexPath, 'utf8');
const updated = html.replace(/(<meta\s+name="app-version"\s+content=")[^"]*(")/, `$1${next}$2`);
if (updated === html) {
console.warn('Warning: app-version meta tag not found in index.html');
} else {
writeFileSync(indexPath, updated);
}
console.log(`${current}${next}`);
// Git commit + tag
const tag = `v${next}`;
try {
execSync(`git add "${pkgPath}" "${indexPath}"`, { cwd: root, stdio: 'inherit' });
execSync(`git commit -m "${tag}"`, { cwd: root, stdio: 'inherit' });
execSync(`git tag ${tag}`, { cwd: root, stdio: 'inherit' });
console.log(`Tagged: ${tag}`);
} catch (err) {
console.error('Git commit/tag failed. Files were updated but no commit/tag was created.');
console.error(err.message);
process.exit(1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment