ci: switch actions freshness tracker from issues to draft PR#104
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Review Summary by QodoSwitch actions freshness tracker from issues to draft PR
WalkthroughsDescription• Replace issue-based tracking with draft pull request management • Add support for managing tracker via dedicated branch and file • Update workflow permissions from issues/read to pull-requests/write • Support backward compatibility with --issue-title and --manage-issue flags Diagramflowchart LR
A["Issue-based Tracking"] -->|Replace| B["Draft PR Tracking"]
B --> C["Dedicated Branch"]
B --> D["Tracker File"]
B --> E["PR Management"]
C --> F["automation/actions-freshness-tracker"]
D --> G[".github/actions-freshness-tracker.md"]
E --> H["Create/Update/Close PR"]
File Changes1. scripts/audit-actions-freshness.js
|
Reviewer's GuideSwitches the actions freshness automation from managing an issue to managing a draft tracker pull request, including new CLI options, GitHub API workflow for maintaining a tracker branch and file, and workflow permission updates. Sequence diagram for managing tracker pull request when findings existsequenceDiagram
actor GitHubActionsRunner
participant AuditScript as audit_actions_freshness_js
participant GitHubAPI
GitHubActionsRunner->>AuditScript: node scripts/audit-actions-freshness.js --manage-pr
AuditScript->>AuditScript: parseArguments(argv)
AuditScript->>AuditScript: scanWorkflowsAndBuildReports()
AuditScript->>AuditScript: writeReportFiles()
AuditScript->>AuditScript: upsertTrackingPullRequest(token, owner, repository, pullRequestTitle, pullRequestBranch, pullRequestFilePath, staleCount, resolutionErrorCount, reportMarkdown)
alt existing_open_tracker_pr
AuditScript->>GitHubAPI: GET /pulls?state=open&head=owner:pullRequestBranch
GitHubAPI-->>AuditScript: 200 existing_pull_requests
else no_existing_tracker_pr
AuditScript->>GitHubAPI: GET /pulls?state=open&head=owner:pullRequestBranch
GitHubAPI-->>AuditScript: 200 []
end
AuditScript->>GitHubAPI: GET /repos/owner/repository
GitHubAPI-->>AuditScript: 200 { default_branch }
AuditScript->>GitHubAPI: GET /git/ref/heads/default_branch
GitHubAPI-->>AuditScript: 200 { sha }
alt tracking_branch_exists
AuditScript->>GitHubAPI: GET /git/ref/heads/pullRequestBranch
GitHubAPI-->>AuditScript: 200 { sha }
else tracking_branch_missing
AuditScript->>GitHubAPI: POST /git/refs (ref=refs/heads/pullRequestBranch, sha=default_branch_sha)
GitHubAPI-->>AuditScript: 201 ref_created
end
AuditScript->>GitHubAPI: GET /contents/pullRequestFilePath?ref=pullRequestBranch
alt file_exists
GitHubAPI-->>AuditScript: 200 { sha, content }
AuditScript->>GitHubAPI: PUT /contents/pullRequestFilePath (branch=pullRequestBranch, content=updated_file, sha=existing_sha)
GitHubAPI-->>AuditScript: 200 file_updated
else file_missing
GitHubAPI-->>AuditScript: 404
AuditScript->>GitHubAPI: PUT /contents/pullRequestFilePath (branch=pullRequestBranch, content=new_file)
GitHubAPI-->>AuditScript: 201 file_created
end
alt tracker_pr_exists
AuditScript->>GitHubAPI: PATCH /pulls/trackingPullRequestNumber (title=pullRequestTitle, body=marker_plus_report)
GitHubAPI-->>AuditScript: 200 pull_request_updated
else tracker_pr_missing
AuditScript->>GitHubAPI: POST /pulls (title=pullRequestTitle, head=pullRequestBranch, base=default_branch, body=marker_plus_report, draft=true)
GitHubAPI-->>AuditScript: 201 draft_pull_request_created
end
AuditScript-->>GitHubActionsRunner: exit 0 with report paths
Sequence diagram for closing tracker pull request when repository is cleansequenceDiagram
actor GitHubActionsRunner
participant AuditScript as audit_actions_freshness_js
participant GitHubAPI
GitHubActionsRunner->>AuditScript: node scripts/audit-actions-freshness.js --manage-pr
AuditScript->>AuditScript: parseArguments(argv)
AuditScript->>AuditScript: scanWorkflowsAndBuildReports()
AuditScript->>AuditScript: writeReportFiles()
AuditScript->>AuditScript: upsertTrackingPullRequest(..., staleCount=0, resolutionErrorCount=0, ...)
AuditScript->>GitHubAPI: GET /pulls?state=open&head=owner:pullRequestBranch
alt tracker_pr_found
GitHubAPI-->>AuditScript: 200 [tracking_pull_request]
AuditScript->>GitHubAPI: PATCH /pulls/trackingPullRequestNumber (state=closed)
GitHubAPI-->>AuditScript: 200 pull_request_closed
else no_tracker_pr
GitHubAPI-->>AuditScript: 200 []
AuditScript-->>GitHubActionsRunner: no_action_needed
end
AuditScript-->>GitHubActionsRunner: exit 0 with report paths
Class diagram for updated actions freshness tracker scriptclassDiagram
class ScriptOptions {
string reportPath
string jsonPath
string workflowDirectory
boolean failOnStale
boolean managePullRequest
string pullRequestTitle
string pullRequestBranch
string pullRequestFilePath
}
class AuditActionsFreshnessModule {
+parseArguments(argv)
+buildMarkdownReport(results)
+buildJsonReport(results)
+getRepositoryMetadata(owner, repository, token)
+ensureTrackingPullRequestBranch(owner, repository, token, defaultBranch, trackingBranch)
+upsertTrackingPullRequestFile(owner, repository, token, trackingBranch, filePath, content)
+findTrackingPullRequest(owner, repository, token, trackingBranch)
+closeTrackingPullRequest(owner, repository, pullRequestNumber, token)
+upsertTrackingPullRequest(token, owner, repository, pullRequestTitle, pullRequestBranch, pullRequestFilePath, staleCount, resolutionErrorCount, reportMarkdown)
+run()
}
class GitHubAPIHelpers {
+githubRequest(endpoint, token, method, body)
+toGitHubRefPath(value)
+toGitHubContentPath(filePath)
}
class Reports {
number staleCount
number resolutionErrorCount
string markdownReport
string jsonReport
}
AuditActionsFreshnessModule --> ScriptOptions : uses
AuditActionsFreshnessModule --> GitHubAPIHelpers : calls
AuditActionsFreshnessModule --> Reports : produces
GitHubAPIHelpers <.. Reports : data sent via githubRequest
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
📝 WalkthroughWalkthroughReplaces issue-based tracking with pull-request-based tracking for the actions-freshness audit: workflow permissions updated for PR creation, CLI flag switched from Changes
Sequence Diagram(s)sequenceDiagram
participant Action as GitHub Action
participant Script as audit-actions-freshness.js
participant GHAPI as GitHub REST API
participant Repo as Repository (branches, files, PRs)
Action->>Script: run with --manage-pr + token
Script->>GHAPI: getRepositoryMetadata()
GHAPI-->>Script: default branch, repo info
Script->>GHAPI: ensureTrackingPullRequestBranch(trackingBranch)
GHAPI-->>Repo: create/update branch ref
Script->>GHAPI: findTrackingPullRequest(trackingBranch)
alt PR exists
GHAPI-->>Script: pull request found
Script->>GHAPI: upsertTrackingPullRequestFile(trackingBranch, filePath, content)
GHAPI-->>Repo: update file in tracking branch
Script->>GHAPI: upsertTrackingPullRequest(...)
else PR missing
Script->>GHAPI: create tracking branch and file
GHAPI-->>Repo: branch+file created
Script->>GHAPI: create pull request from trackingBranch
end
GHAPI-->>Script: PR created/updated or permission error
alt permission error
Script->>Action: appendStepSummaryWarning()
end
Script->>Action: exit with status
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 OpenGrep (1.16.0)scripts/audit-actions-freshness.js┌──────────────┐ �[32m✔�[39m �[1mOpengrep OSS�[0m �[1m Loading rules from local config...�[0m Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello @Mehdi-Bl, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request transitions the automated GitHub Actions freshness tracking mechanism from utilizing GitHub Issues to leveraging draft Pull Requests. This change aims to streamline the process of reporting and resolving stale action references by providing a dedicated, version-controlled artifact (a draft PR with a tracking file) that can be easily updated or closed based on audit findings, offering a more integrated and actionable tracking method within the development workflow. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Ignored Files
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
Dependency Review✅ No vulnerabilities or license issues found.Scanned FilesNone |
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- Consider adding an explicit deprecation path for the old
--manage-issue/--issue-titleflags (e.g., a warning log when they are used), since they are now silently repurposed for PR management and that may surprise existing consumers of the script. - The new
toGitHubRefPathandtoGitHubContentPathhelpers currently perform the same transformation; if there is no anticipated divergence in behavior, you could consolidate them into a single utility to reduce duplication.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider adding an explicit deprecation path for the old `--manage-issue` / `--issue-title` flags (e.g., a warning log when they are used), since they are now silently repurposed for PR management and that may surprise existing consumers of the script.
- The new `toGitHubRefPath` and `toGitHubContentPath` helpers currently perform the same transformation; if there is no anticipated divergence in behavior, you could consolidate them into a single utility to reduce duplication.
## Individual Comments
### Comment 1
<location> `scripts/audit-actions-freshness.js:56-57` </location>
<code_context>
- if (argument === '--issue-title') {
- options.issueTitle = argv[index + 1];
+ if (argument === '--issue-title' || argument === '--pr-title') {
+ options.pullRequestTitle = argv[index + 1];
index += 1;
continue;
</code_context>
<issue_to_address>
**suggestion:** Flag alias naming and error message can be confusing for users migrating from `--issue-title`.
The parser accepts both `--issue-title` and `--pr-title`, but validation reports `The --pr-title option requires a value.` even when the user passed `--issue-title`. That’s potentially confusing. Either explicitly deprecate `--issue-title` with a targeted message, or adjust the validation error to mention both flags so the message matches the accepted aliases.
Suggested implementation:
```javascript
if (argument === '--issue-title' || argument === '--pr-title') {
options.pullRequestTitle = argv[index + 1];
index += 1;
continue;
}
```
```javascript
throw new Error('The --pr-title/--issue-title option requires a value (both flags are accepted aliases).');
```
I assumed the validation error currently uses the exact string `The --pr-title option requires a value.` in `scripts/audit-actions-freshness.js`. If the wording or location is slightly different, update that specific error message string in the same way so that it mentions both `--pr-title` and `--issue-title` and clarifies that they are aliases. No other behavioral changes are required to satisfy your review comment.
</issue_to_address>
### Comment 2
<location> `scripts/audit-actions-freshness.js:481-490` </location>
<code_context>
+}
+async function findTrackingPullRequest({ owner, repository, token, trackingBranch }) {
+ const pullRequests = await githubRequest({
+ endpoint: `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repository)}/pulls?state=open&head=${encodeURIComponent(`${owner}:${trackingBranch}`)}&per_page=10`,
+ token,
+ });
+
+ if (!Array.isArray(pullRequests) || pullRequests.length === 0) {
+ return null;
+ }
+
+ return (
+ pullRequests.find(
+ (pullRequest) =>
</code_context>
<issue_to_address>
**issue (bug_risk):** `findTrackingPullRequest` falls back to the first open PR even if it’s not a tracker, which can update unrelated PRs.
If an open PR from the tracking branch doesn’t include `TRACKING_PULL_REQUEST_MARKER`, this will still return `pullRequests[0]`, causing `upsertTrackingPullRequest` to overwrite and later close that PR. That can affect manually created PRs on the same branch. Consider only operating on PRs that contain the marker, or treating a missing marker as “no tracking PR” and skipping create/update rather than falling back to the first PR.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Code Review
This pull request refactors the actions freshness tracker to use draft pull requests instead of issues for reporting. The changes are well-structured, replacing issue-management logic with new functions for handling git branches, files, and pull requests. My review includes a couple of suggestions to enhance the robustness and user-friendliness of the new implementation, bringing it in line with the helpful features of the previous issue-based system.
| return ( | ||
| pullRequests.find( | ||
| (pullRequest) => | ||
| typeof pullRequest.body === 'string' && | ||
| pullRequest.body.includes(TRACKING_PULL_REQUEST_MARKER) | ||
| ) || pullRequests[0] | ||
| ); |
There was a problem hiding this comment.
The fallback to pullRequests[0] is too lenient and could lead to updating an incorrect pull request if multiple PRs are open from the automation branch and none have the tracking marker. It's safer to only consider PRs that explicitly contain the TRACKING_PULL_REQUEST_MARKER. If no matching PR is found, this function will return undefined, and the upsertTrackingPullRequest function will correctly create a new one.
return pullRequests.find(
(pullRequest) =>
typeof pullRequest.body === 'string' &&
pullRequest.body.includes(TRACKING_PULL_REQUEST_MARKER)
);| async function closeTrackingPullRequest({ owner, repository, pullRequestNumber, token }) { | ||
| await githubRequest({ | ||
| endpoint: `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repository)}/issues/${issueNumber}`, | ||
| endpoint: `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repository)}/pulls/${pullRequestNumber}`, | ||
| token, | ||
| method: 'PATCH', | ||
| body: { state: 'closed' }, | ||
| body: { | ||
| state: 'closed', | ||
| }, | ||
| }); | ||
| } |
There was a problem hiding this comment.
The previous implementation for closing tracker issues added a comment to provide context for the closure. This is a helpful practice that should be retained for pull requests. You can add a comment to a pull request via the issues API, using the pull request number.
async function closeTrackingPullRequest({ owner, repository, pullRequestNumber, token }) {
await githubRequest({
endpoint: `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repository)}/issues/${pullRequestNumber}/comments`,
token,
method: 'POST',
body: {
body: 'Automated actions freshness audit is clean. Closing this tracker pull request.',
},
});
await githubRequest({
endpoint: `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repository)}/pulls/${pullRequestNumber}`,
token,
method: 'PATCH',
body: {
state: 'closed',
},
});
}
Code Review by Qodo
1. Tracker branch can drift
|
| async function ensureTrackingPullRequestBranch({ | ||
| owner, | ||
| repository, | ||
| token, | ||
| defaultBranch, | ||
| trackingBranch, | ||
| }) { | ||
| const defaultBranchRef = await githubRequest({ | ||
| endpoint: `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repository)}/git/ref/heads/${toGitHubRefPath(defaultBranch)}`, | ||
| token, | ||
| }); | ||
| const defaultBranchSha = defaultBranchRef && defaultBranchRef.object ? defaultBranchRef.object.sha : ''; | ||
| if (!defaultBranchSha) { | ||
| throw new Error(`Could not resolve latest commit on ${defaultBranch}.`); | ||
| } | ||
|
|
||
| try { | ||
| await githubRequest({ | ||
| endpoint: `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repository)}/git/ref/heads/${toGitHubRefPath(trackingBranch)}`, | ||
| token, | ||
| }); | ||
|
|
||
| if (!Array.isArray(issues) || issues.length === 0) { | ||
| return null; | ||
| } catch (error) { | ||
| if (error.status !== 404) { | ||
| throw error; | ||
| } | ||
|
|
||
| const trackingIssue = issues.find( | ||
| (issue) => | ||
| !issue.pull_request && | ||
| issue.title === issueTitle && | ||
| typeof issue.body === 'string' && | ||
| issue.body.includes(TRACKING_ISSUE_MARKER) | ||
| ); | ||
| await githubRequest({ | ||
| endpoint: `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repository)}/git/refs`, | ||
| token, | ||
| method: 'POST', | ||
| body: { | ||
| ref: `refs/heads/${trackingBranch}`, | ||
| sha: defaultBranchSha, | ||
| }, | ||
| }); | ||
| console.log(`[actions-freshness] Created branch ${trackingBranch}`); | ||
| } | ||
| } |
There was a problem hiding this comment.
1. Tracker branch can drift 🐞 Bug ⛯ Reliability
The tracking branch is only created when missing and is never fast-forwarded/reset to the current default-branch tip. Over time, the tracker PR will accumulate unrelated diffs/commits from the default branch, making it noisy and potentially unreviewable.
Agent Prompt
### Issue description
The tracker branch (`automation/actions-freshness-tracker`) is only created once and never updated afterwards. This causes the tracker PR to gradually include unrelated diffs from the default branch.
### Issue Context
`ensureTrackingPullRequestBranch` checks for the branch ref and only creates it on 404. If it exists, it does not move it to the latest default-branch commit.
### Fix Focus Areas
- scripts/audit-actions-freshness.js[398-435]
- scripts/audit-actions-freshness.js[551-577]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| async function findTrackingPullRequest({ owner, repository, token, trackingBranch }) { | ||
| const pullRequests = await githubRequest({ | ||
| endpoint: `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repository)}/pulls?state=open&head=${encodeURIComponent(`${owner}:${trackingBranch}`)}&per_page=10`, | ||
| token, | ||
| }); | ||
|
|
||
| if (!Array.isArray(pullRequests) || pullRequests.length === 0) { | ||
| return null; | ||
| } |
There was a problem hiding this comment.
2. Closed pr never reused 🐞 Bug ⛯ Reliability
The tracker PR lookup only searches open PRs; once the workflow closes the tracker PR on a clean run, a later stale run will not find it and will attempt to create a new PR from the same branch. This can lead to repeated tracker PRs (PR spam) or API errors depending on GitHub behavior.
Agent Prompt
### Issue description
The script closes the tracker PR when clean, but later runs only search open PRs. This causes new PR creation attempts instead of reopening/updating the existing tracker PR.
### Issue Context
`findTrackingPullRequest` uses `state=open` and `upsertTrackingPullRequest` creates a new PR whenever lookup returns null.
### Fix Focus Areas
- scripts/audit-actions-freshness.js[480-497]
- scripts/audit-actions-freshness.js[510-606]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@scripts/audit-actions-freshness.js`:
- Around line 414-434: The current try/catch that checks for the tracking branch
using githubRequest(...) and then POSTs to create it can race and get a 422 if
another run created the ref; update the error handling around the POST to treat
a 422 as non-fatal: after the initial try where you call githubRequest(...) with
endpoint `/git/ref/heads/${toGitHubRefPath(trackingBranch)}`, keep the existing
404 handling but when performing the POST to `/git/refs` catch errors from
githubRequest and if the error.status === 422 then re-check the branch exists by
calling the same GET (`/git/ref/heads/${toGitHubRefPath(trackingBranch)}`) and
only throw if that re-check also fails; reference the existing symbols
githubRequest, toGitHubRefPath, trackingBranch and defaultBranchSha when
implementing this retry/check logic.
🧹 Nitpick comments (3)
scripts/audit-actions-freshness.js (3)
375-389:toGitHubRefPathandtoGitHubContentPathare identical implementations.These two functions have the exact same body. Consider extracting a single shared helper (e.g.,
encodePathSegments) and aliasing if distinct names are desired for readability.♻️ Suggested deduplication
-function toGitHubRefPath(value) { - return value - .split('/') - .filter((segment) => segment.length > 0) - .map((segment) => encodeURIComponent(segment)) - .join('/'); -} - -function toGitHubContentPath(filePath) { - return filePath - .split('/') - .filter((segment) => segment.length > 0) - .map((segment) => encodeURIComponent(segment)) - .join('/'); -} +function encodePathSegments(value) { + return value + .split('/') + .filter((segment) => segment.length > 0) + .map((segment) => encodeURIComponent(segment)) + .join('/'); +} + +const toGitHubRefPath = encodePathSegments; +const toGitHubContentPath = encodePathSegments;
510-606: Well-structured PR lifecycle management.The flow correctly handles all states: no findings with no existing PR (no-op), no findings with existing PR (close), findings with existing PR (update), and findings without PR (create draft).
One minor note: when closing the PR on a clean audit, the tracking branch (
pullRequestBranch) is left behind. Consider deleting it to keep the repository tidy, though this is optional.
638-647: Permission error detection relies on a specific GitHub error message string.This is the pragmatic approach, but be aware that if GitHub changes the wording, the detection will silently stop matching and the error will propagate as unhandled. Consider also matching on a broader substring or adding a fallback log.
| try { | ||
| await githubRequest({ | ||
| endpoint: `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repository)}/git/ref/heads/${toGitHubRefPath(trackingBranch)}`, | ||
| token, | ||
| }); | ||
|
|
||
| if (!Array.isArray(issues) || issues.length === 0) { | ||
| return null; | ||
| } catch (error) { | ||
| if (error.status !== 404) { | ||
| throw error; | ||
| } | ||
|
|
||
| const trackingIssue = issues.find( | ||
| (issue) => | ||
| !issue.pull_request && | ||
| issue.title === issueTitle && | ||
| typeof issue.body === 'string' && | ||
| issue.body.includes(TRACKING_ISSUE_MARKER) | ||
| ); | ||
| await githubRequest({ | ||
| endpoint: `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repository)}/git/refs`, | ||
| token, | ||
| method: 'POST', | ||
| body: { | ||
| ref: `refs/heads/${trackingBranch}`, | ||
| sha: defaultBranchSha, | ||
| }, | ||
| }); | ||
| console.log(`[actions-freshness] Created branch ${trackingBranch}`); | ||
| } |
There was a problem hiding this comment.
Potential 422 error if concurrent runs race to create the branch.
If two workflow runs hit the 404 simultaneously, the second POST .../git/refs will fail with a 422 ("Reference already exists") that isn't caught here. Consider also treating 422 as a non-fatal condition (re-check the branch exists).
🛡️ Proposed fix
} catch (error) {
- if (error.status !== 404) {
+ if (error.status !== 404) {
throw error;
}
- await githubRequest({
- endpoint: `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repository)}/git/refs`,
- token,
- method: 'POST',
- body: {
- ref: `refs/heads/${trackingBranch}`,
- sha: defaultBranchSha,
- },
- });
- console.log(`[actions-freshness] Created branch ${trackingBranch}`);
+ try {
+ await githubRequest({
+ endpoint: `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repository)}/git/refs`,
+ token,
+ method: 'POST',
+ body: {
+ ref: `refs/heads/${trackingBranch}`,
+ sha: defaultBranchSha,
+ },
+ });
+ console.log(`[actions-freshness] Created branch ${trackingBranch}`);
+ } catch (createError) {
+ if (createError.status !== 422) {
+ throw createError;
+ }
+ console.log(`[actions-freshness] Branch ${trackingBranch} was created concurrently`);
+ }
}🤖 Prompt for AI Agents
In `@scripts/audit-actions-freshness.js` around lines 414 - 434, The current
try/catch that checks for the tracking branch using githubRequest(...) and then
POSTs to create it can race and get a 422 if another run created the ref; update
the error handling around the POST to treat a 422 as non-fatal: after the
initial try where you call githubRequest(...) with endpoint
`/git/ref/heads/${toGitHubRefPath(trackingBranch)}`, keep the existing 404
handling but when performing the POST to `/git/refs` catch errors from
githubRequest and if the error.status === 422 then re-check the branch exists by
calling the same GET (`/git/ref/heads/${toGitHubRefPath(trackingBranch)}`) and
only throw if that re-check also fails; reference the existing symbols
githubRequest, toGitHubRefPath, trackingBranch and defaultBranchSha when
implementing this retry/check logic.
|



Summary\n- replace actions-freshness issue management with tracker pull request management\n- create/update a draft tracker PR on findings, close it when clean\n- update workflow permissions to use pull-requests/content write and drop issues access\n\n## Validation\n- node --check scripts/audit-actions-freshness.js\n- npm run test -- --runInBand tests/unit/scripts/actions-freshness.test.js\n- node scripts/audit-actions-freshness.js --report /tmp/actions-freshness-report.md --json /tmp/actions-freshness-report.json
Summary by Sourcery
Switch the actions freshness automation from managing a tracking issue to managing a draft tracker pull request backed by a dedicated branch and file.
Enhancements:
CI:
Summary by CodeRabbit
New Features
Changes