From baba405537a5d45886a3b7c1d0b40f2f1a484cec Mon Sep 17 00:00:00 2001 From: Masaru Iritani <25241373+masaru-iritani@users.noreply.github.com> Date: Wed, 18 Dec 2024 09:23:16 +0000 Subject: [PATCH] Detect commit hashes from merge_group event --- README.md | 27 +++++++++++++++++----- src/main.ts | 66 ++++++++++++++++++++++++++++++++++------------------- 2 files changed, 63 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index b5e0f4cf..cf5bd3c5 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,11 @@ don't allow this because they don't work on a level of individual jobs or steps. - The `base` input parameter must not be the same as the branch that triggered the workflow - Changes are detected against the merge-base with the configured base branch or the default branch - Uses git commands to detect changes - repository must be already [checked out](https://github.com/actions/checkout) +- **[Merge queue](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue):** + - Workflow triggered by **[merge_group](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#merge_group)** + - The `base` and `ref` input parameters default to commit hashes from the event + unless explicitly specified. + - Uses git commands to detect changes - repository must be already [checked out](https://github.com/actions/checkout) - **Master, Release, or other long-lived branches:** - Workflow triggered by **[push](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#push)** event 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 # Branch, tag, or commit SHA against which the changes will be detected. # If it references the same branch it was pushed to, # changes are detected against the most recent commit before the push. + # If it is empty and action is triggered by merge_group event, + # the base commit in the event will be used. # Otherwise, it uses git merge-base to find the best common ancestor between # current branch (HEAD) and base. # 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 # Git reference (e.g. branch name) from which the changes will be detected. # Useful when workflow can be triggered only on the default branch (e.g. repository_dispatch event) # but you want to get changes on a different branch. + # If this is empty and action is triggered by merge_group event, + # the head commit in the event will be used. # This option is ignored if action is triggered by pull_request event. # default: ${{ github.ref }} ref: @@ -154,14 +163,14 @@ For more information, see [CHANGELOG](https://github.com/dorny/paths-filter/blob # Default: ${{ github.token }} token: '' - # Optional parameter to override the default behavior of file matching algorithm. + # Optional parameter to override the default behavior of file matching algorithm. # By default files that match at least one pattern defined by the filters will be included. # This parameter allows to override the "at least one pattern" behavior to make it so that - # all of the patterns have to match or otherwise the file is excluded. - # An example scenario where this is useful if you would like to match all - # .ts files in a sub-directory but not .md files. - # The filters below will match markdown files despite the exclusion syntax UNLESS - # you specify 'every' as the predicate-quantifier parameter. When you do that, + # all of the patterns have to match or otherwise the file is excluded. + # An example scenario where this is useful if you would like to match all + # .ts files in a sub-directory but not .md files. + # The filters below will match markdown files despite the exclusion syntax UNLESS + # you specify 'every' as the predicate-quantifier parameter. When you do that, # it will only match the .ts files in the subdirectory as expected. # # backend: @@ -317,6 +326,12 @@ on: branches: # PRs to the following branches will trigger the workflow - master - develop + # Optionally you can use the action in the merge queue + # if your repository enables the feature. + merge_group: + branches: + - master + - develop jobs: build: runs-on: ubuntu-latest diff --git a/src/main.ts b/src/main.ts index 8320287c..44f311c6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,7 +2,7 @@ import * as fs from 'fs' import * as core from '@actions/core' import * as github from '@actions/github' import {GetResponseDataTypeFromEndpointMethod} from '@octokit/types' -import {PushEvent, PullRequestEvent} from '@octokit/webhooks-types' +import {PushEvent, PullRequestEvent, MergeGroupEvent} from '@octokit/webhooks-types' import { isPredicateQuantifier, @@ -84,32 +84,50 @@ async function getChangedFiles(token: string, base: string, ref: string, initial return await git.getChangesOnHead() } - const prEvents = ['pull_request', 'pull_request_review', 'pull_request_review_comment', 'pull_request_target'] - if (prEvents.includes(github.context.eventName)) { - if (ref) { - core.warning(`'ref' input parameter is ignored when 'base' is set to HEAD`) - } - if (base) { - core.warning(`'base' input parameter is ignored when action is triggered by pull request event`) - } - const pr = github.context.payload.pull_request as PullRequestEvent - if (token) { - return await getChangedFilesFromApi(token, pr) + switch (github.context.eventName) { + // To keep backward compatibility, commits in GitHub pull request event + // take precedence over manual inputs. + case 'pull_request': + case 'pull_request_review': + case 'pull_request_review_comment': + case 'pull_request_target': { + if (ref) { + core.warning(`'ref' input parameter is ignored when 'base' is set to HEAD`) + } + if (base) { + core.warning(`'base' input parameter is ignored when action is triggered by pull request event`) + } + const pr = github.context.payload.pull_request as PullRequestEvent + if (token) { + return await getChangedFilesFromApi(token, pr) + } + if (github.context.eventName === 'pull_request_target') { + // pull_request_target is executed in context of base branch and GITHUB_SHA points to last commit in base branch + // Therefore it's not possible to look at changes in last commit + // At the same time we don't want to fetch any code from forked repository + throw new Error(`'token' input parameter is required if action is triggered by 'pull_request_target' event`) + } + core.info('Github token is not available - changes will be detected using git diff') + const baseSha = github.context.payload.pull_request?.base.sha + const defaultBranch = github.context.payload.repository?.default_branch + const currentRef = await git.getCurrentRef() + return await git.getChanges(base || baseSha || defaultBranch, currentRef) } - if (github.context.eventName === 'pull_request_target') { - // pull_request_target is executed in context of base branch and GITHUB_SHA points to last commit in base branch - // Therefor it's not possible to look at changes in last commit - // At the same time we don't want to fetch any code from forked repository - throw new Error(`'token' input parameter is required if action is triggered by 'pull_request_target' event`) + // To keep backward compatibility, manual inputs take precedence over + // commits in GitHub merge queue event. + case 'merge_group': { + const mergeGroup = github.context.payload as MergeGroupEvent + if (!base) { + base = mergeGroup.merge_group.base_sha + } + if (!ref) { + ref = mergeGroup.merge_group.head_sha + } + break } - core.info('Github token is not available - changes will be detected using git diff') - const baseSha = github.context.payload.pull_request?.base.sha - const defaultBranch = github.context.payload.repository?.default_branch - const currentRef = await git.getCurrentRef() - return await git.getChanges(base || baseSha || defaultBranch, currentRef) - } else { - return getChangedFilesFromGit(base, ref, initialFetchDepth) } + + return getChangedFilesFromGit(base, ref, initialFetchDepth) } async function getChangedFilesFromGit(base: string, head: string, initialFetchDepth: number): Promise {