Skip to content
Open
Changes from all commits
Commits
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
46 changes: 37 additions & 9 deletions .github/workflows/release-earn-apps.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ on:

permissions:
contents: write
pull-requests: write

jobs:
release:
Expand Down Expand Up @@ -56,15 +57,42 @@ jobs:
env:
GITHUB_TOKEN: ${{ github.token }}

- name: Merge dev -> main
run: |
git status
git pull
git fetch
git checkout main
git rebase dev
git push origin main
git status
- name: Create or reuse PR from dev to main
uses: actions/github-script@v7
with:
github-token: ${{ github.token }}
script: |
const owner = context.repo.owner
const repo = context.repo.repo
const head = 'dev'
const base = 'main'
Comment on lines +60 to +68

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/release-earn-apps.yaml

Repository: OasisDEX/summerfi-monorepo

Length of output: 4721


Checkout must pin to dev or workflow dispatch branch mismatch can cause wrong release.

Workflow can be dispatched from any branch but checkout is not pinned. Line 67 hardcodes head = 'dev' for PR creation, so releasing from main checks out main, tags main, but tries to open PR from dev → main.

Add ref: dev to checkout step.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release-earn-apps.yaml around lines 60 - 68, The checkout
step is not pinned which can mismatch with the hardcoded head = 'dev' used when
creating the PR; update the checkout action (the step that uses
actions/checkout) to include ref: 'dev' so the workspace actually checks out the
dev branch before tagging and PR creation, and leave the PR creation logic that
sets head = 'dev' unchanged; target the checkout step by its uses:
'actions/checkout' reference and ensure ref: 'dev' is added.

const title = 'chore: merge dev into main after earn release'
const body = 'Automated PR opened by release-earn-apps workflow.'

const { data: prs } = await github.rest.pulls.list({
owner,
repo,
state: 'open',
head: `${owner}:${head}`,
base,
per_page: 1,
})

if (prs.length > 0) {
core.info(`PR already open: #${prs[0].number} ${prs[0].html_url}`)
return
}

const { data: pr } = await github.rest.pulls.create({
owner,
repo,
head,
base,
title,
body,
})
Comment on lines +86 to +93

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -name "release-earn-apps.yaml" -type f

Repository: OasisDEX/summerfi-monorepo

Length of output: 112


🏁 Script executed:

cat -n .github/workflows/release-earn-apps.yaml | sed -n '70,110p'

Repository: OasisDEX/summerfi-monorepo

Length of output: 1610


🏁 Script executed:

cat -n .github/workflows/release-earn-apps.yaml

Repository: OasisDEX/summerfi-monorepo

Length of output: 4721


🌐 Web query:

GitHub REST API PR creation 422 error when PR already exists

💡 Result:

When you call POST /repos/{owner}/{repo}/pulls to create a PR and GitHub returns 422 Unprocessable Entity, one common cause is that an open PR already exists for the same headbase combination (the API responds with a validation error like “A pull request already exists for owner:branch”) [3]. GitHub documents that this endpoint can return 422 “Validation failed” [1].

GitHub’s REST API does not provide an “idempotent create PR” option (i.e., you can’t ask it to return 201/OK if the PR already exists); you need to handle it in your client by detecting the existing PR and treating that case as success [2].

Practical fix (recommended pattern)

  1. Before creating, query for an existing PR using List pull requests with head and (optionally) base filters:
    • GET /repos/{owner}/{repo}/pulls?state=open&head=OWNER:branch&base=main
      GitHub supports filtering PRs by head in user:ref-name format and by base branch name [1].
  2. If the list returns a PR, reuse its number/URL instead of calling create again.
  3. Otherwise, call Create a pull request.

This avoids relying on parsing the 422 message, and prevents repeated create attempts that will always fail once a PR exists. [1]


🌐 Web query:

GitHub API pulls.create 422 Unprocessable Entity error conditions

💡 Result:

For POST /repos/{owner}/{repo}/pulls (“pulls.create”), GitHub returns 422 Unprocessable Entity when the request can’t be validated/processed (or the endpoint is being “spammed”). (docs.github.com)

Common 422 causes for creating a pull request:

  • Missing required fields in the JSON body:

    • head is required (docs.github.com)
    • base is required (docs.github.com)
    • title is required unless you supply issue (and issue is required unless you supply title) (docs.github.com)
    • These typically show up as "message": "Validation Failed" with an entry in errors[] like code: "missing_field". (docs.github.com)
  • Invalid head (very common):

    • The branch name doesn’t exist on GitHub (only local / not pushed yet), or
    • For a PR from a fork, head must be namespaced like username:branch (otherwise it’s “invalid”). (docs.github.com)
  • Invalid base:

    • base must be an existing branch on the current repo, and you can’t target a base branch in a different repository. (docs.github.com)
  • No commits/diffs between head and base:

    • GitHub can reject the PR with a validation error like “No commits between …”. (stackoverflow.com)
  • A PR already exists for the same head:

    • Often returned as a "code": "custom" validation error with a message like “A pull request already exists for …”. (knowledge.broadcom.com)
  • GitHub can’t read the refs you referenced (permissions / token scopes):

    • Example validation error: "not all refs are readable", commonly fixed by ensuring the token/app has appropriate Contents: read access. (stackoverflow.com)

How to quickly pinpoint which one you hit:

  • Inspect the response body’s errors[] entries (code values like missing_field, invalid, already_exists, unprocessable, custom)—GitHub documents what these codes mean. (docs.github.com)

Citations:


Handle concurrent PR creation to prevent 422 errors.

The list check at lines 72-84 doesn't prevent the race condition when two workflow runs execute concurrently and both pass the check before either creates the PR. Add try-catch on 422 to handle idempotently.

Suggested fix
-            const { data: pr } = await github.rest.pulls.create({
-              owner,
-              repo,
-              head,
-              base,
-              title,
-              body,
-            })
-
-            core.info(`Created PR: #${pr.number} ${pr.html_url}`)
+            try {
+              const { data: pr } = await github.rest.pulls.create({
+                owner,
+                repo,
+                head,
+                base,
+                title,
+                body,
+              })
+              core.info(`Created PR: #${pr.number} ${pr.html_url}`)
+            } catch (error) {
+              if (error.status === 422) {
+                core.info('PR already exists; skipping.')
+                return
+              }
+              throw error
+            }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { data: pr } = await github.rest.pulls.create({
owner,
repo,
head,
base,
title,
body,
})
try {
const { data: pr } = await github.rest.pulls.create({
owner,
repo,
head,
base,
title,
body,
})
core.info(`Created PR: #${pr.number} ${pr.html_url}`)
} catch (error) {
if (error.status === 422) {
core.info('PR already exists; skipping.')
return
}
throw error
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release-earn-apps.yaml around lines 86 - 93, Wrap the
github.rest.pulls.create call in a try-catch and handle HTTP 422
(already_exists) idempotently: catch errors from the create call (where the code
currently does const { data: pr } = await github.rest.pulls.create({...})), and
if err.status === 422, re-query the repo for the matching PR (e.g., via
github.rest.pulls.list with the same head/base/title) and use the existing PR
data instead of failing; for other errors rethrow or log and fail as
appropriate.


core.info(`Created PR: #${pr.number} ${pr.html_url}`)

- name: Generate GitHub App token for e2e-tests
id: e2e_tests_app_token
Expand Down
Loading