|
| 1 | +# Create Pull Request Action |
| 2 | + |
| 3 | +This GitHub Action creates or updates a pull request using the `gh` CLI. It is designed as an in-house replacement for `peter-evans/create-pull-request`, with integrated vault-based token resolution. |
| 4 | + |
| 5 | +## Description |
| 6 | + |
| 7 | +The action: |
| 8 | +- Stages and commits file changes on a new branch |
| 9 | +- Creates a pull request if one doesn't exist, or updates an existing one |
| 10 | +- Supports all common PR options: labels, reviewers, assignees, milestones, drafts |
| 11 | +- Automatically resolves authentication tokens via vault, falling back to the provided input token |
| 12 | + |
| 13 | +## Prerequisites |
| 14 | + |
| 15 | +- The repository must be checked out before using this action |
| 16 | +- A GitHub token with `contents: write` and `pull-requests: write` permissions |
| 17 | +- For vault token resolution: `id-token: write` permission and a vault secret at `development/github/token/{REPO_OWNER_NAME_DASH}-release-automation` |
| 18 | + |
| 19 | +## Inputs |
| 20 | + |
| 21 | +| Input | Description | Required | Default | |
| 22 | +|-------|-------------|----------|---------| |
| 23 | +| `token` | GitHub token (vault token preferred, falls back to this) | No | `${{ github.token }}` | |
| 24 | +| `add-paths` | Comma or newline-separated file paths to stage | No | `''` (all changes) | |
| 25 | +| `commit-message` | Commit message for changes | No | `[create-pull-request] automated change` | |
| 26 | +| `committer` | Committer in `Name <email>` format | No | `github-actions[bot] <...>` | |
| 27 | +| `author` | Author in `Name <email>` format | No | `${{ github.actor }} <...>` | |
| 28 | +| `signoff` | Add `Signed-off-by` trailer | No | `false` | |
| 29 | +| `branch` | PR branch name | No | `create-pull-request/patch` | |
| 30 | +| `branch-suffix` | Suffix: `random`, `timestamp`, or `short-commit-hash` | No | `''` | |
| 31 | +| `base` | Base branch for PR | No | Current branch | |
| 32 | +| `title` | PR title | No | `Changes by create-pull-request action` | |
| 33 | +| `body` | PR body | No | `''` | |
| 34 | +| `body-path` | File path for PR body content | No | `''` | |
| 35 | +| `labels` | Comma or newline-separated labels | No | `''` | |
| 36 | +| `assignees` | Comma or newline-separated assignees | No | `''` | |
| 37 | +| `reviewers` | Comma or newline-separated reviewers | No | `''` | |
| 38 | +| `team-reviewers` | Comma or newline-separated team reviewers | No | `''` | |
| 39 | +| `milestone` | Milestone number | No | `''` | |
| 40 | +| `draft` | Create as draft PR | No | `false` | |
| 41 | +| `delete-branch` | Delete branch after PR is merged | No | `false` | |
| 42 | +| `maintainer-can-modify` | Allow maintainer edits | No | `true` | |
| 43 | + |
| 44 | +## Outputs |
| 45 | + |
| 46 | +| Output | Description | |
| 47 | +|--------|-------------| |
| 48 | +| `pull-request-number` | The number of the created or updated PR | |
| 49 | +| `pull-request-url` | The URL of the created or updated PR | |
| 50 | +| `pull-request-operation` | The operation performed: `created`, `updated`, or `none` | |
| 51 | +| `pull-request-head-sha` | The SHA of the head commit on the PR branch | |
| 52 | +| `pull-request-branch` | The name of the PR branch | |
| 53 | + |
| 54 | +## Usage |
| 55 | + |
| 56 | +### Basic usage |
| 57 | + |
| 58 | +```yaml |
| 59 | +- uses: actions/checkout@v4 |
| 60 | + |
| 61 | +- name: Make changes |
| 62 | + run: echo "updated" > file.txt |
| 63 | + |
| 64 | +- name: Create Pull Request |
| 65 | + uses: SonarSource/release-github-actions/create-pull-request@v1 |
| 66 | + with: |
| 67 | + title: 'Automated update' |
| 68 | + branch: bot/automated-update |
| 69 | +``` |
| 70 | +
|
| 71 | +### With explicit token |
| 72 | +
|
| 73 | +```yaml |
| 74 | +- name: Create Pull Request |
| 75 | + uses: SonarSource/release-github-actions/create-pull-request@v1 |
| 76 | + with: |
| 77 | + token: ${{ secrets.MY_TOKEN }} |
| 78 | + commit-message: 'Update dependencies' |
| 79 | + title: 'Update dependencies' |
| 80 | + branch: bot/update-deps |
| 81 | +``` |
| 82 | +
|
| 83 | +### With labels and reviewers |
| 84 | +
|
| 85 | +```yaml |
| 86 | +- name: Create Pull Request |
| 87 | + uses: SonarSource/release-github-actions/create-pull-request@v1 |
| 88 | + with: |
| 89 | + title: 'Update rule metadata' |
| 90 | + branch: bot/update-rule-metadata |
| 91 | + branch-suffix: timestamp |
| 92 | + labels: skip-qa |
| 93 | + reviewers: user1,user2 |
| 94 | + team-reviewers: team-a |
| 95 | +``` |
| 96 | +
|
| 97 | +### With draft PR |
| 98 | +
|
| 99 | +```yaml |
| 100 | +- name: Create Pull Request |
| 101 | + uses: SonarSource/release-github-actions/create-pull-request@v1 |
| 102 | + with: |
| 103 | + title: 'WIP: New feature' |
| 104 | + branch: bot/new-feature |
| 105 | + draft: true |
| 106 | + body: | |
| 107 | + ## Summary |
| 108 | + This PR adds a new feature. |
| 109 | +
|
| 110 | + ## Details |
| 111 | + - Change 1 |
| 112 | + - Change 2 |
| 113 | +``` |
| 114 | +
|
| 115 | +### With branch suffix |
| 116 | +
|
| 117 | +```yaml |
| 118 | +- name: Create Pull Request |
| 119 | + uses: SonarSource/release-github-actions/create-pull-request@v1 |
| 120 | + with: |
| 121 | + title: 'Automated changes' |
| 122 | + branch: bot/changes |
| 123 | + branch-suffix: timestamp # or: random, short-commit-hash |
| 124 | +``` |
| 125 | +
|
| 126 | +## Token Resolution |
| 127 | +
|
| 128 | +The action resolves the GitHub token using the following priority: |
| 129 | +
|
| 130 | +1. **Vault token** (preferred): Fetches `development/github/token/{REPO_OWNER_NAME_DASH}-release-automation` via `SonarSource/vault-action-wrapper@v3` with `continue-on-error: true` |
| 131 | +2. **Input token** (fallback): Uses the `token` input (defaults to `${{ github.token }}`) |
| 132 | + |
| 133 | +If both fail, the action errors. This design allows the action to work in repositories with vault access (using a more privileged token) while gracefully falling back to the workflow token. |
| 134 | + |
| 135 | +## Migration from peter-evans/create-pull-request |
| 136 | + |
| 137 | +This action provides a compatible interface. Key differences: |
| 138 | + |
| 139 | +| Feature | peter-evans/create-pull-request | This action | |
| 140 | +|---------|--------------------------------|-------------| |
| 141 | +| Runtime | Node.js | Bash + `gh` CLI | |
| 142 | +| Token | Input only | Vault-preferred, input fallback | |
| 143 | +| Push | Built-in | `git push --force-with-lease` | |
| 144 | +| PR create/update | GitHub API | `gh pr create` / `gh pr edit` | |
| 145 | + |
| 146 | +To migrate, replace the `uses:` reference and ensure inputs match. Most inputs are compatible by name and behavior. |
| 147 | + |
| 148 | +## Behavior |
| 149 | + |
| 150 | +### No changes detected |
| 151 | +When no files have changed, the action outputs `pull-request-operation=none` and exits successfully without creating a branch or PR. |
| 152 | + |
| 153 | +### Existing PR |
| 154 | +When an open PR already exists for the same head and base branch, the action updates it (title, body, labels, reviewers) rather than creating a duplicate. |
| 155 | + |
| 156 | +### Branch management |
| 157 | +- The action uses `git checkout -B` to create or reset the PR branch |
| 158 | +- Push uses `--force-with-lease` to safely update the remote branch |
| 159 | +- When `delete-branch: true`, the branch is deleted only after the PR is merged |
| 160 | + |
| 161 | +## Error Handling |
| 162 | + |
| 163 | +The action will fail if: |
| 164 | +- No valid token is available (vault and input both empty) |
| 165 | +- The committer format is invalid |
| 166 | +- An invalid `branch-suffix` value is provided |
| 167 | +- Git operations fail (commit, push) |
| 168 | +- PR creation or update fails |
0 commit comments