@henriquehbr/tagit
Version:
A git tag bumper that strictly follows semver
121 lines (96 loc) • 3.52 kB
JavaScript
#!/usr/bin/env node
import minimist from "minimist"
import semverInc from "semver/functions/inc.js"
import semverMajor from "semver/functions/major.js"
import showHelp from "./showHelp.js"
import showVersion from "./showVersion.js"
import getLatestGitTag from "./getLatestGitTag.js"
import getCommitsSinceTag from "./getCommitsSinceTag.js"
import validateCommits from "./validateCommits.js"
import isVersionPreRelease from "./isVersionPreRelease.js"
const argsWithoutExecutable = process.argv.slice(2)
const args = minimist(argsWithoutExecutable)
const flags = {
p: args.p,
f: args.f,
forceVersion: args.forceVersion,
v: args.v,
version: args.version,
h: args.h === true,
help: args.help === true
}
const knownFlags = Object.keys(flags)
const passedFlags = Object.keys(args).filter(flag => flag !== "_")
const unknownFlags = passedFlags.filter(flag => !knownFlags.includes(flag))
const hasUnknownFlags = unknownFlags.length > 0
// defines who will be displayed in case both "-h" and "-v" are passed
const [shouldShowHelpOrVersion] = passedFlags.filter(flag =>
/^(h(elp)?|v(ersion)?)$/.test(flag)
)
const shouldShowHelp =
(flags.h || flags.help || hasUnknownFlags) && shouldShowHelpOrVersion === "h"
if (shouldShowHelp) {
if (hasUnknownFlags) {
const formattedUnknownFlags = unknownFlags.join(", ")
throw new Error(`unknown option: ${formattedUnknownFlags}\n`)
}
showHelp()
process.exit(0)
}
const shouldShowVersion =
(flags.v || flags.version) && shouldShowHelpOrVersion === "v"
if (shouldShowVersion) {
showVersion()
process.exit(0)
}
const forcedVersion = args.f || args.forcedVersion
if (forcedVersion) {
const prefixedForcedVersion = "v" + forcedVersion
console.log(prefixedForcedVersion)
process.exit(0)
}
const latestGitTag = getLatestGitTag()
if (!latestGitTag) {
console.log("v0.1.0")
process.exit(0)
}
const commits = getCommitsSinceTag(latestGitTag)
const commitArray = commits.split("\n")
const validCommits = validateCommits(commitArray)
const hasCommitsSinceLastTag = validCommits.length > 0
if (!hasCommitsSinceLastTag) {
throw new Error("no elligible commits for a release")
}
const validPreReleaseTypes = ["alpha", "beta", "rc"]
const shouldBecomePreRelease = validPreReleaseTypes.includes(args.p)
const shouldIncrementPreRelease =
!shouldBecomePreRelease && isVersionPreRelease(latestGitTag)
if (shouldIncrementPreRelease) {
const isLeavingPreRelease = args.p === "stable"
const bumpType = isLeavingPreRelease ? "patch" : "prerelease"
const newVersion = semverInc(latestGitTag, bumpType, args.p)
const prefixedNewVersion = "v" + newVersion
console.log(prefixedNewVersion)
process.exit(0)
}
const breakingChangesCommitRegex = /^[a-z]+(\([\S]+\))?!: /
const featureCommitRegex = /^feat(\([\S]+\))?: /
const shouldBumpMajor = validCommits.some(commit =>
breakingChangesCommitRegex.test(commit)
)
const shouldBumpMinor = validCommits.some(commit =>
featureCommitRegex.test(commit)
)
const isVersionStable = semverMajor(latestGitTag) !== 0
const bumpTypes = {
major: shouldBumpMajor && isVersionStable,
minor: shouldBumpMinor || (shouldBumpMajor && !isVersionStable),
patch: true
}
const iterableBumpTypes = Object.entries(bumpTypes)
const [bumpType] = iterableBumpTypes.find(([_, bumpCondition]) => bumpCondition)
const possiblyPrefixedBumpType =
(shouldBecomePreRelease ? "pre" : "") + bumpType
const newVersion = semverInc(latestGitTag, possiblyPrefixedBumpType, args.p)
const prefixedNewVersion = "v" + newVersion
console.log(prefixedNewVersion)