Skip to content

Commit

Permalink
Refactor pseudo version handling (#916)
Browse files Browse the repository at this point in the history
  • Loading branch information
raineorshine authored Jul 2, 2021
1 parent 857b825 commit de041de
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 18 deletions.
2 changes: 1 addition & 1 deletion lib/package-managers/gitTags.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const getSortedVersions = async (name, declaration, options) => {

// eslint-disable-next-line fp/no-mutating-methods
const tags = [...tagMap.keys()]
.map(tag => versionUtil.isSimpleVersion(tag) ? tag + '.0.0' : tag)
.map(versionUtil.fixPseudoVersion)
// do not pass semver.valid reference directly since the mapping index will be interpreted as the loose option
// https://github.com/npm/node-semver#functions
.filter(tag => semver.valid(tag))
Expand Down
55 changes: 45 additions & 10 deletions lib/version-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,48 @@ function isPre(version) {
}

/** Checks if a string is a simple version in the format "v1". */
const isSimpleVersion = s => /^[vV]?\d+$/.test(s)
const isMissingMinorAndPatch = s => /^[vV]?\d+$/.test(s)

/** Checks if a version string is missing its match component, e.g. "1.0". */
const isMissingPatch = s => /^[vV]?\d+\.\d+$/.test(s)

/** Removes a leading 'v' or 'V' from a pseudo version.. */
const fixLeadingV = s => s.replace(/^[vV]/, '')

/** Converts a pseudo version that is missing its minor and patch components into a valid semver version. NOOP for valid semver versions. */
const fixMissingMinorAndPatch = s => isMissingMinorAndPatch(s) ? s + '.0.0' : s

/** Converts a pseudo version that is missing its patch component into a valid semver version. NOOP for valid semver versions. */
const fixMissingPatch = s => isMissingPatch(s) ? s + '.0' : s

/** Converts a pseudo version into a valid semver version. NOOP for valid semver versions. */
const fixPseudoVersion = _.flow(fixLeadingV, fixMissingMinorAndPatch, fixMissingPatch)

/** Reverts a valid semver version to a pseudo version that is missing its minor and patch components. NOOP If the original version was a valid semver version. */
const revertMissingMinorAndPatch = _.curry((current, latest) =>
isMissingMinorAndPatch(current)
? latest.slice(0, latest.length - '.0.0'.length)
: latest)

/** Reverts a valid semver version to a pseudo version that is missing its patch components. NOOP If the original version was a valid semver version. */
const revertMissingPatch = _.curry((current, latest) =>
isMissingPatch(current)
? latest.slice(0, latest.length - '.0'.length)
: latest)

/** Reverts a valid semver version to a pseudo version with a leading 'v'. NOOP If the original version was a valid semver version. */
const revertLeadingV = _.curry((current, latest) =>
v(current)
? v(current) + latest
: latest)

/** Reverts a valid semver version to a pseudo version. NOOP If the original version was a valid semver version. */
const revertPseudoVersion = (current, latest) =>
_.flow(
revertLeadingV(current),
revertMissingMinorAndPatch(current),
revertMissingPatch(current)
)(latest)

/**
* Returns 'v' if the string starts with a v, otherwise returns empty string.
Expand Down Expand Up @@ -383,14 +424,7 @@ function upgradeDependencyDeclaration(declaration, latestVersion, options = {})
const upgradeGithubUrl = (declaration, upgraded) => {
const tag = decodeURIComponent(parseGithubUrl(declaration).branch)
.replace(/^semver:/, '')
// if the tag does not start with "v", remove it from upgraded
const upgradedNormalized = !tag.startsWith('v') && upgraded.startsWith('v')
? upgraded.slice(1)
: upgraded
const upgradedWithSimpleStripped = isSimpleVersion(tag)
? upgradedNormalized.replace('.0.0', '')
: upgradedNormalized
return declaration.replace(tag, upgradeDependencyDeclaration(tag, upgradedWithSimpleStripped))
return declaration.replace(tag, upgradeDependencyDeclaration(tag, revertPseudoVersion(tag, upgraded)))
}

module.exports = {
Expand All @@ -401,8 +435,9 @@ module.exports = {
getPrecision,
setPrecision,
addWildCard,
fixPseudoVersion,
revertPseudoVersion,
isPre,
isSimpleVersion,
isWildCard,
isWildPart,
colorizeDiff,
Expand Down
16 changes: 10 additions & 6 deletions lib/versionmanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,21 @@ function isUpgradeable(current, latest) {
}

const version = versionUtil.stringify(range)
const latestNormalized = versionUtil.isSimpleVersion(latest)
? latest.replace('v', '') + '.0.0'
: latest

// allow upgrading of pseudo versions such as "v1" or "1.0"
const latestNormalized = versionUtil.fixPseudoVersion(latest)

const isValidCurrent = Boolean(semver.validRange(version))
const isValidLatest = Boolean(semver.valid(latestNormalized))

// make sure it is a valid range
// not upgradeable if the latest version satisfies the current range
// not upgradeable if the specified version is newer than the latest (indicating a prerelease version)
// NOTE: When "<" is specified with a single digit version, e.g. "<7", and has the same major version as the latest, e.g. "7", isSatisfied(latest, version) will return true since it ignores the "<". In this case, test the original range (current) rather than the versionUtil output (version).
return Boolean(semver.validRange(version)) &&
!isSatisfied(latestNormalized, range.operator === '<' ? current : version) &&
!semver.ltr(latestNormalized, version)
return isValidCurrent &&
isValidLatest &&
!isSatisfied(latestNormalized, range.operator === '<' ? current : version) &&
!semver.ltr(latestNormalized, version)
}

/**
Expand Down
2 changes: 1 addition & 1 deletion test/versionmanager.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ describe('versionmanager', () => {

it('upgrade simple, non-semver versions', () => {
vm.upgradeDependencies({ foo: '1' }, { foo: '2' }).should.eql({ foo: '2' })
vm.upgradeDependencies({ mongodb: '0.5' }, { mongodb: '1.4.30' }).should.eql({ mongodb: '1.4' })
vm.upgradeDependencies({ foo: '1.0' }, { foo: '1.1' }).should.eql({ foo: '1.1' })
vm.upgradeDependencies({ 'ncu-test-simple-tag': 'v1' }, { 'ncu-test-simple-tag': 'v3' }).should.eql({ 'ncu-test-simple-tag': 'v3' })
})

Expand Down

0 comments on commit de041de

Please sign in to comment.