Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions .github/workflows/examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# ghstack Merge Workflow Examples

These examples show how to use the reusable `ghstack-merge.yml` workflow in your repository.

## Quick Start

1. Copy one of the example workflows to your repository's `.github/workflows/` directory
2. Optionally create `.github/merge_rules.yaml` to define merge rules
3. Comment `@ghstack merge` on any ghstack PR to trigger landing

## Examples

| File | Description |
|------|-------------|
| `ghstack-merge-basic.yml` | Minimal setup - just lands PRs on `@ghstack merge` |
| `ghstack-merge-with-rules.yml` | Validates against merge rules before landing |
| `ghstack-merge-dry-run.yml` | Validates without merging (triggered by `@ghstack check`) |
| `ghstack-merge-custom.yml` | Shows all available configuration options |

## Workflow Inputs

| Input | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| `pull_request_number` | number | Yes | - | PR number to land |
| `python_version` | string | No | `'3.11'` | Python version |
| `ghstack_version` | string | No | `'ghstack'` | ghstack package spec |
| `validate_rules` | boolean | No | `true` | Validate against merge rules |
| `dry_run` | boolean | No | `false` | Validate only, don't merge |
| `comment_on_failure` | boolean | No | `true` | Post errors as PR comment |
| `runs_on` | string | No | `'ubuntu-latest'` | GitHub runner to use |

## Secrets

| Secret | Required | Description |
|--------|----------|-------------|
| `github_token` | Yes | Token with `contents:write` and `pull-requests:write` |

## Merge Rules Configuration

Create `.github/merge_rules.yaml` in your repository:

```yaml
# Rules are matched in order - first matching rule wins
- name: core-library
patterns:
- "src/**"
approved_by:
- maintainer-username
- org/team-slug # Team reference
mandatory_checks_name:
- "Test"
- "Lint"

- name: documentation
patterns:
- "docs/**"
- "*.md"
approved_by:
- any # Any approval is sufficient
mandatory_checks_name:
- "Lint"

- name: default
patterns:
- "**/*"
approved_by:
- maintainer-username
mandatory_checks_name:
- "Test"
```

### Rule Fields

| Field | Description |
|-------|-------------|
| `name` | Rule identifier (shown in error messages) |
| `patterns` | File glob patterns (fnmatch syntax) |
| `approved_by` | Required approvers (usernames, `org/team`, or `any`) |
| `mandatory_checks_name` | CI checks that must pass |
| `ignore_flaky_failures` | If `true`, ignore check failures (optional) |

## Error Comments

When validation fails with `comment_on_failure: true`, the workflow posts a comment like:

```markdown
## Merge validation failed for PR #123

**Rule:** core-library

### Errors:
- Missing required approval from: maintainer-username, org/team-slug
- Check "Test" has not passed (status: failure)

### Matched Files:
- `src/main.py`
- `src/utils.py`
```
20 changes: 20 additions & 0 deletions .github/workflows/examples/ghstack-merge-basic.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Basic example: Trigger ghstack land on "@ghstack merge" comment
#
# Copy this file to your repository's .github/workflows/ directory

name: ghstack merge

on:
issue_comment:
types: [created]

jobs:
merge:
if: |
github.event.issue.pull_request &&
contains(github.event.comment.body, '@ghstack merge')
uses: ezyang/ghstack/.github/workflows/ghstack-merge.yml@master
with:
pull_request_number: ${{ github.event.issue.number }}
secrets:
github_token: ${{ secrets.GITHUB_TOKEN }}
30 changes: 30 additions & 0 deletions .github/workflows/examples/ghstack-merge-custom.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Example with custom configuration
#
# This workflow demonstrates all available options:
# - Custom Python version
# - Custom ghstack version (from git)
# - Custom runner
# - All merge options enabled

name: ghstack merge custom

on:
issue_comment:
types: [created]

jobs:
merge:
if: |
github.event.issue.pull_request &&
contains(github.event.comment.body, '@ghstack merge')
uses: ezyang/ghstack/.github/workflows/ghstack-merge.yml@master
with:
pull_request_number: ${{ github.event.issue.number }}
python_version: '3.12'
ghstack_version: 'git+https://github.com/ezyang/ghstack.git@master'
validate_rules: true
dry_run: false
comment_on_failure: true
runs_on: 'ubuntu-latest'
secrets:
github_token: ${{ secrets.GITHUB_TOKEN }}
24 changes: 24 additions & 0 deletions .github/workflows/examples/ghstack-merge-dry-run.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Example with dry-run mode
#
# This workflow validates the PR stack without actually merging.
# Useful for testing merge rules configuration or CI integration.

name: ghstack merge dry-run

on:
issue_comment:
types: [created]

jobs:
validate:
if: |
github.event.issue.pull_request &&
contains(github.event.comment.body, '@ghstack check')
uses: ezyang/ghstack/.github/workflows/ghstack-merge.yml@master
with:
pull_request_number: ${{ github.event.issue.number }}
validate_rules: true
dry_run: true
comment_on_failure: true
secrets:
github_token: ${{ secrets.GITHUB_TOKEN }}
23 changes: 23 additions & 0 deletions .github/workflows/examples/ghstack-merge-with-rules.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Example with merge rules validation
#
# This workflow validates PRs against .github/merge_rules.yaml before landing.
# If validation fails, it posts an error comment on the PR.

name: ghstack merge with rules

on:
issue_comment:
types: [created]

jobs:
merge:
if: |
github.event.issue.pull_request &&
contains(github.event.comment.body, '@ghstack merge')
uses: ezyang/ghstack/.github/workflows/ghstack-merge.yml@master
with:
pull_request_number: ${{ github.event.issue.number }}
validate_rules: true
comment_on_failure: true
secrets:
github_token: ${{ secrets.GITHUB_TOKEN }}