app scaffold

This commit is contained in:
Guangfei.Zhao
2026-08-17 15:29:55 +08:00
commit 681688dfae
301 changed files with 18414 additions and 0 deletions
+140
View File
@@ -0,0 +1,140 @@
# 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
# ---------------------------------------------------------------------------
# builddev/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 加了也跑不通。