diff --git a/lib/workers/package/versions.js b/lib/workers/package/versions.js index d8ac5762ab83f7b0e32ff1c7498039db2061c4e2..0d3f83f87bcc0a5ec9e5a1ca1af8e5c9abb7af56 100644 --- a/lib/workers/package/versions.js +++ b/lib/workers/package/versions.js @@ -172,9 +172,14 @@ function determineUpgrades(npmDep, config) { // Check if it's a range type we support const semverParsed = semverUtils.parseRange(currentVersion); // Check the "last" part, which is also the first and only if it's a simple semver - const [currentSemver] = semverParsed.slice(-1); + const [lastSemver] = semverParsed.slice(-1); + const secondLastSemver = semverParsed[semverParsed.length - 2]; if (semverParsed.length > 1) { - if (currentSemver.operator !== '<' && currentSemver.operator !== '<=') { + if (lastSemver.operator === '<' || lastSemver.operator === '<=') { + logger.debug('Found less than range'); + } else if (secondLastSemver.operator === '||') { + logger.debug('Found an OR range'); + } else { // We don't know how to support complex semver ranges, so don't upgrade result.message = `Complex semver ranges such as "${currentVersion}" are not yet supported so will be skipped`; logger.info( @@ -183,14 +188,13 @@ function determineUpgrades(npmDep, config) { ); return [result]; } - logger.debug('Found less than range'); } // Loop through all upgrades and convert to ranges const rangedUpgrades = _(upgrades) .map(upgrade => ({ ...upgrade, ...{ isRange: true } })) .map(upgrade => { const { major, minor } = semverUtils.parse(upgrade.newVersion); - if (currentSemver.operator === '~') { + if (lastSemver.operator === '~' && semverParsed.length === 1) { // Utilise that a.b is the same as ~a.b.0 const minSatisfying = semver.minSatisfying( versionList, @@ -198,24 +202,44 @@ function determineUpgrades(npmDep, config) { ); // Add a tilde before that version number return { ...upgrade, ...{ newVersion: `~${minSatisfying}` } }; - } else if (currentSemver.operator === '^') { + } else if (lastSemver.operator === '~' && semverParsed.length > 1) { + // Utilise that a.b is the same as ~a.b.0 + const minSatisfying = semver.minSatisfying( + versionList, + `${major}.${minor}` + ); + // Add a tilde before that version number + const newVersion = `~${minSatisfying}`; + return { + ...upgrade, + newVersion: currentVersion + ' || ' + newVersion, + }; + } else if (lastSemver.operator === '^' && semverParsed.length === 1) { + let newVersion; // Special case where major and minor are 0 if (major === '0' && minor === '0') { - return { - ...upgrade, - ...{ - newVersion: `^${upgrade.newVersion}`, - }, - }; + newVersion = `^${upgrade.newVersion}`; + } else { + // If version is < 1, then semver treats ^ same as ~ + const newRange = major === '0' ? `${major}.${minor}` : `${major}`; + const minSatisfying = semver.minSatisfying(versionList, newRange); + // Add in the caret + newVersion = `^${minSatisfying}`; } + return { ...upgrade, newVersion }; + } else if (lastSemver.operator === '^' && semverParsed.length > 1) { // If version is < 1, then semver treats ^ same as ~ const newRange = major === '0' ? `${major}.${minor}` : `${major}`; const minSatisfying = semver.minSatisfying(versionList, newRange); // Add in the caret - return { ...upgrade, ...{ newVersion: `^${minSatisfying}` } }; - } else if (currentSemver.operator === '<=') { - const minorZero = !currentSemver.minor || currentSemver.minor === '0'; - const patchZero = !currentSemver.patch || currentSemver.patch === '0'; + const newVersion = `${currentVersion} || ^${minSatisfying}`; + return { + ...upgrade, + newVersion, + }; + } else if (lastSemver.operator === '<=') { + const minorZero = !lastSemver.minor || lastSemver.minor === '0'; + const patchZero = !lastSemver.patch || lastSemver.patch === '0'; const newRange = [...semverParsed]; if (minorZero && patchZero) { logger.debug('Found a less than major'); @@ -238,9 +262,9 @@ function determineUpgrades(npmDep, config) { } const newVersion = semverUtils.stringifyRange(newRange); return { ...upgrade, newVersion }; - } else if (currentSemver.operator === '<') { - const minorZero = !currentSemver.minor || currentSemver.minor === '0'; - const patchZero = !currentSemver.patch || currentSemver.patch === '0'; + } else if (lastSemver.operator === '<') { + const minorZero = !lastSemver.minor || lastSemver.minor === '0'; + const patchZero = !lastSemver.patch || lastSemver.patch === '0'; const newRange = [...semverParsed]; if (minorZero && patchZero) { logger.debug('Found a less than major'); @@ -263,16 +287,16 @@ function determineUpgrades(npmDep, config) { } const newVersion = semverUtils.stringifyRange(newRange); return { ...upgrade, newVersion }; - } else if (currentSemver.minor === undefined) { + } else if (lastSemver.minor === undefined) { // Example: 1 return { ...upgrade, ...{ newVersion: `${major}` } }; - } else if (currentSemver.minor === 'x') { + } else if (lastSemver.minor === 'x') { // Example: 1.x return { ...upgrade, ...{ newVersion: `${major}.x` } }; - } else if (currentSemver.patch === undefined) { + } else if (lastSemver.patch === undefined) { // Example: 1.2 return { ...upgrade, ...{ newVersion: `${major}.${minor}` } }; - } else if (currentSemver.patch === 'x') { + } else if (lastSemver.patch === 'x') { // Example: 1.2.x return { ...upgrade, ...{ newVersion: `${major}.${minor}.x` } }; } diff --git a/test/workers/package/__snapshots__/versions.spec.js.snap b/test/workers/package/__snapshots__/versions.spec.js.snap index 0c481d3f9d05789d3f9ba2d1b753cd1496b772d6..a7b4c2c4115e1af2e13c70bf6879a2fbc5ef8905 100644 --- a/test/workers/package/__snapshots__/versions.spec.js.snap +++ b/test/workers/package/__snapshots__/versions.spec.js.snap @@ -37,13 +37,6 @@ Array [ ] `; -exports[`workers/package/versions .determineUpgrades(npmDep, config) ignores complex ranges when not pinning 1`] = ` -Object { - "message": "Complex semver ranges such as \\"^0.7.0 || ^0.8.0\\" are not yet supported so will be skipped", - "type": "warning", -} -`; - exports[`workers/package/versions .determineUpgrades(npmDep, config) ignores pinning for ranges when other upgrade exists 1`] = ` Array [ Object { @@ -354,6 +347,52 @@ Array [ ] `; +exports[`workers/package/versions .determineUpgrades(npmDep, config) supports complex major ranges 1`] = ` +Array [ + Object { + "changeLogFromVersion": "2.7.0", + "changeLogToVersion": "3.8.1", + "isMajor": true, + "isRange": true, + "newVersion": "^1.0.0 || ^2.0.0 || ^3.0.0", + "newVersionMajor": 3, + "newVersionMinor": 8, + "type": "major", + "unpublishable": false, + }, +] +`; + +exports[`workers/package/versions .determineUpgrades(npmDep, config) supports complex ranges 1`] = ` +Object { + "changeLogFromVersion": "0.8.12", + "changeLogToVersion": "0.9.7", + "isMinor": true, + "isRange": true, + "newVersion": "^0.7.0 || ^0.8.0 || ^0.9.0", + "newVersionMajor": 0, + "newVersionMinor": 9, + "type": "minor", + "unpublishable": false, +} +`; + +exports[`workers/package/versions .determineUpgrades(npmDep, config) supports complex tilde ranges 1`] = ` +Array [ + Object { + "changeLogFromVersion": "1.3.0", + "changeLogToVersion": "1.4.1", + "isMinor": true, + "isRange": true, + "newVersion": "~1.2.0 || ~1.3.0 || ~1.4.0", + "newVersionMajor": 1, + "newVersionMinor": 4, + "type": "minor", + "unpublishable": false, + }, +] +`; + exports[`workers/package/versions .determineUpgrades(npmDep, config) supports future versions if already future 1`] = ` Array [ Object { diff --git a/test/workers/package/versions.spec.js b/test/workers/package/versions.spec.js index 57e1960b647a2eaa62427ae246da4c81adea304b..872d5efde8de6afce3688fce1b41270ceb9dd3aa 100644 --- a/test/workers/package/versions.spec.js +++ b/test/workers/package/versions.spec.js @@ -156,13 +156,25 @@ describe('workers/package/versions', () => { config.currentVersion = '^0.7.0'; expect(versions.determineUpgrades(qJson, config)).toMatchSnapshot(); }); - it('ignores complex ranges when not pinning', () => { + it('supports complex ranges', () => { config.pinVersions = false; config.currentVersion = '^0.7.0 || ^0.8.0'; const res = versions.determineUpgrades(qJson, config); - expect(res).toHaveLength(1); + expect(res).toHaveLength(2); expect(res[0]).toMatchSnapshot(); }); + it('supports complex major ranges', () => { + config.pinVersions = false; + config.currentVersion = '^1.0.0 || ^2.0.0'; + const res = versions.determineUpgrades(webpackJson, config); + expect(res).toMatchSnapshot(); + }); + it('supports complex tilde ranges', () => { + config.pinVersions = false; + config.currentVersion = '~1.2.0 || ~1.3.0'; + const res = versions.determineUpgrades(qJson, config); + expect(res).toMatchSnapshot(); + }); it('returns nothing for greater than ranges', () => { config.pinVersions = false; config.currentVersion = '>= 0.7.0';