Skip to content

fix: Better release process#76

Draft
thierryskoda wants to merge 1 commit intomainfrom
ts/better-release
Draft

fix: Better release process#76
thierryskoda wants to merge 1 commit intomainfrom
ts/better-release

Conversation

@thierryskoda
Copy link
Copy Markdown
Contributor

@thierryskoda thierryskoda commented May 23, 2025

Implement tag-based release process with automated version management using versions.json for iOS and Android builds

Introduces a new release process that transitions from branch-based to tag-based deployments with automated version management. Key changes include:

📍Where to Start

Start with the new versions.json file which defines the structure for version management, then review scripts/update-versions.js which handles the version updating logic.


Macroscope summarized c823def.

Summary by CodeRabbit

  • New Features

    • Introduced centralized version management for iOS and Android builds using a new versioning file.
    • Automated incrementing of build numbers for both platforms across different environments.
    • Integrated version information directly into app configuration for improved consistency.
  • Chores

    • Updated deployment workflows to streamline build, tagging, and release processes.
    • Enhanced automation for preview and production deployments, including automatic GitHub Release creation and improved concurrency controls.
  • Documentation

    • Clarified workflow descriptions and improved step explanations in deployment processes.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented May 23, 2025

Walkthrough

The changes introduce centralized version management for iOS and Android builds using a new versions.json file and an update script. GitHub Actions workflows for preview, production, and promotion are refactored to automate version incrementing, tagging, and release creation, with workflows now referencing the new versioning system and updated app configuration logic.

Changes

File(s) Change Summary
.github/workflows/preview-deployment.yml Refactored workflow: clarified input descriptions, added versions.json to triggers, made concurrency dynamic, removed unnecessary permissions, renamed job, outputs new build number, uses stricter dependency install, automates version updates/commits.
.github/workflows/production-deployment.yml Changed trigger from branch push to tag pattern, updated concurrency, improved version/build parsing, simplified build step, automated GitHub Release creation, and adjusted permissions.
.github/workflows/promote-to-production.yml Renamed and refocused workflow, removed concurrency, added environment setup, automated version/build update and tagging, commits only if changes exist, merges main into production after tagging.
app.config.ts Imports version data from versions.json, extends config types for build numbers, updates environment configs, and integrates versioning into Expo config for iOS/Android.
eas.json Changed appVersionSource from "remote" to "local".
scripts/update-versions.js New script to increment build numbers in versions.json for specified platform and environment, validates inputs, updates file, and outputs new build number for CI.
versions.json New file storing structured versioning info for iOS (buildNumber) and Android (buildCode) across production, preview, and development channels.

Sequence Diagram(s)

sequenceDiagram
    participant Developer
    participant GitHub Actions
    participant update-versions.js
    participant versions.json
    participant app.config.ts
    participant GitHub Release

    Developer->>GitHub Actions: Push/Tag/PR triggers workflow
    GitHub Actions->>update-versions.js: Run script with platform/env args
    update-versions.js->>versions.json: Read and increment build number/code
    update-versions.js-->>GitHub Actions: Output new build number/code
    GitHub Actions->>app.config.ts: Update with new build number/code
    GitHub Actions->>versions.json: Commit and push changes if updated
    GitHub Actions->>GitHub Release: (Production) Create release with version/build
Loading

Poem

🐇
In burrows deep, the versions grow,
With scripts and JSON all in tow.
The workflows hop, the numbers climb,
Each build now tracked in perfect time.
From preview fields to production tags,
This bunny’s code now never lags!
🥕

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
Learn more here.

✨ Finishing Touches
  • 📝 Generate Docstrings

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (1)
.github/workflows/preview-deployment.yml (1)

106-111: Duplicate deprecation note: set-output usage
As with the production workflow, if update-versions.js or related scripts still emit ::set-output, they should adopt echo "new_build_number=$VALUE" >> $GITHUB_OUTPUT.

🧹 Nitpick comments (2)
scripts/update-versions.js (1)

49-49: Apply optional chaining for cleaner code.

As suggested by the static analysis tool, this can be simplified using optional chaining.

Apply this improvement:

-  const platformConfig = versionsData[platform] && versionsData[platform][env]
+  const platformConfig = versionsData[platform]?.[env]
🧰 Tools
🪛 Biome (1.9.4)

[error] 49-49: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

.github/workflows/production-deployment.yml (1)

36-42: Consider fallback for build number
Currently you only fallback APP_VERSION from package.json. It may be worthwhile to also read the previous build number from versions.json when tag parsing fails, to avoid deployment interruptions.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d4093bf and c823def.

📒 Files selected for processing (7)
  • .github/workflows/preview-deployment.yml (6 hunks)
  • .github/workflows/production-deployment.yml (2 hunks)
  • .github/workflows/promote-to-production.yml (1 hunks)
  • app.config.ts (12 hunks)
  • eas.json (1 hunks)
  • scripts/update-versions.js (1 hunks)
  • versions.json (1 hunks)
🧰 Additional context used
🪛 actionlint (1.7.7)
.github/workflows/promote-to-production.yml

54-54: workflow command "set-output" was deprecated. use echo "{name}={value}" >> $GITHUB_OUTPUT instead: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions

(deprecated-commands)

🪛 Biome (1.9.4)
versions.json

[error] 4-4: expected , but instead found // TODO set the right version using eas:version:get (something like this)

Remove // TODO set the right version using eas:version:get (something like this)

(parse)


[error] 7-7: expected , but instead found // TODO set the right version using eas:version:get (something like this)

Remove // TODO set the right version using eas:version:get (something like this)

(parse)


[error] 10-10: expected , but instead found // TODO set the right version using eas:version:get (something like this)

Remove // TODO set the right version using eas:version:get (something like this)

(parse)

scripts/update-versions.js

[error] 49-49: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (37)
eas.json (1)

4-4: LGTM! Correct alignment with local versioning system.

This change properly configures EAS to use the local versioning system, which aligns perfectly with the new versions.json centralized approach introduced in this PR.

app.config.ts (5)

3-3: LGTM! Clean import of centralized version data.

Great approach to import version data from the centralized versions.json file, providing a single source of truth for versioning across all environments.


16-16: LGTM! Proper type extensions for version fields.

The addition of buildNumber: string for iOS and versionCode: number for Android correctly reflects the platform-specific requirements and aligns with Expo's configuration schema.

Also applies to: 26-26


59-59: LGTM! Consistent version integration across all environments.

The implementation correctly:

  • Converts iOS buildNumber to string (as required by iOS)
  • Uses Android buildCode as number for versionCode
  • Maintains consistency across development, preview, and production environments

Also applies to: 69-69, 91-91, 101-101, 122-122, 132-132


158-160: LGTM! Appropriate runtime version policy change.

Changing from a hardcoded string to nativeVersion policy is the correct approach for the new centralized versioning system, ensuring runtime updates are properly managed based on native build versions.


173-173: LGTM! Proper platform-specific version configuration.

The final iOS and Android configuration correctly uses the version data from the environment settings, completing the integration of the centralized versioning system.

Also applies to: 215-215

scripts/update-versions.js (4)

8-21: LGTM! Robust argument parsing with proper validation.

The argument parsing logic correctly handles both value-based and flag-based arguments, providing flexibility for future enhancements.


28-38: LGTM! Comprehensive input validation.

Excellent validation for both platform and environment parameters, with clear error messages that guide proper usage.


40-73: LGTM! Solid error handling and file operations.

The script demonstrates excellent error handling practices:

  • Proper try-catch blocks for file operations
  • Clear error messages with context
  • Appropriate exit codes for CI/CD integration
  • Validation of data structure before modification
🧰 Tools
🪛 Biome (1.9.4)

[error] 49-49: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


75-77: LGTM! Proper module entry point handling.

Good practice to check require.main === module for direct script execution while allowing the function to be imported and used programmatically.

.github/workflows/promote-to-production.yml (8)

6-7: Permissions scope is correct
Granting contents: write is required for pushing commits and tags from this workflow.


10-17: Job outputs configured for downstream usage
Renaming the job to prepare_and_merge and exposing release_tag, app_version, and build_number aligns perfectly with the new multi-workflow versioning strategy.


19-25: Explicit checkout of main with PAT
Using actions/checkout@v4 with ref: main, fetch-depth: 0, and a personal access token ensures you can push commits and tags back to main.


26-34: Node.js and Yarn setup is solid
Leveraging .nvmrc, Yarn caching, corepack enable, and yarn install --immutable guarantees reproducible installs.


41-50: Robust package.json version extraction
The shell snippet correctly reads and validates package.json’s version field and exports it using the new GITHUB_OUTPUT syntax.


58-67: Validating and applying updated build number
The step guards against missing output and then updates app.config.ts with the new build number—good error handling and consistency with your versioning flow.


69-91: Commit and tag logic is correct
Conditionally committing only when files changed and then creating an annotated tag (v{version}-ios-build.{build_number}) matches best practices for release management.


92-99: Merge strategy confirmation
You’re using git merge main -Xtheirs to favor main on conflict. If that aligns with your release policy, this is a clean approach—otherwise, please verify that automatic theirs-strategy conflicts are acceptable.

.github/workflows/production-deployment.yml (10)

6-8: Tag-based trigger is precise
Switching from branch pushes to tag pattern vX.Y.Z-build.N ensures builds only run for formal releases.


10-11: Scoped concurrency
Using production-deployment-${{ github.ref }} avoids overlaps per tag run—perfect for high-frequency releases.


14-15: Permissions set correctly
id-token: write for potential OIDC-based steps and contents: write for release creation cover the workflow’s needs.


18-19: Job rename aligns with naming conventions
Renaming to build_and_deploy (snake_case) improves consistency against the other workflows.


21-25: Checkout of the release tag
Checking out ${{ github.ref }} with full history (fetch-depth: 0) is essential for release notes and correct source state.


27-35: Accurate parsing of version and build number
The sed expressions reliably extract semver and build components from the tag name; good fallback to package.json for the version.


45-50: Exporting metadata for later steps
Correct use of GITHUB_OUTPUT to expose release_tag, app_version, and build_number for downstream EAS and release steps.


57-65: Node.js and Yarn consistency
Aligns with other workflows—.nvmrc, Yarn cache, and --immutable for reproducibility.


81-83: Passing release tag into EAS build
Exporting RELEASE_TAG_VAL ensures descriptive build messages and traceability.


94-106: Verify GitHub CLI availability
You invoke gh release create directly; please confirm the runner environment includes the GitHub CLI or add an install step (e.g., actions/setup-gh).

.github/workflows/preview-deployment.yml (9)

7-7: Clarified force_native_build input
The description aptly explains its override behavior for check-changes logic.


21-21: Trigger on versions.json updates
Including versions.json in the path filters ensures preview builds bump appropriately when version metadata changes.


29-31: Scoped concurrency for preview runs
preview-deployment-${{ github.ref }} prevents overlapping workflows on the same ref—excellent for PRs and pushes.


77-79: Exposing preview build number
Outputting ios_preview_build_number from the update_versions_json_preview step makes this data available to other jobs or notifications.


85-87: Checkout with full history and PAT
Using token: ${{ secrets.PAT_GITHUB }} and fetch-depth: 0 matches the promote workflow, enabling commits back to the triggering branch.


99-100: Immutable Yarn install
yarn install --immutable enforces lockfile consistency across preview runs.


101-105: Git configuration for preview commits
Distinct bot identity (github-actions-bot-preview) prevents confusion in commit histories.


124-135: Local update of app.config.ts is sound
Validating the new build number then updating the config locally ensures the preview build uses the correct metadata.


150-156: Preview EAS submission step
Running eas build --profile preview --auto-submit against the locally bumped app.config.ts aligns with the intended preview flow.

{
"ios": {
"production": {
"buildNumber": 0 // TODO set the right version using eas:version:get (something like this)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix JSON syntax errors - comments are not valid in JSON.

The TODO comments break JSON parsing and will cause runtime errors when the file is imported by app.config.ts.

Remove the inline comments and fix the JSON syntax:

-      "buildNumber": 0 // TODO set the right version using eas:version:get (something like this)
+      "buildNumber": 0

Apply this fix to all three iOS environment entries.

Also applies to: 7-7, 10-10

🧰 Tools
🪛 Biome (1.9.4)

[error] 4-4: expected , but instead found // TODO set the right version using eas:version:get (something like this)

Remove // TODO set the right version using eas:version:get (something like this)

(parse)

🤖 Prompt for AI Agents
In versions.json at lines 4, 7, and 10, remove the inline comments from the JSON
entries because JSON does not support comments and these cause parsing errors.
Replace lines like "buildNumber": 0 // TODO ... with just "buildNumber": 0 to
ensure valid JSON syntax for all three iOS environment entries.

Comment on lines +1 to +24
{
"ios": {
"production": {
"buildNumber": 0 // TODO set the right version using eas:version:get (something like this)
},
"preview": {
"buildNumber": 0 // TODO set the right version using eas:version:get (something like this)
},
"development": {
"buildNumber": 0 // TODO set the right version using eas:version:get (something like this)
}
},
"android": {
"production": {
"buildCode": 0
},
"preview": {
"buildCode": 0
},
"development": {
"buildCode": 0
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Set proper initial version values instead of placeholder zeros.

All version numbers are initialized to 0, which might not reflect the current app store versions. Consider setting these to actual current values to maintain version continuity.

Would you like me to help generate a script to fetch current versions from the app stores or EAS? The TODO comments suggest using eas:version:get command for this purpose.

You can also run this command to get current versions:


🏁 Script executed:

#!/bin/bash
# Get current versions from EAS for each environment
echo "Getting current iOS versions..."
eas version:get --platform=ios --profile=production
eas version:get --platform=ios --profile=preview
eas version:get --platform=ios --profile=development

echo "Getting current Android versions..."
eas version:get --platform=android --profile=production
eas version:get --platform=android --profile=preview  
eas version:get --platform=android --profile=development

Length of output: 1051


Update versions.json with actual build numbers and codes

Please replace all 0 placeholders in versions.json with the real buildNumber (iOS) and buildCode (Android) that match your current App Store and Play Store releases. You’ll need to fetch these values locally, for example by installing and using the EAS CLI:

npm install -g eas-cli
# iOS
eas version:get --platform ios --profile production
eas version:get --platform ios --profile preview
eas version:get --platform ios --profile development

# Android
eas version:get --platform android --profile production
eas version:get --platform android --profile preview
eas version:get --platform android --profile development

Alternatively, you can look up the current version codes in App Store Connect and Google Play Console and update:

• File: versions.json
– ios.production.buildNumber
– ios.preview.buildNumber
– ios.development.buildNumber
– android.production.buildCode
– android.preview.buildCode
– android.development.buildCode

Ensuring these values are correct will maintain version continuity across your release channels.

🧰 Tools
🪛 Biome (1.9.4)

[error] 4-4: expected , but instead found // TODO set the right version using eas:version:get (something like this)

Remove // TODO set the right version using eas:version:get (something like this)

(parse)


[error] 7-7: expected , but instead found // TODO set the right version using eas:version:get (something like this)

Remove // TODO set the right version using eas:version:get (something like this)

(parse)


[error] 10-10: expected , but instead found // TODO set the right version using eas:version:get (something like this)

Remove // TODO set the right version using eas:version:get (something like this)

(parse)

🤖 Prompt for AI Agents
In versions.json from lines 1 to 24, replace all placeholder zeros for ios
buildNumber and android buildCode with the actual current version numbers for
each environment (production, preview, development). Use the eas-cli commands
eas version:get with the appropriate platform and profile to fetch these values
or retrieve them from App Store Connect and Google Play Console. Update
ios.production.buildNumber, ios.preview.buildNumber,
ios.development.buildNumber, android.production.buildCode,
android.preview.buildCode, and android.development.buildCode accordingly to
maintain version continuity.

`Successfully updated ${platform}.${env}.${keyToUpdate} to ${newBuildNumber} in versions.json`,
)
// Output the new build number so it can be captured by GitHub Actions
console.log(`::set-output name=new_build_number::${newBuildNumber}`)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Update deprecated GitHub Actions output syntax.

The ::set-output syntax is deprecated and will stop working in future GitHub Actions runners.

Replace with the current syntax:

-    console.log(`::set-output name=new_build_number::${newBuildNumber}`)
+    console.log(`new_build_number=${newBuildNumber}` >> process.env.GITHUB_OUTPUT || '/dev/stdout')

Or better yet, use the proper environment file approach:

-    console.log(`::set-output name=new_build_number::${newBuildNumber}`)
+    if (process.env.GITHUB_OUTPUT) {
+      require('fs').appendFileSync(process.env.GITHUB_OUTPUT, `new_build_number=${newBuildNumber}\n`)
+    } else {
+      console.log(`new_build_number=${newBuildNumber}`)
+    }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In scripts/update-versions.js at line 66, the use of the deprecated GitHub
Actions output syntax `::set-output` should be replaced. Instead of logging the
output with `::set-output`, write the output value to the file specified by the
environment variable `GITHUB_OUTPUT` using the proper environment file approach.
This involves appending a line with the format
`new_build_number=${newBuildNumber}` to the file path stored in
`process.env.GITHUB_OUTPUT`.

Comment on lines +52 to +57
- name: Update iOS Production Build Number in versions.json
id: update_versions_json
run: |
node scripts/update-versions.js --platform=ios --env=production
# The script itself uses `::set-output name=new_build_number::VALUE`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Deprecation warning: set-output
The update-versions.js script’s internal use of the deprecated ::set-output command will trigger actionlint errors. Please refactor the script to emit:

echo "new_build_number=$VALUE" >> $GITHUB_OUTPUT
🧰 Tools
🪛 actionlint (1.7.7)

54-54: workflow command "set-output" was deprecated. use echo "{name}={value}" >> $GITHUB_OUTPUT instead: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions

(deprecated-commands)

🤖 Prompt for AI Agents
In .github/workflows/promote-to-production.yml around lines 52 to 57, the
update-versions.js script uses the deprecated `::set-output` command to set
outputs, which causes actionlint errors. Modify the script to replace all
instances of `::set-output name=new_build_number::VALUE` with the new syntax by
appending `new_build_number=VALUE` to the file specified by the environment
variable GITHUB_OUTPUT using `echo "new_build_number=$VALUE" >> $GITHUB_OUTPUT`.

Comment on lines +112 to +120
- name: Commit and Push versions.json
run: |
if ! git diff --quiet versions.json; then
echo "versions.json was updated. Committing and pushing..."
git add versions.json
COMMIT_MSG="chore: Update iOS preview build number to ${{ steps.update_versions_json_preview.outputs.new_build_number }}"
git commit -m "$COMMIT_MSG"
git push origin ${{ github.ref_name }}
else
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Infinite loop risk on push trigger
Committing and pushing versions.json to main (or another branch) under a push-triggered workflow will retrigger this same workflow, causing repeated version bumps. Consider limiting the trigger conditions (e.g., exclude pushes made by the bot) or gating commits via if: github.actor != 'github-actions[bot]'.

🤖 Prompt for AI Agents
In .github/workflows/preview-deployment.yml around lines 112 to 120, the current
workflow commits and pushes changes to versions.json on every push, which can
cause an infinite loop by retriggering the workflow. To fix this, add a
condition to skip the commit and push steps if the actor is the GitHub Actions
bot by using an if statement like `if: github.actor != 'github-actions[bot]'`
before running the commit and push commands. This prevents the workflow from
triggering itself repeatedly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant