chore: refactor release flow to create release on every push#2764
chore: refactor release flow to create release on every push#2764
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughReplaces release-it with a Node ESM bumper, migrates releaser utilities to ESM, updates releaser package metadata, removes a shell changelog extractor, and adds a cancel-if-stale concurrency input and runtime guard across multiple GitHub Actions release/deploy workflows. Changes
Sequence Diagram(s)sequenceDiagram
participant GH as "GitHub Actions"
participant Bumper as "recommended-bump.js"
participant Deps as "find-local-package-dependencies"
participant Conv as "conventional-recommended-bump"
participant GHCLI as "gh CLI / Actions runner"
participant Setup as "reusable-deploy-setup (concurrency guard)"
GH->>Bumper: run recommended-bump (tag-prefix, repo-url, path)
Bumper->>Deps: request local package dependencies (path)
Deps-->>Bumper: return dependency package paths
Bumper->>Conv: load commits & compute whatBump
Conv-->>Bumper: return releaseType + metadata
Bumper->>Bumper: compute nextVersion/nextTag and build changelog
Bumper-->>GH: output JSON (releaseType, versions, changelog)
GH->>GHCLI: gh release create with computed tag & changelog
GHCLI-->>GH: release created
GH->>Setup: invoke reusable-deploy-setup (image_tag, cancel-if-stale)
Setup->>Setup: concurrency guard compares image_tag to recent runs
Setup-->>GH: allow or abort deployment
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2764 +/- ##
==========================================
+ Coverage 51.96% 51.98% +0.01%
==========================================
Files 1041 1041
Lines 27397 27397
Branches 6332 6357 +25
==========================================
+ Hits 14238 14242 +4
+ Misses 12695 12682 -13
- Partials 464 473 +9
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (1)
.github/workflows/all-release.yml (1)
6-8: Broader triggers may cause more frequent workflow runs with empty matrices.The path filter now triggers on any file change in
apps/**/*orpackages/**/*, but the inline script (line 42) still filters to only apps with changedpackage.jsonfiles. This means the workflow will run more frequently but may produce empty matrices.The
if: fromJson(needs.setup.outputs.backends).include[0]guards at lines 59 and 74 should skip jobs gracefully when matrices are empty, so this is likely intentional to support the "release on every push" objective.Consider adding a comment explaining this design choice to help future maintainers understand the intentional trigger broadening.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/all-release.yml around lines 6 - 8, The workflow broadens path filters to "apps/**/*" and "packages/**/*" but the setup script (the inline script that filters to apps with changed package.json) can produce empty matrices; update .github/workflows/all-release.yml by adding a concise comment near the top trigger block and next to the if guards (the if: fromJson(needs.setup.outputs.backends).include[0] checks) explaining this is intentional: triggers are broadened to run on any repo change to enable "release on every push", the setup script narrows to actual changed package.json files, and the if guards are present to skip jobs when matrices are empty—this comment will help future maintainers understand why empty matrices and extra workflow runs are expected.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/reusable-create-github-release.yml:
- Around line 33-36: The sparse-checkout only includes ".github" so the workflow
cannot run the releaser script; update the workflow's "sparse-checkout" entries
to also include the releaser package and any package/app package.json files
required by packages/releaser (so that node
./packages/releaser/recommended-bump.js and
packages/releaser/find-local-package-dependencies.js plus the package.json files
under packages/ and apps/ are present). In short, add paths such as
"packages/releaser/**", "packages/**/package.json" and "apps/**/package.json"
(or simply "packages/**" and "apps/**") to the sparse-checkout block so the
releaser script and its dependency resolution can be executed.
- Around line 85-89: The current gh release create invocation interpolates the
changelog into the --notes argument which can break on quotes or other shell
metacharacters; change the step that runs gh release create to write
steps.bumps.outputs.changelog to a temporary file (or to an environment variable
and feed it via a heredoc) and pass that filepath to gh release create using
--notes-file instead of --notes, ensuring you still use the same tag from
steps.bumps.outputs.git_tag and repo from github.repository.
In `@packages/releaser/recommended-bump.js`:
- Around line 129-131: When result.releaseType is falsy the script currently
calls process.exit(1) with no diagnostics; before exiting, log a clear error
including the reason and relevant data (e.g., console.error("No releaseType
returned from recommended bump:", JSON.stringify(result)) or similar) so callers
can see why it failed, then call process.exit(1); update the block that checks
result.releaseType to emit that diagnostic using the result object (and any
contextual variables you have) before exiting.
- Around line 137-148: The switch on result.releaseType that assigns nextVersion
(variable nextVersion, switch on result.releaseType) lacks a default branch so
nextVersion can be left undefined; add a default case that either sets
nextVersion to the current version string (e.g., `${major}.${minor}.${patch}`)
or explicitly throws a clear error indicating an unsupported releaseType,
ensuring subsequent tag/changelog generation never receives undefined.
- Line 152: The changelog call is only passing the first commit by using
[result.commits[0]]; update the call to pass the full commits array
(result.commits) to generateChangelog so all commits since lastTag are included
(e.g., replace [result.commits[0]] with result.commits when calling
generateChangelog with { repoUrl, lastTag, nextTag, nextVersion }).
- Around line 113-127: The code calls a non-public Bumper method
getLastSemverTag(), which will fail at runtime; either remove the unused lastTag
assignment (delete the const lastTag = await bumper.getLastSemverTag(); line) or
if you need the last semver tag, replace that call by instantiating
ConventionalGitClient and calling its getLastSemverTag({ prefix:
values["tag-prefix"] }) (import ConventionalGitClient from
'@conventional-changelog/git-client', create new
ConventionalGitClient(process.cwd()), then await git.getLastSemverTag with the
prefix) while keeping existing bumper usage (loadPreset, tag, commits, bump).
---
Nitpick comments:
In @.github/workflows/all-release.yml:
- Around line 6-8: The workflow broadens path filters to "apps/**/*" and
"packages/**/*" but the setup script (the inline script that filters to apps
with changed package.json) can produce empty matrices; update
.github/workflows/all-release.yml by adding a concise comment near the top
trigger block and next to the if guards (the if:
fromJson(needs.setup.outputs.backends).include[0] checks) explaining this is
intentional: triggers are broadened to run on any repo change to enable "release
on every push", the setup script narrows to actual changed package.json files,
and the if guards are present to skip jobs when matrices are empty—this comment
will help future maintainers understand why empty matrices and extra workflow
runs are expected.
ea84c46 to
b06b91e
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
.github/workflows/reusable-deploy-setup.yml (1)
56-62:⚠️ Potential issue | 🟠 MajorDon’t strip
-betafrom the deployment image tag.Line 60 removes
-betabefore output. If you dispatch withconsole-api/1.2.3-beta, this will deploy1.2.3instead of the beta image.✅ Keep beta tags for deployment, normalize only for comparison
- # Remove 'v' prefix if present - version="${version#v}" - - # Remove beta suffix if present - version="${version%-beta}" - - echo "image_tag=$version" >> "$GITHUB_OUTPUT" + # Remove 'v' prefix if present for image tags + version="${version#v}" + echo "image_tag=$version" >> "$GITHUB_OUTPUT"- const version = '${{ steps.extract.outputs.image_tag }}'; + const version = '${{ steps.extract.outputs.image_tag }}'.replace(/-beta$/, '');🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/reusable-deploy-setup.yml around lines 56 - 62, The workflow currently strips the "-beta" suffix via the statement version="${version%-beta}" which causes beta dispatches to deploy the non-beta image; instead keep the original version string (the variable named version) when writing image_tag to GITHUB_OUTPUT so beta tags are preserved, and if you need a normalized value for comparisons create a separate temp variable (e.g., normalized_version) that strips the "v" prefix and the "-beta" suffix for comparison logic, leaving the image_tag echo as echo "image_tag=$version" >> "$GITHUB_OUTPUT"..github/workflows/all-release.yml (1)
6-44:⚠️ Potential issue | 🟠 MajorRelease matrix ignores most of the newly-triggered changes.
Line 6-8 now triggers on any
apps/**orpackages/**change, but Line 42 still only selects apps whenapps/*/package.jsonchanges. This makes runs no-op for normal app code changes and for package-only changes, which undermines “release on every push.”✅ Minimal fix to capture app changes
- .filter(f => f.match(/^apps\/[^/]+\/package\.json$/)) + .filter(f => f.match(/^apps\/[^/]+\//))Also decide how
packages/**changes should map to releases (e.g., release all apps or compute dependents). If that dependency-mapping is broader than this PR, consider tracking it separately to keep scope tight. Based on learnings: In the Akash Network Console project, when cross-cutting concerns or broader refactoring issues are identified during PR review, the preferred approach is to create a separate GitHub issue to track the work rather than expanding the scope of the current PR.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/all-release.yml around lines 6 - 44, The matrix currently only detects app changes when apps/*/package.json is modified, so change the file filtering logic in the node script: replace the filter .filter(f => f.match(/^apps\/[^/]+\/package\.json$/)) with a pattern that captures any file under an app directory (e.g., .filter(f => f.match(/^apps\/([^/]+)\//)) and extract app name via .map(f => f.split("/")[1]) to capture normal app code changes; additionally detect any changes matching ^packages\/ to trigger releases for all apps (or set a flag to compute dependents later) by reading the apps directory when packages are changed—update references to APP_ALIASES, workflowFile, and the apps variable accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/reusable-deploy-setup.yml:
- Around line 64-113: Concurrency guard is broken because listWorkflowRuns
doesn't expose run.inputs, so run.inputs?.image_tag is always undefined; surface
the image_tag in a retrievable field (e.g., run.name or an artifact/output) and
parse that instead. Update callers of the reusable workflow to set a predictable
run name (or create a tiny artifact/output) that includes app and image_tag,
then change the script in the concurrency guard (the code using
github.rest.actions.listWorkflowRuns and checking run.inputs?.image_tag) to
extract image_tag from run.name (or fetch the artifact/output for that run) and
use that value for the existing parsing and isNewer comparison for version
blocking.
In @.github/workflows/reusable-release-app.yml:
- Around line 55-58: The gh workflow run invocation passes a malformed -f
argument (`-f ${{ needs.release.outputs.git_tag }}`); change it to a key=value
pair (e.g., `-f image_tag=${{ needs.release.outputs.git_tag }}` or `-f
git_tag=${{ needs.release.outputs.git_tag }}`) so the command accepts the input,
keeping the other flags (`--repo ${{ github.repository }}` and `-f
cancel-if-stale=true`) unchanged; update the gh workflow run line that
references inputs.deploy_workflow and needs.release.outputs.git_tag accordingly.
---
Outside diff comments:
In @.github/workflows/all-release.yml:
- Around line 6-44: The matrix currently only detects app changes when
apps/*/package.json is modified, so change the file filtering logic in the node
script: replace the filter .filter(f => f.match(/^apps\/[^/]+\/package\.json$/))
with a pattern that captures any file under an app directory (e.g., .filter(f =>
f.match(/^apps\/([^/]+)\//)) and extract app name via .map(f => f.split("/")[1])
to capture normal app code changes; additionally detect any changes matching
^packages\/ to trigger releases for all apps (or set a flag to compute
dependents later) by reading the apps directory when packages are changed—update
references to APP_ALIASES, workflowFile, and the apps variable accordingly.
In @.github/workflows/reusable-deploy-setup.yml:
- Around line 56-62: The workflow currently strips the "-beta" suffix via the
statement version="${version%-beta}" which causes beta dispatches to deploy the
non-beta image; instead keep the original version string (the variable named
version) when writing image_tag to GITHUB_OUTPUT so beta tags are preserved, and
if you need a normalized value for comparisons create a separate temp variable
(e.g., normalized_version) that strips the "v" prefix and the "-beta" suffix for
comparison logic, leaving the image_tag echo as echo "image_tag=$version" >>
"$GITHUB_OUTPUT".
---
Duplicate comments:
In @.github/workflows/reusable-create-github-release.yml:
- Around line 83-87: The release creation step interpolates
steps.bumps.outputs.changelog directly into a shell command which can break on
quotes or other metacharacters; change the step to write "${{
steps.bumps.outputs.changelog }}" to a temporary file (or export it as an env
var) and invoke gh release create using the --notes-file option (or pass the env
var safely quoted) instead of --notes, referencing the same outputs
(steps.bumps.outputs.changelog and steps.bumps.outputs.git_tag) so the command
becomes: write changelog -> gh release create "${{ steps.bumps.outputs.git_tag
}}" --repo "${{ github.repository }}" --title "${{ steps.bumps.outputs.git_tag
}}" --notes-file <temp-file-or-path> (or use a safely quoted env var).
In `@packages/releaser/recommended-bump.js`:
- Around line 129-131: The script currently calls process.exit(1) when
result.releaseType is falsy without any diagnostic output; update the check
around result.releaseType to emit a clear error (e.g., console.error or
processLogger.error) that includes context and any relevant data (such as the
full result object or inputs used to compute it) before exiting, so replace the
silent exit in the conditional that references result.releaseType with a logged
message plus process.exit(1).
- Around line 126-127: Replace the call to the non-public method
bumper.getLastSemverTag() with a call to ConventionalGitClient.getLastSemverTag:
import and instantiate ConventionalGitClient (e.g., const git = new
ConventionalGitClient(process.cwd())), then call await git.getLastSemverTag({
prefix: values["tag-prefix"] }) to obtain lastTag; remove or stop using
bumper.getLastSemverTag() and continue using bumper.bump(whatBump) as before.
- Line 152: The changelog call is only passing the first commit
(generateChangelog([result.commits[0]], ...)) so the release notes miss all
other commits; change the call to pass the full commits array (e.g.,
generateChangelog(result.commits, { repoUrl, lastTag, nextTag, nextVersion }))
or a properly filtered/ordered array derived from result.commits so all commits
since lastTag are included when generating the changelog.
- Around line 137-148: The switch on result.releaseType can leave nextVersion
undefined for unexpected values; update the switch in the block that computes
nextVersion to include a default branch that handles unknown release types
(e.g., throw a clear Error or set nextVersion to a safe fallback and log),
referencing the same variables (result.releaseType, nextVersion, major, minor,
patch) so the function always produces a valid nextVersion or fails loudly.
ecb93d9 to
956284e
Compare
There was a problem hiding this comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In @.github/workflows/reusable-create-github-release.yml:
- Around line 83-87: The workflow currently passes the changelog via the gh
CLI's --notes which allows shell metacharacter injection; change the run step to
write "${{ steps.bumps.outputs.changelog }}" into a temporary file (e.g., with
mktemp or here-doc) and call gh release create with --notes-file pointing to
that temp file instead of --notes, then remove the temp file after creating the
release; update the invocation that uses --notes and the reference to "${{
steps.bumps.outputs.changelog }}" accordingly to use the temp file path.
In @.github/workflows/reusable-release-app.yml:
- Around line 57-58: The -f argument is malformed: change the flag usage from
"-f ${{ needs.release.outputs.git_tag }}" to include a key=value pair such as
"-f git_tag=${{ needs.release.outputs.git_tag }}" so the gh workflow run
receives an input name; keep the existing "-f cancel-if-stale=true" as-is.
Ensure the key ("git_tag") matches the workflow's expected input name.
558fbb0 to
17162f1
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/all-release.yml (1)
6-43:⚠️ Potential issue | 🟠 MajorAlign the release matrix with the expanded trigger paths.
With paths now covering any app/package changes, the setup step still derives apps only from
apps/*/package.json. That means most app code changes (or package updates) trigger the workflow but produce an empty matrix and no releases. Consider deriving the app list from any file underapps/<app>/(and define how package changes should map to releases).🔧 Suggested adjustment to app detection
- .filter(f => f.match(/^apps\/[^/]+\/package\.json$/)) - .map(f => f.split("/")[1]) + .filter(f => f.match(/^apps\/[^/]+\//)) + .map(f => f.split("/")[1])🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/all-release.yml around lines 6 - 43, The app detection currently only picks up changed package.json files via the filter /\.match(/^apps\/[^/]+\/package\.json$/)/, so extend it to detect any change under an app directory and still extract the app name; replace that filter with one matching any path under apps (e.g. .filter(f => f.match(/^apps\/[^/]+\//))) and keep the .map(f => f.split("/")[1]) to derive the app name; update any comments/variables that reference APP_ALIASES or workflowFile to ensure package-level changes (and other file changes under apps/<app>/) are mapped to the correct release workflow using workflowFile(app).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/console-api-release.yml:
- Line 26: The workflow currently compares the boolean input via a string
equality check for the input named cancel-if-stale; update the expression to use
the boolean input directly (e.g., use the cancel-if-stale input value itself or
compare explicitly to true) so the cancel-if-stale condition uses a direct
boolean reference instead of string comparison.
In @.github/workflows/reusable-deploy-setup.yml:
- Around line 64-113: The stale-run guard currently ignores runs where
inputs.image_tag is an unprefixed tag (e.g., "v1.2.3"), because the split into
otherPrefix/otherRawVersion expects "app/version"; in the loop that reads
otherImageTag (the block using otherImageTag.split('/', 2) and computing
otherPrefix/otherRawVersion and otherVersion), treat tags without a slash as
belonging to the current app: if otherImageTag.includes('/') use the existing
split, otherwise set otherPrefix = app and otherRawVersion = otherImageTag, then
continue normal normalization (otherRawVersion.replace(/^v/,
'').replace(/-beta$/, '')) and comparison via isNewer.
In `@packages/releaser/recommended-bump.js`:
- Around line 126-136: When result.releaseType is falsy (the no-release path)
replace the current console.error+process.exit(0) with emitting a minimal JSON
object to stdout so downstream jq parsing succeeds; update the branch that
checks result.releaseType in recommended-bump.js (around the
bumper.getLastSemverTag()/bumper.bump() logic) to console.log a stable JSON
payload (e.g., indicating releaseNeeded: false, releaseType: null and optionally
currentVersion from the computed currentVersion variable) and then exit(0) —
ensure you reference result.releaseType, currentVersion, and bumper.bump when
locating the block to modify.
---
Outside diff comments:
In @.github/workflows/all-release.yml:
- Around line 6-43: The app detection currently only picks up changed
package.json files via the filter /\.match(/^apps\/[^/]+\/package\.json$/)/, so
extend it to detect any change under an app directory and still extract the app
name; replace that filter with one matching any path under apps (e.g. .filter(f
=> f.match(/^apps\/[^/]+\//))) and keep the .map(f => f.split("/")[1]) to derive
the app name; update any comments/variables that reference APP_ALIASES or
workflowFile to ensure package-level changes (and other file changes under
apps/<app>/) are mapped to the correct release workflow using workflowFile(app).
---
Duplicate comments:
In @.github/workflows/provider-proxy-release.yml:
- Around line 10-26: The workflow compares the input string to 'true' which is
brittle; replace the string equality check in the jobs.setup 'with:
cancel-if-stale' assignment with a proper boolean parse using fromJson.
Specifically, change the value passed to the reusable workflow from ${{
inputs.cancel-if-stale == 'true' }} to ${{ fromJson(inputs.cancel-if-stale) }}
so the 'cancel-if-stale' input is reliably converted to a boolean.
In `@packages/releaser/recommended-bump.js`:
- Around line 151-163: The changelog is being generated from only the first
commit because generateChangelog is called with [result.commits[0]]; update the
call to pass the full commit array (result.commits) so that
generateChangelog(repoUrl, lastTag, nextTag, nextVersion) receives all commits
and the generatedChangelog/variable changelog includes every commit rather than
just the first one (refer to symbols: generateChangelog, result.commits,
changelog, nextTag, repoUrl).
9bd7b3e to
82206da
Compare
There was a problem hiding this comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In @.github/workflows/reusable-deploy-setup.yml:
- Around line 104-107: Split otherImageTag into parts and normalize prefix vs
raw version so otherRawVersion is never undefined: use something like parts =
otherImageTag.split('/', 2); set otherPrefix = parts.length === 2 ? parts[0] :
undefined and otherRawVersion = parts.length === 2 ? parts[1] : parts[0]; then
use otherVersion = otherRawVersion.replace(/^v/, '').replace(/-beta$/, ''); this
ensures otherRawVersion (and the replace calls) are safe while preserving the
existing comparison on otherPrefix (otherPrefix !== app).
In `@packages/releaser/recommended-bump.js`:
- Line 153: The changelog call is only passing the first commit
([result.commits[0]]) so generateChangelog only receives a single commit; change
the call to pass the entire commits array (e.g., result.commits) to
generateChangelog and, if necessary, guard for an empty array before calling.
Update the expression assigning changelog (the generateChangelog invocation) to
use result.commits instead of [result.commits[0]] so all commits since lastTag
are included.
- Around line 126-132: When the call to bumper.bump(whatBump) returns no
result.releaseType, ensure you emit a minimal JSON payload to stdout (not just
stderr) so downstream steps can parse it; update the branch that currently does
console.error(JSON.stringify({ error: "No releasable commits found" })) to also
write a JSON object to stdout (for example via console.log) indicating the
no-release condition and then exit with code 0, referencing the same
bumper.bump() result handling around lastTag and result.releaseType.
64d3583 to
e4a8cfd
Compare
e4a8cfd to
c3d3b0a
Compare
bbb2f67 to
0f777a3
Compare
0f777a3 to
9d8352d
Compare
There was a problem hiding this comment.
Pull request overview
This PR refactors the release workflow to create releases automatically on every push to main, eliminating the pre-release PR workflow. The changes migrate the releaser tooling from CommonJS to ESM, replace release-it with a custom recommended-bump.js script, and enhance deployment workflows with concurrency controls to prevent stale deployments.
Changes:
- Replaced the pre-release PR workflow with automatic releases triggered on every push to
mainaffectingapps/**/*,packages/**/*, orpackage-lock.json - Migrated
packages/releaserto ESM and replacedrelease-itwith a custom versioning/changelog script based onconventional-recommended-bump - Added
cancel-if-staleconcurrency guards to deployment workflows to skip deployments when newer versions are queued - Removed
.release-it.jsconfig files andreleasenpm scripts from all apps - Updated documentation to reflect the new continuous release workflow
Reviewed changes
Copilot reviewed 40 out of 41 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
packages/releaser/recommended-bump.js |
New script for determining semantic version bumps and generating changelogs based on conventional commits |
packages/releaser/find-local-package-dependencies.js |
Migrated from CommonJS to ESM to support the new module system |
packages/releaser/package.json |
Updated to use ESM ("type": "module") and replaced dependencies |
.github/workflows/all-release.yml |
Modified to trigger on broader path patterns and detect changed apps for release |
.github/workflows/reusable-create-github-release.yml |
Refactored to use the new recommended-bump.js script instead of parsing PR changes |
.github/workflows/reusable-deploy-setup.yml |
Added concurrency guard logic to cancel stale deployments |
.github/workflows/*-release.yml |
Added cancel-if-stale input and workflow-level concurrency controls |
.github/workflows/create-pre-release-pr.yml |
Removed (no longer needed with automatic releases) |
script/extract-changelog.sh |
Removed (changelog extraction now handled by JavaScript) |
apps/*/package.json |
Removed release scripts from all app package.json files |
apps/*/.release-it.js |
Removed config files for the old release-it tooling |
package.json |
Removed release-it and related dependencies, updated esbuild version |
doc/release-workflow.md |
Comprehensive documentation update explaining the new workflow |
Comments suppressed due to low confidence (1)
.github/actions/local-dependencies/action.yml:25
- The inline Node.js script uses dynamic import which requires the file to be treated as an ES module. However, this might fail if Node.js doesn't have access to the file system in the expected way when using
--input-type=modulewith inline code.
Consider changing this to execute the script as a file instead:
node -e "
import('./packages/releaser/find-local-package-dependencies.js').then(({ findLocalPackageDependencies }) => {
const localDependencies = findLocalPackageDependencies('./${{ inputs.path }}')
.map(path => \`\${path}/**\`);
console.log(JSON.stringify(localDependencies));
});
"
Or create a dedicated CLI script file in the releaser package to avoid inline module imports.
node --input-type=module -e '
import { findLocalPackageDependencies } from "./packages/releaser/find-local-package-dependencies.js";
const localDependencies = findLocalPackageDependencies("./${{ inputs.path }}")
.map(path => `${path}/**`);
console.log(JSON.stringify(localDependencies));
' | xargs -I "{}" -0 echo "deps_json={}" >> $GITHUB_OUTPUT
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| reason: | ||
| breakings === 1 ? `There is ${breakings} BREAKING CHANGE and ${features} features` : `There are ${breakings} BREAKING CHANGES and ${features} features` |
There was a problem hiding this comment.
The reason message in the whatBump function has inconsistent grammar. When breakings === 0, it will output "There are 0 BREAKING CHANGES and X features" which sounds awkward.
Consider improving the logic:
reason: breakings === 0
? `There are ${features} feature${features === 1 ? '' : 's'}`
: breakings === 1
? `There is ${breakings} BREAKING CHANGE and ${features} feature${features === 1 ? '' : 's'}`
: `There are ${breakings} BREAKING CHANGES and ${features} feature${features === 1 ? '' : 's'}`This provides better messages for all cases and handles singular/plural forms correctly.
| @@ -4,13 +4,9 @@ | |||
| "description": "Package containing console specific docker files and scripts", | |||
There was a problem hiding this comment.
The package description is outdated. It says "Package containing console specific docker files and scripts" but this package is now the releaser package that handles versioning and changelog generation, not Docker-related functionality.
Update the description to something like: "Package for automated versioning and changelog generation based on Conventional Commits"
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.ref }} | ||
| - "apps/**/*" | ||
| - "packages/**/*" |
There was a problem hiding this comment.
The path filter now triggers on any change under packages/**/*, which means changes to non-releasable packages (like packages/dev-config, packages/docker) will trigger the release workflow unnecessarily.
Consider being more specific about which package changes should trigger releases. For example:
- Only trigger on changes to packages that are actual dependencies of apps
- Exclude infrastructure/tooling packages that don't affect runtime behavior
- Or explicitly filter by checking if the changed files affect app dependencies
Currently, a change to packages/dev-config/.eslintrc.base.js will trigger all app release checks, even though it doesn't affect runtime behavior.
| - "packages/**/*" | |
| - "packages/**/*" | |
| - "!packages/dev-config/**" | |
| - "!packages/docker/**" |
There was a problem hiding this comment.
they are actually important but I need to remap them into apps. Find all dependent apps
| if (otherApp !== app || !otherRawVersion) continue; | ||
|
|
||
| const otherVersion = otherRawVersion?.replace(/^v/, '').replace(/-beta$/, ''); | ||
| if (otherVersion && otherVersion === version) continue; |
There was a problem hiding this comment.
The isNewer function compares version numbers but returns false when versions are equal, yet line 110 explicitly skips when otherVersion === version. This makes line 110 redundant since isNewer(otherVersion, version) would already return false for equal versions.
Consider simplifying by removing the redundant check on line 110, or keeping it for clarity but adding a comment explaining it's for early exit optimization.
| if (otherVersion && otherVersion === version) continue; |
| next_tag=$(echo "$commits_analysis" | jq -r '.nextTag') | ||
| changelog=$(echo "$commits_analysis" | jq -r '.changelog') | ||
| echo "git_tag=$next_tag" >> "$GITHUB_OUTPUT" | ||
| { | ||
| echo "changelog<<CHANGELOG_EOF" | ||
| echo "$changelog" | ||
| echo "CHANGELOG_EOF" | ||
| } >> "$GITHUB_OUTPUT" |
There was a problem hiding this comment.
The recommended-bump.js script outputs JSON to stdout and may also output to stderr in case of errors (line 130: console.error). When the script encounters no releasable commits, it outputs an error JSON object and exits with code 0.
The workflow should check if the next_tag is null or empty after parsing, otherwise it will attempt to create a release with an empty/null tag when there are no releasable commits. Consider adding error handling:
if [ "$next_tag" = "null" ] || [ -z "$next_tag" ]; then
echo "No releasable commits found for $APP_NAME"
exit 0
fiThis check should be added after line 70 to exit early when there's nothing to release.
| repo: context.repo.repo, | ||
| workflow_id: currentRun.workflow_id, | ||
| status, | ||
| per_page: 10 |
There was a problem hiding this comment.
The concurrency guard script only checks the last 10 workflow runs per status (per_page: 10). In a high-velocity repository with many deployments, this might miss a newer version that's outside this window.
Consider either:
- Increasing
per_pageto a higher value (e.g., 50 or 100) to check more runs - Adding pagination to check all recent runs
- Filtering by
created_atdate to check all runs from the last N hours/days
The current implementation could allow stale deployments to proceed if there are many intervening workflow runs.
| per_page: 10 | |
| per_page: 100 |
There was a problem hiding this comment.
unlikely to have more than 10 concurrent runs per app
|
|
||
| const nextTag = `${prefix}${nextVersion}`; | ||
| const repoUrl = values["repo-url"] || ""; | ||
| const changelog = generateChangelog([result.commits[0]], { repoUrl, lastTag, nextTag, nextVersion }); |
There was a problem hiding this comment.
The generateChangelog function is being called with only the first commit (result.commits[0]), but it should be called with all commits (result.commits). This will cause the changelog to only include one commit instead of all releasable commits since the last tag.
Change this to:
const changelog = generateChangelog(result.commits, { repoUrl, lastTag, nextTag, nextVersion });There was a problem hiding this comment.
this is intentional, because release creation is done in parallel and previous tags may not be pushed yet, so commit analyzer will receive more than 1 commit but changelog should generate only for a single commit because other instances of release workflow will create tags and releases for other commits
| RELEASE_CHANGELOG: ${{ steps.bumps.outputs.changelog }} | ||
| RELEASE_VERSION: ${{ steps.bumps.outputs.git_tag }} | ||
| run: | | ||
| gh release create "$RELEASE_VERSION" \ |
There was a problem hiding this comment.
issue(blocking): handle race condition when release with such tag exists. Need to retry and recompute the version or maybe just add a suffix '${version}-${timestamp}'
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.ref }}-${{ inputs.app }} | ||
| group: ${{ github.workflow }}-${{ github.sha }}-${{ inputs.app }} | ||
| cancel-in-progress: true |
There was a problem hiding this comment.
suggestion(blocking): remove concurrency group because it doesn't make sense to have group per sha, because sha are unique
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/reusable-create-github-release.yml:
- Around line 40-51: The cache only stores packages/releaser/node_modules so
hoisted workspace deps in the root node_modules are missed on cache-hit; update
the actions/cache step (id: deps-cache) to include both node_modules and
packages/releaser/node_modules (e.g. path: | node_modules
packages/releaser/node_modules) or otherwise cache the workspace root
node_modules so hoisted dependencies like conventional-recommended-bump are
restored, and keep the existing key (deps-${{ runner.os }}-${{
hashFiles('package-lock.json') }}) or broaden hashFiles to include workspace
lock files if needed; leave the Install Dependencies step (if:
steps.deps-cache.outputs.cache-hit != 'true' / run: npm run safe-install -- -w
packages/releaser) unchanged.
---
Duplicate comments:
In @.github/workflows/console-api-release.yml:
- Line 26: The expression currently compares the workflow_dispatch boolean input
"cancel-if-stale" to the string 'true', which can mis-evaluate; update the
conditional where "cancel-if-stale" is used (the cancel-if-stale input
expression) to use the boolean directly (e.g., use "${{ inputs.cancel-if-stale
}}" or compare to true) so the workflow uses the actual boolean value rather
than a string comparison.
In `@packages/releaser/recommended-bump.js`:
- Line 153: The changelog call is only passing the first commit
(generateChangelog([result.commits[0]], ...)) so it omits all other commits;
change the argument to pass the full commits array (result.commits) to
generateChangelog (or a filtered/ sliced subset if intentional) so the generated
changelog includes all commits since the last release.
- Around line 129-132: The no-release branch in the recommended-bump.js check
for result.releaseType currently writes the JSON error to stderr via
console.error, which breaks downstream jq processing; update the block that
references result.releaseType so it emits a minimal JSON payload to stdout
(e.g., use console.log or process.stdout.write) instead of console.error while
keeping the same exit behavior (process.exit(0)) so pipelines that read stdout
can parse the output consistently.
| - name: Restore Dependencies Cache | ||
| uses: actions/cache@v4 | ||
| id: deps-cache | ||
| with: | ||
| gh-user-to-slack-user: ${{ vars.GH_USER_TO_SLACK_USER }} | ||
| path: | | ||
| packages/releaser/node_modules | ||
| key: deps-${{ runner.os }}-${{ hashFiles('package-lock.json') }} | ||
|
|
||
| - name: Install Dependencies | ||
| if: steps.deps-cache.outputs.cache-hit != 'true' | ||
| run: | | ||
| npm run safe-install -- -w packages/releaser |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect workspace configuration and install strategy to confirm where npm places deps.
echo "=== Root package.json ===" && cat -n package.json && \
echo -e "\n=== .npmrc files ===" && fd -H '^\.npmrc$' -x cat -n {} || echo "No .npmrc found" && \
echo -e "\n=== packages/releaser/package.json ===" && cat -n packages/releaser/package.json && \
echo -e "\n=== safe-install script ===" && rg -A 5 '"safe-install"' package.jsonRepository: akash-network/console
Length of output: 4836
🏁 Script executed:
#!/bin/bash
# Inspect the safe-install script behavior
cat -n script/safe-deps-install.shRepository: akash-network/console
Length of output: 2840
Cache path misses hoisted workspace dependencies on cache-hit.
npm v11.6.2 with default workspace hoisting places transitive dependencies in the root node_modules directory, not in packages/releaser/node_modules. When the cache hits and install is skipped, the root node_modules (containing hoisted dependencies for conventional-recommended-bump) is not restored, breaking the releaser workflow.
🛠️ Proposed change
with:
path: |
+ node_modules
packages/releaser/node_modules📝 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.
| - name: Restore Dependencies Cache | |
| uses: actions/cache@v4 | |
| id: deps-cache | |
| with: | |
| gh-user-to-slack-user: ${{ vars.GH_USER_TO_SLACK_USER }} | |
| path: | | |
| packages/releaser/node_modules | |
| key: deps-${{ runner.os }}-${{ hashFiles('package-lock.json') }} | |
| - name: Install Dependencies | |
| if: steps.deps-cache.outputs.cache-hit != 'true' | |
| run: | | |
| npm run safe-install -- -w packages/releaser | |
| - name: Restore Dependencies Cache | |
| uses: actions/cache@v4 | |
| id: deps-cache | |
| with: | |
| path: | | |
| node_modules | |
| packages/releaser/node_modules | |
| key: deps-${{ runner.os }}-${{ hashFiles('package-lock.json') }} | |
| - name: Install Dependencies | |
| if: steps.deps-cache.outputs.cache-hit != 'true' | |
| run: | | |
| npm run safe-install -- -w packages/releaser |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/reusable-create-github-release.yml around lines 40 - 51,
The cache only stores packages/releaser/node_modules so hoisted workspace deps
in the root node_modules are missed on cache-hit; update the actions/cache step
(id: deps-cache) to include both node_modules and packages/releaser/node_modules
(e.g. path: | node_modules packages/releaser/node_modules) or otherwise cache
the workspace root node_modules so hoisted dependencies like
conventional-recommended-bump are restored, and keep the existing key (deps-${{
runner.os }}-${{ hashFiles('package-lock.json') }}) or broaden hashFiles to
include workspace lock files if needed; leave the Install Dependencies step (if:
steps.deps-cache.outputs.cache-hit != 'true' / run: npm run safe-install -- -w
packages/releaser) unchanged.
Why
We have release PR right now which collects changes and then we have 1 big release and deployment. This causes issues because:
What
Summary by CodeRabbit
Chores
Documentation
Revert