Compare commits
66 Commits
Author | SHA1 | Date | |
---|---|---|---|
d9d6fd980e | |||
8bb8511e4d | |||
c1d92ef456 | |||
1ff93da091 | |||
0524c01297 | |||
548adff9dc | |||
28674474a4 | |||
4fb90330a4 | |||
e4c811acf5 | |||
99ccb3479b | |||
13616a4432 | |||
b5b91bc2b0 | |||
5666cd8fe9 | |||
ad897490d5 | |||
0735106af9 | |||
9aeedaa8c2 | |||
52d31873b6 | |||
09b9ac155b | |||
6ec5e3e26b | |||
8b46437b6d | |||
e361fd1788 | |||
052fc72b41 | |||
ed00d4629c | |||
34371f09e5 | |||
c27ea51ae0 | |||
5e9d0ee9ea | |||
b5f41d9b08 | |||
2455e15969 | |||
05bc46786e | |||
adc6552966 | |||
171fc6cce4 | |||
3fb765f674 | |||
d95c81ee98 | |||
8d5ed6557f | |||
7b1819c092 | |||
be0a8c9666 | |||
a0a6157bf1 | |||
9c5ec2e07d | |||
45c510e1f6 | |||
249b80db6b | |||
6c2b44c6ac | |||
76c58cf6a9 | |||
8c603dbb04 | |||
d01e0807ef | |||
ce699aa2d1 | |||
9984f611a7 | |||
ff0beed1b2 | |||
ddeca94037 | |||
0fd77ba8cc | |||
c7f493a800 | |||
91664dfb28 | |||
13ec5274b1 | |||
bcf9790963 | |||
88ea447de7 | |||
da928d5fcc | |||
2465e435b9 | |||
37b2bd1eca | |||
eb13e17e17 | |||
a1ecc20658 | |||
ffcad23634 | |||
f4b52b768a | |||
af682c8fcb | |||
7378b23cb0 | |||
370ae6d537 | |||
ae0797ee12 | |||
e05457394a |
@ -9,8 +9,7 @@
|
|||||||
"plugin:import/errors",
|
"plugin:import/errors",
|
||||||
"plugin:import/warnings",
|
"plugin:import/warnings",
|
||||||
"plugin:import/typescript",
|
"plugin:import/typescript",
|
||||||
"plugin:prettier/recommended",
|
"plugin:prettier/recommended"
|
||||||
"prettier/@typescript-eslint"
|
|
||||||
],
|
],
|
||||||
"plugins": ["@typescript-eslint"],
|
"plugins": ["@typescript-eslint"],
|
||||||
"rules": {
|
"rules": {
|
||||||
|
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -120,7 +120,7 @@ jobs:
|
|||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@v3
|
uses: peter-evans/create-pull-request@v3
|
||||||
with:
|
with:
|
||||||
commit-message: Update distribution
|
commit-message: 'build: update distribution'
|
||||||
title: Update distribution
|
title: Update distribution
|
||||||
body: |
|
body: |
|
||||||
- Updates the distribution for changes on `master`
|
- Updates the distribution for changes on `master`
|
||||||
|
1
.github/workflows/cpr-example-command.yml
vendored
1
.github/workflows/cpr-example-command.yml
vendored
@ -39,6 +39,7 @@ jobs:
|
|||||||
- name: Check output
|
- name: Check output
|
||||||
run: |
|
run: |
|
||||||
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
|
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
|
||||||
|
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
|
||||||
|
|
||||||
- name: Add reaction
|
- name: Add reaction
|
||||||
uses: peter-evans/create-or-update-comment@v1
|
uses: peter-evans/create-or-update-comment@v1
|
||||||
|
2
.github/workflows/update-dep.yml
vendored
2
.github/workflows/update-dep.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
|||||||
uses: peter-evans/create-pull-request@v3
|
uses: peter-evans/create-pull-request@v3
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
|
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
|
||||||
commit-message: Update dependencies
|
commit-message: 'chore: update dependencies'
|
||||||
committer: GitHub <noreply@github.com>
|
committer: GitHub <noreply@github.com>
|
||||||
author: actions-bot <actions-bot@users.noreply.github.com>
|
author: actions-bot <actions-bot@users.noreply.github.com>
|
||||||
title: Update dependencies
|
title: Update dependencies
|
||||||
|
19
README.md
19
README.md
@ -66,8 +66,14 @@ All inputs are **optional**. If not set, sensible defaults will be used.
|
|||||||
|
|
||||||
### Action outputs
|
### Action outputs
|
||||||
|
|
||||||
The pull request number is output as a step output.
|
The following outputs can be used by subsequent workflow steps.
|
||||||
Note that in order to read the step output the action step must have an id.
|
|
||||||
|
- `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
|
```yml
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
@ -76,6 +82,7 @@ Note that in order to read the step output the action step must have an id.
|
|||||||
- name: Check outputs
|
- name: Check outputs
|
||||||
run: |
|
run: |
|
||||||
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
|
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
|
||||||
|
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Action behaviour
|
### Action behaviour
|
||||||
@ -150,6 +157,11 @@ To create a project card for the pull request, pass the `pull-request-number` st
|
|||||||
issue-number: ${{ steps.cpr.outputs.pull-request-number }}
|
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
|
## Reference Example
|
||||||
|
|
||||||
The following workflow sets many of the action's inputs for reference purposes.
|
The following workflow sets many of the action's inputs for reference purposes.
|
||||||
@ -196,9 +208,10 @@ jobs:
|
|||||||
milestone: 1
|
milestone: 1
|
||||||
draft: false
|
draft: false
|
||||||
|
|
||||||
- name: Check output
|
- name: Check outputs
|
||||||
run: |
|
run: |
|
||||||
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
|
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:
|
An example based on the above reference configuration creates pull requests that look like this:
|
||||||
|
1231
dist/index.js
vendored
1231
dist/index.js
vendored
File diff suppressed because it is too large
Load Diff
@ -16,6 +16,7 @@ This document covers terminology, how the action works, general usage guidelines
|
|||||||
- [Push using SSH (deploy keys)](#push-using-ssh-deploy-keys)
|
- [Push using SSH (deploy keys)](#push-using-ssh-deploy-keys)
|
||||||
- [Push pull request branches to a fork](#push-pull-request-branches-to-a-fork)
|
- [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)
|
- [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)
|
- [Running in a container or on self-hosted runners](#running-in-a-container-or-on-self-hosted-runners)
|
||||||
|
|
||||||
## Terminology
|
## Terminology
|
||||||
@ -129,6 +130,8 @@ jobs:
|
|||||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
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
|
### 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.
|
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.
|
||||||
@ -272,6 +275,48 @@ GitHub App generated tokens are more secure than using a PAT because GitHub App
|
|||||||
token: ${{ steps.generate-token.outputs.token }}
|
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
|
### 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.
|
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.
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
- [Misc workflow tips](#misc-workflow-tips)
|
- [Misc workflow tips](#misc-workflow-tips)
|
||||||
- [Filtering push events](#filtering-push-events)
|
- [Filtering push events](#filtering-push-events)
|
||||||
- [Dynamic configuration using variables](#dynamic-configuration-using-variables)
|
- [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)
|
- [Debugging GitHub Actions](#debugging-github-actions)
|
||||||
|
|
||||||
|
|
||||||
@ -539,21 +541,6 @@ The recommended method is to use [`set-output`](https://docs.github.com/en/actio
|
|||||||
body: ${{ steps.vars.outputs.pr_body }}
|
body: ${{ steps.vars.outputs.pr_body }}
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, [`set-env`](https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable) can be used to create environment variables.
|
|
||||||
|
|
||||||
```yml
|
|
||||||
- name: Set environment variables
|
|
||||||
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)."
|
|
||||||
- name: Create Pull Request
|
|
||||||
uses: peter-evans/create-pull-request@v3
|
|
||||||
with:
|
|
||||||
title: ${{ env.PULL_REQUEST_TITLE }}
|
|
||||||
body: ${{ env.PULL_REQUEST_BODY }}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Setting the pull request body from a file
|
### 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.
|
This example shows how file content can be read into a variable and passed to the action.
|
||||||
@ -574,6 +561,31 @@ The content must be [escaped to preserve newlines](https://github.community/t/se
|
|||||||
body: ${{ steps.get-pr-body.outputs.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
|
### Debugging GitHub Actions
|
||||||
|
|
||||||
#### Runner Diagnostic Logging
|
#### Runner Diagnostic Logging
|
||||||
|
11382
package-lock.json
generated
11382
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
36
package.json
36
package.json
@ -29,26 +29,26 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/peter-evans/create-pull-request",
|
"homepage": "https://github.com/peter-evans/create-pull-request",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "1.2.5",
|
"@actions/core": "1.2.6",
|
||||||
"@actions/exec": "1.0.4",
|
"@actions/exec": "1.0.4",
|
||||||
"@octokit/core": "3.1.2",
|
"@octokit/core": "3.3.2",
|
||||||
"@octokit/plugin-paginate-rest": "2.3.1",
|
"@octokit/plugin-paginate-rest": "2.13.3",
|
||||||
"@octokit/plugin-rest-endpoint-methods": "4.1.3",
|
"@octokit/plugin-rest-endpoint-methods": "5.0.0",
|
||||||
"uuid": "8.3.0"
|
"uuid": "8.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "26.0.13",
|
"@types/jest": "26.0.22",
|
||||||
"@types/node": "14.6.3",
|
"@types/node": "14.14.37",
|
||||||
"@typescript-eslint/parser": "4.0.1",
|
"@typescript-eslint/parser": "4.20.0",
|
||||||
"@vercel/ncc": "0.24.0",
|
"@vercel/ncc": "0.27.0",
|
||||||
"eslint": "7.8.1",
|
"eslint": "7.23.0",
|
||||||
"eslint-plugin-github": "4.1.1",
|
"eslint-plugin-github": "4.1.2",
|
||||||
"eslint-plugin-jest": "23.20.0",
|
"eslint-plugin-jest": "24.3.2",
|
||||||
"jest": "26.4.2",
|
"jest": "26.6.3",
|
||||||
"jest-circus": "26.4.2",
|
"jest-circus": "26.6.3",
|
||||||
"js-yaml": "3.14.0",
|
"js-yaml": "4.0.0",
|
||||||
"prettier": "2.1.1",
|
"prettier": "2.2.1",
|
||||||
"ts-jest": "26.3.0",
|
"ts-jest": "26.5.4",
|
||||||
"typescript": "4.0.2"
|
"typescript": "4.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,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[] {
|
function splitLines(multilineString: string): string[] {
|
||||||
return multilineString
|
return multilineString
|
||||||
.split('\n')
|
.split('\n')
|
||||||
@ -139,8 +130,18 @@ export async function createOrUpdateBranch(
|
|||||||
// Perform fetch and reset the working base
|
// Perform fetch and reset the working base
|
||||||
// Commits made during the workflow will be removed
|
// Commits made during the workflow will be removed
|
||||||
if (workingBaseType == WorkingBaseType.Branch) {
|
if (workingBaseType == WorkingBaseType.Branch) {
|
||||||
core.info(`Resetting working base branch '${workingBase}' to its remote`)
|
core.info(`Resetting working base branch '${workingBase}'`)
|
||||||
await git.fetch([`${workingBase}:${workingBase}`], baseRemote, ['--force'])
|
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
|
// If the working base is not the base, rebase the temp branch commits
|
||||||
@ -177,7 +178,7 @@ export async function createOrUpdateBranch(
|
|||||||
// The pull request branch does not exist
|
// The pull request branch does not exist
|
||||||
core.info(`Pull request branch '${branch}' does not exist yet.`)
|
core.info(`Pull request branch '${branch}' does not exist yet.`)
|
||||||
// Create the pull request branch
|
// 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
|
// Check if the pull request branch is ahead of the base
|
||||||
result.hasDiffWithBase = await isAhead(git, base, branch)
|
result.hasDiffWithBase = await isAhead(git, base, branch)
|
||||||
if (result.hasDiffWithBase) {
|
if (result.hasDiffWithBase) {
|
||||||
@ -205,7 +206,7 @@ export async function createOrUpdateBranch(
|
|||||||
// to have a diff with the base due to different commits for the same changes.
|
// 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.
|
// For changes on base this reset is equivalent to a rebase of the pull request branch.
|
||||||
if (
|
if (
|
||||||
(await hasDiff(git, branch, tempBranch)) ||
|
(await git.hasDiff([`${branch}..${tempBranch}`])) ||
|
||||||
!(await isAhead(git, base, tempBranch))
|
!(await isAhead(git, base, tempBranch))
|
||||||
) {
|
) {
|
||||||
core.info(`Resetting '${branch}'`)
|
core.info(`Resetting '${branch}'`)
|
||||||
|
@ -106,6 +106,12 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
|
|||||||
`The 'base' and 'branch' for a pull request must be different branches. 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()
|
core.endGroup()
|
||||||
|
|
||||||
// Apply the branch suffix if set
|
// Apply the branch suffix if set
|
||||||
@ -189,11 +195,24 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
|
|||||||
|
|
||||||
if (result.hasDiffWithBase) {
|
if (result.hasDiffWithBase) {
|
||||||
// Create or update the pull request
|
// Create or update the pull request
|
||||||
await githubHelper.createOrUpdatePullRequest(
|
const pull = await githubHelper.createOrUpdatePullRequest(
|
||||||
inputs,
|
inputs,
|
||||||
baseRemote.repository,
|
baseRemote.repository,
|
||||||
branchRepository
|
branchRepository
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 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 {
|
} else {
|
||||||
// There is no longer a diff with the base
|
// There is no longer a diff with the base
|
||||||
// Check we are in a state where a branch exists
|
// Check we are in a state where a branch exists
|
||||||
@ -209,6 +228,10 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
|
|||||||
branchRemoteName,
|
branchRemoteName,
|
||||||
`refs/heads/${inputs.branch}`
|
`refs/heads/${inputs.branch}`
|
||||||
])
|
])
|
||||||
|
// Set outputs
|
||||||
|
core.startGroup('Setting outputs')
|
||||||
|
core.setOutput('pull-request-operation', 'closed')
|
||||||
|
core.endGroup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,15 +96,6 @@ export class GitCommandManager {
|
|||||||
return output.exitCode === 0
|
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(
|
async fetch(
|
||||||
refSpec: string[],
|
refSpec: string[],
|
||||||
remoteName?: string,
|
remoteName?: string,
|
||||||
@ -153,18 +144,26 @@ export class GitCommandManager {
|
|||||||
return this.workingDirectory
|
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> {
|
async isDirty(untracked: boolean): Promise<boolean> {
|
||||||
const diffArgs = ['--abbrev=40', '--full-index', '--raw']
|
// Check untracked changes
|
||||||
// Check staged changes
|
if (untracked && (await this.status(['--porcelain', '-unormal']))) {
|
||||||
if (await this.diff([...diffArgs, '--staged'])) {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// Check working index changes
|
// Check working index changes
|
||||||
if (await this.diff(diffArgs)) {
|
if (await this.hasDiff()) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// Check untracked changes
|
// Check staged changes
|
||||||
if (untracked && (await this.status(['--porcelain', '-unormal']))) {
|
if (await this.hasDiff(['--staged'])) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -10,6 +10,12 @@ interface Repository {
|
|||||||
repo: string
|
repo: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Pull {
|
||||||
|
number: number
|
||||||
|
html_url: string
|
||||||
|
created: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export class GitHubHelper {
|
export class GitHubHelper {
|
||||||
private octokit: InstanceType<typeof Octokit>
|
private octokit: InstanceType<typeof Octokit>
|
||||||
|
|
||||||
@ -18,6 +24,7 @@ export class GitHubHelper {
|
|||||||
if (token) {
|
if (token) {
|
||||||
options.auth = `${token}`
|
options.auth = `${token}`
|
||||||
}
|
}
|
||||||
|
options.baseUrl = process.env['GITHUB_API_URL'] || 'https://api.github.com'
|
||||||
this.octokit = new Octokit(options)
|
this.octokit = new Octokit(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,10 +40,10 @@ export class GitHubHelper {
|
|||||||
inputs: Inputs,
|
inputs: Inputs,
|
||||||
baseRepository: string,
|
baseRepository: string,
|
||||||
headBranch: string
|
headBranch: string
|
||||||
): Promise<number> {
|
): Promise<Pull> {
|
||||||
// Try to create the pull request
|
// Try to create the pull request
|
||||||
try {
|
try {
|
||||||
const {data: pull} = await this.octokit.pulls.create({
|
const {data: pull} = await this.octokit.rest.pulls.create({
|
||||||
...this.parseRepository(baseRepository),
|
...this.parseRepository(baseRepository),
|
||||||
title: inputs.title,
|
title: inputs.title,
|
||||||
head: headBranch,
|
head: headBranch,
|
||||||
@ -47,24 +54,30 @@ export class GitHubHelper {
|
|||||||
core.info(
|
core.info(
|
||||||
`Created pull request #${pull.number} (${headBranch} => ${inputs.base})`
|
`Created pull request #${pull.number} (${headBranch} => ${inputs.base})`
|
||||||
)
|
)
|
||||||
return pull.number
|
return {
|
||||||
|
number: pull.number,
|
||||||
|
html_url: pull.html_url,
|
||||||
|
created: true
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (
|
if (
|
||||||
!e.message ||
|
e.message &&
|
||||||
!e.message.includes(`A pull request already exists for ${headBranch}`)
|
e.message.includes(`A pull request already exists for ${headBranch}`)
|
||||||
) {
|
) {
|
||||||
|
core.info(`A pull request already exists for ${headBranch}`)
|
||||||
|
} else {
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the pull request that exists for this branch and base
|
// Update the pull request that exists for this branch and base
|
||||||
const {data: pulls} = await this.octokit.pulls.list({
|
const {data: pulls} = await this.octokit.rest.pulls.list({
|
||||||
...this.parseRepository(baseRepository),
|
...this.parseRepository(baseRepository),
|
||||||
state: 'open',
|
state: 'open',
|
||||||
head: headBranch,
|
head: headBranch,
|
||||||
base: inputs.base
|
base: inputs.base
|
||||||
})
|
})
|
||||||
const {data: pull} = await this.octokit.pulls.update({
|
const {data: pull} = await this.octokit.rest.pulls.update({
|
||||||
...this.parseRepository(baseRepository),
|
...this.parseRepository(baseRepository),
|
||||||
pull_number: pulls[0].number,
|
pull_number: pulls[0].number,
|
||||||
title: inputs.title,
|
title: inputs.title,
|
||||||
@ -74,11 +87,15 @@ export class GitHubHelper {
|
|||||||
core.info(
|
core.info(
|
||||||
`Updated pull request #${pull.number} (${headBranch} => ${inputs.base})`
|
`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> {
|
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)
|
...this.parseRepository(headRepository)
|
||||||
})
|
})
|
||||||
if (!headRepo.parent) {
|
if (!headRepo.parent) {
|
||||||
@ -93,42 +110,38 @@ export class GitHubHelper {
|
|||||||
inputs: Inputs,
|
inputs: Inputs,
|
||||||
baseRepository: string,
|
baseRepository: string,
|
||||||
headRepository: string
|
headRepository: string
|
||||||
): Promise<void> {
|
): Promise<Pull> {
|
||||||
const [headOwner] = headRepository.split('/')
|
const [headOwner] = headRepository.split('/')
|
||||||
const headBranch = `${headOwner}:${inputs.branch}`
|
const headBranch = `${headOwner}:${inputs.branch}`
|
||||||
|
|
||||||
// Create or update the pull request
|
// Create or update the pull request
|
||||||
const pullNumber = await this.createOrUpdate(
|
const pull = await this.createOrUpdate(inputs, baseRepository, headBranch)
|
||||||
inputs,
|
|
||||||
baseRepository,
|
|
||||||
headBranch
|
|
||||||
)
|
|
||||||
|
|
||||||
// Set outputs
|
// Apply milestone
|
||||||
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 = {}
|
|
||||||
if (inputs.milestone) {
|
if (inputs.milestone) {
|
||||||
updateIssueParams['milestone'] = inputs.milestone
|
|
||||||
core.info(`Applying milestone '${inputs.milestone}'`)
|
core.info(`Applying milestone '${inputs.milestone}'`)
|
||||||
}
|
await this.octokit.rest.issues.update({
|
||||||
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({
|
|
||||||
...this.parseRepository(baseRepository),
|
...this.parseRepository(baseRepository),
|
||||||
issue_number: pullNumber,
|
issue_number: pull.number,
|
||||||
...updateIssueParams
|
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 +157,9 @@ export class GitHubHelper {
|
|||||||
}
|
}
|
||||||
if (Object.keys(requestReviewersParams).length > 0) {
|
if (Object.keys(requestReviewersParams).length > 0) {
|
||||||
try {
|
try {
|
||||||
await this.octokit.pulls.requestReviewers({
|
await this.octokit.rest.pulls.requestReviewers({
|
||||||
...this.parseRepository(baseRepository),
|
...this.parseRepository(baseRepository),
|
||||||
pull_number: pullNumber,
|
pull_number: pull.number,
|
||||||
...requestReviewersParams
|
...requestReviewersParams
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -157,5 +170,7 @@ export class GitHubHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return pull
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
src/utils.ts
17
src/utils.ts
@ -39,8 +39,21 @@ interface RemoteDetail {
|
|||||||
export function getRemoteDetail(remoteUrl: string): RemoteDetail {
|
export function getRemoteDetail(remoteUrl: string): RemoteDetail {
|
||||||
// Parse the protocol and github repository from a URL
|
// Parse the protocol and github repository from a URL
|
||||||
// e.g. HTTPS, peter-evans/create-pull-request
|
// e.g. HTTPS, peter-evans/create-pull-request
|
||||||
const httpsUrlPattern = /^https:\/\/.*@?github.com\/(.+\/.+)$/i
|
const githubUrl = process.env['GITHUB_SERVER_URL'] || 'https://github.com'
|
||||||
const sshUrlPattern = /^git@github.com:(.+\/.+).git$/i
|
|
||||||
|
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)
|
const httpsMatch = remoteUrl.match(httpsUrlPattern)
|
||||||
if (httpsMatch) {
|
if (httpsMatch) {
|
||||||
|
Reference in New Issue
Block a user