# CI 门禁。来源:conti-docs/14-conventions-and-ci-gates.md + 08-build-flavors.md # # --------------------------------------------------------------------------- # 门禁的立法目的(14 §一):**约定只有被机器强制才叫约定**。下面每一条都对应 # 一条人工评审记不住、也不该由人来记的规则。 # # TODO(ops): 镜像名和 mac runner 的 tag 都是占位符,两项文档自己就列为待确认: # - Flutter 镜像:需要一个预装 Flutter 3.44.9 的内网镜像(公网 ghcr 拉不动) # - iOS 构建:需要一台 mac runner,目前团队没有 # --------------------------------------------------------------------------- stages: - verify - test - build default: image: $FLUTTER_IMAGE # TODO(ops): 形如 registry.internal/flutter:3.44.9 tags: - docker before_script: - dart pub global activate melos 8.2.2 - export PATH="$PATH:$HOME/.pub-cache/bin" - melos bootstrap variables: # 产物不入库,每一步 CI 都得自己生成一遍(14 §四)。 PUB_CACHE: "$CI_PROJECT_DIR/.pub-cache" cache: key: files: - pubspec.lock paths: - .pub-cache # --------------------------------------------------------------------------- # verify:不跑测试就能发现的问题,全部拦在这里,因为它最快 # --------------------------------------------------------------------------- format: stage: verify script: - melos run format # 格式化不是审美问题:不统一的话每个 PR 的 diff 里都混着大段无关的换行改动, # 评审会开始跳过 diff。 analyze: stage: verify script: - melos run gen - melos run analyze # --fatal-infos 在 melos 脚本里。不加等于 lint 形同虚设——绝大部分 riverpod_lint # 规则报的是 info 级别。 pigeon-consistency: stage: verify script: - melos run gen:pigeon # Pigeon 产物是入库的。改了 pigeons/*.dart 却忘了重新生成,是一个编译期 # 完全看不出来、运行时才炸 MissingPluginException 的经典事故。 - git diff --exit-code || (echo "Pigeon 产物与 pigeons/ 不一致,请本地跑 melos run gen:pigeon 后提交" && exit 1) # --------------------------------------------------------------------------- # test # --------------------------------------------------------------------------- unit-test: stage: test script: - melos run gen - melos run test coverage: '/lines\.*: \d+\.\d+\%/' artifacts: when: always paths: - packages/*/coverage/lcov.info expire_in: 1 week # 覆盖率门禁单独一个 job:它会失败得比较频繁,混在 unit-test 里会让人分不清 # 是"测试挂了"还是"覆盖率不够"。 coverage-gate: stage: test needs: [unit-test] allow_failure: true # TODO: 骨架期先不卡人,等业务代码进来再改成 false script: - dart pub global activate coverde - melos run coverage # --------------------------------------------------------------------------- # build:dev/uat 按分支出包,prod 只认 tag # --------------------------------------------------------------------------- .android-build: &android-build stage: build script: - melos run gen - cd app - > flutter build apk --flavor $FLAVOR -t lib/main_$FLAVOR.dart --dart-define-from-file=env/$FLAVOR.json $EXTRA_ARGS artifacts: paths: - app/build/app/outputs/flutter-apk/*.apk expire_in: 1 month android-dev: <<: *android-build variables: FLAVOR: dev rules: - if: $CI_COMMIT_BRANCH == "develop" android-uat: <<: *android-build variables: FLAVOR: uat rules: - if: $CI_COMMIT_BRANCH == "main" android-prod: <<: *android-build variables: FLAVOR: prod # release 包必须混淆 + 拆符号表,否则 Sentry 上的堆栈是一堆十六进制地址。 # --split-debug-info 的产物要留着,sentry_dart_plugin 靠它还原堆栈。 EXTRA_ARGS: --release --obfuscate --split-debug-info=build/symbols after_script: # SENTRY_AUTH_TOKEN 只从 CI 变量读,仓库里任何文件都不许出现它。 - cd app && dart run sentry_dart_plugin artifacts: paths: - app/build/app/outputs/flutter-apk/*.apk - app/build/symbols expire_in: 1 year rules: - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/ # TODO(ops): iOS 构建需要 mac runner。配置步骤见 app/ios/FLAVORS.md, # 在 Scheme 建好并进 git 之前,这个 job 加了也跑不通。