Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v7 - signed commits #3057

Merged
merged 69 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
744c8ce
Add support for signed commits (#3055)
rustycl0ck Jul 25, 2024
8a55f62
formatting
peter-evans Jul 25, 2024
4cf9647
fix eslint and lint errors
peter-evans Jul 25, 2024
014f5c1
shift setting the base to before the push
peter-evans Jul 25, 2024
7ccbe5d
sign commits by default for testing
peter-evans Jul 25, 2024
8f257d0
add debug lines
peter-evans Jul 26, 2024
bc73bc7
read to buffer not string and use non-legacy method to base64
peter-evans Jul 26, 2024
efd26f0
debug payload without contents
peter-evans Jul 26, 2024
3964293
disable linter for debug code
peter-evans Jul 26, 2024
184d576
fix filepath when using path input
peter-evans Jul 27, 2024
d88643b
try to fix head repo
peter-evans Jul 27, 2024
f09d6ed
remove commented code
peter-evans Jul 27, 2024
9d7ad21
Try refactor of file changes
peter-evans Jul 31, 2024
c298215
add tests for building file changes
peter-evans Jul 31, 2024
9c7a97a
add build file changes test for binary files
peter-evans Aug 2, 2024
6c5dc22
refactor graphql code into github helper class
peter-evans Aug 2, 2024
9cd16da
build file changes even when there is no diff
peter-evans Aug 2, 2024
029414b
add function to get commit detail
peter-evans Aug 7, 2024
ec02db7
fix format
peter-evans Aug 7, 2024
b2a409b
build branch commits
peter-evans Aug 8, 2024
6b1053d
use source mode for deleted files
peter-evans Aug 8, 2024
0c8901c
try rest api route
peter-evans Aug 8, 2024
8605c43
fix check for branch existence
peter-evans Aug 8, 2024
63aac93
force push
peter-evans Aug 8, 2024
0785201
try fix base tree
peter-evans Aug 8, 2024
d94a826
debug commit verification
peter-evans Aug 9, 2024
4c77294
debug commit verification
peter-evans Aug 9, 2024
384bd7f
fix format and cleanup
peter-evans Aug 9, 2024
219a33f
add executable mode file to test
peter-evans Aug 9, 2024
3a6bc1b
limit blob creation concurrency
peter-evans Aug 9, 2024
53ed82a
only build commits when feature enabled
peter-evans Aug 9, 2024
72cf092
remove unused code
peter-evans Aug 9, 2024
b7277ab
update readme link
peter-evans Aug 12, 2024
cc83660
update docs for commit signing
peter-evans Aug 12, 2024
0a565da
fix capital letter
peter-evans Aug 12, 2024
3cc54e8
update docs
peter-evans Aug 12, 2024
13fa7b0
add throttling
peter-evans Aug 14, 2024
e572f56
set default back to false
peter-evans Aug 14, 2024
139c557
output head sha and verified status
peter-evans Aug 14, 2024
1fbc616
log outputs
peter-evans Aug 14, 2024
eb6967b
fix head sha output
peter-evans Aug 15, 2024
59815b2
default the operation output to none
peter-evans Aug 15, 2024
f5bdca7
output retryafter for secondary rate limit
peter-evans Aug 15, 2024
b793f78
use separate client for branch and pull operations
peter-evans Aug 16, 2024
5294a5e
add maintainer-can-modify input
peter-evans Aug 16, 2024
1985abb
rename git-token to branch-token
peter-evans Aug 16, 2024
c006a63
fix branch token input
peter-evans Aug 16, 2024
4a0f9a8
remove deprecated env output
peter-evans Aug 16, 2024
981b469
update docs
peter-evans Aug 16, 2024
942e5a9
fix doc
peter-evans Aug 16, 2024
2ba41ed
update docs
peter-evans Aug 17, 2024
32e97fc
build branch commits when there is a diff with the base
peter-evans Aug 17, 2024
1cd6df6
check verification status of head commit when not known
peter-evans Aug 17, 2024
1045472
fix verified output when no commit signing is being used
peter-evans Aug 17, 2024
c64379e
draft always-true
peter-evans Aug 18, 2024
8f92797
convert to draft on branch updates when there is a diff with base
peter-evans Aug 18, 2024
1e681e3
update docs with blob size limit
peter-evans Aug 20, 2024
a354636
catch errors during blob creation for debugging
peter-evans Aug 21, 2024
42beb85
parse empty commits
peter-evans Aug 23, 2024
034fcb0
pass base commit to push signed commits
peter-evans Aug 23, 2024
02efff6
use parent commit details in create commit
peter-evans Aug 23, 2024
633a5a9
use parent tree for base_tree
peter-evans Aug 23, 2024
6c4c6cf
multipart tree creation
peter-evans Aug 23, 2024
9fc91d9
update docs
peter-evans Aug 23, 2024
ce190a9
update readme about the permissions of the default token
peter-evans Aug 23, 2024
926a201
fix edge case where changes are partially merged
peter-evans Aug 28, 2024
2d44025
add updating documentation
peter-evans Aug 30, 2024
25f1937
fix typo
peter-evans Aug 30, 2024
c58bcf2
update major version
peter-evans Aug 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 42 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -48,12 +48,10 @@ For repositories belonging to an organization, this setting can be managed by ad

All inputs are **optional**. If not set, sensible defaults will be used.

**Note**: If you want pull requests created by this action to trigger an `on: push` or `on: pull_request` workflow then you cannot use the default `GITHUB_TOKEN`. See the [documentation here](docs/concepts-guidelines.md#triggering-further-workflow-runs) for workarounds.

| Name | Description | Default |
| --- | --- | --- |
| `token` | `GITHUB_TOKEN` (permissions `contents: write` and `pull-requests: write`) or a `repo` scoped [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token). | `GITHUB_TOKEN` |
| `git-token` | The [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) that the action will use for git operations. | Defaults to the value of `token` |
| `token` | The token that the action will use to create and update the pull request. See [token](#token). | `GITHUB_TOKEN` |
| `branch-token` | The token that the action will use to create and update the branch. See [branch-token](#branch-token). | Defaults to the value of `token` |
| `path` | Relative path under `GITHUB_WORKSPACE` to the repository. | `GITHUB_WORKSPACE` |
| `add-paths` | A comma or newline-separated list of file paths to commit. Paths should follow git's [pathspec](https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefpathspecapathspec) syntax. If no paths are specified, all new and modified files are added. See [Add specific paths](#add-specific-paths). | |
| `commit-message` | The message to use when committing changes. See [commit-message](#commit-message). | `[create-pull-request] automated change` |
Expand All @@ -65,6 +63,7 @@ All inputs are **optional**. If not set, sensible defaults will be used.
| `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. | |
| `sign-commits` | Sign commits as `github-actions[bot]` when using `GITHUB_TOKEN`, or your own bot when using [GitHub App tokens](docs/concepts-guidelines.md#authenticating-with-github-app-generated-tokens). See [commit signing](docs/concepts-guidelines.md#commit-signature-verification-for-bots) for details. | `false` |
| `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`. | |
Expand All @@ -73,7 +72,35 @@ All inputs are **optional**. If not set, sensible defaults will be used.
| `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), 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` |
| `draft` | Create a [draft pull request](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests#draft-pull-requests). Valid values are `true` (only on create), `always-true` (on create and update), and `false`. | `false` |
| `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. | `true` |

#### token

The token input defaults to the repository's `GITHUB_TOKEN`.

> [!IMPORTANT]
> - If you want pull requests created by this action to trigger an `on: push` or `on: pull_request` workflow then you cannot use the default `GITHUB_TOKEN`. See the [documentation here](docs/concepts-guidelines.md#triggering-further-workflow-runs) for further details.
> - If using the repository's `GITHUB_TOKEN` and your repository was created after 2nd February 2023, the [default permission is read-only](https://github.blog/changelog/2023-02-02-github-actions-updating-the-default-github_token-permissions-to-read-only/). Elevate the [permissions](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/controlling-permissions-for-github_token#defining-access-for-the-github_token-permissions) in your workflow.
> ```yml
> permissions:
> contents: write
> pull-requests: write
> ```

Other token options:
- Classic [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) with `repo` scope.
- Fine-grained [Personal Access Token (PAT)](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) with `contents: write` and `pull-requests: write` scopes.
- [GitHub App tokens](docs/concepts-guidelines.md#authenticating-with-github-app-generated-tokens) with `contents: write` and `pull-requests: write` scopes.

> [!TIP]
> If pull requests could contain changes to Actions workflows you may also need the `workflows` scope.

#### 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 neccessary, to use different tokens for these operations.
It is not advisable to use this input unless you know you need to.

#### commit-message

Expand Down Expand Up @@ -104,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>
```
Expand All @@ -115,17 +142,18 @@ The following outputs can be used by subsequent workflow steps.

- `pull-request-number` - The pull request number.
- `pull-request-url` - The URL of the pull request.
- `pull-request-operation` - The pull request operation performed by the action, `created`, `updated` or `closed`.
- `pull-request-operation` - The pull request operation performed by the action, `created`, `updated`, `closed` or `none`.
- `pull-request-head-sha` - The commit SHA of the pull request branch.
- `pull-request-branch` - The branch name of the pull request.
- `pull-request-commits-verified` - Whether GitHub considers the signature of the branch's commits to be verified; `true` or `false`.

Step outputs can be accessed as in the following example.
Note that in order to read the step outputs the action step must have an id.

```yml
- 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: |
Expand Down Expand Up @@ -188,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
Expand All @@ -215,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
Expand All @@ -225,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 }}
Expand Down Expand Up @@ -260,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
Expand Down
219 changes: 218 additions & 1 deletion __test__/create-or-update-branch.int.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {
createOrUpdateBranch,
tryFetch,
getWorkingBaseAndType
getWorkingBaseAndType,
buildBranchCommits
} from '../lib/create-or-update-branch'
import * as fs from 'fs'
import {GitCommandManager} from '../lib/git-command-manager'
Expand Down Expand Up @@ -229,6 +230,77 @@ describe('create-or-update-branch tests', () => {
expect(workingBaseType).toEqual('commit')
})

it('tests buildBranchCommits with no diff', async () => {
await git.checkout(BRANCH, BASE)
const branchCommits = await buildBranchCommits(git, BASE, BRANCH)
expect(branchCommits.length).toEqual(0)
})

it('tests buildBranchCommits with addition and modification', async () => {
await git.checkout(BRANCH, BASE)
await createChanges()
const UNTRACKED_EXE_FILE = 'a/script.sh'
const filepath = path.join(REPO_PATH, UNTRACKED_EXE_FILE)
await fs.promises.writeFile(filepath, '#!/usr/bin/env bash', {mode: 0o755})
await git.exec(['add', '-A'])
await git.commit(['-m', 'Test changes'])

const branchCommits = await buildBranchCommits(git, BASE, BRANCH)

expect(branchCommits.length).toEqual(1)
expect(branchCommits[0].subject).toEqual('Test changes')
expect(branchCommits[0].changes.length).toEqual(3)
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 () => {
await git.checkout(BRANCH, BASE)
await createChanges()
const TRACKED_FILE_NEW_PATH = 'c/tracked-file.txt'
const filepath = path.join(REPO_PATH, TRACKED_FILE_NEW_PATH)
await fs.promises.mkdir(path.dirname(filepath), {recursive: true})
await fs.promises.rename(path.join(REPO_PATH, TRACKED_FILE), filepath)
await git.exec(['add', '-A'])
await git.commit(['-m', 'Test changes'])

const branchCommits = await buildBranchCommits(git, BASE, BRANCH)

expect(branchCommits.length).toEqual(1)
expect(branchCommits[0].subject).toEqual('Test changes')
expect(branchCommits[0].changes.length).toEqual(3)
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 () => {
await git.checkout(BRANCH, BASE)
for (let i = 0; i < 3; i++) {
await createChanges()
await git.exec(['add', '-A'])
await git.commit(['-m', `Test changes ${i}`])
}

const branchCommits = await buildBranchCommits(git, BASE, BRANCH)

expect(branchCommits.length).toEqual(3)
for (let i = 0; i < 3; i++) {
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).toEqual([
{mode: '100644', path: TRACKED_FILE, status: 'M'},
{mode: '100644', path: UNTRACKED_FILE, status: untrackedFileStatus}
])
}
})

it('tests no changes resulting in no new branch being created', async () => {
const commitMessage = uuidv4()
const result = await createOrUpdateBranch(
Expand Down Expand Up @@ -585,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
Expand Down Expand Up @@ -1607,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
Expand Down
Loading