Skip to content
Merged
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Opinionated GitHub Actions and reusable workflows for foundational continuous-in
### Workflow & repository automation

- [Checkout](actions/checkout/README.md) - event-aware drop-in replacement for `actions/checkout` that supports issue comment triggers.
- [Create and merge pull request](actions/create-and-merge-pull-request/README.md) - opens a pull request, rebases, and merges it with the GitHub Actions bot identity.
- [Create and merge pull request](actions/create-and-merge-pull-request/README.md) - opens a pull request and merges it with the configured strategy and GitHub Actions bot identity.
- [Create or update comment](actions/create-or-update-comment/README.md) - adds or updates comments on issues and pull requests idempotently.
- [Get GitHub Actions bot user](actions/get-github-actions-bot-user/README.md) - retrieves the profile information for the GitHub Actions bot.
- [Get issue number](actions/get-issue-number/README.md) - extracts the relevant issue number from the current workflow context.
Expand Down
16 changes: 13 additions & 3 deletions actions/create-and-merge-pull-request/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
## Overview

Action to create and merge Pull Request.
Opinionated, set GitHub Actions bot as author, then rebase and merge.
Opinionated, set GitHub Actions bot as author, then merge with the configured strategy.

For this action to work you must explicitly allow GitHub Actions to create pull requests.
See <https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository>.
Expand All @@ -50,17 +50,23 @@ See <https://docs.github.com/en/repositories/managing-your-repositorys-settings-
# This input is required.
branch: ""

# The pull request title
# The pull request title and, for merge/squash merges, the merged commit title
# This input is required.
title: ""

# The pull request body
# This input is required.
body: ""

# The commit message for the pull request
# The commit message for the pull request and, for merge/squash merges, the merged commit body
# This input is required.
commit-message: ""

# Merge strategy for the created pull request.
# Valid values: `merge`, `rebase`, `squash`.
#
# Default: `rebase`
merge-method: rebase
```

<!-- usage:end -->
Expand All @@ -75,8 +81,12 @@ See <https://docs.github.com/en/repositories/managing-your-repositorys-settings-
| | See <https://github.com/peter-evans/create-pull-request#action-inputs>. | | |
| **`branch`** | The pull request branch name | **true** | - |
| **`title`** | The pull request title | **true** | - |
| | Also used as the merged commit title for `merge` and `squash`. | | |
| **`body`** | The pull request body | **true** | - |
| **`commit-message`** | The commit message for the pull request | **true** | - |
| | Also used as the merged commit body for `merge` and `squash`. | | |
| **`merge-method`** | Merge strategy for the created pull request. | **false** | `rebase` |
| | Valid values: `merge`, `rebase`, `squash`. | | |

<!-- inputs:end -->

Expand Down
63 changes: 50 additions & 13 deletions actions/create-and-merge-pull-request/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
name: "Create and merge Pull Request"
description: |
Action to create and merge Pull Request.
Opinionated, set GitHub Actions bot as author, then rebase and merge.
Opinionated, set GitHub Actions bot as author, then merge with the configured strategy.
author: hoverkraft
branding:
icon: git-pull-request
Expand All @@ -20,14 +20,20 @@ inputs:
description: "The pull request branch name"
required: true
title:
description: "The pull request title"
description: "The pull request title and, for merge/squash merges, the merged commit title"
required: true
body:
description: "The pull request body"
required: true
commit-message:
description: "The commit message for the pull request"
description: "The commit message for the pull request and, for merge/squash merges, the merged commit body"
required: true
merge-method:
description: |
Merge strategy for the created pull request.
Valid values: `merge`, `rebase`, `squash`.
default: rebase
required: false

outputs:
merged-ref:
Expand Down Expand Up @@ -82,16 +88,33 @@ runs:
env:
GH_TOKEN: ${{ inputs.github-token }}
PULL_REQUEST_NUMBER: ${{ steps.create-pull-request.outputs.pull-request-number }}
MERGE_METHOD: ${{ inputs.merge-method }}
PULL_REQUEST_TITLE: ${{ inputs.title }}
PULL_REQUEST_COMMIT_MESSAGE: ${{ inputs.commit-message }}
with:
github-token: ${{ inputs.github-token }}
script: |
const maxAttempts = 10;
const requiredWorkflowsError = 'Required workflow';
const repository = `${context.repo.owner}/${context.repo.repo}`;
const mergeMethod = (process.env.MERGE_METHOD ?? 'rebase').trim();
const mergeCommitTitle = (process.env.PULL_REQUEST_TITLE ?? '').trim();
const mergeCommitMessage = process.env.PULL_REQUEST_COMMIT_MESSAGE ?? '';
const mergeMethodFlags = {
merge: '--merge',
rebase: '--rebase',
squash: '--squash',
};
const getRetryDelayMs = attempt => Math.min(1000 * (2 ** attempt), 10000);

const sleep = delayMs => new Promise(resolve => setTimeout(resolve, delayMs));

if (!(mergeMethod in mergeMethodFlags)) {
throw new Error(
`Invalid merge method: ${mergeMethod}. Expected one of: ${Object.keys(mergeMethodFlags).join(', ')}`,
);
}

const waitFor = async ({
run,
isComplete,
Expand Down Expand Up @@ -154,20 +177,34 @@ runs:
getTimeoutMessage: () => `Pull request #${pullNumber} is not mergeable after ${maxAttempts} attempts`,
});

const getMergeArguments = pullNumber => {
const args = [
'pr',
'merge',
'-R',
repository,
mergeMethodFlags[mergeMethod],
'--admin',
String(pullNumber),
];

if (mergeMethod !== 'rebase' && mergeCommitTitle) {
args.push('--subject', mergeCommitTitle);
}

if (mergeMethod !== 'rebase' && mergeCommitMessage.trim()) {
args.push('--body', mergeCommitMessage);
}

return args;
};

const mergePullRequest = async pullNumber => {
core.debug(`Merging pull request #${pullNumber} for repository ${repository}...`);
core.debug(`Merging pull request #${pullNumber} for repository ${repository} with method ${mergeMethod}...`);

const { exitCode, stdout, stderr } = await exec.getExecOutput(
'gh',
[
'pr',
'merge',
'-R',
repository,
'--rebase',
'--admin',
String(pullNumber),
],
getMergeArguments(pullNumber),
{
env: process.env,
ignoreReturnCode: true,
Expand Down
Loading