Skip to content

Commit fbd0ab8

Browse files
feat: add merge_group event support
* Detect commit hashes from merge_group event * Apply suggestion from @masaru-iritani Co-authored-by: Masaru Iritani <25241373+masaru-iritani@users.noreply.github.com> * refactor: update PullRequest type usage in getChangedFilesFromApi and related functions * Run `npm run pack` --------- Co-authored-by: Sascha Bratton <sascha@brattonbratton.com>
1 parent efb1da7 commit fbd0ab8

3 files changed

Lines changed: 171 additions & 94 deletions

File tree

README.md

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ don't allow this because they don't work on a level of individual jobs or steps.
2727
- The `base` input parameter must not be the same as the branch that triggered the workflow
2828
- Changes are detected against the merge-base with the configured base branch or the default branch
2929
- Uses git commands to detect changes - repository must be already [checked out](https://github.com/actions/checkout)
30+
- **[Merge queue](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue):**
31+
- Workflow triggered by **[merge_group](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#merge_group)**
32+
- The `base` and `ref` input parameters default to commit hashes from the event
33+
unless explicitly specified.
34+
- Uses git commands to detect changes - repository must be already [checked out](https://github.com/actions/checkout)
3035
- **Master, Release, or other long-lived branches:**
3136
- Workflow triggered by **[push](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#push)** event
3237
when `base` input parameter is the same as the branch that triggered the workflow:
@@ -104,6 +109,8 @@ For more information, see [CHANGELOG](https://github.com/dorny/paths-filter/blob
104109
# Branch, tag, or commit SHA against which the changes will be detected.
105110
# If it references the same branch it was pushed to,
106111
# changes are detected against the most recent commit before the push.
112+
# If it is empty and action is triggered by merge_group event,
113+
# the base commit in the event will be used.
107114
# Otherwise, it uses git merge-base to find the best common ancestor between
108115
# current branch (HEAD) and base.
109116
# When merge-base is found, it's used for change detection - only changes
@@ -117,6 +124,8 @@ For more information, see [CHANGELOG](https://github.com/dorny/paths-filter/blob
117124
# Git reference (e.g. branch name) from which the changes will be detected.
118125
# Useful when workflow can be triggered only on the default branch (e.g. repository_dispatch event)
119126
# but you want to get changes on a different branch.
127+
# If this is empty and action is triggered by merge_group event,
128+
# the head commit in the event will be used.
120129
# This option is ignored if action is triggered by pull_request event.
121130
# default: ${{ github.ref }}
122131
ref:
@@ -154,14 +163,14 @@ For more information, see [CHANGELOG](https://github.com/dorny/paths-filter/blob
154163
# Default: ${{ github.token }}
155164
token: ''
156165
157-
# Optional parameter to override the default behavior of file matching algorithm.
166+
# Optional parameter to override the default behavior of file matching algorithm.
158167
# By default files that match at least one pattern defined by the filters will be included.
159168
# This parameter allows to override the "at least one pattern" behavior to make it so that
160-
# all of the patterns have to match or otherwise the file is excluded.
161-
# An example scenario where this is useful if you would like to match all
162-
# .ts files in a sub-directory but not .md files.
163-
# The filters below will match markdown files despite the exclusion syntax UNLESS
164-
# you specify 'every' as the predicate-quantifier parameter. When you do that,
169+
# all of the patterns have to match or otherwise the file is excluded.
170+
# An example scenario where this is useful if you would like to match all
171+
# .ts files in a sub-directory but not .md files.
172+
# The filters below will match markdown files despite the exclusion syntax UNLESS
173+
# you specify 'every' as the predicate-quantifier parameter. When you do that,
165174
# it will only match the .ts files in the subdirectory as expected.
166175
#
167176
# backend:
@@ -317,6 +326,12 @@ on:
317326
branches: # PRs to the following branches will trigger the workflow
318327
- master
319328
- develop
329+
# Optionally you can use the action in the merge queue
330+
# if your repository enables the feature.
331+
merge_group:
332+
branches:
333+
- master
334+
- develop
320335
jobs:
321336
build:
322337
runs-on: ubuntu-latest

dist/index.js

Lines changed: 107 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,29 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
4242
}) : function(o, v) {
4343
o["default"] = v;
4444
});
45-
var __importStar = (this && this.__importStar) || function (mod) {
46-
if (mod && mod.__esModule) return mod;
47-
var result = {};
48-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
49-
__setModuleDefault(result, mod);
50-
return result;
51-
};
45+
var __importStar = (this && this.__importStar) || (function () {
46+
var ownKeys = function(o) {
47+
ownKeys = Object.getOwnPropertyNames || function (o) {
48+
var ar = [];
49+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
50+
return ar;
51+
};
52+
return ownKeys(o);
53+
};
54+
return function (mod) {
55+
if (mod && mod.__esModule) return mod;
56+
var result = {};
57+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
58+
__setModuleDefault(result, mod);
59+
return result;
60+
};
61+
})();
5262
var __importDefault = (this && this.__importDefault) || function (mod) {
5363
return (mod && mod.__esModule) ? mod : { "default": mod };
5464
};
5565
Object.defineProperty(exports, "__esModule", ({ value: true }));
56-
exports.Filter = exports.isPredicateQuantifier = exports.SUPPORTED_PREDICATE_QUANTIFIERS = exports.PredicateQuantifier = void 0;
66+
exports.Filter = exports.SUPPORTED_PREDICATE_QUANTIFIERS = exports.PredicateQuantifier = void 0;
67+
exports.isPredicateQuantifier = isPredicateQuantifier;
5768
const jsyaml = __importStar(__nccwpck_require__(1917));
5869
const picomatch_1 = __importDefault(__nccwpck_require__(8569));
5970
// Minimatch options used in all matchers
@@ -95,7 +106,6 @@ exports.SUPPORTED_PREDICATE_QUANTIFIERS = Object.values(PredicateQuantifier);
95106
function isPredicateQuantifier(x) {
96107
return exports.SUPPORTED_PREDICATE_QUANTIFIERS.includes(x);
97108
}
98-
exports.isPredicateQuantifier = isPredicateQuantifier;
99109
class Filter {
100110
// Creates instance of Filter and load rules from YAML if it's provided
101111
constructor(yaml, filterConfig) {
@@ -196,15 +206,34 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
196206
}) : function(o, v) {
197207
o["default"] = v;
198208
});
199-
var __importStar = (this && this.__importStar) || function (mod) {
200-
if (mod && mod.__esModule) return mod;
201-
var result = {};
202-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
203-
__setModuleDefault(result, mod);
204-
return result;
205-
};
209+
var __importStar = (this && this.__importStar) || (function () {
210+
var ownKeys = function(o) {
211+
ownKeys = Object.getOwnPropertyNames || function (o) {
212+
var ar = [];
213+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
214+
return ar;
215+
};
216+
return ownKeys(o);
217+
};
218+
return function (mod) {
219+
if (mod && mod.__esModule) return mod;
220+
var result = {};
221+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
222+
__setModuleDefault(result, mod);
223+
return result;
224+
};
225+
})();
206226
Object.defineProperty(exports, "__esModule", ({ value: true }));
207-
exports.isGitSha = exports.getShortName = exports.getCurrentRef = exports.listAllFilesAsAdded = exports.parseGitDiffOutput = exports.getChangesSinceMergeBase = exports.getChangesOnHead = exports.getChanges = exports.getChangesInLastCommit = exports.HEAD = exports.NULL_SHA = void 0;
227+
exports.HEAD = exports.NULL_SHA = void 0;
228+
exports.getChangesInLastCommit = getChangesInLastCommit;
229+
exports.getChanges = getChanges;
230+
exports.getChangesOnHead = getChangesOnHead;
231+
exports.getChangesSinceMergeBase = getChangesSinceMergeBase;
232+
exports.parseGitDiffOutput = parseGitDiffOutput;
233+
exports.listAllFilesAsAdded = listAllFilesAsAdded;
234+
exports.getCurrentRef = getCurrentRef;
235+
exports.getShortName = getShortName;
236+
exports.isGitSha = isGitSha;
208237
const exec_1 = __nccwpck_require__(1514);
209238
const core = __importStar(__nccwpck_require__(2186));
210239
const file_1 = __nccwpck_require__(4014);
@@ -222,7 +251,6 @@ async function getChangesInLastCommit() {
222251
}
223252
return parseGitDiffOutput(output);
224253
}
225-
exports.getChangesInLastCommit = getChangesInLastCommit;
226254
async function getChanges(base, head) {
227255
const baseRef = await ensureRefAvailable(base);
228256
const headRef = await ensureRefAvailable(head);
@@ -240,7 +268,6 @@ async function getChanges(base, head) {
240268
}
241269
return parseGitDiffOutput(output);
242270
}
243-
exports.getChanges = getChanges;
244271
async function getChangesOnHead() {
245272
// Get current changes - both staged and unstaged
246273
core.startGroup(`Change detection on HEAD`);
@@ -254,7 +281,6 @@ async function getChangesOnHead() {
254281
}
255282
return parseGitDiffOutput(output);
256283
}
257-
exports.getChangesOnHead = getChangesOnHead;
258284
async function getChangesSinceMergeBase(base, head, initialFetchDepth) {
259285
let baseRef;
260286
let headRef;
@@ -328,7 +354,6 @@ async function getChangesSinceMergeBase(base, head, initialFetchDepth) {
328354
}
329355
return parseGitDiffOutput(output);
330356
}
331-
exports.getChangesSinceMergeBase = getChangesSinceMergeBase;
332357
function parseGitDiffOutput(output) {
333358
const tokens = output.split('\u0000').filter(s => s.length > 0);
334359
const files = [];
@@ -340,7 +365,6 @@ function parseGitDiffOutput(output) {
340365
}
341366
return files;
342367
}
343-
exports.parseGitDiffOutput = parseGitDiffOutput;
344368
async function listAllFilesAsAdded() {
345369
core.startGroup('Listing all files tracked by git');
346370
let output = '';
@@ -359,7 +383,6 @@ async function listAllFilesAsAdded() {
359383
filename: path
360384
}));
361385
}
362-
exports.listAllFilesAsAdded = listAllFilesAsAdded;
363386
async function getCurrentRef() {
364387
core.startGroup(`Get current git ref`);
365388
try {
@@ -377,7 +400,6 @@ async function getCurrentRef() {
377400
core.endGroup();
378401
}
379402
}
380-
exports.getCurrentRef = getCurrentRef;
381403
function getShortName(ref) {
382404
if (!ref)
383405
return '';
@@ -389,11 +411,9 @@ function getShortName(ref) {
389411
return ref.slice(tags.length);
390412
return ref;
391413
}
392-
exports.getShortName = getShortName;
393414
function isGitSha(ref) {
394415
return /^[a-z0-9]{40}$/.test(ref);
395416
}
396-
exports.isGitSha = isGitSha;
397417
async function hasCommit(ref) {
398418
return (await (0, exec_1.getExecOutput)('git', ['cat-file', '-e', `${ref}^{commit}`], { ignoreReturnCode: true })).exitCode === 0;
399419
}
@@ -466,7 +486,7 @@ const statusMap = {
466486
"use strict";
467487

468488
Object.defineProperty(exports, "__esModule", ({ value: true }));
469-
exports.csvEscape = void 0;
489+
exports.csvEscape = csvEscape;
470490
// Returns filename escaped for CSV
471491
// Wraps file name into "..." only when it contains some potentially unsafe character
472492
function csvEscape(value) {
@@ -482,7 +502,6 @@ function csvEscape(value) {
482502
// another double quote
483503
return `"${value.replace(/"/g, '""')}"`;
484504
}
485-
exports.csvEscape = csvEscape;
486505

487506

488507
/***/ }),
@@ -493,12 +512,12 @@ exports.csvEscape = csvEscape;
493512
"use strict";
494513

495514
Object.defineProperty(exports, "__esModule", ({ value: true }));
496-
exports.shellEscape = exports.backslashEscape = void 0;
515+
exports.backslashEscape = backslashEscape;
516+
exports.shellEscape = shellEscape;
497517
// Backslash escape every character except small subset of definitely safe characters
498518
function backslashEscape(value) {
499519
return value.replace(/([^a-zA-Z0-9,._+:@%/-])/gm, '\\$1');
500520
}
501-
exports.backslashEscape = backslashEscape;
502521
// Returns filename escaped for usage as shell argument.
503522
// Applies "human readable" approach with as few escaping applied as possible
504523
function shellEscape(value) {
@@ -519,7 +538,6 @@ function shellEscape(value) {
519538
// Contains some unsafe characters but no single quote
520539
return `'${value}'`;
521540
}
522-
exports.shellEscape = shellEscape;
523541

524542

525543
/***/ }),
@@ -545,13 +563,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
545563
}) : function(o, v) {
546564
o["default"] = v;
547565
});
548-
var __importStar = (this && this.__importStar) || function (mod) {
549-
if (mod && mod.__esModule) return mod;
550-
var result = {};
551-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
552-
__setModuleDefault(result, mod);
553-
return result;
554-
};
566+
var __importStar = (this && this.__importStar) || (function () {
567+
var ownKeys = function(o) {
568+
ownKeys = Object.getOwnPropertyNames || function (o) {
569+
var ar = [];
570+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
571+
return ar;
572+
};
573+
return ownKeys(o);
574+
};
575+
return function (mod) {
576+
if (mod && mod.__esModule) return mod;
577+
var result = {};
578+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
579+
__setModuleDefault(result, mod);
580+
return result;
581+
};
582+
})();
555583
Object.defineProperty(exports, "__esModule", ({ value: true }));
556584
const fs = __importStar(__nccwpck_require__(7147));
557585
const core = __importStar(__nccwpck_require__(2186));
@@ -617,33 +645,49 @@ async function getChangedFiles(token, base, ref, initialFetchDepth) {
617645
}
618646
return await git.getChangesOnHead();
619647
}
620-
const prEvents = ['pull_request', 'pull_request_review', 'pull_request_review_comment', 'pull_request_target'];
621-
if (prEvents.includes(github.context.eventName)) {
622-
if (ref) {
623-
core.warning(`'ref' input parameter is ignored when 'base' is set to HEAD`);
624-
}
625-
if (base) {
626-
core.warning(`'base' input parameter is ignored when action is triggered by pull request event`);
627-
}
628-
const pr = github.context.payload.pull_request;
629-
if (token) {
630-
return await getChangedFilesFromApi(token, pr);
631-
}
632-
if (github.context.eventName === 'pull_request_target') {
633-
// pull_request_target is executed in context of base branch and GITHUB_SHA points to last commit in base branch
634-
// Therefor it's not possible to look at changes in last commit
635-
// At the same time we don't want to fetch any code from forked repository
636-
throw new Error(`'token' input parameter is required if action is triggered by 'pull_request_target' event`);
648+
switch (github.context.eventName) {
649+
// To keep backward compatibility, commits in GitHub pull request event
650+
// take precedence over manual inputs.
651+
case 'pull_request':
652+
case 'pull_request_review':
653+
case 'pull_request_review_comment':
654+
case 'pull_request_target': {
655+
if (ref) {
656+
core.warning(`'ref' input parameter is ignored when 'base' is set to HEAD`);
657+
}
658+
if (base) {
659+
core.warning(`'base' input parameter is ignored when action is triggered by pull request event`);
660+
}
661+
const pr = github.context.payload.pull_request;
662+
if (token) {
663+
return await getChangedFilesFromApi(token, pr);
664+
}
665+
if (github.context.eventName === 'pull_request_target') {
666+
// pull_request_target is executed in context of base branch and GITHUB_SHA points to last commit in base branch
667+
// Therefore it's not possible to look at changes in last commit
668+
// At the same time we don't want to fetch any code from forked repository
669+
throw new Error(`'token' input parameter is required if action is triggered by 'pull_request_target' event`);
670+
}
671+
core.info('Github token is not available - changes will be detected using git diff');
672+
const baseSha = (_a = github.context.payload.pull_request) === null || _a === void 0 ? void 0 : _a.base.sha;
673+
const defaultBranch = (_b = github.context.payload.repository) === null || _b === void 0 ? void 0 : _b.default_branch;
674+
const currentRef = await git.getCurrentRef();
675+
return await git.getChanges(base || baseSha || defaultBranch, currentRef);
676+
}
677+
// To keep backward compatibility, manual inputs take precedence over
678+
// commits in GitHub merge queue event.
679+
case 'merge_group': {
680+
const mergeGroup = github.context.payload;
681+
if (!base) {
682+
base = mergeGroup.merge_group.base_sha;
683+
}
684+
if (!ref) {
685+
ref = mergeGroup.merge_group.head_sha;
686+
}
687+
break;
637688
}
638-
core.info('Github token is not available - changes will be detected using git diff');
639-
const baseSha = (_a = github.context.payload.pull_request) === null || _a === void 0 ? void 0 : _a.base.sha;
640-
const defaultBranch = (_b = github.context.payload.repository) === null || _b === void 0 ? void 0 : _b.default_branch;
641-
const currentRef = await git.getCurrentRef();
642-
return await git.getChanges(base || baseSha || defaultBranch, currentRef);
643-
}
644-
else {
645-
return getChangedFilesFromGit(base, ref, initialFetchDepth);
646689
}
690+
return getChangedFilesFromGit(base, ref, initialFetchDepth);
647691
}
648692
async function getChangedFilesFromGit(base, head, initialFetchDepth) {
649693
var _a;

0 commit comments

Comments
 (0)