diff --git a/lib/package-managers/gitTags.js b/lib/package-managers/gitTags.js index bf487272..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.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)) diff --git a/lib/version-util.js b/lib/version-util.js index 03904b9c..deb1735d 100644 --- a/lib/version-util.js +++ b/lib/version-util.js @@ -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. @@ -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 = { @@ -401,8 +435,9 @@ module.exports = { getPrecision, setPrecision, addWildCard, + fixPseudoVersion, + revertPseudoVersion, isPre, - isSimpleVersion, isWildCard, isWildPart, colorizeDiff, diff --git a/lib/versionmanager.js b/lib/versionmanager.js index cf3bb762..ceb72588 100644 --- a/lib/versionmanager.js +++ b/lib/versionmanager.js @@ -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) } /** 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' }) })