Repository navigation
chore: automate example app publishing to app stores #5118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
4f76fd0
8047374
977d006
1342c6e
8e2440e
8fb6c25
959a4ba
57b9cf8
121126e
a9fa195
69f201a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,186 @@ | ||||||||||||||||||||
| name: Publish example app | ||||||||||||||||||||
|
|
||||||||||||||||||||
| on: | ||||||||||||||||||||
| release: | ||||||||||||||||||||
| types: [published] | ||||||||||||||||||||
| workflow_dispatch: | ||||||||||||||||||||
| inputs: | ||||||||||||||||||||
| tag: | ||||||||||||||||||||
| description: Release tag to publish the example app for, e.g. v6.0.0 | ||||||||||||||||||||
| required: true | ||||||||||||||||||||
| platform: | ||||||||||||||||||||
| description: Platform to build. Defaults to all. | ||||||||||||||||||||
| required: false | ||||||||||||||||||||
| default: all | ||||||||||||||||||||
| type: choice | ||||||||||||||||||||
| options: | ||||||||||||||||||||
| - all | ||||||||||||||||||||
| - ios | ||||||||||||||||||||
| - android | ||||||||||||||||||||
|
|
||||||||||||||||||||
| permissions: | ||||||||||||||||||||
| contents: read | ||||||||||||||||||||
|
|
||||||||||||||||||||
| concurrency: | ||||||||||||||||||||
| group: publish-example-app | ||||||||||||||||||||
|
|
||||||||||||||||||||
| jobs: | ||||||||||||||||||||
| publish: | ||||||||||||||||||||
| name: Build and submit example app | ||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||
| timeout-minutes: 120 | ||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i'm not sure about this timeout. since we're on free plan, it could take longer than 2 hours. probably simpler to just use
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Entirely your call so just LMK which option you prefer, but I'd suggest to just remove the line and use default 6 hours timeout. Should be more than enough for the builds to pass, we can see errors without going into EAS, and since waiting is free for opensource repos the only downside is the 6-hour release lock if the build gets stuck which doesn't seem to be a problem with the current release cadence.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, 6 hours sounds fine. The repo is public, so the waiting runner doesn't cost us anything, and 6 hours is also the limit for GitHub-hosted runners anyway. That's enough room for the free-tier queue plus both builds and submissions. If a run ever goes past that, the build keeps going on EAS, so the worst case is a failed run while the build still lands. Let's remove the line. |
||||||||||||||||||||
| permissions: | ||||||||||||||||||||
| contents: write | ||||||||||||||||||||
| pull-requests: write | ||||||||||||||||||||
| steps: | ||||||||||||||||||||
| - name: Checkout | ||||||||||||||||||||
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||||||||||||||||||||
| with: | ||||||||||||||||||||
| ref: main | ||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why check main? shouldn't it check the tag that was released? it could result in later commits being published instead of the released tag |
||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Setup | ||||||||||||||||||||
| uses: ./.github/actions/setup | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Resolve release tag and submit profile | ||||||||||||||||||||
| id: release | ||||||||||||||||||||
| env: | ||||||||||||||||||||
| TAG: ${{ github.event.release.tag_name || inputs.tag }} | ||||||||||||||||||||
| PLATFORM: ${{ inputs.platform }} | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| if [ -z "$TAG" ]; then | ||||||||||||||||||||
| echo "::error::No release tag to publish the example app for." | ||||||||||||||||||||
| exit 1 | ||||||||||||||||||||
| fi | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check never runs.
Suggested change
|
||||||||||||||||||||
| if [ "${TAG#*-}" != "$TAG" ]; then | ||||||||||||||||||||
| profile=preview | ||||||||||||||||||||
| else | ||||||||||||||||||||
| profile=production | ||||||||||||||||||||
| fi | ||||||||||||||||||||
|
|
||||||||||||||||||||
| platform=${PLATFORM:-all} | ||||||||||||||||||||
|
|
||||||||||||||||||||
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||
| echo "profile=$profile" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||
| echo "platform=$platform" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||
| echo "Publishing $platform for $TAG using the $profile submit profile." | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Setup Expo | ||||||||||||||||||||
| uses: expo/expo-github-action@c7b66a9c327a43a8fa7c0158e7f30d6040d2481e # v8.2.1 | ||||||||||||||||||||
| with: | ||||||||||||||||||||
| eas-version: latest | ||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we pin |
||||||||||||||||||||
| token: ${{ secrets.EXPO_TOKEN }} | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Check Expo authentication | ||||||||||||||||||||
| working-directory: ./example | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| if ! eas whoami; then | ||||||||||||||||||||
| echo "::error::Could not authenticate with Expo, check EXPO_TOKEN." | ||||||||||||||||||||
| exit 1 | ||||||||||||||||||||
| fi | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Decide between an update and a build | ||||||||||||||||||||
| id: decide | ||||||||||||||||||||
| working-directory: ./example | ||||||||||||||||||||
| env: | ||||||||||||||||||||
| PROFILE: ${{ steps.release.outputs.profile }} | ||||||||||||||||||||
| PLATFORM: ${{ steps.release.outputs.platform }} | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| platforms="$PLATFORM" | ||||||||||||||||||||
| if [ "$PLATFORM" = "all" ]; then | ||||||||||||||||||||
| platforms="ios android" | ||||||||||||||||||||
| fi | ||||||||||||||||||||
|
|
||||||||||||||||||||
| build=false | ||||||||||||||||||||
| for platform in $platforms; do | ||||||||||||||||||||
| hash=$(npx expo-updates fingerprint:generate --platform "$platform" | jq -r '.hash') | ||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ensure fingerprint doesn't change because of version bumps. otherwise it won't match next run and it'll trigger rebuild again. may need a fingerprint config ( /** @type {import('expo/fingerprint').Config} */
module.exports = {
sourceSkips: [
'ExpoConfigVersions',
'PackageJsonAndroidAndIosScriptsIfNotContainRun',
],
};
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. great catch, thank you |
||||||||||||||||||||
|
|
||||||||||||||||||||
| existing=$(eas build:list \ | ||||||||||||||||||||
| --platform "$platform" \ | ||||||||||||||||||||
| --channel "$PROFILE" \ | ||||||||||||||||||||
| --fingerprint-hash "$hash" \ | ||||||||||||||||||||
| --status finished \ | ||||||||||||||||||||
| --limit 1 \ | ||||||||||||||||||||
| --json \ | ||||||||||||||||||||
| --non-interactive | jq 'length') | ||||||||||||||||||||
|
|
||||||||||||||||||||
| echo "$platform: fingerprint $hash, $existing matching build(s)" | ||||||||||||||||||||
| [ "$existing" -eq 0 ] && build=true | ||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When We could keep a list of the platforms that need a build, build only those, and publish an update for the rest. Not a blocker though, fine as a follow-up.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did it in this PR since it was small. Decide now splits platforms into a build list and an update list, so only the one with native changes gets built and the other gets an OTA update. The update step also runs if the other platform's build fails. |
||||||||||||||||||||
| done | ||||||||||||||||||||
|
|
||||||||||||||||||||
| echo "build=$build" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||
| if [ "$build" = true ]; then | ||||||||||||||||||||
| echo "Native code changed, building and submitting." | ||||||||||||||||||||
| else | ||||||||||||||||||||
| echo "No native change, publishing an update instead." | ||||||||||||||||||||
| fi | ||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you check if this fails the workflow on an error instead of continuing? from claude (please verify): a failed command sends the run down the OTA path.
- The default run shell is bash -e without pipefail. If eas build:list or the fingerprint command fails, jq 'length' gets empty input and prints nothing, so existing is empty.
- [ "" -eq 0 ] then errors inside a && list, which doesn't trigger -e. build stays false, and the run publishes an OTA update and reports success.
- Fix: add shell: bash (it runs with -eo pipefail) and check that existing is a number.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. confirmed & fixed |
||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Bump example app version | ||||||||||||||||||||
| if: steps.decide.outputs.build == 'true' | ||||||||||||||||||||
| run: node scripts/bump-example-version.ts example/app.json | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Build and submit to the app stores | ||||||||||||||||||||
| id: submit | ||||||||||||||||||||
| if: steps.decide.outputs.build == 'true' | ||||||||||||||||||||
| working-directory: ./example | ||||||||||||||||||||
| env: | ||||||||||||||||||||
| PROFILE: ${{ steps.release.outputs.profile }} | ||||||||||||||||||||
| PLATFORM: ${{ steps.release.outputs.platform }} | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| eas build \ | ||||||||||||||||||||
| --platform "$PLATFORM" \ | ||||||||||||||||||||
| --profile "$PROFILE" \ | ||||||||||||||||||||
| --auto-submit-with-profile "$PROFILE" \ | ||||||||||||||||||||
| --non-interactive | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Publish an update | ||||||||||||||||||||
| id: update | ||||||||||||||||||||
| if: steps.decide.outputs.build == 'false' | ||||||||||||||||||||
| working-directory: ./example | ||||||||||||||||||||
| env: | ||||||||||||||||||||
| PROFILE: ${{ steps.release.outputs.profile }} | ||||||||||||||||||||
| TAG: ${{ steps.release.outputs.tag }} | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| eas update \ | ||||||||||||||||||||
| --branch "$PROFILE" \ | ||||||||||||||||||||
| --message "$TAG" \ | ||||||||||||||||||||
| --non-interactive | ||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Open version bump PR | ||||||||||||||||||||
| if: ${{ always() && (steps.submit.outcome == 'success' || steps.submit.outcome == 'failure' || steps.submit.outcome == 'cancelled') }} | ||||||||||||||||||||
| uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 | ||||||||||||||||||||
| with: | ||||||||||||||||||||
| token: ${{ secrets.GITHUB_TOKEN }} | ||||||||||||||||||||
| base: main | ||||||||||||||||||||
| add-paths: example/app.json | ||||||||||||||||||||
| branch: chore/example-app-version-${{ steps.release.outputs.tag }} | ||||||||||||||||||||
| commit-message: 'chore: bump example app version for ${{ steps.release.outputs.tag }}' | ||||||||||||||||||||
| title: 'chore: bump example app version for ${{ steps.release.outputs.tag }}' | ||||||||||||||||||||
| labels: example app | ||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd rather not have separate PR/commit for version bumps. Does it need to be stored in the repo? Can't it be derived from release tag automatically? |
||||||||||||||||||||
| body: Version bump for ${{ steps.release.outputs.tag }}. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| - name: Summarise | ||||||||||||||||||||
| if: ${{ !cancelled() && (steps.submit.outcome == 'success' || steps.update.outcome == 'success') }} | ||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can drop this Or we could write the summary at the end of the build and update steps and remove this step entirely.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Went with the second option, the build and update steps write their own summary and the Summarise step is gone. |
||||||||||||||||||||
| env: | ||||||||||||||||||||
| TAG: ${{ steps.release.outputs.tag }} | ||||||||||||||||||||
| PROFILE: ${{ steps.release.outputs.profile }} | ||||||||||||||||||||
| BUILT: ${{ steps.decide.outputs.build }} | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| if [ "$BUILT" = "true" ]; then | ||||||||||||||||||||
| echo "Built and submitted $TAG using the $PROFILE profile." >> "$GITHUB_STEP_SUMMARY" | ||||||||||||||||||||
| else | ||||||||||||||||||||
| echo "Published an OTA update for $TAG on the $PROFILE channel." >> "$GITHUB_STEP_SUMMARY" | ||||||||||||||||||||
| fi | ||||||||||||||||||||
|
|
||||||||||||||||||||
| report-failure: | ||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We start a separate runner here just to print one annotation. The run already shows up as failed, and GitHub already sends an email about it to whoever published the release. If we want to keep the message, a last step in
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved it into a last step in |
||||||||||||||||||||
| name: Report failure | ||||||||||||||||||||
| needs: publish | ||||||||||||||||||||
| if: ${{ always() && needs.publish.result != 'success' }} | ||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||
| steps: | ||||||||||||||||||||
| - name: Report failure | ||||||||||||||||||||
| env: | ||||||||||||||||||||
| TAG: ${{ github.event.release.tag_name || inputs.tag }} | ||||||||||||||||||||
| run: | | ||||||||||||||||||||
| echo "::error::Example app deployment failed for $TAG. The release itself is fine, only the demo app did not update." | ||||||||||||||||||||
| echo "Check EAS and the stores before re-running, a build may already have been submitted." >> "$GITHUB_STEP_SUMMARY" | ||||||||||||||||||||
This file was deleted.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -109,6 +109,8 @@ yarn release | |||||||||||||||||||
|
|
||||||||||||||||||||
| NOTE: You must have a `GITHUB_TOKEN` environment variable available. You can create a GitHub access token with the "repo" access [here](https://github.com/settings/tokens). | ||||||||||||||||||||
|
|
||||||||||||||||||||
| We use EAS for auto-deployments of the example app. Releases with no native changes ship OTA. Releases with native code changes will be pushed to Stores automatically and job will create a PR with version bump, merge it to avoid two releases shipping under the same version. Android will also be auto-submitted for review, iOS still requires manual submission. Pre-releases are shipped to internal track and TestFlight only. | ||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's make this more user focused. it should say what to do. something like:
Suggested change
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| ## Reporting issues | ||||||||||||||||||||
|
|
||||||||||||||||||||
| You can report issues on our [bug tracker](https://github.com/callstack/react-native-paper/issues). Please follow the issue template when opening an issue. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| # prevents build failures due to version mismatch | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please clarify this comment. what kind of version mismatch and build failure?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this good enough explaination? previously it had full context but I rewrote it as minimalistic as possible following suggestion on removing AI prose: |
||
| node_modules/expo-modules-jsi/apple/Products/ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,11 +16,12 @@ | |
| "owner": "react-native-paper", | ||
| "ios": { | ||
| "bundleIdentifier": "com.callstack.reactnativepaperexample", | ||
| "buildNumber": "26.0.5" | ||
| "infoPlist": { | ||
| "ITSAppUsesNonExemptEncryption": false | ||
| } | ||
| }, | ||
| "android": { | ||
| "package": "com.callstack.reactnativepaperexample", | ||
| "versionCode": 38, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. with
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this one is done, I already seeded the values (iOS 26.0.5, Android 38) and they auto-incremented as expected to |
||
| "permissions": [ | ||
| "READ_EXTERNAL_STORAGE", | ||
| "WRITE_EXTERNAL_STORAGE" | ||
|
|
@@ -37,7 +38,7 @@ | |
| } | ||
| }, | ||
| "runtimeVersion": { | ||
| "policy": "sdkVersion" | ||
| "policy": "fingerprint" | ||
| }, | ||
| "updates": { | ||
| "url": "https://u.expo.dev/ba8f5139-58fe-48f0-b2f2-2d675b6eb2d4" | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,35 @@ | ||||
| { | ||||
| "cli": { | ||||
| "appVersionSource": "remote" | ||||
| }, | ||||
| "build": { | ||||
| "production": { | ||||
| "node": "24.13.0", | ||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When the profile doesn't set
Suggested change
One catch is that ln -s ../.nvmrc example/.nvmrc |
||||
| "autoIncrement": true, | ||||
| "android": { | ||||
| "buildType": "app-bundle" | ||||
| }, | ||||
| "channel": "production" | ||||
| }, | ||||
| "preview": { | ||||
| "extends": "production", | ||||
| "channel": "preview" | ||||
| } | ||||
| }, | ||||
| "submit": { | ||||
| "production": { | ||||
| "android": { | ||||
| "track": "production" | ||||
| }, | ||||
| "ios": { | ||||
| "ascAppId": "1548934513" | ||||
| } | ||||
| }, | ||||
| "preview": { | ||||
| "extends": "production", | ||||
| "android": { | ||||
| "track": "internal" | ||||
| } | ||||
| } | ||||
| } | ||||
| } | ||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| import { afterEach, expect, it } from '@jest/globals'; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we don't really need tests for basic scripts |
||
| import { execFileSync } from 'node:child_process'; | ||
| import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; | ||
| import { tmpdir } from 'node:os'; | ||
| import { join } from 'node:path'; | ||
|
|
||
| const script = join(__dirname, '..', 'bump-example-version.ts'); | ||
|
|
||
| const directories: string[] = []; | ||
|
|
||
| const writeAppConfig = (version: string) => { | ||
| const directory = mkdtempSync(join(tmpdir(), 'bump-example-version-')); | ||
| directories.push(directory); | ||
| const appConfigPath = join(directory, 'app.json'); | ||
|
|
||
| writeFileSync( | ||
| appConfigPath, | ||
| JSON.stringify({ expo: { name: 'Example', version } }, null, 2) + '\n' | ||
| ); | ||
|
|
||
| return appConfigPath; | ||
| }; | ||
|
|
||
| const bump = (appConfigPath: string) => { | ||
| execFileSync('node', [script, appConfigPath], { | ||
| stdio: ['ignore', 'pipe', 'pipe'], | ||
| }); | ||
|
|
||
| return JSON.parse(readFileSync(appConfigPath, 'utf8')).expo.version; | ||
| }; | ||
|
|
||
| afterEach(() => { | ||
| directories.splice(0).forEach((directory) => { | ||
| rmSync(directory, { recursive: true, force: true }); | ||
| }); | ||
| }); | ||
|
|
||
| it('bumps the minor version', () => { | ||
| expect(bump(writeAppConfig('3.16.0'))).toBe('3.17.0'); | ||
| }); | ||
|
|
||
| it('increments the minor version past a single digit', () => { | ||
| expect(bump(writeAppConfig('3.9.0'))).toBe('3.10.0'); | ||
| }); | ||
|
|
||
| it('fails when the current version is not a valid version', () => { | ||
| expect(() => bump(writeAppConfig('not-a-version'))).toThrow( | ||
| /got "not-a-version"/ | ||
| ); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import { readFileSync, writeFileSync } from 'node:fs'; | ||
|
|
||
| type AppConfig = { expo?: { version?: string } }; | ||
|
|
||
| const appConfigPath = process.argv[2]; | ||
|
|
||
| if (!appConfigPath) { | ||
| console.error( | ||
| 'Usage: node scripts/bump-example-version.ts <path to the example app config>' | ||
| ); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const appConfig: AppConfig = JSON.parse(readFileSync(appConfigPath, 'utf8')); | ||
| const expo = appConfig.expo; | ||
| const currentVersion = expo?.version; | ||
| const parsed = /^(\d+)\.(\d+)\.(\d+)$/.exec(currentVersion ?? ''); | ||
|
|
||
| if (!expo || !parsed) { | ||
| console.error( | ||
| `Expected a "major.minor.patch" version at expo.version in ${appConfigPath}, got ${JSON.stringify(currentVersion)}.` | ||
| ); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const [, major, minor] = parsed; | ||
| const nextVersion = `${major}.${Number(minor) + 1}.0`; | ||
|
|
||
| expo.version = nextVersion; | ||
|
|
||
| writeFileSync(appConfigPath, JSON.stringify(appConfig, null, 2) + '\n'); | ||
|
|
||
| console.log(`Bumped example app version to ${nextVersion}`); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need this script? Can't the workflow just do something like: - name: Set example app version from the release tag
if: steps.decide.outputs.build == 'true'
working-directory: ./example
env:
TAG: ${{ steps.release.outputs.tag }}
run: |
version="${TAG#v}"
version="${version%%-*}"
jq --arg version "$version" '.expo.version = $version' app.json > app.json.tmp
mv app.json.tmp app.jsonso instead of reading version number from app.json, it'd use the release tag also ensure the step fails if the tag doesn't match |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ensure we only deploy on releases on main. we may need to fetch tags from main and compare to skip releases from other branches such as 5.x