From 50d8c07939a63f5e0b5356bbfc5a61eab5b35aa5 Mon Sep 17 00:00:00 2001 From: JustMe Date: Mon, 5 Oct 2026 02:39:21 +0800 Subject: [PATCH] ci: gate parallel releases on verified commits --- .woodpecker/gitea-release.yml | 1 - .woodpecker/linux-release.yml | 3 ++ .woodpecker/release-preflight.yml | 23 +++++++++ .woodpecker/verify.yml | 2 +- .woodpecker/windows-release.yml | 3 ++ .../Monitor.Backend.Tests/ApiBasicsTests.cs | 3 ++ .../ProbeEndToEndTests.cs | 2 +- ci/wait-for-verified-commit.sh | 49 +++++++++++++++++++ 8 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 .woodpecker/release-preflight.yml create mode 100644 ci/wait-for-verified-commit.sh diff --git a/.woodpecker/gitea-release.yml b/.woodpecker/gitea-release.yml index 4371e2d..f355761 100644 --- a/.woodpecker/gitea-release.yml +++ b/.woodpecker/gitea-release.yml @@ -13,7 +13,6 @@ when: ref: refs/tags/v* depends_on: - - verify - linux-release - windows-release diff --git a/.woodpecker/linux-release.yml b/.woodpecker/linux-release.yml index a3098bc..79e66e8 100644 --- a/.woodpecker/linux-release.yml +++ b/.woodpecker/linux-release.yml @@ -12,6 +12,9 @@ when: - event: tag ref: refs/tags/v* +depends_on: + - release-preflight + concurrency: 1 steps: diff --git a/.woodpecker/release-preflight.yml b/.woodpecker/release-preflight.yml new file mode 100644 index 0000000..63f93a8 --- /dev/null +++ b/.woodpecker/release-preflight.yml @@ -0,0 +1,23 @@ +labels: + ci: domain-linux-native + platform: linux/amd64 + +clone: + - name: git + image: plugin-git + settings: + lfs: false + +when: + - event: tag + ref: refs/tags/v* + +steps: + - name: wait-for-push-verification + image: bash + environment: + GITEA_BASE: http://192.168.2.162:3100 + GITEA_TOKEN: + from_secret: gitea_token + commands: + - bash ci/wait-for-verified-commit.sh diff --git a/.woodpecker/verify.yml b/.woodpecker/verify.yml index ff772d2..57a4be3 100644 --- a/.woodpecker/verify.yml +++ b/.woodpecker/verify.yml @@ -9,7 +9,7 @@ clone: lfs: false when: - - event: [push, pull_request, tag] + - event: [push, pull_request] steps: - name: backend-tests diff --git a/.woodpecker/windows-release.yml b/.woodpecker/windows-release.yml index ba7c6c4..94e9e8c 100644 --- a/.woodpecker/windows-release.yml +++ b/.woodpecker/windows-release.yml @@ -12,6 +12,9 @@ when: - event: tag ref: refs/tags/v* +depends_on: + - release-preflight + concurrency: 1 steps: diff --git a/backend/tests/Monitor.Backend.Tests/ApiBasicsTests.cs b/backend/tests/Monitor.Backend.Tests/ApiBasicsTests.cs index 304dcfb..bf95a14 100644 --- a/backend/tests/Monitor.Backend.Tests/ApiBasicsTests.cs +++ b/backend/tests/Monitor.Backend.Tests/ApiBasicsTests.cs @@ -199,3 +199,6 @@ public sealed class ApiBasicsTests [CollectionDefinition("backend")] public sealed class BackendCollection : ICollectionFixture; + +[CollectionDefinition("probe-e2e")] +public sealed class ProbeEndToEndCollection : ICollectionFixture; diff --git a/backend/tests/Monitor.Backend.Tests/ProbeEndToEndTests.cs b/backend/tests/Monitor.Backend.Tests/ProbeEndToEndTests.cs index 652ccdf..d5f1b85 100644 --- a/backend/tests/Monitor.Backend.Tests/ProbeEndToEndTests.cs +++ b/backend/tests/Monitor.Backend.Tests/ProbeEndToEndTests.cs @@ -3,7 +3,7 @@ using System.Text.Json.Nodes; namespace Monitor.Backend.Tests; /// 真实的后端 + 真实的 Agent + 真实的 Probe(都在进程内,回环网络)。 -[Collection("backend")] +[Collection("probe-e2e")] public sealed class ProbeEndToEndTests { private readonly BackendFixture _backend; diff --git a/ci/wait-for-verified-commit.sh b/ci/wait-for-verified-commit.sh new file mode 100644 index 0000000..59b91e5 --- /dev/null +++ b/ci/wait-for-verified-commit.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# Start release builds only after this exact commit passed push verification. +set -euo pipefail + +[[ "${CI_COMMIT_TAG:-}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]] || { + echo "release preflight must run from a vMAJOR.MINOR.PATCH tag" >&2 + exit 2 +} +[[ -n "${CI_COMMIT_SHA:-}" ]] || { echo "CI_COMMIT_SHA is required" >&2; exit 2; } +[[ -n "${GITEA_TOKEN:-}" ]] || { echo "GITEA_TOKEN is required" >&2; exit 2; } + +gitea_base="${GITEA_BASE:-http://192.168.2.162:3100}" +gitea_base="${gitea_base%/}" +gitea_host="${gitea_base#https://}" +gitea_host="${gitea_host#http://}" +gitea_host="${gitea_host%%/*}" +gitea_host="${gitea_host%%:*}" +tmp="$(mktemp -d)" +netrc="$tmp/netrc" +statuses_json="$tmp/statuses.json" +chmod 700 "$tmp" +printf 'machine %s login justme password %s\n' "$gitea_host" "$GITEA_TOKEN" > "$netrc" +chmod 600 "$netrc" +trap 'rm -rf "$tmp"' EXIT + +verification="" +for attempt in $(seq 1 36); do + curl --fail-with-body --silent --show-error --retry 3 --netrc-file "$netrc" \ + "$gitea_base/api/v1/repos/justme/MyMonitor/commits/$CI_COMMIT_SHA/statuses" \ + -o "$statuses_json" + verification="$(jq -r '[.[] | select(.context == "ci/woodpecker/push/verify")] | sort_by(.created_at) | last | .status // ""' "$statuses_json")" + case "$verification" in + success) + echo "push verification passed for ${CI_COMMIT_SHA:0:7}" + exit 0 + ;; + failure|error) + echo "source commit push verification is $verification" >&2 + exit 1 + ;; + *) + if [[ "$attempt" == 36 ]]; then + echo "timed out waiting for push verification (last status: ${verification:-missing})" >&2 + exit 1 + fi + sleep 10 + ;; + esac +done