Skip to content

Commit a4fafed

Browse files
mheapv1v
andauthored
Merge queue support (#87)
* Add support for merge_queue events * fix: merge-queue support (#85) * Fix merge_group tests --------- Co-authored-by: Victor Martinez <victormartinezrubio@gmail.com>
1 parent 4292bf2 commit a4fafed

2 files changed

Lines changed: 102 additions & 11 deletions

File tree

index.js

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ async function action() {
2727

2828
let providedLabels = core.getInput("labels", { required: true });
2929

30+
core.debug(`gather labels: ${providedLabels}`);
3031
if (labelsAreRegex) {
3132
// If labels are regex they must be provided as new line delimited
3233
providedLabels = providedLabels.split("\n");
@@ -43,6 +44,18 @@ async function action() {
4344
// Remove any empty labels
4445
providedLabels = providedLabels.filter((r) => r);
4546

47+
let issue_number = github.context.issue.number;
48+
49+
if (github.context.eventName === "merge_group" && !issue_number) {
50+
// Parse out of the ref for merge queue
51+
// e.g. refs/heads/gh-readonly-queue/main/pr-17-a3c310584587d4b97c2df0cb46fe050cc46a15d6
52+
const lastPart = github.context.ref.split("/").pop();
53+
issue_number = lastPart.match(/pr-(\d+)-/)[1];
54+
core.info(
55+
`merge_group event detected and issue_number parsed as ${issue_number}`,
56+
);
57+
}
58+
4659
const allowedModes = ["exactly", "minimum", "maximum"];
4760
if (!allowedModes.includes(mode)) {
4861
await exitWithError(
@@ -52,6 +65,7 @@ async function action() {
5265
`Unknown mode input [${mode}]. Must be one of: ${allowedModes.join(
5366
", ",
5467
)}`,
68+
issue_number,
5569
);
5670
return;
5771
}
@@ -65,17 +79,18 @@ async function action() {
6579
`Unknown exit_code input [${exitType}]. Must be one of: ${allowedExitCodes.join(
6680
", ",
6781
)}`,
82+
issue_number,
6883
);
6984
return;
7085
}
7186

72-
// Fetch the labels using the API
87+
core.debug(`fetch the labels for ${issue_number} using the API`);
7388
// We use the API rather than read event.json in case earlier steps
7489
// added a label
7590
const labels = (
7691
await octokit.rest.issues.listLabelsOnIssue({
7792
...github.context.repo,
78-
issue_number: github.context.issue.number,
93+
issue_number,
7994
})
8095
).data;
8196

@@ -98,7 +113,7 @@ async function action() {
98113
);
99114
}
100115

101-
// Is there an error?
116+
core.debug(`detect errors...`);
102117
let errorMode;
103118
if (mode === "exactly" && intersection.length !== count) {
104119
errorMode = "exactly";
@@ -108,7 +123,7 @@ async function action() {
108123
errorMode = "at most";
109124
}
110125

111-
// If so, add a comment (if enabled) and fail the run
126+
core.debug(`if so, add a comment (if enabled) and fail the run...`);
112127
if (errorMode !== undefined) {
113128
const comment = core.getInput("message");
114129
const errorMessage = tmpl(comment, {
@@ -119,15 +134,21 @@ async function action() {
119134
applied: appliedLabels.join(", "),
120135
});
121136

122-
await exitWithError(exitType, octokit, shouldAddComment, errorMessage);
137+
await exitWithError(
138+
exitType,
139+
octokit,
140+
shouldAddComment,
141+
errorMessage,
142+
issue_number,
143+
);
123144
return;
124145
}
125146

126-
// Remove the comment if it exists
147+
core.debug(`remove the comment if it exists...`);
127148
if (shouldAddComment) {
128149
const { data: existing } = await octokit.rest.issues.listComments({
129150
...github.context.repo,
130-
issue_number: github.context.issue.number,
151+
issue_number: issue_number,
131152
});
132153

133154
const generatedComment = existing.find((c) =>
@@ -154,19 +175,25 @@ function tmpl(t, o) {
154175
});
155176
}
156177

157-
async function exitWithError(exitType, octokit, shouldAddComment, message) {
178+
async function exitWithError(
179+
exitType,
180+
octokit,
181+
shouldAddComment,
182+
message,
183+
issue_number,
184+
) {
158185
if (shouldAddComment) {
159186
// Is there an existing comment?
160187
const { data: existing } = await octokit.rest.issues.listComments({
161188
...github.context.repo,
162-
issue_number: github.context.issue.number,
189+
issue_number: issue_number,
163190
});
164191

165192
const generatedComment = existing.find((c) => c.body.includes(matchToken));
166193

167194
const params = {
168195
...github.context.repo,
169-
issue_number: github.context.issue.number,
196+
issue_number: issue_number,
170197
body: `${matchToken}${message}`,
171198
};
172199

index.test.js

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ describe("Required Labels", () => {
3131
core.setOutput = jest.fn();
3232
core.warning = jest.fn();
3333
core.setFailed = jest.fn();
34+
core.debug = jest.fn();
3435
});
3536

3637
afterEach(() => {
@@ -645,6 +646,59 @@ describe("Required Labels", () => {
645646
await action();
646647
});
647648
});
649+
650+
describe("merge_group", () => {
651+
it("extracts the PR number from the ref if needed", async () => {
652+
restoreTest = mockEvent(
653+
"merge_group",
654+
{},
655+
{
656+
INPUT_LABELS: "enhancement",
657+
INPUT_MODE: "exactly",
658+
INPUT_COUNT: "1",
659+
GITHUB_TOKEN: "mock-token-here-abc",
660+
},
661+
{
662+
ref: "refs/heads/gh-readonly-queue/main/pr-28-a3c310584587d4b97c2df0cb46fe050cc46a15d6",
663+
},
664+
);
665+
666+
mockLabels(["enhancement", "bug"]);
667+
668+
await action();
669+
expect(core.setOutput).toBeCalledTimes(2);
670+
expect(core.setOutput).toBeCalledWith("status", "success");
671+
expect(core.setOutput).toBeCalledWith("labels", "enhancement");
672+
});
673+
674+
it("prefers the issue number that is set in the payload to extracting from a ref", async () => {
675+
restoreTest = mockEvent(
676+
"merge_group",
677+
{
678+
issue: {
679+
number: 28,
680+
},
681+
},
682+
{
683+
INPUT_LABELS: "enhancement",
684+
INPUT_MODE: "exactly",
685+
INPUT_COUNT: "1",
686+
GITHUB_TOKEN: "mock-token-here-abc",
687+
},
688+
{
689+
// This would lead to an error as there are no mocks for PR 999
690+
ref: "refs/heads/gh-readonly-queue/main/pr-999-a3c310584587d4b97c2df0cb46fe050cc46a15d6",
691+
},
692+
);
693+
694+
mockLabels(["enhancement", "bug"]);
695+
696+
await action();
697+
expect(core.setOutput).toBeCalledTimes(2);
698+
expect(core.setOutput).toBeCalledWith("status", "success");
699+
expect(core.setOutput).toBeCalledWith("labels", "enhancement");
700+
});
701+
});
648702
});
649703

650704
function mockPr(env) {
@@ -683,8 +737,18 @@ function mockListComments(comments) {
683737
);
684738
}
685739

686-
function mockEvent(eventName, mockPayload, additionalParams = {}) {
740+
function mockEvent(
741+
eventName,
742+
mockPayload,
743+
additionalParams,
744+
additionalContext = {},
745+
) {
687746
github.context.payload = mockPayload;
747+
github.context.eventName = eventName;
748+
749+
for (const key in additionalContext) {
750+
github.context[key] = additionalContext[key];
751+
}
688752

689753
const params = {
690754
GITHUB_EVENT_NAME: eventName,

0 commit comments

Comments
 (0)