|
| 1 | +name: Publish example app |
| 2 | + |
| 3 | +# Publishes the example app that demonstrates the library to the App Store and |
| 4 | +# Play Store. This runs *after* a library release already exists, and cannot |
| 5 | +# affect it: see the failure report in the `report-failure` job below. |
| 6 | + |
| 7 | +on: |
| 8 | + release: |
| 9 | + types: [published] |
| 10 | + workflow_dispatch: |
| 11 | + inputs: |
| 12 | + tag: |
| 13 | + description: Release tag to publish the example app for, e.g. v6.0.0 |
| 14 | + required: true |
| 15 | + platform: |
| 16 | + description: Platforms to build and submit. Pick one to retry after a partial failure, so the platform that already shipped is not submitted twice. |
| 17 | + required: false |
| 18 | + default: all |
| 19 | + type: choice |
| 20 | + options: |
| 21 | + - all |
| 22 | + - ios |
| 23 | + - android |
| 24 | + |
| 25 | +permissions: |
| 26 | + contents: read |
| 27 | + |
| 28 | +concurrency: |
| 29 | + group: publish-example-app |
| 30 | + |
| 31 | +jobs: |
| 32 | + publish: |
| 33 | + name: Build and submit example app |
| 34 | + runs-on: ubuntu-latest |
| 35 | + # An EAS build for two platforms is slow, but not this slow. Without a |
| 36 | + # timeout a stuck run holds the concurrency lock for six hours. |
| 37 | + timeout-minutes: 120 |
| 38 | + permissions: |
| 39 | + contents: write |
| 40 | + pull-requests: write |
| 41 | + steps: |
| 42 | + - name: Checkout |
| 43 | + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 |
| 44 | + with: |
| 45 | + ref: main |
| 46 | + |
| 47 | + - name: Setup |
| 48 | + uses: ./.github/actions/setup |
| 49 | + |
| 50 | + - name: Resolve release tag and submit profile |
| 51 | + id: release |
| 52 | + env: |
| 53 | + TAG: ${{ github.event.release.tag_name || inputs.tag }} |
| 54 | + PLATFORM: ${{ inputs.platform }} |
| 55 | + run: | |
| 56 | + if [ -z "$TAG" ]; then |
| 57 | + echo "::error::No release tag to publish the example app for." |
| 58 | + exit 1 |
| 59 | + fi |
| 60 | +
|
| 61 | + # A semver version with a prerelease identifier (v6.0.0-alpha.1) goes |
| 62 | + # to the test tracks, a stable one (v6.0.0) goes to production. This |
| 63 | + # is derived from the tag rather than from the release's prerelease |
| 64 | + # flag on purpose: .release-it.json currently pins every release to |
| 65 | + # `preRelease: true` for the 6.0 alpha cycle, so that flag stays true |
| 66 | + # for a stable release until somebody remembers to revert it. |
| 67 | + if [ "${TAG#*-}" != "$TAG" ]; then |
| 68 | + profile=preview |
| 69 | + else |
| 70 | + profile=production |
| 71 | + fi |
| 72 | +
|
| 73 | + # A release always publishes both platforms. Only a manual retry can |
| 74 | + # narrow it, to avoid resubmitting a platform that already shipped. |
| 75 | + platform=${PLATFORM:-all} |
| 76 | +
|
| 77 | + echo "tag=$TAG" >> "$GITHUB_OUTPUT" |
| 78 | + echo "profile=$profile" >> "$GITHUB_OUTPUT" |
| 79 | + echo "platform=$platform" >> "$GITHUB_OUTPUT" |
| 80 | + echo "Publishing $platform for $TAG using the $profile submit profile." |
| 81 | +
|
| 82 | + - name: Bump example app version |
| 83 | + run: node scripts/bump-example-version.ts example/app.json |
| 84 | + |
| 85 | + - name: Setup Expo |
| 86 | + uses: expo/expo-github-action@c7b66a9c327a43a8fa7c0158e7f30d6040d2481e # v8.2.1 |
| 87 | + with: |
| 88 | + eas-version: latest |
| 89 | + token: ${{ secrets.EXPO_TOKEN }} |
| 90 | + |
| 91 | + # Build numbers are assigned remotely by EAS (`appVersionSource: remote`), |
| 92 | + # so a retry can never collide with an already submitted build. |
| 93 | + - name: Build and submit to the app stores |
| 94 | + id: submit |
| 95 | + working-directory: ./example |
| 96 | + env: |
| 97 | + SUBMIT_PROFILE: ${{ steps.release.outputs.profile }} |
| 98 | + PLATFORM: ${{ steps.release.outputs.platform }} |
| 99 | + run: | |
| 100 | + eas build \ |
| 101 | + --platform "$PLATFORM" \ |
| 102 | + --profile production \ |
| 103 | + --auto-submit-with-profile "$SUBMIT_PROFILE" \ |
| 104 | + --non-interactive |
| 105 | +
|
| 106 | + # Runs whenever the submit step ran at all, however it ended. `eas build` |
| 107 | + # can ship one platform and fail the other, and cancelling the workflow |
| 108 | + # does not cancel the build on EAS, so in every one of those cases a |
| 109 | + # version may have reached a store and has to be recorded. |
| 110 | + - name: Open example app version bump pull request |
| 111 | + if: ${{ always() && (steps.submit.outcome == 'success' || steps.submit.outcome == 'failure' || steps.submit.outcome == 'cancelled') }} |
| 112 | + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 |
| 113 | + with: |
| 114 | + token: ${{ secrets.GITHUB_TOKEN }} |
| 115 | + base: main |
| 116 | + add-paths: example/app.json |
| 117 | + branch: chore/example-app-version-${{ steps.release.outputs.tag }} |
| 118 | + commit-message: 'chore: bump example app version for ${{ steps.release.outputs.tag }}' |
| 119 | + title: 'chore: bump example app version for ${{ steps.release.outputs.tag }}' |
| 120 | + labels: example app |
| 121 | + body: | |
| 122 | + Records the example app version this run used for |
| 123 | + ${{ steps.release.outputs.tag }}. |
| 124 | +
|
| 125 | + A build for that version may already have been submitted, so this only |
| 126 | + keeps `example/app.json` in sync. iOS build numbers and Android version codes are not in here: |
| 127 | + EAS assigns those remotely. |
| 128 | +
|
| 129 | + - name: Summarise |
| 130 | + if: ${{ !cancelled() && steps.submit.outcome == 'success' }} |
| 131 | + env: |
| 132 | + TAG: ${{ steps.release.outputs.tag }} |
| 133 | + PROFILE: ${{ steps.release.outputs.profile }} |
| 134 | + run: | |
| 135 | + { |
| 136 | + echo "### Example app submitted for \`$TAG\`" |
| 137 | + echo |
| 138 | + echo "Submit profile: \`$PROFILE\`." |
| 139 | + if [ "$PROFILE" = "production" ]; then |
| 140 | + echo "- Android: Play Store **production** track." |
| 141 | + else |
| 142 | + echo "- Android: Play Store **internal** track." |
| 143 | + fi |
| 144 | + echo "- iOS: uploaded to App Store Connect, available in TestFlight." |
| 145 | + echo |
| 146 | + echo "Releasing an iOS build from TestFlight to the App Store is a" |
| 147 | + echo "separate manual step in App Store Connect." |
| 148 | + } >> "$GITHUB_STEP_SUMMARY" |
| 149 | +
|
| 150 | + report-failure: |
| 151 | + name: Report example app deployment problem |
| 152 | + needs: publish |
| 153 | + # Not `failure()`: that misses a cancelled run, and cancellation is the case |
| 154 | + # most likely to leave a build running on EAS with nobody told about it. |
| 155 | + if: ${{ always() && needs.publish.result != 'success' }} |
| 156 | + runs-on: ubuntu-latest |
| 157 | + steps: |
| 158 | + # Whoever published the release is already emailed that this run failed. |
| 159 | + # What that email cannot tell them is that their release is fine, so say |
| 160 | + # it here, where they land when they follow it. |
| 161 | + - name: Say that the library release is unaffected |
| 162 | + env: |
| 163 | + TAG: ${{ github.event.release.tag_name || inputs.tag }} |
| 164 | + run: | |
| 165 | + echo "::error::The example app deployment for $TAG did not finish. The $TAG library release itself published successfully and is not affected." |
| 166 | +
|
| 167 | + cat >> "$GITHUB_STEP_SUMMARY" <<EOF |
| 168 | + ## The \`$TAG\` library release is not affected |
| 169 | +
|
| 170 | + It is published on npm and on GitHub Releases exactly as expected, and |
| 171 | + **nothing here changes that**. This workflow only ever runs *after* a |
| 172 | + release already exists, so it cannot fail, revoke or roll back one. |
| 173 | +
|
| 174 | + - Users of the library need to do nothing. Installing \`react-native-paper\` is unaffected. |
| 175 | + - Nothing has to be re-released to fix this. |
| 176 | + - Only the demo app we ship to the App Store and Play Store did not update. |
| 177 | +
|
| 178 | + ## Before re-running |
| 179 | +
|
| 180 | + **Check the EAS dashboard and the stores first.** A build may already |
| 181 | + have been submitted, and submitting the same version twice is the one |
| 182 | + thing worth avoiding. Cancelling this workflow does not cancel a build |
| 183 | + already running on EAS, so a cancelled run can still ship on its own. |
| 184 | +
|
| 185 | + Once you have confirmed what did and did not reach the stores, re-run |
| 186 | + this workflow on its own, without cutting a new library release: |
| 187 | +
|
| 188 | + **Actions → Publish example app → Run workflow → tag \`$TAG\`** |
| 189 | +
|
| 190 | + If only one platform failed, pick it in the \`platform\` input so the |
| 191 | + other one is not submitted a second time. Retry before merging the |
| 192 | + version bump pull request this run opened, since merging it first |
| 193 | + moves \`main\` on and the retry would ship under a different version. |
| 194 | + EOF |
0 commit comments