Skip to content
90 linesCodeBlameRaw
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, and Expo's hosts as workflow-only domains (mobile-build.yml
19# lists them).
20name: Mobile release
21
22on:
23 push:
24 tags: ["mobile-v*"]
25 workflow_dispatch:
26 inputs:
27 build:
28 description: "An EAS build id to publish instead of building again"
29 type: string
30 notes:
31 description: "A line about the release, shown in the manifest"
32 type: string
33
34permissions:
35 contents: read
36
37concurrency:
38 group: mobile-release
39 cancel-in-progress: false
40
41env:
42 CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
43 WRANGLER_SEND_METRICS: "false"
44
45jobs:
46 release:
47 name: Build and publish to g1t.sh/downloads/mobile
48 runs-on: ubuntu-latest
49 # Production's secrets, without a deployment: a release is not a deploy of
50 # g1t.sh, and would otherwise show on its card as one in progress.
51 environment:
52 name: production
53 deployment: false
54 timeout-minutes: 60
55 steps:
56 - uses: actions/checkout@v5
57 - name: The tag names this version
58 run: |
59 version="$(sed -n 's/^\s*version: "\(.*\)",/\1/p' apps/mobile/app.config.ts | head -1)"
60 if [ "${GITHUB_REF_TYPE}" = tag ] && [ "mobile-v$version" != "${GITHUB_REF_NAME}" ]; then
61 echo "::error::The tag is ${GITHUB_REF_NAME}, but apps/mobile is $version"; exit 1
62 fi
63 # npm's downloads, kept between runs: an install reads them first
64 # and asks the registry only for what changed, so a dropped
65 # connection to it rarely stops the job.
66 - name: Cache npm's downloads
67 uses: actions/cache@v4
68 with:
69 path: ~/.npm
70 key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
71 restore-keys: npm-${{ runner.os }}-
72 # Wrangler, from the root, and the app's own (EAS reads app.config.ts
73 # through its `expo`).
74 - name: Install Wrangler and the app
75 run: npm ci --prefer-offline --no-audit --no-fund -w @g1t/mobile --include-workspace-root
76 - name: Build on EAS
77 if: ${{ !inputs.build }}
78 env:
79 EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
80 run: node scripts/mobile-release.mjs build
81 - name: Fetch the APK
82 env:
83 EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
84 run: node scripts/mobile-release.mjs fetch ${{ inputs.build && format('--build {0}', inputs.build) || '' }}
85 - name: The manifest
86 run: node scripts/mobile-release.mjs manifest --notes "${{ inputs.notes }}"
87 - name: Publish
88 env:
89 CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
90 run: node scripts/mobile-release.mjs publish