Compare commits

...

4 Commits

Author SHA1 Message Date
c58bcf269b update major version 2024-08-30 15:13:17 +00:00
25f1937529 fix typo 2024-08-30 15:50:57 +01:00
2d4402547d add updating documentation 2024-08-30 15:48:19 +01:00
926a201444 fix edge case where changes are partially merged 2024-08-28 17:45:52 +01:00
10 changed files with 242 additions and 46 deletions

View File

@ -32,10 +32,10 @@ Create Pull Request action will:
# Make changes to pull request here
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
```
You can also pin to a [specific release](https://github.com/peter-evans/create-pull-request/releases) version in the format `@v6.x.x`
You can also pin to a [specific release](https://github.com/peter-evans/create-pull-request/releases) version in the format `@v7.x.x`
### Workflow permissions
@ -131,7 +131,7 @@ If you want branches to be deleted immediately on merge then you should use GitH
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@v6
uses: peter-evans/create-pull-request@v7
env:
https_proxy: http://<proxy_address>:<port>
```
@ -153,7 +153,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@v6
uses: peter-evans/create-pull-request@v7
- name: Check outputs
if: ${{ steps.cpr.outputs.pull-request-number }}
run: |
@ -216,7 +216,7 @@ File changes that do not match one of the paths will be stashed and restored aft
```yml
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
add-paths: |
*.java
@ -243,7 +243,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@v6
uses: peter-evans/create-pull-request@v7
```
### Create a project card
@ -253,7 +253,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@v6
uses: peter-evans/create-pull-request@v7
- name: Create or Update Project Card
if: ${{ steps.cpr.outputs.pull-request-number }}
@ -288,7 +288,7 @@ jobs:
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.PAT }}
commit-message: Update report

View File

@ -657,6 +657,76 @@ describe('create-or-update-branch tests', () => {
).toBeTruthy()
})
it('tests create, commit with partial changes on the base, and update', async () => {
// This is an edge case where the changes for a single commit are partially merged to the base
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const result = await createOrUpdateBranch(
git,
commitMessage,
'',
BRANCH,
REMOTE_NAME,
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)
expect(
await gitLogMatches([commitMessage, INIT_COMMIT_MESSAGE])
).toBeTruthy()
// Push pull request branch to remote
await git.push([
'--force-with-lease',
REMOTE_NAME,
`HEAD:refs/heads/${BRANCH}`
])
await afterTest(false)
await beforeTest()
// Create a commit on the base with a partial merge of the changes
await createFile(TRACKED_FILE, changes.tracked)
const baseCommitMessage = uuidv4()
await git.exec(['add', '-A'])
await git.commit(['-m', baseCommitMessage])
await git.push([
'--force',
REMOTE_NAME,
`HEAD:refs/heads/${DEFAULT_BRANCH}`
])
// Create the same tracked and untracked file changes
const _changes = await createChanges(changes.tracked, changes.untracked)
const _commitMessage = uuidv4()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
'',
BRANCH,
REMOTE_NAME,
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)
expect(await getFileContent(UNTRACKED_FILE)).toEqual(_changes.untracked)
expect(
await gitLogMatches([
_commitMessage,
baseCommitMessage,
INIT_COMMIT_MESSAGE
])
).toBeTruthy()
})
it('tests create, squash merge, and update with identical changes', async () => {
// Branches that have been squash merged appear to have a diff with the base due to
// different commits for the same changes. To prevent creating pull requests
@ -1679,6 +1749,81 @@ describe('create-or-update-branch tests', () => {
).toBeTruthy()
})
it('tests create, commit with partial changes on the base, and update (WBNB)', async () => {
// This is an edge case where the changes for a single commit are partially merged to the base
// Set the working base to a branch that is not the pull request base
await git.checkout(NOT_BASE_BRANCH)
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const result = await createOrUpdateBranch(
git,
commitMessage,
BASE,
BRANCH,
REMOTE_NAME,
false,
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)
expect(
await gitLogMatches([commitMessage, INIT_COMMIT_MESSAGE])
).toBeTruthy()
// Push pull request branch to remote
await git.push([
'--force-with-lease',
REMOTE_NAME,
`HEAD:refs/heads/${BRANCH}`
])
await afterTest(false)
await beforeTest()
// Create a commit on the base with a partial merge of the changes
await createFile(TRACKED_FILE, changes.tracked)
const baseCommitMessage = uuidv4()
await git.exec(['add', '-A'])
await git.commit(['-m', baseCommitMessage])
await git.push([
'--force',
REMOTE_NAME,
`HEAD:refs/heads/${DEFAULT_BRANCH}`
])
// Set the working base to a branch that is not the pull request base
await git.checkout(NOT_BASE_BRANCH)
// Create the same tracked and untracked file changes
const _changes = await createChanges(changes.tracked, changes.untracked)
const _commitMessage = uuidv4()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
BASE,
BRANCH,
REMOTE_NAME,
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)
expect(await getFileContent(UNTRACKED_FILE)).toEqual(_changes.untracked)
expect(
await gitLogMatches([
_commitMessage,
baseCommitMessage // fetch depth of base is 1
])
).toBeTruthy()
})
it('tests create, squash merge, and update with identical changes (WBNB)', async () => {
// Branches that have been squash merged appear to have a diff with the base due to
// different commits for the same changes. To prevent creating pull requests

23
dist/index.js vendored
View File

@ -133,6 +133,14 @@ function isEven(git, branch1, branch2) {
!(yield isBehind(git, branch1, branch2)));
});
}
// Return true if the specified number of commits on branch1 and branch2 have a diff
function commitsHaveDiff(git, branch1, branch2, depth) {
return __awaiter(this, void 0, void 0, function* () {
const diff1 = (yield git.exec(['diff', '--stat', `${branch1}..${branch1}~${depth}`])).stdout.trim();
const diff2 = (yield git.exec(['diff', '--stat', `${branch2}..${branch2}~${depth}`])).stdout.trim();
return diff1 !== diff2;
});
}
function splitLines(multilineString) {
return multilineString
.split('\n')
@ -241,20 +249,25 @@ function createOrUpdateBranch(git, commitMessage, base, branch, branchRemoteName
yield git.checkout(branch);
// Reset the branch if one of the following conditions is true.
// - If the branch differs from the recreated temp branch.
// - If the number of commits ahead of the base branch differs between the branch and
// temp branch. This catches a case where the base branch has been force pushed to
// a new commit.
// - If the recreated temp branch is not ahead of the base. This means there will be
// no pull request diff after the branch is reset. This will reset any undeleted
// branches after merging. In particular, it catches a case where the branch was
// squash merged but not deleted. We need to reset to make sure it doesn't appear
// to have a diff with the base due to different commits for the same changes.
// - If the number of commits ahead of the base branch differs between the branch and
// temp branch. This catches a case where the base branch has been force pushed to
// a new commit.
// - If the diff of the commits ahead of the base branch differs between the branch and
// temp branch. This catches a case where changes have been partially merged to the
// base. The overall diff is the same, but the branch needs to be rebased to show
// the correct diff.
//
// For changes on base this reset is equivalent to a rebase of the pull request branch.
const branchCommitsAhead = yield commitsAhead(git, base, branch);
if ((yield git.hasDiff([`${branch}..${tempBranch}`])) ||
branchCommitsAhead != tempBranchCommitsAhead ||
!(tempBranchCommitsAhead > 0) // !isAhead
) {
!(tempBranchCommitsAhead > 0) || // !isAhead
(yield commitsHaveDiff(git, branch, tempBranch, tempBranchCommitsAhead))) {
core.info(`Resetting '${branch}'`);
// Alternatively, git switch -C branch tempBranch
yield git.checkout(branch, tempBranch);

View File

@ -37,7 +37,7 @@ So the straightforward solution is to just not install them during the workflow
- If hooks are automatically enabled by a framework, use an option provided by the framework to disable them. For example, for Husky users, they can be disabled with the `--ignore-scripts` flag, or by setting the `HUSKY` environment variable when the action runs.
```yml
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
env:
HUSKY: '0'
```

View File

@ -92,7 +92,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@v6
- uses: peter-evans/create-pull-request@v7
with:
base: ${{ github.head_ref }}
```
@ -100,7 +100,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@v6
- uses: peter-evans/create-pull-request@v7
with:
base: main
```
@ -186,7 +186,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@v6
- uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.PAT }}
```
@ -216,7 +216,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@v6
uses: peter-evans/create-pull-request@v7
```
### Push pull request branches to a fork
@ -241,7 +241,7 @@ It will use their own fork to push code and create the pull request.
# Make changes to pull request here
- uses: peter-evans/create-pull-request@v6
- uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.MACHINE_USER_PAT }}
push-to-fork: machine-user/fork-of-repository
@ -284,7 +284,7 @@ The following is an example of pushing to a fork using GitHub App tokens.
# Make changes to pull request here
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
branch-token: ${{ steps.generate-token.outputs.token }}
push-to-fork: owner/fork-of-repo
@ -329,7 +329,7 @@ GitHub App generated tokens can be configured with fine-grained permissions and
# Make changes to pull request here
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
token: ${{ steps.generate-token.outputs.token }}
```
@ -357,7 +357,7 @@ In the following example, a pull request is being created in remote repo `owner/
# Make changes to pull request here
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
token: ${{ steps.generate-token.outputs.token }}
```
@ -386,7 +386,7 @@ In this example the `token` input is not supplied, so the action will use the re
# Make changes to pull request here
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
sign-commits: true
```
@ -405,7 +405,7 @@ In this example, the `token` input is generated using a GitHub App. This will si
# Make changes to pull request here
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
token: ${{ steps.generate-token.outputs.token }}
sign-commits: true
@ -448,7 +448,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@v6
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.PAT }}
committer: example <email@example.com>
@ -478,7 +478,7 @@ jobs:
# Make changes to pull request here
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
```
**Ubuntu container example:**
@ -501,5 +501,5 @@ jobs:
# Make changes to pull request here
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
```

View File

@ -49,7 +49,7 @@ jobs:
run: |
git log --format='%aN <%aE>%n%cN <%cE>' | sort -u > AUTHORS
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
commit-message: update authors
title: Update AUTHORS
@ -81,7 +81,7 @@ jobs:
git fetch origin main:main
git reset --hard main
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
branch: production-promotion
```
@ -116,7 +116,7 @@ jobs:
./git-chglog -o CHANGELOG.md
rm git-chglog
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
commit-message: update changelog
title: Update Changelog
@ -153,7 +153,7 @@ jobs:
npx -p npm-check-updates ncu -u
npm install
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.PAT }}
commit-message: Update dependencies
@ -214,7 +214,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@v6
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.PAT }}
commit-message: Update dependencies
@ -249,7 +249,7 @@ jobs:
cargo update
cargo upgrade --to-lockfile
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.PAT }}
commit-message: Update dependencies
@ -307,7 +307,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@v6
uses: peter-evans/create-pull-request@v7
with:
commit-message: Update swagger-ui to ${{ steps.swagger-ui.outputs.release_tag }}
title: Update SwaggerUI to ${{ steps.swagger-ui.outputs.release_tag }}
@ -351,7 +351,7 @@ jobs:
git fetch upstream main:upstream-main
git reset --hard upstream-main
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.PAT }}
branch: upstream-changes
@ -384,7 +384,7 @@ jobs:
--domains quotes.toscrape.com \
http://quotes.toscrape.com/
- name: Create Pull Request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
commit-message: update local website copy
title: Automated Updates to Local Website Copy
@ -481,7 +481,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@v6
uses: peter-evans/create-pull-request@v7
with:
commit-message: autopep8 action fixes
title: Fixes by autopep8 action
@ -540,7 +540,7 @@ 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@v6
uses: peter-evans/create-pull-request@v7
with:
title: ${{ steps.vars.outputs.pr_title }}
body: ${{ steps.vars.outputs.pr_body }}
@ -566,7 +566,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@v6
uses: peter-evans/create-pull-request@v7
with:
body: ${{ steps.template.outputs.result }}
```

View File

@ -1,3 +1,19 @@
## Updating from `v6` to `v7`
### Behaviour changes
- Action input `git-token` has been renamed `branch-token`, to be more clear about its purpose. The `branch-token` is the token that the action will use to create and update the branch.
- The action now handles requests that have been rate-limited by GitHub. Requests hitting a primary rate limit will retry twice, for a total of three attempts. Requests hitting a secondary rate limit will not be retried.
- The `pull-request-operation` output now returns `none` when no operation was executed.
- Removed deprecated output environment variable `PULL_REQUEST_NUMBER`. Please use the `pull-request-number` action output instead.
### What's new
- The action can now sign commits as `github-actions[bot]` when using `GITHUB_TOKEN`, or your own bot when using [GitHub App tokens](concepts-guidelines.md#authenticating-with-github-app-generated-tokens). See [commit signing](concepts-guidelines.md#commit-signature-verification-for-bots) for details.
- Action input `draft` now accepts a new value `always-true`. This will set the pull request to draft status when the pull request is updated, as well as on creation.
- A new action input `maintainer-can-modify` indicates whether [maintainers can modify](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) the pull request. The default is `true`, which retains the existing behaviour of the action.
- A new output `pull-request-commits-verified` returns `true` or `false`, indicating whether GitHub considers the signature of the branch's commits to be verified.
## Updating from `v5` to `v6`
### Behaviour changes

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "create-pull-request",
"version": "6.0.0",
"version": "7.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "create-pull-request",
"version": "6.0.0",
"version": "7.0.0",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.10.1",

View File

@ -1,6 +1,6 @@
{
"name": "create-pull-request",
"version": "6.0.0",
"version": "7.0.0",
"private": true,
"description": "Creates a pull request for changes to your repository in the actions workspace",
"main": "lib/main.js",

View File

@ -124,6 +124,22 @@ async function isEven(
)
}
// Return true if the specified number of commits on branch1 and branch2 have a diff
async function commitsHaveDiff(
git: GitCommandManager,
branch1: string,
branch2: string,
depth: number
): Promise<boolean> {
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[] {
return multilineString
.split('\n')
@ -270,20 +286,26 @@ export async function createOrUpdateBranch(
// Reset the branch if one of the following conditions is true.
// - If the branch differs from the recreated temp branch.
// - If the number of commits ahead of the base branch differs between the branch and
// temp branch. This catches a case where the base branch has been force pushed to
// a new commit.
// - If the recreated temp branch is not ahead of the base. This means there will be
// no pull request diff after the branch is reset. This will reset any undeleted
// branches after merging. In particular, it catches a case where the branch was
// squash merged but not deleted. We need to reset to make sure it doesn't appear
// to have a diff with the base due to different commits for the same changes.
// - If the number of commits ahead of the base branch differs between the branch and
// temp branch. This catches a case where the base branch has been force pushed to
// a new commit.
// - If the diff of the commits ahead of the base branch differs between the branch and
// temp branch. This catches a case where changes have been partially merged to the
// base. The overall diff is the same, but the branch needs to be rebased to show
// the correct diff.
//
// For changes on base this reset is equivalent to a rebase of the pull request branch.
const branchCommitsAhead = await commitsAhead(git, base, branch)
if (
(await git.hasDiff([`${branch}..${tempBranch}`])) ||
branchCommitsAhead != tempBranchCommitsAhead ||
!(tempBranchCommitsAhead > 0) // !isAhead
!(tempBranchCommitsAhead > 0) || // !isAhead
(await commitsHaveDiff(git, branch, tempBranch, tempBranchCommitsAhead))
) {
core.info(`Resetting '${branch}'`)
// Alternatively, git switch -C branch tempBranch