Files
renovate/lib/util/git/commit-trailers.spec.ts
T
Felipe Santos d32e38ec2b fix(github): include commitTrailers in platform-native commits (#44918)
* fix(github): include commitTrailers in platform-native commits

The GitHub platform-native commit path (platformCommit) recreates the
commit via the REST API using only message, so trailers from
commitTrailers / :gitSignOff were dropped even though prepareCommit
wrote them into the local commit.

* test: use codeBlock for multi-line commit trailer expectations

* Remove unnecessary comment

* refactor(gerrit): format commit message with shared helper

Use formatCommitMessage for Gerrit reserved trailers so the final
message is built the same way as the git and GitHub platform-native
paths, then clear trailers so prepareCommit does not append them twice.

* Revert "refactor(gerrit): format commit message with shared helper"

This reverts commit d230fa3802.

* refactor(git): fold commit trailers into the message before scm

Remove CommitFilesConfig.trailers so platforms only ever see a fully
formatted message. Workers call formatCommitMessage once; prepareCommit
and GitHub platform-native commits pass message through as-is. Gerrit
parses the existing trailer block to merge Renovate-Branch/Change-Id.

* refactor(git): drop formatCommitMessage helper

Trailers are already folded into message at the worker boundary, so the
shared formatter only re-joined strings. Inline that at the few call sites
and keep splitCommitMessage for Gerrit's reserved-trailer merge.

* revert: keep the minimal commitTrailers platform-native fix

Drop the later refactors (fold trailers into message, Gerrit changes,
splitCommitMessage). Keep formatCommitMessage shared by prepareCommit
and GitHub platform-native commits only; Gerrit is unchanged.
2026-07-29 06:16:44 +00:00

119 lines
3.5 KiB
TypeScript

import { codeBlock } from 'common-tags';
import { logger } from '~test/util.ts';
import {
filterValidCommitTrailers,
formatCommitMessage,
isValidCommitTrailer,
} from './commit-trailers.ts';
describe('util/git/commit-trailers', () => {
describe('isValidCommitTrailer', () => {
it.each([
'Signed-off-by: Renovate Bot <bot@renovateapp.com>',
'Signed-off-by: {{{gitAuthor}}}',
'Co-authored-by: First Contributor <first@example.com>',
'Renovate-Update-Type: major',
'X-Custom: value with spaces',
])('accepts %j', (trailer) => {
expect(isValidCommitTrailer(trailer)).toBeTrue();
});
it.each([
'no colon',
'Bad key: value',
'Key:no-space',
'Key: multi\nline',
'Signed-off-by: ',
'Signed-off-by:',
'',
42,
null,
undefined,
])('rejects %j', (trailer) => {
expect(isValidCommitTrailer(trailer)).toBeFalse();
});
});
describe('filterValidCommitTrailers', () => {
it('returns valid trailers unchanged', () => {
const trailers = [
'Signed-off-by: Renovate Bot <bot@renovateapp.com>',
'Co-authored-by: First Contributor <first@example.com>',
];
expect(filterValidCommitTrailers(trailers)).toEqual(trailers);
expect(logger.logger.warn).not.toHaveBeenCalled();
});
it('drops invalid trailers and warns', () => {
expect(
filterValidCommitTrailers([
'Signed-off-by: Renovate Bot <bot@renovateapp.com>',
'Signed-off-by: ',
'Key: multi\nline',
]),
).toEqual(['Signed-off-by: Renovate Bot <bot@renovateapp.com>']);
expect(logger.logger.warn).toHaveBeenCalledExactlyOnceWith(
{ invalid: ['Signed-off-by: ', 'Key: multi\nline'] },
'Ignoring invalid commit trailers (must be a single-line Key: value)',
);
});
it('returns empty array when all trailers are invalid', () => {
expect(
filterValidCommitTrailers(['Signed-off-by: ', 'no colon']),
).toEqual([]);
expect(logger.logger.warn).toHaveBeenCalled();
});
});
describe('formatCommitMessage', () => {
it('returns string message unchanged when there are no trailers', () => {
expect(formatCommitMessage('Update something')).toBe('Update something');
});
it('joins array message parts with blank lines', () => {
expect(formatCommitMessage(['Update something', 'Some commit body']))
.toBe(codeBlock`
Update something
Some commit body
`);
});
it('appends trailers as the final block for a string message', () => {
expect(
formatCommitMessage('Update something', [
'Signed-off-by: Renovate Bot <bot@renovateapp.com>',
'Co-authored-by: First Contributor <first@example.com>',
]),
).toBe(codeBlock`
Update something
Signed-off-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: First Contributor <first@example.com>
`);
});
it('appends trailers as the final block for an array message', () => {
expect(
formatCommitMessage(
['Update something', 'Some commit body'],
['Signed-off-by: Renovate Bot <bot@renovateapp.com>'],
),
).toBe(codeBlock`
Update something
Some commit body
Signed-off-by: Renovate Bot <bot@renovateapp.com>
`);
});
it('ignores empty trailer lists', () => {
expect(formatCommitMessage('Update something', [])).toBe(
'Update something',
);
});
});
});