diff --git a/.travis.yml b/.travis.yml index 4c3b9ba1..4077ac49 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,21 @@ cache: matrix: include: + - name: 'Lowest versions of the dependencies' + os: linux + node_js: "10" + env: JOB_PART=test + install: + - rm yarn.lock + - node ./scripts/force-lowest-dependencies + - yarn + - name: 'Highest versions of the dependencies' + os: linux + node_js: "10" + env: JOB_PART=test + install: + - rm yarn.lock + - yarn - os: linux node_js: "10" env: JOB_PART=travis:lint diff --git a/scripts/force-lowest-dependencies.js b/scripts/force-lowest-dependencies.js new file mode 100755 index 00000000..42883986 --- /dev/null +++ b/scripts/force-lowest-dependencies.js @@ -0,0 +1,128 @@ +/* + * This file is part of the Symfony Webpack Encore package. + * + * (c) Fabien Potencier + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +'use strict'; + +const fs = require('fs'); +const childProcess = require('child_process'); + +function getLowestVersion(dependency, range) { + return new Promise((resolve, reject) => { + childProcess.exec( + `npm view "${dependency}@${range}" version`, + { encoding: 'utf-8' }, + (error, stdout) => { + if (error) { + reject(`Could not retrieve versions list for "${dependency}@${range}"`); + return; + } + + const versions = stdout + .split('\n') + .filter(line => line); + + if (versions.length === 0) { + reject(`Could not find a lowest version for "${dependency}@${range}"`); + return; + } + + const parts = versions[0].split(' '); + + // If there is only one version available that version + // is directly printed as the output of npm view. + if (parts.length === 1) { + resolve([dependency, parts[0]]); + return; + } + + // If multiple versions are available then it outputs + // multiple lines matching the following format: + // @ '' + if (parts.length === 2) { + resolve([dependency, parts[1].replace(/'/g, '')]); + return; + } + + reject(`Unexpected response for "${dependency}@${range}": ${versions[0]}`); + } + ); + }); +} + +fs.readFile('package.json', (error, data) => { + if (error) { + throw error; + } + + const packageInfo = JSON.parse(data); + + const dependencyPromises = []; + if (packageInfo.dependencies) { + for (const dependency in packageInfo.dependencies) { + dependencyPromises.push(getLowestVersion( + dependency, + packageInfo.dependencies[dependency] + )); + } + } + + const devDependencyPromises = []; + if (packageInfo.devDependencies) { + for (const devDependency in packageInfo.devDependencies) { + devDependencyPromises.push(getLowestVersion( + devDependency, + packageInfo.devDependencies[devDependency] + )); + } + } + + const dependenciesUpdate = Promise.all(dependencyPromises).then(versions => { + versions.forEach(version => { + packageInfo.dependencies[version[0]] = version[1]; + }); + }); + + const devDependenciesUpdate = Promise.all(devDependencyPromises).then(versions => { + versions.forEach(version => { + packageInfo.devDependencies[version[0]] = version[1]; + }); + }); + + // Once all the lowest versions have been resolved, update the + // package.json file accordingly. + Promise + .all([dependenciesUpdate, devDependenciesUpdate]) + .then(() => new Promise((resolve, reject) => { + fs.writeFile('package.json', JSON.stringify(packageInfo, null, 2), (error) => { + if (error) { + reject(error); + return; + } + + resolve(); + }); + })) + .then(() => { + console.log('Updated package.json file with lowest dependency versions: '); + + console.log('Dependencies:'); + for (const dependency in packageInfo.dependencies) { + console.log(` - ${dependency}: ${packageInfo.dependencies[dependency]}`); + } + + console.log('Dev dependencies:'); + for (const dependency in packageInfo.devDependencies) { + console.log(` - ${dependency}: ${packageInfo.devDependencies[dependency]}`); + } + }) + .catch(error => { + console.error(error); + process.exit(1); // eslint-disable-line + }); +}); diff --git a/test/package-helper.js b/test/package-helper.js index 23defca1..5daf63d9 100644 --- a/test/package-helper.js +++ b/test/package-helper.js @@ -13,6 +13,7 @@ const expect = require('chai').expect; const packageHelper = require('../lib/package-helper'); const path = require('path'); const process = require('process'); +const fs = require('fs'); describe('package-helper', () => { const baseCwd = process.cwd(); @@ -135,14 +136,17 @@ describe('package-helper', () => { describe('addPackagesVersionConstraint', () => { it('Lookup a version constraint', () => { - // hardcoding sass-loader: test WILL break when this changes - const inputPackages = [ { name: 'sass-loader', enforce_version: 7 }, { name: 'node-sass' } ]; + + const packageInfo = JSON.parse( + fs.readFileSync(path.join(__dirname, '../package.json')) + ); + const expectedPackages = [ - { name: 'sass-loader', version: '^7.0.1' }, + { name: 'sass-loader', version: packageInfo.devDependencies['sass-loader'] }, { name: 'node-sass' } ];