440 lines
22 KiB
YAML
440 lines
22 KiB
YAML
# .gitlab-ci.yml
|
|
# GitLab CI/CD Pipeline for D3RO Voice
|
|
|
|
stages:
|
|
- validate
|
|
- test
|
|
- build
|
|
- e2e
|
|
- package
|
|
- publish
|
|
- deploy
|
|
|
|
variables:
|
|
NODE_VERSION: "24.19.0"
|
|
PACKAGE_NAME: "d3ro-voice"
|
|
|
|
default:
|
|
image: node:24.19.0-bookworm
|
|
tags:
|
|
- build-linux-x64
|
|
before_script:
|
|
- npm ci
|
|
|
|
# ────────────────────────────────────────────────────────────────────
|
|
# Validate & Lint
|
|
# ────────────────────────────────────────────────────────────────────
|
|
lint-and-typecheck:
|
|
stage: validate
|
|
script:
|
|
- npm run version:check
|
|
- if [ -n "${CI_COMMIT_TAG:-}" ]; then node scripts/ci/sync-version.mjs --check --tag "$CI_COMMIT_TAG"; fi
|
|
- npm run release:metadata:test
|
|
- npm run security:secrets:test
|
|
- npm run security:secrets
|
|
- npm run release:mobile:boundary:test
|
|
- npm run release:mobile:config:test
|
|
- npm run release:mobile:build-config:test
|
|
- npm run release:play:assets
|
|
- npm run lint
|
|
- npm run typecheck
|
|
rules:
|
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
- if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"'
|
|
- if: '$CI_COMMIT_TAG'
|
|
|
|
# ────────────────────────────────────────────────────────────────────
|
|
# Unit & Integration Tests
|
|
# ────────────────────────────────────────────────────────────────────
|
|
test-unit:
|
|
stage: test
|
|
script:
|
|
- npm test
|
|
coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
|
|
artifacts:
|
|
when: always
|
|
reports:
|
|
junit: junit.xml
|
|
rules:
|
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
- if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"'
|
|
- if: '$CI_COMMIT_TAG'
|
|
|
|
api-server-tests:
|
|
stage: test
|
|
image: mcr.microsoft.com/dotnet/sdk:10.0.302-noble
|
|
before_script: []
|
|
script:
|
|
- dotnet restore apps/api-server.Tests/D3ROVoice.Api.Tests.csproj
|
|
- dotnet test apps/api-server.Tests/D3ROVoice.Api.Tests.csproj --configuration Release --no-restore -p:StaticWebAssetsEnabled=false
|
|
rules:
|
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
- if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"'
|
|
- if: '$CI_COMMIT_TAG'
|
|
|
|
edge-functions-quality:
|
|
stage: test
|
|
image: denoland/deno:2.8.1
|
|
before_script: []
|
|
script:
|
|
- for entrypoint in server/supabase/functions/*/index.ts; do deno check --config server/supabase/functions/deno.json "$entrypoint"; done
|
|
- deno test --config server/supabase/functions/deno.json --allow-read --allow-env server/supabase/functions
|
|
rules:
|
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
- if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"'
|
|
- if: '$CI_COMMIT_TAG'
|
|
|
|
mobile-quality:
|
|
stage: test
|
|
before_script:
|
|
- npm ci
|
|
- npm --prefix apps/mobile-rn ci --workspaces=false
|
|
script:
|
|
- npm --prefix apps/mobile-rn run lint
|
|
- npm --prefix apps/mobile-rn run typecheck
|
|
- npm --prefix apps/mobile-rn run test:ci
|
|
rules:
|
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
- if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"'
|
|
- if: '$CI_COMMIT_TAG'
|
|
|
|
mobile-android:
|
|
stage: build
|
|
image: reactnativecommunity/react-native-android@sha256:24ca7ab5a70ec0b78a81bdc5eeea5924c2531531d53971b6f2321aff08446c36
|
|
needs:
|
|
- mobile-quality
|
|
before_script:
|
|
- export ANDROID_HOME=/opt/android
|
|
- export ANDROID_SDK_ROOT=/opt/android
|
|
- curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz" -o /tmp/node.tar.xz
|
|
- echo '14b342e71204f811bde6153be8e04b62aef63c236fef92b55f9c83154b409647 /tmp/node.tar.xz' | sha256sum -c -
|
|
- mkdir -p /tmp/node24
|
|
- tar -xJf /tmp/node.tar.xz -C /tmp/node24 --strip-components=1
|
|
- export PATH="/tmp/node24/bin:$PATH"
|
|
- node --version | grep -Fx "v${NODE_VERSION}"
|
|
- export D3RO_VERSION_NAME="0.0.0-e2e.${CI_PIPELINE_IID}"
|
|
- export D3RO_VERSION_CODE="${CI_PIPELINE_IID}"
|
|
- sdkmanager "platforms;android-36" "build-tools;36.0.0" >/dev/null
|
|
- npm ci
|
|
- npm --prefix apps/mobile-rn ci --workspaces=false
|
|
script:
|
|
- node scripts/ci/prepare-whisper-model.mjs
|
|
- cd apps/mobile-rn/android
|
|
- ./gradlew :app:assembleDebug :app:assembleDebugAndroidTest :app:assembleE2e -PreactNativeArchitectures=arm64-v8a,x86_64 --no-daemon
|
|
- cd "$CI_PROJECT_DIR"
|
|
- node scripts/ci/verify-mobile-build-config.mjs debug > apps/mobile-rn/android/app/build/outputs/debug-build-config.json
|
|
- node scripts/ci/verify-mobile-build-config.mjs e2e > apps/mobile-rn/android/app/build/outputs/e2e-build-config.json
|
|
- node scripts/ci/verify-android-artifact.mjs --mode debug --apk apps/mobile-rn/android/app/build/outputs/apk/debug/app-debug.apk > apps/mobile-rn/android/app/build/outputs/debug-artifact-evidence.json
|
|
- node scripts/ci/verify-android-artifact.mjs --mode e2e --apk apps/mobile-rn/android/app/build/outputs/apk/e2e/app-e2e.apk --expected-version-name "$D3RO_VERSION_NAME" --expected-version-code "$D3RO_VERSION_CODE" > apps/mobile-rn/android/app/build/outputs/e2e-artifact-evidence.json
|
|
- sha256sum apps/mobile-rn/android/app/build/outputs/apk/debug/app-debug.apk apps/mobile-rn/android/app/build/outputs/apk/e2e/app-e2e.apk > apps/mobile-rn/android/app/build/outputs/android-ci.sha256
|
|
artifacts:
|
|
when: always
|
|
expire_in: 1 day
|
|
paths:
|
|
- apps/mobile-rn/android/app/build/outputs/apk/debug/app-debug.apk
|
|
- apps/mobile-rn/android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk
|
|
- apps/mobile-rn/android/app/build/outputs/apk/e2e/app-e2e.apk
|
|
- apps/mobile-rn/android/app/build/outputs/android-ci.sha256
|
|
- apps/mobile-rn/android/app/build/outputs/*-build-config.json
|
|
- apps/mobile-rn/android/app/build/outputs/*-artifact-evidence.json
|
|
rules:
|
|
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
- if: '$CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop"'
|
|
- if: '$CI_COMMIT_TAG'
|
|
|
|
mobile-emulator-e2e:
|
|
stage: e2e
|
|
image: reactnativecommunity/react-native-android@sha256:24ca7ab5a70ec0b78a81bdc5eeea5924c2531531d53971b6f2321aff08446c36
|
|
tags:
|
|
- android-emulator
|
|
- kvm
|
|
needs:
|
|
- job: mobile-android
|
|
artifacts: true
|
|
before_script: []
|
|
script:
|
|
- export ANDROID_HOME=/opt/android
|
|
- export ANDROID_SDK_ROOT=/opt/android
|
|
- sdkmanager "platform-tools" "emulator" "platforms;android-35" "system-images;android-35;google_apis;x86_64" >/dev/null
|
|
- echo no | avdmanager create avd --force --name d3ro_ci_api35 --package "system-images;android-35;google_apis;x86_64"
|
|
- emulator -avd d3ro_ci_api35 -no-window -noaudio -no-boot-anim -gpu swiftshader_indirect -camera-back none &
|
|
- adb wait-for-device
|
|
- timeout 180 bash -c 'until [[ "$(adb shell getprop sys.boot_completed 2>/dev/null | tr -d "\r")" == "1" ]]; do sleep 2; done'
|
|
- curl -fsSL https://github.com/mobile-dev-inc/maestro/releases/download/cli-2.7.0/maestro.zip -o /tmp/maestro.zip
|
|
- echo 'a4ccab6b604617e7aef6db4f885666056eabe5cfa32befaa3bc994041b8fcbb5 /tmp/maestro.zip' | sha256sum -c -
|
|
- unzip -q /tmp/maestro.zip -d /tmp/maestro
|
|
- export PATH="/tmp/maestro/maestro/bin:$PATH"
|
|
- bash scripts/ci/run-mobile-csprng-instrumentation.sh apps/mobile-rn/android/app/build/outputs/apk/debug/app-debug.apk apps/mobile-rn/android/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk
|
|
- bash scripts/ci/run-mobile-emulator-gate.sh apps/mobile-rn/android/app/build/outputs/apk/e2e/app-e2e.apk
|
|
artifacts:
|
|
when: always
|
|
expire_in: 7 days
|
|
reports:
|
|
junit: apps/mobile-rn/.maestro/*.junit.xml
|
|
paths:
|
|
- apps/mobile-rn/.maestro/*.junit.xml
|
|
- apps/mobile-rn/.maestro-output/
|
|
rules:
|
|
- if: '$D3RO_ANDROID_EMULATOR_RUNNER == "true" && $CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
- if: '$D3RO_ANDROID_EMULATOR_RUNNER == "true" && ($CI_COMMIT_BRANCH == "main" || $CI_COMMIT_BRANCH == "develop")'
|
|
- if: '$D3RO_ANDROID_EMULATOR_RUNNER == "true" && $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
|
|
|
|
# ────────────────────────────────────────────────────────────────────
|
|
# Build Workspaces
|
|
# ────────────────────────────────────────────────────────────────────
|
|
build-workspaces:
|
|
stage: build
|
|
script:
|
|
- npm run build --workspace=@d3ro/desktop
|
|
- npm run build --workspace=@d3ro/admin
|
|
artifacts:
|
|
paths:
|
|
- apps/desktop/out/
|
|
- apps/admin/.next/
|
|
expire_in: 1 day
|
|
rules:
|
|
- if: '$CI_COMMIT_BRANCH == "main"'
|
|
- if: '$CI_COMMIT_TAG'
|
|
|
|
# ────────────────────────────────────────────────────────────────────
|
|
# Package Windows (Windows Runner)
|
|
# ────────────────────────────────────────────────────────────────────
|
|
package-windows:
|
|
stage: package
|
|
tags:
|
|
- build-win-x64
|
|
before_script:
|
|
- npm ci
|
|
script:
|
|
- node scripts/ci/sync-version.mjs --check --tag "$CI_COMMIT_TAG"
|
|
- npm run build --workspace=@d3ro/desktop
|
|
- cd apps/desktop
|
|
- npx electron-builder --win --x64 --config electron-builder.yml
|
|
artifacts:
|
|
name: "d3ro-voice-windows-$CI_COMMIT_TAG"
|
|
paths:
|
|
- apps/desktop/release/*/*.exe
|
|
- apps/desktop/release/*/*.blockmap
|
|
- apps/desktop/release/*/latest.yml
|
|
expire_in: 7 days
|
|
rules:
|
|
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+.*$/'
|
|
|
|
# ────────────────────────────────────────────────────────────────────
|
|
# Package macOS (macOS Runner)
|
|
# ────────────────────────────────────────────────────────────────────
|
|
package-macos:
|
|
stage: package
|
|
tags:
|
|
- build-mac-arm64
|
|
before_script:
|
|
- npm ci
|
|
script:
|
|
- node scripts/ci/sync-version.mjs --check --tag "$CI_COMMIT_TAG"
|
|
- npm run build --workspace=@d3ro/desktop
|
|
- cd apps/desktop
|
|
- npx electron-builder --mac --arm64 --config electron-builder.yml
|
|
artifacts:
|
|
name: "d3ro-voice-macos-$CI_COMMIT_TAG"
|
|
paths:
|
|
- apps/desktop/release/*/*.dmg
|
|
- apps/desktop/release/*/*.zip
|
|
- apps/desktop/release/*/*.blockmap
|
|
- apps/desktop/release/*/latest-mac.yml
|
|
expire_in: 7 days
|
|
rules:
|
|
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+.*$/'
|
|
|
|
# Protected, manually approved Play Console handoff. Configure the three
|
|
# *_FILE variables below as protected GitLab file variables scoped to the
|
|
# mobile-production-release environment. All other credentials must be
|
|
# protected, masked, and hidden project/group variables.
|
|
mobile-production-release:
|
|
stage: package
|
|
image: reactnativecommunity/react-native-android@sha256:24ca7ab5a70ec0b78a81bdc5eeea5924c2531531d53971b6f2321aff08446c36
|
|
needs:
|
|
- job: lint-and-typecheck
|
|
artifacts: false
|
|
- job: test-unit
|
|
artifacts: false
|
|
- job: api-server-tests
|
|
artifacts: false
|
|
- job: edge-functions-quality
|
|
artifacts: false
|
|
- job: mobile-quality
|
|
artifacts: false
|
|
- job: mobile-android
|
|
artifacts: false
|
|
- job: mobile-emulator-e2e
|
|
artifacts: false
|
|
environment:
|
|
name: mobile-production-release
|
|
action: prepare
|
|
before_script: []
|
|
script:
|
|
- |
|
|
set -euo pipefail
|
|
export ANDROID_HOME=/opt/android
|
|
export ANDROID_SDK_ROOT=/opt/android
|
|
curl -fsSL "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz" -o /tmp/node.tar.xz
|
|
echo '14b342e71204f811bde6153be8e04b62aef63c236fef92b55f9c83154b409647 /tmp/node.tar.xz' | sha256sum -c -
|
|
mkdir -p /tmp/node24
|
|
tar -xJf /tmp/node.tar.xz -C /tmp/node24 --strip-components=1
|
|
export PATH="/tmp/node24/bin:$PATH"
|
|
node --version | grep -Fx "v${NODE_VERSION}"
|
|
git fetch --no-tags origin main
|
|
git merge-base --is-ancestor "$CI_COMMIT_SHA" origin/main
|
|
test "$CI_COMMIT_SHA" = "$(git rev-parse HEAD)"
|
|
test -z "$(git status --porcelain --untracked-files=all)"
|
|
SOURCE_TREE_SHA="$(git rev-parse "${CI_COMMIT_SHA}^{tree}")"
|
|
VERSION_NAME="$(node -p "require('./release/product-version.json').version")"
|
|
VERSION_CODE="$(node -p "require('./release/product-version.json').androidVersionCode")"
|
|
ANDROID_UPLOAD_CERT_SHA256="$(node -p "require('./release/android-release-identity.json').uploadCertificateSha256")"
|
|
ADMOB_APP_ID="$(node -p "require('./release/android-release-identity.json').adMobAppId")"
|
|
ADMOB_BANNER_UNIT_ID="$(node -p "require('./release/android-release-identity.json').adMobBannerUnitId")"
|
|
ADMOB_REWARDED_UNIT_ID="$(node -p "require('./release/android-release-identity.json').adMobRewardedUnitId")"
|
|
test "$CI_COMMIT_TAG" = "v${VERSION_NAME}"
|
|
echo "$VERSION_NAME" | grep -Eq '^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'
|
|
echo "$VERSION_CODE" | grep -Eq '^[1-9][0-9]{0,9}$'
|
|
test "$VERSION_CODE" -le 2100000000
|
|
test -s "$ANDROID_RELEASE_KEYSTORE_FILE"
|
|
test -s "$ANDROID_GOOGLE_SERVICES_JSON_FILE"
|
|
test -s "$ANDROID_RELEASE_EVIDENCE_PRIVATE_KEY_FILE"
|
|
install -m 600 "$ANDROID_RELEASE_KEYSTORE_FILE" apps/mobile-rn/android/app/release.keystore
|
|
install -m 600 "$ANDROID_GOOGLE_SERVICES_JSON_FILE" apps/mobile-rn/android/app/google-services.json
|
|
install -m 600 "$ANDROID_RELEASE_EVIDENCE_PRIVATE_KEY_FILE" apps/mobile-rn/android/app/release-evidence-private.pem
|
|
test -n "$ANDROID_RELEASE_STORE_PASSWORD"
|
|
test -n "$ANDROID_RELEASE_KEY_ALIAS"
|
|
test -n "$ANDROID_RELEASE_KEY_PASSWORD"
|
|
test -n "$D3RO_FIREBASE_EXPECTED_PROJECT_ID"
|
|
test -n "$D3RO_FIREBASE_EXPECTED_PROJECT_NUMBER"
|
|
test -n "$D3RO_FIREBASE_EXPECTED_MOBILESDK_APP_ID"
|
|
sdkmanager "platforms;android-36" "build-tools;36.0.0" >/dev/null
|
|
npm ci
|
|
npm --prefix apps/mobile-rn ci --workspaces=false
|
|
npm run security:secrets:test
|
|
npm run security:secrets
|
|
npm run release:mobile:boundary:test
|
|
npm run release:mobile:config:test
|
|
npm run release:mobile:build-config:test
|
|
npm run release:play:assets
|
|
npm --prefix apps/mobile-rn run lint
|
|
npm --prefix apps/mobile-rn run typecheck
|
|
npm --prefix apps/mobile-rn run test:ci
|
|
node scripts/ci/prepare-whisper-model.mjs
|
|
curl --fail --silent --show-error --location --output /tmp/bundletool.jar https://github.com/google/bundletool/releases/download/1.18.3/bundletool-all-1.18.3.jar
|
|
echo 'a099cfa1543f55593bc2ed16a70a7c67fe54b1747bb7301f37fdfd6d91028e29 /tmp/bundletool.jar' | sha256sum -c -
|
|
export D3RO_RELEASE_STORE_FILE="$CI_PROJECT_DIR/apps/mobile-rn/android/app/release.keystore"
|
|
export D3RO_RELEASE_STORE_PASSWORD="$ANDROID_RELEASE_STORE_PASSWORD"
|
|
export D3RO_RELEASE_KEY_ALIAS="$ANDROID_RELEASE_KEY_ALIAS"
|
|
export D3RO_RELEASE_KEY_PASSWORD="$ANDROID_RELEASE_KEY_PASSWORD"
|
|
export D3RO_ADMOB_APP_ID="$ADMOB_APP_ID"
|
|
export D3RO_ADMOB_BANNER_UNIT_ID="$ADMOB_BANNER_UNIT_ID"
|
|
export D3RO_ADMOB_REWARDED_UNIT_ID="$ADMOB_REWARDED_UNIT_ID"
|
|
export D3RO_VERSION_NAME="$VERSION_NAME"
|
|
export D3RO_VERSION_CODE="$VERSION_CODE"
|
|
PLAY_APP_SIGNING_CERT_SHA256="$(node -p "require('./release/android-release-identity.json').playAppSigningCertificateSha256")"
|
|
npm run release:mobile:config
|
|
cd apps/mobile-rn/android
|
|
./gradlew :app:assembleRelease :app:bundleRelease -PreactNativeArchitectures=arm64-v8a --no-daemon
|
|
cd "$CI_PROJECT_DIR"
|
|
APK=apps/mobile-rn/android/app/build/outputs/apk/release/app-release.apk
|
|
AAB=apps/mobile-rn/android/app/build/outputs/bundle/release/app-release.aab
|
|
test -f "$APK"
|
|
test -f "$AAB"
|
|
node scripts/ci/verify-mobile-build-config.mjs release > apps/mobile-rn/android/app/build/outputs/release-build-config.json
|
|
node scripts/ci/create-mobile-release-evidence.mjs \
|
|
--apk "$APK" \
|
|
--aab "$AAB" \
|
|
--bundletool /tmp/bundletool.jar \
|
|
--repository "$CI_PROJECT_PATH" \
|
|
--commit-sha "$CI_COMMIT_SHA" \
|
|
--tree-sha "$SOURCE_TREE_SHA" \
|
|
--git-ref "refs/tags/$CI_COMMIT_TAG" \
|
|
--workflow-identity "gitlab-ci/mobile-production-release" \
|
|
--run-id "$CI_JOB_ID" \
|
|
--run-attempt "1" \
|
|
--runner-identity "$CI_RUNNER_ID:$CI_RUNNER_REVISION" \
|
|
--expected-admob-app-id "$D3RO_ADMOB_APP_ID" \
|
|
--expected-upload-cert-sha256 "$ANDROID_UPLOAD_CERT_SHA256" \
|
|
--expected-version-name "$D3RO_VERSION_NAME" \
|
|
--expected-version-code "$D3RO_VERSION_CODE" \
|
|
--private-key apps/mobile-rn/android/app/release-evidence-private.pem \
|
|
--snapshot-dir apps/mobile-rn/android/app/build/outputs/release-snapshot
|
|
VERIFIER_SHA256="$(sha256sum scripts/ci/verify-android-artifact.mjs | awk '{print $1}')"
|
|
BUNDLETOOL_SHA256="a099cfa1543f55593bc2ed16a70a7c67fe54b1747bb7301f37fdfd6d91028e29"
|
|
node scripts/ci/prepare-mobile-release-publication.mjs \
|
|
--source-root apps/mobile-rn/android/app/build/outputs/release-snapshot \
|
|
--apk apps/mobile-rn/android/app/build/outputs/release-snapshot/app-release.apk \
|
|
--aab apps/mobile-rn/android/app/build/outputs/release-snapshot/app-release.aab \
|
|
--evidence apps/mobile-rn/android/app/build/outputs/release-snapshot/release-artifact-evidence.json \
|
|
--public-key release/mobile-release-evidence-public.pem \
|
|
--destination-dir apps/mobile-rn/android/app/build/outputs/release-publication \
|
|
--expected-admob-app-id "$D3RO_ADMOB_APP_ID" \
|
|
--expected-upload-cert-sha256 "$ANDROID_UPLOAD_CERT_SHA256" \
|
|
--expected-version-name "$D3RO_VERSION_NAME" \
|
|
--expected-version-code "$D3RO_VERSION_CODE" \
|
|
--expected-repository "$CI_PROJECT_PATH" \
|
|
--expected-commit-sha "$CI_COMMIT_SHA" \
|
|
--expected-tree-sha "$SOURCE_TREE_SHA" \
|
|
--expected-git-ref "refs/tags/$CI_COMMIT_TAG" \
|
|
--expected-workflow-identity "gitlab-ci/mobile-production-release" \
|
|
--expected-run-id "$CI_JOB_ID" \
|
|
--expected-run-attempt "1" \
|
|
--expected-runner-identity "$CI_RUNNER_ID:$CI_RUNNER_REVISION" \
|
|
--expected-verifier-sha256 "$VERIFIER_SHA256" \
|
|
--expected-bundletool-sha256 "$BUNDLETOOL_SHA256"
|
|
node scripts/ci/verify-android-app-links.mjs \
|
|
--expected-play-app-signing-cert-sha256 "$PLAY_APP_SIGNING_CERT_SHA256" \
|
|
--forbidden-upload-cert-sha256 "$ANDROID_UPLOAD_CERT_SHA256" \
|
|
> apps/mobile-rn/android/app/build/outputs/release-app-links-evidence.json
|
|
sha256sum \
|
|
apps/mobile-rn/android/app/build/outputs/release-publication/app-release.apk \
|
|
apps/mobile-rn/android/app/build/outputs/release-publication/app-release.aab \
|
|
> apps/mobile-rn/android/app/build/outputs/release-publication/SHA256SUMS.txt
|
|
after_script:
|
|
- rm -f apps/mobile-rn/android/app/release.keystore apps/mobile-rn/android/app/google-services.json apps/mobile-rn/android/app/release-evidence-private.pem
|
|
artifacts:
|
|
access: maintainer
|
|
expire_in: 7 days
|
|
paths:
|
|
- apps/mobile-rn/android/app/build/outputs/release-publication/app-release.aab
|
|
- apps/mobile-rn/android/app/build/outputs/release-publication/android-release-evidence.json
|
|
- apps/mobile-rn/android/app/build/outputs/release-publication/android-publication-manifest.json
|
|
- apps/mobile-rn/android/app/build/outputs/release-publication/SHA256SUMS.txt
|
|
- apps/mobile-rn/android/app/build/outputs/release-snapshot/release-artifact-verification.json
|
|
- apps/mobile-rn/android/app/build/outputs/release-build-config.json
|
|
- apps/mobile-rn/android/app/build/outputs/release-app-links-evidence.json
|
|
manual_confirmation: '검증된 production AAB를 생성해 Maintainer 전용 Play Console handoff로 보낼까요?'
|
|
rules:
|
|
- if: '$D3RO_MOBILE_PRODUCTION_RELEASE_ENABLED == "true" && $D3RO_ANDROID_EMULATOR_RUNNER == "true" && $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
|
|
when: manual
|
|
allow_failure: false
|
|
- when: never
|
|
|
|
# ────────────────────────────────────────────────────────────────────
|
|
# Publish Release (GitLab Package Registry + Release Page)
|
|
# ────────────────────────────────────────────────────────────────────
|
|
publish-release:
|
|
stage: publish
|
|
image: node:24.19.0-bookworm
|
|
needs:
|
|
- job: package-windows
|
|
artifacts: true
|
|
- job: package-macos
|
|
artifacts: true
|
|
optional: true
|
|
- job: mobile-production-release
|
|
artifacts: false
|
|
optional: true
|
|
script:
|
|
- node scripts/ci/publish-gitlab-release.mjs
|
|
rules:
|
|
- if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+.*$/'
|
|
|
|
# ────────────────────────────────────────────────────────────────────
|
|
# Admin NAS deployment remains disabled until an immutable image, authenticated
|
|
# remote target, health check, and rollback path are configured. Do not revive
|
|
# the former DinD job: it only changed an ephemeral CI daemon and referenced a
|
|
# non-existent compose file, so it never deployed the NAS.
|
|
# ────────────────────────────────────────────────────────────────────
|