diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml index 73909eb..78722ea 100644 --- a/.github/workflows/dev-build.yml +++ b/.github/workflows/dev-build.yml @@ -71,6 +71,7 @@ jobs: has_changes: ${{ steps.detect.outputs.has_changes }} release_source: ${{ steps.detect.outputs.release_source }} compare_base: ${{ steps.detect.outputs.compare_base }} + force_global_driver_builds: ${{ steps.detect.outputs.force_global_driver_builds }} source_commit: ${{ steps.published_source.outputs.source_commit }} has_manifest: ${{ steps.published_source.outputs.has_manifest }} steps: @@ -184,8 +185,10 @@ jobs: DRIVERS="$(merge_csv "$DRIVERS" "$REVISION_DRIVERS")" fi fi + FORCE_GLOBAL_DRIVER_BUILDS="$(bash ./tools/should-force-global-driver-builds.sh --base "$BASE_REF" --head "$GITHUB_SHA")" echo "drivers=${DRIVERS}" >> "$GITHUB_OUTPUT" echo "compare_base=${BASE_REF}" >> "$GITHUB_OUTPUT" + echo "force_global_driver_builds=${FORCE_GLOBAL_DRIVER_BUILDS}" >> "$GITHUB_OUTPUT" if [ -n "$DRIVERS" ]; then echo "has_changes=true" >> "$GITHUB_OUTPUT" echo "🧭 Changed driver agents: $DRIVERS" @@ -193,6 +196,9 @@ jobs: echo "has_changes=false" >> "$GITHUB_OUTPUT" echo "🧭 No driver-agent changes detected" fi + if [[ "$FORCE_GLOBAL_DRIVER_BUILDS" == "true" ]]; then + echo "🧭 Driver build/release plumbing changed; preserve global driver rebuild set on every platform" + fi echo "release_source=dev-latest" >> "$GITHUB_OUTPUT" build: @@ -452,9 +458,14 @@ jobs: set -euo pipefail BASE_REF="${{ needs.driver_agents.outputs.compare_base }}" FALLBACK_DRIVERS="${{ needs.driver_agents.outputs.drivers }}" + FORCE_GLOBAL_DRIVER_BUILDS="${{ needs.driver_agents.outputs.force_global_driver_builds }}" - if [[ -z "$BASE_REF" || "$BASE_REF" == "all" ]]; then - echo "⚠️ 当前 driver 检测基线不可做平台 diff,回退使用全局检测结果:${FALLBACK_DRIVERS}" + if [[ -z "$BASE_REF" || "$BASE_REF" == "all" || "$FORCE_GLOBAL_DRIVER_BUILDS" == "true" ]]; then + if [[ "$FORCE_GLOBAL_DRIVER_BUILDS" == "true" && -n "$BASE_REF" && "$BASE_REF" != "all" ]]; then + echo "⚠️ 当前提交涉及 driver 构建/发布链路,保留全局驱动重建结果:${FALLBACK_DRIVERS}" + else + echo "⚠️ 当前 driver 检测基线不可做平台 diff,回退使用全局检测结果:${FALLBACK_DRIVERS}" + fi echo "drivers=${FALLBACK_DRIVERS}" >> "$GITHUB_OUTPUT" else echo "🧭 对比当前平台 revision:base=${BASE_REF} head=${GITHUB_SHA} platform=${{ matrix.platform }}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 21f1605..288709e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -67,6 +67,7 @@ jobs: has_changes: ${{ steps.detect.outputs.has_changes }} release_source: ${{ steps.detect.outputs.release_source }} compare_base: ${{ steps.detect.outputs.compare_base }} + force_global_driver_builds: ${{ steps.detect.outputs.force_global_driver_builds }} published_source_commit: ${{ steps.published_source.outputs.source_commit }} has_manifest: ${{ steps.published_source.outputs.has_manifest }} manifest_valid: ${{ steps.published_source.outputs.manifest_valid }} @@ -185,9 +186,11 @@ jobs: DRIVERS="$(merge_csv "$DRIVERS" "$REVISION_DRIVERS")" fi fi + FORCE_GLOBAL_DRIVER_BUILDS="$(bash ./tools/should-force-global-driver-builds.sh --base "$BASE_REF" --head "$GITHUB_SHA")" echo "drivers=${DRIVERS}" >> "$GITHUB_OUTPUT" echo "release_source=${RELEASE_SOURCE}" >> "$GITHUB_OUTPUT" echo "compare_base=${BASE_REF}" >> "$GITHUB_OUTPUT" + echo "force_global_driver_builds=${FORCE_GLOBAL_DRIVER_BUILDS}" >> "$GITHUB_OUTPUT" if [ -n "$DRIVERS" ]; then echo "has_changes=true" >> "$GITHUB_OUTPUT" echo "🧭 Changed driver agents since ${BASE_REF}: $DRIVERS" @@ -195,6 +198,9 @@ jobs: echo "has_changes=false" >> "$GITHUB_OUTPUT" echo "🧭 No driver-agent changes since ${BASE_REF}" fi + if [[ "$FORCE_GLOBAL_DRIVER_BUILDS" == "true" ]]; then + echo "🧭 Driver build/release plumbing changed; preserve global driver rebuild set on every platform" + fi # Phase 1: Build in parallel and output artifacts build: @@ -450,9 +456,14 @@ jobs: set -euo pipefail BASE_REF="${{ needs.driver_agents.outputs.compare_base }}" FALLBACK_DRIVERS="${{ needs.driver_agents.outputs.drivers }}" + FORCE_GLOBAL_DRIVER_BUILDS="${{ needs.driver_agents.outputs.force_global_driver_builds }}" - if [[ -z "$BASE_REF" || "$BASE_REF" == "all" ]]; then - echo "⚠️ 未拿到可比对的历史 release 基线,回退使用全局检测结果:${FALLBACK_DRIVERS}" + if [[ -z "$BASE_REF" || "$BASE_REF" == "all" || "$FORCE_GLOBAL_DRIVER_BUILDS" == "true" ]]; then + if [[ "$FORCE_GLOBAL_DRIVER_BUILDS" == "true" && -n "$BASE_REF" && "$BASE_REF" != "all" ]]; then + echo "⚠️ 当前提交涉及 driver 构建/发布链路,保留全局驱动重建结果:${FALLBACK_DRIVERS}" + else + echo "⚠️ 未拿到可比对的历史 release 基线,回退使用全局检测结果:${FALLBACK_DRIVERS}" + fi echo "drivers=${FALLBACK_DRIVERS}" >> "$GITHUB_OUTPUT" else echo "🧭 对比当前平台 revision:base=${BASE_REF} head=${GITHUB_SHA} platform=${{ matrix.platform }}" diff --git a/tools/detect-changed-driver-agents.sh b/tools/detect-changed-driver-agents.sh index 4b62277..a01fcea 100644 --- a/tools/detect-changed-driver-agents.sh +++ b/tools/detect-changed-driver-agents.sh @@ -514,8 +514,14 @@ for file in "${!changed_file_set[@]}"; do fi add_forced_drivers_from_tokens "$shared_delta" ;; - tools/compress-driver-artifact.sh) - echo "检测到 driver-agent 压缩脚本变更;保守构建全部 driver-agent:$file" >&2 + tools/compress-driver-artifact.sh|\ + tools/package-driver-release-assets.py|\ + tools/generate-driver-release-manifest.py|\ + tools/complete-driver-release-assets.py|\ + tools/resolve-driver-release-source.py|\ + tools/validate-driver-release-manifest.sh|\ + tools/should-force-global-driver-builds.sh) + echo "检测到 driver-agent 构建/发布链路脚本变更;保守构建全部 driver-agent:$file" >&2 all_drivers_csv exit 0 ;; diff --git a/tools/detect-changed-driver-agents.test.sh b/tools/detect-changed-driver-agents.test.sh index 456d432..d4c9d96 100755 --- a/tools/detect-changed-driver-agents.test.sh +++ b/tools/detect-changed-driver-agents.test.sh @@ -139,4 +139,29 @@ YAMLEOF fi ) +tmpdir_packaging="$(mktemp -d "${TMPDIR:-/tmp}/gonavi-detect-packaging-change.XXXXXX")" +git init -q "$tmpdir_packaging" +mkdir -p "$tmpdir_packaging/tools" +cp tools/detect-changed-driver-agents.sh "$tmpdir_packaging/tools/detect-changed-driver-agents.sh" +cat >"$tmpdir_packaging/tools/package-driver-release-assets.py" <<'PYEOF' +print("package") +PYEOF + +( + cd "$tmpdir_packaging" + git add . + git -c user.name=GoNavi -c user.email=gonavi@example.test commit -q -m initial + base="$(git rev-parse HEAD)" + + printf '\nprint("changed")\n' >> tools/package-driver-release-assets.py + git add tools/package-driver-release-assets.py + git -c user.name=GoNavi -c user.email=gonavi@example.test commit -q -m 'update packaging script' + + actual="$(bash ./tools/detect-changed-driver-agents.sh --base "$base" --head HEAD 2>/dev/null)" + if [[ "$actual" != *"mariadb"* || "$actual" != *"clickhouse"* || "$actual" != *"duckdb"* || "$actual" != *"elasticsearch"* ]]; then + echo "expected packaging script change to trigger all driver builds, got: ${actual:-}" >&2 + exit 1 + fi +) + echo "detect-changed-driver-agents revision test passed" diff --git a/tools/should-force-global-driver-builds.sh b/tools/should-force-global-driver-builds.sh new file mode 100755 index 0000000..72d85fe --- /dev/null +++ b/tools/should-force-global-driver-builds.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$SCRIPT_DIR" + +usage() { + cat <<'EOF' +用法: + ./tools/should-force-global-driver-builds.sh --base --head + +输出: + true 表示本次变更涉及 driver 构建/发布链路,平台构建阶段必须保留全局驱动重建结果 + false 表示可继续按平台 revision diff 缩小重建范围 +EOF +} + +base_ref="" +head_ref="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --base) + base_ref="${2:-}" + shift 2 + ;; + --head) + head_ref="${2:-}" + shift 2 + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "未知参数:$1" >&2 + usage >&2 + exit 1 + ;; + esac +done + +if [[ -z "$base_ref" || -z "$head_ref" ]]; then + usage >&2 + exit 1 +fi + +if [[ "$base_ref" == "all" ]]; then + echo "true" + exit 0 +fi + +if ! git rev-parse --verify "${base_ref}^{commit}" >/dev/null 2>&1; then + echo "无法解析 base ref:$base_ref" >&2 + exit 1 +fi +if ! git rev-parse --verify "${head_ref}^{commit}" >/dev/null 2>&1; then + echo "无法解析 head ref:$head_ref" >&2 + exit 1 +fi + +while IFS= read -r file; do + case "$file" in + .github/workflows/dev-build.yml|\ + .github/workflows/release.yml|\ + build-driver-agents.sh|\ + tools/compress-driver-artifact.sh|\ + tools/detect-changed-driver-agents.sh|\ + tools/diff-driver-agent-revisions.sh|\ + tools/package-driver-release-assets.py|\ + tools/generate-driver-release-manifest.py|\ + tools/complete-driver-release-assets.py|\ + tools/resolve-driver-release-source.py|\ + tools/validate-driver-release-manifest.sh|\ + tools/should-force-global-driver-builds.sh) + echo "true" + exit 0 + ;; + esac +done < <(git diff --name-only "$base_ref" "$head_ref") + +echo "false" diff --git a/tools/should-force-global-driver-builds.test.sh b/tools/should-force-global-driver-builds.test.sh new file mode 100755 index 0000000..07fb1aa --- /dev/null +++ b/tools/should-force-global-driver-builds.test.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$SCRIPT_DIR" + +tmpdir="$(mktemp -d "${TMPDIR:-/tmp}/gonavi-force-global-driver-builds.XXXXXX")" +cleanup() { + rm -rf "$tmpdir" +} +trap cleanup EXIT + +git init -q "$tmpdir" +mkdir -p "$tmpdir/tools" "$tmpdir/.github/workflows" "$tmpdir/internal/db" +cp tools/should-force-global-driver-builds.sh "$tmpdir/tools/should-force-global-driver-builds.sh" +cat >"$tmpdir/.github/workflows/dev-build.yml" <<'YAMLEOF' +name: Dev Build +YAMLEOF +cat >"$tmpdir/tools/package-driver-release-assets.py" <<'PYEOF' +print("package") +PYEOF +cat >"$tmpdir/internal/db/duckdb_impl.go" <<'GOEOF' +package db +GOEOF + +base_ref="" +cd "$tmpdir" +git add . +git -c user.name=GoNavi -c user.email=gonavi@example.test commit -q -m initial +base_ref="$(git rev-parse HEAD)" + +( + cd "$tmpdir" + printf '\n# workflow change\n' >> .github/workflows/dev-build.yml + git add .github/workflows/dev-build.yml + git -c user.name=GoNavi -c user.email=gonavi@example.test commit -q -m 'workflow change' + actual="$(bash ./tools/should-force-global-driver-builds.sh --base "$base_ref" --head HEAD)" + if [[ "$actual" != "true" ]]; then + echo "expected workflow change to force global driver builds, got: ${actual:-}" >&2 + exit 1 + fi +) + +( + cd "$tmpdir" + git reset --hard -q "$base_ref" + printf '\nprint("changed")\n' >> tools/package-driver-release-assets.py + git add tools/package-driver-release-assets.py + git -c user.name=GoNavi -c user.email=gonavi@example.test commit -q -m 'packaging change' + actual="$(bash ./tools/should-force-global-driver-builds.sh --base "$base_ref" --head HEAD)" + if [[ "$actual" != "true" ]]; then + echo "expected packaging change to force global driver builds, got: ${actual:-}" >&2 + exit 1 + fi +) + +( + cd "$tmpdir" + git reset --hard -q "$base_ref" + printf '\n// source-only change\n' >> internal/db/duckdb_impl.go + git add internal/db/duckdb_impl.go + git -c user.name=GoNavi -c user.email=gonavi@example.test commit -q -m 'duckdb source change' + actual="$(bash ./tools/should-force-global-driver-builds.sh --base "$base_ref" --head HEAD)" + if [[ "$actual" != "false" ]]; then + echo "expected source-only driver change not to force global driver builds, got: ${actual:-}" >&2 + exit 1 + fi +) + +( + cd "$tmpdir" + actual="$(bash ./tools/should-force-global-driver-builds.sh --base all --head HEAD)" + if [[ "$actual" != "true" ]]; then + echo "expected base=all to force global driver builds, got: ${actual:-}" >&2 + exit 1 + fi +) + +echo "should-force-global-driver-builds test passed"