Skip to content

Commit

Permalink
feat(git changelog): resolve contributors' GitHub profile URL (#294)
Browse files Browse the repository at this point in the history
  • Loading branch information
giladgd authored Aug 4, 2024
1 parent b6ae060 commit 4dad600
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,14 @@ jobs:
# ... other steps
```

#### Contributor information

The contributor information (such as name and email address) is resolved from the commit author information.

If the commit email address is a GitHub-provided no-reply email (like `<user>@users.noreply.github.com`), then it is used for determaining the GitHub username, which is then used for getting the profile picture from GitHub, as well as linking to the GitHub profile (unless overriden by the [`mapAuthors` option](./configure-vite-plugins#option-mapauthors-map-contributors-information)).

By default, [Gravatar](https://gravatar.com/) is used for getting a profile picture based on an email address.

#### Build on Netlify

By default, Netlify can get all Git logs during the CI/CD build.
Expand Down
43 changes: 43 additions & 0 deletions packages/vitepress-plugin-git-changelog/src/vite/helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
findMapAuthorLink,
getAvatarFromGithubNoreplyAddress,
getCoAuthors,
getProfileUrlFromGithubNoreplyAddress,
mergeRawCommits,
newAvatarForAuthor,
parseCommitAuthors,
Expand Down Expand Up @@ -315,6 +316,28 @@ describe('parseCommitAuthors', () => {
},
])
})

it('should map autresolve github noreply email', async () => {
const mockedCommit = {
paths: ['/fack/path/1.md'],
hash: '62ef7ed8f54ea1faeacf6f6c574df491814ec1b1',
date: 'Wed Apr 24 14:24:44 2024 +0800',
message: 'docs: fix english integrations list',
body: '',
author_name: 'First Last',
author_email: '[email protected]',
}

const authors = await parseCommitAuthors(mockedCommit)
expect(authors).toEqual([
{
name: 'First Last',
email: '[email protected]',
avatarUrl: 'https://avatars.githubusercontent.com/user?size=80',
url: 'https://github.com/user',
},
])
})
})

describe('getCoAuthors', () => {
Expand Down Expand Up @@ -570,6 +593,26 @@ describe('getAvatarFromGithubNoreplyAddress', () => {
})
})

describe('getProfileUrlFromGithubNoreplyAddress', () => {
it('should return undefined for email it cannot handle', async () => {
const avatar = await getProfileUrlFromGithubNoreplyAddress('[email protected]')

expect(avatar).toEqual(undefined)
})

it('should return the GitHub profile URL for GitHub noreply email without user ID', async () => {
const avatar = await getProfileUrlFromGithubNoreplyAddress('[email protected]')

expect(avatar).toEqual('https://github.com/user')
})

it('should return the GitHub profile URL for GitHub noreply email with user ID', async () => {
const avatar = await getProfileUrlFromGithubNoreplyAddress('[email protected]')

expect(avatar).toEqual('https://github.com/user')
})
})

describe('parseCommits', () => {
it('should init commit with fields transformed', async () => {
const mockedCommits = [
Expand Down
17 changes: 17 additions & 0 deletions packages/vitepress-plugin-git-changelog/src/vite/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ export async function parseCommitAuthors(commit: MergedRawCommit, mapContributor
return author
}
author.avatarUrl = await newAvatarForAuthor(undefined, author.email!)
author.url ||= getProfileUrlFromGithubNoreplyAddress(author.email)
return author
}))
}
Expand Down Expand Up @@ -468,6 +469,22 @@ export function getAvatarFromGithubNoreplyAddress(email: string | undefined, siz
return `https://avatars.githubusercontent.com/${userId ? `u/${userId}` : userName}?size=${size}`
}

export function getProfileUrlFromGithubNoreplyAddress(email: string | undefined): string | undefined {
if (!email)
return undefined

const match = email.match(/^(?:(?<userId>\d+)\+)?(?<userName>[a-zA-Z\d-]{1,39})@users.noreply.github.com$/)
if (!match || !match.groups)
return undefined

const { userName } = match.groups

if (!userName)
return undefined

return `https://github.com/${userName}`
}

export async function newAvatarForAuthor(mappedAuthor: Contributor | undefined, email: string): Promise<string> {
if (mappedAuthor) {
if (mappedAuthor.avatar)
Expand Down

0 comments on commit 4dad600

Please sign in to comment.