Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ARMAutoSignOff] Trigger on issue_comment:edited when body contains "next steps to merge" #32554

Merged
merged 4 commits into from
Feb 11, 2025
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
73 changes: 23 additions & 50 deletions .github/src/context.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// @ts-check

Check failure on line 1 in .github/src/context.js

View workflow job for this annotation

GitHub Actions / Protected Files

File '.github/src/context.js' should only be updated by the Azure SDK team. If intentional, the PR may be merged by the Azure SDK team via bypassing the branch protections.

/**
* Extracts inputs from context based on event name and properties.
Expand Down Expand Up @@ -29,72 +29,45 @@
issue_number: payload.pull_request.number,
run_id: NaN,
};
} else if (context.eventName === "workflow_dispatch") {
const payload =
/** @type {import("@octokit/webhooks-types").WorkflowDispatchEvent} */ (
context.payload
);

inputs = {
owner: payload.repository.owner.login,
repo: payload.repository.name,
head_sha: "",
issue_number: NaN,
run_id: NaN,
};
} else if (
context.eventName === "check_suite" &&
context.payload.action === "completed"
context.eventName === "issue_comment" &&
context.payload.action === "edited"
) {
const payload =
/** @type {import("@octokit/webhooks-types").CheckSuiteCompletedEvent} */ (
/** @type {import("@octokit/webhooks-types").IssueCommentEditedEvent} */ (
context.payload
);

const owner = payload.repository.owner.login;
const repo = payload.repository.name;
const head_sha = payload.check_suite.head_sha;

let issue_number;

const pull_requests = payload.check_suite.pull_requests;
if (pull_requests && pull_requests.length > 0) {
// For non-fork PRs, we should be able to extract the PR number from the payload, which avoids an
// unnecessary API call. The listPullRequestsAssociatedWithCommit() API also seems to return
// empty for non-fork PRs.
issue_number = pull_requests[0].number;
} else {
// For fork PRs, we must call an API in the base repository to get the PR number
core.info(
`listPullRequestsAssociatedWithCommit(${owner}, ${repo}, ${head_sha})`,
);
const { data: pullRequests } =
await github.rest.repos.listPullRequestsAssociatedWithCommit({
owner: owner,
repo: repo,
commit_sha: head_sha,
});
const issue_number = payload.issue.number;

if (pullRequests.length === 1) {
issue_number = pullRequests[0].number;
} else {
throw new Error(
`Unexpected number of pull requests associated with commit '${head_sha}'. Expected: '1'. Actual '${pullRequests.length}'.`,
);
}
}
const { data: pr } = await github.rest.pulls.get({
owner: owner,
repo: repo,
pull_number: issue_number,
});

const inputs = {
inputs = {
owner: owner,
repo: repo,
head_sha: head_sha,
head_sha: pr.head.sha,
issue_number: issue_number,
run_id: NaN,
};
} else if (context.eventName === "workflow_dispatch") {
const payload =
/** @type {import("@octokit/webhooks-types").WorkflowDispatchEvent} */ (
context.payload
);

core.info(`inputs: ${JSON.stringify(inputs)}`);

return inputs;
inputs = {
owner: payload.repository.owner.login,
repo: payload.repository.name,
head_sha: "",
issue_number: NaN,
run_id: NaN,
};
} else if (
context.eventName === "workflow_run" &&
context.payload.action === "completed"
Expand Down
81 changes: 22 additions & 59 deletions .github/test/context.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, it, vi } from "vitest";

Check failure on line 1 in .github/test/context.test.js

View workflow job for this annotation

GitHub Actions / Protected Files

File '.github/test/context.test.js' should only be updated by the Azure SDK team. If intentional, the PR may be merged by the Azure SDK team via bypassing the branch protections.
import { extractInputs } from "../src/context.js";
import { createMockCore } from "./mocks.js";
import { createMockCore, createMockGithub } from "./mocks.js";

describe("extractInputs", () => {
it("unsupported_event", async () => {
Expand Down Expand Up @@ -46,68 +46,49 @@
});
});

it("workflow_dispatch", async () => {
const context = {
eventName: "workflow_dispatch",
payload: {
repository: {
name: "TestRepoName",
owner: {
login: "TestRepoOwnerLogin",
},
},
},
};

await expect(
extractInputs(null, context, createMockCore()),
).resolves.toEqual({
owner: "TestRepoOwnerLogin",
repo: "TestRepoName",
head_sha: "",
issue_number: NaN,
run_id: NaN,
it("issue_comment:edited", async () => {
const github = createMockGithub();
github.rest.pulls.get.mockResolvedValue({
data: { head: { sha: "abc123" } },
});
});

it("check_suite:completed (same repo)", async () => {
const context = {
eventName: "check_suite",
eventName: "issue_comment",
payload: {
action: "completed",
check_suite: {
head_sha: "abc123",
pull_requests: [{ number: 123 }],
},
action: "edited",
repository: {
name: "TestRepoName",
owner: {
login: "TestRepoOwnerLogin",
},
},
issue: {
number: 123,
},
},
};

await expect(
extractInputs(null, context, createMockCore()),
extractInputs(github, context, createMockCore()),
).resolves.toEqual({
owner: "TestRepoOwnerLogin",
repo: "TestRepoName",
head_sha: "abc123",
issue_number: 123,
run_id: NaN,
});

expect(github.rest.pulls.get).toHaveBeenCalledWith({
owner: "TestRepoOwnerLogin",
repo: "TestRepoName",
pull_number: 123,
});
});

it("check_suite:completed (fork repo)", async () => {
it("workflow_dispatch", async () => {
const context = {
eventName: "check_suite",
eventName: "workflow_dispatch",
payload: {
action: "completed",
check_suite: {
head_sha: "abc123",
pull_requests: null,
},
repository: {
name: "TestRepoName",
owner: {
Expand All @@ -117,33 +98,15 @@
},
};

const github = {
rest: {
repos: {
listPullRequestsAssociatedWithCommit: vi.fn().mockResolvedValue({
data: [{ number: 123 }],
}),
},
},
};

await expect(
extractInputs(github, context, createMockCore()),
extractInputs(null, context, createMockCore()),
).resolves.toEqual({
owner: "TestRepoOwnerLogin",
repo: "TestRepoName",
head_sha: "abc123",
issue_number: 123,
head_sha: "",
issue_number: NaN,
run_id: NaN,
});

expect(
github.rest.repos.listPullRequestsAssociatedWithCommit,
).toHaveBeenCalledWith({
owner: "TestRepoOwnerLogin",
repo: "TestRepoName",
commit_sha: "abc123",
});
});

it("workflow_run:unsupported_action", async () => {
Expand Down
5 changes: 4 additions & 1 deletion .github/test/mocks.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { vi } from "vitest";

Check failure on line 1 in .github/test/mocks.js

View workflow job for this annotation

GitHub Actions / Protected Files

File '.github/test/mocks.js' should only be updated by the Azure SDK team. If intentional, the PR may be merged by the Azure SDK team via bypassing the branch protections.

// Partial mock of `github` parameter passed into github-script actions
export function createMockGithub() {
Expand All @@ -14,9 +14,12 @@
},
issues: {
addLabels: vi.fn(),
listLabelsOnIssue: vi.fn().mockRejectedValue({ data: [] }),
listLabelsOnIssue: vi.fn().mockResolvedValue({ data: [] }),
removeLabel: vi.fn(),
},
pulls: {
get: vi.fn(),
},
},
};
}
Expand Down
30 changes: 24 additions & 6 deletions .github/workflows/arm-auto-signoff-preview.yaml
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
name: ARM Auto Signoff (Preview)

Check failure on line 1 in .github/workflows/arm-auto-signoff-preview.yaml

View workflow job for this annotation

GitHub Actions / Protected Files

File '.github/workflows/arm-auto-signoff-preview.yaml' should only be updated by the Azure SDK team. If intentional, the PR may be merged by the Azure SDK team via bypassing the branch protections.

on:
# TODO: Re-enable once we figure out how to find the PR number from a check_suite:completed event from a fork PR
# check_suite:
# Depends on check_run status, so must re-evaluate whenever a check_suite is completed.
# Could instead trigger on check_run events, but I think this is unnecessarily noisy.
# types: [completed]
issue_comment:
types:
- edited
pull_request:
types:
# Depends on labels, so must re-evaluate whenever a label is manually added or removed.
# Depends on labels, so must re-evaluate whenever a relevant label is manually added or removed.
- labeled
- unlabeled
# Depends on changed files and check_run status, so must re-evaluate whenever either could change
Expand Down Expand Up @@ -42,6 +40,26 @@
arm-auto-signoff-preview:
name: ARM Auto Signoff (Preview)

# pull_request:labeled - filter to only the input and output labels
# issue_comment:edited - filter to only PR comments containing "next steps to merge",
# a signal that "Swagger LintDiff" status may have changed
if: |
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'pull_request' &&
((github.event.action == 'opened' ||
github.event.action == 'reopened' ||
github.event.action == 'synchronize') ||
((github.event.action == 'labeled' ||
github.event.action == 'unlabeled') &&
(github.event.label.name == 'ARMReview' ||
github.event.label.name == 'NotReadyForARMReview' ||
github.event.label.name == 'SuppressionReviewRequired' ||
github.event.label.name == 'Suppression-Approved' ||
github.event.label.name == 'ARMAutoSignOffPreview')))) ||
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
contains(github.event.comment.body, 'next steps to merge'))

runs-on: ubuntu-24.04

steps:
Expand Down
Loading