checkout/src/git-version.ts
AuroraAeon 72ca3d5f64 compare an explicit patch of zero against the minimum version
GitVersion.checkMinimum guarded the patch comparison with a truthiness check
on `this.patch`, so a version whose patch component was explicitly zero was
treated as if the patch were unspecified and the comparison was skipped
entirely. That made `new GitVersion('4.5.0').checkMinimum(new GitVersion('4.5.1'))`
return true.

Compare the patch only when it was actually specified, distinguishing an
explicit zero from an unspecified one. A two-part version such as "2.28" still
leaves patch as NaN and continues to satisfy any patch of that minor version,
which is the behavior the existing tests rely on.

* compare an explicit patch of zero against the minimum version
* add regression coverage for an explicit patch of zero
* rebuild dist
2026-09-22 19:04:54 +08:00

82 lines
2.1 KiB
TypeScript

export class GitVersion {
private readonly major: number = NaN
private readonly minor: number = NaN
private readonly patch: number = NaN
/**
* Used for comparing the version of git and git-lfs against the minimum required version
* @param version the version string, e.g. 1.2 or 1.2.3
*/
constructor(version?: string) {
if (version) {
const match = version.match(/^(\d+)\.(\d+)(\.(\d+))?$/)
if (match) {
this.major = Number(match[1])
this.minor = Number(match[2])
if (match[4]) {
this.patch = Number(match[4])
}
}
}
}
/**
* Compares the instance against a minimum required version
* @param minimum Minimum version
*/
checkMinimum(minimum: GitVersion): boolean {
if (!minimum.isValid()) {
throw new Error('Arg minimum is not a valid version')
}
// Major is insufficient
if (this.major < minimum.major) {
return false
}
// Major is equal
if (this.major === minimum.major) {
// Minor is insufficient
if (this.minor < minimum.minor) {
return false
}
// Minor is equal
if (this.minor === minimum.minor) {
// Patch is insufficient. The patch component is only compared when it
// was explicitly specified: an instance built from a two-part version
// (e.g. "2.28") leaves patch as NaN, which is treated as satisfying any
// patch of that minor version. An explicit zero must not be mistaken for
// an unspecified value, because 0 is falsy.
if (!Number.isNaN(this.patch) && this.patch < (minimum.patch || 0)) {
return false
}
}
}
return true
}
/**
* Indicates whether the instance was constructed from a valid version string
*/
isValid(): boolean {
return !isNaN(this.major)
}
/**
* Returns the version as a string, e.g. 1.2 or 1.2.3
*/
toString(): string {
let result = ''
if (this.isValid()) {
result = `${this.major}.${this.minor}`
if (!isNaN(this.patch)) {
result += `.${this.patch}`
}
}
return result
}
}