Skip to content
Snippets Groups Projects
Commit 2e8721eb authored by Rhys Arkins's avatar Rhys Arkins
Browse files

Don’t upgrade to future versions unnecessarily

Closes #55

commit 4914c5bbf401711b61d9a54330532175a51a167c
Author: Rhys Arkins <rhys@keylocation.sg>
Date:   Tue Jan 17 12:45:45 2017 +0100

    Update debug

commit 55c8307381397399afda01038b6c50416cba27a3
Author: Rhys Arkins <rhys@keylocation.sg>
Date:   Tue Jan 17 12:44:08 2017 +0100

    Ignore versions newer than “latest”

commit 8aa3e7daa937c0d86f89e1d704853ebee46a54a8
Author: Rhys Arkins <rhys@keylocation.sg>
Date:   Tue Jan 17 11:17:31 2017 +0100

    Ignore futures if current is not future
parent 8b2dada0
No related branches found
No related tags found
No related merge requests found
const got = require('got'); const got = require('got');
module.exports = { module.exports = {
getDependencyVersions, getDependency,
}; };
function getDependencyVersions(depName) { function getDependency(depName) {
// supports scoped packages, e.g. @user/package // supports scoped packages, e.g. @user/package
return got(`https://registry.npmjs.org/${depName.replace('/', '%2F')}`, { return got(`https://registry.npmjs.org/${depName.replace('/', '%2F')}`, {
json: true, json: true,
}).then(res => res.body.versions); }).then(res => res.body);
} }
...@@ -6,15 +6,19 @@ module.exports = { ...@@ -6,15 +6,19 @@ module.exports = {
determineUpgrades, determineUpgrades,
isRange, isRange,
isValidVersion, isValidVersion,
isFuture,
isCurrent,
isPastLatest,
}; };
function determineUpgrades(depName, currentVersion, versions) { function determineUpgrades(dep, currentVersion) {
const versions = dep.versions;
if (!isValidVersion(currentVersion)) { if (!isValidVersion(currentVersion)) {
logger.verbose(`${depName} currentVersion is invalid`); logger.verbose(`${dep.name} currentVersion is invalid`);
return []; return [];
} }
if (!versions || !Object.keys(versions).length) { if (!versions || Object.keys(versions).length === 0) {
logger.verbose(`${depName} versions is null`); logger.verbose(`${dep.name} - no versions`);
return []; return [];
} }
const versionList = Object.keys(versions); const versionList = Object.keys(versions);
...@@ -33,11 +37,20 @@ function determineUpgrades(depName, currentVersion, versions) { ...@@ -33,11 +37,20 @@ function determineUpgrades(depName, currentVersion, versions) {
} }
// Loop through all possible versions // Loop through all possible versions
versionList.forEach((newVersion) => { versionList.forEach((newVersion) => {
if (stable.is(workingVersion) && !stable.is(newVersion)) {
// Ignore unstable versions, unless the current version is unstable
return;
}
if (semver.gt(newVersion, workingVersion)) { if (semver.gt(newVersion, workingVersion)) {
if (stable.is(workingVersion) && !stable.is(newVersion)) {
// Ignore unstable versions, unless the current version is unstable
logger.debug(`Ignoring version ${newVersion} because it's unstable`);
return;
}
if (isCurrent(versions[workingVersion]) && isFuture(versions[newVersion])) {
logger.debug(`Ignoring version ${newVersion} because it's marked as "future"`);
return;
}
if (isPastLatest(dep, newVersion) && !isPastLatest(dep, workingVersion)) {
logger.debug(`Ignoring version ${newVersion} because it's newer than the repo's "latest" tag`);
return;
}
// Group by major versions // Group by major versions
const newVersionMajor = semver.major(newVersion); const newVersionMajor = semver.major(newVersion);
// Save this, if it's a new major version or greater than the previous greatest // Save this, if it's a new major version or greater than the previous greatest
...@@ -70,3 +83,19 @@ function isRange(input) { ...@@ -70,3 +83,19 @@ function isRange(input) {
function isValidVersion(input) { function isValidVersion(input) {
return (semver.valid(input) || semver.validRange(input)) !== null; return (semver.valid(input) || semver.validRange(input)) !== null;
} }
function isFuture(version) {
return version && version.publishConfig && version.publishConfig.tag === 'future';
}
function isCurrent(version) {
return !isFuture(version);
}
function isPastLatest(dep, version) {
if (dep['dist-tags'] && dep['dist-tags'].latest) {
return semver.gt(version, dep['dist-tags'].latest);
}
logger.warn(`No dist-tags.latest for ${dep.name}`);
return false;
}
...@@ -50,8 +50,8 @@ function findUpgrades(dependencies) { ...@@ -50,8 +50,8 @@ function findUpgrades(dependencies) {
const allDependencyUpgrades = []; const allDependencyUpgrades = [];
// We create an array of promises so that they can be executed in parallel // We create an array of promises so that they can be executed in parallel
const allDependencyPromises = dependencies.reduce((promises, dep) => promises.concat( const allDependencyPromises = dependencies.reduce((promises, dep) => promises.concat(
npmApi.getDependencyVersions(dep.depName) npmApi.getDependency(dep.depName)
.then(versions => versionsHelper.determineUpgrades(dep.depName, dep.currentVersion, versions)) .then(npmDependency => versionsHelper.determineUpgrades(npmDependency, dep.currentVersion))
.then((upgrades) => { .then((upgrades) => {
if (upgrades.length > 0) { if (upgrades.length > 0) {
logger.verbose(`${dep.depName}: Upgrades = ${JSON.stringify(upgrades)}`); logger.verbose(`${dep.depName}: Upgrades = ${JSON.stringify(upgrades)}`);
......
This diff is collapsed.
...@@ -3,61 +3,69 @@ const versionsHelper = require('../../lib/helpers/versions'); ...@@ -3,61 +3,69 @@ const versionsHelper = require('../../lib/helpers/versions');
chai.should(); chai.should();
const qJson = require('../_fixtures/npm/01.json');
describe('helpers/versions', () => { describe('helpers/versions', () => {
describe('.determineUpgrades(depName, currentVersion, versions)', () => { describe('.determineUpgrades(dep, currentVersion)', () => {
const testVersions = {
'0.1.0': {},
'1.0.0': {},
'1.0.1': {},
'1.1.0': {},
'2.0.0-alpha1': {},
'2.0.0': {},
'2.0.1': {},
'3.0.0': {},
'3.1.0': {},
};
it('return empty if invalid current version', () => { it('return empty if invalid current version', () => {
versionsHelper.determineUpgrades('foo', 'invalid', { '1.0.0': {} }).should.have.length(0); versionsHelper.determineUpgrades(qJson, 'invalid').should.have.length(0);
}); });
it('return empty if null versions', () => { it('return empty if null versions', () => {
versionsHelper.determineUpgrades('foo', '1.0.0', null).should.have.length(0); const testDep = {
name: 'q',
};
versionsHelper.determineUpgrades(testDep, '1.0.0').should.have.length(0);
}); });
it('return empty if empty versions', () => { it('return empty if empty versions', () => {
versionsHelper.determineUpgrades('foo', '1.0.0', []).should.have.length(0); const testDep = {
name: 'q',
versions: [],
};
versionsHelper.determineUpgrades(testDep, '1.0.0', []).should.have.length(0);
}); });
it('supports minor and major upgrades, including for ranges', () => { it('supports minor and major upgrades for pinned versions', () => {
const upgradeVersions = [ const upgradeVersions = [
{ {
newVersion: '1.1.0', newVersion: '0.9.7',
newVersionMajor: 1, newVersionMajor: 0,
upgradeType: 'minor', upgradeType: 'minor',
workingVersion: '1.0.1', workingVersion: '0.4.4',
}, },
{ {
newVersion: '2.0.1', newVersion: '1.4.1',
newVersionMajor: 2, newVersionMajor: 1,
upgradeType: 'major', upgradeType: 'major',
workingVersion: '1.0.1', workingVersion: '0.4.4',
}, },
];
versionsHelper.determineUpgrades(qJson, '^0.4.0').should.eql(upgradeVersions);
});
it('supports minor and major upgrades for ranged versions', () => {
const pinVersions = [
{ {
newVersion: '3.1.0', newVersion: '0.9.7',
newVersionMajor: 3, newVersionMajor: 0,
upgradeType: 'minor',
workingVersion: '0.4.4',
},
{
newVersion: '1.4.1',
newVersionMajor: 1,
upgradeType: 'major', upgradeType: 'major',
workingVersion: '1.0.1', workingVersion: '0.4.4',
}, },
]; ];
versionsHelper.determineUpgrades('foo', '1.0.1', testVersions).should.eql(upgradeVersions); versionsHelper.determineUpgrades(qJson, '~0.4.0').should.eql(pinVersions);
versionsHelper.determineUpgrades('foo', '~1.0.1', testVersions).should.eql(upgradeVersions);
}); });
it('supports pinning', () => { it('supports future versions', () => {
const upgradeVersions = [ const upgradeVersions = [
{ {
newVersion: '3.1.0', newVersion: '2.0.3',
newVersionMajor: 3, newVersionMajor: 2,
upgradeType: 'pin', upgradeType: 'pin',
}, },
]; ];
versionsHelper.determineUpgrades('foo', '^3.0.0', testVersions).should.eql(upgradeVersions); versionsHelper.determineUpgrades(qJson, '^2.0.0').should.eql(upgradeVersions);
}); });
}); });
describe('.isRange(input)', () => { describe('.isRange(input)', () => {
...@@ -92,4 +100,15 @@ describe('helpers/versions', () => { ...@@ -92,4 +100,15 @@ describe('helpers/versions', () => {
versionsHelper.isValidVersion('https://github.com/singapore/renovate.git').should.eql(false); versionsHelper.isValidVersion('https://github.com/singapore/renovate.git').should.eql(false);
}); });
}); });
describe('.isPastLatest(dep, version)', () => {
it('should return false for less than', () => {
versionsHelper.isPastLatest(qJson, '1.0.0').should.eql(false);
});
it('should return false for equal', () => {
versionsHelper.isPastLatest(qJson, '1.4.1').should.eql(false);
});
it('should return true for greater than', () => {
versionsHelper.isPastLatest(qJson, '2.0.3').should.eql(true);
});
});
}); });
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment