name: Mobile Checks on: pull_request: types: - opened - synchronize - reopened - ready_for_review paths: - 'mobile/**' # Why: the mobile terminal link parsers are conformance-tested against # these shared fixtures; desktop-side fixture edits must re-run this suite. - 'src/shared/terminal-file-link-conformance.ts' # Why all of src/shared: mobile's tsconfig pulls 300+ files from it, and the # typecheck baseline now matches on message text, so a desktop-side rename can # reword a mobile diagnostic and redden this job for an unrelated author. - 'src/shared/**' # Why: the mobile typecheck runs through this script and its baseline. - 'config/scripts/typecheck-diagnostic-baseline.mjs' - 'mobile/typecheck-test-diagnostics.json' # Why: this job holds the only checks that load the Fastfile, so edits to # it or to the release workflow it guards must re-run them. - '.github/workflows/mobile.yml' - '.github/workflows/mobile-ios-release.yml' jobs: verify: runs-on: ubuntu-latest env: # Why: an unfrozen bundler silently re-resolves when Gemfile.lock drifts # from the Gemfile, which is how the release jobs could land on different # fastlane versions in the first place. Fail here instead. BUNDLE_FROZEN: 'true' defaults: run: working-directory: mobile steps: - name: Checkout uses: actions/checkout@v6 with: fetch-depth: 0 filter: blob:none - name: Load base mobile diagnostic baseline env: BASE_SHA: ${{ github.event.pull_request.base.sha }} run: | set -euo pipefail git cat-file -e "$BASE_SHA^{commit}" # Why ls-tree --full-tree: it answers "does the base have this file" from tree # objects alone, so a missing baseline is distinguishable from a git failure. # Anything other than a clean absence aborts the step rather than silently # leaving the growth guard unset, which would pass as "no drift". # Why a bare assignment: inside `[ -n "$(...)" ]` the substitution's exit status # is discarded, so a git failure would read as "base has no baseline" and pass. base_entry="$(git ls-tree -r --full-tree --name-only "$BASE_SHA" -- mobile/typecheck-test-diagnostics.json)" if [ -n "$base_entry" ]; then base_baseline="$RUNNER_TEMP/typecheck-mobile-base.json" git show "$BASE_SHA:mobile/typecheck-test-diagnostics.json" > "$base_baseline" echo "TYPECHECK_BASELINE_BASE_PATH=$base_baseline" >> "$GITHUB_ENV" echo "Mobile growth guard ACTIVE against $BASE_SHA." else echo "::warning::Mobile growth guard INACTIVE: base $BASE_SHA has no baseline yet. Expected only on the PR that introduces it." fi - name: Setup Node.js uses: actions/setup-node@v6 with: node-version-file: package.json # bundler-cache installs mobile/Gemfile.lock, so this job is also what # proves the pinned fastlane the release workflow depends on still # resolves — before a release run finds out. - name: Setup Ruby and fastlane uses: ruby/setup-ruby@v1 with: ruby-version: '3.3' bundler-cache: true working-directory: mobile - name: Setup pnpm uses: pnpm/action-setup@v6 with: run_install: false # Why: the mobile typecheck imports shared types from ../src/shared, and # some of those files import runtime deps (tweetnacl, ws) resolved from # the repo-root node_modules. Without a root install, tsc fails with # "Cannot find module 'tweetnacl'/'ws'". Mobile is a separate pnpm project # (not in the root workspace), so this is a distinct install. # --ignore-scripts skips the root postinstall (Electron native-module # rebuild) which is irrelevant to a type-only check and would only add # time and failure surface on this ubuntu mobile runner. - name: Install root dependencies working-directory: . run: pnpm install --frozen-lockfile --ignore-scripts - name: Install dependencies run: pnpm install --frozen-lockfile - name: Typecheck run: pnpm typecheck - name: Test run: pnpm test - name: Test iOS release version resolution run: ruby fastlane/ios_release_version_test.rb - name: Test TestFlight lane arguments run: ruby fastlane/fastfile_testflight_arguments_test.rb # Why: nothing else in CI loads the Fastfile, so a syntax error, a broken # require, or an undefined constant only surfaces mid-release — the # ios-distribute job failed every run for six days that way. `lanes` just # loads and lists, so it needs no App Store Connect credentials and makes # no network calls to Apple. - name: Smoke-check the Fastfile env: FASTLANE_SKIP_UPDATE_CHECK: '1' FASTLANE_OPT_OUT_USAGE: '1' run: bundle exec fastlane lanes - name: Lint run: pnpm lint - name: Check formatting run: pnpm format:check