Compare commits
142 Commits
Author | SHA1 | Date | |
---|---|---|---|
098a6d3703 | |||
1e6bff9d94 | |||
02a8f71e34 | |||
873341b21c | |||
9606fe7fd0 | |||
21d8ea09d5 | |||
85246161a0 | |||
bc1906950d | |||
be547fcbbb | |||
10a399b4b0 | |||
1a0e857f60 | |||
1f76dd3b26 | |||
efda6f2ece | |||
382b1bf0d8 | |||
040164963a | |||
9e49b1873f | |||
798d65c1e2 | |||
ac8dd8903f | |||
5b5eb8d8d0 | |||
7e6ae5af18 | |||
1c0b168d50 | |||
4e1ec66aad | |||
d07501c8ac | |||
f5ba48ac1e | |||
f0f8250914 | |||
fe61cf72ef | |||
4fa9ccf7a7 | |||
79098666d7 | |||
d7c27ba1b1 | |||
c526248631 | |||
2b66fab098 | |||
57390a8261 | |||
76c6f5c20e | |||
2f092153d6 | |||
c643f6fba5 | |||
8c6bf8e9fa | |||
57ae48c0ec | |||
d4d7b4e3a6 | |||
7865f819b0 | |||
ff2bf9be1f | |||
fa448197ec | |||
e42d7ab098 | |||
57a92650b1 | |||
a623c1421e | |||
1efedcfa53 | |||
73d77c9d42 | |||
ae78d6487c | |||
8c11f0ebce | |||
0c31730c33 | |||
c8e3bd8337 | |||
3e02667f27 | |||
5de036d28f | |||
76ff63671c | |||
6daff55809 | |||
3588b1aa44 | |||
60d8781d60 | |||
ae06da3674 | |||
d806186ee3 | |||
0652023649 | |||
8a825a8466 | |||
b5f830072e | |||
a5d4677573 | |||
4c2973e730 | |||
a05bf394be | |||
803660ec69 | |||
21a254626f | |||
bb0c945e6e | |||
bd41655446 | |||
6d9c0cdf58 | |||
4306b59af5 | |||
80507e9341 | |||
4e9c9ce808 | |||
989188a00c | |||
e4b37ab067 | |||
d721b8be51 | |||
023de218b7 | |||
0cd7ff0e63 | |||
fca1e78bd8 | |||
92a21ab9e6 | |||
157a260267 | |||
270c03dcf3 | |||
8290a989c8 | |||
3f6dd507d6 | |||
842881bb7f | |||
9d48be23dc | |||
88e822f486 | |||
ea82a8b8d7 | |||
ab8fb76677 | |||
506056c16d | |||
f908c6b99c | |||
1c8b8845ee | |||
ad8cdb00a0 | |||
5fa7af1a21 | |||
5848fcb314 | |||
e1f6e4238a | |||
f42c0a796a | |||
e70ffc3767 | |||
9fd47c87b5 | |||
020f4502ee | |||
5931b3373e | |||
657fe58e8f | |||
5f8399b325 | |||
eebb6ccce1 | |||
daee43366d | |||
7574e859c5 | |||
f2c0f053fc | |||
19e044019f | |||
153407881e | |||
143be5d671 | |||
51e8ca2340 | |||
712add83f2 | |||
a9e8aabc8b | |||
37be4ffd94 | |||
a5f0e5dc8e | |||
9ef70ee495 | |||
0a287739d3 | |||
4ddb8c8fe7 | |||
7b276d47e7 | |||
007717eeea | |||
30b8ee1ec7 | |||
8e2fa462cf | |||
efbb6ba75d | |||
4cdfca66b8 | |||
8fbd83c22f | |||
371aec12f4 | |||
83165e6fd4 | |||
0183f33490 | |||
37c110a6c3 | |||
284f54f989 | |||
9e5b234402 | |||
2d8e7db84c | |||
041b6ab163 | |||
31de0fdf3f | |||
28295f6636 | |||
8dcaf3883b | |||
2827897dcc | |||
c4f19d3a23 | |||
46035868a3 | |||
c09e1094b6 | |||
eab3ea092e | |||
e179caf91b | |||
f3a21bf340 |
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
@ -19,21 +19,21 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 16.x
|
node-version: 20.x
|
||||||
cache: npm
|
cache: npm
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run build
|
- run: npm run build
|
||||||
- run: npm run format-check
|
- run: npm run format-check
|
||||||
- run: npm run lint
|
- run: npm run lint
|
||||||
- run: npm run test
|
- run: npm run test
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: dist
|
name: dist
|
||||||
path: dist
|
path: dist
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: action.yml
|
name: action.yml
|
||||||
path: action.yml
|
path: action.yml
|
||||||
@ -46,16 +46,16 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
target: [built, committed]
|
target: [built, committed]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: main
|
ref: main
|
||||||
- if: matrix.target == 'built' || github.event_name == 'pull_request'
|
- if: matrix.target == 'built' || github.event_name == 'pull_request'
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: dist
|
name: dist
|
||||||
path: dist
|
path: dist
|
||||||
- if: matrix.target == 'built' || github.event_name == 'pull_request'
|
- if: matrix.target == 'built' || github.event_name == 'pull_request'
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: action.yml
|
name: action.yml
|
||||||
path: .
|
path: .
|
||||||
@ -68,8 +68,8 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
commit-message: '[CI] test ${{ matrix.target }}'
|
commit-message: '[CI] test ${{ matrix.target }}'
|
||||||
committer: GitHub <noreply@github.com>
|
committer: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
|
||||||
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
|
author: ${{ github.actor }} <${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com>
|
||||||
title: '[CI] test ${{ matrix.target }}'
|
title: '[CI] test ${{ matrix.target }}'
|
||||||
body: |
|
body: |
|
||||||
- CI test case for target '${{ matrix.target }}'
|
- CI test case for target '${{ matrix.target }}'
|
||||||
@ -80,7 +80,7 @@ jobs:
|
|||||||
branch: ci-test-${{ matrix.target }}-${{ github.sha }}
|
branch: ci-test-${{ matrix.target }}-${{ github.sha }}
|
||||||
|
|
||||||
- name: Close Pull
|
- name: Close Pull
|
||||||
uses: peter-evans/close-pull@v2
|
uses: peter-evans/close-pull@v3
|
||||||
with:
|
with:
|
||||||
pull-request-number: ${{ steps.cpr.outputs.pull-request-number }}
|
pull-request-number: ${{ steps.cpr.outputs.pull-request-number }}
|
||||||
comment: '[CI] test ${{ matrix.target }}'
|
comment: '[CI] test ${{ matrix.target }}'
|
||||||
@ -101,7 +101,7 @@ jobs:
|
|||||||
|
|
||||||
- if: steps.fc.outputs.comment-id == ''
|
- if: steps.fc.outputs.comment-id == ''
|
||||||
name: Create comment
|
name: Create comment
|
||||||
uses: peter-evans/create-or-update-comment@v2
|
uses: peter-evans/create-or-update-comment@v3
|
||||||
with:
|
with:
|
||||||
issue-number: ${{ github.event.number }}
|
issue-number: ${{ github.event.number }}
|
||||||
body: |
|
body: |
|
||||||
@ -115,13 +115,13 @@ jobs:
|
|||||||
needs: [test]
|
needs: [test]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: dist
|
name: dist
|
||||||
path: dist
|
path: dist
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@v4
|
uses: peter-evans/create-pull-request@v5
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
|
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
|
||||||
commit-message: 'build: update distribution'
|
commit-message: 'build: update distribution'
|
||||||
|
8
.github/workflows/cpr-example-command.yml
vendored
8
.github/workflows/cpr-example-command.yml
vendored
@ -6,7 +6,7 @@ jobs:
|
|||||||
createPullRequest:
|
createPullRequest:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Make changes to pull request
|
- name: Make changes to pull request
|
||||||
run: date +%s > report.txt
|
run: date +%s > report.txt
|
||||||
@ -16,8 +16,8 @@ jobs:
|
|||||||
uses: ./
|
uses: ./
|
||||||
with:
|
with:
|
||||||
commit-message: Update report
|
commit-message: Update report
|
||||||
committer: GitHub <noreply@github.com>
|
committer: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
|
||||||
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
|
author: ${{ github.actor }} <${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com>
|
||||||
signoff: false
|
signoff: false
|
||||||
title: '[Example] Update report'
|
title: '[Example] Update report'
|
||||||
body: |
|
body: |
|
||||||
@ -42,7 +42,7 @@ jobs:
|
|||||||
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
|
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
|
||||||
|
|
||||||
- name: Add reaction
|
- name: Add reaction
|
||||||
uses: peter-evans/create-or-update-comment@v2
|
uses: peter-evans/create-or-update-comment@v3
|
||||||
with:
|
with:
|
||||||
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
||||||
comment-id: ${{ github.event.client_payload.github.payload.comment.id }}
|
comment-id: ${{ github.event.client_payload.github.payload.comment.id }}
|
||||||
|
2
.github/workflows/slash-command-dispatch.yml
vendored
2
.github/workflows/slash-command-dispatch.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
|||||||
"named_args": true
|
"named_args": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "testv4",
|
"command": "testv5",
|
||||||
"permission": "admin",
|
"permission": "admin",
|
||||||
"repository": "peter-evans/create-pull-request-tests",
|
"repository": "peter-evans/create-pull-request-tests",
|
||||||
"named_args": true
|
"named_args": true
|
||||||
|
2
.github/workflows/update-major-version.yml
vendored
2
.github/workflows/update-major-version.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
|||||||
tag:
|
tag:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
|
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
44
README.md
44
README.md
@ -22,11 +22,12 @@ Create Pull Request action will:
|
|||||||
- [Concepts, guidelines and advanced usage](docs/concepts-guidelines.md)
|
- [Concepts, guidelines and advanced usage](docs/concepts-guidelines.md)
|
||||||
- [Examples](docs/examples.md)
|
- [Examples](docs/examples.md)
|
||||||
- [Updating to v5](docs/updating.md)
|
- [Updating to v5](docs/updating.md)
|
||||||
|
- [Common issues](docs/common-issues.md)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
# Make changes to pull request here
|
# Make changes to pull request here
|
||||||
|
|
||||||
@ -52,14 +53,15 @@ All inputs are **optional**. If not set, sensible defaults will be used.
|
|||||||
| Name | Description | Default |
|
| Name | Description | Default |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `token` | `GITHUB_TOKEN` (permissions `contents: write` and `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` |
|
| `token` | `GITHUB_TOKEN` (permissions `contents: write` and `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` |
|
||||||
|
| `git-token` | The [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) that the action will use for git operations. | Defaults to the value of `token` |
|
||||||
| `path` | Relative path under `GITHUB_WORKSPACE` to the repository. | `GITHUB_WORKSPACE` |
|
| `path` | Relative path under `GITHUB_WORKSPACE` to the repository. | `GITHUB_WORKSPACE` |
|
||||||
| `add-paths` | A comma or newline-separated list of file paths to commit. Paths should follow git's [pathspec](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefpathspecapathspec) syntax. If no paths are specified, all new and modified files are added. See [Add specific paths](#add-specific-paths). | |
|
| `add-paths` | A comma or newline-separated list of file paths to commit. Paths should follow git's [pathspec](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefpathspecapathspec) syntax. If no paths are specified, all new and modified files are added. See [Add specific paths](#add-specific-paths). | |
|
||||||
| `commit-message` | The message to use when committing changes. | `[create-pull-request] automated change` |
|
| `commit-message` | The message to use when committing changes. See [commit-message](#commit-message). | `[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>` |
|
| `committer` | The committer name and email address in the format `Display Name <email@address.com>`. Defaults to the GitHub Actions bot user. | `github-actions[bot] <41898282+github-actions[bot]@users.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>` |
|
| `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_id }}+${{ 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` |
|
| `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` |
|
| `branch` | The pull request branch name. | `create-pull-request/patch` |
|
||||||
| `delete-branch` | Delete the `branch` when closing pull requests, and when undeleted after merging. | `false` |
|
| `delete-branch` | Delete the `branch` if it doesn't have an active pull request associated with it. See [delete-branch](#delete-branch). | `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. | |
|
| `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. |
|
| `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](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. | |
|
||||||
@ -73,6 +75,28 @@ All inputs are **optional**. If not set, sensible defaults will be used.
|
|||||||
| `milestone` | The number of the milestone to associate this pull request with. | |
|
| `milestone` | The number of the milestone to associate this pull request with. | |
|
||||||
| `draft` | Create a [draft pull request](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests#draft-pull-requests). It is not possible to change draft status after creation except through the web interface. | `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). It is not possible to change draft status after creation except through the web interface. | `false` |
|
||||||
|
|
||||||
|
#### commit-message
|
||||||
|
|
||||||
|
In addition to a message, the `commit-message` input can also be used to populate the commit description. Leave a single blank line between the message and description.
|
||||||
|
|
||||||
|
```yml
|
||||||
|
commit-message: |
|
||||||
|
the first line is the commit message
|
||||||
|
|
||||||
|
the commit description starts
|
||||||
|
after a blank line and can be
|
||||||
|
multiple lines
|
||||||
|
```
|
||||||
|
|
||||||
|
#### delete-branch
|
||||||
|
|
||||||
|
The `delete-branch` feature doesn't delete branches immediately on merge. (It can't do that because it would require the merge to somehow trigger the action.)
|
||||||
|
The intention of the feature is that when the action next runs it will delete the `branch` if it doesn't have an active pull request associated with it.
|
||||||
|
|
||||||
|
If you want branches to be deleted immediately on merge then you should use GitHub's `Automatically delete head branches` feature in your repository settings.
|
||||||
|
|
||||||
|
#### Proxy support
|
||||||
|
|
||||||
For self-hosted runners behind a corporate proxy set the `https_proxy` environment variable.
|
For self-hosted runners behind a corporate proxy set the `https_proxy` environment variable.
|
||||||
```yml
|
```yml
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
@ -115,7 +139,7 @@ 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 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 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 it will be updated if necessary. Local changes in the Actions workspace, or changes on the base branch, can cause an update. If no update is required the action exits silently.
|
- If a pull request already exists it will be updated if necessary. Local changes in the Actions workspace, or changes on the base branch, can cause an update. If no update is required 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 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.
|
- 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`](#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).
|
For further details about how the action works and usage guidelines, see [Concepts, guidelines and advanced usage](docs/concepts-guidelines.md).
|
||||||
|
|
||||||
@ -173,7 +197,7 @@ Note that the repository must be checked out on a branch with a remote, it won't
|
|||||||
|
|
||||||
```yml
|
```yml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Create commits
|
- name: Create commits
|
||||||
run: |
|
run: |
|
||||||
git config user.name 'Peter Evans'
|
git config user.name 'Peter Evans'
|
||||||
@ -224,7 +248,7 @@ jobs:
|
|||||||
createPullRequest:
|
createPullRequest:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Make changes to pull request
|
- name: Make changes to pull request
|
||||||
run: date +%s > report.txt
|
run: date +%s > report.txt
|
||||||
@ -235,8 +259,8 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
commit-message: Update report
|
commit-message: Update report
|
||||||
committer: GitHub <noreply@github.com>
|
committer: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
|
||||||
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
|
author: ${{ github.actor }} <${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com>
|
||||||
signoff: false
|
signoff: false
|
||||||
branch: example-patches
|
branch: example-patches
|
||||||
delete-branch: true
|
delete-branch: true
|
||||||
|
@ -8,7 +8,7 @@ import {GitCommandManager} from '../lib/git-command-manager'
|
|||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import {v4 as uuidv4} from 'uuid'
|
import {v4 as uuidv4} from 'uuid'
|
||||||
|
|
||||||
const REPO_PATH = '/git/local/test-base'
|
const REPO_PATH = '/git/local/repos/test-base'
|
||||||
const REMOTE_NAME = 'origin'
|
const REMOTE_NAME = 'origin'
|
||||||
|
|
||||||
const TRACKED_FILE = 'a/tracked-file.txt'
|
const TRACKED_FILE = 'a/tracked-file.txt'
|
||||||
@ -22,7 +22,7 @@ const INIT_COMMIT_MESSAGE = 'Add file to be a tracked file for tests'
|
|||||||
const BRANCH = 'tests/create-pull-request/patch'
|
const BRANCH = 'tests/create-pull-request/patch'
|
||||||
const BASE = DEFAULT_BRANCH
|
const BASE = DEFAULT_BRANCH
|
||||||
|
|
||||||
const FORK_REMOTE_URL = 'git://127.0.0.1/test-fork.git'
|
const FORK_REMOTE_URL = 'git://127.0.0.1/repos/test-fork.git'
|
||||||
const FORK_REMOTE_NAME = 'fork'
|
const FORK_REMOTE_NAME = 'fork'
|
||||||
|
|
||||||
const ADD_PATHS_DEFAULT = []
|
const ADD_PATHS_DEFAULT = []
|
||||||
|
@ -5,18 +5,18 @@ set -euo pipefail
|
|||||||
WORKINGDIR=$PWD
|
WORKINGDIR=$PWD
|
||||||
|
|
||||||
# Create and serve a remote repo
|
# Create and serve a remote repo
|
||||||
mkdir -p /git/remote
|
mkdir -p /git/remote/repos
|
||||||
git config --global init.defaultBranch main
|
git config --global init.defaultBranch main
|
||||||
git init --bare /git/remote/test-base.git
|
git init --bare /git/remote/repos/test-base.git
|
||||||
git daemon --verbose --enable=receive-pack --base-path=/git/remote --export-all /git/remote &>/dev/null &
|
git daemon --verbose --enable=receive-pack --base-path=/git/remote --export-all /git/remote &>/dev/null &
|
||||||
|
|
||||||
# Give the daemon time to start
|
# Give the daemon time to start
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
# Create a local clone and make an initial commit
|
# Create a local clone and make an initial commit
|
||||||
mkdir -p /git/local
|
mkdir -p /git/local/repos
|
||||||
git clone git://127.0.0.1/test-base.git /git/local/test-base
|
git clone git://127.0.0.1/repos/test-base.git /git/local/repos/test-base
|
||||||
cd /git/local/test-base
|
cd /git/local/repos/test-base
|
||||||
git config --global user.email "you@example.com"
|
git config --global user.email "you@example.com"
|
||||||
git config --global user.name "Your Name"
|
git config --global user.name "Your Name"
|
||||||
echo "#test-base" > README.md
|
echo "#test-base" > README.md
|
||||||
@ -30,8 +30,8 @@ git config -l
|
|||||||
|
|
||||||
# Clone a server-side fork of the base repo
|
# Clone a server-side fork of the base repo
|
||||||
cd $WORKINGDIR
|
cd $WORKINGDIR
|
||||||
git clone --mirror git://127.0.0.1/test-base.git /git/remote/test-fork.git
|
git clone --mirror git://127.0.0.1/repos/test-base.git /git/remote/repos/test-fork.git
|
||||||
cd /git/remote/test-fork.git
|
cd /git/remote/repos/test-fork.git
|
||||||
git log -1 --pretty=oneline
|
git log -1 --pretty=oneline
|
||||||
|
|
||||||
# Restore the working directory
|
# Restore the working directory
|
||||||
|
@ -1,32 +1,32 @@
|
|||||||
import {GitCommandManager} from '../lib/git-command-manager'
|
import {GitCommandManager} from '../lib/git-command-manager'
|
||||||
import {GitAuthHelper} from '../lib/git-auth-helper'
|
import {GitConfigHelper} from '../lib/git-config-helper'
|
||||||
|
|
||||||
const REPO_PATH = '/git/local/test-base'
|
const REPO_PATH = '/git/local/repos/test-base'
|
||||||
|
|
||||||
const extraheaderConfigKey = 'http.https://github.com/.extraheader'
|
const extraheaderConfigKey = 'http.https://127.0.0.1/.extraheader'
|
||||||
|
|
||||||
describe('git-auth-helper tests', () => {
|
describe('git-config-helper integration tests', () => {
|
||||||
let git: GitCommandManager
|
let git: GitCommandManager
|
||||||
let gitAuthHelper: GitAuthHelper
|
let gitConfigHelper: GitConfigHelper
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
git = await GitCommandManager.create(REPO_PATH)
|
git = await GitCommandManager.create(REPO_PATH)
|
||||||
gitAuthHelper = new GitAuthHelper(git)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('tests save and restore with no persisted auth', async () => {
|
it('tests save and restore with no persisted auth', async () => {
|
||||||
await gitAuthHelper.savePersistedAuth()
|
const gitConfigHelper = await GitConfigHelper.create(git)
|
||||||
await gitAuthHelper.restorePersistedAuth()
|
await gitConfigHelper.close()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('tests configure and removal of auth', async () => {
|
it('tests configure and removal of auth', async () => {
|
||||||
await gitAuthHelper.configureToken('github-token')
|
const gitConfigHelper = await GitConfigHelper.create(git)
|
||||||
|
await gitConfigHelper.configureToken('github-token')
|
||||||
expect(await git.configExists(extraheaderConfigKey)).toBeTruthy()
|
expect(await git.configExists(extraheaderConfigKey)).toBeTruthy()
|
||||||
expect(await git.getConfigValue(extraheaderConfigKey)).toEqual(
|
expect(await git.getConfigValue(extraheaderConfigKey)).toEqual(
|
||||||
'AUTHORIZATION: basic eC1hY2Nlc3MtdG9rZW46Z2l0aHViLXRva2Vu'
|
'AUTHORIZATION: basic eC1hY2Nlc3MtdG9rZW46Z2l0aHViLXRva2Vu'
|
||||||
)
|
)
|
||||||
|
|
||||||
await gitAuthHelper.removeAuth()
|
await gitConfigHelper.close()
|
||||||
expect(await git.configExists(extraheaderConfigKey)).toBeFalsy()
|
expect(await git.configExists(extraheaderConfigKey)).toBeFalsy()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -34,37 +34,53 @@ describe('git-auth-helper tests', () => {
|
|||||||
const extraheaderConfigValue = 'AUTHORIZATION: basic ***persisted-auth***'
|
const extraheaderConfigValue = 'AUTHORIZATION: basic ***persisted-auth***'
|
||||||
await git.config(extraheaderConfigKey, extraheaderConfigValue)
|
await git.config(extraheaderConfigKey, extraheaderConfigValue)
|
||||||
|
|
||||||
await gitAuthHelper.savePersistedAuth()
|
const gitConfigHelper = await GitConfigHelper.create(git)
|
||||||
|
|
||||||
const exists = await git.configExists(extraheaderConfigKey)
|
const exists = await git.configExists(extraheaderConfigKey)
|
||||||
expect(exists).toBeFalsy()
|
expect(exists).toBeFalsy()
|
||||||
|
|
||||||
await gitAuthHelper.restorePersistedAuth()
|
await gitConfigHelper.close()
|
||||||
|
|
||||||
const configValue = await git.getConfigValue(extraheaderConfigKey)
|
const configValue = await git.getConfigValue(extraheaderConfigKey)
|
||||||
expect(configValue).toEqual(extraheaderConfigValue)
|
expect(configValue).toEqual(extraheaderConfigValue)
|
||||||
|
|
||||||
await gitAuthHelper.removeAuth()
|
const unset = await git.tryConfigUnset(
|
||||||
|
extraheaderConfigKey,
|
||||||
|
'^AUTHORIZATION:'
|
||||||
|
)
|
||||||
|
expect(unset).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('tests not adding/removing the safe.directory config when it already exists', async () => {
|
||||||
|
await git.config('safe.directory', '/another-value', true, true)
|
||||||
|
|
||||||
|
const gitConfigHelper = await GitConfigHelper.create(git)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await git.configExists('safe.directory', '/another-value', true)
|
||||||
|
).toBeTruthy()
|
||||||
|
|
||||||
|
await gitConfigHelper.close()
|
||||||
|
|
||||||
|
const unset = await git.tryConfigUnset(
|
||||||
|
'safe.directory',
|
||||||
|
'/another-value',
|
||||||
|
true
|
||||||
|
)
|
||||||
|
expect(unset).toBeTruthy()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('tests adding and removing the safe.directory config', async () => {
|
it('tests adding and removing the safe.directory config', async () => {
|
||||||
await git.config('safe.directory', '/another-value', true, true)
|
const gitConfigHelper = await GitConfigHelper.create(git)
|
||||||
|
|
||||||
await gitAuthHelper.removeSafeDirectory()
|
|
||||||
await gitAuthHelper.addSafeDirectory()
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
await git.configExists('safe.directory', REPO_PATH, true)
|
await git.configExists('safe.directory', REPO_PATH, true)
|
||||||
).toBeTruthy()
|
).toBeTruthy()
|
||||||
|
|
||||||
await gitAuthHelper.addSafeDirectory()
|
await gitConfigHelper.close()
|
||||||
await gitAuthHelper.removeSafeDirectory()
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
await git.configExists('safe.directory', REPO_PATH, true)
|
await git.configExists('safe.directory', REPO_PATH, true)
|
||||||
).toBeFalsy()
|
).toBeFalsy()
|
||||||
expect(
|
|
||||||
await git.configExists('safe.directory', '/another-value', true)
|
|
||||||
).toBeTruthy()
|
|
||||||
})
|
})
|
||||||
})
|
})
|
93
__test__/git-config-helper.unit.test.ts
Normal file
93
__test__/git-config-helper.unit.test.ts
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import {GitConfigHelper} from '../lib/git-config-helper'
|
||||||
|
|
||||||
|
describe('git-config-helper unit tests', () => {
|
||||||
|
test('parseGitRemote successfully parses HTTPS remote URLs', async () => {
|
||||||
|
const remote1 = GitConfigHelper.parseGitRemote(
|
||||||
|
'https://github.com/peter-evans/create-pull-request'
|
||||||
|
)
|
||||||
|
expect(remote1.hostname).toEqual('github.com')
|
||||||
|
expect(remote1.protocol).toEqual('HTTPS')
|
||||||
|
expect(remote1.repository).toEqual('peter-evans/create-pull-request')
|
||||||
|
|
||||||
|
const remote2 = GitConfigHelper.parseGitRemote(
|
||||||
|
'https://xxx:x-oauth-basic@github.com/peter-evans/create-pull-request'
|
||||||
|
)
|
||||||
|
expect(remote2.hostname).toEqual('github.com')
|
||||||
|
expect(remote2.protocol).toEqual('HTTPS')
|
||||||
|
expect(remote2.repository).toEqual('peter-evans/create-pull-request')
|
||||||
|
|
||||||
|
const remote3 = GitConfigHelper.parseGitRemote(
|
||||||
|
'https://github.com/peter-evans/create-pull-request.git'
|
||||||
|
)
|
||||||
|
expect(remote3.hostname).toEqual('github.com')
|
||||||
|
expect(remote3.protocol).toEqual('HTTPS')
|
||||||
|
expect(remote3.repository).toEqual('peter-evans/create-pull-request')
|
||||||
|
|
||||||
|
const remote4 = GitConfigHelper.parseGitRemote(
|
||||||
|
'https://github.com/peter-evans/ungit'
|
||||||
|
)
|
||||||
|
expect(remote4.hostname).toEqual('github.com')
|
||||||
|
expect(remote4.protocol).toEqual('HTTPS')
|
||||||
|
expect(remote4.repository).toEqual('peter-evans/ungit')
|
||||||
|
|
||||||
|
const remote5 = GitConfigHelper.parseGitRemote(
|
||||||
|
'https://github.com/peter-evans/ungit.git'
|
||||||
|
)
|
||||||
|
expect(remote5.hostname).toEqual('github.com')
|
||||||
|
expect(remote5.protocol).toEqual('HTTPS')
|
||||||
|
expect(remote5.repository).toEqual('peter-evans/ungit')
|
||||||
|
|
||||||
|
const remote6 = GitConfigHelper.parseGitRemote(
|
||||||
|
'https://github.internal.company/peter-evans/create-pull-request'
|
||||||
|
)
|
||||||
|
expect(remote6.hostname).toEqual('github.internal.company')
|
||||||
|
expect(remote6.protocol).toEqual('HTTPS')
|
||||||
|
expect(remote6.repository).toEqual('peter-evans/create-pull-request')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('parseGitRemote successfully parses SSH remote URLs', async () => {
|
||||||
|
const remote1 = GitConfigHelper.parseGitRemote(
|
||||||
|
'git@github.com:peter-evans/create-pull-request.git'
|
||||||
|
)
|
||||||
|
expect(remote1.hostname).toEqual('github.com')
|
||||||
|
expect(remote1.protocol).toEqual('SSH')
|
||||||
|
expect(remote1.repository).toEqual('peter-evans/create-pull-request')
|
||||||
|
|
||||||
|
const remote2 = GitConfigHelper.parseGitRemote(
|
||||||
|
'git@github.com:peter-evans/ungit.git'
|
||||||
|
)
|
||||||
|
expect(remote2.hostname).toEqual('github.com')
|
||||||
|
expect(remote2.protocol).toEqual('SSH')
|
||||||
|
expect(remote2.repository).toEqual('peter-evans/ungit')
|
||||||
|
|
||||||
|
const remote3 = GitConfigHelper.parseGitRemote(
|
||||||
|
'git@github.internal.company:peter-evans/create-pull-request.git'
|
||||||
|
)
|
||||||
|
expect(remote3.hostname).toEqual('github.internal.company')
|
||||||
|
expect(remote3.protocol).toEqual('SSH')
|
||||||
|
expect(remote3.repository).toEqual('peter-evans/create-pull-request')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('parseGitRemote successfully parses GIT remote URLs', async () => {
|
||||||
|
// Unauthenticated git protocol for integration tests only
|
||||||
|
const remote1 = GitConfigHelper.parseGitRemote(
|
||||||
|
'git://127.0.0.1/repos/test-base.git'
|
||||||
|
)
|
||||||
|
expect(remote1.hostname).toEqual('127.0.0.1')
|
||||||
|
expect(remote1.protocol).toEqual('GIT')
|
||||||
|
expect(remote1.repository).toEqual('repos/test-base')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('parseGitRemote fails to parse a remote URL', async () => {
|
||||||
|
const remoteUrl = 'https://github.com/peter-evans'
|
||||||
|
try {
|
||||||
|
GitConfigHelper.parseGitRemote(remoteUrl)
|
||||||
|
// Fail the test if an error wasn't thrown
|
||||||
|
expect(true).toEqual(false)
|
||||||
|
} catch (e: any) {
|
||||||
|
expect(e.message).toEqual(
|
||||||
|
`The format of '${remoteUrl}' is not a valid GitHub repository URL`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
@ -8,7 +8,7 @@ if [[ "$(docker images -q $IMAGE 2> /dev/null)" == "" || $ARG1 == "build" ]]; th
|
|||||||
echo "Building Docker image $IMAGE ..."
|
echo "Building Docker image $IMAGE ..."
|
||||||
|
|
||||||
cat > Dockerfile << EOF
|
cat > Dockerfile << EOF
|
||||||
FROM node:16-alpine
|
FROM node:20-alpine
|
||||||
RUN apk --no-cache add git git-daemon
|
RUN apk --no-cache add git git-daemon
|
||||||
RUN npm install jest jest-environment-jsdom --global
|
RUN npm install jest jest-environment-jsdom --global
|
||||||
WORKDIR /cpr
|
WORKDIR /cpr
|
||||||
|
@ -44,63 +44,6 @@ describe('utils tests', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('getRemoteDetail successfully parses remote URLs', async () => {
|
|
||||||
const remote1 = utils.getRemoteDetail(
|
|
||||||
'https://github.com/peter-evans/create-pull-request'
|
|
||||||
)
|
|
||||||
expect(remote1.protocol).toEqual('HTTPS')
|
|
||||||
expect(remote1.repository).toEqual('peter-evans/create-pull-request')
|
|
||||||
|
|
||||||
const remote2 = utils.getRemoteDetail(
|
|
||||||
'https://xxx:x-oauth-basic@github.com/peter-evans/create-pull-request'
|
|
||||||
)
|
|
||||||
expect(remote2.protocol).toEqual('HTTPS')
|
|
||||||
expect(remote2.repository).toEqual('peter-evans/create-pull-request')
|
|
||||||
|
|
||||||
const remote3 = utils.getRemoteDetail(
|
|
||||||
'git@github.com:peter-evans/create-pull-request.git'
|
|
||||||
)
|
|
||||||
expect(remote3.protocol).toEqual('SSH')
|
|
||||||
expect(remote3.repository).toEqual('peter-evans/create-pull-request')
|
|
||||||
|
|
||||||
const remote4 = utils.getRemoteDetail(
|
|
||||||
'https://github.com/peter-evans/create-pull-request.git'
|
|
||||||
)
|
|
||||||
expect(remote4.protocol).toEqual('HTTPS')
|
|
||||||
expect(remote4.repository).toEqual('peter-evans/create-pull-request')
|
|
||||||
|
|
||||||
const remote5 = utils.getRemoteDetail(
|
|
||||||
'https://github.com/peter-evans/ungit'
|
|
||||||
)
|
|
||||||
expect(remote5.protocol).toEqual('HTTPS')
|
|
||||||
expect(remote5.repository).toEqual('peter-evans/ungit')
|
|
||||||
|
|
||||||
const remote6 = utils.getRemoteDetail(
|
|
||||||
'https://github.com/peter-evans/ungit.git'
|
|
||||||
)
|
|
||||||
expect(remote6.protocol).toEqual('HTTPS')
|
|
||||||
expect(remote6.repository).toEqual('peter-evans/ungit')
|
|
||||||
|
|
||||||
const remote7 = utils.getRemoteDetail(
|
|
||||||
'git@github.com:peter-evans/ungit.git'
|
|
||||||
)
|
|
||||||
expect(remote7.protocol).toEqual('SSH')
|
|
||||||
expect(remote7.repository).toEqual('peter-evans/ungit')
|
|
||||||
})
|
|
||||||
|
|
||||||
test('getRemoteDetail fails to parse a remote URL', async () => {
|
|
||||||
const remoteUrl = 'https://github.com/peter-evans'
|
|
||||||
try {
|
|
||||||
utils.getRemoteDetail(remoteUrl)
|
|
||||||
// Fail the test if an error wasn't thrown
|
|
||||||
expect(true).toEqual(false)
|
|
||||||
} catch (e: any) {
|
|
||||||
expect(e.message).toEqual(
|
|
||||||
`The format of '${remoteUrl}' is not a valid GitHub repository URL`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
test('getRemoteUrl successfully returns remote URLs', async () => {
|
test('getRemoteUrl successfully returns remote URLs', async () => {
|
||||||
const url1 = utils.getRemoteUrl(
|
const url1 = utils.getRemoteUrl(
|
||||||
'HTTPS',
|
'HTTPS',
|
||||||
|
13
action.yml
13
action.yml
@ -4,6 +4,10 @@ inputs:
|
|||||||
token:
|
token:
|
||||||
description: 'GITHUB_TOKEN or a `repo` scoped Personal Access Token (PAT)'
|
description: 'GITHUB_TOKEN or a `repo` scoped Personal Access Token (PAT)'
|
||||||
default: ${{ github.token }}
|
default: ${{ github.token }}
|
||||||
|
git-token:
|
||||||
|
description: >
|
||||||
|
The Personal Access Token (PAT) that the action will use for git operations.
|
||||||
|
Defaults to the value of `token`.
|
||||||
path:
|
path:
|
||||||
description: >
|
description: >
|
||||||
Relative path under $GITHUB_WORKSPACE to the repository.
|
Relative path under $GITHUB_WORKSPACE to the repository.
|
||||||
@ -20,12 +24,12 @@ inputs:
|
|||||||
description: >
|
description: >
|
||||||
The committer name and email address in the format `Display Name <email@address.com>`.
|
The committer name and email address in the format `Display Name <email@address.com>`.
|
||||||
Defaults to the GitHub Actions bot user.
|
Defaults to the GitHub Actions bot user.
|
||||||
default: 'GitHub <noreply@github.com>'
|
default: 'github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>'
|
||||||
author:
|
author:
|
||||||
description: >
|
description: >
|
||||||
The author name and email address in the format `Display Name <email@address.com>`.
|
The author name and email address in the format `Display Name <email@address.com>`.
|
||||||
Defaults to the user who triggered the workflow run.
|
Defaults to the user who triggered the workflow run.
|
||||||
default: '${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>'
|
default: '${{ github.actor }} <${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com>'
|
||||||
signoff:
|
signoff:
|
||||||
description: 'Add `Signed-off-by` line by the committer at the end of the commit log message.'
|
description: 'Add `Signed-off-by` line by the committer at the end of the commit log message.'
|
||||||
default: false
|
default: false
|
||||||
@ -34,8 +38,7 @@ inputs:
|
|||||||
default: 'create-pull-request/patch'
|
default: 'create-pull-request/patch'
|
||||||
delete-branch:
|
delete-branch:
|
||||||
description: >
|
description: >
|
||||||
Delete the `branch` when closing pull requests, and when undeleted after merging.
|
Delete the `branch` if it doesn't have an active pull request associated with it.
|
||||||
Recommend `true`.
|
|
||||||
default: false
|
default: false
|
||||||
branch-suffix:
|
branch-suffix:
|
||||||
description: 'The branch suffix type when using the alternative branching strategy.'
|
description: 'The branch suffix type when using the alternative branching strategy.'
|
||||||
@ -81,7 +84,7 @@ outputs:
|
|||||||
pull-request-head-sha:
|
pull-request-head-sha:
|
||||||
description: 'The commit SHA of the pull request branch.'
|
description: 'The commit SHA of the pull request branch.'
|
||||||
runs:
|
runs:
|
||||||
using: 'node16'
|
using: 'node20'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
branding:
|
branding:
|
||||||
icon: 'git-pull-request'
|
icon: 'git-pull-request'
|
||||||
|
733
dist/index.js
vendored
733
dist/index.js
vendored
@ -171,9 +171,7 @@ function createOrUpdateBranch(git, commitMessage, base, branch, branchRemoteName
|
|||||||
if (branchRemoteName == 'fork') {
|
if (branchRemoteName == 'fork') {
|
||||||
// If pushing to a fork we must fetch with 'unshallow' to avoid the following error on git push
|
// 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)
|
// ! [remote rejected] HEAD -> tests/push-branch-to-fork (shallow update not allowed)
|
||||||
yield git.fetch([`${workingBase}:${workingBase}`], baseRemote, [
|
yield git.fetch([`${workingBase}:${workingBase}`], baseRemote, ['--force'], true);
|
||||||
'--force'
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If the remote is 'origin' we can git reset
|
// If the remote is 'origin' we can git reset
|
||||||
@ -318,38 +316,21 @@ const core = __importStar(__nccwpck_require__(2186));
|
|||||||
const create_or_update_branch_1 = __nccwpck_require__(8363);
|
const create_or_update_branch_1 = __nccwpck_require__(8363);
|
||||||
const github_helper_1 = __nccwpck_require__(446);
|
const github_helper_1 = __nccwpck_require__(446);
|
||||||
const git_command_manager_1 = __nccwpck_require__(738);
|
const git_command_manager_1 = __nccwpck_require__(738);
|
||||||
const git_auth_helper_1 = __nccwpck_require__(2565);
|
const git_config_helper_1 = __nccwpck_require__(8384);
|
||||||
const utils = __importStar(__nccwpck_require__(918));
|
const utils = __importStar(__nccwpck_require__(918));
|
||||||
function createPullRequest(inputs) {
|
function createPullRequest(inputs) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
let gitAuthHelper;
|
let gitConfigHelper, git;
|
||||||
try {
|
try {
|
||||||
if (!inputs.token) {
|
|
||||||
throw new Error(`Input 'token' not supplied. Unable to continue.`);
|
|
||||||
}
|
|
||||||
if (inputs.bodyPath) {
|
|
||||||
if (!utils.fileExistsSync(inputs.bodyPath)) {
|
|
||||||
throw new Error(`File '${inputs.bodyPath}' does not exist.`);
|
|
||||||
}
|
|
||||||
// Update the body input with the contents of the file
|
|
||||||
inputs.body = utils.readFile(inputs.bodyPath);
|
|
||||||
}
|
|
||||||
// Get the repository path
|
|
||||||
const repoPath = utils.getRepoPath(inputs.path);
|
|
||||||
// Create a git command manager
|
|
||||||
const git = yield git_command_manager_1.GitCommandManager.create(repoPath);
|
|
||||||
// Save and unset the extraheader auth config if it exists
|
|
||||||
core.startGroup('Prepare git configuration');
|
core.startGroup('Prepare git configuration');
|
||||||
gitAuthHelper = new git_auth_helper_1.GitAuthHelper(git);
|
const repoPath = utils.getRepoPath(inputs.path);
|
||||||
yield gitAuthHelper.addSafeDirectory();
|
git = yield git_command_manager_1.GitCommandManager.create(repoPath);
|
||||||
yield gitAuthHelper.savePersistedAuth();
|
gitConfigHelper = yield git_config_helper_1.GitConfigHelper.create(git);
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
// Init the GitHub client
|
|
||||||
const githubHelper = new github_helper_1.GitHubHelper(inputs.token);
|
|
||||||
core.startGroup('Determining the base and head repositories');
|
core.startGroup('Determining the base and head repositories');
|
||||||
// Determine the base repository from git config
|
const baseRemote = gitConfigHelper.getGitRemote();
|
||||||
const remoteUrl = yield git.tryGetRemoteUrl();
|
// Init the GitHub client
|
||||||
const baseRemote = utils.getRemoteDetail(remoteUrl);
|
const githubHelper = new github_helper_1.GitHubHelper(baseRemote.hostname, inputs.token);
|
||||||
// Determine the head repository; the target for the pull request branch
|
// Determine the head repository; the target for the pull request branch
|
||||||
const branchRemoteName = inputs.pushToFork ? 'fork' : 'origin';
|
const branchRemoteName = inputs.pushToFork ? 'fork' : 'origin';
|
||||||
const branchRepository = inputs.pushToFork
|
const branchRepository = inputs.pushToFork
|
||||||
@ -358,9 +339,14 @@ function createPullRequest(inputs) {
|
|||||||
if (inputs.pushToFork) {
|
if (inputs.pushToFork) {
|
||||||
// Check if the supplied fork is really a fork of the base
|
// Check if the supplied fork is really a fork of the base
|
||||||
core.info(`Checking if '${branchRepository}' is a fork of '${baseRemote.repository}'`);
|
core.info(`Checking if '${branchRepository}' is a fork of '${baseRemote.repository}'`);
|
||||||
const parentRepository = yield githubHelper.getRepositoryParent(branchRepository);
|
const baseParentRepository = yield githubHelper.getRepositoryParent(baseRemote.repository);
|
||||||
if (parentRepository != baseRemote.repository) {
|
const branchParentRepository = yield githubHelper.getRepositoryParent(branchRepository);
|
||||||
throw new Error(`Repository '${branchRepository}' is not a fork of '${baseRemote.repository}'. Unable to continue.`);
|
if (branchParentRepository == null) {
|
||||||
|
throw new Error(`Repository '${branchRepository}' is not a fork. Unable to continue.`);
|
||||||
|
}
|
||||||
|
if (branchParentRepository != baseRemote.repository &&
|
||||||
|
baseParentRepository != branchParentRepository) {
|
||||||
|
throw new Error(`Repository '${branchRepository}' is not a fork of '${baseRemote.repository}', nor are they siblings. Unable to continue.`);
|
||||||
}
|
}
|
||||||
// Add a remote for the fork
|
// Add a remote for the fork
|
||||||
const remoteUrl = utils.getRemoteUrl(baseRemote.protocol, baseRemote.hostname, branchRepository);
|
const remoteUrl = utils.getRemoteUrl(baseRemote.protocol, baseRemote.hostname, branchRepository);
|
||||||
@ -371,7 +357,7 @@ function createPullRequest(inputs) {
|
|||||||
// Configure auth
|
// Configure auth
|
||||||
if (baseRemote.protocol == 'HTTPS') {
|
if (baseRemote.protocol == 'HTTPS') {
|
||||||
core.startGroup('Configuring credential for HTTPS authentication');
|
core.startGroup('Configuring credential for HTTPS authentication');
|
||||||
yield gitAuthHelper.configureToken(inputs.token);
|
yield gitConfigHelper.configureToken(inputs.gitToken);
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
}
|
}
|
||||||
core.startGroup('Checking the base repository state');
|
core.startGroup('Checking the base repository state');
|
||||||
@ -498,11 +484,11 @@ function createPullRequest(inputs) {
|
|||||||
core.setFailed(utils.getErrorMessage(error));
|
core.setFailed(utils.getErrorMessage(error));
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// Remove auth and restore persisted auth config if it existed
|
|
||||||
core.startGroup('Restore git configuration');
|
core.startGroup('Restore git configuration');
|
||||||
yield gitAuthHelper.removeAuth();
|
if (inputs.pushToFork) {
|
||||||
yield gitAuthHelper.restorePersistedAuth();
|
yield git.exec(['remote', 'rm', 'fork']);
|
||||||
yield gitAuthHelper.removeSafeDirectory();
|
}
|
||||||
|
yield gitConfigHelper.close();
|
||||||
core.endGroup();
|
core.endGroup();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -510,163 +496,6 @@ function createPullRequest(inputs) {
|
|||||||
exports.createPullRequest = createPullRequest;
|
exports.createPullRequest = createPullRequest;
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
|
||||||
|
|
||||||
/***/ 2565:
|
|
||||||
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
||||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
||||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
||||||
}
|
|
||||||
Object.defineProperty(o, k2, desc);
|
|
||||||
}) : (function(o, m, k, k2) {
|
|
||||||
if (k2 === undefined) k2 = k;
|
|
||||||
o[k2] = m[k];
|
|
||||||
}));
|
|
||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
||||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
||||||
}) : function(o, v) {
|
|
||||||
o["default"] = v;
|
|
||||||
});
|
|
||||||
var __importStar = (this && this.__importStar) || function (mod) {
|
|
||||||
if (mod && mod.__esModule) return mod;
|
|
||||||
var result = {};
|
|
||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
||||||
__setModuleDefault(result, mod);
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
||||||
exports.GitAuthHelper = void 0;
|
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
|
||||||
const fs = __importStar(__nccwpck_require__(7147));
|
|
||||||
const path = __importStar(__nccwpck_require__(1017));
|
|
||||||
const url_1 = __nccwpck_require__(7310);
|
|
||||||
const utils = __importStar(__nccwpck_require__(918));
|
|
||||||
class GitAuthHelper {
|
|
||||||
constructor(git) {
|
|
||||||
this.gitConfigPath = '';
|
|
||||||
this.safeDirectoryConfigKey = 'safe.directory';
|
|
||||||
this.safeDirectoryAdded = false;
|
|
||||||
this.extraheaderConfigPlaceholderValue = 'AUTHORIZATION: basic ***';
|
|
||||||
this.extraheaderConfigValueRegex = '^AUTHORIZATION:';
|
|
||||||
this.persistedExtraheaderConfigValue = '';
|
|
||||||
this.git = git;
|
|
||||||
this.workingDirectory = this.git.getWorkingDirectory();
|
|
||||||
const serverUrl = this.getServerUrl();
|
|
||||||
this.extraheaderConfigKey = `http.${serverUrl.origin}/.extraheader`;
|
|
||||||
}
|
|
||||||
addSafeDirectory() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const exists = yield this.git.configExists(this.safeDirectoryConfigKey, this.workingDirectory, true);
|
|
||||||
if (!exists) {
|
|
||||||
yield this.git.config(this.safeDirectoryConfigKey, this.workingDirectory, true, true);
|
|
||||||
this.safeDirectoryAdded = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
removeSafeDirectory() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
if (this.safeDirectoryAdded) {
|
|
||||||
yield this.git.tryConfigUnset(this.safeDirectoryConfigKey, this.workingDirectory, true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
savePersistedAuth() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
// Save and unset persisted extraheader credential in git config if it exists
|
|
||||||
this.persistedExtraheaderConfigValue = yield this.getAndUnset();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
restorePersistedAuth() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
if (this.persistedExtraheaderConfigValue) {
|
|
||||||
try {
|
|
||||||
yield this.setExtraheaderConfig(this.persistedExtraheaderConfigValue);
|
|
||||||
core.info('Persisted git credentials restored');
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
core.warning(utils.getErrorMessage(e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
configureToken(token) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
// Encode and configure the basic credential for HTTPS access
|
|
||||||
const basicCredential = Buffer.from(`x-access-token:${token}`, 'utf8').toString('base64');
|
|
||||||
core.setSecret(basicCredential);
|
|
||||||
const extraheaderConfigValue = `AUTHORIZATION: basic ${basicCredential}`;
|
|
||||||
yield this.setExtraheaderConfig(extraheaderConfigValue);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
removeAuth() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
yield this.getAndUnset();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setExtraheaderConfig(extraheaderConfigValue) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
// Configure a placeholder value. This approach avoids the credential being captured
|
|
||||||
// by process creation audit events, which are commonly logged. For more information,
|
|
||||||
// refer to https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/manage/component-updates/command-line-process-auditing
|
|
||||||
// See https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts#L267-L274
|
|
||||||
yield this.git.config(this.extraheaderConfigKey, this.extraheaderConfigPlaceholderValue);
|
|
||||||
// Replace the placeholder
|
|
||||||
yield this.gitConfigStringReplace(this.extraheaderConfigPlaceholderValue, extraheaderConfigValue);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
getAndUnset() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
let configValue = '';
|
|
||||||
// Save and unset persisted extraheader credential in git config if it exists
|
|
||||||
if (yield this.git.configExists(this.extraheaderConfigKey, this.extraheaderConfigValueRegex)) {
|
|
||||||
configValue = yield this.git.getConfigValue(this.extraheaderConfigKey, this.extraheaderConfigValueRegex);
|
|
||||||
if (yield this.git.tryConfigUnset(this.extraheaderConfigKey, this.extraheaderConfigValueRegex)) {
|
|
||||||
core.info(`Unset config key '${this.extraheaderConfigKey}'`);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
core.warning(`Failed to unset config key '${this.extraheaderConfigKey}'`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return configValue;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
gitConfigStringReplace(find, replace) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
if (this.gitConfigPath.length === 0) {
|
|
||||||
const gitDir = yield this.git.getGitDirectory();
|
|
||||||
this.gitConfigPath = path.join(this.workingDirectory, gitDir, 'config');
|
|
||||||
}
|
|
||||||
let content = (yield fs.promises.readFile(this.gitConfigPath)).toString();
|
|
||||||
const index = content.indexOf(find);
|
|
||||||
if (index < 0 || index != content.lastIndexOf(find)) {
|
|
||||||
throw new Error(`Unable to replace '${find}' in ${this.gitConfigPath}`);
|
|
||||||
}
|
|
||||||
content = content.replace(find, replace);
|
|
||||||
yield fs.promises.writeFile(this.gitConfigPath, content);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
getServerUrl() {
|
|
||||||
return new url_1.URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exports.GitAuthHelper = GitAuthHelper;
|
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 738:
|
/***/ 738:
|
||||||
@ -788,14 +617,15 @@ class GitCommandManager {
|
|||||||
return output.exitCode === 0;
|
return output.exitCode === 0;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
fetch(refSpec, remoteName, options) {
|
fetch(refSpec, remoteName, options, unshallow = false) {
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const args = ['-c', 'protocol.version=2', 'fetch'];
|
const args = ['-c', 'protocol.version=2', 'fetch'];
|
||||||
if (!refSpec.some(x => x === tagsRefSpec)) {
|
if (!refSpec.some(x => x === tagsRefSpec)) {
|
||||||
args.push('--no-tags');
|
args.push('--no-tags');
|
||||||
}
|
}
|
||||||
args.push('--progress', '--no-recurse-submodules');
|
args.push('--progress', '--no-recurse-submodules');
|
||||||
if (utils.fileExistsSync(path.join(this.workingDirectory, '.git', 'shallow'))) {
|
if (unshallow &&
|
||||||
|
utils.fileExistsSync(path.join(this.workingDirectory, '.git', 'shallow'))) {
|
||||||
args.push('--unshallow');
|
args.push('--unshallow');
|
||||||
}
|
}
|
||||||
if (options) {
|
if (options) {
|
||||||
@ -997,6 +827,218 @@ class GitOutput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ 8384:
|
||||||
|
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||||
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||||
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||||
|
}
|
||||||
|
Object.defineProperty(o, k2, desc);
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
|
exports.GitConfigHelper = void 0;
|
||||||
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
|
const fs = __importStar(__nccwpck_require__(7147));
|
||||||
|
const path = __importStar(__nccwpck_require__(1017));
|
||||||
|
const url_1 = __nccwpck_require__(7310);
|
||||||
|
const utils = __importStar(__nccwpck_require__(918));
|
||||||
|
class GitConfigHelper {
|
||||||
|
constructor(git) {
|
||||||
|
this.gitConfigPath = '';
|
||||||
|
this.safeDirectoryConfigKey = 'safe.directory';
|
||||||
|
this.safeDirectoryAdded = false;
|
||||||
|
this.remoteUrl = '';
|
||||||
|
this.extraheaderConfigKey = '';
|
||||||
|
this.extraheaderConfigPlaceholderValue = 'AUTHORIZATION: basic ***';
|
||||||
|
this.extraheaderConfigValueRegex = '^AUTHORIZATION:';
|
||||||
|
this.persistedExtraheaderConfigValue = '';
|
||||||
|
this.git = git;
|
||||||
|
this.workingDirectory = this.git.getWorkingDirectory();
|
||||||
|
}
|
||||||
|
static create(git) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const gitConfigHelper = new GitConfigHelper(git);
|
||||||
|
yield gitConfigHelper.addSafeDirectory();
|
||||||
|
yield gitConfigHelper.fetchRemoteDetail();
|
||||||
|
yield gitConfigHelper.savePersistedAuth();
|
||||||
|
return gitConfigHelper;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
close() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
// Remove auth and restore persisted auth config if it existed
|
||||||
|
yield this.removeAuth();
|
||||||
|
yield this.restorePersistedAuth();
|
||||||
|
yield this.removeSafeDirectory();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
addSafeDirectory() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const exists = yield this.git.configExists(this.safeDirectoryConfigKey, this.workingDirectory, true);
|
||||||
|
if (!exists) {
|
||||||
|
yield this.git.config(this.safeDirectoryConfigKey, this.workingDirectory, true, true);
|
||||||
|
this.safeDirectoryAdded = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
removeSafeDirectory() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (this.safeDirectoryAdded) {
|
||||||
|
yield this.git.tryConfigUnset(this.safeDirectoryConfigKey, this.workingDirectory, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fetchRemoteDetail() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
this.remoteUrl = yield this.git.tryGetRemoteUrl();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
getGitRemote() {
|
||||||
|
return GitConfigHelper.parseGitRemote(this.remoteUrl);
|
||||||
|
}
|
||||||
|
static parseGitRemote(remoteUrl) {
|
||||||
|
const httpsUrlPattern = new RegExp('^(https?)://(?:.+@)?(.+?)/(.+/.+?)(\\.git)?$', 'i');
|
||||||
|
const httpsMatch = remoteUrl.match(httpsUrlPattern);
|
||||||
|
if (httpsMatch) {
|
||||||
|
return {
|
||||||
|
hostname: httpsMatch[2],
|
||||||
|
protocol: 'HTTPS',
|
||||||
|
repository: httpsMatch[3]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const sshUrlPattern = new RegExp('^git@(.+?):(.+/.+)\\.git$', 'i');
|
||||||
|
const sshMatch = remoteUrl.match(sshUrlPattern);
|
||||||
|
if (sshMatch) {
|
||||||
|
return {
|
||||||
|
hostname: sshMatch[1],
|
||||||
|
protocol: 'SSH',
|
||||||
|
repository: sshMatch[2]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Unauthenticated git protocol for integration tests only
|
||||||
|
const gitUrlPattern = new RegExp('^git://(.+?)/(.+/.+)\\.git$', 'i');
|
||||||
|
const gitMatch = remoteUrl.match(gitUrlPattern);
|
||||||
|
if (gitMatch) {
|
||||||
|
return {
|
||||||
|
hostname: gitMatch[1],
|
||||||
|
protocol: 'GIT',
|
||||||
|
repository: gitMatch[2]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
throw new Error(`The format of '${remoteUrl}' is not a valid GitHub repository URL`);
|
||||||
|
}
|
||||||
|
savePersistedAuth() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const serverUrl = new url_1.URL(`https://${this.getGitRemote().hostname}`);
|
||||||
|
this.extraheaderConfigKey = `http.${serverUrl.origin}/.extraheader`;
|
||||||
|
// Save and unset persisted extraheader credential in git config if it exists
|
||||||
|
this.persistedExtraheaderConfigValue = yield this.getAndUnset();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
restorePersistedAuth() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (this.persistedExtraheaderConfigValue) {
|
||||||
|
try {
|
||||||
|
yield this.setExtraheaderConfig(this.persistedExtraheaderConfigValue);
|
||||||
|
core.info('Persisted git credentials restored');
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
core.warning(utils.getErrorMessage(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
configureToken(token) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
// Encode and configure the basic credential for HTTPS access
|
||||||
|
const basicCredential = Buffer.from(`x-access-token:${token}`, 'utf8').toString('base64');
|
||||||
|
core.setSecret(basicCredential);
|
||||||
|
const extraheaderConfigValue = `AUTHORIZATION: basic ${basicCredential}`;
|
||||||
|
yield this.setExtraheaderConfig(extraheaderConfigValue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
removeAuth() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
yield this.getAndUnset();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setExtraheaderConfig(extraheaderConfigValue) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
// Configure a placeholder value. This approach avoids the credential being captured
|
||||||
|
// by process creation audit events, which are commonly logged. For more information,
|
||||||
|
// refer to https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/manage/component-updates/command-line-process-auditing
|
||||||
|
// See https://github.com/actions/checkout/blob/main/src/git-auth-helper.ts#L267-L274
|
||||||
|
yield this.git.config(this.extraheaderConfigKey, this.extraheaderConfigPlaceholderValue);
|
||||||
|
// Replace the placeholder
|
||||||
|
yield this.gitConfigStringReplace(this.extraheaderConfigPlaceholderValue, extraheaderConfigValue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
getAndUnset() {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
let configValue = '';
|
||||||
|
// Save and unset persisted extraheader credential in git config if it exists
|
||||||
|
if (yield this.git.configExists(this.extraheaderConfigKey, this.extraheaderConfigValueRegex)) {
|
||||||
|
configValue = yield this.git.getConfigValue(this.extraheaderConfigKey, this.extraheaderConfigValueRegex);
|
||||||
|
if (yield this.git.tryConfigUnset(this.extraheaderConfigKey, this.extraheaderConfigValueRegex)) {
|
||||||
|
core.info(`Unset config key '${this.extraheaderConfigKey}'`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
core.warning(`Failed to unset config key '${this.extraheaderConfigKey}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return configValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
gitConfigStringReplace(find, replace) {
|
||||||
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
|
if (this.gitConfigPath.length === 0) {
|
||||||
|
const gitDir = yield this.git.getGitDirectory();
|
||||||
|
this.gitConfigPath = path.join(this.workingDirectory, gitDir, 'config');
|
||||||
|
}
|
||||||
|
let content = (yield fs.promises.readFile(this.gitConfigPath)).toString();
|
||||||
|
const index = content.indexOf(find);
|
||||||
|
if (index < 0 || index != content.lastIndexOf(find)) {
|
||||||
|
throw new Error(`Unable to replace '${find}' in ${this.gitConfigPath}`);
|
||||||
|
}
|
||||||
|
content = content.replace(find, replace);
|
||||||
|
yield fs.promises.writeFile(this.gitConfigPath, content);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.GitConfigHelper = GitConfigHelper;
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 446:
|
/***/ 446:
|
||||||
@ -1043,12 +1085,17 @@ const octokit_client_1 = __nccwpck_require__(5040);
|
|||||||
const utils = __importStar(__nccwpck_require__(918));
|
const utils = __importStar(__nccwpck_require__(918));
|
||||||
const ERROR_PR_REVIEW_TOKEN_SCOPE = 'Validation Failed: "Could not resolve to a node with the global id of';
|
const ERROR_PR_REVIEW_TOKEN_SCOPE = 'Validation Failed: "Could not resolve to a node with the global id of';
|
||||||
class GitHubHelper {
|
class GitHubHelper {
|
||||||
constructor(token) {
|
constructor(githubServerHostname, token) {
|
||||||
const options = {};
|
const options = {};
|
||||||
if (token) {
|
if (token) {
|
||||||
options.auth = `${token}`;
|
options.auth = `${token}`;
|
||||||
}
|
}
|
||||||
options.baseUrl = process.env['GITHUB_API_URL'] || 'https://api.github.com';
|
if (githubServerHostname !== 'github.com') {
|
||||||
|
options.baseUrl = `https://${githubServerHostname}/api/v3`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
options.baseUrl = 'https://api.github.com';
|
||||||
|
}
|
||||||
this.octokit = new octokit_client_1.Octokit(options);
|
this.octokit = new octokit_client_1.Octokit(options);
|
||||||
}
|
}
|
||||||
parseRepository(repository) {
|
parseRepository(repository) {
|
||||||
@ -1066,7 +1113,7 @@ class GitHubHelper {
|
|||||||
// Try to create the pull request
|
// Try to create the pull request
|
||||||
try {
|
try {
|
||||||
core.info(`Attempting creation of pull request`);
|
core.info(`Attempting creation of pull request`);
|
||||||
const { data: pull } = yield this.octokit.rest.pulls.create(Object.assign(Object.assign({}, this.parseRepository(baseRepository)), { title: inputs.title, head: headBranch, base: inputs.base, body: inputs.body, draft: inputs.draft }));
|
const { data: pull } = yield this.octokit.rest.pulls.create(Object.assign(Object.assign({}, this.parseRepository(baseRepository)), { title: inputs.title, head: headBranch, head_repo: headRepository, base: inputs.base, body: inputs.body, draft: inputs.draft }));
|
||||||
core.info(`Created pull request #${pull.number} (${headBranch} => ${inputs.base})`);
|
core.info(`Created pull request #${pull.number} (${headBranch} => ${inputs.base})`);
|
||||||
return {
|
return {
|
||||||
number: pull.number,
|
number: pull.number,
|
||||||
@ -1099,7 +1146,7 @@ class GitHubHelper {
|
|||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
const { data: headRepo } = yield this.octokit.rest.repos.get(Object.assign({}, this.parseRepository(headRepository)));
|
const { data: headRepo } = yield this.octokit.rest.repos.get(Object.assign({}, this.parseRepository(headRepository)));
|
||||||
if (!headRepo.parent) {
|
if (!headRepo.parent) {
|
||||||
throw new Error(`Repository '${headRepository}' is not a fork. Unable to continue.`);
|
return null;
|
||||||
}
|
}
|
||||||
return headRepo.parent.full_name;
|
return headRepo.parent.full_name;
|
||||||
});
|
});
|
||||||
@ -1201,6 +1248,7 @@ function run() {
|
|||||||
try {
|
try {
|
||||||
const inputs = {
|
const inputs = {
|
||||||
token: core.getInput('token'),
|
token: core.getInput('token'),
|
||||||
|
gitToken: core.getInput('git-token'),
|
||||||
path: core.getInput('path'),
|
path: core.getInput('path'),
|
||||||
addPaths: utils.getInputAsArray('add-paths'),
|
addPaths: utils.getInputAsArray('add-paths'),
|
||||||
commitMessage: core.getInput('commit-message'),
|
commitMessage: core.getInput('commit-message'),
|
||||||
@ -1223,6 +1271,24 @@ function run() {
|
|||||||
draft: core.getBooleanInput('draft')
|
draft: core.getBooleanInput('draft')
|
||||||
};
|
};
|
||||||
core.debug(`Inputs: ${(0, util_1.inspect)(inputs)}`);
|
core.debug(`Inputs: ${(0, util_1.inspect)(inputs)}`);
|
||||||
|
if (!inputs.token) {
|
||||||
|
throw new Error(`Input 'token' not supplied. Unable to continue.`);
|
||||||
|
}
|
||||||
|
if (!inputs.gitToken) {
|
||||||
|
inputs.gitToken = inputs.token;
|
||||||
|
}
|
||||||
|
if (inputs.bodyPath) {
|
||||||
|
if (!utils.fileExistsSync(inputs.bodyPath)) {
|
||||||
|
throw new Error(`File '${inputs.bodyPath}' does not exist.`);
|
||||||
|
}
|
||||||
|
// Update the body input with the contents of the file
|
||||||
|
inputs.body = utils.readFile(inputs.bodyPath);
|
||||||
|
}
|
||||||
|
// 65536 characters is the maximum allowed for the pull request body.
|
||||||
|
if (inputs.body.length > 65536) {
|
||||||
|
core.warning(`Pull request body is too long. Truncating to 65536 characters.`);
|
||||||
|
inputs.body = inputs.body.substring(0, 65536);
|
||||||
|
}
|
||||||
yield (0, create_pull_request_1.createPullRequest)(inputs);
|
yield (0, create_pull_request_1.createPullRequest)(inputs);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
@ -1290,7 +1356,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||||
exports.getErrorMessage = exports.readFile = exports.fileExistsSync = exports.parseDisplayNameEmail = exports.randomString = exports.secondsSinceEpoch = exports.getRemoteUrl = exports.getRemoteDetail = exports.getRepoPath = exports.stripOrgPrefixFromTeams = exports.getStringAsArray = exports.getInputAsArray = void 0;
|
exports.getErrorMessage = exports.readFile = exports.fileExistsSync = exports.parseDisplayNameEmail = exports.randomString = exports.secondsSinceEpoch = exports.getRemoteUrl = exports.getRepoPath = exports.stripOrgPrefixFromTeams = exports.getStringAsArray = exports.getInputAsArray = void 0;
|
||||||
const core = __importStar(__nccwpck_require__(2186));
|
const core = __importStar(__nccwpck_require__(2186));
|
||||||
const fs = __importStar(__nccwpck_require__(7147));
|
const fs = __importStar(__nccwpck_require__(7147));
|
||||||
const path = __importStar(__nccwpck_require__(1017));
|
const path = __importStar(__nccwpck_require__(1017));
|
||||||
@ -1329,36 +1395,6 @@ function getRepoPath(relativePath) {
|
|||||||
return repoPath;
|
return repoPath;
|
||||||
}
|
}
|
||||||
exports.getRepoPath = getRepoPath;
|
exports.getRepoPath = getRepoPath;
|
||||||
function getRemoteDetail(remoteUrl) {
|
|
||||||
// Parse the protocol and github repository from a URL
|
|
||||||
// e.g. HTTPS, peter-evans/create-pull-request
|
|
||||||
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 hostname = githubServerMatch[1];
|
|
||||||
const httpsUrlPattern = new RegExp('^https?://.*@?' + hostname + '/(.+/.+?)(\\.git)?$', 'i');
|
|
||||||
const sshUrlPattern = new RegExp('^git@' + hostname + ':(.+/.+)\\.git$', 'i');
|
|
||||||
const httpsMatch = remoteUrl.match(httpsUrlPattern);
|
|
||||||
if (httpsMatch) {
|
|
||||||
return {
|
|
||||||
hostname,
|
|
||||||
protocol: 'HTTPS',
|
|
||||||
repository: httpsMatch[1]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const sshMatch = remoteUrl.match(sshUrlPattern);
|
|
||||||
if (sshMatch) {
|
|
||||||
return {
|
|
||||||
hostname,
|
|
||||||
protocol: 'SSH',
|
|
||||||
repository: sshMatch[1]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
throw new Error(`The format of '${remoteUrl}' is not a valid GitHub repository URL`);
|
|
||||||
}
|
|
||||||
exports.getRemoteDetail = getRemoteDetail;
|
|
||||||
function getRemoteUrl(protocol, hostname, repository) {
|
function getRemoteUrl(protocol, hostname, repository) {
|
||||||
return protocol == 'HTTPS'
|
return protocol == 'HTTPS'
|
||||||
? `https://${hostname}/${repository}`
|
? `https://${hostname}/${repository}`
|
||||||
@ -1990,7 +2026,7 @@ class OidcClient {
|
|||||||
.catch(error => {
|
.catch(error => {
|
||||||
throw new Error(`Failed to get ID Token. \n
|
throw new Error(`Failed to get ID Token. \n
|
||||||
Error Code : ${error.statusCode}\n
|
Error Code : ${error.statusCode}\n
|
||||||
Error Message: ${error.result.message}`);
|
Error Message: ${error.message}`);
|
||||||
});
|
});
|
||||||
const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value;
|
const id_token = (_a = res.result) === null || _a === void 0 ? void 0 : _a.value;
|
||||||
if (!id_token) {
|
if (!id_token) {
|
||||||
@ -5171,122 +5207,64 @@ exports.createTokenAuth = createTokenAuth;
|
|||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 6762:
|
/***/ 6762:
|
||||||
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var __defProp = Object.defineProperty;
|
||||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||||
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||||
var universalUserAgent = __nccwpck_require__(5030);
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||||
var beforeAfterHook = __nccwpck_require__(3682);
|
var __export = (target, all) => {
|
||||||
var request = __nccwpck_require__(6234);
|
for (var name in all)
|
||||||
var graphql = __nccwpck_require__(8467);
|
__defProp(target, name, { get: all[name], enumerable: true });
|
||||||
var authToken = __nccwpck_require__(334);
|
};
|
||||||
|
var __copyProps = (to, from, except, desc) => {
|
||||||
const VERSION = "4.2.0";
|
if (from && typeof from === "object" || typeof from === "function") {
|
||||||
|
for (let key of __getOwnPropNames(from))
|
||||||
class Octokit {
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||||
constructor(options = {}) {
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||||
const hook = new beforeAfterHook.Collection();
|
|
||||||
const requestDefaults = {
|
|
||||||
baseUrl: request.request.endpoint.DEFAULTS.baseUrl,
|
|
||||||
headers: {},
|
|
||||||
request: Object.assign({}, options.request, {
|
|
||||||
// @ts-ignore internal usage only, no need to type
|
|
||||||
hook: hook.bind(null, "request")
|
|
||||||
}),
|
|
||||||
mediaType: {
|
|
||||||
previews: [],
|
|
||||||
format: ""
|
|
||||||
}
|
}
|
||||||
}; // prepend default user agent with `options.userAgent` if set
|
return to;
|
||||||
|
};
|
||||||
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||||
|
|
||||||
requestDefaults.headers["user-agent"] = [options.userAgent, `octokit-core.js/${VERSION} ${universalUserAgent.getUserAgent()}`].filter(Boolean).join(" ");
|
// pkg/dist-src/index.js
|
||||||
|
var dist_src_exports = {};
|
||||||
|
__export(dist_src_exports, {
|
||||||
|
Octokit: () => Octokit
|
||||||
|
});
|
||||||
|
module.exports = __toCommonJS(dist_src_exports);
|
||||||
|
var import_universal_user_agent = __nccwpck_require__(5030);
|
||||||
|
var import_before_after_hook = __nccwpck_require__(3682);
|
||||||
|
var import_request = __nccwpck_require__(6234);
|
||||||
|
var import_graphql = __nccwpck_require__(8467);
|
||||||
|
var import_auth_token = __nccwpck_require__(334);
|
||||||
|
|
||||||
if (options.baseUrl) {
|
// pkg/dist-src/version.js
|
||||||
requestDefaults.baseUrl = options.baseUrl;
|
var VERSION = "4.2.4";
|
||||||
}
|
|
||||||
|
|
||||||
if (options.previews) {
|
|
||||||
requestDefaults.mediaType.previews = options.previews;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.timeZone) {
|
|
||||||
requestDefaults.headers["time-zone"] = options.timeZone;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.request = request.request.defaults(requestDefaults);
|
|
||||||
this.graphql = graphql.withCustomRequest(this.request).defaults(requestDefaults);
|
|
||||||
this.log = Object.assign({
|
|
||||||
debug: () => {},
|
|
||||||
info: () => {},
|
|
||||||
warn: console.warn.bind(console),
|
|
||||||
error: console.error.bind(console)
|
|
||||||
}, options.log);
|
|
||||||
this.hook = hook; // (1) If neither `options.authStrategy` nor `options.auth` are set, the `octokit` instance
|
|
||||||
// is unauthenticated. The `this.auth()` method is a no-op and no request hook is registered.
|
|
||||||
// (2) If only `options.auth` is set, use the default token authentication strategy.
|
|
||||||
// (3) If `options.authStrategy` is set then use it and pass in `options.auth`. Always pass own request as many strategies accept a custom request instance.
|
|
||||||
// TODO: type `options.auth` based on `options.authStrategy`.
|
|
||||||
|
|
||||||
if (!options.authStrategy) {
|
|
||||||
if (!options.auth) {
|
|
||||||
// (1)
|
|
||||||
this.auth = async () => ({
|
|
||||||
type: "unauthenticated"
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// (2)
|
|
||||||
const auth = authToken.createTokenAuth(options.auth); // @ts-ignore ¯\_(ツ)_/¯
|
|
||||||
|
|
||||||
hook.wrap("request", auth.hook);
|
|
||||||
this.auth = auth;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const {
|
|
||||||
authStrategy,
|
|
||||||
...otherOptions
|
|
||||||
} = options;
|
|
||||||
const auth = authStrategy(Object.assign({
|
|
||||||
request: this.request,
|
|
||||||
log: this.log,
|
|
||||||
// we pass the current octokit instance as well as its constructor options
|
|
||||||
// to allow for authentication strategies that return a new octokit instance
|
|
||||||
// that shares the same internal state as the current one. The original
|
|
||||||
// requirement for this was the "event-octokit" authentication strategy
|
|
||||||
// of https://github.com/probot/octokit-auth-probot.
|
|
||||||
octokit: this,
|
|
||||||
octokitOptions: otherOptions
|
|
||||||
}, options.auth)); // @ts-ignore ¯\_(ツ)_/¯
|
|
||||||
|
|
||||||
hook.wrap("request", auth.hook);
|
|
||||||
this.auth = auth;
|
|
||||||
} // apply plugins
|
|
||||||
// https://stackoverflow.com/a/16345172
|
|
||||||
|
|
||||||
|
|
||||||
const classConstructor = this.constructor;
|
|
||||||
classConstructor.plugins.forEach(plugin => {
|
|
||||||
Object.assign(this, plugin(this, options));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// pkg/dist-src/index.js
|
||||||
|
var Octokit = class {
|
||||||
static defaults(defaults) {
|
static defaults(defaults) {
|
||||||
const OctokitWithDefaults = class extends this {
|
const OctokitWithDefaults = class extends this {
|
||||||
constructor(...args) {
|
constructor(...args) {
|
||||||
const options = args[0] || {};
|
const options = args[0] || {};
|
||||||
|
|
||||||
if (typeof defaults === "function") {
|
if (typeof defaults === "function") {
|
||||||
super(defaults(options));
|
super(defaults(options));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
super(
|
||||||
super(Object.assign({}, defaults, options, options.userAgent && defaults.userAgent ? {
|
Object.assign(
|
||||||
|
{},
|
||||||
|
defaults,
|
||||||
|
options,
|
||||||
|
options.userAgent && defaults.userAgent ? {
|
||||||
userAgent: `${options.userAgent} ${defaults.userAgent}`
|
userAgent: `${options.userAgent} ${defaults.userAgent}`
|
||||||
} : null));
|
} : null
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
return OctokitWithDefaults;
|
return OctokitWithDefaults;
|
||||||
}
|
}
|
||||||
@ -5296,22 +5274,97 @@ class Octokit {
|
|||||||
* @example
|
* @example
|
||||||
* const API = Octokit.plugin(plugin1, plugin2, plugin3, ...)
|
* const API = Octokit.plugin(plugin1, plugin2, plugin3, ...)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
static plugin(...newPlugins) {
|
static plugin(...newPlugins) {
|
||||||
var _a;
|
var _a;
|
||||||
|
|
||||||
const currentPlugins = this.plugins;
|
const currentPlugins = this.plugins;
|
||||||
const NewOctokit = (_a = class extends this {}, _a.plugins = currentPlugins.concat(newPlugins.filter(plugin => !currentPlugins.includes(plugin))), _a);
|
const NewOctokit = (_a = class extends this {
|
||||||
|
}, _a.plugins = currentPlugins.concat(
|
||||||
|
newPlugins.filter((plugin) => !currentPlugins.includes(plugin))
|
||||||
|
), _a);
|
||||||
return NewOctokit;
|
return NewOctokit;
|
||||||
}
|
}
|
||||||
|
constructor(options = {}) {
|
||||||
}
|
const hook = new import_before_after_hook.Collection();
|
||||||
|
const requestDefaults = {
|
||||||
|
baseUrl: import_request.request.endpoint.DEFAULTS.baseUrl,
|
||||||
|
headers: {},
|
||||||
|
request: Object.assign({}, options.request, {
|
||||||
|
// @ts-ignore internal usage only, no need to type
|
||||||
|
hook: hook.bind(null, "request")
|
||||||
|
}),
|
||||||
|
mediaType: {
|
||||||
|
previews: [],
|
||||||
|
format: ""
|
||||||
|
}
|
||||||
|
};
|
||||||
|
requestDefaults.headers["user-agent"] = [
|
||||||
|
options.userAgent,
|
||||||
|
`octokit-core.js/${VERSION} ${(0, import_universal_user_agent.getUserAgent)()}`
|
||||||
|
].filter(Boolean).join(" ");
|
||||||
|
if (options.baseUrl) {
|
||||||
|
requestDefaults.baseUrl = options.baseUrl;
|
||||||
|
}
|
||||||
|
if (options.previews) {
|
||||||
|
requestDefaults.mediaType.previews = options.previews;
|
||||||
|
}
|
||||||
|
if (options.timeZone) {
|
||||||
|
requestDefaults.headers["time-zone"] = options.timeZone;
|
||||||
|
}
|
||||||
|
this.request = import_request.request.defaults(requestDefaults);
|
||||||
|
this.graphql = (0, import_graphql.withCustomRequest)(this.request).defaults(requestDefaults);
|
||||||
|
this.log = Object.assign(
|
||||||
|
{
|
||||||
|
debug: () => {
|
||||||
|
},
|
||||||
|
info: () => {
|
||||||
|
},
|
||||||
|
warn: console.warn.bind(console),
|
||||||
|
error: console.error.bind(console)
|
||||||
|
},
|
||||||
|
options.log
|
||||||
|
);
|
||||||
|
this.hook = hook;
|
||||||
|
if (!options.authStrategy) {
|
||||||
|
if (!options.auth) {
|
||||||
|
this.auth = async () => ({
|
||||||
|
type: "unauthenticated"
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const auth = (0, import_auth_token.createTokenAuth)(options.auth);
|
||||||
|
hook.wrap("request", auth.hook);
|
||||||
|
this.auth = auth;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const { authStrategy, ...otherOptions } = options;
|
||||||
|
const auth = authStrategy(
|
||||||
|
Object.assign(
|
||||||
|
{
|
||||||
|
request: this.request,
|
||||||
|
log: this.log,
|
||||||
|
// we pass the current octokit instance as well as its constructor options
|
||||||
|
// to allow for authentication strategies that return a new octokit instance
|
||||||
|
// that shares the same internal state as the current one. The original
|
||||||
|
// requirement for this was the "event-octokit" authentication strategy
|
||||||
|
// of https://github.com/probot/octokit-auth-probot.
|
||||||
|
octokit: this,
|
||||||
|
octokitOptions: otherOptions
|
||||||
|
},
|
||||||
|
options.auth
|
||||||
|
)
|
||||||
|
);
|
||||||
|
hook.wrap("request", auth.hook);
|
||||||
|
this.auth = auth;
|
||||||
|
}
|
||||||
|
const classConstructor = this.constructor;
|
||||||
|
classConstructor.plugins.forEach((plugin) => {
|
||||||
|
Object.assign(this, plugin(this, options));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
Octokit.VERSION = VERSION;
|
Octokit.VERSION = VERSION;
|
||||||
Octokit.plugins = [];
|
Octokit.plugins = [];
|
||||||
|
// Annotate the CommonJS export names for ESM import in node:
|
||||||
exports.Octokit = Octokit;
|
0 && (0);
|
||||||
//# sourceMappingURL=index.js.map
|
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
@ -13917,7 +13970,7 @@ for (let i = 0; i < 256; ++i) {
|
|||||||
function unsafeStringify(arr, offset = 0) {
|
function unsafeStringify(arr, offset = 0) {
|
||||||
// Note: Be careful editing this code! It's been tuned for performance
|
// Note: Be careful editing this code! It's been tuned for performance
|
||||||
// and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
|
// and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
|
||||||
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
|
return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
|
||||||
}
|
}
|
||||||
|
|
||||||
function stringify(arr, offset = 0) {
|
function stringify(arr, offset = 0) {
|
||||||
|
48
docs/common-issues.md
Normal file
48
docs/common-issues.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# Common issues
|
||||||
|
|
||||||
|
- [Troubleshooting](#troubleshooting)
|
||||||
|
- [Create using an existing branch as the PR branch](#create-using-an-existing-branch-as-the-pr-branch)
|
||||||
|
- [Frequently requested features](#use-case-create-a-pull-request-to-update-x-on-release)
|
||||||
|
- [Disable force updates to existing PR branches](#disable-force-updates-to-existing-pr-branches)
|
||||||
|
- [Add a no-verify option to bypass git hooks](#add-a-no-verify-option-to-bypass-git-hooks)
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Create using an existing branch as the PR branch
|
||||||
|
|
||||||
|
A common point of confusion is to try and use an existing branch containing changes to raise in a PR as the `branch` input. This will not work because the action is primarily designed to be used in workflows where the PR branch does not exist yet. The action creates and manages the PR branch itself.
|
||||||
|
|
||||||
|
If you have an existing branch that you just want to create a PR for, then I recommend using the official [GitHub CLI](https://cli.github.com/manual/gh_pr_create) in a workflow step.
|
||||||
|
|
||||||
|
Alternatively, if you are trying to keep a branch up to date with another branch, then you can follow [this example](https://github.com/peter-evans/create-pull-request/blob/main/docs/examples.md#keep-a-branch-up-to-date-with-another).
|
||||||
|
|
||||||
|
## Frequently requested features
|
||||||
|
|
||||||
|
### Disable force updates to existing PR branches
|
||||||
|
|
||||||
|
This behaviour is fundamental to how the action works and is a conscious design decision. The "rule" that I based this design on is that when a workflow executes the action to create or update a PR, the result of those two possible actions should never be different. The easiest way to maintain that consistency is to rebase the PR branch and force push it.
|
||||||
|
|
||||||
|
If you want to avoid this behaviour there are some things that might work depending on your use case:
|
||||||
|
- Check if the pull request branch exists in a separate step before the action runs and act accordingly.
|
||||||
|
- Use the [alternative strategy](https://github.com/peter-evans/create-pull-request#alternative-strategy---always-create-a-new-pull-request-branch) of always creating a new PR that won't be updated by the action.
|
||||||
|
- [Create your own commits](https://github.com/peter-evans/create-pull-request#create-your-own-commits) each time the action is created/updated.
|
||||||
|
|
||||||
|
### Add a no-verify option to bypass git hooks
|
||||||
|
|
||||||
|
Presently, there is no plan to add this feature to the action.
|
||||||
|
The reason is that I'm trying very hard to keep the interface for this action to a minimum to prevent it becoming bloated and complicated.
|
||||||
|
|
||||||
|
Git hooks must be installed after a repository is checked out in order for them to work.
|
||||||
|
So the straightforward solution is to just not install them during the workflow where this action is used.
|
||||||
|
|
||||||
|
- If hooks are automatically enabled by a framework, use an option provided by the framework to disable them. For example, for Husky users, they can be disabled with the `--ignore-scripts` flag.
|
||||||
|
- If hooks are installed in a script, then add a condition checking if the `CI` environment variable exists.
|
||||||
|
```sh
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
[ -n "$CI" ] && exit 0
|
||||||
|
```
|
||||||
|
- If preventing the hooks installing is problematic, just delete them in a workflow step before the action runs.
|
||||||
|
```yml
|
||||||
|
- run: rm .git/hooks -rf
|
||||||
|
```
|
@ -36,7 +36,7 @@ For each [event type](https://docs.github.com/en/actions/reference/events-that-t
|
|||||||
The default can be overridden by specifying a `ref` on checkout.
|
The default can be overridden by specifying a `ref` on checkout.
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: develop
|
ref: develop
|
||||||
```
|
```
|
||||||
@ -73,7 +73,7 @@ jobs:
|
|||||||
example:
|
example:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
||||||
@ -173,7 +173,7 @@ This action uses [ncc](https://github.com/vercel/ncc) to compile the Node.js cod
|
|||||||
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.
|
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
|
```yml
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.PAT }}
|
token: ${{ secrets.PAT }}
|
||||||
repository: owner/repo
|
repository: owner/repo
|
||||||
@ -200,7 +200,7 @@ How to use SSH (deploy keys) with create-pull-request action:
|
|||||||
|
|
||||||
```yml
|
```yml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
|
||||||
@ -226,7 +226,7 @@ Note that if you choose to use this method (not give the machine account `write`
|
|||||||
6. As shown in the following example workflow, set the `push-to-fork` input to the full repository name of the fork.
|
6. As shown in the following example workflow, set the `push-to-fork` input to the full repository name of the fork.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
# Make changes to pull request here
|
# Make changes to pull request here
|
||||||
|
|
||||||
@ -236,6 +236,8 @@ Note that if you choose to use this method (not give the machine account `write`
|
|||||||
push-to-fork: machine-user/fork-of-repository
|
push-to-fork: machine-user/fork-of-repository
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note: You can also combine `push-to-fork` with [creating pull requests in a remote repository](#creating-pull-requests-in-a-remote-repository).
|
||||||
|
|
||||||
### Authenticating with GitHub App generated tokens
|
### Authenticating with GitHub App generated tokens
|
||||||
|
|
||||||
A GitHub App can be created for the sole purpose of generating tokens for use with GitHub actions.
|
A GitHub App can be created for the sole purpose of generating tokens for use with GitHub actions.
|
||||||
@ -262,7 +264,7 @@ GitHub App generated tokens are more secure than using a PAT because GitHub App
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: tibdex/github-app-token@v1
|
- uses: tibdex/github-app-token@v1
|
||||||
id: generate-token
|
id: generate-token
|
||||||
@ -302,14 +304,14 @@ The action can use GPG to sign commits with a GPG key that you generate yourself
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: crazy-max/ghaction-import-gpg@v3
|
- uses: crazy-max/ghaction-import-gpg@v5
|
||||||
with:
|
with:
|
||||||
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
|
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
passphrase: ${{ secrets.GPG_PASSPHRASE }}
|
passphrase: ${{ secrets.GPG_PASSPHRASE }}
|
||||||
git-user-signingkey: true
|
git_user_signingkey: true
|
||||||
git-commit-gpgsign: true
|
git_commit_gpgsign: true
|
||||||
|
|
||||||
# Make changes to pull request here
|
# Make changes to pull request here
|
||||||
|
|
||||||
@ -339,7 +341,7 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: apk --no-cache add git
|
run: apk --no-cache add git
|
||||||
|
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
# Make changes to pull request here
|
# Make changes to pull request here
|
||||||
|
|
||||||
@ -362,7 +364,7 @@ jobs:
|
|||||||
add-apt-repository -y ppa:git-core/ppa
|
add-apt-repository -y ppa:git-core/ppa
|
||||||
apt-get install -y git
|
apt-get install -y git
|
||||||
|
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
# Make changes to pull request here
|
# Make changes to pull request here
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ jobs:
|
|||||||
updateAuthors:
|
updateAuthors:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Update AUTHORS
|
- name: Update AUTHORS
|
||||||
@ -74,7 +74,7 @@ jobs:
|
|||||||
productionPromotion:
|
productionPromotion:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: production
|
ref: production
|
||||||
- name: Reset promotion branch
|
- name: Reset promotion branch
|
||||||
@ -107,7 +107,7 @@ jobs:
|
|||||||
updateChangelog:
|
updateChangelog:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Update Changelog
|
- name: Update Changelog
|
||||||
@ -145,7 +145,7 @@ jobs:
|
|||||||
update-dep:
|
update-dep:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '16.x'
|
node-version: '16.x'
|
||||||
@ -181,7 +181,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 16.x
|
node-version: 16.x
|
||||||
@ -205,7 +205,7 @@ jobs:
|
|||||||
update-dep:
|
update-dep:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
@ -243,7 +243,7 @@ jobs:
|
|||||||
update-dep:
|
update-dep:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Update dependencies
|
- name: Update dependencies
|
||||||
run: |
|
run: |
|
||||||
cargo install cargo-edit
|
cargo install cargo-edit
|
||||||
@ -278,7 +278,7 @@ jobs:
|
|||||||
updateSwagger:
|
updateSwagger:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Get Latest Swagger UI Release
|
- name: Get Latest Swagger UI Release
|
||||||
id: swagger-ui
|
id: swagger-ui
|
||||||
run: |
|
run: |
|
||||||
@ -343,7 +343,7 @@ jobs:
|
|||||||
updateFork:
|
updateFork:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: fork-owner/repo
|
repository: fork-owner/repo
|
||||||
- name: Reset the default branch with upstream changes
|
- name: Reset the default branch with upstream changes
|
||||||
@ -371,7 +371,7 @@ jobs:
|
|||||||
format:
|
format:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- name: Download website
|
- name: Download website
|
||||||
run: |
|
run: |
|
||||||
wget \
|
wget \
|
||||||
@ -467,7 +467,7 @@ jobs:
|
|||||||
if: startsWith(github.head_ref, 'autopep8-patches') == false && github.event.pull_request.head.repo.full_name == github.repository
|
if: startsWith(github.head_ref, 'autopep8-patches') == false && github.event.pull_request.head.repo.full_name == github.repository
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.head_ref }}
|
ref: ${{ github.head_ref }}
|
||||||
- name: autopep8
|
- name: autopep8
|
||||||
@ -516,13 +516,13 @@ jobs:
|
|||||||
if: startsWith(github.ref, 'refs/heads/')
|
if: startsWith(github.ref, 'refs/heads/')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
...
|
...
|
||||||
|
|
||||||
someOtherJob:
|
someOtherJob:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
2543
package-lock.json
generated
2543
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
35
package.json
35
package.json
@ -29,31 +29,32 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/peter-evans/create-pull-request",
|
"homepage": "https://github.com/peter-evans/create-pull-request",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^1.10.1",
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^1.1.1",
|
||||||
"@octokit/core": "^4.2.0",
|
"@octokit/core": "^4.2.4",
|
||||||
"@octokit/plugin-paginate-rest": "^5.0.1",
|
"@octokit/plugin-paginate-rest": "^5.0.1",
|
||||||
"@octokit/plugin-rest-endpoint-methods": "^6.8.1",
|
"@octokit/plugin-rest-endpoint-methods": "^6.8.1",
|
||||||
"https-proxy-agent": "^5.0.1",
|
"https-proxy-agent": "^5.0.1",
|
||||||
"proxy-from-env": "^1.1.0",
|
"proxy-from-env": "^1.1.0",
|
||||||
"uuid": "^9.0.0"
|
"uuid": "^9.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.5.0",
|
"@types/jest": "^29.5.11",
|
||||||
"@types/node": "^18.15.11",
|
"@types/node": "^18.19.3",
|
||||||
"@typescript-eslint/parser": "^5.57.1",
|
"@typescript-eslint/parser": "^5.62.0",
|
||||||
"@vercel/ncc": "^0.36.1",
|
"@vercel/ncc": "^0.38.1",
|
||||||
"eslint": "^8.37.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-import-resolver-typescript": "^3.5.4",
|
"eslint-import-resolver-typescript": "^3.6.1",
|
||||||
"eslint-plugin-github": "^4.7.0",
|
"eslint-plugin-github": "^4.10.1",
|
||||||
"eslint-plugin-import": "^2.27.5",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"eslint-plugin-jest": "^27.2.1",
|
"eslint-plugin-jest": "^27.6.0",
|
||||||
"jest": "^29.5.0",
|
"eslint-plugin-prettier": "^5.1.2",
|
||||||
"jest-circus": "^29.4.2",
|
"jest": "^29.7.0",
|
||||||
"jest-environment-jsdom": "^29.5.0",
|
"jest-circus": "^29.7.0",
|
||||||
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"prettier": "^2.8.7",
|
"prettier": "^3.1.1",
|
||||||
"ts-jest": "^29.1.0",
|
"ts-jest": "^29.1.1",
|
||||||
"typescript": "^4.9.5"
|
"typescript": "^4.9.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,9 +180,12 @@ export async function createOrUpdateBranch(
|
|||||||
if (branchRemoteName == 'fork') {
|
if (branchRemoteName == 'fork') {
|
||||||
// If pushing to a fork we must fetch with 'unshallow' to avoid the following error on git push
|
// 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)
|
// ! [remote rejected] HEAD -> tests/push-branch-to-fork (shallow update not allowed)
|
||||||
await git.fetch([`${workingBase}:${workingBase}`], baseRemote, [
|
await git.fetch(
|
||||||
'--force'
|
[`${workingBase}:${workingBase}`],
|
||||||
])
|
baseRemote,
|
||||||
|
['--force'],
|
||||||
|
true
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
// If the remote is 'origin' we can git reset
|
// If the remote is 'origin' we can git reset
|
||||||
await git.checkout(workingBase)
|
await git.checkout(workingBase)
|
||||||
|
@ -6,11 +6,12 @@ import {
|
|||||||
} from './create-or-update-branch'
|
} from './create-or-update-branch'
|
||||||
import {GitHubHelper} from './github-helper'
|
import {GitHubHelper} from './github-helper'
|
||||||
import {GitCommandManager} from './git-command-manager'
|
import {GitCommandManager} from './git-command-manager'
|
||||||
import {GitAuthHelper} from './git-auth-helper'
|
import {GitConfigHelper} from './git-config-helper'
|
||||||
import * as utils from './utils'
|
import * as utils from './utils'
|
||||||
|
|
||||||
export interface Inputs {
|
export interface Inputs {
|
||||||
token: string
|
token: string
|
||||||
|
gitToken: string
|
||||||
path: string
|
path: string
|
||||||
addPaths: string[]
|
addPaths: string[]
|
||||||
commitMessage: string
|
commitMessage: string
|
||||||
@ -34,38 +35,18 @@ export interface Inputs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function createPullRequest(inputs: Inputs): Promise<void> {
|
export async function createPullRequest(inputs: Inputs): Promise<void> {
|
||||||
let gitAuthHelper
|
let gitConfigHelper, git
|
||||||
try {
|
try {
|
||||||
if (!inputs.token) {
|
|
||||||
throw new Error(`Input 'token' not supplied. Unable to continue.`)
|
|
||||||
}
|
|
||||||
if (inputs.bodyPath) {
|
|
||||||
if (!utils.fileExistsSync(inputs.bodyPath)) {
|
|
||||||
throw new Error(`File '${inputs.bodyPath}' does not exist.`)
|
|
||||||
}
|
|
||||||
// Update the body input with the contents of the file
|
|
||||||
inputs.body = utils.readFile(inputs.bodyPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the repository path
|
|
||||||
const repoPath = utils.getRepoPath(inputs.path)
|
|
||||||
// Create a git command manager
|
|
||||||
const git = await GitCommandManager.create(repoPath)
|
|
||||||
|
|
||||||
// Save and unset the extraheader auth config if it exists
|
|
||||||
core.startGroup('Prepare git configuration')
|
core.startGroup('Prepare git configuration')
|
||||||
gitAuthHelper = new GitAuthHelper(git)
|
const repoPath = utils.getRepoPath(inputs.path)
|
||||||
await gitAuthHelper.addSafeDirectory()
|
git = await GitCommandManager.create(repoPath)
|
||||||
await gitAuthHelper.savePersistedAuth()
|
gitConfigHelper = await GitConfigHelper.create(git)
|
||||||
core.endGroup()
|
core.endGroup()
|
||||||
|
|
||||||
// Init the GitHub client
|
|
||||||
const githubHelper = new GitHubHelper(inputs.token)
|
|
||||||
|
|
||||||
core.startGroup('Determining the base and head repositories')
|
core.startGroup('Determining the base and head repositories')
|
||||||
// Determine the base repository from git config
|
const baseRemote = gitConfigHelper.getGitRemote()
|
||||||
const remoteUrl = await git.tryGetRemoteUrl()
|
// Init the GitHub client
|
||||||
const baseRemote = utils.getRemoteDetail(remoteUrl)
|
const githubHelper = new GitHubHelper(baseRemote.hostname, inputs.token)
|
||||||
// Determine the head repository; the target for the pull request branch
|
// Determine the head repository; the target for the pull request branch
|
||||||
const branchRemoteName = inputs.pushToFork ? 'fork' : 'origin'
|
const branchRemoteName = inputs.pushToFork ? 'fork' : 'origin'
|
||||||
const branchRepository = inputs.pushToFork
|
const branchRepository = inputs.pushToFork
|
||||||
@ -76,12 +57,22 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
|
|||||||
core.info(
|
core.info(
|
||||||
`Checking if '${branchRepository}' is a fork of '${baseRemote.repository}'`
|
`Checking if '${branchRepository}' is a fork of '${baseRemote.repository}'`
|
||||||
)
|
)
|
||||||
const parentRepository = await githubHelper.getRepositoryParent(
|
const baseParentRepository = await githubHelper.getRepositoryParent(
|
||||||
branchRepository
|
baseRemote.repository
|
||||||
)
|
)
|
||||||
if (parentRepository != baseRemote.repository) {
|
const branchParentRepository =
|
||||||
|
await githubHelper.getRepositoryParent(branchRepository)
|
||||||
|
if (branchParentRepository == null) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Repository '${branchRepository}' is not a fork of '${baseRemote.repository}'. Unable to continue.`
|
`Repository '${branchRepository}' is not a fork. Unable to continue.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
branchParentRepository != baseRemote.repository &&
|
||||||
|
baseParentRepository != branchParentRepository
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
`Repository '${branchRepository}' is not a fork of '${baseRemote.repository}', nor are they siblings. Unable to continue.`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Add a remote for the fork
|
// Add a remote for the fork
|
||||||
@ -100,7 +91,7 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
|
|||||||
// Configure auth
|
// Configure auth
|
||||||
if (baseRemote.protocol == 'HTTPS') {
|
if (baseRemote.protocol == 'HTTPS') {
|
||||||
core.startGroup('Configuring credential for HTTPS authentication')
|
core.startGroup('Configuring credential for HTTPS authentication')
|
||||||
await gitAuthHelper.configureToken(inputs.token)
|
await gitConfigHelper.configureToken(inputs.gitToken)
|
||||||
core.endGroup()
|
core.endGroup()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,11 +251,11 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(utils.getErrorMessage(error))
|
core.setFailed(utils.getErrorMessage(error))
|
||||||
} finally {
|
} finally {
|
||||||
// Remove auth and restore persisted auth config if it existed
|
|
||||||
core.startGroup('Restore git configuration')
|
core.startGroup('Restore git configuration')
|
||||||
await gitAuthHelper.removeAuth()
|
if (inputs.pushToFork) {
|
||||||
await gitAuthHelper.restorePersistedAuth()
|
await git.exec(['remote', 'rm', 'fork'])
|
||||||
await gitAuthHelper.removeSafeDirectory()
|
}
|
||||||
|
await gitConfigHelper.close()
|
||||||
core.endGroup()
|
core.endGroup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,8 @@ export class GitCommandManager {
|
|||||||
async fetch(
|
async fetch(
|
||||||
refSpec: string[],
|
refSpec: string[],
|
||||||
remoteName?: string,
|
remoteName?: string,
|
||||||
options?: string[]
|
options?: string[],
|
||||||
|
unshallow = false
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const args = ['-c', 'protocol.version=2', 'fetch']
|
const args = ['-c', 'protocol.version=2', 'fetch']
|
||||||
if (!refSpec.some(x => x === tagsRefSpec)) {
|
if (!refSpec.some(x => x === tagsRefSpec)) {
|
||||||
@ -113,7 +114,9 @@ export class GitCommandManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
args.push('--progress', '--no-recurse-submodules')
|
args.push('--progress', '--no-recurse-submodules')
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
unshallow &&
|
||||||
utils.fileExistsSync(path.join(this.workingDirectory, '.git', 'shallow'))
|
utils.fileExistsSync(path.join(this.workingDirectory, '.git', 'shallow'))
|
||||||
) {
|
) {
|
||||||
args.push('--unshallow')
|
args.push('--unshallow')
|
||||||
|
@ -5,22 +5,42 @@ import * as path from 'path'
|
|||||||
import {URL} from 'url'
|
import {URL} from 'url'
|
||||||
import * as utils from './utils'
|
import * as utils from './utils'
|
||||||
|
|
||||||
export class GitAuthHelper {
|
interface GitRemote {
|
||||||
|
hostname: string
|
||||||
|
protocol: string
|
||||||
|
repository: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GitConfigHelper {
|
||||||
private git: GitCommandManager
|
private git: GitCommandManager
|
||||||
private gitConfigPath = ''
|
private gitConfigPath = ''
|
||||||
private workingDirectory: string
|
private workingDirectory: string
|
||||||
private safeDirectoryConfigKey = 'safe.directory'
|
private safeDirectoryConfigKey = 'safe.directory'
|
||||||
private safeDirectoryAdded = false
|
private safeDirectoryAdded = false
|
||||||
private extraheaderConfigKey: string
|
private remoteUrl = ''
|
||||||
|
private extraheaderConfigKey = ''
|
||||||
private extraheaderConfigPlaceholderValue = 'AUTHORIZATION: basic ***'
|
private extraheaderConfigPlaceholderValue = 'AUTHORIZATION: basic ***'
|
||||||
private extraheaderConfigValueRegex = '^AUTHORIZATION:'
|
private extraheaderConfigValueRegex = '^AUTHORIZATION:'
|
||||||
private persistedExtraheaderConfigValue = ''
|
private persistedExtraheaderConfigValue = ''
|
||||||
|
|
||||||
constructor(git: GitCommandManager) {
|
private constructor(git: GitCommandManager) {
|
||||||
this.git = git
|
this.git = git
|
||||||
this.workingDirectory = this.git.getWorkingDirectory()
|
this.workingDirectory = this.git.getWorkingDirectory()
|
||||||
const serverUrl = this.getServerUrl()
|
}
|
||||||
this.extraheaderConfigKey = `http.${serverUrl.origin}/.extraheader`
|
|
||||||
|
static async create(git: GitCommandManager): Promise<GitConfigHelper> {
|
||||||
|
const gitConfigHelper = new GitConfigHelper(git)
|
||||||
|
await gitConfigHelper.addSafeDirectory()
|
||||||
|
await gitConfigHelper.fetchRemoteDetail()
|
||||||
|
await gitConfigHelper.savePersistedAuth()
|
||||||
|
return gitConfigHelper
|
||||||
|
}
|
||||||
|
|
||||||
|
async close(): Promise<void> {
|
||||||
|
// Remove auth and restore persisted auth config if it existed
|
||||||
|
await this.removeAuth()
|
||||||
|
await this.restorePersistedAuth()
|
||||||
|
await this.removeSafeDirectory()
|
||||||
}
|
}
|
||||||
|
|
||||||
async addSafeDirectory(): Promise<void> {
|
async addSafeDirectory(): Promise<void> {
|
||||||
@ -50,7 +70,57 @@ export class GitAuthHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fetchRemoteDetail(): Promise<void> {
|
||||||
|
this.remoteUrl = await this.git.tryGetRemoteUrl()
|
||||||
|
}
|
||||||
|
|
||||||
|
getGitRemote(): GitRemote {
|
||||||
|
return GitConfigHelper.parseGitRemote(this.remoteUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
static parseGitRemote(remoteUrl: string): GitRemote {
|
||||||
|
const httpsUrlPattern = new RegExp(
|
||||||
|
'^(https?)://(?:.+@)?(.+?)/(.+/.+?)(\\.git)?$',
|
||||||
|
'i'
|
||||||
|
)
|
||||||
|
const httpsMatch = remoteUrl.match(httpsUrlPattern)
|
||||||
|
if (httpsMatch) {
|
||||||
|
return {
|
||||||
|
hostname: httpsMatch[2],
|
||||||
|
protocol: 'HTTPS',
|
||||||
|
repository: httpsMatch[3]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const sshUrlPattern = new RegExp('^git@(.+?):(.+/.+)\\.git$', 'i')
|
||||||
|
const sshMatch = remoteUrl.match(sshUrlPattern)
|
||||||
|
if (sshMatch) {
|
||||||
|
return {
|
||||||
|
hostname: sshMatch[1],
|
||||||
|
protocol: 'SSH',
|
||||||
|
repository: sshMatch[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unauthenticated git protocol for integration tests only
|
||||||
|
const gitUrlPattern = new RegExp('^git://(.+?)/(.+/.+)\\.git$', 'i')
|
||||||
|
const gitMatch = remoteUrl.match(gitUrlPattern)
|
||||||
|
if (gitMatch) {
|
||||||
|
return {
|
||||||
|
hostname: gitMatch[1],
|
||||||
|
protocol: 'GIT',
|
||||||
|
repository: gitMatch[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(
|
||||||
|
`The format of '${remoteUrl}' is not a valid GitHub repository URL`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async savePersistedAuth(): Promise<void> {
|
async savePersistedAuth(): Promise<void> {
|
||||||
|
const serverUrl = new URL(`https://${this.getGitRemote().hostname}`)
|
||||||
|
this.extraheaderConfigKey = `http.${serverUrl.origin}/.extraheader`
|
||||||
// Save and unset persisted extraheader credential in git config if it exists
|
// Save and unset persisted extraheader credential in git config if it exists
|
||||||
this.persistedExtraheaderConfigValue = await this.getAndUnset()
|
this.persistedExtraheaderConfigValue = await this.getAndUnset()
|
||||||
}
|
}
|
||||||
@ -144,8 +214,4 @@ export class GitAuthHelper {
|
|||||||
content = content.replace(find, replace)
|
content = content.replace(find, replace)
|
||||||
await fs.promises.writeFile(this.gitConfigPath, content)
|
await fs.promises.writeFile(this.gitConfigPath, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
private getServerUrl(): URL {
|
|
||||||
return new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com')
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -20,12 +20,16 @@ interface Pull {
|
|||||||
export class GitHubHelper {
|
export class GitHubHelper {
|
||||||
private octokit: InstanceType<typeof Octokit>
|
private octokit: InstanceType<typeof Octokit>
|
||||||
|
|
||||||
constructor(token: string) {
|
constructor(githubServerHostname: string, token: string) {
|
||||||
const options: OctokitOptions = {}
|
const options: OctokitOptions = {}
|
||||||
if (token) {
|
if (token) {
|
||||||
options.auth = `${token}`
|
options.auth = `${token}`
|
||||||
}
|
}
|
||||||
options.baseUrl = process.env['GITHUB_API_URL'] || 'https://api.github.com'
|
if (githubServerHostname !== 'github.com') {
|
||||||
|
options.baseUrl = `https://${githubServerHostname}/api/v3`
|
||||||
|
} else {
|
||||||
|
options.baseUrl = 'https://api.github.com'
|
||||||
|
}
|
||||||
this.octokit = new Octokit(options)
|
this.octokit = new Octokit(options)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +57,7 @@ export class GitHubHelper {
|
|||||||
...this.parseRepository(baseRepository),
|
...this.parseRepository(baseRepository),
|
||||||
title: inputs.title,
|
title: inputs.title,
|
||||||
head: headBranch,
|
head: headBranch,
|
||||||
|
head_repo: headRepository,
|
||||||
base: inputs.base,
|
base: inputs.base,
|
||||||
body: inputs.body,
|
body: inputs.body,
|
||||||
draft: inputs.draft
|
draft: inputs.draft
|
||||||
@ -100,14 +105,12 @@ export class GitHubHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRepositoryParent(headRepository: string): Promise<string> {
|
async getRepositoryParent(headRepository: string): Promise<string | null> {
|
||||||
const {data: headRepo} = await this.octokit.rest.repos.get({
|
const {data: headRepo} = await this.octokit.rest.repos.get({
|
||||||
...this.parseRepository(headRepository)
|
...this.parseRepository(headRepository)
|
||||||
})
|
})
|
||||||
if (!headRepo.parent) {
|
if (!headRepo.parent) {
|
||||||
throw new Error(
|
return null
|
||||||
`Repository '${headRepository}' is not a fork. Unable to continue.`
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return headRepo.parent.full_name
|
return headRepo.parent.full_name
|
||||||
}
|
}
|
||||||
|
22
src/main.ts
22
src/main.ts
@ -7,6 +7,7 @@ async function run(): Promise<void> {
|
|||||||
try {
|
try {
|
||||||
const inputs: Inputs = {
|
const inputs: Inputs = {
|
||||||
token: core.getInput('token'),
|
token: core.getInput('token'),
|
||||||
|
gitToken: core.getInput('git-token'),
|
||||||
path: core.getInput('path'),
|
path: core.getInput('path'),
|
||||||
addPaths: utils.getInputAsArray('add-paths'),
|
addPaths: utils.getInputAsArray('add-paths'),
|
||||||
commitMessage: core.getInput('commit-message'),
|
commitMessage: core.getInput('commit-message'),
|
||||||
@ -30,6 +31,27 @@ async function run(): Promise<void> {
|
|||||||
}
|
}
|
||||||
core.debug(`Inputs: ${inspect(inputs)}`)
|
core.debug(`Inputs: ${inspect(inputs)}`)
|
||||||
|
|
||||||
|
if (!inputs.token) {
|
||||||
|
throw new Error(`Input 'token' not supplied. Unable to continue.`)
|
||||||
|
}
|
||||||
|
if (!inputs.gitToken) {
|
||||||
|
inputs.gitToken = inputs.token
|
||||||
|
}
|
||||||
|
if (inputs.bodyPath) {
|
||||||
|
if (!utils.fileExistsSync(inputs.bodyPath)) {
|
||||||
|
throw new Error(`File '${inputs.bodyPath}' does not exist.`)
|
||||||
|
}
|
||||||
|
// Update the body input with the contents of the file
|
||||||
|
inputs.body = utils.readFile(inputs.bodyPath)
|
||||||
|
}
|
||||||
|
// 65536 characters is the maximum allowed for the pull request body.
|
||||||
|
if (inputs.body.length > 65536) {
|
||||||
|
core.warning(
|
||||||
|
`Pull request body is too long. Truncating to 65536 characters.`
|
||||||
|
)
|
||||||
|
inputs.body = inputs.body.substring(0, 65536)
|
||||||
|
}
|
||||||
|
|
||||||
await createPullRequest(inputs)
|
await createPullRequest(inputs)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(utils.getErrorMessage(error))
|
core.setFailed(utils.getErrorMessage(error))
|
||||||
|
47
src/utils.ts
47
src/utils.ts
@ -41,53 +41,6 @@ export function getRepoPath(relativePath?: string): string {
|
|||||||
return repoPath
|
return repoPath
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RemoteDetail {
|
|
||||||
hostname: string
|
|
||||||
protocol: string
|
|
||||||
repository: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRemoteDetail(remoteUrl: string): RemoteDetail {
|
|
||||||
// Parse the protocol and github repository from a URL
|
|
||||||
// e.g. HTTPS, peter-evans/create-pull-request
|
|
||||||
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 hostname = githubServerMatch[1]
|
|
||||||
|
|
||||||
const httpsUrlPattern = new RegExp(
|
|
||||||
'^https?://.*@?' + hostname + '/(.+/.+?)(\\.git)?$',
|
|
||||||
'i'
|
|
||||||
)
|
|
||||||
const sshUrlPattern = new RegExp('^git@' + hostname + ':(.+/.+)\\.git$', 'i')
|
|
||||||
|
|
||||||
const httpsMatch = remoteUrl.match(httpsUrlPattern)
|
|
||||||
if (httpsMatch) {
|
|
||||||
return {
|
|
||||||
hostname,
|
|
||||||
protocol: 'HTTPS',
|
|
||||||
repository: httpsMatch[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const sshMatch = remoteUrl.match(sshUrlPattern)
|
|
||||||
if (sshMatch) {
|
|
||||||
return {
|
|
||||||
hostname,
|
|
||||||
protocol: 'SSH',
|
|
||||||
repository: sshMatch[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(
|
|
||||||
`The format of '${remoteUrl}' is not a valid GitHub repository URL`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getRemoteUrl(
|
export function getRemoteUrl(
|
||||||
protocol: string,
|
protocol: string,
|
||||||
hostname: string,
|
hostname: string,
|
||||||
|
Reference in New Issue
Block a user