From d9146fe050bd2dfe558ad8ceee9cc1810fda20f6 Mon Sep 17 00:00:00 2001 From: Raine Revere Date: Fri, 2 Jul 2021 07:26:52 -0600 Subject: [PATCH 1/3] Upgrade pseudo version numbers that are missing a patch. --- lib/version-util.js | 4 ++++ lib/versionmanager.js | 12 +++++++++--- test/versionmanager.test.js | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/version-util.js b/lib/version-util.js index 03904b9c..543f48e4 100644 --- a/lib/version-util.js +++ b/lib/version-util.js @@ -234,6 +234,9 @@ function isPre(version) { /** Checks if a string is a simple version in the format "v1". */ const isSimpleVersion = s => /^[vV]?\d+$/.test(s) +/** Checks if a version string is missing its match component, e.g. "1.0". */ +const isMissingPatch = s => /^\d+\.\d+$/.test(s) + /** * Returns 'v' if the string starts with a v, otherwise returns empty string. * @@ -401,6 +404,7 @@ module.exports = { getPrecision, setPrecision, addWildCard, + isMissingPatch, isPre, isSimpleVersion, isWildCard, diff --git a/lib/versionmanager.js b/lib/versionmanager.js index cf3bb762..0b39ab07 100644 --- a/lib/versionmanager.js +++ b/lib/versionmanager.js @@ -108,15 +108,21 @@ function isUpgradeable(current, latest) { } const version = versionUtil.stringify(range) - const latestNormalized = versionUtil.isSimpleVersion(latest) - ? latest.replace('v', '') + '.0.0' + + // allow upgrading of pseudo versions such as "v1" or "1.0" + const latestNormalized = versionUtil.isSimpleVersion(latest) ? latest.replace('v', '') + '.0.0' + : versionUtil.isMissingPatch(latest) ? latest + '.0' : 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)) && + return isValidCurrent && + isValidLatest && !isSatisfied(latestNormalized, range.operator === '<' ? current : version) && !semver.ltr(latestNormalized, version) } diff --git a/test/versionmanager.test.js b/test/versionmanager.test.js index 613f2722..2d596abc 100644 --- a/test/versionmanager.test.js +++ b/test/versionmanager.test.js @@ -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' }) }) From 1235a8c0815ccff121b256590ef986a093be2373 Mon Sep 17 00:00:00 2001 From: Raine Revere Date: Fri, 2 Jul 2021 07:29:45 -0600 Subject: [PATCH 2/3] Rename isSimpleVersion -> isMissingMinorAndPatch. --- lib/package-managers/gitTags.js | 2 +- lib/version-util.js | 8 ++++---- lib/versionmanager.js | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/package-managers/gitTags.js b/lib/package-managers/gitTags.js index bf487272..266008cb 100644 --- a/lib/package-managers/gitTags.js +++ b/lib/package-managers/gitTags.js @@ -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(tag => versionUtil.isMissingMinorAndPatch(tag) ? tag + '.0.0' : tag) // 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)) diff --git a/lib/version-util.js b/lib/version-util.js index 543f48e4..2a41daa7 100644 --- a/lib/version-util.js +++ b/lib/version-util.js @@ -232,10 +232,10 @@ 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 => /^\d+\.\d+$/.test(s) +const isMissingPatch = s => /^[vV]?\d+\.\d+$/.test(s) /** * Returns 'v' if the string starts with a v, otherwise returns empty string. @@ -390,7 +390,7 @@ const upgradeGithubUrl = (declaration, upgraded) => { const upgradedNormalized = !tag.startsWith('v') && upgraded.startsWith('v') ? upgraded.slice(1) : upgraded - const upgradedWithSimpleStripped = isSimpleVersion(tag) + const upgradedWithSimpleStripped = isMissingMinorAndPatch(tag) ? upgradedNormalized.replace('.0.0', '') : upgradedNormalized return declaration.replace(tag, upgradeDependencyDeclaration(tag, upgradedWithSimpleStripped)) @@ -406,7 +406,7 @@ module.exports = { addWildCard, isMissingPatch, isPre, - isSimpleVersion, + isMissingMinorAndPatch, isWildCard, isWildPart, colorizeDiff, diff --git a/lib/versionmanager.js b/lib/versionmanager.js index 0b39ab07..c859e66a 100644 --- a/lib/versionmanager.js +++ b/lib/versionmanager.js @@ -110,7 +110,7 @@ function isUpgradeable(current, latest) { const version = versionUtil.stringify(range) // allow upgrading of pseudo versions such as "v1" or "1.0" - const latestNormalized = versionUtil.isSimpleVersion(latest) ? latest.replace('v', '') + '.0.0' + const latestNormalized = versionUtil.isMissingMinorAndPatch(latest) ? latest.replace('v', '') + '.0.0' : versionUtil.isMissingPatch(latest) ? latest + '.0' : latest From cc6df8f93a2e96f41f5bdcf28150e5f4a137a37d Mon Sep 17 00:00:00 2001 From: Raine Revere Date: Fri, 2 Jul 2021 08:04:17 -0600 Subject: [PATCH 3/3] Refactor pseudo version handling. --- lib/package-managers/gitTags.js | 2 +- lib/version-util.js | 51 ++++++++++++++++++++++++++------- lib/versionmanager.js | 10 +++---- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/lib/package-managers/gitTags.js b/lib/package-managers/gitTags.js index 266008cb..e4e999c5 100644 --- a/lib/package-managers/gitTags.js +++ b/lib/package-managers/gitTags.js @@ -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.isMissingMinorAndPatch(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)) diff --git a/lib/version-util.js b/lib/version-util.js index 2a41daa7..deb1735d 100644 --- a/lib/version-util.js +++ b/lib/version-util.js @@ -237,6 +237,44 @@ 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. * @@ -386,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 = isMissingMinorAndPatch(tag) - ? upgradedNormalized.replace('.0.0', '') - : upgradedNormalized - return declaration.replace(tag, upgradeDependencyDeclaration(tag, upgradedWithSimpleStripped)) + return declaration.replace(tag, upgradeDependencyDeclaration(tag, revertPseudoVersion(tag, upgraded))) } module.exports = { @@ -404,9 +435,9 @@ module.exports = { getPrecision, setPrecision, addWildCard, - isMissingPatch, + fixPseudoVersion, + revertPseudoVersion, isPre, - isMissingMinorAndPatch, isWildCard, isWildPart, colorizeDiff, diff --git a/lib/versionmanager.js b/lib/versionmanager.js index c859e66a..ceb72588 100644 --- a/lib/versionmanager.js +++ b/lib/versionmanager.js @@ -110,9 +110,7 @@ function isUpgradeable(current, latest) { const version = versionUtil.stringify(range) // allow upgrading of pseudo versions such as "v1" or "1.0" - const latestNormalized = versionUtil.isMissingMinorAndPatch(latest) ? latest.replace('v', '') + '.0.0' - : versionUtil.isMissingPatch(latest) ? latest + '.0' - : latest + const latestNormalized = versionUtil.fixPseudoVersion(latest) const isValidCurrent = Boolean(semver.validRange(version)) const isValidLatest = Boolean(semver.valid(latestNormalized)) @@ -122,9 +120,9 @@ function isUpgradeable(current, latest) { // 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 isValidCurrent && - isValidLatest && - !isSatisfied(latestNormalized, range.operator === '<' ? current : version) && - !semver.ltr(latestNormalized, version) + isValidLatest && + !isSatisfied(latestNormalized, range.operator === '<' ? current : version) && + !semver.ltr(latestNormalized, version) } /**