Skip to content

Commit 4b9ea40

Browse files
feat: add config option to enable Signed-off-by in commit messages (#7766)
* refactor: add email field to User type Most backends don't need any change because they already populate this field. * feat: add config option to enable Signed-off-by in commit messages Some organizations require Signed-off-by trailers in commit messages (e.g. for Developer Certificate of Origin). GitHub has a setting to enable this when authoring changes from the Web UI. This patch adds a similar setting for DecapCMS. Closes: #7730 --------- Co-authored-by: Martin Jagodic <jagodicmartin1@gmail.com>
1 parent c90804f commit 4b9ea40

10 files changed

Lines changed: 48 additions & 5 deletions

File tree

packages/decap-cms-backend-git-gateway/src/implementation.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ export default class GitGateway implements Implementation {
381381
return {
382382
name: userData.name,
383383
login: userData.email,
384+
email: userData.email,
384385
avatar_url: userData.avatar_url,
385386
} as unknown as User;
386387
});

packages/decap-cms-backend-gitea/src/API.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export default class API {
131131

132132
static DEFAULT_COMMIT_MESSAGE = 'Automatically generated by Static CMS';
133133

134-
user(): Promise<{ full_name: string; login: string; avatar_url: string }> {
134+
user(): Promise<{ full_name: string; login: string; email: string; avatar_url: string }> {
135135
if (!this._userPromise) {
136136
this._userPromise = this.getUser();
137137
}

packages/decap-cms-backend-gitea/src/implementation.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ export default class Gitea implements Implementation {
183183
return {
184184
name: user.full_name,
185185
login: user.login,
186+
email: user.email,
186187
avatar_url: user.avatar_url,
187188
token: state.token as string,
188189
};

packages/decap-cms-backend-github/src/API.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,14 @@ export default class API {
253253

254254
static DEFAULT_COMMIT_MESSAGE = 'Automatically generated by Decap CMS';
255255

256-
user(): Promise<{ name: string; login: string }> {
256+
user(): Promise<{ name: string; login: string; email?: string }> {
257257
if (!this._userPromise) {
258258
this._userPromise = this.getUser({ token: this.token });
259259
}
260260
return this._userPromise.then(user => ({
261261
name: user.name || 'Unknown',
262262
login: user.login,
263+
email: user.email ?? undefined,
263264
}));
264265
}
265266

packages/decap-cms-core/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ declare module 'decap-cms-core' {
364364
auth_type?: 'implicit' | 'pkce';
365365
cms_label_prefix?: string;
366366
squash_merges?: boolean;
367+
signoff_commits?: boolean;
367368
proxy_url?: string;
368369
commit_messages?: {
369370
create?: string;

packages/decap-cms-core/src/backend.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,6 +1178,7 @@ export class Backend {
11781178
path,
11791179
authorLogin: user.login,
11801180
authorName: user.name,
1181+
authorEmail: user.email,
11811182
},
11821183
user.useOpenAuthoring,
11831184
);
@@ -1253,6 +1254,7 @@ export class Backend {
12531254
path: file.path,
12541255
authorLogin: user.login,
12551256
authorName: user.name,
1257+
authorEmail: user.email,
12561258
},
12571259
user.useOpenAuthoring,
12581260
),
@@ -1279,6 +1281,7 @@ export class Backend {
12791281
path,
12801282
authorLogin: user.login,
12811283
authorName: user.name,
1284+
authorEmail: user.email,
12821285
},
12831286
user.useOpenAuthoring,
12841287
);
@@ -1303,6 +1306,7 @@ export class Backend {
13031306
path,
13041307
authorLogin: user.login,
13051308
authorName: user.name,
1309+
authorEmail: user.email,
13061310
},
13071311
user.useOpenAuthoring,
13081312
);

packages/decap-cms-core/src/lib/__tests__/formatters.spec.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,27 @@ describe('formatters', () => {
247247
'Ignoring unknown variable “author-email” in open authoring message template.',
248248
);
249249
});
250+
251+
it('should return commit with trailer when signoff_commits is enabled', () => {
252+
const collection = Map({ label_singular: 'Collection' });
253+
const config = {
254+
backend: {
255+
signoff_commits: true,
256+
},
257+
};
258+
259+
expect(
260+
commitMessageFormatter('create', config, {
261+
slug: 'doc-slug',
262+
path: 'file-path',
263+
collection,
264+
authorName: 'Test User',
265+
authorEmail: 'test-user@example.org',
266+
}),
267+
).toEqual(
268+
'Create Collection “doc-slug”\n\nSigned-off-by: Test User <test-user@example.org>\n',
269+
);
270+
});
250271
});
251272

252273
describe('prepareSlug', () => {

packages/decap-cms-core/src/lib/formatters.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,28 @@ type Options = {
4444
collection?: Collection;
4545
authorLogin?: string;
4646
authorName?: string;
47+
authorEmail?: string;
4748
};
4849

4950
export function commitMessageFormatter(
5051
type: keyof typeof commitMessageTemplates,
5152
config: CmsConfig,
52-
{ slug, path, collection, authorLogin, authorName }: Options,
53+
{ slug, path, collection, authorLogin, authorName, authorEmail }: Options,
5354
isOpenAuthoring?: boolean,
5455
) {
5556
const templates = { ...commitMessageTemplates, ...(config.backend.commit_messages || {}) };
5657

58+
let trailers = '';
59+
if (config.backend.signoff_commits) {
60+
if (!authorName) {
61+
console.warn('Option signoff_commits is enabled, but author name is unknown');
62+
} else if (!authorEmail) {
63+
console.warn('Option signoff_commits is enabled, but author email is unknown');
64+
} else {
65+
trailers = `\n\nSigned-off-by: ${authorName} <${authorEmail}>\n`;
66+
}
67+
}
68+
5769
const commitMessage = templates[type].replace(variableRegex, (_, variable) => {
5870
switch (variable) {
5971
case 'slug':
@@ -73,7 +85,7 @@ export function commitMessageFormatter(
7385
});
7486

7587
if (!isOpenAuthoring) {
76-
return commitMessage;
88+
return commitMessage + trailers;
7789
}
7890

7991
const message = templates.openAuthoring.replace(variableRegex, (_, variable) => {
@@ -90,7 +102,7 @@ export function commitMessageFormatter(
90102
}
91103
});
92104

93-
return message;
105+
return message + trailers;
94106
}
95107

96108
export function prepareSlug(slug: string) {

packages/decap-cms-core/src/types/redux.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ export interface CmsBackend {
377377
auth_endpoint?: string;
378378
cms_label_prefix?: string;
379379
squash_merges?: boolean;
380+
signoff_commits?: boolean;
380381
proxy_url?: string;
381382
commit_messages?: {
382383
create?: string;

packages/decap-cms-lib-util/src/implementation.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export type Credentials = { token: string | {}; refresh_token?: string };
9090
export type User = Credentials & {
9191
backendName?: string;
9292
login?: string;
93+
email?: string;
9394
name: string;
9495
useOpenAuthoring?: boolean;
9596
};

0 commit comments

Comments
 (0)