Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
97 linesCodeBlameRaw
1# Builds the phone app for Android on EAS, to install from a link or a QR
2# code before it is in Google Play. Nothing is published: the run's summary
3# links the build's page on expo.dev, which shows the QR code, and the APK.
4#
5# - `preview` (default): g1t (beta), sh.g1t.app.preview, a standalone signed
6# APK that needs no computer: what testers install, from the build page's
7# QR code. Code changes reach it over the air (`eas update --channel
8# preview`), so it is built again only when the native side changes; on
9# main that happens by itself (the paths below). mobile-release.yml
10# publishes these on g1t.sh/download.
11# - `development`: g1t (dev), sh.g1t.app.dev, with expo-dev-client. It loads
12# the app's code from `npx expo start` on your computer.
13#
14# Needs the repository secret EXPO_TOKEN (an Expo access token with access
15# to @flagon-io/g1t), and Expo's hosts allowed for these workflows alone in
16# the project's Settings, Guardrails, Workflow-only domains:
17#
18# api.expo.dev | mobile-build.yml, mobile-release.yml
19# expo.dev | mobile-build.yml, mobile-release.yml
20# storage.googleapis.com | mobile-build.yml, mobile-release.yml
21# *.eascdn.net | mobile-build.yml, mobile-release.yml
22#
23# (the API, its artifact links, where EAS uploads the project's archive,
24# and where an artifact link sends the APK's download).
25name: Mobile build
26
27on:
28 push:
29 branches: [main]
30 paths:
31 - apps/mobile/app.config.ts
32 - apps/mobile/eas.json
33 - apps/mobile/package.json
34 - apps/mobile/assets/images/**
35 workflow_dispatch:
36 inputs:
37 profile:
38 description: "The EAS build profile"
39 type: choice
40 options: [preview, development]
41 default: preview
42
43permissions:
44 contents: read
45
46concurrency:
47 group: mobile-build-${{ inputs.profile || 'preview' }}
48 cancel-in-progress: true
49
50jobs:
51 build:
52 name: Build Android (${{ inputs.profile || 'preview' }}) on EAS
53 runs-on: ubuntu-latest
54 timeout-minutes: 60
55 env:
56 PROFILE: ${{ inputs.profile || 'preview' }}
57 steps:
58 - uses: actions/checkout@v5
59 - name: Cache npm's downloads
60 uses: actions/cache@v4
61 with:
62 path: ~/.npm
63 key: npm-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
64 restore-keys: npm-${{ runner.os }}-
65 # EAS reads app.config.ts through the app's own `expo`.
66 - name: Install the app's dependencies
67 run: npm ci --prefer-offline --no-audit --no-fund -w @g1t/mobile
68 - name: Build on EAS
69 working-directory: apps/mobile
70 env:
71 EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
72 run: |
73 # A token pasted with a newline breaks the request's header.
74 export EXPO_TOKEN="$(printf %s "$EXPO_TOKEN" | tr -d '[:space:]')"
75 # Without a token Expo answers 200; a bare 403 is the sandbox's egress refusing it.
76 code="$(curl -s -o /dev/null -w '%{http_code}' -X POST https://api.expo.dev/graphql \
77 -H 'Content-Type: application/json' -d '{"query":"{ meUserActor { id } }"}')"
78 echo "api.expo.dev answers this runner with $code"
79 if [ "$code" = 403 ]; then echo "::error::api.expo.dev is not allowed: add the workflow-only domains above in the project's Guardrails"; exit 1; fi
80 npx --yes eas-cli@24.12.1 whoami
81 npx --yes eas-cli@24.12.1 build --platform android --profile "$PROFILE" \
82 --non-interactive --wait --json > build.json
83 node -e '
84 const [build] = JSON.parse(require("fs").readFileSync("build.json", "utf8"));
85 const page = `https://expo.dev/accounts/flagon-io/projects/g1t/builds/${build.id}`;
86 const lines = [
87 `### g1t for Android, ${process.env.PROFILE} build`,
88 "",
89 `- Status: ${build.status}`,
90 `- Version: ${build.appVersion} (versionCode ${build.appBuildVersion})`,
91 `- Install: open [the build on expo.dev](${page}) and scan its QR code with the phone`,
92 build.artifacts?.buildUrl ? `- APK: ${build.artifacts.buildUrl}` : "",
93 ];
94 console.log(lines.join("\n"));
95 require("fs").appendFileSync(process.env.GITHUB_STEP_SUMMARY, lines.join("\n") + "\n");
96 if (build.status !== "FINISHED") process.exit(1);
97 '