Compare commits
69 Commits
Author | SHA1 | Date | |
---|---|---|---|
c58bcf269b | |||
25f1937529 | |||
2d4402547d | |||
926a201444 | |||
ce190a9972 | |||
9fc91d93e9 | |||
6c4c6cfe81 | |||
633a5a9752 | |||
02efff68da | |||
034fcb0bf3 | |||
42beb85339 | |||
a3546365cd | |||
1e681e3226 | |||
8f92797560 | |||
c64379e4f4 | |||
10454726b6 | |||
1cd6df66ac | |||
32e97fc746 | |||
2ba41ede85 | |||
942e5a917e | |||
981b4699e5 | |||
4a0f9a8513 | |||
c006a630f0 | |||
1985abb7f4 | |||
5294a5ed9d | |||
b793f780d4 | |||
f5bdca7bbf | |||
59815b27ea | |||
eb6967ba69 | |||
1fbc61676c | |||
139c557742 | |||
e572f56030 | |||
13fa7b0c66 | |||
3cc54e847d | |||
0a565da02b | |||
cc836600d9 | |||
b7277ab0b4 | |||
72cf0929ae | |||
53ed82a297 | |||
3a6bc1b6c6 | |||
219a33fe88 | |||
384bd7f976 | |||
4c77294175 | |||
d94a826899 | |||
0785201fba | |||
63aac9338f | |||
8605c43792 | |||
0c8901cc91 | |||
6b1053d0d8 | |||
b2a409b0a3 | |||
ec02db74e9 | |||
029414bc07 | |||
9cd16daf06 | |||
6c5dc224d1 | |||
9c7a97affd | |||
c29821586c | |||
9d7ad21b2f | |||
f09d6ed256 | |||
d88643b9ac | |||
184d576617 | |||
396429353a | |||
efd26f0872 | |||
bc73bc700a | |||
8f257d093e | |||
7ccbe5d7c3 | |||
014f5c1fb1 | |||
4cf9647c0e | |||
8a55f622b6 | |||
744c8ceb5d |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -124,7 +124,7 @@ jobs:
|
||||
name: dist
|
||||
path: dist
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
with:
|
||||
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
|
||||
commit-message: 'build: update distribution'
|
||||
|
4
.github/workflows/cpr-example-command.yml
vendored
4
.github/workflows/cpr-example-command.yml
vendored
@ -29,8 +29,8 @@ jobs:
|
||||
labels: |
|
||||
report
|
||||
automated pr
|
||||
assignees: retepsnave
|
||||
reviewers: retepsnave
|
||||
assignees: peter-evans
|
||||
reviewers: peter-evans
|
||||
milestone: 1
|
||||
draft: false
|
||||
branch: example-patches
|
||||
|
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": "testv5",
|
||||
"permission": "admin",
|
||||
"repository": "peter-evans/create-pull-request-tests",
|
||||
"named_args": true
|
||||
},
|
||||
{
|
||||
"command": "clean",
|
||||
"permission": "admin",
|
||||
|
2
.github/workflows/update-major-version.yml
vendored
2
.github/workflows/update-major-version.yml
vendored
@ -11,8 +11,8 @@ on:
|
||||
type: choice
|
||||
description: The major version tag to update
|
||||
options:
|
||||
- v5
|
||||
- v6
|
||||
- v7
|
||||
|
||||
jobs:
|
||||
tag:
|
||||
|
24
README.md
24
README.md
@ -15,13 +15,13 @@ Create Pull Request action will:
|
||||
- tracked (modified) files
|
||||
- commits made during the workflow that have not been pushed
|
||||
2. Commit all changes to a new branch, or update an existing pull request branch.
|
||||
3. Create or update a pull request to merge the branch into the base—the branch checked out in the workflow.
|
||||
3. Create a pull request to merge the new branch into the base—the branch checked out in the workflow.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Concepts, guidelines and advanced usage](docs/concepts-guidelines.md)
|
||||
- [Examples](docs/examples.md)
|
||||
- [Updating to v7](docs/updating.md)
|
||||
- [Updating to v6](docs/updating.md)
|
||||
- [Common issues](docs/common-issues.md)
|
||||
|
||||
## Usage
|
||||
@ -99,7 +99,7 @@ Other token options:
|
||||
#### branch-token
|
||||
|
||||
The action first creates a branch, and then creates a pull request for the branch.
|
||||
For some rare use cases it can be useful, or even necessary, to use different tokens for these operations.
|
||||
For some rare use cases it can be useful, or even neccessary, to use different tokens for these operations.
|
||||
It is not advisable to use this input unless you know you need to.
|
||||
|
||||
#### commit-message
|
||||
@ -246,6 +246,24 @@ Note that the repository must be checked out on a branch with a remote, it won't
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
```
|
||||
|
||||
### Create a project card
|
||||
|
||||
To create a project card for the pull request, pass the `pull-request-number` step output to [create-or-update-project-card](https://github.com/peter-evans/create-or-update-project-card) action.
|
||||
|
||||
```yml
|
||||
- name: Create Pull Request
|
||||
id: cpr
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
|
||||
- name: Create or Update Project Card
|
||||
if: ${{ steps.cpr.outputs.pull-request-number }}
|
||||
uses: peter-evans/create-or-update-project-card@v2
|
||||
with:
|
||||
project-name: My project
|
||||
column-name: My column
|
||||
issue-number: ${{ steps.cpr.outputs.pull-request-number }}
|
||||
```
|
||||
|
||||
### Auto-merge
|
||||
|
||||
Auto-merge can be enabled on a pull request allowing it to be automatically merged once requirements have been satisfied.
|
||||
|
@ -250,15 +250,11 @@ describe('create-or-update-branch tests', () => {
|
||||
expect(branchCommits.length).toEqual(1)
|
||||
expect(branchCommits[0].subject).toEqual('Test changes')
|
||||
expect(branchCommits[0].changes.length).toEqual(3)
|
||||
expect(branchCommits[0].changes[0].mode).toEqual('100755')
|
||||
expect(branchCommits[0].changes[0].path).toEqual(UNTRACKED_EXE_FILE)
|
||||
expect(branchCommits[0].changes[0].status).toEqual('A')
|
||||
expect(branchCommits[0].changes[1].mode).toEqual('100644')
|
||||
expect(branchCommits[0].changes[1].path).toEqual(TRACKED_FILE)
|
||||
expect(branchCommits[0].changes[1].status).toEqual('M')
|
||||
expect(branchCommits[0].changes[2].mode).toEqual('100644')
|
||||
expect(branchCommits[0].changes[2].path).toEqual(UNTRACKED_FILE)
|
||||
expect(branchCommits[0].changes[2].status).toEqual('A')
|
||||
expect(branchCommits[0].changes).toEqual([
|
||||
{mode: '100755', path: UNTRACKED_EXE_FILE, status: 'A'},
|
||||
{mode: '100644', path: TRACKED_FILE, status: 'M'},
|
||||
{mode: '100644', path: UNTRACKED_FILE, status: 'A'}
|
||||
])
|
||||
})
|
||||
|
||||
it('tests buildBranchCommits with addition and deletion', async () => {
|
||||
@ -276,15 +272,11 @@ describe('create-or-update-branch tests', () => {
|
||||
expect(branchCommits.length).toEqual(1)
|
||||
expect(branchCommits[0].subject).toEqual('Test changes')
|
||||
expect(branchCommits[0].changes.length).toEqual(3)
|
||||
expect(branchCommits[0].changes[0].mode).toEqual('100644')
|
||||
expect(branchCommits[0].changes[0].path).toEqual(TRACKED_FILE)
|
||||
expect(branchCommits[0].changes[0].status).toEqual('D')
|
||||
expect(branchCommits[0].changes[1].mode).toEqual('100644')
|
||||
expect(branchCommits[0].changes[1].path).toEqual(UNTRACKED_FILE)
|
||||
expect(branchCommits[0].changes[1].status).toEqual('A')
|
||||
expect(branchCommits[0].changes[2].mode).toEqual('100644')
|
||||
expect(branchCommits[0].changes[2].path).toEqual(TRACKED_FILE_NEW_PATH)
|
||||
expect(branchCommits[0].changes[2].status).toEqual('A')
|
||||
expect(branchCommits[0].changes).toEqual([
|
||||
{mode: '100644', path: TRACKED_FILE, status: 'D'},
|
||||
{mode: '100644', path: UNTRACKED_FILE, status: 'A'},
|
||||
{mode: '100644', path: TRACKED_FILE_NEW_PATH, status: 'A'}
|
||||
])
|
||||
})
|
||||
|
||||
it('tests buildBranchCommits with multiple commits', async () => {
|
||||
@ -302,13 +294,10 @@ describe('create-or-update-branch tests', () => {
|
||||
expect(branchCommits[i].subject).toEqual(`Test changes ${i}`)
|
||||
expect(branchCommits[i].changes.length).toEqual(2)
|
||||
const untrackedFileStatus = i == 0 ? 'A' : 'M'
|
||||
|
||||
expect(branchCommits[i].changes[0].mode).toEqual('100644')
|
||||
expect(branchCommits[i].changes[0].path).toEqual(TRACKED_FILE)
|
||||
expect(branchCommits[i].changes[0].status).toEqual('M')
|
||||
expect(branchCommits[i].changes[1].mode).toEqual('100644')
|
||||
expect(branchCommits[i].changes[1].path).toEqual(UNTRACKED_FILE)
|
||||
expect(branchCommits[i].changes[1].status).toEqual(untrackedFileStatus)
|
||||
expect(branchCommits[i].changes).toEqual([
|
||||
{mode: '100644', path: TRACKED_FILE, status: 'M'},
|
||||
{mode: '100644', path: UNTRACKED_FILE, status: untrackedFileStatus}
|
||||
])
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -19,17 +19,14 @@ git clone git://127.0.0.1/repos/test-base.git /git/local/repos/test-base
|
||||
cd /git/local/repos/test-base
|
||||
git config --global user.email "you@example.com"
|
||||
git config --global user.name "Your Name"
|
||||
echo "#test-base" > README→TEMP.md
|
||||
echo "#test-base" > README.md
|
||||
git add .
|
||||
git commit -m "initial commit"
|
||||
git commit --allow-empty -m "empty commit for tests"
|
||||
echo "#test-base :sparkles:" > README→TEMP.md
|
||||
echo "#test-base :sparkles:" > README.md
|
||||
git add .
|
||||
git commit -m "add sparkles" -m "Change description:
|
||||
- updates README→TEMP.md to add sparkles to the title"
|
||||
mv README→TEMP.md README.md
|
||||
git add .
|
||||
git commit -m "rename readme"
|
||||
- updates README.md to add sparkles to the title"
|
||||
git push -u
|
||||
git log -1 --pretty=oneline
|
||||
git config --global --unset user.email
|
||||
|
@ -11,16 +11,15 @@ describe('git-command-manager integration tests', () => {
|
||||
})
|
||||
|
||||
it('tests getCommit', async () => {
|
||||
const initialCommit = await git.getCommit('HEAD^^^')
|
||||
const emptyCommit = await git.getCommit('HEAD^^')
|
||||
const modifiedCommit = await git.getCommit('HEAD^')
|
||||
const initialCommit = await git.getCommit('HEAD^^')
|
||||
const emptyCommit = await git.getCommit('HEAD^')
|
||||
const headCommit = await git.getCommit('HEAD')
|
||||
|
||||
expect(initialCommit.subject).toEqual('initial commit')
|
||||
expect(initialCommit.signed).toBeFalsy()
|
||||
expect(initialCommit.changes[0].mode).toEqual('100644')
|
||||
expect(initialCommit.changes[0].status).toEqual('A')
|
||||
expect(initialCommit.changes[0].path).toEqual('README→TEMP.md') // filename contains unicode
|
||||
expect(initialCommit.changes).toEqual([
|
||||
{mode: '100644', status: 'A', path: 'README.md'}
|
||||
])
|
||||
|
||||
expect(emptyCommit.subject).toEqual('empty commit for tests')
|
||||
expect(emptyCommit.tree).toEqual(initialCommit.tree) // empty commits have no tree and reference the parent's
|
||||
@ -28,21 +27,11 @@ describe('git-command-manager integration tests', () => {
|
||||
expect(emptyCommit.signed).toBeFalsy()
|
||||
expect(emptyCommit.changes).toEqual([])
|
||||
|
||||
expect(modifiedCommit.subject).toEqual('add sparkles')
|
||||
expect(modifiedCommit.parents[0]).toEqual(emptyCommit.sha)
|
||||
expect(modifiedCommit.signed).toBeFalsy()
|
||||
expect(modifiedCommit.changes[0].mode).toEqual('100644')
|
||||
expect(modifiedCommit.changes[0].status).toEqual('M')
|
||||
expect(modifiedCommit.changes[0].path).toEqual('README→TEMP.md')
|
||||
|
||||
expect(headCommit.subject).toEqual('rename readme')
|
||||
expect(headCommit.parents[0]).toEqual(modifiedCommit.sha)
|
||||
expect(headCommit.subject).toEqual('add sparkles')
|
||||
expect(headCommit.parents[0]).toEqual(emptyCommit.sha)
|
||||
expect(headCommit.signed).toBeFalsy()
|
||||
expect(headCommit.changes[0].mode).toEqual('100644')
|
||||
expect(headCommit.changes[0].status).toEqual('A')
|
||||
expect(headCommit.changes[0].path).toEqual('README.md')
|
||||
expect(headCommit.changes[1].mode).toEqual('100644')
|
||||
expect(headCommit.changes[1].status).toEqual('D')
|
||||
expect(headCommit.changes[1].path).toEqual('README→TEMP.md')
|
||||
expect(headCommit.changes).toEqual([
|
||||
{mode: '100644', status: 'M', path: 'README.md'}
|
||||
])
|
||||
})
|
||||
})
|
||||
|
16
dist/790.index.js
vendored
16
dist/790.index.js
vendored
@ -1,16 +0,0 @@
|
||||
"use strict";
|
||||
exports.id = 790;
|
||||
exports.ids = [790];
|
||||
exports.modules = {
|
||||
|
||||
/***/ 790:
|
||||
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
||||
|
||||
var N=Object.defineProperty;var c=(_,a)=>N(_,"name",{value:a,configurable:!0});__webpack_require__(3024),__webpack_require__(6760);const node=__webpack_require__(117);__webpack_require__(7067),__webpack_require__(4708),__webpack_require__(8522),__webpack_require__(7075),__webpack_require__(4573),__webpack_require__(7975),__webpack_require__(3465),__webpack_require__(3136),__webpack_require__(7030);let s=0;const S={START_BOUNDARY:s++,HEADER_FIELD_START:s++,HEADER_FIELD:s++,HEADER_VALUE_START:s++,HEADER_VALUE:s++,HEADER_VALUE_ALMOST_DONE:s++,HEADERS_ALMOST_DONE:s++,PART_DATA_START:s++,PART_DATA:s++,END:s++};let f=1;const F={PART_BOUNDARY:f,LAST_BOUNDARY:f*=2},LF=10,CR=13,SPACE=32,HYPHEN=45,COLON=58,A=97,Z=122,lower=c(_=>_|32,"lower"),noop=c(()=>{},"noop");class MultipartParser{static{c(this,"MultipartParser")}constructor(a){this.index=0,this.flags=0,this.onHeaderEnd=noop,this.onHeaderField=noop,this.onHeadersEnd=noop,this.onHeaderValue=noop,this.onPartBegin=noop,this.onPartData=noop,this.onPartEnd=noop,this.boundaryChars={},a=`\r
|
||||
--`+a;const t=new Uint8Array(a.length);for(let n=0;n<a.length;n++)t[n]=a.charCodeAt(n),this.boundaryChars[t[n]]=!0;this.boundary=t,this.lookbehind=new Uint8Array(this.boundary.length+8),this.state=S.START_BOUNDARY}write(a){let t=0;const n=a.length;let E=this.index,{lookbehind:d,boundary:h,boundaryChars:H,index:e,state:o,flags:l}=this;const b=this.boundary.length,m=b-1,O=a.length;let r,P;const u=c(D=>{this[D+"Mark"]=t},"mark"),i=c(D=>{delete this[D+"Mark"]},"clear"),T=c((D,p,R,g)=>{(p===void 0||p!==R)&&this[D](g&&g.subarray(p,R))},"callback"),L=c((D,p)=>{const R=D+"Mark";R in this&&(p?(T(D,this[R],t,a),delete this[R]):(T(D,this[R],a.length,a),this[R]=0))},"dataCallback");for(t=0;t<n;t++)switch(r=a[t],o){case S.START_BOUNDARY:if(e===h.length-2){if(r===HYPHEN)l|=F.LAST_BOUNDARY;else if(r!==CR)return;e++;break}else if(e-1===h.length-2){if(l&F.LAST_BOUNDARY&&r===HYPHEN)o=S.END,l=0;else if(!(l&F.LAST_BOUNDARY)&&r===LF)e=0,T("onPartBegin"),o=S.HEADER_FIELD_START;else return;break}r!==h[e+2]&&(e=-2),r===h[e+2]&&e++;break;case S.HEADER_FIELD_START:o=S.HEADER_FIELD,u("onHeaderField"),e=0;case S.HEADER_FIELD:if(r===CR){i("onHeaderField"),o=S.HEADERS_ALMOST_DONE;break}if(e++,r===HYPHEN)break;if(r===COLON){if(e===1)return;L("onHeaderField",!0),o=S.HEADER_VALUE_START;break}if(P=lower(r),P<A||P>Z)return;break;case S.HEADER_VALUE_START:if(r===SPACE)break;u("onHeaderValue"),o=S.HEADER_VALUE;case S.HEADER_VALUE:r===CR&&(L("onHeaderValue",!0),T("onHeaderEnd"),o=S.HEADER_VALUE_ALMOST_DONE);break;case S.HEADER_VALUE_ALMOST_DONE:if(r!==LF)return;o=S.HEADER_FIELD_START;break;case S.HEADERS_ALMOST_DONE:if(r!==LF)return;T("onHeadersEnd"),o=S.PART_DATA_START;break;case S.PART_DATA_START:o=S.PART_DATA,u("onPartData");case S.PART_DATA:if(E=e,e===0){for(t+=m;t<O&&!(a[t]in H);)t+=b;t-=m,r=a[t]}if(e<h.length)h[e]===r?(e===0&&L("onPartData",!0),e++):e=0;else if(e===h.length)e++,r===CR?l|=F.PART_BOUNDARY:r===HYPHEN?l|=F.LAST_BOUNDARY:e=0;else if(e-1===h.length)if(l&F.PART_BOUNDARY){if(e=0,r===LF){l&=~F.PART_BOUNDARY,T("onPartEnd"),T("onPartBegin"),o=S.HEADER_FIELD_START;break}}else l&F.LAST_BOUNDARY&&r===HYPHEN?(T("onPartEnd"),o=S.END,l=0):e=0;if(e>0)d[e-1]=r;else if(E>0){const D=new Uint8Array(d.buffer,d.byteOffset,d.byteLength);T("onPartData",0,E,D),E=0,u("onPartData"),t--}break;case S.END:break;default:throw new Error(`Unexpected state entered: ${o}`)}L("onHeaderField"),L("onHeaderValue"),L("onPartData"),this.index=e,this.state=o,this.flags=l}end(){if(this.state===S.HEADER_FIELD_START&&this.index===0||this.state===S.PART_DATA&&this.index===this.boundary.length)this.onPartEnd();else if(this.state!==S.END)throw new Error("MultipartParser.end(): stream ended unexpectedly")}}function _fileName(_){const a=_.match(/\bfilename=("(.*?)"|([^()<>@,;:\\"/[\]?={}\s\t]+))($|;\s)/i);if(!a)return;const t=a[2]||a[3]||"";let n=t.slice(t.lastIndexOf("\\")+1);return n=n.replace(/%22/g,'"'),n=n.replace(/&#(\d{4});/g,(E,d)=>String.fromCharCode(d)),n}c(_fileName,"_fileName");async function toFormData(_,a){if(!/multipart/i.test(a))throw new TypeError("Failed to fetch");const t=a.match(/boundary=(?:"([^"]+)"|([^;]+))/i);if(!t)throw new TypeError("no or bad content-type header, no multipart boundary");const n=new MultipartParser(t[1]||t[2]);let E,d,h,H,e,o;const l=[],b=new node.FormData,m=c(i=>{h+=u.decode(i,{stream:!0})},"onPartData"),O=c(i=>{l.push(i)},"appendToFile"),r=c(()=>{const i=new node.File(l,o,{type:e});b.append(H,i)},"appendFileToFormData"),P=c(()=>{b.append(H,h)},"appendEntryToFormData"),u=new TextDecoder("utf-8");u.decode(),n.onPartBegin=function(){n.onPartData=m,n.onPartEnd=P,E="",d="",h="",H="",e="",o=null,l.length=0},n.onHeaderField=function(i){E+=u.decode(i,{stream:!0})},n.onHeaderValue=function(i){d+=u.decode(i,{stream:!0})},n.onHeaderEnd=function(){if(d+=u.decode(),E=E.toLowerCase(),E==="content-disposition"){const i=d.match(/\bname=("([^"]*)"|([^()<>@,;:\\"/[\]?={}\s\t]+))/i);i&&(H=i[2]||i[3]||""),o=_fileName(d),o&&(n.onPartData=O,n.onPartEnd=r)}else E==="content-type"&&(e=d);d="",E=""};for await(const i of _)n.write(i);return n.end(),b}c(toFormData,"toFormData"),exports.toFormData=toFormData;
|
||||
|
||||
|
||||
/***/ })
|
||||
|
||||
};
|
||||
;
|
29637
dist/index.js
vendored
29637
dist/index.js
vendored
File diff suppressed because it is too large
Load Diff
@ -231,7 +231,7 @@ It will use their own fork to push code and create the pull request.
|
||||
|
||||
1. Create a new GitHub user and login.
|
||||
2. Fork the repository that you will be creating pull requests in.
|
||||
3. Create a Classic [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) with `repo` and `workflow` scopes.
|
||||
3. Create a Classic [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) with `repo` scope.
|
||||
4. Logout and log back into your main user account.
|
||||
5. Add a secret to your repository containing the above PAT.
|
||||
6. As shown in the following example workflow, set the `push-to-fork` input to the full repository name of the fork.
|
||||
@ -303,7 +303,7 @@ GitHub App generated tokens can be configured with fine-grained permissions and
|
||||
- Uncheck `Active` under `Webhook`. You do not need to enter a `Webhook URL`.
|
||||
- Under `Repository permissions: Contents` select `Access: Read & write`.
|
||||
- Under `Repository permissions: Pull requests` select `Access: Read & write`.
|
||||
- Under `Repository permissions: Workflows` select `Access: Read & write`.
|
||||
- Under `Repository permissions: Workflows` select `Access: Read-only`.
|
||||
- **NOTE**: Only needed if pull requests could contain changes to Actions workflows.
|
||||
- Under `Organization permissions: Members` select `Access: Read-only`.
|
||||
- **NOTE**: Only needed if you would like add teams as reviewers to PRs.
|
||||
|
@ -22,7 +22,7 @@
|
||||
- [Dynamic configuration using variables](#dynamic-configuration-using-variables)
|
||||
- [Using a markdown template](#using-a-markdown-template)
|
||||
- [Debugging GitHub Actions](#debugging-github-actions)
|
||||
- [Show an annotation message for a created pull request](#show-an-annotation-message-for-a-created-pull-request)
|
||||
|
||||
|
||||
## Use case: Create a pull request to update X on push
|
||||
|
||||
@ -324,7 +324,7 @@ jobs:
|
||||
|
||||
### Keep a fork up-to-date with its upstream
|
||||
|
||||
This example is designed to be run in a separate repository from the fork repository itself.
|
||||
This example is designed to be run in a seperate repository from the fork repository itself.
|
||||
The aim of this is to prevent committing anything to the fork's default branch would cause it to differ from the upstream.
|
||||
|
||||
In the following example workflow, `owner/repo` is the upstream repository and `fork-owner/repo` is the fork. It assumes the default branch of the upstream repository is called `main`.
|
||||
@ -612,30 +612,3 @@ To enable step debug logging set the secret `ACTIONS_STEP_DEBUG` to `true` in th
|
||||
MATRIX_CONTEXT: ${{ toJson(matrix) }}
|
||||
run: echo "$MATRIX_CONTEXT"
|
||||
```
|
||||
|
||||
### Show an annotation message for a created pull request
|
||||
|
||||
Showing an annotation message for a created or updated pull request allows you to confirm the pull request easily, such as by visiting the link. This can be achieved by adding a step that uses the [`notice` workflow command](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions?tool=bash#setting-a-notice-message).
|
||||
|
||||
For example:
|
||||
|
||||
```yml
|
||||
- name: Create Pull Request
|
||||
id: cpr
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
|
||||
- name: Show message for created Pull Request
|
||||
if: ${{ steps.cpr.outputs.pull-request-url && steps.cpr.outputs.pull-request-operation != 'none' }}
|
||||
shell: bash
|
||||
env:
|
||||
PR_URL: ${{ steps.cpr.outputs.pull-request-url }}
|
||||
PR_OPERATION: ${{ steps.cpr.outputs.pull-request-operation }}
|
||||
run: |
|
||||
echo "::notice::${PR_URL} was ${PR_OPERATION}."
|
||||
```
|
||||
|
||||
In this example, when a pull request is created, you will be able to see the following message on an action run page (e.g., `/actions/runs/12812393039`):
|
||||
|
||||
```
|
||||
https://github.com/peter-evans/create-pull-request/pull/1 was created.
|
||||
```
|
||||
|
576
package-lock.json
generated
576
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@ -29,35 +29,35 @@
|
||||
},
|
||||
"homepage": "https://github.com/peter-evans/create-pull-request",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.11.1",
|
||||
"@actions/core": "^1.10.1",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@octokit/core": "^6.1.4",
|
||||
"@octokit/plugin-paginate-rest": "^11.4.3",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^13.3.1",
|
||||
"@octokit/plugin-throttling": "^9.4.0",
|
||||
"node-fetch-native": "^1.6.6",
|
||||
"p-limit": "^6.2.0",
|
||||
"@octokit/core": "^6.1.2",
|
||||
"@octokit/plugin-paginate-rest": "^11.3.3",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^13.2.4",
|
||||
"@octokit/plugin-throttling": "^9.3.1",
|
||||
"p-limit": "^6.1.0",
|
||||
"proxy-from-env": "^1.1.0",
|
||||
"undici": "^6.19.8",
|
||||
"uuid": "^9.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "^18.19.76",
|
||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||
"@typescript-eslint/parser": "^7.18.0",
|
||||
"@vercel/ncc": "^0.38.3",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-import-resolver-typescript": "^3.8.3",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^18.19.46",
|
||||
"@typescript-eslint/eslint-plugin": "^7.17.0",
|
||||
"@typescript-eslint/parser": "^7.17.0",
|
||||
"@vercel/ncc": "^0.38.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.3",
|
||||
"eslint-plugin-github": "^4.10.2",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-jest": "^27.9.0",
|
||||
"eslint-plugin-prettier": "^5.2.3",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"jest": "^29.7.0",
|
||||
"jest-circus": "^29.7.0",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"prettier": "^3.5.2",
|
||||
"ts-jest": "^29.2.6",
|
||||
"typescript": "^5.7.3",
|
||||
"undici": "^6.21.1"
|
||||
"prettier": "^3.3.3",
|
||||
"ts-jest": "^29.2.5",
|
||||
"typescript": "^5.5.4"
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import * as core from '@actions/core'
|
||||
import {GitCommandManager, Commit} from './git-command-manager'
|
||||
import {v4 as uuidv4} from 'uuid'
|
||||
import * as utils from './utils'
|
||||
|
||||
const CHERRYPICK_EMPTY =
|
||||
'The previous cherry-pick is now empty, possibly due to conflict resolution.'
|
||||
@ -19,7 +18,7 @@ export async function getWorkingBaseAndType(
|
||||
): Promise<[string, WorkingBaseType]> {
|
||||
const symbolicRefResult = await git.exec(
|
||||
['symbolic-ref', 'HEAD', '--short'],
|
||||
{allowAllExitCodes: true}
|
||||
true
|
||||
)
|
||||
if (symbolicRefResult.exitCode == 0) {
|
||||
// A ref is checked out
|
||||
@ -132,22 +131,13 @@ async function commitsHaveDiff(
|
||||
branch2: string,
|
||||
depth: number
|
||||
): Promise<boolean> {
|
||||
// Some action use cases lead to the depth being a very large number and the diff fails.
|
||||
// I've made this check optional for now because it was a fix for an edge case that is
|
||||
// very rare, anyway.
|
||||
try {
|
||||
const diff1 = (
|
||||
await git.exec(['diff', '--stat', `${branch1}..${branch1}~${depth}`])
|
||||
).stdout.trim()
|
||||
const diff2 = (
|
||||
await git.exec(['diff', '--stat', `${branch2}..${branch2}~${depth}`])
|
||||
).stdout.trim()
|
||||
return diff1 !== diff2
|
||||
} catch (error) {
|
||||
core.info('Failed optional check of commits diff; Skipping.')
|
||||
core.debug(utils.getErrorMessage(error))
|
||||
return false
|
||||
}
|
||||
const diff1 = (
|
||||
await git.exec(['diff', '--stat', `${branch1}..${branch1}~${depth}`])
|
||||
).stdout.trim()
|
||||
const diff2 = (
|
||||
await git.exec(['diff', '--stat', `${branch2}..${branch2}~${depth}`])
|
||||
).stdout.trim()
|
||||
return diff1 !== diff2
|
||||
}
|
||||
|
||||
function splitLines(multilineString: string): string[] {
|
||||
@ -200,7 +190,7 @@ export async function createOrUpdateBranch(
|
||||
} else {
|
||||
aopts.push('-A')
|
||||
}
|
||||
await git.exec(aopts, {allowAllExitCodes: true})
|
||||
await git.exec(aopts, true)
|
||||
const popts = ['-m', commitMessage]
|
||||
if (signoff) {
|
||||
popts.push('--signoff')
|
||||
|
@ -211,7 +211,6 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
|
||||
const stashed = await git.stashPush(['--include-untracked'])
|
||||
await git.checkout(inputs.branch)
|
||||
const pushSignedCommitsResult = await ghBranch.pushSignedCommits(
|
||||
git,
|
||||
result.branchCommits,
|
||||
result.baseCommit,
|
||||
repoPath,
|
||||
|
@ -2,7 +2,6 @@ import * as exec from '@actions/exec'
|
||||
import * as io from '@actions/io'
|
||||
import * as utils from './utils'
|
||||
import * as path from 'path'
|
||||
import stream, {Writable} from 'stream'
|
||||
|
||||
const tagsRefSpec = '+refs/tags/*:refs/tags/*'
|
||||
|
||||
@ -15,19 +14,12 @@ export type Commit = {
|
||||
body: string
|
||||
changes: {
|
||||
mode: string
|
||||
dstSha: string
|
||||
status: 'A' | 'M' | 'D'
|
||||
path: string
|
||||
}[]
|
||||
unparsedChanges: string[]
|
||||
}
|
||||
|
||||
export type ExecOpts = {
|
||||
allowAllExitCodes?: boolean
|
||||
encoding?: 'utf8' | 'base64'
|
||||
suppressGitCmdOutput?: boolean
|
||||
}
|
||||
|
||||
export class GitCommandManager {
|
||||
private gitPath: string
|
||||
private workingDirectory: string
|
||||
@ -73,7 +65,7 @@ export class GitCommandManager {
|
||||
args.push(...options)
|
||||
}
|
||||
|
||||
return await this.exec(args, {allowAllExitCodes: allowAllExitCodes})
|
||||
return await this.exec(args, allowAllExitCodes)
|
||||
}
|
||||
|
||||
async commit(
|
||||
@ -89,7 +81,7 @@ export class GitCommandManager {
|
||||
args.push(...options)
|
||||
}
|
||||
|
||||
return await this.exec(args, {allowAllExitCodes: allowAllExitCodes})
|
||||
return await this.exec(args, allowAllExitCodes)
|
||||
}
|
||||
|
||||
async config(
|
||||
@ -120,7 +112,7 @@ export class GitCommandManager {
|
||||
configKey,
|
||||
configValue
|
||||
],
|
||||
{allowAllExitCodes: true}
|
||||
true
|
||||
)
|
||||
return output.exitCode === 0
|
||||
}
|
||||
@ -163,20 +155,13 @@ export class GitCommandManager {
|
||||
|
||||
async getCommit(ref: string): Promise<Commit> {
|
||||
const endOfBody = '###EOB###'
|
||||
const output = await this.exec(
|
||||
[
|
||||
'-c',
|
||||
'core.quotePath=false',
|
||||
'show',
|
||||
'--raw',
|
||||
'--cc',
|
||||
'--no-renames',
|
||||
'--no-abbrev',
|
||||
`--format=%H%n%T%n%P%n%G?%n%s%n%b%n${endOfBody}`,
|
||||
ref
|
||||
],
|
||||
{suppressGitCmdOutput: true}
|
||||
)
|
||||
const output = await this.exec([
|
||||
'show',
|
||||
'--raw',
|
||||
'--cc',
|
||||
`--format=%H%n%T%n%P%n%G?%n%s%n%b%n${endOfBody}`,
|
||||
ref
|
||||
])
|
||||
const lines = output.stdout.split('\n')
|
||||
const endOfBodyIndex = lines.lastIndexOf(endOfBody)
|
||||
const detailLines = lines.slice(0, endOfBodyIndex)
|
||||
@ -191,14 +176,13 @@ export class GitCommandManager {
|
||||
body: detailLines.slice(5, endOfBodyIndex).join('\n'),
|
||||
changes: lines.slice(endOfBodyIndex + 2, -1).map(line => {
|
||||
const change = line.match(
|
||||
/^:(\d{6}) (\d{6}) \w{40} (\w{40}) ([AMD])\s+(.*)$/
|
||||
/^:(\d{6}) (\d{6}) \w{7} \w{7} ([AMD])\s+(.*)$/
|
||||
)
|
||||
if (change) {
|
||||
return {
|
||||
mode: change[4] === 'D' ? change[1] : change[2],
|
||||
dstSha: change[3],
|
||||
status: change[4],
|
||||
path: change[5]
|
||||
mode: change[3] === 'D' ? change[1] : change[2],
|
||||
status: change[3],
|
||||
path: change[4]
|
||||
}
|
||||
} else {
|
||||
unparsedChanges.push(line)
|
||||
@ -232,7 +216,7 @@ export class GitCommandManager {
|
||||
if (options) {
|
||||
args.push(...options)
|
||||
}
|
||||
const output = await this.exec(args, {allowAllExitCodes: true})
|
||||
const output = await this.exec(args, true)
|
||||
return output.exitCode === 1
|
||||
}
|
||||
|
||||
@ -288,15 +272,6 @@ export class GitCommandManager {
|
||||
return output.stdout.trim()
|
||||
}
|
||||
|
||||
async showFileAtRefBase64(ref: string, path: string): Promise<string> {
|
||||
const args = ['show', `${ref}:${path}`]
|
||||
const output = await this.exec(args, {
|
||||
encoding: 'base64',
|
||||
suppressGitCmdOutput: true
|
||||
})
|
||||
return output.stdout.trim()
|
||||
}
|
||||
|
||||
async stashPush(options?: string[]): Promise<boolean> {
|
||||
const args = ['stash', 'push']
|
||||
if (options) {
|
||||
@ -345,7 +320,7 @@ export class GitCommandManager {
|
||||
configKey,
|
||||
configValue
|
||||
],
|
||||
{allowAllExitCodes: true}
|
||||
true
|
||||
)
|
||||
return output.exitCode === 0
|
||||
}
|
||||
@ -353,7 +328,7 @@ export class GitCommandManager {
|
||||
async tryGetRemoteUrl(): Promise<string> {
|
||||
const output = await this.exec(
|
||||
['config', '--local', '--get', 'remote.origin.url'],
|
||||
{allowAllExitCodes: true}
|
||||
true
|
||||
)
|
||||
|
||||
if (output.exitCode !== 0) {
|
||||
@ -368,30 +343,16 @@ export class GitCommandManager {
|
||||
return stdout
|
||||
}
|
||||
|
||||
async exec(
|
||||
args: string[],
|
||||
{
|
||||
encoding = 'utf8',
|
||||
allowAllExitCodes = false,
|
||||
suppressGitCmdOutput = false
|
||||
}: ExecOpts = {}
|
||||
): Promise<GitOutput> {
|
||||
async exec(args: string[], allowAllExitCodes = false): Promise<GitOutput> {
|
||||
const result = new GitOutput()
|
||||
|
||||
if (process.env['CPR_SHOW_GIT_CMD_OUTPUT']) {
|
||||
// debug mode overrides the suppressGitCmdOutput option
|
||||
suppressGitCmdOutput = false
|
||||
}
|
||||
|
||||
const env = {}
|
||||
for (const key of Object.keys(process.env)) {
|
||||
env[key] = process.env[key]
|
||||
}
|
||||
|
||||
const stdout: Buffer[] = []
|
||||
let stdoutLength = 0
|
||||
const stderr: Buffer[] = []
|
||||
let stderrLength = 0
|
||||
const stdout: string[] = []
|
||||
const stderr: string[] = []
|
||||
|
||||
const options = {
|
||||
cwd: this.workingDirectory,
|
||||
@ -399,21 +360,17 @@ export class GitCommandManager {
|
||||
ignoreReturnCode: allowAllExitCodes,
|
||||
listeners: {
|
||||
stdout: (data: Buffer) => {
|
||||
stdout.push(data)
|
||||
stdoutLength += data.length
|
||||
stdout.push(data.toString())
|
||||
},
|
||||
stderr: (data: Buffer) => {
|
||||
stderr.push(data)
|
||||
stderrLength += data.length
|
||||
stderr.push(data.toString())
|
||||
}
|
||||
},
|
||||
outStream: outStreamHandler(process.stdout, suppressGitCmdOutput),
|
||||
errStream: outStreamHandler(process.stderr, suppressGitCmdOutput)
|
||||
}
|
||||
}
|
||||
|
||||
result.exitCode = await exec.exec(`"${this.gitPath}"`, args, options)
|
||||
result.stdout = Buffer.concat(stdout, stdoutLength).toString(encoding)
|
||||
result.stderr = Buffer.concat(stderr, stderrLength).toString(encoding)
|
||||
result.stdout = stdout.join('')
|
||||
result.stderr = stderr.join('')
|
||||
return result
|
||||
}
|
||||
}
|
||||
@ -423,24 +380,3 @@ class GitOutput {
|
||||
stderr = ''
|
||||
exitCode = 0
|
||||
}
|
||||
|
||||
const outStreamHandler = (
|
||||
outStream: Writable,
|
||||
suppressGitCmdOutput: boolean
|
||||
): Writable => {
|
||||
return new stream.Writable({
|
||||
write(chunk, _, next) {
|
||||
if (suppressGitCmdOutput) {
|
||||
const lines = chunk.toString().trimEnd().split('\n')
|
||||
for (const line of lines) {
|
||||
if (line.startsWith('[command]')) {
|
||||
outStream.write(`${line}\n`)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
outStream.write(chunk)
|
||||
}
|
||||
next()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as core from '@actions/core'
|
||||
import {Inputs} from './create-pull-request'
|
||||
import {Commit, GitCommandManager} from './git-command-manager'
|
||||
import {Commit} from './git-command-manager'
|
||||
import {Octokit, OctokitOptions, throttleOptions} from './octokit-client'
|
||||
import pLimit from 'p-limit'
|
||||
import * as utils from './utils'
|
||||
@ -35,7 +35,7 @@ type TreeObject = {
|
||||
path: string
|
||||
mode: '100644' | '100755' | '040000' | '160000' | '120000'
|
||||
sha: string | null
|
||||
type: 'blob' | 'commit'
|
||||
type: 'blob'
|
||||
}
|
||||
|
||||
export class GitHubHelper {
|
||||
@ -220,7 +220,6 @@ export class GitHubHelper {
|
||||
}
|
||||
|
||||
async pushSignedCommits(
|
||||
git: GitCommandManager,
|
||||
branchCommits: Commit[],
|
||||
baseCommit: Commit,
|
||||
repoPath: string,
|
||||
@ -234,7 +233,6 @@ export class GitHubHelper {
|
||||
}
|
||||
for (const commit of branchCommits) {
|
||||
headCommit = await this.createCommit(
|
||||
git,
|
||||
commit,
|
||||
headCommit,
|
||||
repoPath,
|
||||
@ -246,7 +244,6 @@ export class GitHubHelper {
|
||||
}
|
||||
|
||||
private async createCommit(
|
||||
git: GitCommandManager,
|
||||
commit: Commit,
|
||||
parentCommit: CommitResponse,
|
||||
repoPath: string,
|
||||
@ -258,45 +255,32 @@ export class GitHubHelper {
|
||||
if (commit.changes.length > 0) {
|
||||
core.info(`Creating tree objects for local commit ${commit.sha}`)
|
||||
const treeObjects = await Promise.all(
|
||||
commit.changes.map(async ({path, mode, status, dstSha}) => {
|
||||
if (mode === '160000') {
|
||||
// submodule
|
||||
core.info(`Creating tree object for submodule commit at '${path}'`)
|
||||
return <TreeObject>{
|
||||
path,
|
||||
mode,
|
||||
sha: dstSha,
|
||||
type: 'commit'
|
||||
}
|
||||
} else {
|
||||
let sha: string | null = null
|
||||
if (status === 'A' || status === 'M') {
|
||||
try {
|
||||
const {data: blob} = await blobCreationLimit(async () =>
|
||||
this.octokit.rest.git.createBlob({
|
||||
...repository,
|
||||
content: await git.showFileAtRefBase64(commit.sha, path),
|
||||
encoding: 'base64'
|
||||
})
|
||||
)
|
||||
sha = blob.sha
|
||||
} catch (error) {
|
||||
core.error(
|
||||
`Error creating blob for file '${path}': ${utils.getErrorMessage(error)}`
|
||||
)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
core.info(
|
||||
`Creating tree object for blob at '${path}' with status '${status}'`
|
||||
)
|
||||
return <TreeObject>{
|
||||
path,
|
||||
mode,
|
||||
sha,
|
||||
type: 'blob'
|
||||
commit.changes.map(async ({path, mode, status}) => {
|
||||
let sha: string | null = null
|
||||
if (status === 'A' || status === 'M') {
|
||||
try {
|
||||
const {data: blob} = await blobCreationLimit(() =>
|
||||
this.octokit.rest.git.createBlob({
|
||||
...repository,
|
||||
content: utils.readFileBase64([repoPath, path]),
|
||||
encoding: 'base64'
|
||||
})
|
||||
)
|
||||
sha = blob.sha
|
||||
} catch (error) {
|
||||
core.error(
|
||||
`Error creating blob for file '${path}': ${utils.getErrorMessage(error)}`
|
||||
)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
core.info(`Created blob for file '${path}'`)
|
||||
return <TreeObject>{
|
||||
path,
|
||||
mode,
|
||||
sha,
|
||||
type: 'blob'
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
|
@ -3,7 +3,8 @@ import {Octokit as OctokitCore} from '@octokit/core'
|
||||
import {paginateRest} from '@octokit/plugin-paginate-rest'
|
||||
import {restEndpointMethods} from '@octokit/plugin-rest-endpoint-methods'
|
||||
import {throttling} from '@octokit/plugin-throttling'
|
||||
import {fetch} from 'node-fetch-native/proxy'
|
||||
import {getProxyForUrl} from 'proxy-from-env'
|
||||
import {ProxyAgent, fetch as undiciFetch} from 'undici'
|
||||
export {RestEndpointMethodTypes} from '@octokit/plugin-rest-endpoint-methods'
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
export {OctokitOptions} from '@octokit/core/dist-types/types'
|
||||
@ -32,9 +33,23 @@ export const throttleOptions = {
|
||||
}
|
||||
}
|
||||
|
||||
const proxyFetch =
|
||||
(proxyUrl: string): typeof undiciFetch =>
|
||||
(url, opts) => {
|
||||
return undiciFetch(url, {
|
||||
...opts,
|
||||
dispatcher: new ProxyAgent({
|
||||
uri: proxyUrl
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Octokit plugin to support the standard environment variables http_proxy, https_proxy and no_proxy
|
||||
function autoProxyAgent(octokit: OctokitCore) {
|
||||
octokit.hook.before('request', options => {
|
||||
options.request.fetch = fetch
|
||||
const proxy = getProxyForUrl(options.baseUrl)
|
||||
if (proxy) {
|
||||
options.request.fetch = proxyFetch(proxy)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -126,6 +126,10 @@ export function readFile(path: string): string {
|
||||
return fs.readFileSync(path, 'utf-8')
|
||||
}
|
||||
|
||||
export function readFileBase64(pathParts: string[]): string {
|
||||
return fs.readFileSync(path.resolve(...pathParts)).toString('base64')
|
||||
}
|
||||
|
||||
/* 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