Compare commits

...

143 Commits

Author SHA1 Message Date
01f7dd1d28 Merge pull request #829 from peter-evans/logging
fix: improve logging
2021-05-14 13:58:45 +09:00
32c71c837c fix: improve logging 2021-05-14 13:47:55 +09:00
a6d621d73e Merge pull request #820 from peter-evans/dependabot/npm_and_yarn/hosted-git-info-2.8.9
build(deps): bump hosted-git-info from 2.8.8 to 2.8.9
2021-05-13 13:18:59 +09:00
09f51e6391 Merge pull request #819 from peter-evans/dependabot/npm_and_yarn/lodash-4.17.21
build(deps): bump lodash from 4.17.19 to 4.17.21
2021-05-13 13:09:37 +09:00
ed04db61de build(deps): bump hosted-git-info from 2.8.8 to 2.8.9
Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.8 to 2.8.9.
- [Release notes](https://github.com/npm/hosted-git-info/releases)
- [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md)
- [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-13 03:57:30 +00:00
ea6b55fc9d build(deps): bump lodash from 4.17.19 to 4.17.21
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.19 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.19...4.17.21)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-13 03:57:16 +00:00
88896f707d Merge pull request #816 from peter-evans/update-distribution
Update distribution
2021-05-13 12:51:15 +09:00
423630f7c0 build: update distribution 2021-05-13 03:50:34 +00:00
66cc0cc1e2 Merge pull request #776 from peter-evans/update-dependencies
Update dependencies
2021-05-13 12:48:13 +09:00
2a63057d1e chore: update dependencies 2021-05-13 02:16:24 +00:00
f83efdc34a docs: update default branch 2021-05-13 09:53:24 +09:00
fff683e9ca docs: update default branch 2021-05-13 09:43:00 +09:00
9f83247b25 ci: update default branch 2021-05-13 09:42:47 +09:00
670e508eb6 docs: update readme 2021-05-11 10:12:39 +09:00
d9d6fd980e Merge pull request #804 from peter-evans/gpg-sign-fix
fix: remove unnecessary gpg-sign input
2021-05-10 09:19:01 +09:00
8bb8511e4d fix: remove unnecessary gpg-sign input 2021-05-10 09:01:53 +09:00
c1d92ef456 docs: update readme 2021-05-09 14:44:37 +09:00
1ff93da091 Merge pull request #795 from peter-evans/gpg-sign
feat: add input to enable gpg commit signing
2021-05-09 14:15:03 +09:00
0524c01297 feat: add input to enable gpg commit signing 2021-05-09 10:14:59 +09:00
548adff9dc docs: update examples 2021-04-09 15:03:53 +09:00
28674474a4 docs: add link to github blog post 2021-04-06 10:46:44 +09:00
4fb90330a4 Merge pull request #773 from peter-evans/update-distribution
Update distribution
2021-04-01 12:08:39 +09:00
e4c811acf5 build: update distribution 2021-04-01 03:07:25 +00:00
99ccb3479b Merge pull request #759 from peter-evans/update-dependencies
Update dependencies
2021-04-01 12:05:05 +09:00
13616a4432 fix: update octokit rest methods 2021-04-01 11:56:16 +09:00
b5b91bc2b0 chore: update dependencies 2021-04-01 01:28:21 +00:00
5666cd8fe9 Merge pull request #755 from peter-evans/update-distribution
Update distribution
2021-03-16 11:35:49 +09:00
ad897490d5 build: update distribution 2021-03-16 02:35:04 +00:00
0735106af9 Merge pull request #744 from peter-evans/update-dependencies
Update dependencies
2021-03-16 11:31:26 +09:00
9aeedaa8c2 fix: remove unnecessary prettier config 2021-03-16 11:16:45 +09:00
52d31873b6 chore: update dependencies 2021-03-11 01:43:57 +00:00
09b9ac155b Merge pull request #740 from peter-evans/update-distribution
Update distribution
2021-02-25 11:22:27 +09:00
6ec5e3e26b build: update distribution 2021-02-25 02:20:17 +00:00
8b46437b6d Merge pull request #709 from peter-evans/update-dependencies
Update dependencies
2021-02-25 11:17:55 +09:00
e361fd1788 chore: update dependencies 2021-02-25 01:38:41 +00:00
052fc72b41 Merge pull request #724 from peter-evans/fix-assignees
fix: use the correct assignees property
2021-02-10 09:28:28 +09:00
ed00d4629c fix: use the correct assignees property 2021-02-10 09:00:23 +09:00
34371f09e5 Merge pull request #719 from peter-evans/add-to-lists
fix: add to labels and assignees instead of resetting
2021-02-08 10:19:41 +09:00
c27ea51ae0 fix: add to labels and assignees instead of resetting 2021-02-08 09:32:46 +09:00
5e9d0ee9ea Merge pull request #712 from peter-evans/operation-output
feat: add pull-request-operation output
2021-02-01 10:28:29 +09:00
b5f41d9b08 feat: add pull-request-operation output 2021-02-01 09:57:11 +09:00
2455e15969 Merge pull request #704 from jonico/support-ghes
Support GitHub Enterprise Server
2021-01-26 11:17:38 +09:00
05bc46786e Support GitHub Server API URL
* pass GitHub Server API in Octokkit constructor
2021-01-25 19:16:19 +01:00
adc6552966 Support GitHub Enterprise Server
* parse GITHUB_SERVER_URL if present
* accept proper server remotes as well
2021-01-25 18:25:20 +01:00
171fc6cce4 Merge pull request #701 from peter-evans/update-distribution
Update distribution
2021-01-25 14:22:27 +09:00
3fb765f674 build: update distribution 2021-01-25 05:19:37 +00:00
d95c81ee98 Merge pull request #686 from peter-evans/update-dependencies
Update dependencies
2021-01-25 14:16:59 +09:00
8d5ed6557f chore: update dependencies 2021-01-21 02:46:33 +00:00
7b1819c092 Merge pull request #683 from peter-evans/update-distribution
Update distribution
2020-12-28 10:22:06 +09:00
be0a8c9666 build: update distribution 2020-12-28 01:20:44 +00:00
a0a6157bf1 Merge pull request #594 from peter-evans/update-dependencies
Update dependencies
2020-12-28 10:18:18 +09:00
9c5ec2e07d chore: update dependencies 2020-12-24 02:04:52 +00:00
45c510e1f6 Merge pull request #672 from peter-evans/reset-perf
perf: git reset instead of fetch
2020-12-23 14:28:23 +09:00
249b80db6b perf: git reset instead of fetch 2020-12-23 14:10:40 +09:00
6c2b44c6ac Merge pull request #666 from peter-evans/dependabot/npm_and_yarn/node-notifier-8.0.1
build(deps): bump node-notifier from 8.0.0 to 8.0.1
2020-12-23 09:48:12 +09:00
76c58cf6a9 build(deps): bump node-notifier from 8.0.0 to 8.0.1
Bumps [node-notifier](https://github.com/mikaelbr/node-notifier) from 8.0.0 to 8.0.1.
- [Release notes](https://github.com/mikaelbr/node-notifier/releases)
- [Changelog](https://github.com/mikaelbr/node-notifier/blob/v8.0.1/CHANGELOG.md)
- [Commits](https://github.com/mikaelbr/node-notifier/compare/v8.0.0...v8.0.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-12-22 13:17:50 +00:00
8c603dbb04 Merge pull request #653 from peter-evans/fix-error-handling
fix: change or->and to catch all errors
2020-12-09 09:56:23 +09:00
d01e0807ef fix: change or->and to catch all errors 2020-12-09 09:38:10 +09:00
ce699aa2d1 Merge pull request #637 from peter-evans/prune-remote
fix: prune stale remote ref for self-hosted runners
2020-11-25 12:40:23 +09:00
9984f611a7 fix: prune stale remote ref for self-hosted runners 2020-11-24 12:34:57 +09:00
ff0beed1b2 Merge pull request #627 from peter-evans/git-diff-perf
perf: set diff quiet and switch isdirty command order
2020-11-17 13:22:44 +09:00
ddeca94037 perf: set diff quiet and switch isdirty command order 2020-11-17 11:42:31 +09:00
0fd77ba8cc docs: add missing contents link 2020-10-26 09:23:01 +09:00
c7f493a800 docs: remove deprecated set-env example 2020-10-02 15:53:49 +09:00
91664dfb28 Merge pull request #604 from peter-evans/update-distribution
Update distribution
2020-10-02 15:18:04 +09:00
13ec5274b1 build: update distribution 2020-10-02 06:17:23 +00:00
bcf9790963 Merge pull request #599 from peter-evans/dependabot/npm_and_yarn/actions/core-1.2.6
Bump @actions/core from 1.2.5 to 1.2.6
2020-10-02 15:14:43 +09:00
88ea447de7 Bump @actions/core from 1.2.5 to 1.2.6
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-01 17:24:16 +00:00
da928d5fcc Merge pull request #587 from peter-evans/url-output
feat: output the pull request url
2020-09-17 11:18:34 +09:00
2465e435b9 feat: output the pull request url 2020-09-17 10:41:26 +09:00
37b2bd1eca Merge pull request #584 from peter-evans/update-distribution
Update distribution
2020-09-17 10:39:30 +09:00
eb13e17e17 build: update distribution 2020-09-17 01:38:44 +00:00
a1ecc20658 Merge pull request #565 from peter-evans/update-dependencies
Update dependencies
2020-09-17 10:36:25 +09:00
ffcad23634 chore: update dependencies 2020-09-17 01:15:53 +00:00
f4b52b768a Merge pull request #574 from peter-evans/update-distribution
Update distribution
2020-09-13 15:13:25 +09:00
af682c8fcb build: update distribution 2020-09-13 06:11:21 +00:00
7378b23cb0 Merge pull request #569 from peter-evans/dependabot/npm_and_yarn/node-fetch-2.6.1
Bump node-fetch from 2.6.0 to 2.6.1
2020-09-13 15:08:27 +09:00
370ae6d537 Bump node-fetch from 2.6.0 to 2.6.1
Bumps [node-fetch](https://github.com/bitinn/node-fetch) from 2.6.0 to 2.6.1.
- [Release notes](https://github.com/bitinn/node-fetch/releases)
- [Changelog](https://github.com/node-fetch/node-fetch/blob/master/docs/CHANGELOG.md)
- [Commits](https://github.com/bitinn/node-fetch/compare/v2.6.0...v2.6.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-09-12 21:49:56 +00:00
ae0797ee12 ci: update commit message type 2020-09-07 17:25:24 +09:00
e05457394a ci: update commit messages 2020-09-07 15:26:59 +09:00
44f76dd5b3 Merge pull request #558 from peter-evans/update-distribution
Update distribution
2020-09-07 09:30:37 +09:00
279e66ed27 Update distribution 2020-09-07 00:29:59 +00:00
ce9dd3641e Merge pull request #511 from peter-evans/update-dependencies
Update dependencies
2020-09-07 09:27:33 +09:00
1a00b34382 Update dependencies 2020-09-07 09:18:17 +09:00
e17bb55cb7 Merge pull request #547 from peter-evans/delete-branch
feat: add input for branch delete
2020-09-07 09:14:08 +09:00
1890e1ec35 Merge pull request #537 from peter-evans/squash-merge-fix
fix: reset branches to handle squash merge
2020-09-07 09:10:33 +09:00
a49ee3308e feat: add input for branch delete 2020-09-06 10:21:35 +09:00
16fa12ee5f fix: reset branches to handle squash merge 2020-09-06 08:55:33 +09:00
5ea31358e9 docs: updates related to checkout 2020-09-01 09:15:45 +09:00
105f0d3816 docs: update examples 2020-08-30 15:17:23 +09:00
8fb2374109 docs: update readme 2020-08-30 11:20:42 +09:00
a68328a1ee docs: update concepts-guidelines 2020-08-30 11:06:03 +09:00
9bf4b302a5 Merge pull request #526 from peter-evans/detached-head
feat: support checkout on a commit in addition to a ref
2020-08-30 10:02:44 +09:00
da6a868b86 docs: update readme 2020-08-30 09:55:17 +09:00
cbd5e97fef docs: update concepts-guidelines 2020-08-30 09:55:07 +09:00
095c53659b feat: support checkout on a commit in addition to a ref 2020-08-29 17:28:46 +09:00
fc687f898b docs: update examples 2020-08-25 12:18:25 +09:00
3b32bfa4f7 Merge pull request #517 from peter-evans/update-ncc
Change zeit to vercel
2020-08-22 11:51:38 +09:00
9c3bf74d10 Change zeit to vercel 2020-08-22 11:42:42 +09:00
b9ed02107c Update documentation 2020-08-22 11:11:38 +09:00
2f31350598 Remove unused slash command 2020-08-20 14:31:41 +09:00
d14206169d Update documentation 2020-08-19 18:29:04 +09:00
82c423c73b Merge pull request #508 from peter-evans/update-distribution
Update distribution
2020-08-19 17:40:53 +09:00
7cf22579c6 Update distribution 2020-08-19 08:39:31 +00:00
5893420513 Merge pull request #503 from peter-evans/not-updated-fix
Fix pr create/update for already up to date branches
2020-08-19 17:37:01 +09:00
8bdec9b230 Fix pr create/update for already up to date branches 2020-08-19 17:08:59 +09:00
2570a753e0 Merge pull request #497 from peter-evans/branch-check-fix
Fix branch naming check for push-to-fork
2020-08-19 14:27:34 +09:00
1c466bedd5 Fix branch naming check for push-to-fork 2020-08-19 12:22:50 +09:00
a755ad5ffb Merge pull request #492 from peter-evans/update-distribution
Update distribution
2020-08-19 12:21:35 +09:00
52cabd40b9 Update distribution 2020-08-19 03:20:28 +00:00
12b7e7a141 Merge pull request #467 from peter-evans/update-dependencies
Update dependencies
2020-08-19 12:18:09 +09:00
8f96fd0252 Merge pull request #488 from jsoref/spelling
Spelling
2020-08-19 12:09:20 +09:00
5f45e30ff9 spelling: uncommitted
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-08-18 12:51:12 -04:00
348abed1de spelling: javascript
Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
2020-08-17 23:27:12 -04:00
06ab0ad94e Update documentation 2020-08-16 13:34:15 +09:00
de6e791e81 Update documentation 2020-08-15 14:21:58 +09:00
184bc2eccd Update documentation 2020-08-14 11:08:04 +09:00
4dab765cf5 Update dependencies 2020-08-13 01:09:37 +00:00
329417f094 Update documentation 2020-08-04 22:02:58 +09:00
7311df63a5 Update documentation 2020-08-04 15:44:58 +09:00
47a0e6b298 Update documentation 2020-08-04 14:27:36 +09:00
9b02473bb0 Update documentation 2020-08-04 14:20:01 +09:00
40b1b245eb Merge pull request #477 from peter-evans/dev
signoff
2020-07-31 18:08:02 +09:00
64c8d492d5 Update documentation 2020-07-31 16:59:26 +09:00
28fddffcf8 Add test for signoff 2020-07-31 16:57:41 +09:00
ba8309ff9c Refactor setting commit params 2020-07-31 16:57:16 +09:00
ee482f51bd Move input next to commit related inputs for context 2020-07-31 16:56:10 +09:00
bf7dd38b26 Merge pull request #476 from pvogt09/master
Adds option to signoff commits
2020-07-31 15:12:43 +09:00
71a37c5c33 Update documentation 2020-07-31 10:24:31 +09:00
f9af0fbfc0 Merge pull request #3 from pvogt09/update-distribution
Update distribution
2020-07-30 17:18:52 +02:00
0c57887fe8 Update distribution 2020-07-30 15:18:17 +00:00
7ad9f6e012 try -s instead of --signoff
Signed-off-by: pvogt09 <50047961+pvogt09@users.noreply.github.com>
2020-07-30 16:23:22 +02:00
dd364f2835 adds argument to test cases
Signed-off-by: pvogt09 <50047961+pvogt09@users.noreply.github.com>
2020-07-30 16:06:07 +02:00
ddd52205b6 adds signoff option to sign off commits
Signed-off-by: pvogt09 <50047961+pvogt09@users.noreply.github.com>
2020-07-30 15:57:37 +02:00
a81d0faef6 Merge pull request #470 from peter-evans/rem-dep
Remove unnecessary dependency
2020-07-30 12:26:57 +09:00
fc03a820b2 Remove unnecessary dependency 2020-07-30 12:16:48 +09:00
b2cdf099d0 Update ci workflow 2020-07-25 14:02:46 +09:00
f3d08d3f0b Update slash-command-dispatch to v2 2020-07-25 13:23:29 +09:00
3a21b8d668 Update slash-command-dispatch to v2-beta 2020-07-25 12:53:35 +09:00
132b02c8e1 Merge pull request #455 from peter-evans/lodash-vuln
Update lodash to fix vuln
2020-07-23 17:18:11 +09:00
9507cdc7ac Update lodash to fix vuln 2020-07-23 17:06:02 +09:00
f4bf0d40c3 Update workflows to v3 2020-07-23 16:20:49 +09:00
cf325ed84b Update example screenshot 2020-07-23 15:37:47 +09:00
23 changed files with 15821 additions and 12035 deletions

View File

@ -9,8 +9,7 @@
"plugin:import/errors",
"plugin:import/warnings",
"plugin:import/typescript",
"plugin:prettier/recommended",
"prettier/@typescript-eslint"
"plugin:prettier/recommended"
],
"plugins": ["@typescript-eslint"],
"rules": {

View File

@ -1,12 +1,12 @@
name: CI
on:
push:
branches: [master]
branches: [main]
paths-ignore:
- 'README.md'
- 'docs/**'
pull_request:
branches: [master]
branches: [main]
paths-ignore:
- 'README.md'
- 'docs/**'
@ -45,7 +45,7 @@ jobs:
steps:
- uses: actions/checkout@v2
with:
ref: master
ref: main
- if: matrix.target == 'built' || github.event_name == 'pull_request'
uses: actions/download-artifact@v2
with:
@ -108,25 +108,22 @@ jobs:
```
package:
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: [test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: rm -rf dist
- uses: actions/download-artifact@v2
with:
name: dist
path: dist
- name: Create Pull Request
uses: peter-evans/create-pull-request@v2
uses: peter-evans/create-pull-request@v3
with:
commit-message: Update distribution
committer: GitHub <noreply@github.com>
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
commit-message: 'build: update distribution'
title: Update distribution
body: |
- Updates the distribution for changes on `master`
- Updates the distribution for changes on `main`
Auto-generated by [create-pull-request][1]

View File

@ -18,6 +18,7 @@ jobs:
commit-message: Update report
committer: GitHub <noreply@github.com>
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
signoff: false
title: '[Example] Update report'
body: |
Update report
@ -33,10 +34,12 @@ jobs:
milestone: 1
draft: false
branch: example-patches
delete-branch: true
- name: Check output
run: |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
- name: Add reaction
uses: peter-evans/create-or-update-comment@v1

View File

@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Slash Command Dispatch
uses: peter-evans/slash-command-dispatch@v1
uses: peter-evans/slash-command-dispatch@v2
with:
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
config: >
@ -18,12 +18,6 @@ jobs:
"repository": "peter-evans/create-pull-request-tests",
"named_args": true
},
{
"command": "pytest",
"permission": "admin",
"repository": "peter-evans/create-pull-request-tests",
"named_args": true
},
{
"command": "clean",
"permission": "admin",

View File

@ -15,10 +15,10 @@ jobs:
npx -p npm-check-updates ncu -u
npm install
- name: Create Pull Request
uses: peter-evans/create-pull-request@v2
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
commit-message: Update dependencies
commit-message: 'chore: update dependencies'
committer: GitHub <noreply@github.com>
author: actions-bot <actions-bot@users.noreply.github.com>
title: Update dependencies

View File

@ -26,6 +26,10 @@ Create Pull Request action will:
## Usage
```yml
- uses: actions/checkout@v2
# Make changes to pull request here
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
```
@ -36,32 +40,40 @@ You can also pin to a [specific release](https://github.com/peter-evans/create-p
All inputs are **optional**. If not set, sensible defaults will be used.
**Note**: If you want pull requests created by this action to trigger an `on: push` or `on: pull_request` workflow then you cannot use the default `GITHUB_TOKEN`. See the [documentation here](https://github.com/peter-evans/create-pull-request/blob/master/docs/concepts-guidelines.md#triggering-further-workflow-runs) for workarounds.
**Note**: If you want pull requests created by this action to trigger an `on: push` or `on: pull_request` workflow then you cannot use the default `GITHUB_TOKEN`. See the [documentation here](docs/concepts-guidelines.md#triggering-further-workflow-runs) for workarounds.
| Name | Description | Default |
| --- | --- | --- |
| `token` | `GITHUB_TOKEN` or a `repo` scoped [Personal Access Token (PAT)](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line). | `GITHUB_TOKEN` |
| `token` | `GITHUB_TOKEN` (`contents: write`, `pull-requests: write`) or a `repo` scoped [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token). | `GITHUB_TOKEN` |
| `path` | Relative path under `GITHUB_WORKSPACE` to the repository. | `GITHUB_WORKSPACE` |
| `commit-message` | The message to use when committing changes. | `[create-pull-request] automated change` |
| `committer` | The committer name and email address in the format `Display Name <email@address.com>`. Defaults to the GitHub Actions bot user. | `GitHub <noreply@github.com>` |
| `author` | The author name and email address in the format `Display Name <email@address.com>`. Defaults to the user who triggered the workflow run. | `${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>` |
| `signoff` | Add [`Signed-off-by`](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---signoff) line by the committer at the end of the commit log message. | `false` |
| `branch` | The pull request branch name. | `create-pull-request/patch` |
| `delete-branch` | Delete the `branch` when closing pull requests, and when undeleted after merging. Recommend `true`. | `false` |
| `branch-suffix` | The branch suffix type when using the alternative branching strategy. Valid values are `random`, `timestamp` and `short-commit-hash`. See [Alternative strategy](#alternative-strategy---always-create-a-new-pull-request-branch) for details. | |
| `base` | Sets the pull request base branch. | Defaults to the branch checked out in the workflow. |
| `push-to-fork` | A fork of the checked out parent repository to which the pull request branch will be pushed. e.g. `owner/repo-fork`. The pull request will be created to merge the fork's branch into the parent's base. See [push pull request branches to a fork](https://github.com/peter-evans/create-pull-request/blob/master/docs/concepts-guidelines.md#push-pull-request-branches-to-a-fork) for details. | |
| `push-to-fork` | A fork of the checked-out parent repository to which the pull request branch will be pushed. e.g. `owner/repo-fork`. The pull request will be created to merge the fork's branch into the parent's base. See [push pull request branches to a fork](docs/concepts-guidelines.md#push-pull-request-branches-to-a-fork) for details. | |
| `title` | The title of the pull request. | `Changes by create-pull-request action` |
| `body` | The body of the pull request. | `Automated changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action` |
| `labels` | A comma or newline separated list of labels. | |
| `assignees` | A comma or newline separated list of assignees (GitHub usernames). | |
| `reviewers` | A comma or newline separated list of reviewers (GitHub usernames) to request a review from. | |
| `team-reviewers` | A comma or newline separated list of GitHub teams to request a review from. Note that a `repo` scoped [PAT](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) may be required. See [this issue](https://github.com/peter-evans/create-pull-request/issues/155). | |
| `labels` | A comma or newline-separated list of labels. | |
| `assignees` | A comma or newline-separated list of assignees (GitHub usernames). | |
| `reviewers` | A comma or newline-separated list of reviewers (GitHub usernames) to request a review from. | |
| `team-reviewers` | A comma or newline-separated list of GitHub teams to request a review from. Note that a `repo` scoped [PAT](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) may be required. See [this issue](https://github.com/peter-evans/create-pull-request/issues/155). | |
| `milestone` | The number of the milestone to associate this pull request with. | |
| `draft` | Create a [draft pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests#draft-pull-requests). | `false` |
| `draft` | Create a [draft pull request](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests#draft-pull-requests). | `false` |
### Action outputs
The pull request number is output as a step output.
Note that in order to read the step output the action step must have an id.
The following outputs can be used by subsequent workflow steps.
- `pull-request-number` - The pull request number.
- `pull-request-url` - The URL of the pull request.
- `pull-request-operation` - The pull request operation performed by the action, `created`, `updated` or `closed`.
Step outputs can be accessed as in the following example.
Note that in order to read the step outputs the action step must have an id.
```yml
- name: Create Pull Request
@ -70,17 +82,7 @@ Note that in order to read the step output the action step must have an id.
- name: Check outputs
run: |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
```
### Checkout
This action expects repositories to be checked out with `actions/checkout@v2`.
If there is some reason you need to use `actions/checkout@v1` the following step can be added to checkout the branch.
```yml
- uses: actions/checkout@v1
- run: git checkout "${GITHUB_REF:11}"
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
```
### Action behaviour
@ -91,10 +93,10 @@ Any subsequent changes will be committed to the *same* branch and reflected in t
How the action behaves:
- If there are changes (i.e. a diff exists with the checked out base branch), the changes will be pushed to a new `branch` and a pull request created.
- If there are no changes (i.e. no diff exists with the checked out base branch), no pull request will be created and the action exits silently.
- If there are changes (i.e. a diff exists with the checked-out base branch), the changes will be pushed to a new `branch` and a pull request created.
- If there are no changes (i.e. no diff exists with the checked-out base branch), no pull request will be created and the action exits silently.
- If a pull request already exists and there are no further changes (i.e. no diff with the current pull request branch) then the action exits silently.
- If a pull request exists and new changes on the base branch make the pull request unnecessary (i.e. there is no longer a diff between the base and pull request branch), the pull request is automatically closed and the branch deleted.
- If a pull request exists and new changes on the base branch make the pull request unnecessary (i.e. there is no longer a diff between the pull request branch and the base), the pull request is automatically closed. Additionally, if `delete-branch` is set to `true` the `branch` will be deleted.
For further details about how the action works and usage guidelines, see [Concepts, guidelines and advanced usage](docs/concepts-guidelines.md).
@ -114,6 +116,7 @@ To use this strategy, set input `branch-suffix` with one of the following option
### Controlling commits
As well as relying on the action to handle uncommitted changes, you can additionally make your own commits before the action runs.
Note that the repository must be checked out on a branch with a remote, it won't work for [events which checkout a commit](docs/concepts-guidelines.md#events-which-checkout-a-commit).
```yml
steps:
@ -154,15 +157,19 @@ To create a project card for the pull request, pass the `pull-request-number` st
issue-number: ${{ steps.cpr.outputs.pull-request-number }}
```
### Auto-merge
Auto-merge can be enabled on a pull request allowing it to be automatically merged once requirements have been satisfied.
See [enable-pull-request-automerge](https://github.com/peter-evans/enable-pull-request-automerge) action for usage details.
## Reference Example
The following workflow is a reference example that sets all the main inputs.
The following workflow sets many of the action's inputs for reference purposes.
Check the [defaults](#action-inputs) to avoid setting inputs unnecessarily.
See [examples](docs/examples.md) for more realistic use cases.
```yml
name: Create Pull Request
on: push
jobs:
createPullRequest:
runs-on: ubuntu-latest
@ -180,7 +187,9 @@ jobs:
commit-message: Update report
committer: GitHub <noreply@github.com>
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
signoff: false
branch: example-patches
delete-branch: true
title: '[Example] Update report'
body: |
Update report
@ -199,9 +208,10 @@ jobs:
milestone: 1
draft: false
- name: Check output
- name: Check outputs
run: |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
```
An example based on the above reference configuration creates pull requests that look like this:

View File

@ -1,4 +1,8 @@
import {createOrUpdateBranch, tryFetch} from '../lib/create-or-update-branch'
import {
createOrUpdateBranch,
tryFetch,
getWorkingBaseAndType
} from '../lib/create-or-update-branch'
import * as fs from 'fs'
import {GitCommandManager} from '../lib/git-command-manager'
import * as path from 'path'
@ -193,6 +197,21 @@ describe('create-or-update-branch tests', () => {
expect(await tryFetch(git, REMOTE_NAME, NOT_EXIST_BRANCH)).toBeFalsy()
})
it('tests getWorkingBaseAndType on a checked out ref', async () => {
const [workingBase, workingBaseType] = await getWorkingBaseAndType(git)
expect(workingBase).toEqual(BASE)
expect(workingBaseType).toEqual('branch')
})
it('tests getWorkingBaseAndType on a checked out commit', async () => {
// Checkout the HEAD commit SHA
const headSha = await git.revParse('HEAD')
await git.exec(['checkout', headSha])
const [workingBase, workingBaseType] = await getWorkingBaseAndType(git)
expect(workingBase).toEqual(headSha)
expect(workingBaseType).toEqual('commit')
})
it('tests no changes resulting in no new branch being created', async () => {
const commitMessage = uuidv4()
const result = await createOrUpdateBranch(
@ -200,7 +219,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('none')
expect(await gitLogMatches([INIT_COMMIT_MESSAGE])).toBeTruthy()
@ -215,7 +235,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(trackedContent)
@ -241,7 +262,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
@ -260,7 +282,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(UNTRACKED_FILE)).toEqual(untrackedContent)
@ -286,7 +309,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
@ -307,7 +331,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
@ -334,9 +359,10 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('none')
expect(_result.action).toEqual('not-updated')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
expect(
@ -353,7 +379,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
@ -388,7 +415,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
@ -417,7 +445,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
@ -443,7 +472,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeFalsy()
@ -462,7 +492,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
@ -500,7 +531,76 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeFalsy()
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
expect(await getFileContent(UNTRACKED_FILE)).toEqual(_changes.untracked)
expect(
await gitLogMatches([...commits.commitMsgs, INIT_COMMIT_MESSAGE])
).toBeTruthy()
})
it('tests create, squash merge, and update with identical changes', async () => {
// Branches that have been squash merged appear to have a diff with the base due to
// different commits for the same changes. To prevent creating pull requests
// unnecessarily we reset (rebase) the pull request branch when a reset would result
// in no diff with the base. This will reset any undeleted branches after merging.
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const result = await createOrUpdateBranch(
git,
commitMessage,
'',
BRANCH,
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
expect(
await gitLogMatches([commitMessage, INIT_COMMIT_MESSAGE])
).toBeTruthy()
// Push pull request branch to remote
await git.push([
'--force-with-lease',
REMOTE_NAME,
`HEAD:refs/heads/${BRANCH}`
])
await afterTest(false)
await beforeTest()
// Create a commit on the base with the same changes as the branch
// This simulates squash merge of the pull request
const commits = await createCommits(
git,
1,
changes.tracked,
changes.untracked
)
await git.push([
'--force',
REMOTE_NAME,
`HEAD:refs/heads/${DEFAULT_BRANCH}`
])
// Create the same tracked and untracked file changes (no change on update)
const _changes = await createChanges(changes.tracked, changes.untracked)
const _commitMessage = uuidv4()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
'',
BRANCH,
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeFalsy()
@ -520,7 +620,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(commits.changes.tracked)
@ -549,7 +650,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
@ -573,7 +675,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
@ -606,7 +709,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
@ -632,7 +736,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
@ -673,7 +778,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
'',
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
@ -698,7 +804,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
'',
BRANCH,
FORK_REMOTE_NAME
FORK_REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
@ -725,7 +832,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
'',
BRANCH,
FORK_REMOTE_NAME
FORK_REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
@ -736,6 +844,69 @@ describe('create-or-update-branch tests', () => {
).toBeTruthy()
})
it('tests create and update with signoff on commit', async () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const result = await createOrUpdateBranch(
git,
commitMessage,
'',
BRANCH,
REMOTE_NAME,
true
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
expect(
await gitLogMatches([commitMessage, INIT_COMMIT_MESSAGE])
).toBeTruthy()
// Check signoff in commit body
const commitBody = (
await git.exec(['log', `-1`, '--format=%b'])
).stdout.trim()
expect(commitBody).toEqual(
'Signed-off-by: Committer Name <committer@example.com>'
)
// Push pull request branch to remote
await git.push([
'--force-with-lease',
REMOTE_NAME,
`HEAD:refs/heads/${BRANCH}`
])
await afterTest(false)
await beforeTest()
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
'',
BRANCH,
REMOTE_NAME,
true
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
expect(await getFileContent(UNTRACKED_FILE)).toEqual(_changes.untracked)
expect(
await gitLogMatches([_commitMessage, INIT_COMMIT_MESSAGE])
).toBeTruthy()
// Check signoff in commit body
const _commitBody = (
await git.exec(['log', `-1`, '--format=%b'])
).stdout.trim()
expect(_commitBody).toEqual(
'Signed-off-by: Committer Name <committer@example.com>'
)
})
// Working Base is Not Base (WBNB)
it('tests no changes resulting in no new branch being created (WBNB)', async () => {
@ -748,7 +919,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('none')
expect(await gitLogMatches([INIT_COMMIT_MESSAGE])).toBeTruthy()
@ -766,7 +938,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(trackedContent)
@ -795,7 +968,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
@ -817,7 +991,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(UNTRACKED_FILE)).toEqual(untrackedContent)
@ -846,7 +1021,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
@ -870,7 +1046,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
@ -900,9 +1077,10 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('none')
expect(_result.action).toEqual('not-updated')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
expect(
@ -922,7 +1100,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
@ -960,7 +1139,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
@ -992,7 +1172,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
@ -1021,7 +1202,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeFalsy()
@ -1045,7 +1227,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
@ -1086,7 +1269,82 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeFalsy()
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
expect(await getFileContent(UNTRACKED_FILE)).toEqual(_changes.untracked)
expect(
await gitLogMatches([...commits.commitMsgs, INIT_COMMIT_MESSAGE])
).toBeTruthy()
})
it('tests create, squash merge, and update with identical changes (WBNB)', async () => {
// Branches that have been squash merged appear to have a diff with the base due to
// different commits for the same changes. To prevent creating pull requests
// unnecessarily we reset (rebase) the pull request branch when a reset would result
// in no diff with the base. This will reset any undeleted branches after merging.
// Set the working base to a branch that is not the pull request base
await git.checkout(NOT_BASE_BRANCH)
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const result = await createOrUpdateBranch(
git,
commitMessage,
BASE,
BRANCH,
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
expect(
await gitLogMatches([commitMessage, INIT_COMMIT_MESSAGE])
).toBeTruthy()
// Push pull request branch to remote
await git.push([
'--force-with-lease',
REMOTE_NAME,
`HEAD:refs/heads/${BRANCH}`
])
await afterTest(false)
await beforeTest()
// Create a commit on the base with the same changes as the branch
// This simulates squash merge of the pull request
const commits = await createCommits(
git,
1,
changes.tracked,
changes.untracked
)
await git.push([
'--force',
REMOTE_NAME,
`HEAD:refs/heads/${DEFAULT_BRANCH}`
])
// Set the working base to a branch that is not the pull request base
await git.checkout(NOT_BASE_BRANCH)
// Create the same tracked and untracked file changes (no change on update)
const _changes = await createChanges(changes.tracked, changes.untracked)
const _commitMessage = uuidv4()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
BASE,
BRANCH,
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeFalsy()
@ -1109,7 +1367,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(commits.changes.tracked)
@ -1141,7 +1400,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
@ -1168,7 +1428,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
@ -1204,7 +1465,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
@ -1233,7 +1495,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
@ -1277,7 +1540,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
BASE,
BRANCH,
REMOTE_NAME
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
@ -1305,7 +1569,8 @@ describe('create-or-update-branch tests', () => {
commitMessage,
BASE,
BRANCH,
FORK_REMOTE_NAME
FORK_REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
@ -1335,7 +1600,8 @@ describe('create-or-update-branch tests', () => {
_commitMessage,
BASE,
BRANCH,
FORK_REMOTE_NAME
FORK_REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
@ -1345,4 +1611,133 @@ describe('create-or-update-branch tests', () => {
await gitLogMatches([_commitMessage, INIT_COMMIT_MESSAGE])
).toBeTruthy()
})
// Working Base is Not a Ref (WBNR)
// A commit is checked out leaving the repository in a "detached HEAD" state
it('tests create and update in detached HEAD state (WBNR)', async () => {
// Checkout the HEAD commit SHA
const headSha = await git.revParse('HEAD')
await git.checkout(headSha)
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const result = await createOrUpdateBranch(
git,
commitMessage,
BASE,
BRANCH,
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
expect(
await gitLogMatches([commitMessage, INIT_COMMIT_MESSAGE])
).toBeTruthy()
// Push pull request branch to remote
await git.push([
'--force-with-lease',
REMOTE_NAME,
`HEAD:refs/heads/${BRANCH}`
])
await afterTest(false)
await beforeTest()
// Checkout the HEAD commit SHA
const _headSha = await git.revParse('HEAD')
await git.checkout(_headSha)
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
BASE,
BRANCH,
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
expect(await getFileContent(UNTRACKED_FILE)).toEqual(_changes.untracked)
expect(
await gitLogMatches([_commitMessage, INIT_COMMIT_MESSAGE])
).toBeTruthy()
})
it('tests create and update with commits on the base inbetween, in detached HEAD state (WBNR)', async () => {
// Checkout the HEAD commit SHA
const headSha = await git.revParse('HEAD')
await git.checkout(headSha)
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const result = await createOrUpdateBranch(
git,
commitMessage,
BASE,
BRANCH,
REMOTE_NAME,
false
)
expect(result.action).toEqual('created')
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
expect(
await gitLogMatches([commitMessage, INIT_COMMIT_MESSAGE])
).toBeTruthy()
// Push pull request branch to remote
await git.push([
'--force-with-lease',
REMOTE_NAME,
`HEAD:refs/heads/${BRANCH}`
])
await afterTest(false)
await beforeTest()
// Create commits on the base
const commitsOnBase = await createCommits(git)
await git.push([
'--force',
REMOTE_NAME,
`HEAD:refs/heads/${DEFAULT_BRANCH}`
])
// Checkout the HEAD commit SHA
const _headSha = await git.revParse('HEAD')
await git.checkout(_headSha)
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
BASE,
BRANCH,
REMOTE_NAME,
false
)
expect(_result.action).toEqual('updated')
expect(_result.hasDiffWithBase).toBeTruthy()
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
expect(await getFileContent(UNTRACKED_FILE)).toEqual(_changes.untracked)
expect(
await gitLogMatches([
_commitMessage,
...commitsOnBase.commitMsgs,
INIT_COMMIT_MESSAGE
])
).toBeTruthy()
})
})

View File

@ -21,9 +21,17 @@ inputs:
The author name and email address in the format `Display Name <email@address.com>`.
Defaults to the user who triggered the workflow run.
default: '${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>'
signoff:
description: 'Add `Signed-off-by` line by the committer at the end of the commit log message.'
default: false
branch:
description: 'The pull request branch name.'
default: 'create-pull-request/patch'
delete-branch:
description: >
Delete the `branch` when closing pull requests, and when undeleted after merging.
Recommend `true`.
default: false
branch-suffix:
description: 'The branch suffix type when using the alternative branching strategy.'
base:

13854
dist/index.js vendored

File diff suppressed because it is too large Load Diff

View File

@ -29,37 +29,37 @@
orientation: "vertical-reverse"
});
const master = gitgraph.branch("master");
master.commit("Last commit on base");
const localMaster = gitgraph.branch("<#1> master (local)");
localMaster.commit({
subject: "<uncommited changes>",
body: "Changes made to the local base during the workflow",
const main = gitgraph.branch("main");
main.commit("Last commit on base");
const localMain = gitgraph.branch("<#1> main (local)");
localMain.commit({
subject: "<uncommitted changes>",
body: "Changes to the local base during the workflow",
})
const remotePatch = gitgraph.branch("create-pull-request/patch");
remotePatch.merge({
branch: localMaster,
branch: localMain,
commitOptions: {
subject: "[create-pull-request] automated change",
body: "Changes pushed to create the remote branch",
},
});
master.commit("New commit on base");
main.commit("New commit on base");
const localMaster2 = gitgraph.branch("<#2> master (local)");
localMaster2.commit({
subject: "<uncommited changes>",
body: "Changes made to the updated local base during the workflow",
const localMain2 = gitgraph.branch("<#2> main (local)");
localMain2.commit({
subject: "<uncommitted changes>",
body: "Changes to the updated local base during the workflow",
})
remotePatch.merge({
branch: localMaster2,
branch: localMain2,
commitOptions: {
subject: "[create-pull-request] automated change",
body: "Changes force pushed to update the remote branch",
},
});
master.merge(remotePatch);
main.merge(remotePatch);
</script>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 327 KiB

View File

@ -7,8 +7,8 @@ This document covers terminology, how the action works, general usage guidelines
- [How the action works](#how-the-action-works)
- [Guidelines](#guidelines)
- [Providing a consistent base](#providing-a-consistent-base)
- [Pull request events](#pull-request-events)
- [Restrictions on forked repositories](#restrictions-on-forked-repositories)
- [Events which checkout a commit](#events-which-checkout-a-commit)
- [Restrictions on repository forks](#restrictions-on-repository-forks)
- [Triggering further workflow runs](#triggering-further-workflow-runs)
- [Security](#security)
- [Advanced usage](#advanced-usage)
@ -16,12 +16,12 @@ This document covers terminology, how the action works, general usage guidelines
- [Push using SSH (deploy keys)](#push-using-ssh-deploy-keys)
- [Push pull request branches to a fork](#push-pull-request-branches-to-a-fork)
- [Authenticating with GitHub App generated tokens](#authenticating-with-github-app-generated-tokens)
- [GPG commit signature verification](#gpg-commit-signature-verification)
- [Running in a container or on self-hosted runners](#running-in-a-container-or-on-self-hosted-runners)
- [Creating pull requests on tag push](#creating-pull-requests-on-tag-push)
## Terminology
[Pull requests](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests#about-pull-requests) are proposed changes to a repository branch that can be reviewed by a repository's collaborators before being accepted or rejected.
[Pull requests](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests#about-pull-requests) are proposed changes to a repository branch that can be reviewed by a repository's collaborators before being accepted or rejected.
A pull request references two branches:
@ -30,9 +30,8 @@ A pull request references two branches:
## Events and checkout
For each [event type](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/events-that-trigger-workflows) there is a default `GITHUB_SHA` that will be checked out by the GitHub Actions [checkout](https://github.com/actions/checkout) action.
The majority of events will default to checking out the "last commit on default branch," which in most cases will be the latest commit on `master`.
This action expects repositories to be checked out with the official GitHub Actions [checkout](https://github.com/actions/checkout) action.
For each [event type](https://docs.github.com/en/actions/reference/events-that-trigger-workflows) there is a default `GITHUB_SHA` that will be checked out.
The default can be overridden by specifying a `ref` on checkout.
@ -44,7 +43,7 @@ The default can be overridden by specifying a `ref` on checkout.
## How the action works
By default, the action expects to be executed on the pull request `base`&mdash;the branch you intend to modify with the proposed changes.
Unless the `base` input is supplied, the action expects the target repository to be checked out on the pull request `base`&mdash;the branch you intend to modify with the proposed changes.
Workflow steps:
@ -60,11 +59,11 @@ The following git diagram shows how the action creates and updates a pull reques
### Providing a consistent base
For the action to work correctly it should be executed in a workflow that checks out a *consistent base* branch. This will be the base of the pull request unless overridden with the `base` input.
For the action to work correctly it should be executed in a workflow that checks out a *consistent* base branch. This will be the base of the pull request unless overridden with the `base` input.
This means your workflow should be consistently checking out the branch that you intend to modify once the PR is merged.
In the following example, the [`push`](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/events-that-trigger-workflows#push-event-push) and [`create`](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/events-that-trigger-workflows#create-event-create) events both trigger the same workflow. This will cause the checkout action to checkout commits from inconsistent branches. Do *not* do this. It will cause multiple pull requests to be created for each additional `base` the action is executed against.
In the following example, the [`push`](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#push) and [`create`](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#create) events both trigger the same workflow. This will cause the checkout action to checkout inconsistent branches and commits. Do *not* do this. It will cause multiple pull requests to be created for each additional `base` the action is executed against.
```yml
on:
@ -77,32 +76,48 @@ jobs:
- uses: actions/checkout@v2
```
Although rare, there may be use cases where it makes sense to execute the workflow on a branch that is not the base of the pull request. In these cases, the base branch can be specified with the `base` action input. The action will attempt to rebase changes made during the workflow on to the actual base.
There may be use cases where it makes sense to execute the workflow on a branch that is not the base of the pull request. In these cases, the base branch can be specified with the `base` action input. The action will attempt to rebase changes made during the workflow on to the actual base.
### Pull request events
### Events which checkout a commit
Workflows triggered by `pull_request` events will by default check out a [merge commit](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/events-that-trigger-workflows#pull-request-event-pull_request). To prevent the merge commit being included in created pull requests it is necessary to checkout the `head_ref`.
The [default checkout](#events-and-checkout) for the majority of events will leave the repository checked out on a branch.
However, some events such as `release` and `pull_request` will leave the repository in a "detached HEAD" state.
This is because they checkout a commit, not a branch.
In these cases, you *must supply* the `base` input so the action can rebase changes made during the workflow for the pull request.
Workflows triggered by [`pull_request`](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request) events will by default check out a merge commit. Set the `base` input as follows to base the new pull request on the current pull request's branch.
```yml
- uses: actions/checkout@v2
- uses: peter-evans/create-pull-request@v3
with:
ref: ${{ github.head_ref }}
base: ${{ github.head_ref }}
```
### Restrictions on forked repositories
Workflows triggered by [`release`](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#release) events will by default check out a tag. For most use cases, you will need to set the `base` input to the branch name of the tagged commit.
GitHub Actions have imposed restrictions on events triggered by a forked repository. Specifically, the `pull_request` event triggered by a fork opening a pull request in the upstream repository.
```yml
- uses: peter-evans/create-pull-request@v3
with:
base: main
```
- Events from forks cannot access secrets, except for for the default `GITHUB_TOKEN`.
### Restrictions on repository forks
GitHub Actions have imposed restrictions on workflow runs triggered by public repository forks.
Private repositories can be configured to [enable workflows](https://docs.github.com/en/github/administering-a-repository/disabling-or-limiting-github-actions-for-a-repository#enabling-workflows-for-private-repository-forks) from forks to run without restriction.
The restrictions apply to the `pull_request` event triggered by a fork opening a pull request in the upstream repository.
- Events from forks cannot access secrets, except for the default `GITHUB_TOKEN`.
> With the exception of GITHUB_TOKEN, secrets are not passed to the runner when a workflow is triggered from a forked repository.
[GitHub Actions: Using encrypted secrets in a workflow](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets#using-encrypted-secrets-in-a-workflow)
[GitHub Actions: Using encrypted secrets in a workflow](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#using-encrypted-secrets-in-a-workflow)
- The `GITHUB_TOKEN` has read-only access when an event is triggered by a forked repository.
[GitHub Actions: Permissions for the GITHUB_TOKEN](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/authenticating-with-the-github_token#permissions-for-the-github_token)
[GitHub Actions: Permissions for the GITHUB_TOKEN](https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token#permissions-for-the-github_token)
These restrictions mean that during a `pull_request` event triggered by a forked repository, actions have no write access to GitHub resources and will fail on attempt.
These restrictions mean that during a `pull_request` event triggered by a forked repository, actions have no write access to GitHub resources and will fail on any attempt.
A job condition can be added to prevent workflows from executing when triggered by a repository fork.
@ -115,22 +130,28 @@ jobs:
if: github.event.pull_request.head.repo.full_name == github.repository
```
For further reading regarding the security of pull requests, see this GitHub blog post titled [Keeping your GitHub Actions and workflows secure: Preventing pwn requests](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/)
### Triggering further workflow runs
Pull requests created by the action using the default `GITHUB_TOKEN` cannot trigger other workflows. If you have `on: pull_request` or `on: push` workflows acting as checks on pull requests, they will not run.
> When you use the repository's GITHUB_TOKEN to perform tasks on behalf of the GitHub Actions app, events triggered by the GITHUB_TOKEN will not create a new workflow run.
[GitHub Actions: Events that trigger workflows](https://help.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token)
[GitHub Actions: Events that trigger workflows](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token)
#### Workarounds to trigger further workflow runs
There are a number of workarounds with different pros and cons.
- Use the default `GITHUB_TOKEN` and allow the action to create pull requests that have no checks enabled. Manually close pull requests and immediately reopen them. This will enable `on: pull_request` workflows to run and be added as checks.
- Use a `repo` scoped [Personal Access Token (PAT)](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) created on an account that has write access to the repository that pull requests are being created in. This is the standard workaround and [recommended by GitHub](https://help.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token). However, the PAT cannot be scoped to a specific repository so the token becomes a very sensitive secret. If this is a concern, the PAT can instead be created for a dedicated [machine account](https://help.github.com/en/github/site-policy/github-terms-of-service#3-account-requirements) that has collaborator access to the repository. Also note that because the account that owns the PAT will be the creator of pull requests, that user account will be unable to perform actions such as request changes or approve the pull request.
- Use a `repo` scoped [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) created on an account that has write access to the repository that pull requests are being created in. This is the standard workaround and [recommended by GitHub](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token). However, the PAT cannot be scoped to a specific repository so the token becomes a very sensitive secret. If this is a concern, the PAT can instead be created for a dedicated [machine account](https://docs.github.com/en/github/site-policy/github-terms-of-service#3-account-requirements) that has collaborator access to the repository. Also note that because the account that owns the PAT will be the creator of pull requests, that user account will be unable to perform actions such as request changes or approve the pull request.
- Use [SSH (deploy keys)](#push-using-ssh-deploy-keys) to push the pull request branch. This is arguably more secure than using a PAT because deploy keys can be set per repository. However, this method will only trigger `on: push` workflows.
- Use a [machine account that creates pull requests from its own fork](#push-pull-request-branches-to-a-fork). This is the most secure because the PAT created only grants access to the machine account's fork, not the main repository. This method will trigger `on: pull_request` workflows to run. Workflows triggered `on: push` will not run because the push event is in the fork.
- Use a [GitHub App to generate a token](#authenticating-with-github-app-generated-tokens) that can be used with this action. GitHub App generated tokens are more secure than using a PAT because GitHub App access permissions can be set with finer granularity and are scoped to only repositories where the App is installed. This method will trigger both `on: push` and `on: pull_request` workflows.
### Security
@ -139,17 +160,17 @@ From a security perspective it's good practice to fork third-party actions, revi
By using third-party actions directly the risk exists that it could be modified to do something malicious, such as capturing secrets.
Alternatively, use the action directly and reference the commit hash for the version you want to target.
```
```yml
- uses: thirdparty/foo-action@172ec762f2ac8e050062398456fccd30444f8f30
```
This action uses [ncc](https://github.com/zeit/ncc) to compile the Node.js code and dependencies into a single Javascript file under the [dist](https://github.com/peter-evans/create-pull-request/tree/master/dist) directory.
This action uses [ncc](https://github.com/vercel/ncc) to compile the Node.js code and dependencies into a single JavaScript file under the [dist](https://github.com/peter-evans/create-pull-request/tree/main/dist) directory.
## Advanced usage
### Creating pull requests in a remote repository
Checking out a branch from a different repository from where the workflow is executing will make *that repository* the target for the created pull request. In this case, a `repo` scoped [Personal Access Token (PAT)](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) is required.
Checking out a branch from a different repository from where the workflow is executing will make *that repository* the target for the created pull request. In this case, a `repo` scoped [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) is required.
```yml
- uses: actions/checkout@v2
@ -166,12 +187,13 @@ Checking out a branch from a different repository from where the workflow is exe
### Push using SSH (deploy keys)
[Deploy keys](https://developer.github.com/v3/guides/managing-deploy-keys/#deploy-keys) can be set per repository and so are arguably more secure than using a `repo` scoped [Personal Access Token (PAT)](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line).
[Deploy keys](https://developer.github.com/v3/guides/managing-deploy-keys/#deploy-keys) can be set per repository and so are arguably more secure than using a `repo` scoped [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token).
Allowing the action to push with a configured deploy key will trigger `on: push` workflows. This makes it an alternative to using a PAT to trigger checks for pull requests.
Note that you cannot use deploy keys alone to [create a pull request in a remote repository](#creating-pull-requests-in-a-remote-repository) because then using a PAT would become a requirement. This method only makes sense if creating a pull request in the repository where the workflow is running.
How to use SSH (deploy keys) with create-pull-request action:
1. [Create a new SSH key pair](https://help.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent#generating-a-new-ssh-key) for your repository. Do not set a passphrase.
1. [Create a new SSH key pair](https://docs.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent#generating-a-new-ssh-key) for your repository. Do not set a passphrase.
2. Copy the contents of the public key (.pub file) to a new repository [deploy key](https://developer.github.com/v3/guides/managing-deploy-keys/#deploy-keys) and check the box to "Allow write access."
3. Add a secret to the repository containing the entire contents of the private key.
4. As shown in the example below, configure `actions/checkout` to use the deploy key you have created.
@ -191,14 +213,14 @@ How to use SSH (deploy keys) with create-pull-request action:
### Push pull request branches to a fork
Instead of pushing pull request branches to the repository you want to update, you can push them to a fork of that repository.
This allows you to employ the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege) by using a dedicated user acting as a [machine account](https://help.github.com/en/github/site-policy/github-terms-of-service#3-account-requirements).
This allows you to employ the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege) by using a dedicated user acting as a [machine account](https://docs.github.com/en/github/site-policy/github-terms-of-service#3-account-requirements).
This user has no access to the main repository.
It will use their own fork to push code and create the pull request.
1. Create a new GitHub user and login.
2. Fork the repository that you will be creating pull requests in.
3. Create a [Personal Access Token (PAT)](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line).
4. Logout and log back in to your main user account.
3. Create a [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token).
4. Logout and log back into your main user account.
5. Add a secret to your repository containing the above PAT.
6. As shown in the following example workflow, set the `push-to-fork` input to the full repository name of the fork.
@ -216,10 +238,10 @@ It will use their own fork to push code and create the pull request.
### Authenticating with GitHub App generated tokens
A GitHub App can be created for the sole purpose of generating tokens for use with GitHub actions.
These tokens can be used in place of `GITHUB_TOKEN` or a [Personal Access Token (PAT)](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line).
These tokens can be used in place of `GITHUB_TOKEN` or a [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token).
GitHub App generated tokens are more secure than using a PAT because GitHub App access permissions can be set with finer granularity and are scoped to only repositories where the App is installed.
1. Create a minimal [GitHub App](https://developer.github.com/apps/building-github-apps/creating-a-github-app/), setting the following fields:
1. Create a minimal [GitHub App](https://docs.github.com/en/developers/apps/creating-a-github-app), setting the following fields:
- Set `GitHub App name`.
- Set `Homepage URL` to anything you like, such as your GitHub profile page.
@ -253,6 +275,48 @@ GitHub App generated tokens are more secure than using a PAT because GitHub App
token: ${{ steps.generate-token.outputs.token }}
```
### GPG commit signature verification
The action can use GPG to sign commits with a GPG key that you generate yourself.
1. Follow GitHub's guide to [generate a new GPG key](https://docs.github.com/en/github/authenticating-to-github/generating-a-new-gpg-key).
2. [Add the public key](https://docs.github.com/en/github/authenticating-to-github/adding-a-new-gpg-key-to-your-github-account) to the user account associated with the [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) that you will use with the action.
3. Copy the private key to your clipboard, replacing `email@example.com` with the email address of your GPG key.
```
# macOS
gpg --armor --export-secret-key email@example.com | pbcopy
```
4. Paste the private key into a repository secret where the workflow will run. e.g. `GPG_PRIVATE_KEY`
5. Create another repository secret for the key's passphrase, if applicable. e.g. `GPG_PASSPHRASE`
6. The following example workflow shows how to use [crazy-max/ghaction-import-gpg](https://github.com/crazy-max/ghaction-import-gpg) to import your GPG key and allow the action to sign commits.
Note that the `committer` email address *MUST* match the email address used to create your GPG key.
```yaml
steps:
- uses: actions/checkout@v2
- uses: crazy-max/ghaction-import-gpg@v3
with:
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
git-user-signingkey: true
git-commit-gpgsign: true
# Make changes to pull request here
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.PAT }}
committer: example <email@example.com>
```
### Running in a container or on self-hosted runners
This action can be run inside a container, or on [self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners), by installing the necessary dependencies.
@ -302,63 +366,3 @@ jobs:
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
```
### Creating pull requests on tag push
An `on: push` workflow will also trigger when tags are pushed.
During these events, the `actions/checkout` action will check out the `ref/tags/<tag>` git ref by default.
This means the repository will *not* be checked out on an active branch.
If you would like to run `create-pull-request` action on the tagged commit you can achieve this by creating a temporary branch as follows.
```yml
on:
push:
tags:
- 'v*.*.*'
jobs:
example:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Create a temporary tag branch
run: |
git config --global user.name 'GitHub'
git config --global user.email 'noreply@github.com'
git checkout -b temp-${GITHUB_REF:10}
git push --set-upstream origin temp-${GITHUB_REF:10}
# Make changes to pull request here
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
base: master
- name: Delete tag branch
run: |
git push --delete origin temp-${GITHUB_REF:10}
```
This is an alternative, simpler workflow to the one above. However, this is not guaranteed to checkout the tagged commit.
There is a chance that in between the tag being pushed and checking out the `master` branch in the workflow, another commit is made to `master`. If that possibility is not a concern, this workflow will work fine.
```yml
on:
push:
tags:
- 'v*.*.*'
jobs:
example:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
ref: master
# Make changes to pull request here
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
```

View File

@ -3,10 +3,14 @@
- [Use case: Create a pull request to update X on push](#use-case-create-a-pull-request-to-update-x-on-push)
- [Update project authors](#update-project-authors)
- [Keep a branch up-to-date with another](#keep-a-branch-up-to-date-with-another)
- [Use case: Create a pull request to update X on release](#use-case-create-a-pull-request-to-update-x-on-release)
- [Update changelog](#update-changelog)
- [Use case: Create a pull request to update X periodically](#use-case-create-a-pull-request-to-update-x-periodically)
- [Update NPM dependencies](#update-npm-dependencies)
- [Update Gradle dependencies](#update-gradle-dependencies)
- [Update Cargo dependencies](#update-cargo-dependencies)
- [Update SwaggerUI for GitHub Pages](#update-swaggerui-for-github-pages)
- [Keep a fork up-to-date with its upstream](#keep-a-fork-up-to-date-with-its-upstream)
- [Spider and download a website](#spider-and-download-a-website)
- [Use case: Create a pull request to update X by calling the GitHub API](#use-case-create-a-pull-request-to-update-x-by-calling-the-github-api)
- [Call the GitHub API from an external service](#call-the-github-api-from-an-external-service)
@ -16,6 +20,8 @@
- [Misc workflow tips](#misc-workflow-tips)
- [Filtering push events](#filtering-push-events)
- [Dynamic configuration using variables](#dynamic-configuration-using-variables)
- [Setting the pull request body from a file](#setting-the-pull-request-body-from-a-file)
- [Using a markdown template](#using-a-markdown-template)
- [Debugging GitHub Actions](#debugging-github-actions)
@ -32,7 +38,7 @@ name: Update AUTHORS
on:
push:
branches:
- master
- main
jobs:
updateAuthors:
runs-on: ubuntu-latest
@ -56,14 +62,14 @@ jobs:
This is a use case where a branch should be kept up to date with another by opening a pull request to update it. The pull request should then be updated with new changes until it is merged or closed.
In this example scenario, a branch called `production` should be updated via pull request to keep it in sync with `master`. Merging the pull request is effectively promoting those changes to production.
In this example scenario, a branch called `production` should be updated via pull request to keep it in sync with `main`. Merging the pull request is effectively promoting those changes to production.
```yml
name: Create production promotion pull request
on:
push:
branches:
- master
- main
jobs:
productionPromotion:
runs-on: ubuntu-latest
@ -73,14 +79,53 @@ jobs:
ref: production
- name: Reset promotion branch
run: |
git fetch origin master:master
git reset --hard master
git fetch origin main:main
git reset --hard main
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
branch: production-promotion
```
## Use case: Create a pull request to update X on release
This pattern will work well for updating any kind of static content based on the tagged commit of a release. Note that because `release` is one of the [events which checkout a commit](concepts-guidelines.md#events-which-checkout-a-commit) it is necessary to supply the `base` input to the action.
### Update changelog
Raises a pull request to update the `CHANGELOG.md` file based on the tagged commit of the release.
Note that [git-chglog](https://github.com/git-chglog/git-chglog/) requires some configuration files to exist in the repository before this workflow will work.
This workflow assumes the tagged release was made on a default branch called `main`.
```yml
name: Update Changelog
on:
release:
types: [published]
jobs:
updateChangelog:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Update Changelog
run: |
curl -o git-chglog -L https://github.com/git-chglog/git-chglog/releases/download/0.9.1/git-chglog_linux_amd64
chmod u+x git-chglog
./git-chglog -o CHANGELOG.md
rm git-chglog
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
commit-message: update changelog
title: Update Changelog
body: Update changelog to reflect release changes
branch: update-changelog
base: main
```
## Use case: Create a pull request to update X periodically
This pattern will work well for updating any kind of static content from an external source. The workflow executes on a schedule and raises a pull request when there are changes.
@ -89,7 +134,7 @@ This pattern will work well for updating any kind of static content from an exte
This workflow will create a pull request for npm dependencies.
It works best in combination with a build workflow triggered on `push` and `pull_request`.
A [Personal Access Token (PAT)](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) can be used in order for the creation of the pull request to trigger further workflows. See the [documentation here](https://github.com/peter-evans/create-pull-request/blob/master/docs/concepts-guidelines.md#triggering-further-workflow-runs) for further details.
A [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) can be used in order for the creation of the pull request to trigger further workflows. See the [documentation here](concepts-guidelines.md#triggering-further-workflow-runs) for further details.
```yml
name: Update Dependencies
@ -129,9 +174,9 @@ The above workflow works best in combination with a build workflow triggered on
name: CI
on:
push:
branches: [master]
branches: [main]
pull_request:
branches: [master]
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
@ -183,6 +228,41 @@ jobs:
branch: update-dependencies
```
### Update Cargo dependencies
The following workflow will create a pull request for Cargo dependencies.
It optionally uses [`cargo-edit`](https://github.com/killercup/cargo-edit) to update `Cargo.toml` and keep it in sync with `Cargo.lock`.
```yml
name: Update Dependencies
on:
schedule:
- cron: '0 1 * * 1'
jobs:
update-dep:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Update dependencies
run: |
cargo install cargo-edit
cargo update
cargo upgrade --to-lockfile
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.PAT }}
commit-message: Update dependencies
title: Update dependencies
body: |
- Dependency updates
Auto-generated by [create-pull-request][1]
[1]: https://github.com/peter-evans/create-pull-request
branch: update-dependencies
```
### Update SwaggerUI for GitHub Pages
When using [GitHub Pages to host Swagger documentation](https://github.com/peter-evans/swagger-github-pages), this workflow updates the repository with the latest distribution of [SwaggerUI](https://github.com/swagger-api/swagger-ui).
@ -240,6 +320,41 @@ jobs:
branch: swagger-ui-updates
```
### Keep a fork up-to-date with its upstream
This example is designed to be run in a seperate repository from the fork repository itself.
The aim of this is to prevent committing anything to the fork's default branch would cause it to differ from the upstream.
In the following example workflow, `owner/repo` is the upstream repository and `fork-owner/repo` is the fork. It assumes the default branch of the upstream repository is called `main`.
The [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) should have `repo` scope. Additionally, if the upstream makes changes to the `.github/workflows` directory, the action will be unable to push the changes to a branch and throw the error "_(refusing to allow a GitHub App to create or update workflow `.github/workflows/xxx.yml` without `workflows` permission)_". To allow these changes to be pushed to the fork, add the `workflow` scope to the PAT. Of course, allowing this comes with the risk that the workflow changes from the upstream could run and do something unexpected. Disabling GitHub Actions in the fork is highly recommended to prevent this.
When you merge the pull request make sure to choose the [`Rebase and merge`](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-request-merges#rebase-and-merge-your-pull-request-commits) option. This will make the fork's commits match the commits on the upstream.
```yml
name: Update fork
on:
schedule:
- cron: '0 0 * * 0'
jobs:
updateFork:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
repository: fork-owner/repo
- name: Reset the default branch with upstream changes
run: |
git remote add upstream https://github.com/owner/repo.git
git fetch upstream main:upstream-main
git reset --hard upstream-main
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.PAT }}
branch: upstream-changes
```
### Spider and download a website
This workflow spiders a website and downloads the content. Any changes to the website will be raised in a pull request.
@ -277,7 +392,7 @@ jobs:
## Use case: Create a pull request to update X by calling the GitHub API
You can use the GitHub API to trigger a webhook event called [`repository_dispatch`](https://help.github.com/en/github/automating-your-workflow-with-github-actions/events-that-trigger-workflows#external-events-repository_dispatch) when you want to trigger a workflow for activity that happens outside of GitHub.
You can use the GitHub API to trigger a webhook event called [`repository_dispatch`](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#repository_dispatch) when you want to trigger a workflow for any activity that happens outside of GitHub.
This pattern will work well for updating any kind of static content from an external source.
You can modify any of the examples in the previous section to work in this fashion.
@ -295,7 +410,7 @@ on:
An `on: repository_dispatch` workflow can be triggered by a call to the GitHub API as follows.
- `[username]` is a GitHub username
- `[token]` is a `repo` scoped [Personal Access Token](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line)
- `[token]` is a `repo` scoped [Personal Access Token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token)
- `[repository]` is the name of the repository the workflow resides in.
```
@ -326,7 +441,8 @@ An `on: repository_dispatch` workflow can be triggered from another workflow wit
This is a pattern that lends itself to automated code linting and fixing. A pull request can be created to fix or modify something during an `on: pull_request` workflow. The pull request containing the fix will be raised with the original pull request as the base. This can be then be merged to update the original pull request and pass any required tests.
Note that due to [limitations on forked repositories](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/authenticating-with-the-github_token#permissions-for-the-github_token) workflows for this use case do not work for pull requests raised from forks.
Note that due to [token restrictions on public repository forks](https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token#permissions-for-the-github_token), workflows for this use case do not work for pull requests raised from forks.
Private repositories can be configured to [enable workflows](https://docs.github.com/en/github/administering-a-repository/disabling-or-limiting-github-actions-for-a-repository#enabling-workflows-for-private-repository-forks) from forks to run without restriction.
### autopep8
@ -409,7 +525,7 @@ jobs:
The following examples show how configuration for the action can be dynamically defined in a previous workflow step.
The recommended method is to use [`set-output`](https://help.github.com/en/github/automating-your-workflow-with-github-actions/development-tools-for-github-actions#set-an-output-parameter-set-output). Note that the step where output variables are defined must have an id.
The recommended method is to use [`set-output`](https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-output-parameter). Note that the step where output variables are defined must have an id.
```yml
- name: Set output variables
@ -425,31 +541,61 @@ The recommended method is to use [`set-output`](https://help.github.com/en/githu
body: ${{ steps.vars.outputs.pr_body }}
```
Alternatively, [`set-env`](https://help.github.com/en/github/automating-your-workflow-with-github-actions/development-tools-for-github-actions#set-an-environment-variable-set-env) can be used to create environment variables.
### Setting the pull request body from a file
This example shows how file content can be read into a variable and passed to the action.
The content must be [escaped to preserve newlines](https://github.community/t/set-output-truncates-multiline-strings/16852/3).
```yml
- name: Set environment variables
- id: get-pr-body
run: |
echo ::set-env name=PULL_REQUEST_TITLE::"[Test] Add report file $(date +%d-%m-%Y)"
echo ::set-env name=PULL_REQUEST_BODY::"This PR was auto-generated on $(date +%d-%m-%Y) \
by [create-pull-request](https://github.com/peter-evans/create-pull-request)."
body=$(cat pr-body.txt)
body="${body//'%'/'%25'}"
body="${body//$'\n'/'%0A'}"
body="${body//$'\r'/'%0D'}"
echo ::set-output name=body::$body
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
title: ${{ env.PULL_REQUEST_TITLE }}
body: ${{ env.PULL_REQUEST_BODY }}
body: ${{ steps.get-pr-body.outputs.body }}
```
### Using a markdown template
In this example, a markdown template file is added to the repository at `.github/pull-request-template.md` with the following content.
```
This is a test pull request template
Render template variables such as {{ .foo }} and {{ .bar }}.
```
The template is rendered using the [render-template](https://github.com/chuhlomin/render-template) action and the result is used to create the pull request.
```yml
- name: Render template
id: template
uses: chuhlomin/render-template@v1.2
with:
template: .github/pull-request-template.md
vars: |
foo: this
bar: that
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
with:
body: ${{ steps.template.outputs.result }}
```
### Debugging GitHub Actions
#### Runner Diagnostic Logging
[Runner diagnostic logging](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/managing-a-workflow-run#enabling-runner-diagnostic-logging) provides additional log files that contain information about how a runner is executing an action.
[Runner diagnostic logging](https://docs.github.com/en/actions/configuring-and-managing-workflows/managing-a-workflow-run#enabling-runner-diagnostic-logging) provides additional log files that contain information about how a runner is executing an action.
To enable runner diagnostic logging, set the secret `ACTIONS_RUNNER_DEBUG` to `true` in the repository that contains the workflow.
#### Step Debug Logging
[Step debug logging](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/managing-a-workflow-run#enabling-step-debug-logging) increases the verbosity of a job's logs during and after a job's execution.
[Step debug logging](https://docs.github.com/en/actions/configuring-and-managing-workflows/managing-a-workflow-run#enabling-step-debug-logging) increases the verbosity of a job's logs during and after a job's execution.
To enable step debug logging set the secret `ACTIONS_STEP_DEBUG` to `true` in the repository that contains the workflow.
#### Output Various Contexts

View File

@ -59,7 +59,7 @@
run: git checkout "${GITHUB_REF:11}"
```
- The two branch naming strategies have been swapped. Fixed branch naming strategy is now the default. i.e. `branch-suffix: none` is now the default and should be removed from configuration if set.
- The two branch naming strategies have been swapped. Fixed-branch naming strategy is now the default. i.e. `branch-suffix: none` is now the default and should be removed from configuration if set.
- `author-name`, `author-email`, `committer-name`, `committer-email` have been removed in favour of `author` and `committer`.
They can both be set in the format `Display Name <email@address.com>`

12619
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -29,27 +29,26 @@
},
"homepage": "https://github.com/peter-evans/create-pull-request",
"dependencies": {
"@actions/core": "1.2.4",
"@actions/core": "1.2.7",
"@actions/exec": "1.0.4",
"@actions/tool-cache": "1.3.4",
"@octokit/core": "3.1.0",
"@octokit/plugin-paginate-rest": "2.2.3",
"@octokit/plugin-rest-endpoint-methods": "4.0.0",
"uuid": "8.2.0"
"@octokit/core": "3.4.0",
"@octokit/plugin-paginate-rest": "2.13.3",
"@octokit/plugin-rest-endpoint-methods": "5.1.1",
"uuid": "8.3.2"
},
"devDependencies": {
"@types/jest": "25.2.2",
"@types/node": "14.0.1",
"@typescript-eslint/parser": "2.33.0",
"@zeit/ncc": "0.22.1",
"eslint": "7.0.0",
"eslint-plugin-github": "3.4.1",
"eslint-plugin-jest": "23.11.0",
"jest": "26.0.1",
"jest-circus": "26.0.1",
"js-yaml": "3.13.1",
"prettier": "2.0.5",
"ts-jest": "25.5.1",
"typescript": "3.9.2"
"@types/jest": "26.0.23",
"@types/node": "15.0.3",
"@typescript-eslint/parser": "4.23.0",
"@vercel/ncc": "0.28.5",
"eslint": "7.26.0",
"eslint-plugin-github": "4.1.3",
"eslint-plugin-jest": "24.3.6",
"jest": "26.6.3",
"jest-circus": "26.6.3",
"js-yaml": "4.1.0",
"prettier": "2.3.0",
"ts-jest": "26.5.6",
"typescript": "4.2.4"
}
}

View File

@ -5,6 +5,28 @@ import {v4 as uuidv4} from 'uuid'
const CHERRYPICK_EMPTY =
'The previous cherry-pick is now empty, possibly due to conflict resolution.'
export enum WorkingBaseType {
Branch = 'branch',
Commit = 'commit'
}
export async function getWorkingBaseAndType(
git: GitCommandManager
): Promise<[string, WorkingBaseType]> {
const symbolicRefResult = await git.exec(
['symbolic-ref', 'HEAD', '--short'],
true
)
if (symbolicRefResult.exitCode == 0) {
// A ref is checked out
return [symbolicRefResult.stdout.trim(), WorkingBaseType.Branch]
} else {
// A commit is checked out (detached HEAD)
const headSha = await git.revParse('HEAD')
return [headSha, WorkingBaseType.Commit]
}
}
export async function tryFetch(
git: GitCommandManager,
remote: string,
@ -56,15 +78,6 @@ async function isEven(
)
}
async function hasDiff(
git: GitCommandManager,
branch1: string,
branch2: string
): Promise<boolean> {
const result = await git.diff([`${branch1}..${branch2}`])
return result.length > 0
}
function splitLines(multilineString: string): string[] {
return multilineString
.split('\n')
@ -77,10 +90,18 @@ export async function createOrUpdateBranch(
commitMessage: string,
base: string,
branch: string,
branchRemoteName: string
branchRemoteName: string,
signoff: boolean
): Promise<CreateOrUpdateBranchResult> {
// Get the working base. This may or may not be the actual base.
const workingBase = await git.symbolicRef('HEAD', ['--short'])
// Get the working base.
// When a ref, it may or may not be the actual base.
// When a commit, we must rebase onto the actual base.
const [workingBase, workingBaseType] = await getWorkingBaseAndType(git)
core.info(`Working base is ${workingBaseType} '${workingBase}'`)
if (workingBaseType == WorkingBaseType.Commit && !base) {
throw new Error(`When in 'detached HEAD' state, 'base' must be supplied.`)
}
// If the base is not specified it is assumed to be the working base.
base = base ? base : workingBase
const baseRemote = 'origin'
@ -95,21 +116,39 @@ export async function createOrUpdateBranch(
// Save the working base changes to a temporary branch
const tempBranch = uuidv4()
await git.checkout(tempBranch, 'HEAD')
// Commit any uncomitted changes
// Commit any uncommitted changes
if (await git.isDirty(true)) {
core.info('Uncommitted changes found. Adding a commit.')
await git.exec(['add', '-A'])
await git.commit(['-m', commitMessage])
const params = ['-m', commitMessage]
if (signoff) {
params.push('--signoff')
}
await git.commit(params)
}
// Perform fetch and reset the working base
// Commits made during the workflow will be removed
await git.fetch([`${workingBase}:${workingBase}`], baseRemote, ['--force'])
if (workingBaseType == WorkingBaseType.Branch) {
core.info(`Resetting working base branch '${workingBase}'`)
if (branchRemoteName == 'fork') {
// If pushing to a fork we must fetch with 'unshallow' to avoid the following error on git push
// ! [remote rejected] HEAD -> tests/push-branch-to-fork (shallow update not allowed)
await git.fetch([`${workingBase}:${workingBase}`], baseRemote, [
'--force'
])
} else {
// If the remote is 'origin' we can git reset
await git.checkout(workingBase)
await git.exec(['reset', '--hard', `${baseRemote}/${workingBase}`])
}
}
// If the working base is not the base, rebase the temp branch commits
// This will also be true if the working base type is a commit
if (workingBase != base) {
core.info(
`Rebasing commits made to branch '${workingBase}' on to base branch '${base}'`
`Rebasing commits made to ${workingBaseType} '${workingBase}' on to base branch '${base}'`
)
// Checkout the actual base
await git.fetch([`${base}:${base}`], baseRemote, ['--force'])
@ -139,7 +178,7 @@ export async function createOrUpdateBranch(
// The pull request branch does not exist
core.info(`Pull request branch '${branch}' does not exist yet.`)
// Create the pull request branch
await git.checkout(branch, 'HEAD')
await git.checkout(branch, tempBranch)
// Check if the pull request branch is ahead of the base
result.hasDiffWithBase = await isAhead(git, base, branch)
if (result.hasDiffWithBase) {
@ -158,9 +197,18 @@ export async function createOrUpdateBranch(
// Checkout the pull request branch
await git.checkout(branch)
if (await hasDiff(git, branch, tempBranch)) {
// If the branch differs from the recreated temp version then the branch is reset
// For changes on base this action is similar to a rebase of the pull request branch
// Reset the branch if one of the following conditions is true.
// - If the branch differs from the recreated temp branch.
// - If the recreated temp branch is not ahead of the base. This means there will be
// no pull request diff after the branch is reset. This will reset any undeleted
// branches after merging. In particular, it catches a case where the branch was
// squash merged but not deleted. We need to reset to make sure it doesn't appear
// to have a diff with the base due to different commits for the same changes.
// For changes on base this reset is equivalent to a rebase of the pull request branch.
if (
(await git.hasDiff([`${branch}..${tempBranch}`])) ||
!(await isAhead(git, base, tempBranch))
) {
core.info(`Resetting '${branch}'`)
// Alternatively, git switch -C branch tempBranch
await git.checkout(branch, tempBranch)
@ -173,6 +221,7 @@ export async function createOrUpdateBranch(
result.action = 'updated'
core.info(`Updated branch '${branch}'`)
} else {
result.action = 'not-updated'
core.info(
`Branch '${branch}' is even with its remote and will not be updated`
)

View File

@ -1,5 +1,9 @@
import * as core from '@actions/core'
import {createOrUpdateBranch} from './create-or-update-branch'
import {
createOrUpdateBranch,
getWorkingBaseAndType,
WorkingBaseType
} from './create-or-update-branch'
import {GitHubHelper} from './github-helper'
import {GitCommandManager} from './git-command-manager'
import {GitAuthHelper} from './git-auth-helper'
@ -11,7 +15,9 @@ export interface Inputs {
commitMessage: string
committer: string
author: string
signoff: boolean
branch: string
deleteBranch: boolean
branchSuffix: string
base: string
pushToFork: string
@ -80,32 +86,32 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
core.endGroup()
}
// Determine if the checked out ref is a valid base for a pull request
// The action needs the checked out HEAD ref to be a branch
// This check will fail in the following cases:
// - HEAD is detached
// - HEAD is a merge commit (pull_request events)
// - HEAD is a tag
core.startGroup('Checking the checked out ref')
const symbolicRefResult = await git.exec(
['symbolic-ref', 'HEAD', '--short'],
true
)
if (symbolicRefResult.exitCode != 0) {
core.debug(`${symbolicRefResult.stderr}`)
core.startGroup('Checking the base repository state')
const [workingBase, workingBaseType] = await getWorkingBaseAndType(git)
core.info(`Working base is ${workingBaseType} '${workingBase}'`)
// When in detached HEAD state (checked out on a commit), we need to
// know the 'base' branch in order to rebase changes.
if (workingBaseType == WorkingBaseType.Commit && !inputs.base) {
throw new Error(
'The checked out ref is not a valid base for a pull request. Unable to continue.'
`When the repository is checked out on a commit instead of a branch, the 'base' input must be supplied.`
)
}
const workingBase = symbolicRefResult.stdout.trim()
// Exit if the working base is a PR branch created by this action.
// This may occur when using a PAT instead of GITHUB_TOKEN because
// a PAT allows workflow actions to trigger further events.
if (workingBase.startsWith(inputs.branch)) {
// If the base is not specified it is assumed to be the working base.
const base = inputs.base ? inputs.base : workingBase
// Throw an error if the base and branch are not different branches
// of the 'origin' remote. An identically named branch in the `fork`
// remote is perfectly fine.
if (branchRemoteName == 'origin' && base == inputs.branch) {
throw new Error(
`Working base branch '${workingBase}' was created by this action. Unable to continue.`
`The 'base' and 'branch' for a pull request must be different branches. Unable to continue.`
)
}
// For self-hosted runners the repository state persists between runs.
// This command prunes the stale remote ref when the pull request branch was
// deleted after being merged or closed. Without this the push using
// '--force-with-lease' fails due to "stale info."
// https://github.com/peter-evans/create-pull-request/issues/633
await git.exec(['remote', 'prune', branchRemoteName])
core.endGroup()
// Apply the branch suffix if set
@ -166,7 +172,8 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
inputs.commitMessage,
inputs.base,
inputs.branch,
branchRemoteName
branchRemoteName,
inputs.signoff
)
core.endGroup()
@ -181,29 +188,53 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
`HEAD:refs/heads/${inputs.branch}`
])
core.endGroup()
}
// Set the base. It would have been '' if not specified as an input
inputs.base = result.base
// Set the base. It would have been '' if not specified as an input
inputs.base = result.base
if (result.hasDiffWithBase) {
// Create or update the pull request
await githubHelper.createOrUpdatePullRequest(
inputs,
baseRemote.repository,
branchRepository
)
} else {
// If there is no longer a diff with the base delete the branch
if (result.hasDiffWithBase) {
// Create or update the pull request
core.startGroup('Create or update the pull request')
const pull = await githubHelper.createOrUpdatePullRequest(
inputs,
baseRemote.repository,
branchRepository
)
core.endGroup()
// Set outputs
core.startGroup('Setting outputs')
core.setOutput('pull-request-number', pull.number)
core.setOutput('pull-request-url', pull.html_url)
if (pull.created) {
core.setOutput('pull-request-operation', 'created')
} else if (result.action == 'updated') {
core.setOutput('pull-request-operation', 'updated')
}
// Deprecated
core.exportVariable('PULL_REQUEST_NUMBER', pull.number)
core.endGroup()
} else {
// There is no longer a diff with the base
// Check we are in a state where a branch exists
if (['updated', 'not-updated'].includes(result.action)) {
core.info(
`Branch '${inputs.branch}' no longer differs from base branch '${inputs.base}'`
)
core.info(`Closing pull request and deleting branch '${inputs.branch}'`)
await git.push([
'--delete',
'--force',
branchRemoteName,
`refs/heads/${inputs.branch}`
])
if (inputs.deleteBranch) {
core.info(`Deleting branch '${inputs.branch}'`)
await git.push([
'--delete',
'--force',
branchRemoteName,
`refs/heads/${inputs.branch}`
])
// Set outputs
core.startGroup('Setting outputs')
core.setOutput('pull-request-operation', 'closed')
core.endGroup()
}
}
}
} catch (error) {

View File

@ -96,15 +96,6 @@ export class GitCommandManager {
return output.exitCode === 0
}
async diff(options?: string[]): Promise<string> {
const args = ['-c', 'core.pager=cat', 'diff']
if (options) {
args.push(...options)
}
const output = await this.exec(args)
return output.stdout.trim()
}
async fetch(
refSpec: string[],
remoteName?: string,
@ -153,18 +144,26 @@ export class GitCommandManager {
return this.workingDirectory
}
async hasDiff(options?: string[]): Promise<boolean> {
const args = ['diff', '--quiet']
if (options) {
args.push(...options)
}
const output = await this.exec(args, true)
return output.exitCode === 1
}
async isDirty(untracked: boolean): Promise<boolean> {
const diffArgs = ['--abbrev=40', '--full-index', '--raw']
// Check staged changes
if (await this.diff([...diffArgs, '--staged'])) {
// Check untracked changes
if (untracked && (await this.status(['--porcelain', '-unormal']))) {
return true
}
// Check working index changes
if (await this.diff(diffArgs)) {
if (await this.hasDiff()) {
return true
}
// Check untracked changes
if (untracked && (await this.status(['--porcelain', '-unormal']))) {
// Check staged changes
if (await this.hasDiff(['--staged'])) {
return true
}
return false

View File

@ -10,6 +10,12 @@ interface Repository {
repo: string
}
interface Pull {
number: number
html_url: string
created: boolean
}
export class GitHubHelper {
private octokit: InstanceType<typeof Octokit>
@ -18,6 +24,7 @@ export class GitHubHelper {
if (token) {
options.auth = `${token}`
}
options.baseUrl = process.env['GITHUB_API_URL'] || 'https://api.github.com'
this.octokit = new Octokit(options)
}
@ -33,10 +40,11 @@ export class GitHubHelper {
inputs: Inputs,
baseRepository: string,
headBranch: string
): Promise<number> {
): Promise<Pull> {
// Try to create the pull request
try {
const {data: pull} = await this.octokit.pulls.create({
core.info(`Attempting creation of pull request`)
const {data: pull} = await this.octokit.rest.pulls.create({
...this.parseRepository(baseRepository),
title: inputs.title,
head: headBranch,
@ -47,24 +55,32 @@ export class GitHubHelper {
core.info(
`Created pull request #${pull.number} (${headBranch} => ${inputs.base})`
)
return pull.number
return {
number: pull.number,
html_url: pull.html_url,
created: true
}
} catch (e) {
if (
!e.message ||
!e.message.includes(`A pull request already exists for ${headBranch}`)
e.message &&
e.message.includes(`A pull request already exists for ${headBranch}`)
) {
core.info(`A pull request already exists for ${headBranch}`)
} else {
throw e
}
}
// Update the pull request that exists for this branch and base
const {data: pulls} = await this.octokit.pulls.list({
core.info(`Fetching existing pull request`)
const {data: pulls} = await this.octokit.rest.pulls.list({
...this.parseRepository(baseRepository),
state: 'open',
head: headBranch,
base: inputs.base
})
const {data: pull} = await this.octokit.pulls.update({
core.info(`Attempting update of pull request`)
const {data: pull} = await this.octokit.rest.pulls.update({
...this.parseRepository(baseRepository),
pull_number: pulls[0].number,
title: inputs.title,
@ -74,11 +90,15 @@ export class GitHubHelper {
core.info(
`Updated pull request #${pull.number} (${headBranch} => ${inputs.base})`
)
return pull.number
return {
number: pull.number,
html_url: pull.html_url,
created: false
}
}
async getRepositoryParent(headRepository: string): Promise<string> {
const {data: headRepo} = await this.octokit.repos.get({
const {data: headRepo} = await this.octokit.rest.repos.get({
...this.parseRepository(headRepository)
})
if (!headRepo.parent) {
@ -93,42 +113,38 @@ export class GitHubHelper {
inputs: Inputs,
baseRepository: string,
headRepository: string
): Promise<void> {
): Promise<Pull> {
const [headOwner] = headRepository.split('/')
const headBranch = `${headOwner}:${inputs.branch}`
// Create or update the pull request
const pullNumber = await this.createOrUpdate(
inputs,
baseRepository,
headBranch
)
const pull = await this.createOrUpdate(inputs, baseRepository, headBranch)
// Set outputs
core.startGroup('Setting outputs')
core.setOutput('pull-request-number', pullNumber)
core.exportVariable('PULL_REQUEST_NUMBER', pullNumber)
core.endGroup()
// Set milestone, labels and assignees
const updateIssueParams = {}
// Apply milestone
if (inputs.milestone) {
updateIssueParams['milestone'] = inputs.milestone
core.info(`Applying milestone '${inputs.milestone}'`)
}
if (inputs.labels.length > 0) {
updateIssueParams['labels'] = inputs.labels
core.info(`Applying labels '${inputs.labels}'`)
}
if (inputs.assignees.length > 0) {
updateIssueParams['assignees'] = inputs.assignees
core.info(`Applying assignees '${inputs.assignees}'`)
}
if (Object.keys(updateIssueParams).length > 0) {
await this.octokit.issues.update({
await this.octokit.rest.issues.update({
...this.parseRepository(baseRepository),
issue_number: pullNumber,
...updateIssueParams
issue_number: pull.number,
milestone: inputs.milestone
})
}
// Apply labels
if (inputs.labels.length > 0) {
core.info(`Applying labels '${inputs.labels}'`)
await this.octokit.rest.issues.addLabels({
...this.parseRepository(baseRepository),
issue_number: pull.number,
labels: inputs.labels
})
}
// Apply assignees
if (inputs.assignees.length > 0) {
core.info(`Applying assignees '${inputs.assignees}'`)
await this.octokit.rest.issues.addAssignees({
...this.parseRepository(baseRepository),
issue_number: pull.number,
assignees: inputs.assignees
})
}
@ -144,9 +160,9 @@ export class GitHubHelper {
}
if (Object.keys(requestReviewersParams).length > 0) {
try {
await this.octokit.pulls.requestReviewers({
await this.octokit.rest.pulls.requestReviewers({
...this.parseRepository(baseRepository),
pull_number: pullNumber,
pull_number: pull.number,
...requestReviewersParams
})
} catch (e) {
@ -157,5 +173,7 @@ export class GitHubHelper {
}
}
}
return pull
}
}

View File

@ -11,7 +11,9 @@ async function run(): Promise<void> {
commitMessage: core.getInput('commit-message'),
committer: core.getInput('committer'),
author: core.getInput('author'),
signoff: core.getInput('signoff') === 'true',
branch: core.getInput('branch'),
deleteBranch: core.getInput('delete-branch') === 'true',
branchSuffix: core.getInput('branch-suffix'),
base: core.getInput('base'),
pushToFork: core.getInput('push-to-fork'),

View File

@ -39,8 +39,21 @@ interface RemoteDetail {
export function getRemoteDetail(remoteUrl: string): RemoteDetail {
// Parse the protocol and github repository from a URL
// e.g. HTTPS, peter-evans/create-pull-request
const httpsUrlPattern = /^https:\/\/.*@?github.com\/(.+\/.+)$/i
const sshUrlPattern = /^git@github.com:(.+\/.+).git$/i
const githubUrl = process.env['GITHUB_SERVER_URL'] || 'https://github.com'
const githubServerMatch = githubUrl.match(/^https?:\/\/(.+)$/i)
if (!githubServerMatch) {
throw new Error('Could not parse GitHub Server name')
}
const httpsUrlPattern = new RegExp(
'^https?://.*@?' + githubServerMatch[1] + '/(.+/.+)$',
'i'
)
const sshUrlPattern = new RegExp(
'^git@' + githubServerMatch[1] + ':(.+/.+).git$',
'i'
)
const httpsMatch = remoteUrl.match(httpsUrlPattern)
if (httpsMatch) {