Skip to content

Commit

Permalink
fix: properly attribute the github-actions[bot] as a commit author
Browse files Browse the repository at this point in the history
  • Loading branch information
kormide committed Jan 2, 2024
1 parent 09fdf46 commit 2decffc
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 4 deletions.
48 changes: 48 additions & 0 deletions e2e/e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,54 @@ describe("e2e tests", () => {

expect(messages[0].subject).toEqual(`Publish to BCR`);
});

test("commits are properly attributed to the github-actions[bot] when it is the releaser", async () => {
const repo = Fixture.Versioned;
const tag = "v1.0.0";
await setupLocalRemoteRulesetRepo(repo, tag, {
login: "committer",
email: "committer@test.org",
});

fakeGitHub.mockUser({ login: "github-actions[bot]" });
fakeGitHub.mockRepository(testOrg, repo);
fakeGitHub.mockRepository(
testOrg,
"bazel-central-registry",
"bazelbuild",
"bazel-central-registry"
);
fakeGitHub.mockAppInstallation(testOrg, repo);
fakeGitHub.mockAppInstallation(testOrg, "bazel-central-registry");

const releaseArchive = await makeReleaseTarball(repo, "versioned-1.0.0");
await fakeGitHub.mockReleaseArchive(
`/${testOrg}/${repo}/archive/refs/tags/${tag}.tar.gz`,
releaseArchive
);

const response = await publishReleaseEvent(
cloudFunctions.getBaseUrl(),
secrets.webhookSecret,
{
owner: testOrg,
repo,
tag,
releaser: { login: "github-actions[bot]" },
}
);

expect(response.status).toEqual(200);

const git = getBcr();
const entryBranch = await getLatestBranch(git);
const logs = await git.log({ maxCount: 1, from: entryBranch });

expect(logs.latest?.author_email).toEqual(
"41898282+github-actions[bot]@users.noreply.github.com"
);
expect(logs.latest?.author_name).toEqual("github-actions[bot]");
});
});

const testReleaseArchives: string[] = [];
Expand Down
6 changes: 3 additions & 3 deletions e2e/helpers/fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export enum Fixture {
export async function setupLocalRemoteRulesetRepo(
fixture: Fixture,
tag: string,
releaser: Partial<User>
commitAuthor: Partial<User>
): Promise<void> {
const gitRepoPath = path.join(PREPARED_FIXTURES_PATH, fixture);
let git: SimpleGit;
Expand All @@ -44,8 +44,8 @@ export async function setupLocalRemoteRulesetRepo(
git = simpleGit(gitRepoPath);
await git.init();
await git.add("./*");
await git.addConfig("user.name", releaser.login!);
await git.addConfig("user.email", releaser.email!);
await git.addConfig("user.name", commitAuthor.login!);
await git.addConfig("user.email", commitAuthor.email!);
await git.commit("first commit");
} else {
git = simpleGit(gitRepoPath);
Expand Down
2 changes: 1 addition & 1 deletion e2e/stubs/fake-github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ export class FakeGitHub implements StubbedServer {
const pattern = /\/users\/([^/]+)\/repos/;
await this.server.forGet(pattern).thenCallback((request) => {
const match = request.path.match(pattern);
const owner = match![1];
const owner = decodeURIComponent(match![1]);

if (this.ownedRepos.has(owner)) {
return {
Expand Down
15 changes: 15 additions & 0 deletions src/infrastructure/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ export class MissingRepositoryInstallationError extends Error {
}

export class GitHubClient {
// The GitHub API does not return a name or an email for the github-actions[bot].
// See https://api.github.com/users/github-actions%5Bbot%5D
// Yet, an email and a name are implicitly set when the bot is an author of a
// commit. Hardcode the (stable) name and email so that we can also author commits
// as the GitHub actions bot.
// See https://github.com/orgs/community/discussions/26560#discussioncomment-3252340.
public static readonly GITHUB_ACTIONS_BOT: User = {
username: "github-actions[bot]",
name: "github-actions[bot]",
email: "41898282+github-actions[bot]@users.noreply.github.com",
};

// Cache installation tokens as they expire after an hour, which is more than
// enough time for a cloud function to run.
private readonly _installationTokenCache: any = {};
Expand Down Expand Up @@ -109,6 +121,9 @@ export class GitHubClient {
username: string,
repository: Repository
): Promise<User> {
if (username === GitHubClient.GITHUB_ACTIONS_BOT.username) {
return GitHubClient.GITHUB_ACTIONS_BOT;
}
const octokit = await this.getRepoAuthorizedOctokit(repository);
const { data } = await octokit.rest.users.getByUsername({ username });
return { name: data.name, username, email: data.email };
Expand Down

0 comments on commit 2decffc

Please sign in to comment.