Skip to content

Commit 6a5a6b4

Browse files
committed
Add GitHub Actions reusable workflow for ghstack merge
Adds a reusable workflow that can be called from other repositories to automate ghstack landing via PR comments. Files: - .github/workflows/ghstack-merge.yml: Reusable workflow with inputs: - pull_request_number (required) - python_version, ghstack_version, runs_on (optional) - validate_rules, dry_run, comment_on_failure (optional booleans) - .github/workflows/ghstack-merge-on-comment.yml: Example caller workflow that triggers on "ghstack merge" PR comments - .github/merge_rules.yaml: Example merge rules configuration Usage in other repos: uses: ezyang/ghstack/.github/workflows/ghstack-merge.yml@master with: pull_request_number: ${{ github.event.issue.number }} secrets: github_token: ${{ secrets.GITHUB_TOKEN }} ghstack-source-id: ac23b16 ghstack-comment-id: 3807839215 Pull-Request: #319
1 parent 6f590d8 commit 6a5a6b4

File tree

3 files changed

+175
-0
lines changed

3 files changed

+175
-0
lines changed

.github/merge_rules.yaml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Merge rules for ghstack land
2+
#
3+
# Rules are matched in order - first matching rule wins.
4+
# Each rule specifies:
5+
# - name: A descriptive name for the rule
6+
# - patterns: File glob patterns to match (fnmatch syntax)
7+
# - approved_by: Required approvers (usernames or org/team refs)
8+
# Use "any" to accept any approved review
9+
# - mandatory_checks_name: CI checks that must pass
10+
# - ignore_flaky_failures: (optional) If true, ignore check failures
11+
12+
- name: core-library
13+
patterns:
14+
- "src/ghstack/**"
15+
approved_by:
16+
- ezyang
17+
- pytorch/ghstack-maintainers # Team reference example
18+
mandatory_checks_name:
19+
- "Test"
20+
- "Lint"
21+
22+
- name: documentation
23+
patterns:
24+
- "docs/**"
25+
- "*.md"
26+
approved_by:
27+
- any # Any approved review is sufficient
28+
mandatory_checks_name:
29+
- "Lint"
30+
31+
- name: ci-config
32+
patterns:
33+
- ".github/**"
34+
approved_by:
35+
- ezyang
36+
mandatory_checks_name:
37+
- "Test"
38+
- "Lint"
39+
40+
- name: default
41+
patterns:
42+
- "*"
43+
- "**/*"
44+
approved_by:
45+
- ezyang
46+
mandatory_checks_name:
47+
- "Test"
48+
- "Lint"
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Example workflow that calls the reusable ghstack-merge workflow
2+
# when someone comments "@ghstack merge" on a PR.
3+
#
4+
# To use in your repository:
5+
# 1. Copy this file to .github/workflows/
6+
# 2. Optionally create .github/merge_rules.yaml for merge rules
7+
# 3. Comment "@ghstack merge" on any ghstack PR to trigger landing
8+
9+
name: ghstack merge on comment
10+
11+
on:
12+
issue_comment:
13+
types: [created]
14+
15+
jobs:
16+
check-comment:
17+
# Only run on PR comments containing '@ghstack merge'
18+
if: |
19+
github.event.issue.pull_request &&
20+
contains(github.event.comment.body, '@ghstack merge')
21+
runs-on: ubuntu-latest
22+
outputs:
23+
should_merge: ${{ steps.check.outputs.should_merge }}
24+
steps:
25+
- name: Check if comment triggers merge
26+
id: check
27+
run: echo "should_merge=true" >> $GITHUB_OUTPUT
28+
29+
merge:
30+
needs: check-comment
31+
if: needs.check-comment.outputs.should_merge == 'true'
32+
uses: ezyang/ghstack/.github/workflows/ghstack-merge.yml@master
33+
with:
34+
pull_request_number: ${{ github.event.issue.number }}
35+
validate_rules: true
36+
comment_on_failure: true
37+
secrets:
38+
github_token: ${{ secrets.GITHUB_TOKEN }}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
name: ghstack merge
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
pull_request_number:
7+
description: 'The pull request number to land'
8+
required: true
9+
type: number
10+
python_version:
11+
description: 'Python version to use'
12+
required: false
13+
type: string
14+
default: '3.11'
15+
ghstack_version:
16+
description: 'ghstack version to install (e.g., "ghstack", "ghstack==0.14.0", "git+https://github.com/ezyang/ghstack.git")'
17+
required: false
18+
type: string
19+
default: 'ghstack'
20+
validate_rules:
21+
description: 'Whether to validate against merge rules'
22+
required: false
23+
type: boolean
24+
default: true
25+
dry_run:
26+
description: 'Validate only, do not actually merge'
27+
required: false
28+
type: boolean
29+
default: false
30+
comment_on_failure:
31+
description: 'Post validation errors as PR comment'
32+
required: false
33+
type: boolean
34+
default: true
35+
runs_on:
36+
description: 'Runner to use'
37+
required: false
38+
type: string
39+
default: 'ubuntu-latest'
40+
secrets:
41+
github_token:
42+
description: 'GitHub token with contents:write and pull-requests:write permissions'
43+
required: true
44+
45+
jobs:
46+
merge:
47+
runs-on: ${{ inputs.runs_on }}
48+
permissions:
49+
contents: write
50+
pull-requests: write
51+
steps:
52+
- uses: actions/checkout@v4
53+
with:
54+
fetch-depth: 0
55+
token: ${{ secrets.github_token }}
56+
57+
- name: Setup Python
58+
uses: actions/setup-python@v5
59+
with:
60+
python-version: ${{ inputs.python_version }}
61+
62+
- name: Install ghstack
63+
run: pip install '${{ inputs.ghstack_version }}'
64+
65+
- name: Configure git
66+
run: |
67+
git config user.name "github-actions[bot]"
68+
git config user.email "github-actions[bot]@users.noreply.github.com"
69+
70+
- name: Build ghstack land command
71+
id: build-command
72+
run: |
73+
CMD="ghstack land"
74+
if [ "${{ inputs.validate_rules }}" = "true" ]; then
75+
CMD="$CMD --validate-rules"
76+
fi
77+
if [ "${{ inputs.dry_run }}" = "true" ]; then
78+
CMD="$CMD --dry-run"
79+
fi
80+
if [ "${{ inputs.comment_on_failure }}" = "true" ]; then
81+
CMD="$CMD --comment-on-failure"
82+
fi
83+
CMD="$CMD ${{ inputs.pull_request_number }}"
84+
echo "command=$CMD" >> $GITHUB_OUTPUT
85+
86+
- name: Run ghstack land
87+
env:
88+
GITHUB_TOKEN: ${{ secrets.github_token }}
89+
run: ${{ steps.build-command.outputs.command }}

0 commit comments

Comments
 (0)