diff --git a/lib/config/definitions.js b/lib/config/definitions.js index dde22ceab759b46a54f710ac72ee8686cc335a1d..6f8dc3aadf7ad214a1cfc03911a4b9de46be4008 100644 --- a/lib/config/definitions.js +++ b/lib/config/definitions.js @@ -202,7 +202,6 @@ const options = [ { name: 'platform', description: 'Platform type of repository', - stage: 'repository', type: 'string', default: 'github', admin: true, @@ -602,7 +601,12 @@ const options = [ 'Configuration to apply when updating a Docker digest (same tag)', stage: 'package', type: 'json', - default: {}, + default: { + branchTopic: '{{{depNameSanitized}}}-digest', + commitMessageExtra: 'to {{newDigestShort}}', + commitMessageTopic: '{{{depName}}} commit hash', + prBody: template('prBody', 'digest'), + }, cli: false, mergeable: true, }, diff --git a/lib/config/templates/digest/pr-body.hbs b/lib/config/templates/digest/pr-body.hbs new file mode 100644 index 0000000000000000000000000000000000000000..7c1e6ab51bf4587bffb9eb48cf9564daef9a8e1d --- /dev/null +++ b/lib/config/templates/digest/pr-body.hbs @@ -0,0 +1,33 @@ +This Pull Request updates dependency `{{{depName}}}` to the latest sha (`{{{newDigest}}}`). + +If you wish to disable digest updates, add `":disableDigestUpdates" to the `extends` array in your config. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule ("{{{schedule}}}"{{#if timezone}} in timezone `{{{timezone}}}`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +# Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- `{{error.depName}}`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +# Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- `{{warning.depName}}`: {{warning.message}} +{{/each}} +{{/if}} diff --git a/lib/datasource/github.js b/lib/datasource/github.js index 3512506ff58a1efb6c4c76831e09128012db3e20..44f1ba40af0358a835c77e569d40964664dbc4f4 100644 --- a/lib/datasource/github.js +++ b/lib/datasource/github.js @@ -3,6 +3,7 @@ const versioning = require('../versioning'); module.exports = { getPreset, + getDigest, getPkgReleases, }; @@ -36,6 +37,39 @@ function getCacheKey(repo, type) { return `${repo}:${type}`; } +async function getDigest(config) { + const cachedResult = await renovateCache.get( + cacheNamespace, + getCacheKey(config.githubRepo, 'commit') + ); + if (cachedResult) { + return cachedResult; + } + let digest; + try { + const url = `https://api.github.com/repos/${ + config.githubRepo + }/commits?per_page=1`; + digest = (await ghGot(url)).body[0].sha; + } catch (err) { + logger.info( + { githubRepo: config.githubRepo, err }, + 'Error getting latest commit from GitHub repo' + ); + } + if (!digest) { + return null; + } + const cacheMinutes = 10; + await renovateCache.set( + cacheNamespace, + getCacheKey(config.githubRepo, 'commit'), + digest, + cacheMinutes + ); + return digest; +} + async function getPkgReleases(purl, config) { const { versionScheme } = config || {}; const { fullname: repo, qualifiers: options } = purl; diff --git a/lib/manager/npm/extract/index.js b/lib/manager/npm/extract/index.js index 639fdabc31a3bd26ebce2cca10cea395b35e0c17..5cf44ee96b36e59a3fce52602b8b0d7306d2b358 100644 --- a/lib/manager/npm/extract/index.js +++ b/lib/manager/npm/extract/index.js @@ -176,9 +176,22 @@ async function extractDependencies(content, fileName, config) { dep.currentRawValue = dep.currentValue; dep.currentValue = depRefPart; dep.purl = `pkg:github/${githubOwnerRepo}?ref=tags`; + dep.pinDigests = false; + } else if ( + depRefPart.match(/^[0-9a-f]{7}$/) || + depRefPart.match(/^[0-9a-f]{40}$/) + ) { + dep.currentRawValue = dep.currentValue; + dep.currentValue = null; + dep.currentDigest = depRefPart; + dep.purl = `pkg:github/${githubOwnerRepo}`; + } else { + dep.skipReason = 'unversioned-reference'; return dep; } - dep.skipReason = 'unversioned-reference'; + dep.githubRepo = githubOwnerRepo; + dep.repositoryUrl = `https://github.com/${githubOwnerRepo}`; + dep.gitRef = true; return dep; } diff --git a/lib/manager/npm/post-update/index.js b/lib/manager/npm/post-update/index.js index 04dbf257cf28cf9e0f8c078a591cb0af63c9162e..cb451f0e99530b0a2ee9cf6ff4029e414b5c6f53 100644 --- a/lib/manager/npm/post-update/index.js +++ b/lib/manager/npm/post-update/index.js @@ -5,6 +5,7 @@ const npm = require('./npm'); const lerna = require('./lerna'); const yarn = require('./yarn'); const pnpm = require('./pnpm'); +const hostRules = require('../../../util/host-rules'); module.exports = { determineLockFileDirs, @@ -256,6 +257,21 @@ async function writeUpdatedPackageFiles(config) { } delete massagedFile.engines; delete massagedFile.scripts; + try { + const { token } = hostRules.find({ platform: config.platform }); + for (const upgrade of config.upgrades) { + if (upgrade.gitRef && upgrade.packageFile === packageFile.name) { + massagedFile[upgrade.depType][upgrade.depName] = massagedFile[ + upgrade.depType + ][upgrade.depName].replace( + 'git+https://github.com', + `git+https://${token}@github.com` + ); + } + } + } catch (err) { + logger.warn({ err }, 'Error adding token to package files'); + } await fs.outputFile( upath.join(config.localDir, packageFile.name), JSON.stringify(massagedFile) @@ -295,6 +311,13 @@ async function getAdditionalFiles(config, packageFiles) { : { HOME: process.env.HOME, PATH: process.env.PATH }; env.NODE_ENV = 'dev'; + let token = ''; + try { + ({ token } = hostRules.find({ platform: config.platform })); + token += '@'; + } catch (err) { + logger.warn({ err }, 'Error getting token for packageFile'); + } for (const lockFile of dirs.npmLockDirs) { const lockFileDir = path.dirname(lockFile); const fileName = path.basename(lockFile); @@ -341,7 +364,7 @@ async function getAdditionalFiles(config, packageFiles) { logger.debug(`${lockFile} needs updating`); updatedLockFiles.push({ name: lockFile, - contents: res.lockFile, + contents: res.lockFile.replace(new RegExp(`${token}`, 'g'), ''), }); } else { logger.debug(`${lockFile} hasn't changed`); diff --git a/lib/manager/npm/update.js b/lib/manager/npm/update.js index 3b030fab48d70c1919636b1d3ccdedb7522cc011..e518fd67335009386a0b795fc716c760398c3ea0 100644 --- a/lib/manager/npm/update.js +++ b/lib/manager/npm/update.js @@ -10,11 +10,19 @@ function updateDependency(fileContent, upgrade) { const { depType, depName } = upgrade; let { newValue } = upgrade; if (upgrade.currentRawValue) { - logger.info('Replacing package.json git reference'); - newValue = upgrade.currentRawValue.replace( - upgrade.currentValue, - upgrade.newValue - ); + if (upgrade.currentDigest) { + logger.info('Updating package.json git digest'); + newValue = upgrade.currentRawValue.replace( + upgrade.currentDigest, + upgrade.newDigest.substring(0, upgrade.currentDigest.length) + ); + } else { + logger.info('Updating package.json git version tag'); + newValue = upgrade.currentRawValue.replace( + upgrade.currentValue, + upgrade.newValue + ); + } } logger.debug(`npm.updateDependency(): ${depType}.${depName} = ${newValue}`); try { diff --git a/test/datasource/github.spec.js b/test/datasource/github.spec.js index f942a52b1ec448cd3cc9e5858528769763ec088b..4c382e83de57b4bbffd34031af4f100386a3f1f4 100644 --- a/test/datasource/github.spec.js +++ b/test/datasource/github.spec.js @@ -7,6 +7,40 @@ jest.mock('got'); describe('datasource/github', () => { beforeEach(() => global.renovateCache.rmAll()); + describe('getDigest', () => { + beforeEach(() => { + jest.resetAllMocks(); + return global.renovateCache.rmAll(); + }); + it('returns null if no token', async () => { + ghGot.mockReturnValueOnce({ body: [] }); + const res = await github.getDigest( + { depName: 'some-dep', githubRepo: 'some/dep' }, + null + ); + expect(res).toBe(null); + }); + it('returns digest', async () => { + ghGot.mockReturnValueOnce({ body: [{ sha: 'abcdef' }] }); + const res = await github.getDigest( + { depName: 'some-dep', githubRepo: 'some/dep' }, + null + ); + expect(res).toBe('abcdef'); + }); + it('returns cached digest', async () => { + ghGot.mockReturnValueOnce({ body: [{ sha: '12345' }] }); + await github.getDigest( + { depName: 'some-dep', githubRepo: 'some/dep' }, + null + ); + const res = await github.getDigest( + { depName: 'some-dep', githubRepo: 'some/dep' }, + null + ); + expect(res).toBe('12345'); + }); + }); describe('getPreset()', () => { it('throws if non-default', async () => { await expect( diff --git a/test/manager/npm/__snapshots__/update.spec.js.snap b/test/manager/npm/__snapshots__/update.spec.js.snap index 62a8a6473e6a884eaab5dadd552cb561f955c62a..95785e2f7e0f978cdb267678ab1b674b9d08ffd3 100644 --- a/test/manager/npm/__snapshots__/update.spec.js.snap +++ b/test/manager/npm/__snapshots__/update.spec.js.snap @@ -7,3 +7,5 @@ exports[`workers/branch/package-json .bumpPackageVersion() updates 1`] = `"{\\"n exports[`workers/branch/package-json .updateDependency(fileContent, depType, depName, newValue) replaces a github dependency value 1`] = `"{\\"dependencies\\":{\\"gulp\\":\\"gulpjs/gulp#v4.0.0\\"}}"`; exports[`workers/branch/package-json .updateDependency(fileContent, depType, depName, newValue) replaces a github fully specified version 1`] = `"{\\"dependencies\\":{\\"n\\":\\"git+https://github.com/owner/n#v1.1.0\\"}}"`; + +exports[`workers/branch/package-json .updateDependency(fileContent, depType, depName, newValue) replaces a github short hash 1`] = `"{\\"dependencies\\":{\\"gulp\\":\\"gulpjs/gulp#0000000\\"}}"`; diff --git a/test/manager/npm/extract/__snapshots__/index.spec.js.snap b/test/manager/npm/extract/__snapshots__/index.spec.js.snap index f08a8bf20f861bb75ebcf4339d07b48351f9fffe..9e52a784e130f54ea9a78a055977010940d96725 100644 --- a/test/manager/npm/extract/__snapshots__/index.spec.js.snap +++ b/test/manager/npm/extract/__snapshots__/index.spec.js.snap @@ -133,8 +133,12 @@ Object { "currentValue": "v1.1.0", "depName": "c", "depType": "dependencies", + "gitRef": true, + "githubRepo": "owner/c", + "pinDigests": false, "prettyDepType": "dependency", "purl": "pkg:github/owner/c?ref=tags", + "repositoryUrl": "https://github.com/owner/c", "versionScheme": "semver", }, Object { @@ -146,11 +150,16 @@ Object { "versionScheme": "semver", }, Object { - "currentValue": "github:owner/e#49b5aca613b33c5b626ae68c03a385f25c142f55", + "currentDigest": "49b5aca613b33c5b626ae68c03a385f25c142f55", + "currentRawValue": "github:owner/e#49b5aca613b33c5b626ae68c03a385f25c142f55", + "currentValue": null, "depName": "e", "depType": "dependencies", + "gitRef": true, + "githubRepo": "owner/e", "prettyDepType": "dependency", - "skipReason": "unversioned-reference", + "purl": "pkg:github/owner/e", + "repositoryUrl": "https://github.com/owner/e", "versionScheme": "semver", }, Object { @@ -158,8 +167,12 @@ Object { "currentValue": "v2.0.0", "depName": "f", "depType": "dependencies", + "gitRef": true, + "githubRepo": "owner/f", + "pinDigests": false, "prettyDepType": "dependency", "purl": "pkg:github/owner/f?ref=tags", + "repositoryUrl": "https://github.com/owner/f", "versionScheme": "semver", }, Object { @@ -195,19 +208,29 @@ Object { "versionScheme": "semver", }, Object { - "currentValue": "github:owner/k#49b5aca", + "currentDigest": "49b5aca", + "currentRawValue": "github:owner/k#49b5aca", + "currentValue": null, "depName": "k", "depType": "dependencies", + "gitRef": true, + "githubRepo": "owner/k", "prettyDepType": "dependency", - "skipReason": "unversioned-reference", + "purl": "pkg:github/owner/k", + "repositoryUrl": "https://github.com/owner/k", "versionScheme": "semver", }, Object { - "currentValue": "github:owner/l.git#abcdef0", + "currentDigest": "abcdef0", + "currentRawValue": "github:owner/l.git#abcdef0", + "currentValue": null, "depName": "l", "depType": "dependencies", + "gitRef": true, + "githubRepo": "owner/l", "prettyDepType": "dependency", - "skipReason": "unversioned-reference", + "purl": "pkg:github/owner/l", + "repositoryUrl": "https://github.com/owner/l", "versionScheme": "semver", }, Object { @@ -215,8 +238,12 @@ Object { "currentValue": "v1.0.0", "depName": "m", "depType": "dependencies", + "gitRef": true, + "githubRepo": "owner/m", + "pinDigests": false, "prettyDepType": "dependency", "purl": "pkg:github/owner/m?ref=tags", + "repositoryUrl": "https://github.com/owner/m", "versionScheme": "semver", }, Object { @@ -224,8 +251,12 @@ Object { "currentValue": "v2.0.0", "depName": "n", "depType": "dependencies", + "gitRef": true, + "githubRepo": "owner/n", + "pinDigests": false, "prettyDepType": "dependency", "purl": "pkg:github/owner/n?ref=tags", + "repositoryUrl": "https://github.com/owner/n", "versionScheme": "semver", }, ], diff --git a/test/manager/npm/update.spec.js b/test/manager/npm/update.spec.js index 93fc10fe2832842d3dca8790c8ef655822cf4f43..b53582f58ce1b6bb05227f6c8c53dbc4b608925d 100644 --- a/test/manager/npm/update.spec.js +++ b/test/manager/npm/update.spec.js @@ -40,6 +40,22 @@ describe('workers/branch/package-json', () => { const res = npmUpdater.updateDependency(input, upgrade); expect(res).toMatchSnapshot(); }); + it('replaces a github short hash', () => { + const upgrade = { + depType: 'dependencies', + depName: 'gulp', + currentDigest: 'abcdef7', + currentRawValue: 'gulpjs/gulp#abcdef7', + newDigest: '0000000000111111111122222222223333333333', + }; + const input = JSON.stringify({ + dependencies: { + gulp: 'gulpjs/gulp#abcdef7', + }, + }); + const res = npmUpdater.updateDependency(input, upgrade); + expect(res).toMatchSnapshot(); + }); it('replaces a github fully specified version', () => { const upgrade = { depType: 'dependencies', diff --git a/test/workers/branch/lock-files/index.spec.js b/test/workers/branch/lock-files/index.spec.js index 6767c1fdaa0fe26b6f00aeaacb93092f2457b76b..c07a9c9ea84f6ef60557c2ea0a9cb200291fc007 100644 --- a/test/workers/branch/lock-files/index.spec.js +++ b/test/workers/branch/lock-files/index.spec.js @@ -8,6 +8,10 @@ const yarn = require('../../../../lib/manager/npm/post-update/yarn'); const pnpm = require('../../../../lib/manager/npm/post-update/pnpm'); const lerna = require('../../../../lib/manager/npm/post-update/lerna'); +const hostRules = require('../../../../lib/util/host-rules'); + +hostRules.find = jest.fn(() => 'token-abc'); + const { // determineLockFileDirs, // writeExistingFiles, @@ -275,6 +279,7 @@ describe('manager/npm/post-update', () => { '{ "name": "some-other-name", "engines": { "node": "^6.0.0" }}', }, ]; + config.upgrades = []; await writeUpdatedPackageFiles(config); expect(fs.outputFile.mock.calls).toHaveLength(2); expect(fs.outputFile.mock.calls[1][1].includes('"engines"')).toBe(false); diff --git a/test/workers/repository/updates/__snapshots__/flatten.spec.js.snap b/test/workers/repository/updates/__snapshots__/flatten.spec.js.snap index 865e28a287990f899f945beaa6fadcd441d1c419..50debd4670622ed828830fbb7bd421bae345b5d6 100644 --- a/test/workers/repository/updates/__snapshots__/flatten.spec.js.snap +++ b/test/workers/repository/updates/__snapshots__/flatten.spec.js.snap @@ -40,6 +40,7 @@ Array [ "npmToken": null, "npmrc": null, "packageFile": "package.json", + "platform": "github", "prBody": "This Pull Request {{#if isRollback}}rolls back{{else}}updates{{/if}} {{#if prettyDepType}}{{{prettyDepType}}}{{else}}dependency{{/if}} \`{{{depName}}}\` {{#if hasUrls}}({{#if homepage}}[homepage]({{{homepage}}}){{#if repositoryUrl}}, [source]({{{repositoryUrl}}}){{/if}}{{else}}[source]({{{repositoryUrl}}}){{/if}}{{#if changelogUrl}}, [changelog]({{{changelogUrl}}}){{/if}}){{/if}} from \`{{#unless isRange}}{{#unless isPin}}v{{/unless}}{{/unless}}{{{currentValue}}}\` to \`{{#unless isRange}}v{{/unless}}{{{newValue}}}\`{{#if isRollback}}. This is necessary and important because \`v{{{currentValue}}}\` cannot currently be found in the package's registry.{{/if}}\\n{{#if hasTypes}}\\n\\nThis PR also includes an upgrade to the corresponding [@types/{{{depName}}}](https://npmjs.com/package/@types/{{{depName}}}) package.\\n{{/if}}\\n{{#if releases.length}}\\n\\n{{#if schedule}}\\n**Note**: This PR was created on a configured schedule (\\"{{{schedule}}}\\"{{#if timezone}} in timezone \`{{{timezone}}}\`{{/if}}) and will not receive updates outside those times.\\n{{/if}}\\n\\n{{#if isPin}}\\n**Important**: Renovate will wait until you have merged this Pin request before creating PRs for any *upgrades*. If you do not wish to pin anything, please update your config accordingly instead of leaving this PR open.\\n{{/if}}\\n{{#if hasReleaseNotes}}\\n\\n<details>\\n<summary>Release Notes</summary>\\n\\n{{#each releases as |release|}}\\n{{#if release.releaseNotes}}\\n### [{{#if release.releaseNotes.name}}{{{release.releaseNotes.name}}}{{else}}\`v{{{release.version}}}\`{{/if}}]({{{release.releaseNotes.url}}})\\n{{#if release.compare.url}}\\n[Compare Source]({{release.compare.url}})\\n\\n{{/if}}\\n{{{release.releaseNotes.body}}}\\n\\n---\\n\\n{{/if}}\\n{{/each}}\\n</details>\\n{{/if}}\\n\\n{{/if}}\\n\\n{{#if hasErrors}}\\n\\n---\\n\\n# Errors\\n\\nRenovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR.\\n\\n{{#each errors as |error|}}\\n- \`{{error.depName}}\`: {{error.message}}\\n{{/each}}\\n{{/if}}\\n\\n{{#if hasWarnings}}\\n\\n---\\n\\n# Warnings\\n\\nPlease make sure the following warnings are safe to ignore:\\n\\n{{#each warnings as |warning|}}\\n- \`{{warning.depName}}\`: {{warning.message}}\\n{{/each}}\\n{{/if}}", "prConcurrentLimit": 0, "prCreation": "immediate", @@ -112,6 +113,7 @@ Array [ "npmToken": null, "npmrc": null, "packageFile": "package.json", + "platform": "github", "prBody": "This Pull Request {{#if isRollback}}rolls back{{else}}updates{{/if}} {{#if prettyDepType}}{{{prettyDepType}}}{{else}}dependency{{/if}} \`{{{depName}}}\` {{#if hasUrls}}({{#if homepage}}[homepage]({{{homepage}}}){{#if repositoryUrl}}, [source]({{{repositoryUrl}}}){{/if}}{{else}}[source]({{{repositoryUrl}}}){{/if}}{{#if changelogUrl}}, [changelog]({{{changelogUrl}}}){{/if}}){{/if}} from \`{{#unless isRange}}{{#unless isPin}}v{{/unless}}{{/unless}}{{{currentValue}}}\` to \`{{#unless isRange}}v{{/unless}}{{{newValue}}}\`{{#if isRollback}}. This is necessary and important because \`v{{{currentValue}}}\` cannot currently be found in the package's registry.{{/if}}\\n{{#if hasTypes}}\\n\\nThis PR also includes an upgrade to the corresponding [@types/{{{depName}}}](https://npmjs.com/package/@types/{{{depName}}}) package.\\n{{/if}}\\n{{#if releases.length}}\\n\\n{{#if schedule}}\\n**Note**: This PR was created on a configured schedule (\\"{{{schedule}}}\\"{{#if timezone}} in timezone \`{{{timezone}}}\`{{/if}}) and will not receive updates outside those times.\\n{{/if}}\\n\\n{{#if isPin}}\\n**Important**: Renovate will wait until you have merged this Pin request before creating PRs for any *upgrades*. If you do not wish to pin anything, please update your config accordingly instead of leaving this PR open.\\n{{/if}}\\n{{#if hasReleaseNotes}}\\n\\n<details>\\n<summary>Release Notes</summary>\\n\\n{{#each releases as |release|}}\\n{{#if release.releaseNotes}}\\n### [{{#if release.releaseNotes.name}}{{{release.releaseNotes.name}}}{{else}}\`v{{{release.version}}}\`{{/if}}]({{{release.releaseNotes.url}}})\\n{{#if release.compare.url}}\\n[Compare Source]({{release.compare.url}})\\n\\n{{/if}}\\n{{{release.releaseNotes.body}}}\\n\\n---\\n\\n{{/if}}\\n{{/each}}\\n</details>\\n{{/if}}\\n\\n{{/if}}\\n\\n{{#if hasErrors}}\\n\\n---\\n\\n# Errors\\n\\nRenovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR.\\n\\n{{#each errors as |error|}}\\n- \`{{error.depName}}\`: {{error.message}}\\n{{/each}}\\n{{/if}}\\n\\n{{#if hasWarnings}}\\n\\n---\\n\\n# Warnings\\n\\nPlease make sure the following warnings are safe to ignore:\\n\\n{{#each warnings as |warning|}}\\n- \`{{warning.depName}}\`: {{warning.message}}\\n{{/each}}\\n{{/if}}", "prConcurrentLimit": 0, "prCreation": "immediate", @@ -181,6 +183,7 @@ Array [ "npmToken": null, "npmrc": null, "packageFile": "package.json", + "platform": "github", "prBody": "This Pull Request updates \`package.json\` lock files to use the latest dependency versions.\\n\\n{{#if schedule}}\\n**Note**: This PR was created on a configured schedule (\\"{{{schedule}}}\\"{{#if timezone}} in timezone \`{{{timezone}}}\`{{/if}}) and will not receive updates outside those times.\\n{{/if}}\\n\\n{{#if hasErrors}}\\n\\n---\\n\\n# Errors\\n\\nRenovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR.\\n\\n{{#each errors as |error|}}\\n- \`{{error.depName}}\`: {{error.message}}\\n{{/each}}\\n{{/if}}\\n\\n{{#if hasWarnings}}\\n\\n---\\n\\n# Warnings\\n\\nPlease make sure the following warnings are safe to ignore:\\n\\n{{#each warnings as |warning|}}\\n- \`{{warning.depName}}\`: {{warning.message}}\\n{{/each}}\\n{{/if}}", "prConcurrentLimit": 0, "prCreation": "immediate", @@ -256,6 +259,7 @@ Array [ "npmToken": null, "npmrc": null, "packageFile": "backend/package.json", + "platform": "github", "prBody": "This Pull Request {{#if isRollback}}rolls back{{else}}updates{{/if}} {{#if prettyDepType}}{{{prettyDepType}}}{{else}}dependency{{/if}} \`{{{depName}}}\` {{#if hasUrls}}({{#if homepage}}[homepage]({{{homepage}}}){{#if repositoryUrl}}, [source]({{{repositoryUrl}}}){{/if}}{{else}}[source]({{{repositoryUrl}}}){{/if}}{{#if changelogUrl}}, [changelog]({{{changelogUrl}}}){{/if}}){{/if}} from \`{{#unless isRange}}{{#unless isPin}}v{{/unless}}{{/unless}}{{{currentValue}}}\` to \`{{#unless isRange}}v{{/unless}}{{{newValue}}}\`{{#if isRollback}}. This is necessary and important because \`v{{{currentValue}}}\` cannot currently be found in the package's registry.{{/if}}\\n{{#if hasTypes}}\\n\\nThis PR also includes an upgrade to the corresponding [@types/{{{depName}}}](https://npmjs.com/package/@types/{{{depName}}}) package.\\n{{/if}}\\n{{#if releases.length}}\\n\\n{{#if schedule}}\\n**Note**: This PR was created on a configured schedule (\\"{{{schedule}}}\\"{{#if timezone}} in timezone \`{{{timezone}}}\`{{/if}}) and will not receive updates outside those times.\\n{{/if}}\\n\\n{{#if isPin}}\\n**Important**: Renovate will wait until you have merged this Pin request before creating PRs for any *upgrades*. If you do not wish to pin anything, please update your config accordingly instead of leaving this PR open.\\n{{/if}}\\n{{#if hasReleaseNotes}}\\n\\n<details>\\n<summary>Release Notes</summary>\\n\\n{{#each releases as |release|}}\\n{{#if release.releaseNotes}}\\n### [{{#if release.releaseNotes.name}}{{{release.releaseNotes.name}}}{{else}}\`v{{{release.version}}}\`{{/if}}]({{{release.releaseNotes.url}}})\\n{{#if release.compare.url}}\\n[Compare Source]({{release.compare.url}})\\n\\n{{/if}}\\n{{{release.releaseNotes.body}}}\\n\\n---\\n\\n{{/if}}\\n{{/each}}\\n</details>\\n{{/if}}\\n\\n{{/if}}\\n\\n{{#if hasErrors}}\\n\\n---\\n\\n# Errors\\n\\nRenovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR.\\n\\n{{#each errors as |error|}}\\n- \`{{error.depName}}\`: {{error.message}}\\n{{/each}}\\n{{/if}}\\n\\n{{#if hasWarnings}}\\n\\n---\\n\\n# Warnings\\n\\nPlease make sure the following warnings are safe to ignore:\\n\\n{{#each warnings as |warning|}}\\n- \`{{warning.depName}}\`: {{warning.message}}\\n{{/each}}\\n{{/if}}", "prConcurrentLimit": 0, "prCreation": "immediate", @@ -325,6 +329,7 @@ Array [ "npmToken": null, "npmrc": null, "packageFile": "backend/package.json", + "platform": "github", "prBody": "This Pull Request updates \`package.json\` lock files to use the latest dependency versions.\\n\\n{{#if schedule}}\\n**Note**: This PR was created on a configured schedule (\\"{{{schedule}}}\\"{{#if timezone}} in timezone \`{{{timezone}}}\`{{/if}}) and will not receive updates outside those times.\\n{{/if}}\\n\\n{{#if hasErrors}}\\n\\n---\\n\\n# Errors\\n\\nRenovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR.\\n\\n{{#each errors as |error|}}\\n- \`{{error.depName}}\`: {{error.message}}\\n{{/each}}\\n{{/if}}\\n\\n{{#if hasWarnings}}\\n\\n---\\n\\n# Warnings\\n\\nPlease make sure the following warnings are safe to ignore:\\n\\n{{#each warnings as |warning|}}\\n- \`{{warning.depName}}\`: {{warning.message}}\\n{{/each}}\\n{{/if}}", "prConcurrentLimit": 0, "prCreation": "immediate", @@ -400,6 +405,7 @@ Array [ "npmToken": null, "npmrc": null, "packageFile": "frontend/package.json", + "platform": "github", "prBody": "This Pull Request {{#if isRollback}}rolls back{{else}}updates{{/if}} {{#if prettyDepType}}{{{prettyDepType}}}{{else}}dependency{{/if}} \`{{{depName}}}\` {{#if hasUrls}}({{#if homepage}}[homepage]({{{homepage}}}){{#if repositoryUrl}}, [source]({{{repositoryUrl}}}){{/if}}{{else}}[source]({{{repositoryUrl}}}){{/if}}{{#if changelogUrl}}, [changelog]({{{changelogUrl}}}){{/if}}){{/if}} from \`{{#unless isRange}}{{#unless isPin}}v{{/unless}}{{/unless}}{{{currentValue}}}\` to \`{{#unless isRange}}v{{/unless}}{{{newValue}}}\`{{#if isRollback}}. This is necessary and important because \`v{{{currentValue}}}\` cannot currently be found in the package's registry.{{/if}}\\n{{#if hasTypes}}\\n\\nThis PR also includes an upgrade to the corresponding [@types/{{{depName}}}](https://npmjs.com/package/@types/{{{depName}}}) package.\\n{{/if}}\\n{{#if releases.length}}\\n\\n{{#if schedule}}\\n**Note**: This PR was created on a configured schedule (\\"{{{schedule}}}\\"{{#if timezone}} in timezone \`{{{timezone}}}\`{{/if}}) and will not receive updates outside those times.\\n{{/if}}\\n\\n{{#if isPin}}\\n**Important**: Renovate will wait until you have merged this Pin request before creating PRs for any *upgrades*. If you do not wish to pin anything, please update your config accordingly instead of leaving this PR open.\\n{{/if}}\\n{{#if hasReleaseNotes}}\\n\\n<details>\\n<summary>Release Notes</summary>\\n\\n{{#each releases as |release|}}\\n{{#if release.releaseNotes}}\\n### [{{#if release.releaseNotes.name}}{{{release.releaseNotes.name}}}{{else}}\`v{{{release.version}}}\`{{/if}}]({{{release.releaseNotes.url}}})\\n{{#if release.compare.url}}\\n[Compare Source]({{release.compare.url}})\\n\\n{{/if}}\\n{{{release.releaseNotes.body}}}\\n\\n---\\n\\n{{/if}}\\n{{/each}}\\n</details>\\n{{/if}}\\n\\n{{/if}}\\n\\n{{#if hasErrors}}\\n\\n---\\n\\n# Errors\\n\\nRenovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR.\\n\\n{{#each errors as |error|}}\\n- \`{{error.depName}}\`: {{error.message}}\\n{{/each}}\\n{{/if}}\\n\\n{{#if hasWarnings}}\\n\\n---\\n\\n# Warnings\\n\\nPlease make sure the following warnings are safe to ignore:\\n\\n{{#each warnings as |warning|}}\\n- \`{{warning.depName}}\`: {{warning.message}}\\n{{/each}}\\n{{/if}}", "prConcurrentLimit": 0, "prCreation": "immediate", @@ -472,6 +478,7 @@ Array [ "npmToken": null, "npmrc": null, "packageFile": "Dockerfile", + "platform": "github", "prBody": "This Pull Request updates Docker base image \`{{{depName}}}\` from tag \`{{{currentTag}}}\` to new tag \`{{{newValue}}}{{#if tagSuffix}}-{{{tagSuffix}}}{{/if}}\`. For details on Renovate's Docker support, please visit https://renovatebot.com/docs/docker\\n\\n{{#if schedule}}\\n**Note**: This PR was created on a configured schedule (\\"{{{schedule}}}\\"{{#if timezone}} in timezone \`{{{timezone}}}\`{{/if}}) and will not receive updates outside those times.\\n{{/if}}\\n\\n{{#if hasErrors}}\\n\\n---\\n\\n# Errors\\n\\nRenovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR.\\n\\n{{#each errors as |error|}}\\n- \`{{error.depName}}\`: {{error.message}}\\n{{/each}}\\n{{/if}}\\n\\n{{#if hasWarnings}}\\n\\n---\\n\\n# Warnings\\n\\nPlease make sure the following warnings are safe to ignore:\\n\\n{{#each warnings as |warning|}}\\n- \`{{warning.depName}}\`: {{warning.message}}\\n{{/each}}\\n{{/if}}", "prConcurrentLimit": 0, "prCreation": "immediate", @@ -544,6 +551,7 @@ Array [ "npmToken": null, "npmrc": null, "packageFile": "Dockerfile", + "platform": "github", "prBody": "This Pull Request updates Docker base image \`{{{depName}}}\` from tag \`{{{currentTag}}}\` to new tag \`{{{newValue}}}{{#if tagSuffix}}-{{{tagSuffix}}}{{/if}}\`. For details on Renovate's Docker support, please visit https://renovatebot.com/docs/docker\\n\\n{{#if schedule}}\\n**Note**: This PR was created on a configured schedule (\\"{{{schedule}}}\\"{{#if timezone}} in timezone \`{{{timezone}}}\`{{/if}}) and will not receive updates outside those times.\\n{{/if}}\\n\\n{{#if hasErrors}}\\n\\n---\\n\\n# Errors\\n\\nRenovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR.\\n\\n{{#each errors as |error|}}\\n- \`{{error.depName}}\`: {{error.message}}\\n{{/each}}\\n{{/if}}\\n\\n{{#if hasWarnings}}\\n\\n---\\n\\n# Warnings\\n\\nPlease make sure the following warnings are safe to ignore:\\n\\n{{#each warnings as |warning|}}\\n- \`{{warning.depName}}\`: {{warning.message}}\\n{{/each}}\\n{{/if}}", "prConcurrentLimit": 0, "prCreation": "immediate",