Compare commits
101 Commits
Author | SHA1 | Date | |
---|---|---|---|
284f54f989 | |||
9e5b234402 | |||
2d8e7db84c | |||
041b6ab163 | |||
31de0fdf3f | |||
28295f6636 | |||
8dcaf3883b | |||
2827897dcc | |||
c4f19d3a23 | |||
46035868a3 | |||
c09e1094b6 | |||
eab3ea092e | |||
e179caf91b | |||
f3a21bf340 | |||
5b4a9f6a9e | |||
1847e5d1d6 | |||
c246f7e912 | |||
2dd2b11b09 | |||
05d5a3c3f9 | |||
21479f22fc | |||
36a56dac07 | |||
b7f0c9773b | |||
6a62596740 | |||
d1ed29fe1e | |||
e34fedf492 | |||
495ffbb489 | |||
073c8e6ece | |||
375254568c | |||
09af4e30b5 | |||
38e0b6e68b | |||
a95ef54b72 | |||
021e16bf4a | |||
5141da944e | |||
6217f0d61d | |||
e5cb5210cd | |||
7414bc0848 | |||
f8fe2469e5 | |||
b8f683bda6 | |||
d5f5f4bf24 | |||
6c2fad6b3d | |||
a716f73d72 | |||
24b0f8edad | |||
0e6a687637 | |||
e913bb956f | |||
82604c59cc | |||
951d1b87f0 | |||
df0f02f84a | |||
274dd7d2dc | |||
a38ad37eff | |||
450c1f7d69 | |||
a057a6160f | |||
391a18894a | |||
f5be40c5f3 | |||
4eca541d3c | |||
5a4c812497 | |||
37c8100cff | |||
ec919b7792 | |||
000e3c6002 | |||
85176410d0 | |||
ac971fe9b8 | |||
3019dd596d | |||
e73c69172d | |||
d4a593d321 | |||
58815ba2b6 | |||
29267e1085 | |||
7f1f68b1c1 | |||
38e03b3c64 | |||
3861a52f7a | |||
f14600d64a | |||
9895f5748a | |||
84c5454c6e | |||
f63262067e | |||
aa2f52f5a1 | |||
bb5781b719 | |||
e398a27af3 | |||
d015db1f4a | |||
f962808be0 | |||
2dd85e3f19 | |||
2f0833515b | |||
ca4fd2f0d1 | |||
ea54357f43 | |||
df09107abb | |||
16ae6c427b | |||
852fead4ce | |||
9b996f5c6a | |||
e8211ce8f4 | |||
10f43fe334 | |||
1313abbfb6 | |||
73ff87b6a4 | |||
d4d765620e | |||
646f785c1f | |||
f73101ae67 | |||
78389986b6 | |||
c5bc9fd446 | |||
17815d689c | |||
a8d53a0985 | |||
daf3998db5 | |||
8861bdedc8 | |||
75a5de63f0 | |||
d36c8e0863 | |||
2b011faafd |
9
.github/dependabot.yml
vendored
9
.github/dependabot.yml
vendored
@ -4,6 +4,7 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "tuesday"
|
||||
labels:
|
||||
- "dependencies"
|
||||
|
||||
@ -11,5 +12,9 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
allow:
|
||||
- dependency-name: "@actions/*"
|
||||
day: "tuesday"
|
||||
ignore:
|
||||
- dependency-name: "*"
|
||||
update-types: ["version-update:semver-major"]
|
||||
labels:
|
||||
- "dependencies"
|
||||
|
13
.github/workflows/automerge-dependabot.yml
vendored
Normal file
13
.github/workflows/automerge-dependabot.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
name: Auto-merge Dependabot
|
||||
on: pull_request
|
||||
|
||||
jobs:
|
||||
automerge:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.actor == 'dependabot[bot]'
|
||||
steps:
|
||||
- uses: peter-evans/enable-pull-request-automerge@v3
|
||||
with:
|
||||
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
|
||||
pull-request-number: ${{ github.event.pull_request.number }}
|
||||
merge-method: squash
|
9
.github/workflows/ci.yml
vendored
9
.github/workflows/ci.yml
vendored
@ -77,10 +77,10 @@ jobs:
|
||||
Auto-generated by [create-pull-request][1]
|
||||
|
||||
[1]: https://github.com/peter-evans/create-pull-request
|
||||
branch: ci-test-${{ matrix.target }}
|
||||
branch: ci-test-${{ matrix.target }}-${{ github.sha }}
|
||||
|
||||
- name: Close Pull
|
||||
uses: peter-evans/close-pull@v2
|
||||
uses: peter-evans/close-pull@v3
|
||||
with:
|
||||
pull-request-number: ${{ steps.cpr.outputs.pull-request-number }}
|
||||
comment: '[CI] test ${{ matrix.target }}'
|
||||
@ -101,7 +101,7 @@ jobs:
|
||||
|
||||
- if: steps.fc.outputs.comment-id == ''
|
||||
name: Create comment
|
||||
uses: peter-evans/create-or-update-comment@v2
|
||||
uses: peter-evans/create-or-update-comment@v3
|
||||
with:
|
||||
issue-number: ${{ github.event.number }}
|
||||
body: |
|
||||
@ -121,8 +121,9 @@ jobs:
|
||||
name: dist
|
||||
path: dist
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
|
||||
commit-message: 'build: update distribution'
|
||||
title: Update distribution
|
||||
body: |
|
||||
|
2
.github/workflows/cpr-example-command.yml
vendored
2
.github/workflows/cpr-example-command.yml
vendored
@ -42,7 +42,7 @@ jobs:
|
||||
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
|
||||
|
||||
- name: Add reaction
|
||||
uses: peter-evans/create-or-update-comment@v2
|
||||
uses: peter-evans/create-or-update-comment@v3
|
||||
with:
|
||||
repository: ${{ github.event.client_payload.github.payload.repository.full_name }}
|
||||
comment-id: ${{ github.event.client_payload.github.payload.comment.id }}
|
||||
|
6
.github/workflows/slash-command-dispatch.yml
vendored
6
.github/workflows/slash-command-dispatch.yml
vendored
@ -18,6 +18,12 @@ jobs:
|
||||
"repository": "peter-evans/create-pull-request-tests",
|
||||
"named_args": true
|
||||
},
|
||||
{
|
||||
"command": "testv4",
|
||||
"permission": "admin",
|
||||
"repository": "peter-evans/create-pull-request-tests",
|
||||
"named_args": true
|
||||
},
|
||||
{
|
||||
"command": "clean",
|
||||
"permission": "admin",
|
||||
|
32
.github/workflows/update-major-version.yml
vendored
Normal file
32
.github/workflows/update-major-version.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: Update Major Version
|
||||
run-name: Update ${{ github.event.inputs.main_version }} to ${{ github.event.inputs.target }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
target:
|
||||
description: The target tag or reference
|
||||
required: true
|
||||
main_version:
|
||||
type: choice
|
||||
description: The major version tag to update
|
||||
options:
|
||||
- v4
|
||||
- v5
|
||||
|
||||
jobs:
|
||||
tag:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
|
||||
fetch-depth: 0
|
||||
- name: Git config
|
||||
run: |
|
||||
git config user.name actions-bot
|
||||
git config user.email actions-bot@users.noreply.github.com
|
||||
- name: Tag new target
|
||||
run: git tag -f ${{ github.event.inputs.main_version }} ${{ github.event.inputs.target }}
|
||||
- name: Push new tag
|
||||
run: git push origin ${{ github.event.inputs.main_version }} --force
|
29
README.md
29
README.md
@ -21,7 +21,7 @@ Create Pull Request action will:
|
||||
|
||||
- [Concepts, guidelines and advanced usage](docs/concepts-guidelines.md)
|
||||
- [Examples](docs/examples.md)
|
||||
- [Updating to v4](docs/updating.md)
|
||||
- [Updating to v5](docs/updating.md)
|
||||
|
||||
## Usage
|
||||
|
||||
@ -31,10 +31,10 @@ Create Pull Request action will:
|
||||
# Make changes to pull request here
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
```
|
||||
|
||||
You can also pin to a [specific release](https://github.com/peter-evans/create-pull-request/releases) version in the format `@v4.x.x`
|
||||
You can also pin to a [specific release](https://github.com/peter-evans/create-pull-request/releases) version in the format `@v5.x.x`
|
||||
|
||||
### Workflow permissions
|
||||
|
||||
@ -59,23 +59,24 @@ All inputs are **optional**. If not set, sensible defaults will be used.
|
||||
| `author` | The author name and email address in the format `Display Name <email@address.com>`. Defaults to the user who triggered the workflow run. | `${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>` |
|
||||
| `signoff` | Add [`Signed-off-by`](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---signoff) line by the committer at the end of the commit log message. | `false` |
|
||||
| `branch` | The pull request branch name. | `create-pull-request/patch` |
|
||||
| `delete-branch` | Delete the `branch` when closing pull requests, and when undeleted after merging. Recommend `true`. | `false` |
|
||||
| `delete-branch` | Delete the `branch` when closing pull requests, and when undeleted after merging. | `false` |
|
||||
| `branch-suffix` | The branch suffix type when using the alternative branching strategy. Valid values are `random`, `timestamp` and `short-commit-hash`. See [Alternative strategy](#alternative-strategy---always-create-a-new-pull-request-branch) for details. | |
|
||||
| `base` | Sets the pull request base branch. | Defaults to the branch checked out in the workflow. |
|
||||
| `push-to-fork` | A fork of the checked-out parent repository to which the pull request branch will be pushed. e.g. `owner/repo-fork`. The pull request will be created to merge the fork's branch into the parent's base. See [push pull request branches to a fork](docs/concepts-guidelines.md#push-pull-request-branches-to-a-fork) for details. | |
|
||||
| `title` | The title of the pull request. | `Changes by create-pull-request action` |
|
||||
| `body` | The body of the pull request. | `Automated changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action` |
|
||||
| `body-path` | The path to a file containing the pull request body. Takes precedence over `body`. | |
|
||||
| `labels` | A comma or newline-separated list of labels. | |
|
||||
| `assignees` | A comma or newline-separated list of assignees (GitHub usernames). | |
|
||||
| `reviewers` | A comma or newline-separated list of reviewers (GitHub usernames) to request a review from. | |
|
||||
| `team-reviewers` | A comma or newline-separated list of GitHub teams to request a review from. Note that a `repo` scoped [PAT](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) may be required. See [this issue](https://github.com/peter-evans/create-pull-request/issues/155). If using a GitHub App, refer to [Authenticating with GitHub App generated tokens](docs/concepts-guidelines.md#authenticating-with-github-app-generated-tokens) for the proper permissions. | |
|
||||
| `team-reviewers` | A comma or newline-separated list of GitHub teams to request a review from. Note that a `repo` scoped [PAT](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token), or equivalent [GitHub App permissions](docs/concepts-guidelines.md#authenticating-with-github-app-generated-tokens), are required. | |
|
||||
| `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` |
|
||||
|
||||
For self-hosted runners behind a corporate proxy set the `https_proxy` environment variable.
|
||||
```yml
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
env:
|
||||
https_proxy: http://<proxy_address>:<port>
|
||||
```
|
||||
@ -95,7 +96,7 @@ Note that in order to read the step outputs the action step must have an id.
|
||||
```yml
|
||||
- name: Create Pull Request
|
||||
id: cpr
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
- name: Check outputs
|
||||
if: ${{ steps.cpr.outputs.pull-request-number }}
|
||||
run: |
|
||||
@ -154,11 +155,11 @@ If there are files or directories you want to ignore you can simply add them to
|
||||
|
||||
You can control which files are committed with the `add-paths` input.
|
||||
Paths should follow git's [pathspec](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefpathspecapathspec) syntax.
|
||||
All file changes that do not match one of the paths will be discarded.
|
||||
File changes that do not match one of the paths will be stashed and restored after the action has completed.
|
||||
|
||||
```yml
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
add-paths: |
|
||||
*.java
|
||||
@ -185,7 +186,7 @@ Note that the repository must be checked out on a branch with a remote, it won't
|
||||
- name: Uncommitted change
|
||||
run: date +%s > report.txt
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
```
|
||||
|
||||
### Create a project card
|
||||
@ -195,7 +196,7 @@ To create a project card for the pull request, pass the `pull-request-number` st
|
||||
```yml
|
||||
- name: Create Pull Request
|
||||
id: cpr
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
|
||||
- name: Create or Update Project Card
|
||||
if: ${{ steps.cpr.outputs.pull-request-number }}
|
||||
@ -230,7 +231,7 @@ jobs:
|
||||
|
||||
- name: Create Pull Request
|
||||
id: cpr
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
token: ${{ secrets.PAT }}
|
||||
commit-message: Update report
|
||||
@ -252,8 +253,8 @@ jobs:
|
||||
assignees: peter-evans
|
||||
reviewers: peter-evans
|
||||
team-reviewers: |
|
||||
owners
|
||||
maintainers
|
||||
developers
|
||||
qa-team
|
||||
milestone: 1
|
||||
draft: false
|
||||
```
|
||||
|
@ -245,6 +245,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(trackedContent)
|
||||
expect(
|
||||
@ -273,6 +274,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_trackedContent)
|
||||
@ -294,6 +296,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(untrackedContent)
|
||||
expect(
|
||||
@ -322,6 +325,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(_untrackedContent)
|
||||
@ -345,6 +349,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -374,6 +379,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('not-updated')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -395,6 +401,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -432,6 +439,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -463,6 +471,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -491,6 +500,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeFalsy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(defaultTrackedContent)
|
||||
@ -512,6 +522,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -552,6 +563,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeFalsy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -579,6 +591,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -622,6 +635,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeFalsy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -647,6 +661,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -685,6 +700,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -707,6 +723,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(commits.changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(
|
||||
@ -738,6 +755,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_commits.changes.tracked)
|
||||
@ -764,6 +782,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -799,6 +818,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -827,6 +847,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -870,6 +891,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -897,6 +919,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -926,6 +949,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -948,6 +972,7 @@ describe('create-or-update-branch tests', () => {
|
||||
true,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -984,6 +1009,7 @@ describe('create-or-update-branch tests', () => {
|
||||
true,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -1013,6 +1039,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_MULTI
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -1042,6 +1069,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_MULTI
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -1064,6 +1092,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_WILDCARD
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -1093,6 +1122,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_WILDCARD
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -1115,10 +1145,55 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
['nonexistent/*']
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('none')
|
||||
expect(await gitLogMatches([INIT_COMMIT_MESSAGE])).toBeTruthy()
|
||||
})
|
||||
|
||||
it('tests create consecutive branches with restored changes from stash', async () => {
|
||||
const BRANCHA = `${BRANCH}-a`
|
||||
const BRANCHB = `${BRANCH}-b`
|
||||
|
||||
// Create tracked and untracked file changes
|
||||
const changes = await createChanges()
|
||||
const commitMessage = uuidv4()
|
||||
const resultA = await createOrUpdateBranch(
|
||||
git,
|
||||
commitMessage,
|
||||
'',
|
||||
BRANCHA,
|
||||
REMOTE_NAME,
|
||||
false,
|
||||
['a']
|
||||
)
|
||||
const resultB = await createOrUpdateBranch(
|
||||
git,
|
||||
commitMessage,
|
||||
'',
|
||||
BRANCHB,
|
||||
REMOTE_NAME,
|
||||
false,
|
||||
['b']
|
||||
)
|
||||
await git.checkout(BRANCHA)
|
||||
expect(resultA.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(
|
||||
await gitLogMatches([commitMessage, INIT_COMMIT_MESSAGE])
|
||||
).toBeTruthy()
|
||||
await git.checkout(BRANCHB)
|
||||
expect(resultB.action).toEqual('created')
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
expect(
|
||||
await gitLogMatches([commitMessage, INIT_COMMIT_MESSAGE])
|
||||
).toBeTruthy()
|
||||
|
||||
// Delete the local branches
|
||||
await git.checkout(DEFAULT_BRANCH)
|
||||
await git.exec(['branch', '--delete', '--force', BRANCHA])
|
||||
await git.exec(['branch', '--delete', '--force', BRANCHB])
|
||||
})
|
||||
|
||||
// Working Base is Not Base (WBNB)
|
||||
|
||||
it('tests no changes resulting in no new branch being created (WBNB)', async () => {
|
||||
@ -1135,6 +1210,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('none')
|
||||
expect(await gitLogMatches([INIT_COMMIT_MESSAGE])).toBeTruthy()
|
||||
})
|
||||
@ -1155,6 +1231,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(trackedContent)
|
||||
expect(
|
||||
@ -1186,6 +1263,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_trackedContent)
|
||||
@ -1210,6 +1288,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(untrackedContent)
|
||||
expect(
|
||||
@ -1241,6 +1320,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(_untrackedContent)
|
||||
@ -1267,6 +1347,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -1299,6 +1380,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('not-updated')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -1323,6 +1405,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -1363,6 +1446,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -1397,6 +1481,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -1428,6 +1513,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeFalsy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(defaultTrackedContent)
|
||||
@ -1454,6 +1540,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -1497,6 +1584,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeFalsy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -1527,6 +1615,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -1573,6 +1662,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeFalsy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -1601,6 +1691,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -1642,6 +1733,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -1667,6 +1759,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(commits.changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(
|
||||
@ -1701,6 +1794,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_commits.changes.tracked)
|
||||
@ -1730,6 +1824,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -1768,6 +1863,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -1799,6 +1895,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -1845,6 +1942,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -1875,6 +1973,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -1907,6 +2006,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -1936,6 +2036,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -1969,6 +2070,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -1995,6 +2097,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(result.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
@ -2036,6 +2139,7 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
expect(_result.action).toEqual('updated')
|
||||
expect(_result.hasDiffWithBase).toBeTruthy()
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(_changes.tracked)
|
||||
@ -2068,7 +2172,56 @@ describe('create-or-update-branch tests', () => {
|
||||
false,
|
||||
ADD_PATHS_DEFAULT
|
||||
)
|
||||
await git.checkout(BRANCH)
|
||||
// The action cannot successfully create the branch
|
||||
expect(result.action).toEqual('none')
|
||||
})
|
||||
|
||||
it('tests create consecutive branches with restored changes from stash in detached HEAD state (WBNR)', async () => {
|
||||
// Checkout the HEAD commit SHA
|
||||
const headSha = await git.revParse('HEAD')
|
||||
await git.checkout(headSha)
|
||||
|
||||
const BRANCHA = `${BRANCH}-a`
|
||||
const BRANCHB = `${BRANCH}-b`
|
||||
|
||||
// Create tracked and untracked file changes
|
||||
const changes = await createChanges()
|
||||
const commitMessage = uuidv4()
|
||||
const resultA = await createOrUpdateBranch(
|
||||
git,
|
||||
commitMessage,
|
||||
BASE,
|
||||
BRANCHA,
|
||||
REMOTE_NAME,
|
||||
false,
|
||||
['a']
|
||||
)
|
||||
const resultB = await createOrUpdateBranch(
|
||||
git,
|
||||
commitMessage,
|
||||
BASE,
|
||||
BRANCHB,
|
||||
REMOTE_NAME,
|
||||
false,
|
||||
['b']
|
||||
)
|
||||
await git.checkout(BRANCHA)
|
||||
expect(resultA.action).toEqual('created')
|
||||
expect(await getFileContent(TRACKED_FILE)).toEqual(changes.tracked)
|
||||
expect(
|
||||
await gitLogMatches([commitMessage, INIT_COMMIT_MESSAGE])
|
||||
).toBeTruthy()
|
||||
await git.checkout(BRANCHB)
|
||||
expect(resultB.action).toEqual('created')
|
||||
expect(await getFileContent(UNTRACKED_FILE)).toEqual(changes.untracked)
|
||||
expect(
|
||||
await gitLogMatches([commitMessage, INIT_COMMIT_MESSAGE])
|
||||
).toBeTruthy()
|
||||
|
||||
// Delete the local branches
|
||||
await git.checkout(DEFAULT_BRANCH)
|
||||
await git.exec(['branch', '--delete', '--force', BRANCHA])
|
||||
await git.exec(['branch', '--delete', '--force', BRANCHB])
|
||||
})
|
||||
})
|
||||
|
@ -46,4 +46,25 @@ describe('git-auth-helper tests', () => {
|
||||
|
||||
await gitAuthHelper.removeAuth()
|
||||
})
|
||||
|
||||
it('tests adding and removing the safe.directory config', async () => {
|
||||
await git.config('safe.directory', '/another-value', true, true)
|
||||
|
||||
await gitAuthHelper.removeSafeDirectory()
|
||||
await gitAuthHelper.addSafeDirectory()
|
||||
|
||||
expect(
|
||||
await git.configExists('safe.directory', REPO_PATH, true)
|
||||
).toBeTruthy()
|
||||
|
||||
await gitAuthHelper.addSafeDirectory()
|
||||
await gitAuthHelper.removeSafeDirectory()
|
||||
|
||||
expect(
|
||||
await git.configExists('safe.directory', REPO_PATH, true)
|
||||
).toBeFalsy()
|
||||
expect(
|
||||
await git.configExists('safe.directory', '/another-value', true)
|
||||
).toBeTruthy()
|
||||
})
|
||||
})
|
||||
|
@ -25,6 +25,18 @@ describe('utils tests', () => {
|
||||
expect(array2.length).toEqual(0)
|
||||
})
|
||||
|
||||
test('stripOrgPrefixFromTeams strips org prefixes correctly', async () => {
|
||||
const array = utils.stripOrgPrefixFromTeams([
|
||||
'org/team1',
|
||||
'org/team2',
|
||||
'team3'
|
||||
])
|
||||
expect(array.length).toEqual(3)
|
||||
expect(array[0]).toEqual('team1')
|
||||
expect(array[1]).toEqual('team2')
|
||||
expect(array[2]).toEqual('team3')
|
||||
})
|
||||
|
||||
test('getRepoPath successfully returns the path to the repository', async () => {
|
||||
expect(utils.getRepoPath()).toEqual(process.env['GITHUB_WORKSPACE'])
|
||||
expect(utils.getRepoPath('foo')).toEqual(
|
||||
|
@ -54,6 +54,8 @@ inputs:
|
||||
body:
|
||||
description: 'The body of the pull request.'
|
||||
default: 'Automated changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action'
|
||||
body-path:
|
||||
description: 'The path to a file containing the pull request body. Takes precedence over `body`.'
|
||||
labels:
|
||||
description: 'A comma or newline separated list of labels.'
|
||||
assignees:
|
||||
|
1010
dist/bridge.js
vendored
1010
dist/bridge.js
vendored
File diff suppressed because it is too large
Load Diff
977
dist/events.js
vendored
977
dist/events.js
vendored
@ -1,977 +0,0 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// Modified by the vm2 team to make this a standalone module to be loaded into the sandbox.
|
||||
|
||||
'use strict';
|
||||
|
||||
const host = fromhost;
|
||||
|
||||
const {
|
||||
Boolean,
|
||||
Error,
|
||||
String,
|
||||
Symbol
|
||||
} = globalThis;
|
||||
|
||||
const ReflectApply = Reflect.apply;
|
||||
const ReflectOwnKeys = Reflect.ownKeys;
|
||||
|
||||
const ErrorCaptureStackTrace = Error.captureStackTrace;
|
||||
|
||||
const NumberIsNaN = Number.isNaN;
|
||||
|
||||
const ObjectCreate = Object.create;
|
||||
const ObjectDefineProperty = Object.defineProperty;
|
||||
const ObjectDefineProperties = Object.defineProperties;
|
||||
const ObjectGetPrototypeOf = Object.getPrototypeOf;
|
||||
|
||||
const SymbolFor = Symbol.for;
|
||||
|
||||
function uncurryThis(func) {
|
||||
return (thiz, ...args) => ReflectApply(func, thiz, args);
|
||||
}
|
||||
|
||||
const ArrayPrototypeIndexOf = uncurryThis(Array.prototype.indexOf);
|
||||
const ArrayPrototypeJoin = uncurryThis(Array.prototype.join);
|
||||
const ArrayPrototypeSlice = uncurryThis(Array.prototype.slice);
|
||||
const ArrayPrototypeSplice = uncurryThis(Array.prototype.splice);
|
||||
const ArrayPrototypeUnshift = uncurryThis(Array.prototype.unshift);
|
||||
|
||||
const kRejection = SymbolFor('nodejs.rejection');
|
||||
|
||||
function inspect(obj) {
|
||||
return typeof obj === 'symbol' ? obj.toString() : `${obj}`;
|
||||
}
|
||||
|
||||
function spliceOne(list, index) {
|
||||
for (; index + 1 < list.length; index++)
|
||||
list[index] = list[index + 1];
|
||||
list.pop();
|
||||
}
|
||||
|
||||
function assert(what, message) {
|
||||
if (!what) throw new Error(message);
|
||||
}
|
||||
|
||||
function E(key, msg, Base) {
|
||||
return function NodeError(...args) {
|
||||
const error = new Base();
|
||||
const message = ReflectApply(msg, error, args);
|
||||
ObjectDefineProperties(error, {
|
||||
message: {
|
||||
value: message,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
},
|
||||
toString: {
|
||||
value() {
|
||||
return `${this.name} [${key}]: ${this.message}`;
|
||||
},
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
},
|
||||
});
|
||||
error.code = key;
|
||||
return error;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
const ERR_INVALID_ARG_TYPE = E('ERR_INVALID_ARG_TYPE',
|
||||
(name, expected, actual) => {
|
||||
assert(typeof name === 'string', "'name' must be a string");
|
||||
if (!ArrayIsArray(expected)) {
|
||||
expected = [expected];
|
||||
}
|
||||
|
||||
let msg = 'The ';
|
||||
if (StringPrototypeEndsWith(name, ' argument')) {
|
||||
// For cases like 'first argument'
|
||||
msg += `${name} `;
|
||||
} else {
|
||||
const type = StringPrototypeIncludes(name, '.') ? 'property' : 'argument';
|
||||
msg += `"${name}" ${type} `;
|
||||
}
|
||||
msg += 'must be ';
|
||||
|
||||
const types = [];
|
||||
const instances = [];
|
||||
const other = [];
|
||||
|
||||
for (const value of expected) {
|
||||
assert(typeof value === 'string',
|
||||
'All expected entries have to be of type string');
|
||||
if (ArrayPrototypeIncludes(kTypes, value)) {
|
||||
ArrayPrototypePush(types, StringPrototypeToLowerCase(value));
|
||||
} else if (RegExpPrototypeTest(classRegExp, value)) {
|
||||
ArrayPrototypePush(instances, value);
|
||||
} else {
|
||||
assert(value !== 'object',
|
||||
'The value "object" should be written as "Object"');
|
||||
ArrayPrototypePush(other, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Special handle `object` in case other instances are allowed to outline
|
||||
// the differences between each other.
|
||||
if (instances.length > 0) {
|
||||
const pos = ArrayPrototypeIndexOf(types, 'object');
|
||||
if (pos !== -1) {
|
||||
ArrayPrototypeSplice(types, pos, 1);
|
||||
ArrayPrototypePush(instances, 'Object');
|
||||
}
|
||||
}
|
||||
|
||||
if (types.length > 0) {
|
||||
if (types.length > 2) {
|
||||
const last = ArrayPrototypePop(types);
|
||||
msg += `one of type ${ArrayPrototypeJoin(types, ', ')}, or ${last}`;
|
||||
} else if (types.length === 2) {
|
||||
msg += `one of type ${types[0]} or ${types[1]}`;
|
||||
} else {
|
||||
msg += `of type ${types[0]}`;
|
||||
}
|
||||
if (instances.length > 0 || other.length > 0)
|
||||
msg += ' or ';
|
||||
}
|
||||
|
||||
if (instances.length > 0) {
|
||||
if (instances.length > 2) {
|
||||
const last = ArrayPrototypePop(instances);
|
||||
msg +=
|
||||
`an instance of ${ArrayPrototypeJoin(instances, ', ')}, or ${last}`;
|
||||
} else {
|
||||
msg += `an instance of ${instances[0]}`;
|
||||
if (instances.length === 2) {
|
||||
msg += ` or ${instances[1]}`;
|
||||
}
|
||||
}
|
||||
if (other.length > 0)
|
||||
msg += ' or ';
|
||||
}
|
||||
|
||||
if (other.length > 0) {
|
||||
if (other.length > 2) {
|
||||
const last = ArrayPrototypePop(other);
|
||||
msg += `one of ${ArrayPrototypeJoin(other, ', ')}, or ${last}`;
|
||||
} else if (other.length === 2) {
|
||||
msg += `one of ${other[0]} or ${other[1]}`;
|
||||
} else {
|
||||
if (StringPrototypeToLowerCase(other[0]) !== other[0])
|
||||
msg += 'an ';
|
||||
msg += `${other[0]}`;
|
||||
}
|
||||
}
|
||||
|
||||
if (actual == null) {
|
||||
msg += `. Received ${actual}`;
|
||||
} else if (typeof actual === 'function' && actual.name) {
|
||||
msg += `. Received function ${actual.name}`;
|
||||
} else if (typeof actual === 'object') {
|
||||
if (actual.constructor && actual.constructor.name) {
|
||||
msg += `. Received an instance of ${actual.constructor.name}`;
|
||||
} else {
|
||||
const inspected = inspect(actual, { depth: -1 });
|
||||
msg += `. Received ${inspected}`;
|
||||
}
|
||||
} else {
|
||||
let inspected = inspect(actual, { colors: false });
|
||||
if (inspected.length > 25)
|
||||
inspected = `${StringPrototypeSlice(inspected, 0, 25)}...`;
|
||||
msg += `. Received type ${typeof actual} (${inspected})`;
|
||||
}
|
||||
return msg;
|
||||
}, TypeError);
|
||||
|
||||
const ERR_INVALID_THIS = E('ERR_INVALID_THIS', s => `Value of "this" must be of type ${s}`, TypeError);
|
||||
|
||||
const ERR_OUT_OF_RANGE = E('ERR_OUT_OF_RANGE',
|
||||
(str, range, input, replaceDefaultBoolean = false) => {
|
||||
assert(range, 'Missing "range" argument');
|
||||
let msg = replaceDefaultBoolean ? str :
|
||||
`The value of "${str}" is out of range.`;
|
||||
const received = inspect(input);
|
||||
msg += ` It must be ${range}. Received ${received}`;
|
||||
return msg;
|
||||
}, RangeError);
|
||||
|
||||
const ERR_UNHANDLED_ERROR = E('ERR_UNHANDLED_ERROR',
|
||||
err => {
|
||||
const msg = 'Unhandled error.';
|
||||
if (err === undefined) return msg;
|
||||
return `${msg} (${err})`;
|
||||
}, Error);
|
||||
|
||||
function validateBoolean(value, name) {
|
||||
if (typeof value !== 'boolean')
|
||||
throw new ERR_INVALID_ARG_TYPE(name, 'boolean', value);
|
||||
}
|
||||
|
||||
function validateFunction(value, name) {
|
||||
if (typeof value !== 'function')
|
||||
throw new ERR_INVALID_ARG_TYPE(name, 'Function', value);
|
||||
}
|
||||
|
||||
function validateString(value, name) {
|
||||
if (typeof value !== 'string')
|
||||
throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
|
||||
}
|
||||
|
||||
function nc(cond, e) {
|
||||
return cond === undefined || cond === null ? e : cond;
|
||||
}
|
||||
|
||||
function oc(base, key) {
|
||||
return base === undefined || base === null ? undefined : base[key];
|
||||
}
|
||||
|
||||
const kCapture = Symbol('kCapture');
|
||||
const kErrorMonitor = host.kErrorMonitor || Symbol('events.errorMonitor');
|
||||
const kMaxEventTargetListeners = Symbol('events.maxEventTargetListeners');
|
||||
const kMaxEventTargetListenersWarned =
|
||||
Symbol('events.maxEventTargetListenersWarned');
|
||||
|
||||
const kIsEventTarget = SymbolFor('nodejs.event_target');
|
||||
|
||||
function isEventTarget(obj) {
|
||||
return oc(oc(obj, 'constructor'), kIsEventTarget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new `EventEmitter` instance.
|
||||
* @param {{ captureRejections?: boolean; }} [opts]
|
||||
* @constructs {EventEmitter}
|
||||
*/
|
||||
function EventEmitter(opts) {
|
||||
EventEmitter.init.call(this, opts);
|
||||
}
|
||||
module.exports = EventEmitter;
|
||||
if (host.once) module.exports.once = host.once;
|
||||
if (host.on) module.exports.on = host.on;
|
||||
if (host.getEventListeners) module.exports.getEventListeners = host.getEventListeners;
|
||||
// Backwards-compat with node 0.10.x
|
||||
EventEmitter.EventEmitter = EventEmitter;
|
||||
|
||||
EventEmitter.usingDomains = false;
|
||||
|
||||
EventEmitter.captureRejectionSymbol = kRejection;
|
||||
ObjectDefineProperty(EventEmitter, 'captureRejections', {
|
||||
get() {
|
||||
return EventEmitter.prototype[kCapture];
|
||||
},
|
||||
set(value) {
|
||||
validateBoolean(value, 'EventEmitter.captureRejections');
|
||||
|
||||
EventEmitter.prototype[kCapture] = value;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
if (host.EventEmitterReferencingAsyncResource) {
|
||||
const kAsyncResource = Symbol('kAsyncResource');
|
||||
const EventEmitterReferencingAsyncResource = host.EventEmitterReferencingAsyncResource;
|
||||
|
||||
class EventEmitterAsyncResource extends EventEmitter {
|
||||
/**
|
||||
* @param {{
|
||||
* name?: string,
|
||||
* triggerAsyncId?: number,
|
||||
* requireManualDestroy?: boolean,
|
||||
* }} [options]
|
||||
*/
|
||||
constructor(options = undefined) {
|
||||
let name;
|
||||
if (typeof options === 'string') {
|
||||
name = options;
|
||||
options = undefined;
|
||||
} else {
|
||||
if (new.target === EventEmitterAsyncResource) {
|
||||
validateString(oc(options, 'name'), 'options.name');
|
||||
}
|
||||
name = oc(options, 'name') || new.target.name;
|
||||
}
|
||||
super(options);
|
||||
|
||||
this[kAsyncResource] =
|
||||
new EventEmitterReferencingAsyncResource(this, name, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {symbol,string} event
|
||||
* @param {...any} args
|
||||
* @returns {boolean}
|
||||
*/
|
||||
emit(event, ...args) {
|
||||
if (this[kAsyncResource] === undefined)
|
||||
throw new ERR_INVALID_THIS('EventEmitterAsyncResource');
|
||||
const { asyncResource } = this;
|
||||
ArrayPrototypeUnshift(args, super.emit, this, event);
|
||||
return ReflectApply(asyncResource.runInAsyncScope, asyncResource,
|
||||
args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
*/
|
||||
emitDestroy() {
|
||||
if (this[kAsyncResource] === undefined)
|
||||
throw new ERR_INVALID_THIS('EventEmitterAsyncResource');
|
||||
this.asyncResource.emitDestroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
get asyncId() {
|
||||
if (this[kAsyncResource] === undefined)
|
||||
throw new ERR_INVALID_THIS('EventEmitterAsyncResource');
|
||||
return this.asyncResource.asyncId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
get triggerAsyncId() {
|
||||
if (this[kAsyncResource] === undefined)
|
||||
throw new ERR_INVALID_THIS('EventEmitterAsyncResource');
|
||||
return this.asyncResource.triggerAsyncId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {EventEmitterReferencingAsyncResource}
|
||||
*/
|
||||
get asyncResource() {
|
||||
if (this[kAsyncResource] === undefined)
|
||||
throw new ERR_INVALID_THIS('EventEmitterAsyncResource');
|
||||
return this[kAsyncResource];
|
||||
}
|
||||
}
|
||||
EventEmitter.EventEmitterAsyncResource = EventEmitterAsyncResource;
|
||||
}
|
||||
|
||||
EventEmitter.errorMonitor = kErrorMonitor;
|
||||
|
||||
// The default for captureRejections is false
|
||||
ObjectDefineProperty(EventEmitter.prototype, kCapture, {
|
||||
value: false,
|
||||
writable: true,
|
||||
enumerable: false
|
||||
});
|
||||
|
||||
EventEmitter.prototype._events = undefined;
|
||||
EventEmitter.prototype._eventsCount = 0;
|
||||
EventEmitter.prototype._maxListeners = undefined;
|
||||
|
||||
// By default EventEmitters will print a warning if more than 10 listeners are
|
||||
// added to it. This is a useful default which helps finding memory leaks.
|
||||
let defaultMaxListeners = 10;
|
||||
|
||||
function checkListener(listener) {
|
||||
validateFunction(listener, 'listener');
|
||||
}
|
||||
|
||||
ObjectDefineProperty(EventEmitter, 'defaultMaxListeners', {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return defaultMaxListeners;
|
||||
},
|
||||
set: function(arg) {
|
||||
if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
|
||||
throw new ERR_OUT_OF_RANGE('defaultMaxListeners',
|
||||
'a non-negative number',
|
||||
arg);
|
||||
}
|
||||
defaultMaxListeners = arg;
|
||||
}
|
||||
});
|
||||
|
||||
ObjectDefineProperties(EventEmitter, {
|
||||
kMaxEventTargetListeners: {
|
||||
value: kMaxEventTargetListeners,
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
writable: false,
|
||||
},
|
||||
kMaxEventTargetListenersWarned: {
|
||||
value: kMaxEventTargetListenersWarned,
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
writable: false,
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Sets the max listeners.
|
||||
* @param {number} n
|
||||
* @param {EventTarget[] | EventEmitter[]} [eventTargets]
|
||||
* @returns {void}
|
||||
*/
|
||||
EventEmitter.setMaxListeners =
|
||||
function(n = defaultMaxListeners, ...eventTargets) {
|
||||
if (typeof n !== 'number' || n < 0 || NumberIsNaN(n))
|
||||
throw new ERR_OUT_OF_RANGE('n', 'a non-negative number', n);
|
||||
if (eventTargets.length === 0) {
|
||||
defaultMaxListeners = n;
|
||||
} else {
|
||||
for (let i = 0; i < eventTargets.length; i++) {
|
||||
const target = eventTargets[i];
|
||||
if (isEventTarget(target)) {
|
||||
target[kMaxEventTargetListeners] = n;
|
||||
target[kMaxEventTargetListenersWarned] = false;
|
||||
} else if (typeof target.setMaxListeners === 'function') {
|
||||
target.setMaxListeners(n);
|
||||
} else {
|
||||
throw new ERR_INVALID_ARG_TYPE(
|
||||
'eventTargets',
|
||||
['EventEmitter', 'EventTarget'],
|
||||
target);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// If you're updating this function definition, please also update any
|
||||
// re-definitions, such as the one in the Domain module (lib/domain.js).
|
||||
EventEmitter.init = function(opts) {
|
||||
|
||||
if (this._events === undefined ||
|
||||
this._events === ObjectGetPrototypeOf(this)._events) {
|
||||
this._events = ObjectCreate(null);
|
||||
this._eventsCount = 0;
|
||||
}
|
||||
|
||||
this._maxListeners = this._maxListeners || undefined;
|
||||
|
||||
|
||||
if (oc(opts, 'captureRejections')) {
|
||||
validateBoolean(opts.captureRejections, 'options.captureRejections');
|
||||
this[kCapture] = Boolean(opts.captureRejections);
|
||||
} else {
|
||||
// Assigning the kCapture property directly saves an expensive
|
||||
// prototype lookup in a very sensitive hot path.
|
||||
this[kCapture] = EventEmitter.prototype[kCapture];
|
||||
}
|
||||
};
|
||||
|
||||
function addCatch(that, promise, type, args) {
|
||||
if (!that[kCapture]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle Promises/A+ spec, then could be a getter
|
||||
// that throws on second use.
|
||||
try {
|
||||
const then = promise.then;
|
||||
|
||||
if (typeof then === 'function') {
|
||||
then.call(promise, undefined, function(err) {
|
||||
// The callback is called with nextTick to avoid a follow-up
|
||||
// rejection from this promise.
|
||||
process.nextTick(emitUnhandledRejectionOrErr, that, err, type, args);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
that.emit('error', err);
|
||||
}
|
||||
}
|
||||
|
||||
function emitUnhandledRejectionOrErr(ee, err, type, args) {
|
||||
if (typeof ee[kRejection] === 'function') {
|
||||
ee[kRejection](err, type, ...args);
|
||||
} else {
|
||||
// We have to disable the capture rejections mechanism, otherwise
|
||||
// we might end up in an infinite loop.
|
||||
const prev = ee[kCapture];
|
||||
|
||||
// If the error handler throws, it is not catchable and it
|
||||
// will end up in 'uncaughtException'. We restore the previous
|
||||
// value of kCapture in case the uncaughtException is present
|
||||
// and the exception is handled.
|
||||
try {
|
||||
ee[kCapture] = false;
|
||||
ee.emit('error', err);
|
||||
} finally {
|
||||
ee[kCapture] = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the max listeners of the event emitter.
|
||||
* @param {number} n
|
||||
* @returns {EventEmitter}
|
||||
*/
|
||||
EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
|
||||
if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
|
||||
throw new ERR_OUT_OF_RANGE('n', 'a non-negative number', n);
|
||||
}
|
||||
this._maxListeners = n;
|
||||
return this;
|
||||
};
|
||||
|
||||
function _getMaxListeners(that) {
|
||||
if (that._maxListeners === undefined)
|
||||
return EventEmitter.defaultMaxListeners;
|
||||
return that._maxListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current max listener value for the event emitter.
|
||||
* @returns {number}
|
||||
*/
|
||||
EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
|
||||
return _getMaxListeners(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Synchronously calls each of the listeners registered
|
||||
* for the event.
|
||||
* @param {string | symbol} type
|
||||
* @param {...any} [args]
|
||||
* @returns {boolean}
|
||||
*/
|
||||
EventEmitter.prototype.emit = function emit(type, ...args) {
|
||||
let doError = (type === 'error');
|
||||
|
||||
const events = this._events;
|
||||
if (events !== undefined) {
|
||||
if (doError && events[kErrorMonitor] !== undefined)
|
||||
this.emit(kErrorMonitor, ...args);
|
||||
doError = (doError && events.error === undefined);
|
||||
} else if (!doError)
|
||||
return false;
|
||||
|
||||
// If there is no 'error' event listener then throw.
|
||||
if (doError) {
|
||||
let er;
|
||||
if (args.length > 0)
|
||||
er = args[0];
|
||||
if (er instanceof Error) {
|
||||
try {
|
||||
const capture = {};
|
||||
ErrorCaptureStackTrace(capture, EventEmitter.prototype.emit);
|
||||
} catch (e) {}
|
||||
|
||||
// Note: The comments on the `throw` lines are intentional, they show
|
||||
// up in Node's output if this results in an unhandled exception.
|
||||
throw er; // Unhandled 'error' event
|
||||
}
|
||||
|
||||
let stringifiedEr;
|
||||
try {
|
||||
stringifiedEr = inspect(er);
|
||||
} catch (e) {
|
||||
stringifiedEr = er;
|
||||
}
|
||||
|
||||
// At least give some kind of context to the user
|
||||
const err = new ERR_UNHANDLED_ERROR(stringifiedEr);
|
||||
err.context = er;
|
||||
throw err; // Unhandled 'error' event
|
||||
}
|
||||
|
||||
const handler = events[type];
|
||||
|
||||
if (handler === undefined)
|
||||
return false;
|
||||
|
||||
if (typeof handler === 'function') {
|
||||
const result = handler.apply(this, args);
|
||||
|
||||
// We check if result is undefined first because that
|
||||
// is the most common case so we do not pay any perf
|
||||
// penalty
|
||||
if (result !== undefined && result !== null) {
|
||||
addCatch(this, result, type, args);
|
||||
}
|
||||
} else {
|
||||
const len = handler.length;
|
||||
const listeners = arrayClone(handler);
|
||||
for (let i = 0; i < len; ++i) {
|
||||
const result = listeners[i].apply(this, args);
|
||||
|
||||
// We check if result is undefined first because that
|
||||
// is the most common case so we do not pay any perf
|
||||
// penalty.
|
||||
// This code is duplicated because extracting it away
|
||||
// would make it non-inlineable.
|
||||
if (result !== undefined && result !== null) {
|
||||
addCatch(this, result, type, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
function _addListener(target, type, listener, prepend) {
|
||||
let m;
|
||||
let events;
|
||||
let existing;
|
||||
|
||||
checkListener(listener);
|
||||
|
||||
events = target._events;
|
||||
if (events === undefined) {
|
||||
events = target._events = ObjectCreate(null);
|
||||
target._eventsCount = 0;
|
||||
} else {
|
||||
// To avoid recursion in the case that type === "newListener"! Before
|
||||
// adding it to the listeners, first emit "newListener".
|
||||
if (events.newListener !== undefined) {
|
||||
target.emit('newListener', type,
|
||||
nc(listener.listener, listener));
|
||||
|
||||
// Re-assign `events` because a newListener handler could have caused the
|
||||
// this._events to be assigned to a new object
|
||||
events = target._events;
|
||||
}
|
||||
existing = events[type];
|
||||
}
|
||||
|
||||
if (existing === undefined) {
|
||||
// Optimize the case of one listener. Don't need the extra array object.
|
||||
events[type] = listener;
|
||||
++target._eventsCount;
|
||||
} else {
|
||||
if (typeof existing === 'function') {
|
||||
// Adding the second element, need to change to array.
|
||||
existing = events[type] =
|
||||
prepend ? [listener, existing] : [existing, listener];
|
||||
// If we've already got an array, just append.
|
||||
} else if (prepend) {
|
||||
existing.unshift(listener);
|
||||
} else {
|
||||
existing.push(listener);
|
||||
}
|
||||
|
||||
// Check for listener leak
|
||||
m = _getMaxListeners(target);
|
||||
if (m > 0 && existing.length > m && !existing.warned) {
|
||||
existing.warned = true;
|
||||
// No error code for this since it is a Warning
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
const w = new Error('Possible EventEmitter memory leak detected. ' +
|
||||
`${existing.length} ${String(type)} listeners ` +
|
||||
`added to ${inspect(target, { depth: -1 })}. Use ` +
|
||||
'emitter.setMaxListeners() to increase limit');
|
||||
w.name = 'MaxListenersExceededWarning';
|
||||
w.emitter = target;
|
||||
w.type = type;
|
||||
w.count = existing.length;
|
||||
process.emitWarning(w);
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to the event emitter.
|
||||
* @param {string | symbol} type
|
||||
* @param {Function} listener
|
||||
* @returns {EventEmitter}
|
||||
*/
|
||||
EventEmitter.prototype.addListener = function addListener(type, listener) {
|
||||
return _addListener(this, type, listener, false);
|
||||
};
|
||||
|
||||
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
|
||||
|
||||
/**
|
||||
* Adds the `listener` function to the beginning of
|
||||
* the listeners array.
|
||||
* @param {string | symbol} type
|
||||
* @param {Function} listener
|
||||
* @returns {EventEmitter}
|
||||
*/
|
||||
EventEmitter.prototype.prependListener =
|
||||
function prependListener(type, listener) {
|
||||
return _addListener(this, type, listener, true);
|
||||
};
|
||||
|
||||
function onceWrapper() {
|
||||
if (!this.fired) {
|
||||
this.target.removeListener(this.type, this.wrapFn);
|
||||
this.fired = true;
|
||||
if (arguments.length === 0)
|
||||
return this.listener.call(this.target);
|
||||
return this.listener.apply(this.target, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
function _onceWrap(target, type, listener) {
|
||||
const state = { fired: false, wrapFn: undefined, target, type, listener };
|
||||
const wrapped = onceWrapper.bind(state);
|
||||
wrapped.listener = listener;
|
||||
state.wrapFn = wrapped;
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a one-time `listener` function to the event emitter.
|
||||
* @param {string | symbol} type
|
||||
* @param {Function} listener
|
||||
* @returns {EventEmitter}
|
||||
*/
|
||||
EventEmitter.prototype.once = function once(type, listener) {
|
||||
checkListener(listener);
|
||||
|
||||
this.on(type, _onceWrap(this, type, listener));
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a one-time `listener` function to the beginning of
|
||||
* the listeners array.
|
||||
* @param {string | symbol} type
|
||||
* @param {Function} listener
|
||||
* @returns {EventEmitter}
|
||||
*/
|
||||
EventEmitter.prototype.prependOnceListener =
|
||||
function prependOnceListener(type, listener) {
|
||||
checkListener(listener);
|
||||
|
||||
this.prependListener(type, _onceWrap(this, type, listener));
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the specified `listener` from the listeners array.
|
||||
* @param {string | symbol} type
|
||||
* @param {Function} listener
|
||||
* @returns {EventEmitter}
|
||||
*/
|
||||
EventEmitter.prototype.removeListener =
|
||||
function removeListener(type, listener) {
|
||||
checkListener(listener);
|
||||
|
||||
const events = this._events;
|
||||
if (events === undefined)
|
||||
return this;
|
||||
|
||||
const list = events[type];
|
||||
if (list === undefined)
|
||||
return this;
|
||||
|
||||
if (list === listener || list.listener === listener) {
|
||||
if (--this._eventsCount === 0)
|
||||
this._events = ObjectCreate(null);
|
||||
else {
|
||||
delete events[type];
|
||||
if (events.removeListener)
|
||||
this.emit('removeListener', type, list.listener || listener);
|
||||
}
|
||||
} else if (typeof list !== 'function') {
|
||||
let position = -1;
|
||||
|
||||
for (let i = list.length - 1; i >= 0; i--) {
|
||||
if (list[i] === listener || list[i].listener === listener) {
|
||||
position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (position < 0)
|
||||
return this;
|
||||
|
||||
if (position === 0)
|
||||
list.shift();
|
||||
else {
|
||||
spliceOne(list, position);
|
||||
}
|
||||
|
||||
if (list.length === 1)
|
||||
events[type] = list[0];
|
||||
|
||||
if (events.removeListener !== undefined)
|
||||
this.emit('removeListener', type, listener);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
||||
|
||||
/**
|
||||
* Removes all listeners from the event emitter. (Only
|
||||
* removes listeners for a specific event name if specified
|
||||
* as `type`).
|
||||
* @param {string | symbol} [type]
|
||||
* @returns {EventEmitter}
|
||||
*/
|
||||
EventEmitter.prototype.removeAllListeners =
|
||||
function removeAllListeners(type) {
|
||||
const events = this._events;
|
||||
if (events === undefined)
|
||||
return this;
|
||||
|
||||
// Not listening for removeListener, no need to emit
|
||||
if (events.removeListener === undefined) {
|
||||
if (arguments.length === 0) {
|
||||
this._events = ObjectCreate(null);
|
||||
this._eventsCount = 0;
|
||||
} else if (events[type] !== undefined) {
|
||||
if (--this._eventsCount === 0)
|
||||
this._events = ObjectCreate(null);
|
||||
else
|
||||
delete events[type];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
// Emit removeListener for all listeners on all events
|
||||
if (arguments.length === 0) {
|
||||
for (const key of ReflectOwnKeys(events)) {
|
||||
if (key === 'removeListener') continue;
|
||||
this.removeAllListeners(key);
|
||||
}
|
||||
this.removeAllListeners('removeListener');
|
||||
this._events = ObjectCreate(null);
|
||||
this._eventsCount = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
const listeners = events[type];
|
||||
|
||||
if (typeof listeners === 'function') {
|
||||
this.removeListener(type, listeners);
|
||||
} else if (listeners !== undefined) {
|
||||
// LIFO order
|
||||
for (let i = listeners.length - 1; i >= 0; i--) {
|
||||
this.removeListener(type, listeners[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
function _listeners(target, type, unwrap) {
|
||||
const events = target._events;
|
||||
|
||||
if (events === undefined)
|
||||
return [];
|
||||
|
||||
const evlistener = events[type];
|
||||
if (evlistener === undefined)
|
||||
return [];
|
||||
|
||||
if (typeof evlistener === 'function')
|
||||
return unwrap ? [evlistener.listener || evlistener] : [evlistener];
|
||||
|
||||
return unwrap ?
|
||||
unwrapListeners(evlistener) : arrayClone(evlistener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the array of listeners for the event name
|
||||
* specified as `type`.
|
||||
* @param {string | symbol} type
|
||||
* @returns {Function[]}
|
||||
*/
|
||||
EventEmitter.prototype.listeners = function listeners(type) {
|
||||
return _listeners(this, type, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a copy of the array of listeners and wrappers for
|
||||
* the event name specified as `type`.
|
||||
* @param {string | symbol} type
|
||||
* @returns {Function[]}
|
||||
*/
|
||||
EventEmitter.prototype.rawListeners = function rawListeners(type) {
|
||||
return _listeners(this, type, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the number of listeners listening to the event name
|
||||
* specified as `type`.
|
||||
* @deprecated since v3.2.0
|
||||
* @param {EventEmitter} emitter
|
||||
* @param {string | symbol} type
|
||||
* @returns {number}
|
||||
*/
|
||||
EventEmitter.listenerCount = function(emitter, type) {
|
||||
if (typeof emitter.listenerCount === 'function') {
|
||||
return emitter.listenerCount(type);
|
||||
}
|
||||
return emitter.listenerCount(type);
|
||||
};
|
||||
|
||||
EventEmitter.prototype.listenerCount = listenerCount;
|
||||
|
||||
/**
|
||||
* Returns the number of listeners listening to event name
|
||||
* specified as `type`.
|
||||
* @param {string | symbol} type
|
||||
* @returns {number}
|
||||
*/
|
||||
function listenerCount(type) {
|
||||
const events = this._events;
|
||||
|
||||
if (events !== undefined) {
|
||||
const evlistener = events[type];
|
||||
|
||||
if (typeof evlistener === 'function') {
|
||||
return 1;
|
||||
} else if (evlistener !== undefined) {
|
||||
return evlistener.length;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array listing the events for which
|
||||
* the emitter has registered listeners.
|
||||
* @returns {any[]}
|
||||
*/
|
||||
EventEmitter.prototype.eventNames = function eventNames() {
|
||||
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
|
||||
};
|
||||
|
||||
function arrayClone(arr) {
|
||||
// At least since V8 8.3, this implementation is faster than the previous
|
||||
// which always used a simple for-loop
|
||||
switch (arr.length) {
|
||||
case 2: return [arr[0], arr[1]];
|
||||
case 3: return [arr[0], arr[1], arr[2]];
|
||||
case 4: return [arr[0], arr[1], arr[2], arr[3]];
|
||||
case 5: return [arr[0], arr[1], arr[2], arr[3], arr[4]];
|
||||
case 6: return [arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]];
|
||||
}
|
||||
return ArrayPrototypeSlice(arr);
|
||||
}
|
||||
|
||||
function unwrapListeners(arr) {
|
||||
const ret = arrayClone(arr);
|
||||
for (let i = 0; i < ret.length; ++i) {
|
||||
const orig = ret[i].listener;
|
||||
if (typeof orig === 'function')
|
||||
ret[i] = orig;
|
||||
}
|
||||
return ret;
|
||||
}
|
51130
dist/index.js
vendored
51130
dist/index.js
vendored
File diff suppressed because it is too large
Load Diff
469
dist/setup-node-sandbox.js
vendored
469
dist/setup-node-sandbox.js
vendored
@ -1,469 +0,0 @@
|
||||
/* global host, data, VMError */
|
||||
|
||||
'use strict';
|
||||
|
||||
const LocalError = Error;
|
||||
const LocalTypeError = TypeError;
|
||||
const LocalWeakMap = WeakMap;
|
||||
|
||||
const {
|
||||
apply: localReflectApply,
|
||||
defineProperty: localReflectDefineProperty
|
||||
} = Reflect;
|
||||
|
||||
const {
|
||||
set: localWeakMapSet,
|
||||
get: localWeakMapGet
|
||||
} = LocalWeakMap.prototype;
|
||||
|
||||
const {
|
||||
isArray: localArrayIsArray
|
||||
} = Array;
|
||||
|
||||
function uncurryThis(func) {
|
||||
return (thiz, ...args) => localReflectApply(func, thiz, args);
|
||||
}
|
||||
|
||||
const localArrayPrototypeSlice = uncurryThis(Array.prototype.slice);
|
||||
const localArrayPrototypeIncludes = uncurryThis(Array.prototype.includes);
|
||||
const localArrayPrototypePush = uncurryThis(Array.prototype.push);
|
||||
const localArrayPrototypeIndexOf = uncurryThis(Array.prototype.indexOf);
|
||||
const localArrayPrototypeSplice = uncurryThis(Array.prototype.splice);
|
||||
const localStringPrototypeStartsWith = uncurryThis(String.prototype.startsWith);
|
||||
const localStringPrototypeSlice = uncurryThis(String.prototype.slice);
|
||||
const localStringPrototypeIndexOf = uncurryThis(String.prototype.indexOf);
|
||||
|
||||
const {
|
||||
argv: optionArgv,
|
||||
env: optionEnv,
|
||||
console: optionConsole,
|
||||
vm,
|
||||
resolver,
|
||||
extensions
|
||||
} = data;
|
||||
|
||||
function ensureSandboxArray(a) {
|
||||
return localArrayPrototypeSlice(a);
|
||||
}
|
||||
|
||||
const globalPaths = ensureSandboxArray(resolver.globalPaths);
|
||||
|
||||
class Module {
|
||||
|
||||
constructor(id, path, parent) {
|
||||
this.id = id;
|
||||
this.filename = id;
|
||||
this.path = path;
|
||||
this.parent = parent;
|
||||
this.loaded = false;
|
||||
this.paths = path ? ensureSandboxArray(resolver.genLookupPaths(path)) : [];
|
||||
this.children = [];
|
||||
this.exports = {};
|
||||
}
|
||||
|
||||
_updateChildren(child, isNew) {
|
||||
const children = this.children;
|
||||
if (children && (isNew || !localArrayPrototypeIncludes(children, child))) {
|
||||
localArrayPrototypePush(children, child);
|
||||
}
|
||||
}
|
||||
|
||||
require(id) {
|
||||
return requireImpl(this, id, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const originalRequire = Module.prototype.require;
|
||||
const cacheBuiltins = {__proto__: null};
|
||||
|
||||
function requireImpl(mod, id, direct) {
|
||||
if (direct && mod.require !== originalRequire) {
|
||||
return mod.require(id);
|
||||
}
|
||||
const filename = resolver.resolve(mod, id, undefined, Module._extensions, direct);
|
||||
if (localStringPrototypeStartsWith(filename, 'node:')) {
|
||||
id = localStringPrototypeSlice(filename, 5);
|
||||
let nmod = cacheBuiltins[id];
|
||||
if (!nmod) {
|
||||
nmod = resolver.loadBuiltinModule(vm, id);
|
||||
if (!nmod) throw new VMError(`Cannot find module '${filename}'`, 'ENOTFOUND');
|
||||
cacheBuiltins[id] = nmod;
|
||||
}
|
||||
return nmod;
|
||||
}
|
||||
|
||||
const cachedModule = Module._cache[filename];
|
||||
if (cachedModule !== undefined) {
|
||||
mod._updateChildren(cachedModule, false);
|
||||
return cachedModule.exports;
|
||||
}
|
||||
|
||||
let nmod = cacheBuiltins[id];
|
||||
if (nmod) return nmod;
|
||||
nmod = resolver.loadBuiltinModule(vm, id);
|
||||
if (nmod) {
|
||||
cacheBuiltins[id] = nmod;
|
||||
return nmod;
|
||||
}
|
||||
|
||||
const path = resolver.pathDirname(filename);
|
||||
const module = new Module(filename, path, mod);
|
||||
resolver.registerModule(module, filename, path, mod, direct);
|
||||
mod._updateChildren(module, true);
|
||||
try {
|
||||
Module._cache[filename] = module;
|
||||
const handler = findBestExtensionHandler(filename);
|
||||
handler(module, filename);
|
||||
module.loaded = true;
|
||||
} catch (e) {
|
||||
delete Module._cache[filename];
|
||||
const children = mod.children;
|
||||
if (localArrayIsArray(children)) {
|
||||
const index = localArrayPrototypeIndexOf(children, module);
|
||||
if (index !== -1) {
|
||||
localArrayPrototypeSplice(children, index, 1);
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
return module.exports;
|
||||
}
|
||||
|
||||
Module.builtinModules = ensureSandboxArray(resolver.getBuiltinModulesList());
|
||||
Module.globalPaths = globalPaths;
|
||||
Module._extensions = {__proto__: null};
|
||||
Module._cache = {__proto__: null};
|
||||
|
||||
{
|
||||
const keys = Object.getOwnPropertyNames(extensions);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i];
|
||||
const handler = extensions[key];
|
||||
Module._extensions[key] = (mod, filename) => handler(mod, filename);
|
||||
}
|
||||
}
|
||||
|
||||
function findBestExtensionHandler(filename) {
|
||||
const name = resolver.pathBasename(filename);
|
||||
for (let i = 0; (i = localStringPrototypeIndexOf(name, '.', i + 1)) !== -1;) {
|
||||
const ext = localStringPrototypeSlice(name, i);
|
||||
const handler = Module._extensions[ext];
|
||||
if (handler) return handler;
|
||||
}
|
||||
const js = Module._extensions['.js'];
|
||||
if (js) return js;
|
||||
const keys = Object.getOwnPropertyNames(Module._extensions);
|
||||
if (keys.length === 0) throw new VMError(`Failed to load '${filename}': Unknown type.`, 'ELOADFAIL');
|
||||
return Module._extensions[keys[0]];
|
||||
}
|
||||
|
||||
function createRequireForModule(mod) {
|
||||
// eslint-disable-next-line no-shadow
|
||||
function require(id) {
|
||||
return requireImpl(mod, id, true);
|
||||
}
|
||||
function resolve(id, options) {
|
||||
return resolver.resolve(mod, id, options, Module._extensions, true);
|
||||
}
|
||||
require.resolve = resolve;
|
||||
function paths(id) {
|
||||
return ensureSandboxArray(resolver.lookupPaths(mod, id));
|
||||
}
|
||||
resolve.paths = paths;
|
||||
|
||||
require.extensions = Module._extensions;
|
||||
|
||||
require.cache = Module._cache;
|
||||
|
||||
return require;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare sandbox.
|
||||
*/
|
||||
|
||||
const TIMERS = new LocalWeakMap();
|
||||
|
||||
class Timeout {
|
||||
}
|
||||
|
||||
class Interval {
|
||||
}
|
||||
|
||||
class Immediate {
|
||||
}
|
||||
|
||||
function clearTimer(timer) {
|
||||
const obj = localReflectApply(localWeakMapGet, TIMERS, [timer]);
|
||||
if (obj) {
|
||||
obj.clear(obj.value);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a function and not an arrow function, since the original is also a function
|
||||
// eslint-disable-next-line no-shadow
|
||||
global.setTimeout = function setTimeout(callback, delay, ...args) {
|
||||
if (typeof callback !== 'function') throw new LocalTypeError('"callback" argument must be a function');
|
||||
const obj = new Timeout(callback, args);
|
||||
const cb = () => {
|
||||
localReflectApply(callback, null, args);
|
||||
};
|
||||
const tmr = host.setTimeout(cb, delay);
|
||||
|
||||
const ref = {
|
||||
__proto__: null,
|
||||
clear: host.clearTimeout,
|
||||
value: tmr
|
||||
};
|
||||
|
||||
localReflectApply(localWeakMapSet, TIMERS, [obj, ref]);
|
||||
return obj;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
global.setInterval = function setInterval(callback, interval, ...args) {
|
||||
if (typeof callback !== 'function') throw new LocalTypeError('"callback" argument must be a function');
|
||||
const obj = new Interval();
|
||||
const cb = () => {
|
||||
localReflectApply(callback, null, args);
|
||||
};
|
||||
const tmr = host.setInterval(cb, interval);
|
||||
|
||||
const ref = {
|
||||
__proto__: null,
|
||||
clear: host.clearInterval,
|
||||
value: tmr
|
||||
};
|
||||
|
||||
localReflectApply(localWeakMapSet, TIMERS, [obj, ref]);
|
||||
return obj;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
global.setImmediate = function setImmediate(callback, ...args) {
|
||||
if (typeof callback !== 'function') throw new LocalTypeError('"callback" argument must be a function');
|
||||
const obj = new Immediate();
|
||||
const cb = () => {
|
||||
localReflectApply(callback, null, args);
|
||||
};
|
||||
const tmr = host.setImmediate(cb);
|
||||
|
||||
const ref = {
|
||||
__proto__: null,
|
||||
clear: host.clearImmediate,
|
||||
value: tmr
|
||||
};
|
||||
|
||||
localReflectApply(localWeakMapSet, TIMERS, [obj, ref]);
|
||||
return obj;
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
global.clearTimeout = function clearTimeout(timeout) {
|
||||
clearTimer(timeout);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
global.clearInterval = function clearInterval(interval) {
|
||||
clearTimer(interval);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
global.clearImmediate = function clearImmediate(immediate) {
|
||||
clearTimer(immediate);
|
||||
};
|
||||
|
||||
const localProcess = host.process;
|
||||
|
||||
function vmEmitArgs(event, args) {
|
||||
const allargs = [event];
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
if (!localReflectDefineProperty(allargs, i + 1, {
|
||||
__proto__: null,
|
||||
value: args[i],
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
})) throw new LocalError('Unexpected');
|
||||
}
|
||||
return localReflectApply(vm.emit, vm, allargs);
|
||||
}
|
||||
|
||||
const LISTENERS = new LocalWeakMap();
|
||||
const LISTENER_HANDLER = new LocalWeakMap();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} name
|
||||
* @param {*} handler
|
||||
* @this process
|
||||
* @return {this}
|
||||
*/
|
||||
function addListener(name, handler) {
|
||||
if (name !== 'beforeExit' && name !== 'exit') {
|
||||
throw new LocalError(`Access denied to listen for '${name}' event.`);
|
||||
}
|
||||
|
||||
let cb = localReflectApply(localWeakMapGet, LISTENERS, [handler]);
|
||||
if (!cb) {
|
||||
cb = () => {
|
||||
handler();
|
||||
};
|
||||
localReflectApply(localWeakMapSet, LISTENER_HANDLER, [cb, handler]);
|
||||
localReflectApply(localWeakMapSet, LISTENERS, [handler, cb]);
|
||||
}
|
||||
|
||||
localProcess.on(name, cb);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @this process
|
||||
* @return {this}
|
||||
*/
|
||||
// eslint-disable-next-line no-shadow
|
||||
function process() {
|
||||
return this;
|
||||
}
|
||||
|
||||
const baseUptime = localProcess.uptime();
|
||||
|
||||
// FIXME wrong class structure
|
||||
global.process = {
|
||||
__proto__: process.prototype,
|
||||
argv: optionArgv !== undefined ? optionArgv : [],
|
||||
title: localProcess.title,
|
||||
version: localProcess.version,
|
||||
versions: localProcess.versions,
|
||||
arch: localProcess.arch,
|
||||
platform: localProcess.platform,
|
||||
env: optionEnv !== undefined ? optionEnv : {},
|
||||
pid: localProcess.pid,
|
||||
features: localProcess.features,
|
||||
nextTick: function nextTick(callback, ...args) {
|
||||
if (typeof callback !== 'function') {
|
||||
throw new LocalError('Callback must be a function.');
|
||||
}
|
||||
|
||||
localProcess.nextTick(()=>{
|
||||
localReflectApply(callback, null, args);
|
||||
});
|
||||
},
|
||||
hrtime: function hrtime(time) {
|
||||
return localProcess.hrtime(time);
|
||||
},
|
||||
uptime: function uptime() {
|
||||
return localProcess.uptime() - baseUptime;
|
||||
},
|
||||
cwd: function cwd() {
|
||||
return localProcess.cwd();
|
||||
},
|
||||
addListener,
|
||||
on: addListener,
|
||||
|
||||
once: function once(name, handler) {
|
||||
if (name !== 'beforeExit' && name !== 'exit') {
|
||||
throw new LocalError(`Access denied to listen for '${name}' event.`);
|
||||
}
|
||||
|
||||
let triggered = false;
|
||||
const cb = () => {
|
||||
if (triggered) return;
|
||||
triggered = true;
|
||||
localProcess.removeListener(name, cb);
|
||||
handler();
|
||||
};
|
||||
localReflectApply(localWeakMapSet, LISTENER_HANDLER, [cb, handler]);
|
||||
|
||||
localProcess.on(name, cb);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
listeners: function listeners(name) {
|
||||
if (name !== 'beforeExit' && name !== 'exit') {
|
||||
// Maybe add ({__proto__:null})[name] to throw when name fails in https://tc39.es/ecma262/#sec-topropertykey.
|
||||
return [];
|
||||
}
|
||||
|
||||
// Filter out listeners, which were not created in this sandbox
|
||||
const all = localProcess.listeners(name);
|
||||
const filtered = [];
|
||||
let j = 0;
|
||||
for (let i = 0; i < all.length; i++) {
|
||||
const h = localReflectApply(localWeakMapGet, LISTENER_HANDLER, [all[i]]);
|
||||
if (h) {
|
||||
if (!localReflectDefineProperty(filtered, j, {
|
||||
__proto__: null,
|
||||
value: h,
|
||||
writable: true,
|
||||
enumerable: true,
|
||||
configurable: true
|
||||
})) throw new LocalError('Unexpected');
|
||||
j++;
|
||||
}
|
||||
}
|
||||
return filtered;
|
||||
},
|
||||
|
||||
removeListener: function removeListener(name, handler) {
|
||||
if (name !== 'beforeExit' && name !== 'exit') {
|
||||
return this;
|
||||
}
|
||||
|
||||
const cb = localReflectApply(localWeakMapGet, LISTENERS, [handler]);
|
||||
if (cb) localProcess.removeListener(name, cb);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
umask: function umask() {
|
||||
if (arguments.length) {
|
||||
throw new LocalError('Access denied to set umask.');
|
||||
}
|
||||
|
||||
return localProcess.umask();
|
||||
}
|
||||
};
|
||||
|
||||
if (optionConsole === 'inherit') {
|
||||
global.console = host.console;
|
||||
} else if (optionConsole === 'redirect') {
|
||||
global.console = {
|
||||
debug(...args) {
|
||||
vmEmitArgs('console.debug', args);
|
||||
},
|
||||
log(...args) {
|
||||
vmEmitArgs('console.log', args);
|
||||
},
|
||||
info(...args) {
|
||||
vmEmitArgs('console.info', args);
|
||||
},
|
||||
warn(...args) {
|
||||
vmEmitArgs('console.warn', args);
|
||||
},
|
||||
error(...args) {
|
||||
vmEmitArgs('console.error', args);
|
||||
},
|
||||
dir(...args) {
|
||||
vmEmitArgs('console.dir', args);
|
||||
},
|
||||
time() {},
|
||||
timeEnd() {},
|
||||
trace(...args) {
|
||||
vmEmitArgs('console.trace', args);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
__proto__: null,
|
||||
Module,
|
||||
jsonParse: JSON.parse,
|
||||
createRequireForModule,
|
||||
requireImpl
|
||||
};
|
457
dist/setup-sandbox.js
vendored
457
dist/setup-sandbox.js
vendored
@ -1,457 +0,0 @@
|
||||
/* global host, bridge, data, context */
|
||||
|
||||
'use strict';
|
||||
|
||||
const {
|
||||
Object: localObject,
|
||||
Array: localArray,
|
||||
Error: LocalError,
|
||||
Reflect: localReflect,
|
||||
Proxy: LocalProxy,
|
||||
WeakMap: LocalWeakMap,
|
||||
Function: localFunction,
|
||||
Promise: localPromise,
|
||||
eval: localEval
|
||||
} = global;
|
||||
|
||||
const {
|
||||
freeze: localObjectFreeze
|
||||
} = localObject;
|
||||
|
||||
const {
|
||||
getPrototypeOf: localReflectGetPrototypeOf,
|
||||
apply: localReflectApply,
|
||||
deleteProperty: localReflectDeleteProperty,
|
||||
has: localReflectHas,
|
||||
defineProperty: localReflectDefineProperty,
|
||||
setPrototypeOf: localReflectSetPrototypeOf,
|
||||
getOwnPropertyDescriptor: localReflectGetOwnPropertyDescriptor
|
||||
} = localReflect;
|
||||
|
||||
const {
|
||||
isArray: localArrayIsArray
|
||||
} = localArray;
|
||||
|
||||
const {
|
||||
ensureThis,
|
||||
ReadOnlyHandler,
|
||||
from,
|
||||
fromWithFactory,
|
||||
readonlyFactory,
|
||||
connect,
|
||||
addProtoMapping,
|
||||
VMError,
|
||||
ReadOnlyMockHandler
|
||||
} = bridge;
|
||||
|
||||
const {
|
||||
allowAsync,
|
||||
GeneratorFunction,
|
||||
AsyncFunction,
|
||||
AsyncGeneratorFunction
|
||||
} = data;
|
||||
|
||||
const {
|
||||
get: localWeakMapGet,
|
||||
set: localWeakMapSet
|
||||
} = LocalWeakMap.prototype;
|
||||
|
||||
function localUnexpected() {
|
||||
return new VMError('Should not happen');
|
||||
}
|
||||
|
||||
// global is originally prototype of host.Object so it can be used to climb up from the sandbox.
|
||||
if (!localReflectSetPrototypeOf(context, localObject.prototype)) throw localUnexpected();
|
||||
|
||||
Object.defineProperties(global, {
|
||||
global: {value: global, writable: true, configurable: true, enumerable: true},
|
||||
globalThis: {value: global, writable: true, configurable: true},
|
||||
GLOBAL: {value: global, writable: true, configurable: true},
|
||||
root: {value: global, writable: true, configurable: true},
|
||||
Error: {value: LocalError}
|
||||
});
|
||||
|
||||
if (!localReflectDefineProperty(global, 'VMError', {
|
||||
__proto__: null,
|
||||
value: VMError,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
})) throw localUnexpected();
|
||||
|
||||
// Fixes buffer unsafe allocation
|
||||
/* eslint-disable no-use-before-define */
|
||||
class BufferHandler extends ReadOnlyHandler {
|
||||
|
||||
apply(target, thiz, args) {
|
||||
if (args.length > 0 && typeof args[0] === 'number') {
|
||||
return LocalBuffer.alloc(args[0]);
|
||||
}
|
||||
return localReflectApply(LocalBuffer.from, LocalBuffer, args);
|
||||
}
|
||||
|
||||
construct(target, args, newTarget) {
|
||||
if (args.length > 0 && typeof args[0] === 'number') {
|
||||
return LocalBuffer.alloc(args[0]);
|
||||
}
|
||||
return localReflectApply(LocalBuffer.from, LocalBuffer, args);
|
||||
}
|
||||
|
||||
}
|
||||
/* eslint-enable no-use-before-define */
|
||||
|
||||
const LocalBuffer = fromWithFactory(obj => new BufferHandler(obj), host.Buffer);
|
||||
|
||||
|
||||
if (!localReflectDefineProperty(global, 'Buffer', {
|
||||
__proto__: null,
|
||||
value: LocalBuffer,
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
})) throw localUnexpected();
|
||||
|
||||
addProtoMapping(LocalBuffer.prototype, host.Buffer.prototype, 'Uint8Array');
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} size Size of new buffer
|
||||
* @this LocalBuffer
|
||||
* @return {LocalBuffer}
|
||||
*/
|
||||
function allocUnsafe(size) {
|
||||
return LocalBuffer.alloc(size);
|
||||
}
|
||||
|
||||
connect(allocUnsafe, host.Buffer.allocUnsafe);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} size Size of new buffer
|
||||
* @this LocalBuffer
|
||||
* @return {LocalBuffer}
|
||||
*/
|
||||
function allocUnsafeSlow(size) {
|
||||
return LocalBuffer.alloc(size);
|
||||
}
|
||||
|
||||
connect(allocUnsafeSlow, host.Buffer.allocUnsafeSlow);
|
||||
|
||||
/**
|
||||
* Replacement for Buffer inspect
|
||||
*
|
||||
* @param {*} recurseTimes
|
||||
* @param {*} ctx
|
||||
* @this LocalBuffer
|
||||
* @return {string}
|
||||
*/
|
||||
function inspect(recurseTimes, ctx) {
|
||||
// Mimic old behavior, could throw but didn't pass a test.
|
||||
const max = host.INSPECT_MAX_BYTES;
|
||||
const actualMax = Math.min(max, this.length);
|
||||
const remaining = this.length - max;
|
||||
let str = this.hexSlice(0, actualMax).replace(/(.{2})/g, '$1 ').trim();
|
||||
if (remaining > 0) str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`;
|
||||
return `<${this.constructor.name} ${str}>`;
|
||||
}
|
||||
|
||||
connect(inspect, host.Buffer.prototype.inspect);
|
||||
|
||||
connect(localFunction.prototype.bind, host.Function.prototype.bind);
|
||||
|
||||
connect(localObject.prototype.__defineGetter__, host.Object.prototype.__defineGetter__);
|
||||
connect(localObject.prototype.__defineSetter__, host.Object.prototype.__defineSetter__);
|
||||
connect(localObject.prototype.__lookupGetter__, host.Object.prototype.__lookupGetter__);
|
||||
connect(localObject.prototype.__lookupSetter__, host.Object.prototype.__lookupSetter__);
|
||||
|
||||
/*
|
||||
* PrepareStackTrace sanitization
|
||||
*/
|
||||
|
||||
const oldPrepareStackTraceDesc = localReflectGetOwnPropertyDescriptor(LocalError, 'prepareStackTrace');
|
||||
|
||||
let currentPrepareStackTrace = LocalError.prepareStackTrace;
|
||||
const wrappedPrepareStackTrace = new LocalWeakMap();
|
||||
if (typeof currentPrepareStackTrace === 'function') {
|
||||
wrappedPrepareStackTrace.set(currentPrepareStackTrace, currentPrepareStackTrace);
|
||||
}
|
||||
|
||||
let OriginalCallSite;
|
||||
LocalError.prepareStackTrace = (e, sst) => {
|
||||
OriginalCallSite = sst[0].constructor;
|
||||
};
|
||||
new LocalError().stack;
|
||||
if (typeof OriginalCallSite === 'function') {
|
||||
LocalError.prepareStackTrace = undefined;
|
||||
|
||||
function makeCallSiteGetters(list) {
|
||||
const callSiteGetters = [];
|
||||
for (let i=0; i<list.length; i++) {
|
||||
const name = list[i];
|
||||
const func = OriginalCallSite.prototype[name];
|
||||
callSiteGetters[i] = {__proto__: null,
|
||||
name,
|
||||
propName: '_' + name,
|
||||
func: (thiz) => {
|
||||
return localReflectApply(func, thiz, []);
|
||||
}
|
||||
};
|
||||
}
|
||||
return callSiteGetters;
|
||||
}
|
||||
|
||||
function applyCallSiteGetters(thiz, callSite, getters) {
|
||||
for (let i=0; i<getters.length; i++) {
|
||||
const getter = getters[i];
|
||||
localReflectDefineProperty(thiz, getter.propName, {
|
||||
__proto__: null,
|
||||
value: getter.func(callSite)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const callSiteGetters = makeCallSiteGetters([
|
||||
'getTypeName',
|
||||
'getFunctionName',
|
||||
'getMethodName',
|
||||
'getFileName',
|
||||
'getLineNumber',
|
||||
'getColumnNumber',
|
||||
'getEvalOrigin',
|
||||
'isToplevel',
|
||||
'isEval',
|
||||
'isNative',
|
||||
'isConstructor',
|
||||
'isAsync',
|
||||
'isPromiseAll',
|
||||
'getPromiseIndex'
|
||||
]);
|
||||
|
||||
class CallSite {
|
||||
constructor(callSite) {
|
||||
applyCallSiteGetters(this, callSite, callSiteGetters);
|
||||
}
|
||||
getThis() {
|
||||
return undefined;
|
||||
}
|
||||
getFunction() {
|
||||
return undefined;
|
||||
}
|
||||
toString() {
|
||||
return 'CallSite {}';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (let i=0; i<callSiteGetters.length; i++) {
|
||||
const name = callSiteGetters[i].name;
|
||||
const funcProp = localReflectGetOwnPropertyDescriptor(OriginalCallSite.prototype, name);
|
||||
if (!funcProp) continue;
|
||||
const propertyName = callSiteGetters[i].propName;
|
||||
const func = {func() {
|
||||
return this[propertyName];
|
||||
}}.func;
|
||||
const nameProp = localReflectGetOwnPropertyDescriptor(func, 'name');
|
||||
if (!nameProp) throw localUnexpected();
|
||||
nameProp.value = name;
|
||||
if (!localReflectDefineProperty(func, 'name', nameProp)) throw localUnexpected();
|
||||
funcProp.value = func;
|
||||
if (!localReflectDefineProperty(CallSite.prototype, name, funcProp)) throw localUnexpected();
|
||||
}
|
||||
|
||||
if (!localReflectDefineProperty(LocalError, 'prepareStackTrace', {
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
get() {
|
||||
return currentPrepareStackTrace;
|
||||
},
|
||||
set(value) {
|
||||
if (typeof(value) !== 'function') {
|
||||
currentPrepareStackTrace = value;
|
||||
return;
|
||||
}
|
||||
const wrapped = localReflectApply(localWeakMapGet, wrappedPrepareStackTrace, [value]);
|
||||
if (wrapped) {
|
||||
currentPrepareStackTrace = wrapped;
|
||||
return;
|
||||
}
|
||||
const newWrapped = (error, sst) => {
|
||||
if (localArrayIsArray(sst)) {
|
||||
for (let i=0; i < sst.length; i++) {
|
||||
const cs = sst[i];
|
||||
if (typeof cs === 'object' && localReflectGetPrototypeOf(cs) === OriginalCallSite.prototype) {
|
||||
sst[i] = new CallSite(cs);
|
||||
}
|
||||
}
|
||||
}
|
||||
return value(error, sst);
|
||||
};
|
||||
localReflectApply(localWeakMapSet, wrappedPrepareStackTrace, [value, newWrapped]);
|
||||
localReflectApply(localWeakMapSet, wrappedPrepareStackTrace, [newWrapped, newWrapped]);
|
||||
currentPrepareStackTrace = newWrapped;
|
||||
}
|
||||
})) throw localUnexpected();
|
||||
} else if (oldPrepareStackTraceDesc) {
|
||||
localReflectDefineProperty(LocalError, 'prepareStackTrace', oldPrepareStackTraceDesc);
|
||||
} else {
|
||||
localReflectDeleteProperty(LocalError, 'prepareStackTrace');
|
||||
}
|
||||
|
||||
/*
|
||||
* Exception sanitization
|
||||
*/
|
||||
|
||||
const withProxy = localObjectFreeze({
|
||||
__proto__: null,
|
||||
has(target, key) {
|
||||
if (key === host.INTERNAL_STATE_NAME) return false;
|
||||
return localReflectHas(target, key);
|
||||
}
|
||||
});
|
||||
|
||||
const interanState = localObjectFreeze({
|
||||
__proto__: null,
|
||||
wrapWith(x) {
|
||||
if (x === null || x === undefined) return x;
|
||||
return new LocalProxy(localObject(x), withProxy);
|
||||
},
|
||||
handleException: ensureThis,
|
||||
import(what) {
|
||||
throw new VMError('Dynamic Import not supported');
|
||||
}
|
||||
});
|
||||
|
||||
if (!localReflectDefineProperty(global, host.INTERNAL_STATE_NAME, {
|
||||
__proto__: null,
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
writable: false,
|
||||
value: interanState
|
||||
})) throw localUnexpected();
|
||||
|
||||
/*
|
||||
* Eval sanitization
|
||||
*/
|
||||
|
||||
function throwAsync() {
|
||||
return new VMError('Async not available');
|
||||
}
|
||||
|
||||
function makeFunction(inputArgs, isAsync, isGenerator) {
|
||||
const lastArgs = inputArgs.length - 1;
|
||||
let code = lastArgs >= 0 ? `${inputArgs[lastArgs]}` : '';
|
||||
let args = lastArgs > 0 ? `${inputArgs[0]}` : '';
|
||||
for (let i = 1; i < lastArgs; i++) {
|
||||
args += `,${inputArgs[i]}`;
|
||||
}
|
||||
try {
|
||||
code = host.transformAndCheck(args, code, isAsync, isGenerator, allowAsync);
|
||||
} catch (e) {
|
||||
throw bridge.from(e);
|
||||
}
|
||||
return localEval(code);
|
||||
}
|
||||
|
||||
const FunctionHandler = {
|
||||
__proto__: null,
|
||||
apply(target, thiz, args) {
|
||||
return makeFunction(args, this.isAsync, this.isGenerator);
|
||||
},
|
||||
construct(target, args, newTarget) {
|
||||
return makeFunction(args, this.isAsync, this.isGenerator);
|
||||
}
|
||||
};
|
||||
|
||||
const EvalHandler = {
|
||||
__proto__: null,
|
||||
apply(target, thiz, args) {
|
||||
if (args.length === 0) return undefined;
|
||||
let code = `${args[0]}`;
|
||||
try {
|
||||
code = host.transformAndCheck(null, code, false, false, allowAsync);
|
||||
} catch (e) {
|
||||
throw bridge.from(e);
|
||||
}
|
||||
return localEval(code);
|
||||
}
|
||||
};
|
||||
|
||||
const AsyncErrorHandler = {
|
||||
__proto__: null,
|
||||
apply(target, thiz, args) {
|
||||
throw throwAsync();
|
||||
},
|
||||
construct(target, args, newTarget) {
|
||||
throw throwAsync();
|
||||
}
|
||||
};
|
||||
|
||||
function makeCheckFunction(isAsync, isGenerator) {
|
||||
if (isAsync && !allowAsync) return AsyncErrorHandler;
|
||||
return {
|
||||
__proto__: FunctionHandler,
|
||||
isAsync,
|
||||
isGenerator
|
||||
};
|
||||
}
|
||||
|
||||
function overrideWithProxy(obj, prop, value, handler) {
|
||||
const proxy = new LocalProxy(value, handler);
|
||||
if (!localReflectDefineProperty(obj, prop, {__proto__: null, value: proxy})) throw localUnexpected();
|
||||
return proxy;
|
||||
}
|
||||
|
||||
const proxiedFunction = overrideWithProxy(localFunction.prototype, 'constructor', localFunction, makeCheckFunction(false, false));
|
||||
if (GeneratorFunction) {
|
||||
if (!localReflectSetPrototypeOf(GeneratorFunction, proxiedFunction)) throw localUnexpected();
|
||||
overrideWithProxy(GeneratorFunction.prototype, 'constructor', GeneratorFunction, makeCheckFunction(false, true));
|
||||
}
|
||||
if (AsyncFunction) {
|
||||
if (!localReflectSetPrototypeOf(AsyncFunction, proxiedFunction)) throw localUnexpected();
|
||||
overrideWithProxy(AsyncFunction.prototype, 'constructor', AsyncFunction, makeCheckFunction(true, false));
|
||||
}
|
||||
if (AsyncGeneratorFunction) {
|
||||
if (!localReflectSetPrototypeOf(AsyncGeneratorFunction, proxiedFunction)) throw localUnexpected();
|
||||
overrideWithProxy(AsyncGeneratorFunction.prototype, 'constructor', AsyncGeneratorFunction, makeCheckFunction(true, true));
|
||||
}
|
||||
|
||||
global.Function = proxiedFunction;
|
||||
global.eval = new LocalProxy(localEval, EvalHandler);
|
||||
|
||||
/*
|
||||
* Promise sanitization
|
||||
*/
|
||||
|
||||
if (localPromise && !allowAsync) {
|
||||
|
||||
const PromisePrototype = localPromise.prototype;
|
||||
|
||||
overrideWithProxy(PromisePrototype, 'then', PromisePrototype.then, AsyncErrorHandler);
|
||||
// This seems not to work, and will produce
|
||||
// UnhandledPromiseRejectionWarning: TypeError: Method Promise.prototype.then called on incompatible receiver [object Object].
|
||||
// This is likely caused since the host.Promise.prototype.then cannot use the VM Proxy object.
|
||||
// Contextify.connect(host.Promise.prototype.then, Promise.prototype.then);
|
||||
|
||||
if (PromisePrototype.finally) {
|
||||
overrideWithProxy(PromisePrototype, 'finally', PromisePrototype.finally, AsyncErrorHandler);
|
||||
// Contextify.connect(host.Promise.prototype.finally, Promise.prototype.finally);
|
||||
}
|
||||
if (Promise.prototype.catch) {
|
||||
overrideWithProxy(PromisePrototype, 'catch', PromisePrototype.catch, AsyncErrorHandler);
|
||||
// Contextify.connect(host.Promise.prototype.catch, Promise.prototype.catch);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function readonly(other, mock) {
|
||||
// Note: other@other(unsafe) mock@other(unsafe) returns@this(unsafe) throws@this(unsafe)
|
||||
if (!mock) return fromWithFactory(readonlyFactory, other);
|
||||
const tmock = from(mock);
|
||||
return fromWithFactory(obj=>new ReadOnlyMockHandler(obj, tmock), other);
|
||||
}
|
||||
|
||||
return {
|
||||
__proto__: null,
|
||||
readonly,
|
||||
global
|
||||
};
|
@ -88,7 +88,7 @@ In these cases, you *must supply* the `base` input so the action can rebase chan
|
||||
Workflows triggered by [`pull_request`](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request) events will by default check out a merge commit. Set the `base` input as follows to base the new pull request on the current pull request's branch.
|
||||
|
||||
```yml
|
||||
- uses: peter-evans/create-pull-request@v4
|
||||
- uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
base: ${{ github.head_ref }}
|
||||
```
|
||||
@ -96,7 +96,7 @@ Workflows triggered by [`pull_request`](https://docs.github.com/en/actions/refer
|
||||
Workflows triggered by [`release`](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#release) events will by default check out a tag. For most use cases, you will need to set the `base` input to the branch name of the tagged commit.
|
||||
|
||||
```yml
|
||||
- uses: peter-evans/create-pull-request@v4
|
||||
- uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
base: main
|
||||
```
|
||||
@ -146,7 +146,7 @@ There are a number of workarounds with different pros and cons.
|
||||
|
||||
- Use the default `GITHUB_TOKEN` and allow the action to create pull requests that have no checks enabled. Manually close pull requests and immediately reopen them. This will enable `on: pull_request` workflows to run and be added as checks. To prevent merging of pull requests without checks erroneously, use [branch protection rules](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/defining-the-mergeability-of-pull-requests).
|
||||
|
||||
- Use a `repo` scoped [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) created on an account that has write access to the repository that pull requests are being created in. This is the standard workaround and [recommended by GitHub](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#triggering-new-workflows-using-a-personal-access-token). However, the PAT cannot be scoped to a specific repository so the token becomes a very sensitive secret. If this is a concern, the PAT can instead be created for a dedicated [machine account](https://docs.github.com/en/github/site-policy/github-terms-of-service#3-account-requirements) that has collaborator access to the repository. Also note that because the account that owns the PAT will be the creator of pull requests, that user account will be unable to perform actions such as request changes or approve the pull request.
|
||||
- Use a `repo` scoped [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) created on an account that has write access to the repository that pull requests are being created in. This is the standard workaround and [recommended by GitHub](https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow). However, the PAT cannot be scoped to a specific repository so the token becomes a very sensitive secret. If this is a concern, the PAT can instead be created for a dedicated [machine account](https://docs.github.com/en/github/site-policy/github-terms-of-service#3-account-requirements) that has collaborator access to the repository. Also note that because the account that owns the PAT will be the creator of pull requests, that user account will be unable to perform actions such as request changes or approve the pull request.
|
||||
|
||||
- Use [SSH (deploy keys)](#push-using-ssh-deploy-keys) to push the pull request branch. This is arguably more secure than using a PAT because deploy keys can be set per repository. However, this method will only trigger `on: push` workflows.
|
||||
|
||||
@ -180,7 +180,7 @@ Checking out a branch from a different repository from where the workflow is exe
|
||||
|
||||
# Make changes to pull request here
|
||||
|
||||
- uses: peter-evans/create-pull-request@v4
|
||||
- uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
token: ${{ secrets.PAT }}
|
||||
```
|
||||
@ -207,7 +207,7 @@ How to use SSH (deploy keys) with create-pull-request action:
|
||||
# Make changes to pull request here
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
```
|
||||
|
||||
### Push pull request branches to a fork
|
||||
@ -230,12 +230,14 @@ Note that if you choose to use this method (not give the machine account `write`
|
||||
|
||||
# Make changes to pull request here
|
||||
|
||||
- uses: peter-evans/create-pull-request@v4
|
||||
- uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
token: ${{ secrets.MACHINE_USER_PAT }}
|
||||
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
|
||||
|
||||
A GitHub App can be created for the sole purpose of generating tokens for use with GitHub actions.
|
||||
@ -273,7 +275,7 @@ GitHub App generated tokens are more secure than using a PAT because GitHub App
|
||||
# Make changes to pull request here
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
```
|
||||
@ -314,7 +316,7 @@ The action can use GPG to sign commits with a GPG key that you generate yourself
|
||||
# Make changes to pull request here
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
token: ${{ secrets.PAT }}
|
||||
committer: example <email@example.com>
|
||||
@ -344,7 +346,7 @@ jobs:
|
||||
# Make changes to pull request here
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
```
|
||||
|
||||
**Ubuntu container example:**
|
||||
@ -367,5 +369,5 @@ jobs:
|
||||
# Make changes to pull request here
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
```
|
||||
|
@ -19,8 +19,8 @@
|
||||
- [autopep8](#autopep8)
|
||||
- [Misc workflow tips](#misc-workflow-tips)
|
||||
- [Filtering push events](#filtering-push-events)
|
||||
- [Bypassing git hooks](#bypassing-git-hooks)
|
||||
- [Dynamic configuration using variables](#dynamic-configuration-using-variables)
|
||||
- [Setting the pull request body from a file](#setting-the-pull-request-body-from-a-file)
|
||||
- [Using a markdown template](#using-a-markdown-template)
|
||||
- [Debugging GitHub Actions](#debugging-github-actions)
|
||||
|
||||
@ -50,7 +50,7 @@ jobs:
|
||||
run: |
|
||||
git log --format='%aN <%aE>%n%cN <%cE>' | sort -u > AUTHORS
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
commit-message: update authors
|
||||
title: Update AUTHORS
|
||||
@ -82,7 +82,7 @@ jobs:
|
||||
git fetch origin main:main
|
||||
git reset --hard main
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
branch: production-promotion
|
||||
```
|
||||
@ -117,7 +117,7 @@ jobs:
|
||||
./git-chglog -o CHANGELOG.md
|
||||
rm git-chglog
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
commit-message: update changelog
|
||||
title: Update Changelog
|
||||
@ -154,7 +154,7 @@ jobs:
|
||||
npx -p npm-check-updates ncu -u
|
||||
npm install
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
token: ${{ secrets.PAT }}
|
||||
commit-message: Update dependencies
|
||||
@ -215,7 +215,7 @@ jobs:
|
||||
- name: Perform dependency resolution and write new lockfiles
|
||||
run: ./gradlew dependencies --write-locks
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
token: ${{ secrets.PAT }}
|
||||
commit-message: Update dependencies
|
||||
@ -250,7 +250,7 @@ jobs:
|
||||
cargo update
|
||||
cargo upgrade --to-lockfile
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
token: ${{ secrets.PAT }}
|
||||
commit-message: Update dependencies
|
||||
@ -308,7 +308,7 @@ jobs:
|
||||
# Update current release
|
||||
echo ${{ steps.swagger-ui.outputs.release_tag }} > swagger-ui.version
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
commit-message: Update swagger-ui to ${{ steps.swagger-ui.outputs.release_tag }}
|
||||
title: Update SwaggerUI to ${{ steps.swagger-ui.outputs.release_tag }}
|
||||
@ -352,7 +352,7 @@ jobs:
|
||||
git fetch upstream main:upstream-main
|
||||
git reset --hard upstream-main
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
token: ${{ secrets.PAT }}
|
||||
branch: upstream-changes
|
||||
@ -385,7 +385,7 @@ jobs:
|
||||
--domains quotes.toscrape.com \
|
||||
http://quotes.toscrape.com/
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
commit-message: update local website copy
|
||||
title: Automated Updates to Local Website Copy
|
||||
@ -482,7 +482,7 @@ jobs:
|
||||
echo "branch-name=$branch-name" >> $GITHUB_OUTPUT
|
||||
- name: Create Pull Request
|
||||
if: steps.autopep8.outputs.exit-code == 2
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
commit-message: autopep8 action fixes
|
||||
title: Fixes by autopep8 action
|
||||
@ -526,6 +526,18 @@ jobs:
|
||||
...
|
||||
```
|
||||
|
||||
### Bypassing git hooks
|
||||
|
||||
If you have git hooks that prevent the action from working correctly you can remove them before running the action.
|
||||
|
||||
```yml
|
||||
# Remove git hooks
|
||||
- run: rm -rf .git/hooks
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
```
|
||||
|
||||
### Dynamic configuration using variables
|
||||
|
||||
The following examples show how configuration for the action can be dynamically defined in a previous workflow step.
|
||||
@ -541,31 +553,12 @@ Note that the step where output variables are defined must have an id.
|
||||
echo "pr_title=$pr_title" >> $GITHUB_OUTPUT
|
||||
echo "pr_body=$pr_body" >> $GITHUB_OUTPUT
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
title: ${{ steps.vars.outputs.pr_title }}
|
||||
body: ${{ steps.vars.outputs.pr_body }}
|
||||
```
|
||||
|
||||
### Setting the pull request body from a file
|
||||
|
||||
This example shows how file content can be read into a variable and passed to the action.
|
||||
|
||||
```yml
|
||||
- id: get-pr-body
|
||||
run: |
|
||||
body=$(cat pr-body.txt)
|
||||
delimiter="$(openssl rand -hex 8)"
|
||||
echo "body<<$delimiter" >> $GITHUB_OUTPUT
|
||||
echo "$body" >> $GITHUB_OUTPUT
|
||||
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
body: ${{ steps.get-pr-body.outputs.body }}
|
||||
```
|
||||
|
||||
### Using a markdown template
|
||||
|
||||
In this example, a markdown template file is added to the repository at `.github/pull-request-template.md` with the following content.
|
||||
@ -586,7 +579,7 @@ The template is rendered using the [render-template](https://github.com/chuhlomi
|
||||
bar: that
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
body: ${{ steps.template.outputs.result }}
|
||||
```
|
||||
|
@ -1,6 +1,23 @@
|
||||
## Updating from `v4` to `v5`
|
||||
|
||||
### Behaviour changes
|
||||
|
||||
- The action will no longer leave the local repository checked out on the pull request `branch`. Instead, it will leave the repository checked out on the branch or commit that it was when the action started.
|
||||
- When using `add-paths`, uncommitted changes will no longer be destroyed. They will be stashed and restored at the end of the action run.
|
||||
|
||||
### What's new
|
||||
|
||||
- Adds input `body-path`, the path to a file containing the pull request body.
|
||||
- At the end of the action run the local repository is now checked out on the branch or commit that it was when the action started.
|
||||
- Any uncommitted tracked or untracked changes are now stashed and restored at the end of the action run. Currently, this can only occur when using the `add-paths` input, which allows for changes to not be committed. Previously, any uncommitted changes would be destroyed.
|
||||
- The proxy implementation has been revised but is not expected to have any change in behaviour. It continues to support the standard environment variables `http_proxy`, `https_proxy` and `no_proxy`.
|
||||
- Now sets the git `safe.directory` configuration for the local repository path. The configuration is removed when the action completes. Fixes issue https://github.com/peter-evans/create-pull-request/issues/1170.
|
||||
- Now determines the git directory path using the `git rev-parse --git-dir` command. This allows users with custom repository configurations to use the action.
|
||||
- Improved handling of the `team-reviewers` input and associated errors.
|
||||
|
||||
## Updating from `v3` to `v4`
|
||||
|
||||
### Breaking changes
|
||||
### Behaviour changes
|
||||
|
||||
- The `add-paths` input no longer accepts `-A` as a valid value. When committing all new and modified files the `add-paths` input should be omitted.
|
||||
|
||||
@ -14,7 +31,7 @@
|
||||
|
||||
## Updating from `v2` to `v3`
|
||||
|
||||
### Breaking changes
|
||||
### Behaviour changes
|
||||
|
||||
- The `author` input now defaults to the user who triggered the workflow run. This default is set via [action.yml](../action.yml) as `${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>`, where `github.actor` is the GitHub user account associated with the run. For example, `peter-evans <peter-evans@users.noreply.github.com>`.
|
||||
|
||||
@ -62,7 +79,7 @@
|
||||
|
||||
## Updating from `v1` to `v2`
|
||||
|
||||
### Breaking changes
|
||||
### Behaviour changes
|
||||
|
||||
- `v2` now expects repositories to be checked out with `actions/checkout@v2`
|
||||
|
||||
|
11328
package-lock.json
generated
11328
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
43
package.json
43
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-pull-request",
|
||||
"version": "4.0.0",
|
||||
"version": "5.0.0",
|
||||
"private": true,
|
||||
"description": "Creates a pull request for changes to your repository in the actions workspace",
|
||||
"main": "lib/main.js",
|
||||
@ -31,28 +31,29 @@
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.0",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@octokit/core": "^3.5.1",
|
||||
"@octokit/plugin-paginate-rest": "^2.17.0",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^5.13.0",
|
||||
"proxy-agent": "^5.0.0",
|
||||
"uuid": "^8.3.2"
|
||||
"@octokit/core": "^4.2.0",
|
||||
"@octokit/plugin-paginate-rest": "^5.0.1",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^6.8.1",
|
||||
"https-proxy-agent": "^5.0.1",
|
||||
"proxy-from-env": "^1.1.0",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^27.5.0",
|
||||
"@types/node": "^16.11.11",
|
||||
"@typescript-eslint/parser": "^5.5.0",
|
||||
"@vercel/ncc": "^0.32.0",
|
||||
"eslint": "^8.3.0",
|
||||
"eslint-import-resolver-typescript": "^2.5.0",
|
||||
"eslint-plugin-github": "^4.3.5",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-jest": "^26.1.5",
|
||||
"jest": "^28.1.0",
|
||||
"jest-circus": "^28.1.0",
|
||||
"jest-environment-jsdom": "^28.1.0",
|
||||
"@types/jest": "^29.5.1",
|
||||
"@types/node": "^18.16.0",
|
||||
"@typescript-eslint/parser": "^5.59.1",
|
||||
"@vercel/ncc": "^0.36.1",
|
||||
"eslint": "^8.39.0",
|
||||
"eslint-import-resolver-typescript": "^3.5.5",
|
||||
"eslint-plugin-github": "^4.7.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"jest": "^29.5.0",
|
||||
"jest-circus": "^29.4.2",
|
||||
"jest-environment-jsdom": "^29.5.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"prettier": "^2.5.0",
|
||||
"ts-jest": "^28.0.2",
|
||||
"typescript": "^4.5.2"
|
||||
"prettier": "^2.8.8",
|
||||
"ts-jest": "^29.1.0",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
|
@ -106,6 +106,13 @@ function splitLines(multilineString: string): string[] {
|
||||
.filter(x => x !== '')
|
||||
}
|
||||
|
||||
interface CreateOrUpdateBranchResult {
|
||||
action: string
|
||||
base: string
|
||||
hasDiffWithBase: boolean
|
||||
headSha: string
|
||||
}
|
||||
|
||||
export async function createOrUpdateBranch(
|
||||
git: GitCommandManager,
|
||||
commitMessage: string,
|
||||
@ -163,9 +170,8 @@ export async function createOrUpdateBranch(
|
||||
}
|
||||
}
|
||||
|
||||
// Remove uncommitted tracked and untracked changes
|
||||
await git.exec(['reset', '--hard'])
|
||||
await git.exec(['clean', '-f', '-d'])
|
||||
// Stash any uncommitted tracked and untracked changes
|
||||
const stashed = await git.stashPush(['--include-untracked'])
|
||||
|
||||
// Perform fetch and reset the working base
|
||||
// Commits made during the workflow will be removed
|
||||
@ -283,12 +289,13 @@ export async function createOrUpdateBranch(
|
||||
// Delete the temporary branch
|
||||
await git.exec(['branch', '--delete', '--force', tempBranch])
|
||||
|
||||
// Checkout the working base to leave the local repository as it was found
|
||||
await git.checkout(workingBase)
|
||||
|
||||
// Restore any stashed changes
|
||||
if (stashed) {
|
||||
await git.stashPop()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
interface CreateOrUpdateBranchResult {
|
||||
action: string
|
||||
base: string
|
||||
hasDiffWithBase: boolean
|
||||
headSha: string
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ export interface Inputs {
|
||||
pushToFork: string
|
||||
title: string
|
||||
body: string
|
||||
bodyPath: string
|
||||
labels: string[]
|
||||
assignees: string[]
|
||||
reviewers: string[]
|
||||
@ -35,14 +36,33 @@ export interface Inputs {
|
||||
export async function createPullRequest(inputs: Inputs): Promise<void> {
|
||||
let gitAuthHelper
|
||||
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)
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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('Save persisted git credentials')
|
||||
core.startGroup('Prepare git configuration')
|
||||
gitAuthHelper = new GitAuthHelper(git)
|
||||
await gitAuthHelper.addSafeDirectory()
|
||||
await gitAuthHelper.savePersistedAuth()
|
||||
core.endGroup()
|
||||
|
||||
@ -191,7 +211,7 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
|
||||
await git.push([
|
||||
'--force-with-lease',
|
||||
branchRemoteName,
|
||||
`HEAD:refs/heads/${inputs.branch}`
|
||||
`${inputs.branch}:refs/heads/${inputs.branch}`
|
||||
])
|
||||
core.endGroup()
|
||||
}
|
||||
@ -248,9 +268,10 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
|
||||
core.setFailed(utils.getErrorMessage(error))
|
||||
} finally {
|
||||
// Remove auth and restore persisted auth config if it existed
|
||||
core.startGroup('Restore persisted git credentials')
|
||||
core.startGroup('Restore git configuration')
|
||||
await gitAuthHelper.removeAuth()
|
||||
await gitAuthHelper.restorePersistedAuth()
|
||||
await gitAuthHelper.removeSafeDirectory()
|
||||
core.endGroup()
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,10 @@ import * as utils from './utils'
|
||||
|
||||
export class GitAuthHelper {
|
||||
private git: GitCommandManager
|
||||
private gitConfigPath: string
|
||||
private gitConfigPath = ''
|
||||
private workingDirectory: string
|
||||
private safeDirectoryConfigKey = 'safe.directory'
|
||||
private safeDirectoryAdded = false
|
||||
private extraheaderConfigKey: string
|
||||
private extraheaderConfigPlaceholderValue = 'AUTHORIZATION: basic ***'
|
||||
private extraheaderConfigValueRegex = '^AUTHORIZATION:'
|
||||
@ -15,15 +18,38 @@ export class GitAuthHelper {
|
||||
|
||||
constructor(git: GitCommandManager) {
|
||||
this.git = git
|
||||
this.gitConfigPath = path.join(
|
||||
this.git.getWorkingDirectory(),
|
||||
'.git',
|
||||
'config'
|
||||
)
|
||||
this.workingDirectory = this.git.getWorkingDirectory()
|
||||
const serverUrl = this.getServerUrl()
|
||||
this.extraheaderConfigKey = `http.${serverUrl.origin}/.extraheader`
|
||||
}
|
||||
|
||||
async addSafeDirectory(): Promise<void> {
|
||||
const exists = await this.git.configExists(
|
||||
this.safeDirectoryConfigKey,
|
||||
this.workingDirectory,
|
||||
true
|
||||
)
|
||||
if (!exists) {
|
||||
await this.git.config(
|
||||
this.safeDirectoryConfigKey,
|
||||
this.workingDirectory,
|
||||
true,
|
||||
true
|
||||
)
|
||||
this.safeDirectoryAdded = true
|
||||
}
|
||||
}
|
||||
|
||||
async removeSafeDirectory(): Promise<void> {
|
||||
if (this.safeDirectoryAdded) {
|
||||
await this.git.tryConfigUnset(
|
||||
this.safeDirectoryConfigKey,
|
||||
this.workingDirectory,
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async savePersistedAuth(): Promise<void> {
|
||||
// Save and unset persisted extraheader credential in git config if it exists
|
||||
this.persistedExtraheaderConfigValue = await this.getAndUnset()
|
||||
@ -106,6 +132,10 @@ export class GitAuthHelper {
|
||||
find: string,
|
||||
replace: string
|
||||
): Promise<void> {
|
||||
if (this.gitConfigPath.length === 0) {
|
||||
const gitDir = await this.git.getGitDirectory()
|
||||
this.gitConfigPath = path.join(this.workingDirectory, gitDir, 'config')
|
||||
}
|
||||
let content = (await fs.promises.readFile(this.gitConfigPath)).toString()
|
||||
const index = content.indexOf(find)
|
||||
if (index < 0 || index != content.lastIndexOf(find)) {
|
||||
@ -116,12 +146,6 @@ export class GitAuthHelper {
|
||||
}
|
||||
|
||||
private getServerUrl(): URL {
|
||||
// todo: remove GITHUB_URL after support for GHES Alpha is no longer needed
|
||||
// See https://github.com/actions/checkout/blob/main/src/url-helper.ts#L22-L29
|
||||
return new URL(
|
||||
process.env['GITHUB_SERVER_URL'] ||
|
||||
process.env['GITHUB_URL'] ||
|
||||
'https://github.com'
|
||||
)
|
||||
return new URL(process.env['GITHUB_SERVER_URL'] || 'https://github.com')
|
||||
}
|
||||
}
|
||||
|
@ -72,14 +72,15 @@ export class GitCommandManager {
|
||||
async config(
|
||||
configKey: string,
|
||||
configValue: string,
|
||||
globalConfig?: boolean
|
||||
globalConfig?: boolean,
|
||||
add?: boolean
|
||||
): Promise<void> {
|
||||
await this.exec([
|
||||
'config',
|
||||
globalConfig ? '--global' : '--local',
|
||||
configKey,
|
||||
configValue
|
||||
])
|
||||
const args: string[] = ['config', globalConfig ? '--global' : '--local']
|
||||
if (add) {
|
||||
args.push('--add')
|
||||
}
|
||||
args.push(...[configKey, configValue])
|
||||
await this.exec(args)
|
||||
}
|
||||
|
||||
async configExists(
|
||||
@ -145,6 +146,10 @@ export class GitCommandManager {
|
||||
return output.stdout.trim().split(`${configKey} `)[1]
|
||||
}
|
||||
|
||||
getGitDirectory(): Promise<string> {
|
||||
return this.revParse('--git-dir')
|
||||
}
|
||||
|
||||
getWorkingDirectory(): string {
|
||||
return this.workingDirectory
|
||||
}
|
||||
@ -210,6 +215,23 @@ export class GitCommandManager {
|
||||
return output.stdout.trim()
|
||||
}
|
||||
|
||||
async stashPush(options?: string[]): Promise<boolean> {
|
||||
const args = ['stash', 'push']
|
||||
if (options) {
|
||||
args.push(...options)
|
||||
}
|
||||
const output = await this.exec(args)
|
||||
return output.stdout.trim() !== 'No local changes to save'
|
||||
}
|
||||
|
||||
async stashPop(options?: string[]): Promise<void> {
|
||||
const args = ['stash', 'pop']
|
||||
if (options) {
|
||||
args.push(...options)
|
||||
}
|
||||
await this.exec(args)
|
||||
}
|
||||
|
||||
async status(options?: string[]): Promise<string> {
|
||||
const args = ['status']
|
||||
if (options) {
|
||||
|
@ -3,8 +3,8 @@ import {Inputs} from './create-pull-request'
|
||||
import {Octokit, OctokitOptions} from './octokit-client'
|
||||
import * as utils from './utils'
|
||||
|
||||
const ERROR_PR_REVIEW_FROM_AUTHOR =
|
||||
'Review cannot be requested from pull request author'
|
||||
const ERROR_PR_REVIEW_TOKEN_SCOPE =
|
||||
'Validation Failed: "Could not resolve to a node with the global id of'
|
||||
|
||||
interface Repository {
|
||||
owner: string
|
||||
@ -159,8 +159,9 @@ export class GitHubHelper {
|
||||
core.info(`Requesting reviewers '${inputs.reviewers}'`)
|
||||
}
|
||||
if (inputs.teamReviewers.length > 0) {
|
||||
requestReviewersParams['team_reviewers'] = inputs.teamReviewers
|
||||
core.info(`Requesting team reviewers '${inputs.teamReviewers}'`)
|
||||
const teams = utils.stripOrgPrefixFromTeams(inputs.teamReviewers)
|
||||
requestReviewersParams['team_reviewers'] = teams
|
||||
core.info(`Requesting team reviewers '${teams}'`)
|
||||
}
|
||||
if (Object.keys(requestReviewersParams).length > 0) {
|
||||
try {
|
||||
@ -170,11 +171,12 @@ export class GitHubHelper {
|
||||
...requestReviewersParams
|
||||
})
|
||||
} catch (e) {
|
||||
if (utils.getErrorMessage(e).includes(ERROR_PR_REVIEW_FROM_AUTHOR)) {
|
||||
core.warning(ERROR_PR_REVIEW_FROM_AUTHOR)
|
||||
} else {
|
||||
throw e
|
||||
if (utils.getErrorMessage(e).includes(ERROR_PR_REVIEW_TOKEN_SCOPE)) {
|
||||
core.error(
|
||||
`Unable to request reviewers. If requesting team reviewers a 'repo' scoped PAT is required.`
|
||||
)
|
||||
}
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ async function run(): Promise<void> {
|
||||
pushToFork: core.getInput('push-to-fork'),
|
||||
title: core.getInput('title'),
|
||||
body: core.getInput('body'),
|
||||
bodyPath: core.getInput('body-path'),
|
||||
labels: utils.getInputAsArray('labels'),
|
||||
assignees: utils.getInputAsArray('assignees'),
|
||||
reviewers: utils.getInputAsArray('reviewers'),
|
||||
|
@ -1,7 +1,8 @@
|
||||
import {Octokit as Core} from '@octokit/core'
|
||||
import {paginateRest} from '@octokit/plugin-paginate-rest'
|
||||
import {restEndpointMethods} from '@octokit/plugin-rest-endpoint-methods'
|
||||
import ProxyAgent from 'proxy-agent'
|
||||
import {HttpsProxyAgent} from 'https-proxy-agent'
|
||||
import {getProxyForUrl} from 'proxy-from-env'
|
||||
export {RestEndpointMethodTypes} from '@octokit/plugin-rest-endpoint-methods'
|
||||
export {OctokitOptions} from '@octokit/core/dist-types/types'
|
||||
|
||||
@ -13,16 +14,10 @@ export const Octokit = Core.plugin(
|
||||
|
||||
// Octokit plugin to support the standard environment variables http_proxy, https_proxy and no_proxy
|
||||
function autoProxyAgent(octokit: Core) {
|
||||
const proxy =
|
||||
process.env.https_proxy ||
|
||||
process.env.HTTPS_PROXY ||
|
||||
process.env.http_proxy ||
|
||||
process.env.HTTP_PROXY
|
||||
|
||||
if (!proxy) return
|
||||
|
||||
const agent = new ProxyAgent()
|
||||
octokit.hook.before('request', options => {
|
||||
options.request.agent = agent
|
||||
const proxy = getProxyForUrl(options.baseUrl)
|
||||
if (proxy) {
|
||||
options.request.agent = new HttpsProxyAgent(proxy)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
14
src/utils.ts
14
src/utils.ts
@ -16,6 +16,16 @@ export function getStringAsArray(str: string): string[] {
|
||||
.filter(x => x !== '')
|
||||
}
|
||||
|
||||
export function stripOrgPrefixFromTeams(teams: string[]): string[] {
|
||||
return teams.map(team => {
|
||||
const slashIndex = team.lastIndexOf('/')
|
||||
if (slashIndex > 0) {
|
||||
return team.substring(slashIndex + 1)
|
||||
}
|
||||
return team
|
||||
})
|
||||
}
|
||||
|
||||
export function getRepoPath(relativePath?: string): string {
|
||||
let githubWorkspacePath = process.env['GITHUB_WORKSPACE']
|
||||
if (!githubWorkspacePath) {
|
||||
@ -159,6 +169,10 @@ export function fileExistsSync(path: string): boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
export function readFile(path: string): string {
|
||||
return fs.readFileSync(path, 'utf-8')
|
||||
}
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
function hasErrorCode(error: any): error is {code: string} {
|
||||
return typeof (error && error.code) === 'string'
|
||||
|
Reference in New Issue
Block a user