| 1 | # Releases the phone app for Android (apps/mobile) on g1t.sh/download, |
| 2 | # while it is not in Google Play: EAS builds the `preview` profile (g1t |
| 3 | # (beta), a signed release APK), and the APK is published to |
| 4 | # g1t.sh/downloads/mobile/ (the g1t-downloads R2 bucket), with latest.json |
| 5 | # pointed at it. Google Play and the App Store wait on Flagon's D-U-N-S |
| 6 | # number; until then this is how the app is given out. |
| 7 | # |
| 8 | # A release is a tag `mobile-v<version>`, where the version is the one in |
| 9 | # apps/mobile/app.config.ts; or run it by hand, optionally naming a build |
| 10 | # EAS already made. scripts/mobile-release.mjs does the work. |
| 11 | # |
| 12 | # Most changes reach installed apps without a release: `eas update |
| 13 | # --channel preview` (expo-updates). A release is for a change to the |
| 14 | # app's native side (a new module, app.config.ts) or its version. |
| 15 | # |
| 16 | # Needs the repository secret EXPO_TOKEN (an Expo access token with access |
| 17 | # to the g1t project), CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID as the |
| 18 | # deploy has them. |
| 19 | name: Mobile release |
| 20 | |
| 21 | on: |
| 22 | push: |
| 23 | tags: ["mobile-v*"] |
| 24 | workflow_dispatch: |
| 25 | inputs: |
| 26 | build: |
| 27 | description: "An EAS build id to publish instead of building again" |
| 28 | type: string |
| 29 | notes: |
| 30 | description: "A line about the release, shown in the manifest" |
| 31 | type: string |
| 32 | |
| 33 | permissions: |
| 34 | contents: read |
| 35 | |
| 36 | concurrency: |
| 37 | group: mobile-release |
| 38 | cancel-in-progress: false |
| 39 | |
| 40 | env: |
| 41 | CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }} |
| 42 | WRANGLER_SEND_METRICS: "false" |
| 43 | |
| 44 | jobs: |
| 45 | release: |
| 46 | name: Build and publish to g1t.sh/downloads/mobile |
| 47 | runs-on: ubuntu-latest |
| 48 | # Production's secrets, without a deployment: a release is not a deploy of |
| 49 | # g1t.sh, and would otherwise show on its card as one in progress. |
| 50 | environment: |
| 51 | name: production |
| 52 | deployment: false |
| 53 | timeout-minutes: 60 |
| 54 | steps: |
| 55 | - uses: actions/checkout@v5 |
| 56 | - name: The tag names this version |
| 57 | run: | |
| 58 | version="$(sed -n 's/^\s*version: "\(.*\)",/\1/p' apps/mobile/app.config.ts | head -1)" |
| 59 | if [ "${GITHUB_REF_TYPE}" = tag ] && [ "mobile-v$version" != "${GITHUB_REF_NAME}" ]; then |
| 60 | echo "::error::The tag is ${GITHUB_REF_NAME}, but apps/mobile is $version"; exit 1 |
| 61 | fi |
| 62 | # npm's downloads, kept between runs: an install reads them first |
| 63 | # and asks the registry only for what changed, so a dropped |
| 64 | # connection to it rarely stops the job. |
| 65 | - name: Cache npm's downloads |
| 66 | uses: actions/cache@v4 |
| 67 | with: |
| 68 | path: ~/.npm |
| 69 | key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }} |
| 70 | restore-keys: npm-${{ runner.os }}- |
| 71 | - name: Install Wrangler |
| 72 | run: npm ci --prefer-offline --workspaces=false --no-audit --no-fund |
| 73 | - name: Build on EAS |
| 74 | if: ${{ !inputs.build }} |
| 75 | env: |
| 76 | EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }} |
| 77 | run: node scripts/mobile-release.mjs build |
| 78 | - name: Fetch the APK |
| 79 | env: |
| 80 | EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }} |
| 81 | run: node scripts/mobile-release.mjs fetch ${{ inputs.build && format('--build {0}', inputs.build) || '' }} |
| 82 | - name: The manifest |
| 83 | run: node scripts/mobile-release.mjs manifest --notes "${{ inputs.notes }}" |
| 84 | - name: Publish |
| 85 | env: |
| 86 | CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} |
| 87 | run: node scripts/mobile-release.mjs publish |