diff --git a/.gitea/workflows/backup.yml b/.gitea/workflows/backup.yml index 3756baf..fc4dbb9 100644 --- a/.gitea/workflows/backup.yml +++ b/.gitea/workflows/backup.yml @@ -1,8 +1,9 @@ name: DB Backup on: - schedule: - - cron: '0 18 * * *' # UTC 18:00 = 北京时间 02:00 + # 定时备份已暂停(保留手动触发)。恢复时取消下面 schedule 的注释即可。 + # schedule: + # - cron: '0 18 * * *' # UTC 18:00 = 北京时间 02:00 workflow_dispatch: jobs: diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml deleted file mode 100644 index 61b939a..0000000 --- a/.gitea/workflows/ci.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: CI - -on: - push: - branches-ignore: [main] - pull_request: - -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-go@v5 - with: - go-version-file: backend/go.mod - cache-dependency-path: backend/go.sum - - - name: Go tests - working-directory: backend - run: go test ./... - - - uses: subosito/flutter-action@v2 - with: - channel: stable - cache: true - - - name: Flutter tests - working-directory: client - run: flutter test diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 9b72015..ded42af 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -16,6 +16,9 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Provision (idempotent — auto-runs if host not initialized) + run: sh scripts/ci/provision-mac.sh + - name: Compile (Linux backend + Flutter Web) run: sh scripts/ci/compile.sh "${{ gitea.ref_name }}" @@ -26,6 +29,9 @@ jobs: path: dist/ build-macos: + # Same physical runner as build-linux-web (label: mac, capacity 1). Run them + # serially via needs so the second job doesn't sit queued and time out. + needs: build-linux-web runs-on: mac env: PUB_HOSTED_URL: https://pub.flutter-io.cn @@ -34,6 +40,9 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Provision (idempotent — auto-runs if host not initialized) + run: sh scripts/ci/provision-mac.sh + - name: Compile (Flutter macOS) run: sh scripts/ci/compile-macos.sh "${{ gitea.ref_name }}" @@ -53,6 +62,10 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Provision (idempotent — auto-runs if host not initialized) + shell: bash + run: sh scripts/ci/provision-windows.sh + - name: Compile (Flutter Windows) shell: bash run: sh scripts/ci/compile-windows.sh "${{ gitea.ref_name }}" diff --git a/CHANGELOG.md b/CHANGELOG.md index 852ad52..54cc96f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.6] - 2026-06-03 + +### 改进 +- CI 运行环境自愈预置:mac/windows runner 首次构建自动 `flutter precache` 并预热 pub/go/npm 缓存(stamp 文件按 Flutter 版本短路),后续构建不再运行时下载 engine +- 发版流水线同一 mac runner 上的任务改为串行(build-macos 依赖 build-linux-web),避免排队等待超时失败 +- 暂停定时数据库备份(保留手动触发) + ## [1.0.5] - 2026-06-03 ### 修复 diff --git a/scripts/ci/_env.sh b/scripts/ci/_env.sh new file mode 100644 index 0000000..f7b9208 --- /dev/null +++ b/scripts/ci/_env.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# _env.sh — shared CI mirror env. `source` this from other scripts. +# Idempotent: only sets vars if not already provided by the environment. + +export GOPROXY="${GOPROXY:-https://goproxy.cn,direct}" +export PUB_HOSTED_URL="${PUB_HOSTED_URL:-https://pub.flutter-io.cn}" +export FLUTTER_STORAGE_BASE_URL="${FLUTTER_STORAGE_BASE_URL:-https://storage.flutter-io.cn}" + +# Ensure Homebrew tools are on PATH (macOS runners); harmless elsewhere. +case ":${PATH}:" in + *":/opt/homebrew/bin:"*) ;; + *) export PATH="/opt/homebrew/bin:${PATH}" ;; +esac diff --git a/scripts/ci/compile-macos.sh b/scripts/ci/compile-macos.sh index b7cc1bf..ca42b11 100755 --- a/scripts/ci/compile-macos.sh +++ b/scripts/ci/compile-macos.sh @@ -2,9 +2,8 @@ # compile-macos.sh — build Flutter macOS desktop, package into dist/ set -euo pipefail -export GOPROXY="${GOPROXY:-https://goproxy.cn,direct}" -export PUB_HOSTED_URL="${PUB_HOSTED_URL:-https://pub.flutter-io.cn}" -export FLUTTER_STORAGE_BASE_URL="${FLUTTER_STORAGE_BASE_URL:-https://storage.flutter-io.cn}" +# shellcheck source=scripts/ci/_env.sh +. "$(dirname "$0")/_env.sh" TAG="$1" VER="${TAG#v}" diff --git a/scripts/ci/compile-windows.sh b/scripts/ci/compile-windows.sh index d1b4768..66e2078 100755 --- a/scripts/ci/compile-windows.sh +++ b/scripts/ci/compile-windows.sh @@ -2,9 +2,8 @@ # compile-windows.sh — build Flutter Windows desktop, package into dist/ set -euo pipefail -export GOPROXY="${GOPROXY:-https://goproxy.cn,direct}" -export PUB_HOSTED_URL="${PUB_HOSTED_URL:-https://pub.flutter-io.cn}" -export FLUTTER_STORAGE_BASE_URL="${FLUTTER_STORAGE_BASE_URL:-https://storage.flutter-io.cn}" +# shellcheck source=scripts/ci/_env.sh +. "$(dirname "$0")/_env.sh" TAG="$1" VER="${TAG#v}" diff --git a/scripts/ci/compile.sh b/scripts/ci/compile.sh index 3ad87e5..8355884 100755 --- a/scripts/ci/compile.sh +++ b/scripts/ci/compile.sh @@ -2,10 +2,8 @@ # compile.sh — build backend + Flutter web, package into dist/ set -euo pipefail -export PATH="/opt/homebrew/bin:$PATH" -export GOPROXY="${GOPROXY:-https://goproxy.cn,direct}" -export PUB_HOSTED_URL="${PUB_HOSTED_URL:-https://pub.flutter-io.cn}" -export FLUTTER_STORAGE_BASE_URL="${FLUTTER_STORAGE_BASE_URL:-https://storage.flutter-io.cn}" +# shellcheck source=scripts/ci/_env.sh +. "$(dirname "$0")/_env.sh" TAG="$1" VER="${TAG#v}" diff --git a/scripts/ci/provision-mac.sh b/scripts/ci/provision-mac.sh new file mode 100644 index 0000000..9d1284a --- /dev/null +++ b/scripts/ci/provision-mac.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# provision-mac.sh — idempotent provisioning for the macOS host runner. +# +# Pre-warms everything the build jobs (compile.sh / compile-macos.sh) would +# otherwise download at runtime: Flutter macOS+web engine artifacts, pub +# packages, Go modules, npm deps. Safe to run on every pipeline run — it +# short-circuits via a stamp file keyed to the installed Flutter version, so +# once provisioned it returns in milliseconds and downloads nothing. +set -euo pipefail + +SCRIPT_DIR="$(dirname "$0")" +# shellcheck source=scripts/ci/_env.sh +. "${SCRIPT_DIR}/_env.sh" + +STAMP_DIR="${HOME}/.cache/jiu-ci" +STAMP="${STAMP_DIR}/provisioned-mac" +CUR="${STAMP_DIR}/.flutter-version-mac.cur" +mkdir -p "$STAMP_DIR" + +# --- detection: skip if already provisioned for this Flutter version --- +if ! command -v flutter >/dev/null 2>&1; then + echo "ERROR: flutter not found on PATH. Install Flutter on this runner first." >&2 + exit 1 +fi +flutter --version --machine > "$CUR" 2>/dev/null || flutter --version > "$CUR" 2>&1 || true + +if [ -s "$STAMP" ] && cmp -s "$STAMP" "$CUR"; then + echo "==> provision-mac: already provisioned (Flutter unchanged), skipping." + exit 0 +fi + +echo "==> provision-mac: not provisioned (or Flutter changed) — running." + +# --- toolchain presence (do not auto-install system-level tools) --- +for tool in go node npm; do + if ! command -v "$tool" >/dev/null 2>&1; then + echo "ERROR: '$tool' not found on PATH. Install it on this runner first." >&2 + exit 1 + fi +done + +# --- warm Flutter platform engines (the macOS SDK download seen in CI) --- +echo "==> precache Flutter engines (macos, web)" +flutter precache --macos --web --universal + +# --- warm dependency caches --- +echo "==> flutter pub get (client)" +(cd "${SCRIPT_DIR}/../../client" && flutter pub get) + +echo "==> go mod download (backend)" +(cd "${SCRIPT_DIR}/../../backend" && go mod download) + +echo "==> npm ci (web)" +(cd "${SCRIPT_DIR}/../../web" && npm ci --prefer-offline) + +# --- mark provisioned --- +cp "$CUR" "$STAMP" +echo "==> provision-mac: done." +echo "--- versions ---" +flutter --version | head -1 +go version +node --version diff --git a/scripts/ci/provision-windows.sh b/scripts/ci/provision-windows.sh new file mode 100644 index 0000000..af861cf --- /dev/null +++ b/scripts/ci/provision-windows.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# provision-windows.sh — idempotent provisioning for the Windows host runner. +# +# Pre-warms what compile-windows.sh would download at runtime: Flutter Windows +# engine artifacts and pub packages. Short-circuits via a stamp file keyed to +# the installed Flutter version, so repeat runs return immediately. +set -euo pipefail + +SCRIPT_DIR="$(dirname "$0")" +# shellcheck source=scripts/ci/_env.sh +. "${SCRIPT_DIR}/_env.sh" + +STAMP_DIR="${HOME}/.cache/jiu-ci" +STAMP="${STAMP_DIR}/provisioned-windows" +CUR="${STAMP_DIR}/.flutter-version-win.cur" +mkdir -p "$STAMP_DIR" + +# --- detection --- +if ! command -v flutter >/dev/null 2>&1; then + echo "ERROR: flutter not found on PATH. Install Flutter on this runner first." >&2 + exit 1 +fi +flutter --version --machine > "$CUR" 2>/dev/null || flutter --version > "$CUR" 2>&1 || true + +if [ -s "$STAMP" ] && cmp -s "$STAMP" "$CUR"; then + echo "==> provision-windows: already provisioned (Flutter unchanged), skipping." + exit 0 +fi + +echo "==> provision-windows: not provisioned (or Flutter changed) — running." + +# --- warm Flutter Windows engine + pub deps --- +echo "==> precache Flutter engine (windows)" +flutter precache --windows + +echo "==> flutter pub get (client)" +(cd "${SCRIPT_DIR}/../../client" && flutter pub get) + +# --- mark provisioned --- +cp "$CUR" "$STAMP" +echo "==> provision-windows: done." +flutter --version | head -1