Last active
September 20, 2020 06:35
-
-
Save RaschidJFR/f915fdf6c1d6479e24085c92ac6b127b to your computer and use it in GitHub Desktop.
Print version information in different formats from `git describe`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
// Use this script to parse version tags from git describe | |
// Use `node version -h` for help | |
const { spawn, exec } = require('child_process'); | |
const program = require('commander'); | |
program | |
.name('node version') | |
.usage('[--describe | --full | --numeric | --prerelease] [--tag <version.tag>]') | |
.option('-b, --build', 'Output describe info (without version): <PRE-RELEASE-PHASE(2)>.<PRE-RELEASE-VERSION(2)>.<COMMITS(2)>') | |
.option('-d, --describe', 'Similar format as doing `git describe --tags`: <VERSION>-<PRE-RELEASE>-<COMMITS>-<HASH>') | |
.option('-f, --full', 'Add prerelease info to output: <VERSION>-<PRE-RELEASE>') | |
.option('-n, --numeric', 'Encode version info into numeric format for Android: <VERSION(6)><PRE-RELEASE-PHASE(1)><PRE-RELEASE-VERSION(1)><COMMITS(2)>') | |
.option('-p, --prerelease', 'Output prerelease info instead of version') | |
.option('-r, --branch-release', 'Get the version string from current release/* branch. <COMMITS> will be counted from the last parent commit.') | |
.option('-t, --tag <string>', 'Use this version tag instead of the one from git describe'); | |
program.parse(process.argv); | |
function getReleaseFromBranch() { | |
return new Promise((resolve) => { | |
const child = spawn('git', ['rev-parse', '--abbrev-ref', 'HEAD']); | |
child.stdout.on('data', data => { | |
const branchName = data.toString(); | |
const v = branchName.match(/(release|hotfix)\/(\d+\.\d+(\.\d+)*.*)/); | |
resolve(v && v[2]); | |
}); | |
}); | |
} | |
/** | |
* @param {string} prerelease In the format `phase.version`. E.g.: `beta.2` | |
*/ | |
function encodePrerelease(prerelease) { | |
// 1 digit for prerelease version + 1 for prerelease phase | |
let numPrerelease = '0'; // 1 digit | |
let numPhase = '4'; | |
if (prerelease) { | |
numPrerelease = prerelease.split('.')[1] || '0'; | |
const prSegments = prerelease.split('.'); | |
let phase = prSegments.shift(); | |
if (/[a-z]+\d+/.test(phase)) { | |
const a = phase.match(/[a-z]+/)[0]; | |
const n = phase.match(/[\d]+/)[0]; | |
phase = a; | |
numPrerelease = n; | |
} | |
// Max number for versionCode is `2100000000` http://tiny.cc/f94uhz | |
numPhase = phase === 'dev' || phase === 'next' || phase === 'd' ? '0' | |
: phase === 'alpha' || phase === 'a' ? '1' | |
: phase === 'beta' || phase === 'b' ? '2' | |
: phase === 'rc' || phase === 'r' ? '3' | |
: '4'; | |
} | |
return { | |
phase: numPhase, | |
version: numPrerelease | |
}; | |
} | |
async function parseTag(tag, commits) { | |
const segments = tag.trim().toLowerCase().split('-'); | |
const version = segments[0]; | |
let prerelease = segments.length >= 2 ? segments[1] : ''; | |
prerelease = prerelease ? prerelease.match(/[a-z]+(\.?\d+)?/) && prerelease.match(/[a-z]+(\.?\d+)?/)[0] : null; | |
if (!commits) { | |
commits = segments.length === 3 ? | |
Number(segments[2]) ? segments[2] : segments[1] | |
: segments.length === 2 ? segments[1] | |
: segments.length > 3 ? segments[segments.length - 2] | |
: null; | |
commits = commits ? commits.match(/^\d+$/) && commits.match(/^\d+$/)[0] : null; | |
} | |
// const hash = segments.length === 4 ? segments[3].trim() : null; | |
let output = version; | |
if (program.prerelease) { | |
output = prerelease; | |
} else if (program.full) { | |
output = `${version}-${prerelease}`; | |
} else if (program.describe) { | |
output = tag + (program.branchRelease ? `-${commits}` : ''); | |
} else if (program.build) { | |
const { phase, version } = encodePrerelease(prerelease); | |
output = `${phase}.${version}.${commits || 0}`; | |
} else if (program.numeric) { | |
// 6 digits for version | |
let numVersion = version.split('.') | |
.map(n => | |
n[1] ? n : '0' + n) | |
.join(''); | |
for (let i = numVersion.length; i < 6; i++) { | |
numVersion += '0'; | |
} | |
const { phase: numPhase, version: numPrerelease } = encodePrerelease(prerelease); | |
// 2 digits for commits | |
let numCommits = '00'; | |
if (commits) { | |
numCommits = ''; | |
for (let i = commits.length; i < 2; i++) { | |
numCommits += '0'; | |
} | |
numCommits += commits; | |
} | |
numCommits = Number(numCommits) > 99 ? '99' : numCommits; // Clamp to 99 | |
// <VERSION(6)><PRE-RELEASE-PHASE(1)><PRE-RELEASE-VERSION(1)><COMMITS(2)> | |
output = `${numVersion}${numPhase}${numPrerelease}${numCommits}`; | |
} | |
output = output.split('-').filter(s => !!s && s !== 'null').join('-'); | |
console.log(output); | |
} | |
const t = (program.tag ? 1 : 0) + (program.branchRelease ? 1 : 0); | |
if (t > 1) { | |
console.error('Error: options [--tag --branch-release] cannot be combined'); | |
process.exit(1); | |
} | |
if (program.tag) { | |
parseTag(program.tag); | |
} else { | |
if (program.branchRelease) { | |
exec('git merge-base HEAD master', (_err, strMergeBase, _stderr) => { | |
if (_err) throw new Error(_err); | |
exec(`git log ${strMergeBase.trim()}..HEAD --oneline | wc -l`, (_err, data, _stderr) => { | |
if (_err) throw new Error(_err); | |
const commitCount = data.trim(); | |
getReleaseFromBranch().then(version => { | |
if (!version) { | |
console.error('This is not a release/ branch'); | |
process.exit(1); | |
} | |
version = version.replace(/-[!\da-zA-Z\.]+$/, '').concat('-next'); | |
parseTag(version, commitCount); | |
}); | |
}); | |
}); | |
} else { | |
const child = spawn('git', ['describe', '--tags']); | |
child.stdout.on('data', data => { | |
const tags = data.toString(); | |
parseTag(tags); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment