From 96116e0451d7227d2ca61a857c57d92fed6f206c Mon Sep 17 00:00:00 2001 From: Gauvain Date: Thu, 11 Jun 2026 11:08:07 +0200 Subject: [PATCH] feat(settings): show Actions run number for CI builds, hide store build number (#1711) --- .github/workflows/build-apps.yml | 11 ++++++++--- app.config.js | 6 ++++++ components/settings/UserInfo.tsx | 2 +- eas.json | 8 ++++++++ utils/version.ts | 29 ++++++++++++++++++----------- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build-apps.yml b/.github/workflows/build-apps.yml index 69a115072..c3fee61b8 100644 --- a/.github/workflows/build-apps.yml +++ b/.github/workflows/build-apps.yml @@ -12,10 +12,13 @@ on: branches: [develop, master] # Exposed to `expo prebuild` (app.config.js → extra.build) so Settings can show the -# branch + commit a CI build was made from. EAS cloud builds use EAS_BUILD_* instead. +# branch + commit + Actions run a CI build was made from. EAS cloud builds use +# EAS_BUILD_* instead. The run number maps a sideloaded build back to its Actions +# run (artifacts + logs) without needing Expo access. env: EXPO_PUBLIC_GIT_BRANCH: ${{ github.head_ref || github.ref_name }} EXPO_PUBLIC_GIT_COMMIT: ${{ github.sha }} + EXPO_PUBLIC_GIT_RUN_NUMBER: ${{ github.run_number }} jobs: build-android-phone: @@ -237,7 +240,9 @@ jobs: - name: 🚀 Build iOS app env: EXPO_TV: 0 - run: eas build -p ios --local --non-interactive + # `ci` profile (extends production, autoIncrement off): keeps CI builds out of + # the production version tier and stops them inflating the store build counter. + run: eas build -p ios --local --non-interactive --profile ci - name: 📅 Set date tag run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV @@ -362,7 +367,7 @@ jobs: - name: 🚀 Build iOS app env: EXPO_TV: 1 - run: eas build -p ios --local --non-interactive + run: eas build -p ios --local --non-interactive --profile ci_tv - name: 📅 Set date tag run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV diff --git a/app.config.js b/app.config.js index 970567360..d29ddc324 100644 --- a/app.config.js +++ b/app.config.js @@ -33,6 +33,12 @@ const buildMeta = { process.env.EAS_BUILD_PROFILE || process.env.EXPO_PUBLIC_BUILD_PROFILE || null, + // GitHub Actions run number (#2098) — lets anyone map a sideloaded CI build back + // to its Actions run (artifacts + logs) without Expo access. Null outside CI. + runNumber: + process.env.GITHUB_RUN_NUMBER || + process.env.EXPO_PUBLIC_GIT_RUN_NUMBER || + null, builtAt: new Date().toISOString(), }; diff --git a/components/settings/UserInfo.tsx b/components/settings/UserInfo.tsx index 6711d6554..9c55293d8 100644 --- a/components/settings/UserInfo.tsx +++ b/components/settings/UserInfo.tsx @@ -14,7 +14,7 @@ export const UserInfo: React.FC = ({ ...props }) => { const { t } = useTranslation(); // Graduated build identifier — see utils/version.ts: - // dev → "0.54.1 · branch · commit", develop/CI → "0.54.1 · commit", production → "0.54.1 (42)". + // dev → "0.54.1 · branch · commit", develop/CI → "0.54.1 · commit · #run", production → "0.54.1". const { display: version } = getVersionInfo(); return ( diff --git a/eas.json b/eas.json index 966881ce9..f4099eda6 100644 --- a/eas.json +++ b/eas.json @@ -97,6 +97,14 @@ "credentialsSource": "local", "config": "ios-production.yml" } + }, + "ci": { + "extends": "production", + "autoIncrement": false + }, + "ci_tv": { + "extends": "production_tv", + "autoIncrement": false } }, "submit": { diff --git a/utils/version.ts b/utils/version.ts index 79ba2c1bf..812665c40 100644 --- a/utils/version.ts +++ b/utils/version.ts @@ -10,6 +10,7 @@ export interface BuildMeta { commit?: string | null; branch?: string | null; profile?: string | null; + runNumber?: string | null; builtAt?: string | null; } @@ -22,8 +23,10 @@ export interface VersionInfo { commit: string | null; /** Git branch the build was made from, e.g. "develop". */ branch: string | null; - /** EAS build profile, e.g. "production", "preview", or null for local. */ + /** EAS build profile, e.g. "production", "ci", "preview", or null for local. */ profile: string | null; + /** GitHub Actions run number the build came from, e.g. "2098". Null outside CI. */ + runNumber: string | null; isDev: boolean; isProduction: boolean; /** Graduated label for the Settings "App version" row (see tiering below). */ @@ -34,13 +37,13 @@ export interface VersionInfo { * Resolve a graduated version string for Settings. * * Tiering (most → least detailed): - * - dev / local build → `version · branch · commit` (full context for debugging) - * - develop / CI / preview → `version · commit` (pin the exact source) - * - production (store / TestFlight) → `version (build)` (store-correlatable; the - * build number lets TestFlight reports pin a build whose version isn't a - * published release. Note: TestFlight and the public App Store ship the same - * binary — telling them apart needs a runtime iOS receipt check, intentionally - * not done here.) + * - dev / local build → `version · branch · commit` (full context for debugging) + * - develop / CI / preview → `version · commit · #run` (pin the exact source; the + * Actions run number maps the build to its run — artifacts + logs — without + * Expo access) + * - production (store / TestFlight) → `version` (build number intentionally + * not shown: TestFlight already displays it to testers, and the commit pins the + * binary better) */ export function getVersionInfo(): VersionInfo { // Read native/config values defensively — a version string must never crash Settings @@ -60,6 +63,7 @@ export function getVersionInfo(): VersionInfo { const commit = meta.commit ?? null; const branch = meta.branch ?? null; const profile = meta.profile ?? null; + const runNumber = meta.runNumber ?? null; const isDev = __DEV__ === true; const isProduction = typeof profile === "string" && profile.startsWith("production"); @@ -68,10 +72,12 @@ export function getVersionInfo(): VersionInfo { if (isDev) { display = [version ?? "dev", branch, commit].filter(Boolean).join(" · "); } else if (isProduction) { - display = - version && build ? `${version} (${build})` : (version ?? build ?? "N/A"); + display = version ?? build ?? "N/A"; } else { - display = [version, commit].filter(Boolean).join(" · ") || version || "N/A"; + display = + [version, commit, runNumber && `#${runNumber}`] + .filter(Boolean) + .join(" · ") || "N/A"; } return { @@ -80,6 +86,7 @@ export function getVersionInfo(): VersionInfo { commit, branch, profile, + runNumber, isDev, isProduction, display,