Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor pseudo version handling #916

Merged
merged 3 commits into from
Jul 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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