renovate/lib/manager/npm/versions.js

468 lines
17 KiB
JavaScript
Raw Normal View History

const _ = require('lodash');
2018-04-10 03:20:46 +00:00
const {
getMajor,
getMinor,
getPatch,
isGreaterThan,
isRange,
isStable,
isUnstable,
isPinnedVersion,
matchesSemver,
maxSatisfyingVersion,
minSatisfyingVersion,
parseRange,
parseVersion,
stringifyRange,
} = require('../../util/semver');
const moment = require('moment');
Move code into github and npm helper libraries commit 8e84875bd5f7e4584d707d88d6850565bb02c79c Author: Rhys Arkins <rhys@keylocation.sg> Date: Sat Jan 7 08:22:21 2017 +0100 Synchronous commit 0f24ea192bcf54aae1264e91a4b6eb98fea55448 Author: Rhys Arkins <rhys@keylocation.sg> Date: Sat Jan 7 07:12:20 2017 +0100 externalise more npm commit 458d60975fc967f1373c81cd0fa28a9717dd9b0b Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 15:45:08 2017 +0100 Externalise npm commit 5d4f39e72d2977af1fec12d7a0a39d3877e4ad02 Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 15:35:16 2017 +0100 Remove ghGot commit 06898801c1e591d6db9e6ac1e565233af5e9be7e Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 15:34:43 2017 +0100 Externalise PR functions commit 0b0e0f781b3384ad57a1df3df7d1089b2c72079a Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 15:34:25 2017 +0100 Enable verbose commit 4cebf1e0a80d7e14b9704c5fd7e5d0b036b9661a Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 14:23:12 2017 +0100 verbose commit 5a984b91e099cccb5c9dff857a6be07b3b4dedd5 Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 14:22:59 2017 +0100 Change default branch naming commit ab9bc952c81d16be9be57227382dff8d05e73f54 Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 13:05:08 2017 +0100 Fix branch matching commit eeecf17e196245964aed5247cf1703619d42b0d4 Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 11:15:16 2017 +0100 Update message commit d27b345c5eb51dcb7e32b903beafe0728e24bfdb Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 11:09:39 2017 +0100 Refactor file write commit 7f12ef69f456ecd064be5d9851157131222f7700 Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 10:59:24 2017 +0100 Refactor writeFile commit 8c7cc9e6a6c7e398aa60cb828c16ff51f36f2efa Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 10:39:27 2017 +0100 Refactor getFile commit b4338ade6d29b830ead657267248c93216c2f91d Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 10:15:02 2017 +0100 refactor commit dc4aeb39dad367844836da7f93e9f167864f6030 Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 10:14:34 2017 +0100 createBranch commit d6a357f609de55d7b934652f30592219391a9884 Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 10:04:04 2017 +0100 Add createBranch commit 11ba4e9f6c2153d7b783670944570cb4968ff718 Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 07:27:08 2017 +0100 Rename commit 7a4be0fde0e070e2149bc4c34397c4903096ac51 Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 07:17:31 2017 +0100 Externalise some github functions commit e393e92bcc9cb548fac3637644b0330a136f3611 Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 07:17:19 2017 +0100 Fix error message commit 59fb50656d84491780bc31bab4cb9263a7912c03 Author: Rhys Arkins <rhys@keylocation.sg> Date: Fri Jan 6 07:16:59 2017 +0100 Improve error checks commit bc44b3a0d820ab5756c3b3c746402329e5b52703 Author: Rhys Arkins <rhys@keylocation.sg> Date: Thu Jan 5 15:34:04 2017 +0100 Make base branch configurable commit b9d31776814723d991a226d1ca1b2f39d0d2af85 Author: Rhys Arkins <rhys@keylocation.sg> Date: Thu Jan 5 15:33:44 2017 +0100 Reorder early lines commit b75f9f25cfb86f029b73445aae67b7889ff09b3e Author: Rhys Arkins <rhys@keylocation.sg> Date: Thu Jan 5 15:26:47 2017 +0100 Error if RENOVATE_TOKEN is undefined Closes #11 commit 34e13a70326a71b3ee7f18c12ec3de55b78bcaa1 Author: Rhys Arkins <rhys@keylocation.sg> Date: Thu Jan 5 14:43:42 2017 +0100 arrow functions commit 6006db2deae887938bc20a07c93d1a59bd8cd74e Author: Rhys Arkins <rhys@keylocation.sg> Date: Thu Jan 5 14:39:30 2017 +0100 Refactor templates
2017-01-07 07:22:48 +00:00
module.exports = {
determineUpgrades,
isPastLatest,
2017-01-11 12:19:59 +00:00
};
function determineUpgrades(npmDep, config) {
const dependency = npmDep.name;
logger.debug({ dependency }, `determineUpgrades()`);
logger.trace({ npmDep, config });
const result = {
type: 'warning',
};
const { lockedVersion, pinVersions, allowedVersions } = config;
const { versions } = npmDep;
if (!versions || Object.keys(versions).length === 0) {
result.message = `No versions returned from registry for this package`;
logger.warn({ dependency }, result.message);
return [result];
2017-01-12 16:04:25 +00:00
}
let versionList = Object.keys(versions);
2017-01-12 16:04:25 +00:00
const allUpgrades = {};
let { currentVersion } = config;
// filter out versions past latest
const currentIsPastLatest = isPastLatest(
npmDep,
2018-04-10 03:20:46 +00:00
minSatisfyingVersion(versionList, currentVersion)
);
if (currentIsPastLatest) {
logger.debug({ name: npmDep.name, currentVersion }, 'currentIsPastLatest');
}
versionList = versionList.filter(
version =>
currentIsPastLatest || // if current is past latest then don't filter any
config.respectLatest === false || // if user has configured respectLatest to false
isPastLatest(npmDep, version) === false // if the version is less than or equal to latest
);
let rangeOperator;
2018-04-10 03:20:46 +00:00
if (config.upgradeInRange && isRange(currentVersion)) {
logger.debug({ currentVersion }, 'upgradeInRange is true');
2018-04-10 03:20:46 +00:00
const parsedRange = parseRange(currentVersion);
if (parsedRange && parsedRange.length === 1) {
const [range] = parsedRange;
if (range.major && range.minor && range.patch) {
if (range.operator === '^' || range.operator === '~') {
logger.debug('Applying upgradeInRange');
currentVersion = `${range.major}.${range.minor}.${range.patch}`;
currentVersion += range.release ? `-${range.release}` : '';
logger.debug({ currentVersion }, 'upgradeInRange currentVersion');
rangeOperator = range.operator;
} else {
logger.debug({ currentVersion }, 'Unsupported range type');
}
} else {
logger.debug({ currentVersion }, 'Range is not fully specified');
}
} else {
logger.debug({ currentVersion }, 'Skipping complex range');
}
}
let changeLogFromVersion = currentVersion;
2017-01-12 16:04:25 +00:00
// Check for a current range and pin it
if (isRange(currentVersion)) {
let newVersion;
2018-04-10 03:20:46 +00:00
if (pinVersions && lockedVersion && isPinnedVersion(lockedVersion)) {
newVersion = lockedVersion;
} else {
// Pin ranges to their maximum satisfying version
logger.debug({ dependency }, 'currentVersion is range, not locked');
2018-04-10 03:20:46 +00:00
const maxSatisfying = maxSatisfyingVersion(versionList, currentVersion);
if (!maxSatisfying) {
result.message = `No satisfying version found for existing dependency range "${currentVersion}"`;
logger.info(
{ dependency, currentVersion },
`Warning: ${result.message}`
);
return [result];
}
logger.debug({ dependency, maxSatisfying });
newVersion = maxSatisfying;
}
2017-01-13 09:06:38 +00:00
allUpgrades.pin = {
type: 'pin',
Refactor repository worker (#344) * Move to subdir * Downgrade eslint to 3 * Refactor api and config usage * Refactor mergeRenovateJson * Test mergeRenovateJson * getOnboardingStatus tests * Refactor repository structure * Refactor config.logger * Revert "Refactor config.logger" This reverts commit 6d7f81af6ee284d01aab811dab7eb05c2274edf3. * Refactor repository logging * Refactor try/catch * Refactor platform and onboarding * Refactor setNpmrc * Fix github logger * npm api use config.logger * Refactor repo worker logger * Refactor repo worker * Refactor branched upgrades * Repository refactoring * Move some debug logging to trace * Deprecate fileName * Refactor upgrades * Refactor repository logs * More repository log refactoring * Refactor repository location * Revert "Refactor repository location" This reverts commit faecbf29516737a2752de54103c0228b9112a51c. * Fix tests * mergeRenovateJson * Recombine repository worker * Add initApis tests * add detectPackageFiles tests * Add determineRepoUpgrades tests * start groupUpgradesByBranch tests * add test * add test * Finish groupUpgradesByBranch coverage * Test updateBranchesSequentially * Finish repo coverage * Finish branch worker coverage * Finish workers coverage * Fix isPin * Complete workers coverage * Finish helpers coverage * Add gitlab api tests * getBranchStatus tests * test createPr * start getPr testing * getPr * update and merge PR tests * getFile * getFileContent tests * getFileJson tests * createFile * updateFile * createBranch * commitFilesToBranch * update yarn * Update yarn
2017-06-25 05:36:13 +00:00
isPin: true,
newVersion,
2018-04-10 03:20:46 +00:00
newVersionMajor: getMajor(newVersion),
2017-01-13 09:06:38 +00:00
};
changeLogFromVersion = newVersion;
} else if (versionList.indexOf(currentVersion) === -1 && !rangeOperator) {
logger.debug({ dependency }, 'Cannot find currentVersion');
try {
2018-04-10 03:20:46 +00:00
const rollbackVersion = maxSatisfyingVersion(
versionList,
`<${currentVersion}`
);
allUpgrades.rollback = {
type: 'rollback',
isRollback: true,
newVersion: rollbackVersion,
2018-04-10 03:20:46 +00:00
newVersionMajor: getMajor(rollbackVersion),
semanticCommitType: 'fix',
commitMessageAction: 'Roll back',
branchName:
'{{{branchPrefix}}}rollback-{{{depNameSanitized}}}-{{{newVersionMajor}}}.x',
};
} catch (err) /* istanbul ignore next */ {
logger.info(
{ dependency, currentVersion },
'Warning: current version is missing from npm registry and cannot roll back'
);
}
2017-01-12 16:04:25 +00:00
}
_(versionList)
// Filter out older versions as we can't upgrade to those
2018-04-10 03:20:46 +00:00
.filter(version => isGreaterThan(version, changeLogFromVersion))
// fillter out non-allowed versions if preference is set
.reject(
2018-04-10 03:20:46 +00:00
version => allowedVersions && !matchesSemver(version, allowedVersions)
)
// Ignore unstable versions, unless the current version is unstable
2017-04-21 08:12:41 +00:00
.reject(
version =>
config.ignoreUnstable &&
2018-04-10 03:20:46 +00:00
isStable(changeLogFromVersion) &&
isUnstable(version)
2017-04-21 08:12:41 +00:00
)
// Do not jump to a new major unstable just because the current is unstable
.reject(
version =>
config.ignoreUnstable &&
2018-04-10 03:20:46 +00:00
isUnstable(version) &&
getMajor(version) > getMajor(changeLogFromVersion)
)
// Loop through all possible versions
2017-04-21 08:12:41 +00:00
.forEach(newVersion => {
2017-01-12 16:04:25 +00:00
// Group by major versions
2018-04-10 03:20:46 +00:00
const newVersionMajor = getMajor(newVersion);
const newVersionMinor = getMinor(newVersion);
const hasPatchOnlyAutomerge =
config.patch &&
config.patch.automerge === true &&
(config.minor && config.minor.automerge !== true);
let type;
2018-04-10 03:20:46 +00:00
if (newVersionMajor > getMajor(changeLogFromVersion)) {
type = 'major';
} else if (
2018-04-10 03:20:46 +00:00
newVersionMinor === getMinor(changeLogFromVersion) &&
(config.separatePatchReleases || hasPatchOnlyAutomerge)
) {
// Only use patch if configured to
type = 'patch';
} else {
type = 'minor';
}
let upgradeKey;
if (
!config.separateMajorReleases ||
config.groupName ||
config.major.automerge === true
) {
// If we're not separating releases then we use a common lookup key
upgradeKey = 'latest';
} else if (!config.multipleMajorPrs && type === 'major') {
upgradeKey = 'major';
} else if (type === 'patch') {
upgradeKey = `{{{newVersionMajor}}}.{{{newVersionMinor}}}`;
} else {
// Use major version as lookup key
upgradeKey = newVersionMajor;
}
2017-01-12 16:04:25 +00:00
// Save this, if it's a new major version or greater than the previous greatest
2017-04-21 08:12:41 +00:00
if (
!allUpgrades[upgradeKey] ||
2018-04-10 03:20:46 +00:00
isGreaterThan(newVersion, allUpgrades[upgradeKey].newVersion)
2017-04-21 08:12:41 +00:00
) {
const changeLogToVersion = newVersion;
allUpgrades[upgradeKey] = {
type,
2017-01-12 16:04:25 +00:00
newVersion,
newVersionMajor,
newVersionMinor,
changeLogFromVersion,
changeLogToVersion,
2017-01-12 16:04:25 +00:00
};
if (type === 'major') {
Refactor repository worker (#344) * Move to subdir * Downgrade eslint to 3 * Refactor api and config usage * Refactor mergeRenovateJson * Test mergeRenovateJson * getOnboardingStatus tests * Refactor repository structure * Refactor config.logger * Revert "Refactor config.logger" This reverts commit 6d7f81af6ee284d01aab811dab7eb05c2274edf3. * Refactor repository logging * Refactor try/catch * Refactor platform and onboarding * Refactor setNpmrc * Fix github logger * npm api use config.logger * Refactor repo worker logger * Refactor repo worker * Refactor branched upgrades * Repository refactoring * Move some debug logging to trace * Deprecate fileName * Refactor upgrades * Refactor repository logs * More repository log refactoring * Refactor repository location * Revert "Refactor repository location" This reverts commit faecbf29516737a2752de54103c0228b9112a51c. * Fix tests * mergeRenovateJson * Recombine repository worker * Add initApis tests * add detectPackageFiles tests * Add determineRepoUpgrades tests * start groupUpgradesByBranch tests * add test * add test * Finish groupUpgradesByBranch coverage * Test updateBranchesSequentially * Finish repo coverage * Finish branch worker coverage * Finish workers coverage * Fix isPin * Complete workers coverage * Finish helpers coverage * Add gitlab api tests * getBranchStatus tests * test createPr * start getPr testing * getPr * update and merge PR tests * getFile * getFileContent tests * getFileJson tests * createFile * updateFile * createBranch * commitFilesToBranch * update yarn * Update yarn
2017-06-25 05:36:13 +00:00
allUpgrades[upgradeKey].isMajor = true;
} else if (type === 'minor') {
Refactor repository worker (#344) * Move to subdir * Downgrade eslint to 3 * Refactor api and config usage * Refactor mergeRenovateJson * Test mergeRenovateJson * getOnboardingStatus tests * Refactor repository structure * Refactor config.logger * Revert "Refactor config.logger" This reverts commit 6d7f81af6ee284d01aab811dab7eb05c2274edf3. * Refactor repository logging * Refactor try/catch * Refactor platform and onboarding * Refactor setNpmrc * Fix github logger * npm api use config.logger * Refactor repo worker logger * Refactor repo worker * Refactor branched upgrades * Repository refactoring * Move some debug logging to trace * Deprecate fileName * Refactor upgrades * Refactor repository logs * More repository log refactoring * Refactor repository location * Revert "Refactor repository location" This reverts commit faecbf29516737a2752de54103c0228b9112a51c. * Fix tests * mergeRenovateJson * Recombine repository worker * Add initApis tests * add detectPackageFiles tests * Add determineRepoUpgrades tests * start groupUpgradesByBranch tests * add test * add test * Finish groupUpgradesByBranch coverage * Test updateBranchesSequentially * Finish repo coverage * Finish branch worker coverage * Finish workers coverage * Fix isPin * Complete workers coverage * Finish helpers coverage * Add gitlab api tests * getBranchStatus tests * test createPr * start getPr testing * getPr * update and merge PR tests * getFile * getFileContent tests * getFileJson tests * createFile * updateFile * createBranch * commitFilesToBranch * update yarn * Update yarn
2017-06-25 05:36:13 +00:00
allUpgrades[upgradeKey].isMinor = true;
} else if (type === 'patch') {
allUpgrades[upgradeKey].isPatch = true;
Refactor repository worker (#344) * Move to subdir * Downgrade eslint to 3 * Refactor api and config usage * Refactor mergeRenovateJson * Test mergeRenovateJson * getOnboardingStatus tests * Refactor repository structure * Refactor config.logger * Revert "Refactor config.logger" This reverts commit 6d7f81af6ee284d01aab811dab7eb05c2274edf3. * Refactor repository logging * Refactor try/catch * Refactor platform and onboarding * Refactor setNpmrc * Fix github logger * npm api use config.logger * Refactor repo worker logger * Refactor repo worker * Refactor branched upgrades * Repository refactoring * Move some debug logging to trace * Deprecate fileName * Refactor upgrades * Refactor repository logs * More repository log refactoring * Refactor repository location * Revert "Refactor repository location" This reverts commit faecbf29516737a2752de54103c0228b9112a51c. * Fix tests * mergeRenovateJson * Recombine repository worker * Add initApis tests * add detectPackageFiles tests * Add determineRepoUpgrades tests * start groupUpgradesByBranch tests * add test * add test * Finish groupUpgradesByBranch coverage * Test updateBranchesSequentially * Finish repo coverage * Finish branch worker coverage * Finish workers coverage * Fix isPin * Complete workers coverage * Finish helpers coverage * Add gitlab api tests * getBranchStatus tests * test createPr * start getPr testing * getPr * update and merge PR tests * getFile * getFileContent tests * getFileJson tests * createFile * updateFile * createBranch * commitFilesToBranch * update yarn * Update yarn
2017-06-25 05:36:13 +00:00
}
2017-01-07 21:00:32 +00:00
}
});
2017-01-12 16:04:25 +00:00
// Return only the values - we don't need the keys anymore
let upgrades = Object.keys(allUpgrades).map(key => allUpgrades[key]);
for (const upgrade of upgrades) {
const version = versions[upgrade.newVersion];
const elapsed = version ? moment().diff(moment(version.time), 'days') : 999;
upgrade.unpublishable = elapsed > 0;
}
// Return now if array is empty, or we can keep pinned version upgrades
if (upgrades.length === 0 || config.pinVersions || !isRange(currentVersion)) {
return rangeOperator
? upgrades.map(upgrade => ({
...upgrade,
newVersion: `${rangeOperator}${upgrade.newVersion}`,
isRange: true,
}))
: upgrades;
}
2018-03-27 19:57:02 +00:00
logger.debug({ dependency }, 'User wants ranges - filtering out pins');
upgrades = upgrades.filter(upgrade => upgrade.type !== 'pin');
// Return empty if all results were pins
if (!upgrades.length) {
logger.debug({ dependency }, 'No upgrades left - returning');
return [];
}
// Check if it's a range type we support
2018-04-10 03:20:46 +00:00
const semverParsed = parseRange(currentVersion);
// Check the "last" part, which is also the first and only if it's a simple semver
const [lastSemver] = semverParsed.slice(-1);
const secondLastSemver = semverParsed[semverParsed.length - 2];
if (semverParsed.length > 1) {
if (lastSemver.operator === '<' || lastSemver.operator === '<=') {
logger.debug({ dependency }, 'Found less than range');
} else if (secondLastSemver.operator === '||') {
logger.debug({ dependency }, 'Found an OR range');
} else if (secondLastSemver.operator === '-') {
logger.info(
{ dependency, currentVersion, upgrades, semverParsed },
'Found a hyphen 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(
{ dependency, upgrades, semverParsed },
'Semver warning: ' + result.message
);
return [result];
}
}
// Loop through all upgrades and convert to ranges
const rangedUpgrades = _(upgrades)
.map(upgrade => ({ ...upgrade, ...{ isRange: true } }))
2017-04-21 08:12:41 +00:00
.map(upgrade => {
2018-04-10 03:20:46 +00:00
const { major, minor } = parseVersion(upgrade.newVersion);
const canReplace = config.versionStrategy !== 'widen';
const forceReplace = config.versionStrategy === 'replace';
const canWiden = config.versionStrategy !== 'replace';
const forceWiden = config.versionStrategy === 'widen';
if (
lastSemver.operator === '~' &&
canReplace &&
(semverParsed.length === 1 || forceReplace)
) {
2017-04-21 08:12:41 +00:00
// Utilise that a.b is the same as ~a.b.0
2018-04-10 03:20:46 +00:00
const minSatisfying = minSatisfyingVersion(
2017-04-21 08:12:41 +00:00
versionList,
2017-04-21 08:25:49 +00:00
`${major}.${minor}`
2017-04-21 08:12:41 +00:00
);
// Add a tilde before that version number
return { ...upgrade, ...{ newVersion: `~${minSatisfying}` } };
} else if (
lastSemver.operator === '~' &&
canWiden &&
(semverParsed.length > 1 || forceWiden)
) {
// Utilise that a.b is the same as ~a.b.0
2018-04-10 03:20:46 +00:00
const minSatisfying = minSatisfyingVersion(
versionList,
`${major}.${minor}`
);
// Add a tilde before that version number
const newVersion = `${currentVersion} || ~${minSatisfying}`;
return {
...upgrade,
newVersion,
};
} else if (
lastSemver.operator === '^' &&
canReplace &&
(semverParsed.length === 1 || forceReplace)
) {
let newVersion;
// Special case where major and minor are 0
if (major === '0' && minor === '0') {
newVersion = `^${upgrade.newVersion}`;
} else {
// If version is < 1, then semver treats ^ same as ~
const newRange = major === '0' ? `${major}.${minor}` : `${major}`;
2018-04-10 03:20:46 +00:00
const minSatisfying = minSatisfyingVersion(versionList, newRange);
// Add in the caret
newVersion = `^${minSatisfying}`;
}
return { ...upgrade, newVersion };
} else if (
lastSemver.operator === '^' &&
canWiden &&
(semverParsed.length > 1 || forceWiden)
) {
2017-04-21 08:12:41 +00:00
// If version is < 1, then semver treats ^ same as ~
const newRange = major === '0' ? `${major}.${minor}` : `${major}`;
2018-04-10 03:20:46 +00:00
const minSatisfying = minSatisfyingVersion(versionList, newRange);
2017-04-21 08:12:41 +00:00
// Add in the caret
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({ dependency }, 'Found a less than major');
newRange[newRange.length - 1].major = String(
upgrade.newVersionMajor + 1
);
} else if (patchZero) {
logger.debug({ dependency }, 'Found a less than minor');
newRange[newRange.length - 1].major = String(upgrade.newVersionMajor);
newRange[newRange.length - 1].minor = String(
upgrade.newVersionMinor + 1
);
} else {
logger.debug({ dependency }, 'Found a less than full semver');
newRange[newRange.length - 1].major = String(upgrade.newVersionMajor);
newRange[newRange.length - 1].minor = String(upgrade.newVersionMinor);
newRange[newRange.length - 1].patch = String(
2018-04-10 03:20:46 +00:00
getPatch(upgrade.newVersion)
);
}
2018-04-10 03:20:46 +00:00
let newVersion = stringifyRange(newRange);
newVersion = fixRange(newVersion, lastSemver, currentVersion);
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({ dependency }, 'Found a less than major');
newRange[newRange.length - 1].major = String(
upgrade.newVersionMajor + 1
);
} else if (patchZero) {
logger.debug({ dependency }, 'Found a less than minor');
newRange[newRange.length - 1].major = String(upgrade.newVersionMajor);
newRange[newRange.length - 1].minor = String(
upgrade.newVersionMinor + 1
);
} else {
logger.debug({ dependency }, 'Found full semver minor');
newRange[newRange.length - 1].major = String(upgrade.newVersionMajor);
newRange[newRange.length - 1].minor = String(upgrade.newVersionMinor);
newRange[newRange.length - 1].patch = String(
2018-04-10 03:20:46 +00:00
getPatch(upgrade.newVersion) + 1
);
}
2018-04-10 03:20:46 +00:00
let newVersion = stringifyRange(newRange);
newVersion = fixRange(newVersion, lastSemver, currentVersion);
return { ...upgrade, newVersion };
} else if (lastSemver.minor === undefined) {
2017-04-21 08:12:41 +00:00
// Example: 1
const newRange = [...semverParsed];
logger.debug({ dependency }, 'Found a standalone major');
newRange[newRange.length - 1].major = String(upgrade.newVersionMajor);
let newVersion;
if (secondLastSemver && secondLastSemver.operator === '||') {
newVersion = `${currentVersion} || ${upgrade.newVersionMajor}`;
} else {
2018-04-10 03:20:46 +00:00
newVersion = stringifyRange(newRange);
// Fixes a bug with stringifyRange
newVersion = newVersion.replace(/\.0/g, '');
}
return { ...upgrade, newVersion };
} else if (lastSemver.minor === 'x') {
2017-04-21 08:12:41 +00:00
// Example: 1.x
const newRange = [...semverParsed];
logger.debug({ dependency }, 'Found a .x');
newRange[newRange.length - 1].major = String(upgrade.newVersionMajor);
let newVersion;
if (secondLastSemver && secondLastSemver.operator === '||') {
newVersion = `${currentVersion} || ${upgrade.newVersionMajor}.x`;
} else {
2018-04-10 03:20:46 +00:00
newVersion = stringifyRange(newRange);
// Fixes a bug with stringifyRange
newVersion = newVersion.replace(/\.0/g, '');
}
return { ...upgrade, newVersion };
} else if (lastSemver.patch === undefined) {
2017-04-21 08:12:41 +00:00
// Example: 1.2
return { ...upgrade, ...{ newVersion: `${major}.${minor}` } };
} else if (lastSemver.patch === 'x' && semverParsed.length === 1) {
2017-04-21 08:12:41 +00:00
// Example: 1.2.x
return { ...upgrade, ...{ newVersion: `${major}.${minor}.x` } };
2017-04-21 08:12:41 +00:00
}
// istanbul ignore next
result.message = `The current semver range "${currentVersion}" is not supported so won't ever be upgraded`;
// istanbul ignore next
logger.warn({ dependency }, result.message);
// istanbul ignore next
2017-04-21 08:12:41 +00:00
return null;
})
.compact()
.value();
// istanbul ignore if
if (result.message) {
// There must have been an error converting to ranges
return [result];
}
return rangedUpgrades;
2017-01-07 21:00:32 +00:00
}
function fixRange(version, lastSemver, currentVersion) {
let newVersion = version;
if (!lastSemver.patch) {
newVersion = newVersion.replace(/\.0$/, '');
}
if (!currentVersion.includes('< ')) {
newVersion = newVersion.replace(/< /g, '<');
}
if (!currentVersion.includes('> ')) {
newVersion = newVersion.replace(/> /g, '>');
}
if (!currentVersion.includes('>= ')) {
newVersion = newVersion.replace(/>= /g, '>=');
}
if (!currentVersion.includes('<= ')) {
newVersion = newVersion.replace(/<= /g, '<=');
}
return newVersion;
}
function isPastLatest(npmDep, version) {
if (!version) {
return false;
}
if (npmDep['dist-tags'] && npmDep['dist-tags'].latest) {
2018-04-10 03:20:46 +00:00
return isGreaterThan(version, npmDep['dist-tags'].latest);
}
logger.warn(`No dist-tags.latest for ${npmDep.name}`);
return false;
}