OverviewFilesCommitsIssuesDocsReleasesPeers

cthuloid / .pear-git / ci.yaml

97 lines · yaml ref:
# pear-git CI for the cthuloid repo: builds the Android app (android/) on
# android-v<x.y.z> TAGS ONLY, and publishes a signed APK as a forge download:
#   https://7rnx.net/git/releases/cthuloid/android-v<x.y.z>/dist/cthuloid-lights.apk
# See docs/DESIGN-android.md §5.
#
# ⛔ The forge runs this for EVERY pushed branch and tag and cannot filter, so each
# step checks the ref itself (GIT_REF / GIT_REF_KIND are injected) and does nothing
# unless the gate step decided to build. Every push publishes `dist/` -- on a
# non-release ref it holds only skipped.txt. (A listed-but-missing file would make
# collectArtifacts throw and leave a misleading error in the forge log.)
#
# ⛔ CI runs in a `git archive | tar -x` extraction: no .git, no node_modules, no
# PATH guarantees, `sh -c` (not bash). Host paths are absolute, as in
# favela-surface-android's ci.yaml.
#
# ⛔ THE SIGNING KEY is ~/android-toolchain/cthuloid.keystore with its password in
# cthuloid.keystore.pass -- outside the repo, never in git. Android refuses an
# update signed with any other key (uninstall, i.e. data loss, is the only way
# out), so the build FAILS if the key is missing rather than signing with another.

steps:
  - name: gate
    run: |
      set -e
      mkdir -p dist
      if [ "$GIT_REF_KIND" = "tag" ] && echo "$GIT_REF" | grep -Eq '^android-v[0-9]+\.[0-9]+\.[0-9]+$'; then
        echo "release build: $GIT_REF"
      else
        echo "not an android-v<x.y.z> tag ($GIT_REF_KIND $GIT_REF): nothing to build"
        echo "APKs are built on android-v<x.y.z> tags only; this ref ($GIT_REF_KIND $GIT_REF) built nothing." > dist/skipped.txt
        touch .skip
      fi
    timeout: 30

  - name: deps
    run: |
      set -e
      [ -f .skip ] && exit 0
      export PATH=/home/fleeky/.nvm/versions/node/v24.13.0/bin:$PATH
      (cd webui && npm ci --no-audit --no-fund)
      (cd android && npm ci --no-audit --no-fund)
      test -e android/node_modules/cthuloid-web/lib/app.js
    timeout: 900

  - name: version
    # The version comes from the tag, never from hand-editing a field.
    run: |
      set -e
      [ -f .skip ] && exit 0
      export PATH=/home/fleeky/.nvm/versions/node/v24.13.0/bin:$PATH
      V=${GIT_REF#android-v}
      (cd android && node -e "const fs=require('fs');const p=JSON.parse(fs.readFileSync('package.json'));p.version=process.argv[1];fs.writeFileSync('package.json',JSON.stringify(p,null,2)+'\n')" "$V")
      grep '"version"' android/package.json
    timeout: 30

  - name: prebuild
    run: |
      set -e
      [ -f .skip ] && exit 0
      export PATH=/home/fleeky/.nvm/versions/node/v24.13.0/bin:$PATH
      (cd android && npm run prebuild:android)
      test -s android/android/app/src/main/assets/worklet.bundle
    timeout: 900

  - name: assemble
    run: |
      set -e
      [ -f .skip ] && exit 0
      T=/home/fleeky/android-toolchain
      test -s $T/cthuloid.keystore
      test -s $T/cthuloid.keystore.pass
      export JAVA_HOME=$T/jdk-17.0.13+11
      export ANDROID_HOME=$T/sdk
      export PATH=/home/fleeky/.nvm/versions/node/v24.13.0/bin:$PATH
      export CTHULOID_KEYSTORE=$T/cthuloid.keystore
      CTHULOID_KEYSTORE_PASS=$(cat $T/cthuloid.keystore.pass)
      export CTHULOID_KEYSTORE_PASS
      # Every new-architecture library's codegen must exist before CMake configure
      # (favela-surface-android's ci.yaml); unqualified so it covers all of them.
      $T/gradle-8.13/bin/gradle -p android/android generateCodegenArtifactsFromSchema
      $T/gradle-8.13/bin/gradle -p android/android assembleRelease
      cp android/android/app/build/outputs/apk/release/app-release.apk dist/cthuloid-lights.apk
      # The artifact, not the intent: every native lib's NEEDED entries are in the APK...
      (cd android && node scripts/verify-apk-addons.mjs ../dist/cthuloid-lights.apk)
      # ...and it is signed with THIS key, not a debug or stray one.
      WANT=$($JAVA_HOME/bin/keytool -list -v -keystore $T/cthuloid.keystore -storepass:file $T/cthuloid.keystore.pass | sed -n 's/.*SHA256: //p' | head -1 | tr -d ': ' | tr 'A-F' 'a-f')
      GOT=$($ANDROID_HOME/build-tools/34.0.0/apksigner verify --print-certs dist/cthuloid-lights.apk | sed -n 's/.*certificate SHA-256 digest: //p' | head -1)
      echo "signer want=$WANT got=$GOT"
      [ -n "$WANT" ] && [ "$WANT" = "$GOT" ]
      (cd dist && sha256sum cthuloid-lights.apk > cthuloid-lights.apk.sha256)
      ls -l dist
    timeout: 2700

artifacts:
  # A directory: files only on a release tag, skipped.txt otherwise.
  - dist