diff --git a/lib/modules/platform/azure/index.spec.ts b/lib/modules/platform/azure/index.spec.ts index c234df87956723760c9fbdd3b7407715556039a9..08774ad666b73fd29c83ce5a2252572c4864f5d3 100644 --- a/lib/modules/platform/azure/index.spec.ts +++ b/lib/modules/platform/azure/index.spec.ts @@ -1087,10 +1087,11 @@ describe('modules/platform/azure/index', () => { describe('massageMarkdown(input)', () => { it('returns updated pr body', () => { - const input = - '\n---\n\n - [ ] <!-- rebase-check --> rebase\nplus also [a link](https://github.com/foo/bar/issues/5)'; - expect(azure.massageMarkdown(input)).toMatchInlineSnapshot( - `"plus also [a link](https://github.com/foo/bar/issues/5)"` + const prBody = + '\n---\n\n - [ ] <!-- rebase-check --> rebase\n<!--renovate-config-hash:-->' + + 'plus also [a link](https://github.com/foo/bar/issues/5)'; + expect(azure.massageMarkdown(prBody)).toBe( + 'plus also [a link](https://github.com/foo/bar/issues/5)' ); }); }); diff --git a/lib/modules/platform/azure/index.ts b/lib/modules/platform/azure/index.ts index 51191062354e8afbd255b716ed4a54ba7b505e41..0730237afb6dc7d96bf14fbe638b76c1d871cd90 100644 --- a/lib/modules/platform/azure/index.ts +++ b/lib/modules/platform/azure/index.ts @@ -746,7 +746,7 @@ export function massageMarkdown(input: string): string { 'rename PR to start with "rebase!"' ) .replace(regEx(`\n---\n\n.*?<!-- rebase-check -->.*?\n`), '') - .replace(regEx(/<!--renovate-debug:.*?-->/), ''); + .replace(regEx(/<!--renovate-(?:debug|config-hash):.*?-->/g), ''); } /* istanbul ignore next */ diff --git a/lib/modules/platform/bitbucket/index.spec.ts b/lib/modules/platform/bitbucket/index.spec.ts index 35aef41c28d062a27d868769791e95efb0b96f64..ceb70ab7a7dfe04bed8af5b088412f3074770f42 100644 --- a/lib/modules/platform/bitbucket/index.spec.ts +++ b/lib/modules/platform/bitbucket/index.spec.ts @@ -996,11 +996,10 @@ describe('modules/platform/bitbucket/index', () => { describe('massageMarkdown()', () => { it('returns diff files', () => { - expect( - bitbucket.massageMarkdown( - '<details><summary>foo</summary>bar</details>text<details>' - ) - ).toMatchSnapshot(); + const prBody = + '<details><summary>foo</summary>bar</details>text<details>' + + '\n---\n\n - [ ] <!-- rebase-check --> rebase\n<!--renovate-config-hash:-->'; + expect(bitbucket.massageMarkdown(prBody)).toMatchSnapshot(); }); }); diff --git a/lib/modules/platform/bitbucket/index.ts b/lib/modules/platform/bitbucket/index.ts index b839c2ecdf4a9ef6b645ded12a1d091ee864f5d7..6d63ecf1a2775a108559f2813176308a878566d0 100644 --- a/lib/modules/platform/bitbucket/index.ts +++ b/lib/modules/platform/bitbucket/index.ts @@ -488,7 +488,7 @@ export function massageMarkdown(input: string): string { .replace(regEx(/<\/?details>/g), '') .replace(regEx(`\n---\n\n.*?<!-- rebase-check -->.*?\n`), '') .replace(regEx(/\]\(\.\.\/pull\//g), '](../../pull-requests/') - .replace(regEx(/<!--renovate-debug:.*?-->/), ''); + .replace(regEx(/<!--renovate-(?:debug|config-hash):.*?-->/g), ''); } export async function ensureIssue({ diff --git a/lib/modules/platform/pr-body.spec.ts b/lib/modules/platform/pr-body.spec.ts index 1439ee61569fb6c86d71f016d137026cc7e7a05c..89967f8a31d96fb3e48f31f362eebdfc28a88838 100644 --- a/lib/modules/platform/pr-body.spec.ts +++ b/lib/modules/platform/pr-body.spec.ts @@ -1,3 +1,4 @@ +import hasha from 'hasha'; import { getPrBodyStruct, hashBody } from './pr-body'; describe('modules/platform/pr-body', () => { @@ -47,13 +48,50 @@ describe('modules/platform/pr-body', () => { ); }); - it('returns rebaseRequested flag', () => { - expect(getPrBodyStruct('- [x] <!-- rebase-check -->')).toEqual({ - hash: '023952693e1e00a52a71b65d9b4804bca6ca9f215c20f6e029dbf420f322d541', + it('hashes an undefined body', () => { + // nullish operator branch coverage + const hash = + 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'; + expect(hashBody(undefined)).toBe(hash); + }); + + it('returns rebaseRequested=true flag', () => { + const input = '- [x] <!-- rebase-check -->'; + const hash = hashBody(input); + expect(getPrBodyStruct(input)).toEqual({ + hash, rebaseRequested: true, }); }); + it('returns rebaseRequested=false flag', () => { + const input = '- [ ] <!-- rebase-check -->'; + const hash = hashBody(input); + expect(getPrBodyStruct(input)).toEqual({ + hash, + rebaseRequested: false, + }); + }); + + it('returns rebaseRequested=undefined flag', () => { + const input = '- <!-- rebase-check -->'; + const hash = hashBody(input); + expect(getPrBodyStruct(input)).toEqual({ + hash, + }); + }); + + it('returns raw config hash', () => { + const config = '{}'; + const rawConfigHash = hasha(config, { algorithm: 'sha256' }); + const input = `<!--renovate-config-hash:${rawConfigHash}-->`; + const hash = hashBody(input); + expect(getPrBodyStruct(input)).toEqual({ + hash, + rawConfigHash, + }); + }); + it('strips reviewable section', () => { expect(getPrBodyStruct('foo<!-- Reviewable:start -->bar')).toEqual({ hash: hashBody('foo'), diff --git a/lib/modules/platform/pr-body.ts b/lib/modules/platform/pr-body.ts index 5fe70dd8dd3aea927d4fb1910e7912f5dd958d54..88f28826bcd73a17b4e58918971f94cf744ee755 100644 --- a/lib/modules/platform/pr-body.ts +++ b/lib/modules/platform/pr-body.ts @@ -1,3 +1,4 @@ +import is from '@sindresorhus/is'; import hasha from 'hasha'; import { logger } from '../../logger'; import { stripEmojis } from '../../util/emoji'; @@ -9,6 +10,12 @@ export const prDebugDataRe = regEx( /\n?<!--renovate-debug:(?<payload>.*?)-->\n?/ ); +const renovateConfigHashRe = regEx( + /\n?<!--renovate-config-hash:(?<payload>.*?)-->\n?/ +); + +const prCheckboxRe = regEx(/- (?<checkbox>\[[\sx]]) <!-- rebase-check -->/); + function noWhitespaceOrHeadings(input: string): string { return input.replace(regEx(/\r?\n|\r|\s|#/g), ''); } @@ -28,8 +35,12 @@ export function hashBody(body: string | undefined): string { return result; } -function isRebaseRequested(body: string | undefined): boolean { - return !!body?.includes(`- [x] <!-- rebase-check -->`); +function isRebaseRequested(body: string): boolean | undefined { + const match = prCheckboxRe.exec(body); + if (!match) { + return undefined; + } + return match.groups?.checkbox === '[x]'; } export function getRenovateDebugPayload(body: string): string | undefined { @@ -37,6 +48,11 @@ export function getRenovateDebugPayload(body: string): string | undefined { return match?.groups?.payload; } +export function getRenovateConfigHashPayload(body: string): string | undefined { + const match = renovateConfigHashRe.exec(body); + return match?.groups?.payload; +} + export function getPrBodyStruct( input: string | undefined | null ): PrBodyStruct { @@ -45,10 +61,16 @@ export function getPrBodyStruct( const result: PrBodyStruct = { hash }; const rebaseRequested = isRebaseRequested(body); - if (rebaseRequested) { + + if (!is.undefined(rebaseRequested)) { result.rebaseRequested = rebaseRequested; } + const rawConfigHash = getRenovateConfigHashPayload(body); + if (rawConfigHash) { + result.rawConfigHash = rawConfigHash; + } + const debugPayload = getRenovateDebugPayload(body); if (debugPayload) { try { diff --git a/lib/modules/platform/types.ts b/lib/modules/platform/types.ts index ff2b266f2c814fa3665db3479ea189bbd85c7243..56a625eab08735782527800302c1a04f4c3590be 100644 --- a/lib/modules/platform/types.ts +++ b/lib/modules/platform/types.ts @@ -52,6 +52,7 @@ export interface PrDebugData { export interface PrBodyStruct { hash: string; + rawConfigHash?: string; rebaseRequested?: boolean; debugData?: PrDebugData; }