Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions bot/src/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ export interface GitHubApi {
head: string,
token: string,
): Promise<Comparison>;
tagObject(
repository: string,
sha: string,
token: string,
): Promise<string | undefined>;
listComments(
repository: string,
issue: number,
Expand Down Expand Up @@ -235,6 +240,14 @@ export function githubApi(fetchFn: typeof fetch = fetch): GitHubApi {
const path = `/repos/${repository}/issues/comments/${id}`;
return expectOk(await call<IssueComment>("PATCH", path, token, { body }));
},
async tagObject(repository, sha, token) {
const result = await call<{ object: { sha: string } }>(
"GET",
`/repos/${repository}/git/tags/${sha}`,
token,
);
return result.status === 404 ? undefined : expectOk(result).object.sha;
},
async revoke(token) {
expectOk(await call<undefined>("DELETE", "/installation/token", token));
},
Expand Down
7 changes: 6 additions & 1 deletion bot/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,15 @@ async function decideRef(
): Promise<Decision> {
const repository = await deps.github.repository(claims.repository, token);
if (claims.ref.startsWith("refs/tags/")) {
// An annotated tag's sha names the tag object; judge the commit under it.
// Tag objects are immutable, so peeling keeps the sha claim authoritative.
const commit =
(await deps.github.tagObject(claims.repository, claims.sha, token)) ??
claims.sha;
const comparison = await deps.github.compare(
claims.repository,
repository.default_branch,
claims.sha,
commit,
token,
);
return decideTag(claims.ref, comparison.status);
Expand Down
15 changes: 15 additions & 0 deletions bot/test/github.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,18 @@ test("createComment and updateComment send the body", async () => {
[{ body: "b" }, { body: "c" }],
);
});

test("tagObject peels an annotated tag and is undefined for a commit", async () => {
const { api } = fakeGitHub({
"GET /repos/acme/mylib/git/tags/aaaa": {
status: 200,
body: { object: { sha: "bbbb", type: "commit" } },
},
"GET /repos/acme/mylib/git/tags/cccc": {
status: 404,
body: { message: "Not Found" },
},
});
assert.equal(await api.tagObject("acme/mylib", "aaaa", "ghs_x"), "bbbb");
assert.equal(await api.tagObject("acme/mylib", "cccc", "ghs_x"), undefined);
});
18 changes: 18 additions & 0 deletions bot/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ function fakeGitHub(
defaultBranch?: string;
compareStatus?: string;
comments?: IssueComment[];
tagObjects?: Record<string, string>;
} = {},
): Fake {
const fake: Fake = {
Expand All @@ -66,6 +67,9 @@ function fakeGitHub(
fake.compared.push(head);
return { status: opts.compareStatus ?? "diverged" };
},
async tagObject(_repository, sha) {
return opts.tagObjects?.[sha];
},
async listComments() {
return fake.comments;
},
Expand Down Expand Up @@ -289,6 +293,20 @@ test("a tag is judged by the commit that ran, not the tag name", async () => {
assert.deepEqual(fake.compared, [claims().sha]);
});

test("an annotated tag's object sha is peeled to its commit before the compare", async () => {
const objectSha = "9999999999999999999999999999999999999999";
const fake = fakeGitHub({
compareStatus: "behind",
tagObjects: { [objectSha]: "abc123" },
});
const { status } = await request(
{ ref: "refs/tags/v1.0.0", sha: objectSha },
fake,
);
assert.equal(status, 200);
assert.deepEqual(fake.compared, ["abc123"]);
});

test("a tag whose commit is off the default branch is refused and revoked", async () => {
const fake = fakeGitHub({ compareStatus: "diverged" });
const { status, body } = await request({ ref: "refs/tags/v1.0.0" }, fake);
Expand Down
Loading