From 448d845bc17fefc8943be7103cca653c256fb7fb Mon Sep 17 00:00:00 2001 From: pengzhanbo Date: Tue, 5 Nov 2024 10:39:14 +0800 Subject: [PATCH] feat(plugin-git): add collect of co-authors (#285) --- docs/plugins/development/git.md | 8 +++ docs/zh/plugins/development/git.md | 7 ++ .../development/plugin-git/src/node/types.ts | 5 ++ .../plugin-git/src/node/utils/getCommits.ts | 18 ++++- .../src/node/utils/resolveChangelog.ts | 4 +- .../src/node/utils/resolveContributors.ts | 65 ++++++++++--------- 6 files changed, 75 insertions(+), 32 deletions(-) diff --git a/docs/plugins/development/git.md b/docs/plugins/development/git.md index d456e36df..4e6b3602d 100644 --- a/docs/plugins/development/git.md +++ b/docs/plugins/development/git.md @@ -314,6 +314,14 @@ interface GitChangelog { * The url of the release tag */ tagUrl?: string + + /** + * The list of co-authors + */ + coAuthors?: { + name: string + email: string + }[] } ``` diff --git a/docs/zh/plugins/development/git.md b/docs/zh/plugins/development/git.md index 3480e0c1a..7474bb142 100644 --- a/docs/zh/plugins/development/git.md +++ b/docs/zh/plugins/development/git.md @@ -308,6 +308,13 @@ interface GitChangelog { * tag 访问地址 */ tagUrl?: string + /** + * 协同作者列表 + */ + coAuthors?: { + name: string + email: string + }[] } ``` diff --git a/plugins/development/plugin-git/src/node/types.ts b/plugins/development/plugin-git/src/node/types.ts index f0cd49836..116e507ad 100644 --- a/plugins/development/plugin-git/src/node/types.ts +++ b/plugins/development/plugin-git/src/node/types.ts @@ -261,6 +261,11 @@ export interface RawCommit { * Commit author email */ email: string + + /** + * The co-authors of the commit + */ + coAuthors?: Pick[] } export interface MergedRawCommit extends Omit { diff --git a/plugins/development/plugin-git/src/node/utils/getCommits.ts b/plugins/development/plugin-git/src/node/utils/getCommits.ts index aa0866261..213a5a8cc 100644 --- a/plugins/development/plugin-git/src/node/utils/getCommits.ts +++ b/plugins/development/plugin-git/src/node/utils/getCommits.ts @@ -1,10 +1,25 @@ import { execa } from 'execa' -import type { MergedRawCommit, RawCommit } from '../types.js' +import type { GitContributor, MergedRawCommit, RawCommit } from '../types.js' const FORMAT = '%H|%an|%ae|%ad|%s|%d|%b' const SPLIT_CHAR = '[GIT_LOG_COMMIT_END]' const RE_SPLIT = /\[GIT_LOG_COMMIT_END\]$/ +const RE_CO_AUTHOR = /^ *Co-authored-by: ?([^<]*)<([^>]*)> */gim + +const getCoAuthors = ( + body: string, +): Pick[] => { + if (!body) return [] + + return [...body.matchAll(RE_CO_AUTHOR)] + .map(([, name, email]) => ({ + name: name.trim(), + email: email.trim(), + })) + .filter(Boolean) +} + /** * Get raw commits * @@ -55,6 +70,7 @@ export const parseRawCommits = ( refs, author, email, + coAuthors: getCoAuthors(body), } }) diff --git a/plugins/development/plugin-git/src/node/utils/resolveChangelog.ts b/plugins/development/plugin-git/src/node/utils/resolveChangelog.ts index 8156fae4f..2045a2a35 100644 --- a/plugins/development/plugin-git/src/node/utils/resolveChangelog.ts +++ b/plugins/development/plugin-git/src/node/utils/resolveChangelog.ts @@ -83,7 +83,7 @@ export const resolveChangelog = ( : commits for (const commit of sliceCommits) { - const { hash, message, date, author, email, refs } = commit + const { hash, message, date, author, email, refs, coAuthors } = commit const tag = parseTagName(refs) const contributor = getContributorWithConfig( contributors, @@ -97,6 +97,8 @@ export const resolveChangelog = ( message: app.markdown.renderInline(message), } + if (coAuthors) resolved.coAuthors = coAuthors + if (pattern.issue && repo) { resolved.message = resolved.message.replace( RE_ISSUE, diff --git a/plugins/development/plugin-git/src/node/utils/resolveContributors.ts b/plugins/development/plugin-git/src/node/utils/resolveContributors.ts index 1574888ce..35f051f65 100644 --- a/plugins/development/plugin-git/src/node/utils/resolveContributors.ts +++ b/plugins/development/plugin-git/src/node/utils/resolveContributors.ts @@ -16,7 +16,7 @@ export const getUserNameWithNoreplyEmail = ( return undefined } -const toArray = (value?: string[] | string): string[] => { +const toArray = (value?: T | T[]): T[] => { if (!value) return [] return Array.isArray(value) ? value : [value] } @@ -46,38 +46,43 @@ export const getRawContributors = async ( const contributors = new Map() for (const commit of commits) { - const { author, email } = commit - const config = getContributorWithConfig( - options.list ?? [], - getUserNameWithNoreplyEmail(email) ?? author, - ) - const username = config?.username ?? author - const name = config?.name ?? username - - const contributor = contributors.get(name + email) - if (contributor) { - contributor.commits++ - } else { - const item: GitContributor = { - name, - email, - commits: 1, - } + const authors = [ + { name: commit.author, email: commit.email }, + ...toArray(commit.coAuthors), + ] + for (const { name: author, email } of authors) { + const config = getContributorWithConfig( + options.list ?? [], + getUserNameWithNoreplyEmail(email) ?? author, + ) + const username = config?.username ?? author + const name = config?.name ?? username + + const contributor = contributors.get(name + email) + if (contributor) { + contributor.commits++ + } else { + const item: GitContributor = { + name, + email, + commits: 1, + } - if (options.avatar) - item.avatar = - config?.avatar ?? - (gitProvider === 'github' - ? `https://avatars.githubusercontent.com/${username}?v=4` - : `https://gravatar.com/avatar/${await digestSHA256(email || username)}?d=retro`) + if (options.avatar) + item.avatar = + config?.avatar ?? + (gitProvider === 'github' + ? `https://avatars.githubusercontent.com/${username}?v=4` + : `https://gravatar.com/avatar/${await digestSHA256(email || username)}?d=retro`) - const url = - (config?.url ?? gitProvider === 'github') - ? `https://github.com/${username}` - : undefined - if (url) item.url = url + const url = + (config?.url ?? gitProvider === 'github') + ? `https://github.com/${username}` + : undefined + if (url) item.url = url - contributors.set(name + email, item) + contributors.set(name + email, item) + } } }