From 16d36a15e2106b9d873974b9ba43d811e5ba1209 Mon Sep 17 00:00:00 2001 From: Rhys Arkins <rhys@keylocation.sg> Date: Tue, 29 Aug 2017 09:25:44 +0200 Subject: [PATCH] feat: add npmToken, npmrc and yarnrc configuration support (#753) Renovate config can now support the fields `npmToken`, `npmrc` and `yarnrc`. `npmrc` and `yarnrc` (note no `.` prefix) can be used as an alternative to checking the respective files into the repo and have the same effect. `npmToken` is a shorter alternative and allows for just the npm token to be added, defaulting to the public npm registry. --- docs/configuration.md | 27 +++++++++++++++++++ docs/faq.md | 8 +++--- lib/config/definitions.js | 19 +++++++++++++ lib/config/massage.js | 3 +++ lib/config/presets.js | 4 +-- lib/logger/config-serializer.js | 8 +++++- lib/workers/branch/lock-files.js | 11 ++++++++ lib/workers/package-file/index.js | 4 +-- lib/workers/package/index.js | 6 +---- lib/workers/repository/apis.js | 21 +++++++++------ lib/workers/repository/upgrades.js | 1 - .../config/__snapshots__/massage.spec.js.snap | 7 +++++ test/config/massage.spec.js | 6 +++++ test/workers/branch/lock-files.spec.js | 4 ++- .../package/__snapshots__/index.spec.js.snap | 8 ++++++ .../__snapshots__/apis.spec.js.snap | 4 --- test/workers/repository/apis.spec.js | 9 ++++--- 17 files changed, 119 insertions(+), 31 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 9dc387908b..1b00948f7c 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -79,6 +79,9 @@ $ node renovate --help --platform <string> Platform type of repository --endpoint <string> Custom endpoint to use --token <string> Repository Auth Token + --npmrc <string> String copy of npmrc file. Use \n instead of line breaks + --yarnrc <string> String copy of yarnrc file. Use \n instead of line breaks + --autodiscover [boolean] Autodiscover all repositories --autodiscover [boolean] Autodiscover all repositories --github-app-id <integer> GitHub App ID (enables GitHub App functionality if set) --github-app-key <string> GitHub App Private Key (.pem file contents) @@ -250,6 +253,30 @@ Obviously, you can't set repository or package file location with this method. <td>`RENOVATE_TOKEN`</td> <td>`--token`<td> </tr> +<tr> + <td>`npmrc`</td> + <td>String copy of npmrc file. Use \n instead of line breaks</td> + <td>string</td> + <td><pre>null</pre></td> + <td>`RENOVATE_NPMRC`</td> + <td>`--npmrc`<td> +</tr> +<tr> + <td>`yarnrc`</td> + <td>String copy of yarnrc file. Use \n instead of line breaks</td> + <td>string</td> + <td><pre>null</pre></td> + <td>`RENOVATE_YARNRC`</td> + <td>`--yarnrc`<td> +</tr> +<tr> + <td>`autodiscover`</td> + <td>Autodiscover all repositories</td> + <td>boolean</td> + <td><pre>false</pre></td> + <td>`RENOVATE_AUTODISCOVER`</td> + <td>`--autodiscover`<td> +</tr> <tr> <td>`autodiscover`</td> <td>Autodiscover all repositories</td> diff --git a/docs/faq.md b/docs/faq.md index de5b181ab2..e24072cd7d 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -33,12 +33,14 @@ If for example your repository default branch is `master` but your Pull Requests ### Support private npm modules -If you are running your own Renovate instance, then the easiest way to support private modules is to make sure the appropriate credentials are in `~/.npmrc`; +If you are running your own Renovate instance, then the easiest way to support private modules is to make sure the appropriate credentials are in `.npmrc` or `~/.npmrc`; -If you are using hosted Renovate instance, and your repository `package.json` includes private modules, then you can: +If you are using a hosted Renovate instance (such as the Renovate app), and your `package.json` includes private modules, then you can: 1. Commit an `.npmrc` file to the repository, and Renovate will use this, or -2. If using the [GitHub App hosted service](https://github.com/apps/renovate), authorize the npm user named "renovate" with read-only access to the relevant modules. This "renovate" account is used solely for the purpose of the renovate GitHub App. +2. Add the contents of your `.npmrc` file to the config field `npmrc` in your `renovate.json` or `package.json` renovate config +3. Add a valid npm authToken to the config field `npmToken` in your `renovate.json` or `package.json` renovate config +4. If using the [GitHub App hosted service](https://github.com/apps/renovate), authorize the npm user named "renovate" with read-only access to the relevant modules. This "renovate" account is used solely for the purpose of the renovate GitHub App. ### Control renovate's schedule diff --git a/lib/config/definitions.js b/lib/config/definitions.js index 146f2ec50b..2dca42af88 100644 --- a/lib/config/definitions.js +++ b/lib/config/definitions.js @@ -111,6 +111,25 @@ const options = [ stage: 'repository', type: 'string', }, + { + name: 'npmrc', + description: 'String copy of npmrc file. Use \\n instead of line breaks', + stage: 'branch', + type: 'string', + }, + { + name: 'yarnrc', + description: 'String copy of yarnrc file. Use \\n instead of line breaks', + stage: 'branch', + type: 'string', + }, + { + name: 'autodiscover', + description: 'Autodiscover all repositories', + stage: 'repository', + type: 'boolean', + default: false, + }, { name: 'autodiscover', description: 'Autodiscover all repositories', diff --git a/lib/config/massage.js b/lib/config/massage.js index 80391a8cd5..dd66e43825 100644 --- a/lib/config/massage.js +++ b/lib/config/massage.js @@ -18,6 +18,9 @@ function massageConfig(config) { const val = config[key]; if (allowedStrings.includes(key) && typeof val === 'string') { massagedConfig[key] = [val]; + } else if (key === 'npmToken') { + massagedConfig.npmrc = `//registry.npmjs.org/:_authToken=${val}\n`; + delete massagedConfig.npmToken; } else if (isObject(val)) { massagedConfig[key] = massageConfig(val); } else if (Array.isArray(val)) { diff --git a/lib/config/presets.js b/lib/config/presets.js index 584c537fdd..0e76d809c3 100644 --- a/lib/config/presets.js +++ b/lib/config/presets.js @@ -64,8 +64,8 @@ async function resolveConfigPresets( } } } - logger.debug({ config: inputConfig }, 'Input config'); - logger.debug({ config }, 'Resolved config'); + logger.trace({ config: inputConfig }, 'Input config'); + logger.trace({ config }, 'Resolved config'); return config; } diff --git a/lib/logger/config-serializer.js b/lib/logger/config-serializer.js index 136b13b077..fff9cee8f2 100644 --- a/lib/logger/config-serializer.js +++ b/lib/logger/config-serializer.js @@ -3,7 +3,13 @@ const traverse = require('traverse'); module.exports = configSerializer; function configSerializer(config) { - const redactedFields = ['token', 'githubAppKey']; + const redactedFields = [ + 'token', + 'githubAppKey', + 'npmToken', + 'npmrc', + 'yarnrc', + ]; const functionFields = ['api', 'logger']; const templateFields = ['commitMessage', 'prTitle', 'prBody']; // eslint-disable-next-line array-callback-return diff --git a/lib/workers/branch/lock-files.js b/lib/workers/branch/lock-files.js index bef878c5f2..b8a703a3e7 100644 --- a/lib/workers/branch/lock-files.js +++ b/lib/workers/branch/lock-files.js @@ -77,6 +77,17 @@ function determineLockFileDirs(config) { async function writeExistingFiles(config) { const { logger } = config; + if (config.npmrc) { + logger.debug('Writing repo .npmrc'); + await fs.outputFile(path.join(config.tmpDir.name, '.npmrc'), config.npmrc); + } + if (config.yarnrc) { + logger.debug('Writing repo .yarnrc'); + await fs.outputFile( + path.join(config.tmpDir.name, '.yarnrc'), + config.yarnrc + ); + } if (!config.packageFiles) { return; } diff --git a/lib/workers/package-file/index.js b/lib/workers/package-file/index.js index b570401bdb..2eeecaaf13 100644 --- a/lib/workers/package-file/index.js +++ b/lib/workers/package-file/index.js @@ -39,7 +39,7 @@ async function renovatePackageFile(packageFileConfig) { packageFile: depTypeConfig.packageFile, depType: depTypeConfig.depType, }); - logger.debug({ config: depTypeConfig }, 'depTypeConfig'); + logger.trace({ config: depTypeConfig }, 'depTypeConfig'); return configParser.filterConfig(depTypeConfig, 'depType'); }); logger.trace({ config: depTypeConfigs }, `depTypeConfigs`); @@ -59,7 +59,7 @@ async function renovatePackageFile(packageFileConfig) { config.lockFileMaintenance ); lockFileMaintenanceConf.type = 'lockFileMaintenance'; - logger.debug( + logger.trace( { config: lockFileMaintenanceConf }, `lockFileMaintenanceConf` ); diff --git a/lib/workers/package/index.js b/lib/workers/package/index.js index a3101ba19f..5938f7804b 100644 --- a/lib/workers/package/index.js +++ b/lib/workers/package/index.js @@ -48,11 +48,7 @@ async function renovatePackage(config) { '. This will block *all* dependencies from being updated due to presence of lock file.'; } results = [result]; - if (config.depName[0] === '@') { - logger.info(result.message); - } else { - logger.warn(result.message); - } + logger.warn(result.message); } logger.debug({ results }, `${config.depName} lookup results`); // Flatten the result on top of config, add repositoryUrl diff --git a/lib/workers/repository/apis.js b/lib/workers/repository/apis.js index 55bfb09168..69ad08c397 100644 --- a/lib/workers/repository/apis.js +++ b/lib/workers/repository/apis.js @@ -9,11 +9,10 @@ const presets = require('../../config/presets'); // API const githubApi = require('../../api/github'); const gitlabApi = require('../../api/gitlab'); -const npmApi = require('../../api/npm'); module.exports = { detectSemanticCommits, - setNpmrc, + getNpmrc, initApis, mergeRenovateJson, checkForLerna, @@ -37,16 +36,17 @@ async function detectSemanticCommits(config) { } // Check for .npmrc in repository and pass it to npm api if found -async function setNpmrc(config) { +async function getNpmrc(config) { + let npmrc; try { - const npmrcContent = await config.api.getFileContent('.npmrc'); - if (npmrcContent) { + npmrc = await config.api.getFileContent('.npmrc'); + if (npmrc) { config.logger.debug('Found .npmrc file in repository'); - npmApi.setNpmrc(npmrcContent); } } catch (err) { config.logger.error('Failed to set .npmrc'); } + return { ...config, npmrc }; } async function checkForLerna(config) { @@ -95,8 +95,7 @@ async function initApis(inputConfig, token) { if (config.semanticCommits === null) { config.semanticCommits = await module.exports.detectSemanticCommits(config); } - await module.exports.setNpmrc(config); - return config; + return module.exports.getNpmrc(config); } function migrateAndValidate(config, input) { @@ -271,10 +270,16 @@ async function resolvePackageFiles(inputConfig) { path.join(path.dirname(packageFile.packageFile), '.npmrc'), config.baseBranch ); + if (!packageFile.npmrc) { + delete packageFile.npmrc; + } packageFile.yarnrc = await config.api.getFileContent( path.join(path.dirname(packageFile.packageFile), '.yarnrc'), config.baseBranch ); + if (!packageFile.yarnrc) { + delete packageFile.yarnrc; + } if (packageFile.content) { // check for workspaces if ( diff --git a/lib/workers/repository/upgrades.js b/lib/workers/repository/upgrades.js index 07ff5ffaed..64d6a0a7be 100644 --- a/lib/workers/repository/upgrades.js +++ b/lib/workers/repository/upgrades.js @@ -146,7 +146,6 @@ function getPackageFileConfig(repoConfig, index) { repoConfig, packageFile ); - repoConfig.logger.trace({ config: repoConfig }, 'repoConfig'); packageFileConfig.logger = packageFileConfig.logger.child({ repository: packageFileConfig.repository, packageFile: packageFileConfig.packageFile, diff --git a/test/config/__snapshots__/massage.spec.js.snap b/test/config/__snapshots__/massage.spec.js.snap index 1d7df63798..5b3b9202f9 100644 --- a/test/config/__snapshots__/massage.spec.js.snap +++ b/test/config/__snapshots__/massage.spec.js.snap @@ -1,3 +1,10 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`config/massage massageConfig massages npmToken 1`] = ` +Object { + "npmrc": "//registry.npmjs.org/:_authToken=some-token +", +} +`; + exports[`config/massage massageConfig returns empty 1`] = `Object {}`; diff --git a/test/config/massage.spec.js b/test/config/massage.spec.js index 8bcf47466d..fa8bb4ec5a 100644 --- a/test/config/massage.spec.js +++ b/test/config/massage.spec.js @@ -14,5 +14,11 @@ describe('config/massage', () => { const res = massage.massageConfig(config); expect(Array.isArray(res.schedule)).toBe(true); }); + it('massages npmToken', () => { + const config = { + npmToken: 'some-token', + }; + expect(massage.massageConfig(config)).toMatchSnapshot(); + }); }); }); diff --git a/test/workers/branch/lock-files.spec.js b/test/workers/branch/lock-files.spec.js index 05cdbd3bf5..16ba4ff814 100644 --- a/test/workers/branch/lock-files.spec.js +++ b/test/workers/branch/lock-files.spec.js @@ -186,9 +186,11 @@ describe('workers/branch/lock-files', () => { fs.remove = jest.fn(); }); it('returns if no packageFiles', async () => { + config.npmrc = 'some-npmrc'; + config.yarnrc = 'some-yarnrc'; delete config.packageFiles; await writeExistingFiles(config); - expect(fs.outputFile.mock.calls).toHaveLength(0); + expect(fs.outputFile.mock.calls).toHaveLength(2); }); it('writes files and removes files', async () => { config.packageFiles = [ diff --git a/test/workers/package/__snapshots__/index.spec.js.snap b/test/workers/package/__snapshots__/index.spec.js.snap index ec40674aae..3cf042d22d 100644 --- a/test/workers/package/__snapshots__/index.spec.js.snap +++ b/test/workers/package/__snapshots__/index.spec.js.snap @@ -5,6 +5,8 @@ Array [ "description", "timezone", "schedule", + "npmrc", + "yarnrc", "packageFiles", "branchPrefix", "semanticCommits", @@ -40,6 +42,8 @@ Array [ "description", "timezone", "schedule", + "npmrc", + "yarnrc", "packageFiles", "branchPrefix", "semanticCommits", @@ -153,6 +157,7 @@ This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](ht "labels": Array [], "lazyGrouping": true, "message": "Failed to look up dependency. This will block *all* dependencies from being updated due to presence of lock file.", + "npmrc": null, "packageFiles": Array [], "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request {{#if isRollback}}rolls back{{else}}updates{{/if}} dependency {{#if repositoryUrl}}[{{depName}}]({{repositoryUrl}}){{else}}\`{{depName}}\`{{/if}} from \`v{{currentVersion}}\` to \`v{{newVersion}}\`{{#if isRollback}}. This is necessary and important because \`v{{currentVersion}}\` cannot be found in the npm registry - probably because of it being unpublished.{{/if}} {{#if releases.length}} @@ -220,6 +225,7 @@ This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](ht "timezone": null, "type": "error", "unpublishSafe": false, + "yarnrc": null, }, ] `; @@ -307,6 +313,7 @@ This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](ht "labels": Array [], "lazyGrouping": true, "message": "Failed to look up dependency", + "npmrc": null, "packageFiles": Array [], "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request {{#if isRollback}}rolls back{{else}}updates{{/if}} dependency {{#if repositoryUrl}}[{{depName}}]({{repositoryUrl}}){{else}}\`{{depName}}\`{{/if}} from \`v{{currentVersion}}\` to \`v{{newVersion}}\`{{#if isRollback}}. This is necessary and important because \`v{{currentVersion}}\` cannot be found in the npm registry - probably because of it being unpublished.{{/if}} {{#if releases.length}} @@ -374,6 +381,7 @@ This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](ht "timezone": null, "type": "error", "unpublishSafe": false, + "yarnrc": null, }, ] `; diff --git a/test/workers/repository/__snapshots__/apis.spec.js.snap b/test/workers/repository/__snapshots__/apis.spec.js.snap index f3a1a1a96d..7af498776c 100644 --- a/test/workers/repository/__snapshots__/apis.spec.js.snap +++ b/test/workers/repository/__snapshots__/apis.spec.js.snap @@ -99,18 +99,14 @@ Array [ "errors": Array [], "hasPackageLock": true, "hasYarnLock": true, - "npmrc": null, "packageFile": "package.json", "warnings": Array [], - "yarnrc": null, }, Object { "content": Object {}, "hasPackageLock": false, "hasYarnLock": false, - "npmrc": null, "packageFile": "a/package.json", - "yarnrc": null, }, ] `; diff --git a/test/workers/repository/apis.spec.js b/test/workers/repository/apis.spec.js index 346eee59e4..24da3950d6 100644 --- a/test/workers/repository/apis.spec.js +++ b/test/workers/repository/apis.spec.js @@ -14,14 +14,14 @@ jest.mock('../../../lib/api/gitlab'); jest.mock('../../../lib/api/npm'); describe('workers/repository/apis', () => { - describe('setNpmrc(config)', () => { + describe('getNpmrc', () => { it('Skips if npmrc not found', async () => { const config = { api: { getFileContent: jest.fn(), }, }; - await apis.setNpmrc(config); + expect(await apis.getNpmrc(config)).toMatchObject(config); }); it('Parses if npmrc found', async () => { const config = { @@ -30,7 +30,8 @@ describe('workers/repository/apis', () => { }, logger, }; - await apis.setNpmrc(config); + const res = await apis.getNpmrc(config); + expect(res.npmrc).toEqual('a = b'); }); it('Catches errors', async () => { const config = { @@ -41,7 +42,7 @@ describe('workers/repository/apis', () => { }, logger, }; - await apis.setNpmrc(config); + expect(await apis.getNpmrc(config)).toMatchObject(config); }); }); describe('detectSemanticCommits', () => { -- GitLab