Compare commits

...

21 Commits

Author SHA1 Message Date
Peter Evans 2ef8501772 refactor: replace uuid dep with Node.js built-in crypto.randomUUID
Replace the third-party `uuid` package with the native `crypto.randomUUID()`
function available in Node.js, reducing the bundle size and external
dependencies.

- Remove `uuid` from `dependencies` in `package.json`
- Replace `import {v4 as uuidv4} from 'uuid'` with `import {randomUUID} from 'crypto'` in `src/create-or-update-branch.ts`
- Replace all `uuidv4()` calls with `randomUUID()` in `__test__/create-or-update-branch.int.test.ts`
- Rebuild `dist/index.js`, removing ~680 lines of bundled `uuid` library code
- Update `package-lock.json` to reflect removed dependency
2026-05-06 10:30:23 +00:00
dependabot[bot] d8c15c739f build(deps-dev): bump the npm group with 2 updates (#4372)
Bumps the npm group with 2 updates: [prettier](https://github.com/prettier/prettier) and [undici](https://github.com/nodejs/undici).


Updates `prettier` from 3.8.1 to 3.8.3
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.8.1...3.8.3)

Updates `undici` from 6.24.1 to 6.25.0
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v6.24.1...v6.25.0)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.8.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: undici
  dependency-version: 6.25.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-01 14:37:34 +00:00
actions-bot eec7ab75b2 build: update distribution (#4361)
Co-authored-by: peter-evans <18365890+peter-evans@users.noreply.github.com>
2026-04-10 17:35:29 +01:00
Peter Evans 5f6978faf0 fix: retry post-creation API calls on 422 eventual consistency errors (#4356)
Add retry logic to handle GitHub API eventual consistency errors that
can occur after creating a new pull request. Follow-up API calls for
milestones, labels, assignees, and reviewers may fail with a 422
"Could not resolve to a node" error before the PR is fully propagated.

- Add generic `retryWithBackoff` helper in `src/utils.ts` with
  exponential backoff (default 2 retries, starting at 1s delay)
- Wrap post-creation API calls in `src/github-helper.ts` with
  `withRetryForNewPr()`, which only retries for newly created PRs
- Use `@octokit/request-error` `RequestError` type for precise error
  matching (status 422 + "Could not resolve to a node" message)
- Add unit tests for `retryWithBackoff` covering success, retry,
  exhaustion, and non-retryable error scenarios
- Update `dist/index.js` bundle and `package.json` dependencies
2026-04-10 17:23:55 +01:00
dependabot[bot] d32e88dac7 build(deps-dev): bump the npm group with 3 updates (#4349)
Bumps the npm group with 3 updates: [jest-environment-jsdom](https://github.com/jestjs/jest/tree/HEAD/packages/jest-environment-jsdom), [ts-jest](https://github.com/kulshekhar/ts-jest) and [undici](https://github.com/nodejs/undici).


Updates `jest-environment-jsdom` from 30.2.0 to 30.3.0
- [Release notes](https://github.com/jestjs/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jestjs/jest/commits/v30.3.0/packages/jest-environment-jsdom)

Updates `ts-jest` from 29.4.6 to 29.4.9
- [Release notes](https://github.com/kulshekhar/ts-jest/releases)
- [Changelog](https://github.com/kulshekhar/ts-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/kulshekhar/ts-jest/compare/v29.4.6...v29.4.9)

Updates `undici` from 6.24.0 to 6.24.1
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v6.24.0...v6.24.1)

---
updated-dependencies:
- dependency-name: jest-environment-jsdom
  dependency-version: 30.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm
- dependency-name: ts-jest
  dependency-version: 29.4.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: undici
  dependency-version: 6.24.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-01 15:23:34 +00:00
dependabot[bot] 8170bccad1 build(deps-dev): bump handlebars from 4.7.8 to 4.7.9 (#4344)
Bumps [handlebars](https://github.com/handlebars-lang/handlebars.js) from 4.7.8 to 4.7.9.
- [Release notes](https://github.com/handlebars-lang/handlebars.js/releases)
- [Changelog](https://github.com/handlebars-lang/handlebars.js/blob/v4.7.9/release-notes.md)
- [Commits](https://github.com/handlebars-lang/handlebars.js/compare/v4.7.8...v4.7.9)

---
updated-dependencies:
- dependency-name: handlebars
  dependency-version: 4.7.9
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-27 20:17:57 +00:00
dependabot[bot] 00418193b4 build(deps): bump picomatch (#4339)
Bumps  and [picomatch](https://github.com/micromatch/picomatch). These dependencies needed to be updated together.

Updates `picomatch` from 2.3.1 to 2.3.2
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2)

Updates `picomatch` from 4.0.2 to 4.0.4
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2)

Updates `picomatch` from 4.0.3 to 4.0.4
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2)

---
updated-dependencies:
- dependency-name: picomatch
  dependency-version: 2.3.2
  dependency-type: indirect
- dependency-name: picomatch
  dependency-version: 4.0.4
  dependency-type: indirect
- dependency-name: picomatch
  dependency-version: 4.0.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-25 21:50:05 +00:00
dependabot[bot] b993918c85 build(deps-dev): bump flatted from 3.3.1 to 3.4.2 (#4334)
Bumps [flatted](https://github.com/WebReflection/flatted) from 3.3.1 to 3.4.2.
- [Commits](https://github.com/WebReflection/flatted/compare/v3.3.1...v3.4.2)

---
updated-dependencies:
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-20 00:22:17 +00:00
dependabot[bot] 36d7c8468b build(deps-dev): bump undici from 6.23.0 to 6.24.0 (#4328)
Bumps [undici](https://github.com/nodejs/undici) from 6.23.0 to 6.24.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v6.23.0...v6.24.0)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 6.24.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-14 06:18:43 +00:00
dependabot[bot] a45d1fb447 build(deps): bump @tootallnate/once and jest-environment-jsdom (#4323)
Removes [@tootallnate/once](https://github.com/TooTallNate/once). It's no longer used after updating ancestor dependency [jest-environment-jsdom](https://github.com/jestjs/jest/tree/HEAD/packages/jest-environment-jsdom). These dependencies need to be updated together.


Removes `@tootallnate/once`

Updates `jest-environment-jsdom` from 29.7.0 to 30.2.0
- [Release notes](https://github.com/jestjs/jest/releases)
- [Changelog](https://github.com/jestjs/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jestjs/jest/commits/v30.2.0/packages/jest-environment-jsdom)

---
updated-dependencies:
- dependency-name: "@tootallnate/once"
  dependency-version: 
  dependency-type: indirect
- dependency-name: jest-environment-jsdom
  dependency-version: 30.2.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-05 06:14:22 +00:00
dependabot[bot] 3499eb6183 build(deps): bump the github-actions group with 2 updates (#4316)
Bumps the github-actions group with 2 updates: [actions/upload-artifact](https://github.com/actions/upload-artifact) and [actions/download-artifact](https://github.com/actions/download-artifact).


Updates `actions/upload-artifact` from 6 to 7
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

Updates `actions/download-artifact` from 7 to 8
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v7...v8)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-01 12:34:50 +00:00
dependabot[bot] 3f3b473b8c build(deps): bump minimatch (#4311)
Bumps  and [minimatch](https://github.com/isaacs/minimatch). These dependencies needed to be updated together.

Updates `minimatch` from 3.1.2 to 3.1.5
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5)

Updates `minimatch` from 9.0.5 to 9.0.9
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 3.1.5
  dependency-type: indirect
- dependency-name: minimatch
  dependency-version: 9.0.9
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-28 06:50:02 +00:00
dependabot[bot] 6699836a21 build(deps-dev): bump the npm group with 2 updates (#4305)
Bumps the npm group with 2 updates: [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier) and [prettier](https://github.com/prettier/prettier).


Updates `eslint-plugin-prettier` from 5.5.4 to 5.5.5
- [Release notes](https://github.com/prettier/eslint-plugin-prettier/releases)
- [Changelog](https://github.com/prettier/eslint-plugin-prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-plugin-prettier/compare/v5.5.4...v5.5.5)

Updates `prettier` from 3.7.4 to 3.8.1
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.7.4...3.8.1)

---
updated-dependencies:
- dependency-name: eslint-plugin-prettier
  dependency-version: 5.5.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: prettier
  dependency-version: 3.8.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-01 12:35:41 +00:00
Peter Evans c0f553fe54 feat: add @octokit/plugin-retry to handle retriable server errors (#4298)
Add the retry plugin to automatically retry requests that fail with
server errors (5xx status codes). Configure the plugin to exclude 429
(rate limit) from retries since that is already handled by the
throttling plugin.

- Add @octokit/plugin-retry dependency
- Register retry plugin in Octokit client
- Export retryOptions with doNotRetry list excluding 429
- Apply retryOptions in GitHubHelper constructor
2026-01-21 15:20:27 +00:00
Peter Evans 70001242bf fix: Handle remote prune failures gracefully (#4295)
Wrap the git remote prune command in a try-catch block to prevent
the action from failing if the prune operation fails. Instead, log
a warning message and allow the action to continue.

Fixes edge cases where the prune command may fail on self-hosted
runners but shouldn't block the pull request creation workflow.
2026-01-21 15:04:51 +00:00
actions-bot 34aa40e9cf build: update distribution (#4289) 2026-01-15 07:55:19 +00:00
dependabot[bot] 641099ddca build(deps-dev): bump undici from 6.22.0 to 6.23.0 (#4284)
Bumps [undici](https://github.com/nodejs/undici) from 6.22.0 to 6.23.0.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v6.22.0...v6.23.0)

---
updated-dependencies:
- dependency-name: undici
  dependency-version: 6.23.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-15 00:49:39 +00:00
dependabot[bot] 2271f1ddcf build(deps-dev): bump the npm group with 2 updates (#4274)
Bumps the npm group with 2 updates: [prettier](https://github.com/prettier/prettier) and [ts-jest](https://github.com/kulshekhar/ts-jest).


Updates `prettier` from 3.7.3 to 3.7.4
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.7.3...3.7.4)

Updates `ts-jest` from 29.4.5 to 29.4.6
- [Release notes](https://github.com/kulshekhar/ts-jest/releases)
- [Changelog](https://github.com/kulshekhar/ts-jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/kulshekhar/ts-jest/compare/v29.4.5...v29.4.6)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.7.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
- dependency-name: ts-jest
  dependency-version: 29.4.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-01 12:04:07 +00:00
dependabot[bot] 437c31a11d build(deps): bump the github-actions group with 2 updates (#4273)
Bumps the github-actions group with 2 updates: [actions/upload-artifact](https://github.com/actions/upload-artifact) and [actions/download-artifact](https://github.com/actions/download-artifact).


Updates `actions/upload-artifact` from 5 to 6
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

Updates `actions/download-artifact` from 6 to 7
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-01 12:03:28 +00:00
Peter Evans 0979079bc2 docs: update readme 2025-12-10 07:32:05 +00:00
Andreas Deininger 5b751cdf40 README.md: bump given GitHub actions to their latest versions (#4265)
Co-authored-by: Andreas Deininger <adeininger@urbanonline.de>
2025-12-10 07:30:53 +00:00
12 changed files with 1352 additions and 1267 deletions
+6 -6
View File
@@ -29,11 +29,11 @@ jobs:
- run: npm run format-check
- run: npm run lint
- run: npm run test
- uses: actions/upload-artifact@v5
- uses: actions/upload-artifact@v7
with:
name: dist
path: dist
- uses: actions/upload-artifact@v5
- uses: actions/upload-artifact@v7
with:
name: action.yml
path: action.yml
@@ -50,12 +50,12 @@ jobs:
with:
ref: main
- if: matrix.target == 'built' || github.event_name == 'pull_request'
uses: actions/download-artifact@v6
uses: actions/download-artifact@v8
with:
name: dist
path: dist
- if: matrix.target == 'built' || github.event_name == 'pull_request'
uses: actions/download-artifact@v6
uses: actions/download-artifact@v8
with:
name: action.yml
path: .
@@ -119,12 +119,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/download-artifact@v6
- uses: actions/download-artifact@v8
with:
name: dist
path: dist
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
uses: peter-evans/create-pull-request@v8
with:
token: ${{ secrets.ACTIONS_BOT_TOKEN }}
commit-message: 'build: update distribution'
+9 -9
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@v7
uses: peter-evans/create-pull-request@v8
```
You can also pin to a [specific release](https://github.com/peter-evans/create-pull-request/releases) version in the format `@v7.x.x`
You can also pin to a [specific release](https://github.com/peter-evans/create-pull-request/releases) version in the format `@v8.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@v7
uses: peter-evans/create-pull-request@v8
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@v7
uses: peter-evans/create-pull-request@v8
- 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@v7
uses: peter-evans/create-pull-request@v8
with:
add-paths: |
*.java
@@ -230,7 +230,7 @@ Note that the repository must be checked out on a branch with a remote, it won't
```yml
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Create commits
run: |
git config user.name 'Peter Evans'
@@ -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@v7
uses: peter-evans/create-pull-request@v8
```
### Auto-merge
@@ -263,14 +263,14 @@ jobs:
createPullRequest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Make changes to pull request
run: date +%s > report.txt
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@v7
uses: peter-evans/create-pull-request@v8
with:
token: ${{ secrets.PAT }}
commit-message: Update report
+75 -75
View File
@@ -4,10 +4,10 @@ import {
getWorkingBaseAndType,
buildBranchCommits
} from '../lib/create-or-update-branch'
import {randomUUID} from 'crypto'
import * as fs from 'fs'
import {GitCommandManager} from '../lib/git-command-manager'
import * as path from 'path'
import {v4 as uuidv4} from 'uuid'
const REPO_PATH = '/git/local/repos/test-base'
const REMOTE_NAME = 'origin'
@@ -31,7 +31,7 @@ const ADD_PATHS_MULTI = ['a', 'b']
const ADD_PATHS_WILDCARD = ['a/*.txt', 'b/*.txt']
async function createFile(filename: string, content?: string): Promise<string> {
const _content = content ? content : uuidv4()
const _content = content ? content : randomUUID()
const filepath = path.join(REPO_PATH, filename)
await fs.promises.mkdir(path.dirname(filepath), {recursive: true})
await fs.promises.writeFile(filepath, _content, {encoding: 'utf8'})
@@ -82,7 +82,7 @@ async function createCommits(
} else {
result.changes = await createChanges()
}
const commitMessage = uuidv4()
const commitMessage = randomUUID()
await git.exec(['add', '-A'])
await git.commit(['-m', commitMessage])
result.commitMsgs.unshift(commitMessage)
@@ -313,7 +313,7 @@ describe('create-or-update-branch tests', () => {
})
it('tests no changes resulting in no new branch being created', async () => {
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -330,7 +330,7 @@ describe('create-or-update-branch tests', () => {
it('tests create and update with a tracked file change', async () => {
// Create a tracked file change
const trackedContent = await createFile(TRACKED_FILE)
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -359,7 +359,7 @@ describe('create-or-update-branch tests', () => {
// Create a tracked file change
const _trackedContent = await createFile(TRACKED_FILE)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -381,7 +381,7 @@ describe('create-or-update-branch tests', () => {
it('tests create and update with an untracked file change', async () => {
// Create an untracked file change
const untrackedContent = await createFile(UNTRACKED_FILE)
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -410,7 +410,7 @@ describe('create-or-update-branch tests', () => {
// Create an untracked file change
const _untrackedContent = await createFile(UNTRACKED_FILE)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -434,7 +434,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -464,7 +464,7 @@ describe('create-or-update-branch tests', () => {
// Create identical tracked and untracked file changes
await createChanges(changes.tracked, changes.untracked)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -486,7 +486,7 @@ describe('create-or-update-branch tests', () => {
it('tests create and update with commits on the base inbetween', async () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -524,7 +524,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -556,7 +556,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -585,7 +585,7 @@ describe('create-or-update-branch tests', () => {
await beforeTest()
// Running with no update effectively reverts the branch back to match the base
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -607,7 +607,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -648,7 +648,7 @@ describe('create-or-update-branch tests', () => {
commits.changes.tracked,
commits.changes.untracked
)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -673,7 +673,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -703,7 +703,7 @@ describe('create-or-update-branch tests', () => {
// Create a commit on the base with a partial merge of the changes
await createFile(TRACKED_FILE, changes.tracked)
const baseCommitMessage = uuidv4()
const baseCommitMessage = randomUUID()
await git.exec(['add', '-A'])
await git.commit(['-m', baseCommitMessage])
await git.push([
@@ -714,7 +714,7 @@ describe('create-or-update-branch tests', () => {
// Create the same tracked and untracked file changes
const _changes = await createChanges(changes.tracked, changes.untracked)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -746,7 +746,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -790,7 +790,7 @@ describe('create-or-update-branch tests', () => {
// Create the same tracked and untracked file changes (no change on update)
const _changes = await createChanges(changes.tracked, changes.untracked)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -816,7 +816,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -845,7 +845,7 @@ describe('create-or-update-branch tests', () => {
await beforeTest()
// Force push the base branch to a different commit
const amendedCommitMessage = uuidv4()
const amendedCommitMessage = randomUUID()
await git.commit(['--amend', '-m', amendedCommitMessage])
await git.push([
'--force',
@@ -855,7 +855,7 @@ describe('create-or-update-branch tests', () => {
// Create the same tracked and untracked file changes (no change on update)
const _changes = await createChanges(changes.tracked, changes.untracked)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -878,7 +878,7 @@ describe('create-or-update-branch tests', () => {
it('tests create and update with commits on the working base (during the workflow)', async () => {
// Create commits on the working base
const commits = await createCommits(git)
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -910,7 +910,7 @@ describe('create-or-update-branch tests', () => {
// Create commits on the working base
const _commits = await createCommits(git)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -937,7 +937,7 @@ describe('create-or-update-branch tests', () => {
const commits = await createCommits(git)
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -973,7 +973,7 @@ describe('create-or-update-branch tests', () => {
const _commits = await createCommits(git)
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -1002,7 +1002,7 @@ describe('create-or-update-branch tests', () => {
const commits = await createCommits(git)
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1046,7 +1046,7 @@ describe('create-or-update-branch tests', () => {
const _commits = await createCommits(git)
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -1074,7 +1074,7 @@ describe('create-or-update-branch tests', () => {
it('tests create and update using a different remote from the base', async () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1104,7 +1104,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -1127,7 +1127,7 @@ describe('create-or-update-branch tests', () => {
it('tests create and update with signoff on commit', async () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1164,7 +1164,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -1194,7 +1194,7 @@ describe('create-or-update-branch tests', () => {
it('tests create and update with multiple add-paths', async () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1224,7 +1224,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -1247,7 +1247,7 @@ describe('create-or-update-branch tests', () => {
it('tests create and update with wildcard add-paths', async () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1277,7 +1277,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -1300,7 +1300,7 @@ describe('create-or-update-branch tests', () => {
it('tests create with add-paths resolving to no changes when other changes exist', async () => {
// Create tracked and untracked file changes
await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1321,7 +1321,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const resultA = await createOrUpdateBranch(
git,
commitMessage,
@@ -1365,7 +1365,7 @@ describe('create-or-update-branch tests', () => {
// Set the working base to a branch that is not the pull request base
await git.checkout(NOT_BASE_BRANCH)
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1386,7 +1386,7 @@ describe('create-or-update-branch tests', () => {
// Create a tracked file change
const trackedContent = await createFile(TRACKED_FILE)
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1418,7 +1418,7 @@ describe('create-or-update-branch tests', () => {
// Create a tracked file change
const _trackedContent = await createFile(TRACKED_FILE)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -1443,7 +1443,7 @@ describe('create-or-update-branch tests', () => {
// Create an untracked file change
const untrackedContent = await createFile(UNTRACKED_FILE)
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1475,7 +1475,7 @@ describe('create-or-update-branch tests', () => {
// Create an untracked file change
const _untrackedContent = await createFile(UNTRACKED_FILE)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -1502,7 +1502,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1535,7 +1535,7 @@ describe('create-or-update-branch tests', () => {
// Create identical tracked and untracked file changes
await createChanges(changes.tracked, changes.untracked)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -1560,7 +1560,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1601,7 +1601,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -1635,7 +1635,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1667,7 +1667,7 @@ describe('create-or-update-branch tests', () => {
await git.checkout(NOT_BASE_BRANCH)
// Running with no update effectively reverts the branch back to match the base
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -1694,7 +1694,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1738,7 +1738,7 @@ describe('create-or-update-branch tests', () => {
commits.changes.tracked,
commits.changes.untracked
)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -1768,7 +1768,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1798,7 +1798,7 @@ describe('create-or-update-branch tests', () => {
// Create a commit on the base with a partial merge of the changes
await createFile(TRACKED_FILE, changes.tracked)
const baseCommitMessage = uuidv4()
const baseCommitMessage = randomUUID()
await git.exec(['add', '-A'])
await git.commit(['-m', baseCommitMessage])
await git.push([
@@ -1812,7 +1812,7 @@ describe('create-or-update-branch tests', () => {
// Create the same tracked and untracked file changes
const _changes = await createChanges(changes.tracked, changes.untracked)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -1846,7 +1846,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1893,7 +1893,7 @@ describe('create-or-update-branch tests', () => {
// Create the same tracked and untracked file changes (no change on update)
const _changes = await createChanges(changes.tracked, changes.untracked)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -1924,7 +1924,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -1953,7 +1953,7 @@ describe('create-or-update-branch tests', () => {
await beforeTest()
// Force push the base branch to a different commit
const amendedCommitMessage = uuidv4()
const amendedCommitMessage = randomUUID()
await git.commit(['--amend', '-m', amendedCommitMessage])
await git.push([
'--force',
@@ -1966,7 +1966,7 @@ describe('create-or-update-branch tests', () => {
// Create the same tracked and untracked file changes (no change on update)
const _changes = await createChanges(changes.tracked, changes.untracked)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -1992,7 +1992,7 @@ describe('create-or-update-branch tests', () => {
// Create commits on the working base
const commits = await createCommits(git)
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -2027,7 +2027,7 @@ describe('create-or-update-branch tests', () => {
// Create commits on the working base
const _commits = await createCommits(git)
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -2057,7 +2057,7 @@ describe('create-or-update-branch tests', () => {
const commits = await createCommits(git)
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -2096,7 +2096,7 @@ describe('create-or-update-branch tests', () => {
const _commits = await createCommits(git)
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -2128,7 +2128,7 @@ describe('create-or-update-branch tests', () => {
const commits = await createCommits(git)
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -2175,7 +2175,7 @@ describe('create-or-update-branch tests', () => {
const _commits = await createCommits(git)
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -2205,7 +2205,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -2238,7 +2238,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -2268,7 +2268,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -2302,7 +2302,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -2329,7 +2329,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -2371,7 +2371,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const _changes = await createChanges()
const _commitMessage = uuidv4()
const _commitMessage = randomUUID()
const _result = await createOrUpdateBranch(
git,
_commitMessage,
@@ -2403,7 +2403,7 @@ describe('create-or-update-branch tests', () => {
// Create commits on the working base
const commits = await createCommits(git)
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const result = await createOrUpdateBranch(
git,
commitMessage,
@@ -2428,7 +2428,7 @@ describe('create-or-update-branch tests', () => {
// Create tracked and untracked file changes
const changes = await createChanges()
const commitMessage = uuidv4()
const commitMessage = randomUUID()
const resultA = await createOrUpdateBranch(
git,
commitMessage,
+68
View File
@@ -118,3 +118,71 @@ describe('utils tests', () => {
}
})
})
describe('retryWithBackoff', () => {
const makeConsistencyError = () => {
const error = new Error(
'Validation Failed: "Could not resolve to a node with the global id of \'PR_abc123\'."'
)
;(error as any).status = 422
return error
}
const shouldRetry = (e: unknown): boolean =>
e instanceof Error &&
(e as any).status === 422 &&
e.message.includes('Could not resolve to a node')
test('succeeds on first attempt without retrying', async () => {
const fn = jest.fn().mockResolvedValue('success')
const result = await utils.retryWithBackoff(fn, shouldRetry, 2, 1)
expect(result).toBe('success')
expect(fn).toHaveBeenCalledTimes(1)
})
test('retries on eventual consistency 422 and succeeds', async () => {
const fn = jest
.fn()
.mockRejectedValueOnce(makeConsistencyError())
.mockResolvedValue('success')
const result = await utils.retryWithBackoff(fn, shouldRetry, 2, 1)
expect(result).toBe('success')
expect(fn).toHaveBeenCalledTimes(2)
})
test('exhausts retries on persistent 422 and throws', async () => {
const fn = jest.fn().mockRejectedValue(makeConsistencyError())
await expect(utils.retryWithBackoff(fn, shouldRetry, 2, 1)).rejects.toThrow(
'Could not resolve to a node'
)
expect(fn).toHaveBeenCalledTimes(3) // 1 initial + 2 retries
})
test('does not retry on non-422 errors', async () => {
const error = new Error('Forbidden')
;(error as any).status = 403
const fn = jest.fn().mockRejectedValue(error)
await expect(utils.retryWithBackoff(fn, shouldRetry, 2, 1)).rejects.toThrow(
'Forbidden'
)
expect(fn).toHaveBeenCalledTimes(1)
})
test('does not retry on 422 without the consistency error message', async () => {
const error = new Error('Validation Failed: invalid label')
;(error as any).status = 422
const fn = jest.fn().mockRejectedValue(error)
await expect(utils.retryWithBackoff(fn, shouldRetry, 2, 1)).rejects.toThrow(
'Validation Failed: invalid label'
)
expect(fn).toHaveBeenCalledTimes(1)
})
test('does not retry on plain Error objects', async () => {
const fn = jest.fn().mockRejectedValue(new Error('Something broke'))
await expect(utils.retryWithBackoff(fn, shouldRetry, 2, 1)).rejects.toThrow(
'Something broke'
)
expect(fn).toHaveBeenCalledTimes(1)
})
})
+227 -739
View File
File diff suppressed because it is too large Load Diff
+870 -407
View File
File diff suppressed because it is too large Load Diff
+8 -7
View File
@@ -37,10 +37,11 @@
"@octokit/core": "^6.1.6",
"@octokit/plugin-paginate-rest": "^11.6.0",
"@octokit/plugin-rest-endpoint-methods": "^13.5.0",
"@octokit/plugin-retry": "^7.2.1",
"@octokit/plugin-throttling": "^9.6.1",
"@octokit/request-error": "^6.1.8",
"node-fetch-native": "^1.6.7",
"p-limit": "^6.2.0",
"uuid": "^9.0.1"
"p-limit": "^6.2.0"
},
"devDependencies": {
"@types/jest": "^29.5.14",
@@ -53,14 +54,14 @@
"eslint-plugin-github": "^4.10.2",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jest": "^27.9.0",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-prettier": "^5.5.5",
"jest": "^29.7.0",
"jest-circus": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-environment-jsdom": "^30.3.0",
"js-yaml": "^4.1.1",
"prettier": "^3.7.3",
"ts-jest": "^29.4.5",
"prettier": "^3.8.3",
"ts-jest": "^29.4.9",
"typescript": "^5.9.3",
"undici": "^6.22.0"
"undici": "^6.25.0"
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
import * as core from '@actions/core'
import {randomUUID} from 'crypto'
import {GitCommandManager, Commit} from './git-command-manager'
import {v4 as uuidv4} from 'uuid'
import * as utils from './utils'
const CHERRYPICK_EMPTY =
@@ -189,7 +189,7 @@ export async function createOrUpdateBranch(
const baseRemote = 'origin'
// Save the working base changes to a temporary branch
const tempBranch = uuidv4()
const tempBranch = randomUUID()
await git.checkout(tempBranch, 'HEAD')
// Commit any uncommitted changes
if (await git.isDirty(true, addPaths)) {
+7 -1
View File
@@ -127,7 +127,13 @@ export async function createPullRequest(inputs: Inputs): Promise<void> {
// deleted after being merged or closed. Without this the push using
// '--force-with-lease' fails due to "stale info."
// https://github.com/peter-evans/create-pull-request/issues/633
await git.exec(['remote', 'prune', branchRemoteName])
try {
await git.exec(['remote', 'prune', branchRemoteName])
} catch (error) {
core.warning(
`Failed to prune remote '${branchRemoteName}': ${(error as Error).message}`
)
}
}
core.endGroup()
+49 -21
View File
@@ -1,7 +1,13 @@
import * as core from '@actions/core'
import {RequestError} from '@octokit/request-error'
import {Inputs} from './create-pull-request'
import {Commit, GitCommandManager} from './git-command-manager'
import {Octokit, OctokitOptions, throttleOptions} from './octokit-client'
import {
Octokit,
OctokitOptions,
retryOptions,
throttleOptions
} from './octokit-client'
import pLimit from 'p-limit'
import * as utils from './utils'
@@ -52,6 +58,7 @@ export class GitHubHelper {
options.baseUrl = 'https://api.github.com'
}
options.throttle = throttleOptions
options.retry = retryOptions
this.octokit = new Octokit(options)
}
@@ -203,32 +210,51 @@ export class GitHubHelper {
headRepository
)
// After creating a new PR, follow-up API calls can fail with a 422
// "Could not resolve to a node" error due to GitHub API eventual
// consistency. Wrap post-creation calls with targeted retry logic.
// See: https://github.com/peter-evans/create-pull-request/issues/4321
const isEventualConsistencyError = (e: unknown): boolean =>
e instanceof RequestError &&
e.status === 422 &&
e.message.includes('Could not resolve to a node')
const withRetryForNewPr = <T>(fn: () => Promise<T>): Promise<T> =>
pull.created
? utils.retryWithBackoff(fn, isEventualConsistencyError)
: fn()
// Apply milestone
if (inputs.milestone) {
core.info(`Applying milestone '${inputs.milestone}'`)
await this.octokit.rest.issues.update({
...this.parseRepository(baseRepository),
issue_number: pull.number,
milestone: inputs.milestone
})
await withRetryForNewPr(() =>
this.octokit.rest.issues.update({
...this.parseRepository(baseRepository),
issue_number: pull.number,
milestone: inputs.milestone
})
)
}
// Apply labels
if (inputs.labels.length > 0) {
core.info(`Applying labels '${inputs.labels}'`)
await this.octokit.rest.issues.addLabels({
...this.parseRepository(baseRepository),
issue_number: pull.number,
labels: inputs.labels
})
await withRetryForNewPr(() =>
this.octokit.rest.issues.addLabels({
...this.parseRepository(baseRepository),
issue_number: pull.number,
labels: inputs.labels
})
)
}
// Apply assignees
if (inputs.assignees.length > 0) {
core.info(`Applying assignees '${inputs.assignees}'`)
await this.octokit.rest.issues.addAssignees({
...this.parseRepository(baseRepository),
issue_number: pull.number,
assignees: inputs.assignees
})
await withRetryForNewPr(() =>
this.octokit.rest.issues.addAssignees({
...this.parseRepository(baseRepository),
issue_number: pull.number,
assignees: inputs.assignees
})
)
}
// Request reviewers and team reviewers
@@ -244,11 +270,13 @@ export class GitHubHelper {
}
if (Object.keys(requestReviewersParams).length > 0) {
try {
await this.octokit.rest.pulls.requestReviewers({
...this.parseRepository(baseRepository),
pull_number: pull.number,
...requestReviewersParams
})
await withRetryForNewPr(() =>
this.octokit.rest.pulls.requestReviewers({
...this.parseRepository(baseRepository),
pull_number: pull.number,
...requestReviewersParams
})
)
} catch (e) {
if (utils.getErrorMessage(e).includes(ERROR_PR_REVIEW_TOKEN_SCOPE)) {
core.error(
+7
View File
@@ -2,6 +2,7 @@ import * as core from '@actions/core'
import {Octokit as OctokitCore} from '@octokit/core'
import {paginateRest} from '@octokit/plugin-paginate-rest'
import {restEndpointMethods} from '@octokit/plugin-rest-endpoint-methods'
import {retry} from '@octokit/plugin-retry'
import {throttling} from '@octokit/plugin-throttling'
import {fetch} from 'node-fetch-native/proxy'
export {RestEndpointMethodTypes} from '@octokit/plugin-rest-endpoint-methods'
@@ -11,6 +12,7 @@ export {OctokitOptions} from '@octokit/core/dist-types/types'
export const Octokit = OctokitCore.plugin(
paginateRest,
restEndpointMethods,
retry,
throttling,
autoProxyAgent
)
@@ -32,6 +34,11 @@ export const throttleOptions = {
}
}
export const retryOptions = {
// 429 is handled by the throttling plugin, so we exclude it from retry
doNotRetry: [400, 401, 403, 404, 410, 422, 429, 451]
}
// Octokit plugin to support the standard environment variables http_proxy, https_proxy and no_proxy
function autoProxyAgent(octokit: OctokitCore) {
octokit.hook.before('request', options => {
+24
View File
@@ -140,3 +140,27 @@ export const isSelfHosted = (): boolean =>
process.env['RUNNER_ENVIRONMENT'] !== 'github-hosted' &&
(process.env['AGENT_ISSELFHOSTED'] === '1' ||
process.env['AGENT_ISSELFHOSTED'] === undefined)
export async function retryWithBackoff<T>(
fn: () => Promise<T>,
shouldRetry: (error: unknown) => boolean,
maxRetries = 2,
delayMs = 1000
): Promise<T> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn()
} catch (e) {
if (attempt < maxRetries && shouldRetry(e)) {
const delay = delayMs * Math.pow(2, attempt)
core.info(
`Request failed (attempt ${attempt + 1}/${maxRetries + 1}), retrying in ${delay}ms...`
)
await new Promise(resolve => setTimeout(resolve, delay))
} else {
throw e
}
}
}
throw new Error('Unexpected: retry loop exited without return or throw')
}