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 b5e0f4c..cf5bd3c 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 8320287..44f311c 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`)
+  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 (base) {
-      core.warning(`'base' input parameter is ignored when action is triggered by pull request 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
     }
-    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
-      // 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`)
-    }
-    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<File[]> {