feat(ci): scripts/ci 基座(_env/lib-forgejo/notify)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
# _env.sh — shared CI mirror env + tag-version helper. `source` this from other
|
||||
# scripts; do not execute directly. Idempotent: only sets vars if not already
|
||||
# provided by the environment (e.g. workflow-level overrides).
|
||||
|
||||
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}"
|
||||
|
||||
# Forgejo/Gitea repo coordinates (used by lib-forgejo.sh). Secrets
|
||||
# FORGEJO_TOKEN / FORGEJO_URL are injected by the CI runner, not set here.
|
||||
export FORGEJO_REPO="${FORGEJO_REPO:-wangjia/pangolin}"
|
||||
|
||||
# Ensure Homebrew tools are on PATH (macOS runners); harmless elsewhere.
|
||||
case ":${PATH}:" in
|
||||
*":/opt/homebrew/bin:"*) ;;
|
||||
*) export PATH="/opt/homebrew/bin:${PATH}" ;;
|
||||
esac
|
||||
|
||||
# ver_from_tag <prefix> <ref>
|
||||
# Strips an optional "refs/tags/" prefix, then the "<prefix>-v" prefix,
|
||||
# leaving a bare semver. Uses parameter expansion only (no command
|
||||
# substitution). Examples:
|
||||
# ver_from_tag server server-v1.2.3 -> 1.2.3
|
||||
# ver_from_tag server refs/tags/server-v1.2.3 -> 1.2.3
|
||||
ver_from_tag() {
|
||||
local prefix="$1" ref="$2"
|
||||
ref="${ref#refs/tags/}"
|
||||
ref="${ref#"${prefix}"-v}"
|
||||
printf '%s' "$ref"
|
||||
}
|
||||
Executable
+105
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env bash
|
||||
# lib-forgejo.sh — Forgejo/Gitea release API helpers shared by the pangolin
|
||||
# release pipelines (website / server / client). `source` this after _env.sh.
|
||||
#
|
||||
# Provides:
|
||||
# forgejo_release_ensure <tag> <title> -> looks up or creates the release
|
||||
# for <tag>; sets/exports RELEASE_ID
|
||||
# forgejo_upload_asset <tag> <file> -> uploads one asset to that release
|
||||
#
|
||||
# Requires env: FORGEJO_URL, FORGEJO_TOKEN, FORGEJO_REPO (see _env.sh for the
|
||||
# default FORGEJO_REPO=wangjia/pangolin).
|
||||
#
|
||||
# No command substitution ($()) is used anywhere: HTTP status codes and JSON
|
||||
# fields are written to temp files by curl/python3 and read back with `read`.
|
||||
|
||||
: "${FORGEJO_REPO:=wangjia/pangolin}"
|
||||
|
||||
# forgejo_release_ensure <tag> <title>
|
||||
forgejo_release_ensure() {
|
||||
local tag="$1" title="$2"
|
||||
local get_code_file get_body_file get_code
|
||||
|
||||
get_code_file="/tmp/forgejo_get_code.$$"
|
||||
get_body_file="/tmp/forgejo_get_body.$$.json"
|
||||
|
||||
curl -k -s -o "$get_body_file" -w '%{http_code}' \
|
||||
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
"${FORGEJO_URL}/api/v1/repos/${FORGEJO_REPO}/releases/tags/${tag}" \
|
||||
> "$get_code_file"
|
||||
read -r get_code < "$get_code_file"
|
||||
rm -f "$get_code_file"
|
||||
|
||||
if [ "$get_code" = "200" ]; then
|
||||
echo "==> forgejo: release ${tag} already exists"
|
||||
_forgejo_read_release_id "$get_body_file"
|
||||
rm -f "$get_body_file"
|
||||
return 0
|
||||
fi
|
||||
rm -f "$get_body_file"
|
||||
|
||||
echo "==> forgejo: creating release ${tag}"
|
||||
local create_code_file create_body_file create_code
|
||||
create_code_file="/tmp/forgejo_create_code.$$"
|
||||
create_body_file="/tmp/forgejo_create_body.$$.json"
|
||||
|
||||
curl -k -s -o "$create_body_file" -w '%{http_code}' \
|
||||
-X POST "${FORGEJO_URL}/api/v1/repos/${FORGEJO_REPO}/releases" \
|
||||
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\":\"${tag}\",\"name\":\"${title}\",\"draft\":false,\"prerelease\":false}" \
|
||||
> "$create_code_file"
|
||||
read -r create_code < "$create_code_file"
|
||||
rm -f "$create_code_file"
|
||||
|
||||
if [ "$create_code" -lt 200 ] || [ "$create_code" -ge 300 ]; then
|
||||
echo "==> forgejo: release create FAILED (HTTP ${create_code})" >&2
|
||||
cat "$create_body_file" >&2
|
||||
rm -f "$create_body_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_forgejo_read_release_id "$create_body_file"
|
||||
rm -f "$create_body_file"
|
||||
echo "==> forgejo: release_id=${RELEASE_ID}"
|
||||
}
|
||||
|
||||
# _forgejo_read_release_id <json_file> — internal: sets/exports RELEASE_ID.
|
||||
_forgejo_read_release_id() {
|
||||
local json_file="$1" id_file
|
||||
id_file="/tmp/forgejo_release_id.$$"
|
||||
python3 -c "import json,sys; print(json.load(open(sys.argv[1]))['id'])" \
|
||||
"$json_file" > "$id_file"
|
||||
read -r RELEASE_ID < "$id_file"
|
||||
rm -f "$id_file"
|
||||
export RELEASE_ID
|
||||
}
|
||||
|
||||
# forgejo_upload_asset <tag> <file>
|
||||
forgejo_upload_asset() {
|
||||
local tag="$1" file="$2"
|
||||
|
||||
if [ -z "${RELEASE_ID:-}" ]; then
|
||||
forgejo_release_ensure "$tag" "$tag" || return 1
|
||||
fi
|
||||
|
||||
local code_file body_file code
|
||||
code_file="/tmp/forgejo_upload_code.$$"
|
||||
body_file="/tmp/forgejo_upload_body.$$.json"
|
||||
|
||||
curl -k -s -o "$body_file" -w '%{http_code}' \
|
||||
-X POST "${FORGEJO_URL}/api/v1/repos/${FORGEJO_REPO}/releases/${RELEASE_ID}/assets" \
|
||||
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
-F "attachment=@${file}" \
|
||||
> "$code_file"
|
||||
read -r code < "$code_file"
|
||||
rm -f "$code_file"
|
||||
|
||||
echo "==> forgejo: uploaded ${file} (HTTP ${code})"
|
||||
if [ "$code" -lt 200 ] || [ "$code" -ge 300 ]; then
|
||||
cat "$body_file" >&2
|
||||
rm -f "$body_file"
|
||||
return 1
|
||||
fi
|
||||
rm -f "$body_file"
|
||||
}
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env bash
|
||||
# notify.sh — Telegram CI notifications. `source` this from other scripts.
|
||||
#
|
||||
# Provides:
|
||||
# notify_ok <msg> -> send a "success" notification
|
||||
# notify_fail <msg> -> send a "failure" notification
|
||||
#
|
||||
# Uses the same TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID convention as
|
||||
# deploy/bootstrap/monitor/pangolin-monitor.sh. Safe no-op (never fails the
|
||||
# pipeline) when those are unset, or when the Telegram API call itself fails.
|
||||
|
||||
_notify_send() {
|
||||
local text="$1"
|
||||
if [ -z "${TELEGRAM_BOT_TOKEN:-}" ] || [ -z "${TELEGRAM_CHAT_ID:-}" ]; then
|
||||
echo "==> notify: (skipped, no TELEGRAM_BOT_TOKEN/TELEGRAM_CHAT_ID) ${text}"
|
||||
return 0
|
||||
fi
|
||||
curl -fsS --max-time 15 \
|
||||
"https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
|
||||
--data-urlencode "chat_id=${TELEGRAM_CHAT_ID}" \
|
||||
--data-urlencode "text=${text}" \
|
||||
--data "disable_web_page_preview=true" >/dev/null 2>&1 \
|
||||
|| echo "==> notify: Telegram 发送失败(已忽略,不影响流水线)" >&2
|
||||
}
|
||||
|
||||
# notify_ok <msg>
|
||||
notify_ok() {
|
||||
local msg="$1"
|
||||
_notify_send "✅ Pangolin CI: ${msg}"
|
||||
}
|
||||
|
||||
# notify_fail <msg>
|
||||
notify_fail() {
|
||||
local msg="$1"
|
||||
_notify_send "❌ Pangolin CI: ${msg}"
|
||||
}
|
||||
Reference in New Issue
Block a user