1
0
forked from Eeveid/lightOps
Files
lightOps/scripts/publish-gitea-release.sh
zhilv abcfcf7b33 🐛 fix(release): 改用 RELEASE_TOKEN 发布版本
- 工作流发布步骤改为显式使用仓库密钥 RELEASE_TOKEN
- 去掉发布脚本对 404 的吞错处理,改回明确暴露真实权限或接口错误
- 便于验证当前自定义 token 是否具备 Gitea Release 创建与附件上传权限
2026-05-26 12:46:24 +08:00

234 lines
6.1 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -Eeuo pipefail
GITEA_URL="${GITEA_URL:-https://gitea.kmux.cn}"
OWNER="${GITEA_OWNER:-Eeveid}"
REPO="${GITEA_REPO:-lightOps}"
TAG=""
TITLE=""
NOTES=""
TARGET="main"
CREATE_TAG="true"
PUSH_TAG="true"
PRERELEASE="false"
PACKAGES=()
usage() {
cat <<'EOF'
LightOps Gitea Release 自动发布脚本
用法:
GITEA_TOKEN=<token> bash scripts/publish-gitea-release.sh --tag v0.1.0 --package target/releases/lightops.tar.gz
选项:
--gitea-url <url> Gitea 地址,默认 https://gitea.kmux.cn
--owner <owner> 仓库所有者,默认 Eeveid
--repo <repo> 仓库名,默认 lightOps
--tag <tag> 发布标签,例如 v0.1.0,必填
--title <title> Release 标题,默认等于 tag
--notes <text> Release 说明
--target <ref> tag 指向的分支或提交,默认 main
--package <path> 要上传的发布包,可重复传入
--no-create-tag 不自动创建本地 tag
--no-push-tag 不自动推送 tag
--prerelease 标记为预发布
-h, --help 显示帮助
环境变量:
GITEA_TOKEN Gitea Access Token必须具备仓库 Release 写入权限
EOF
}
while [[ $# -gt 0 ]]; do
case "$1" in
--gitea-url)
GITEA_URL="${2:?缺少 --gitea-url 参数值}"
shift 2
;;
--owner)
OWNER="${2:?缺少 --owner 参数值}"
shift 2
;;
--repo)
REPO="${2:?缺少 --repo 参数值}"
shift 2
;;
--tag)
TAG="${2:?缺少 --tag 参数值}"
shift 2
;;
--title)
TITLE="${2:?缺少 --title 参数值}"
shift 2
;;
--notes)
NOTES="${2:?缺少 --notes 参数值}"
shift 2
;;
--target)
TARGET="${2:?缺少 --target 参数值}"
shift 2
;;
--package)
PACKAGES+=("${2:?缺少 --package 参数值}")
shift 2
;;
--no-create-tag)
CREATE_TAG="false"
shift
;;
--no-push-tag)
PUSH_TAG="false"
shift
;;
--prerelease)
PRERELEASE="true"
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "未知参数:$1" >&2
usage >&2
exit 2
;;
esac
done
log() {
printf '\033[1;32m[LightOps]\033[0m %s\n' "$*"
}
fail() {
printf '\033[1;31m[LightOps]\033[0m %s\n' "$*" >&2
exit 1
}
require_cmd() {
command -v "$1" >/dev/null 2>&1 || fail "缺少命令:$1"
}
detect_json_runtime() {
if command -v node >/dev/null 2>&1; then
echo "node"
elif command -v python3 >/dev/null 2>&1; then
echo "python3"
elif command -v python >/dev/null 2>&1; then
echo "python"
else
return 1
fi
}
json_escape() {
case "$JSON_RUNTIME" in
node)
node -e 'let s=""; process.stdin.setEncoding("utf8"); process.stdin.on("data", d => s += d); process.stdin.on("end", () => process.stdout.write(JSON.stringify(s)));'
;;
*)
"$JSON_RUNTIME" -c 'import json,sys; print(json.dumps(sys.stdin.read()))'
;;
esac
}
api_url() {
printf '%s/api/v1/repos/%s/%s/%s' "${GITEA_URL%/}" "$OWNER" "$REPO" "$1"
}
api_get() {
curl -fsS -H "Authorization: token ${GITEA_TOKEN}" "$1"
}
api_post_json() {
curl -fsS -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "$2" \
"$1"
}
api_post_json_with_status() {
local output_file status
output_file="$(mktemp)"
status="$(curl -sS -o "$output_file" -w '%{http_code}' -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "$2" \
"$1")" || {
cat "$output_file" >&2 || true
rm -f "$output_file"
return 1
}
cat "$output_file"
rm -f "$output_file"
printf '\n%s' "$status"
}
release_id_from_json() {
case "$JSON_RUNTIME" in
node)
node -e 'let s=""; process.stdin.setEncoding("utf8"); process.stdin.on("data", d => s += d); process.stdin.on("end", () => process.stdout.write(String(JSON.parse(s).id)));'
;;
*)
"$JSON_RUNTIME" -c 'import json,sys; print(json.load(sys.stdin)["id"])'
;;
esac
}
[[ -n "$TAG" ]] || fail "必须指定 --tag"
[[ -n "${GITEA_TOKEN:-}" ]] || fail "必须设置 GITEA_TOKEN"
[[ ${#PACKAGES[@]} -gt 0 ]] || fail "至少指定一个 --package"
[[ -n "$TITLE" ]] || TITLE="$TAG"
require_cmd curl
require_cmd git
JSON_RUNTIME="$(detect_json_runtime)" || fail "缺少命令node、python 或 python3"
for package in "${PACKAGES[@]}"; do
[[ -f "$package" ]] || fail "发布包不存在:$package"
done
if [[ "$CREATE_TAG" == "true" ]] && ! git rev-parse "$TAG" >/dev/null 2>&1; then
log "创建本地 tag$TAG"
git tag -a "$TAG" "$TARGET" -m "$TITLE"
fi
if [[ "$PUSH_TAG" == "true" ]]; then
log "推送 tag$TAG"
git push origin "$TAG"
fi
release_url="$(api_url "releases/tags/${TAG}")"
release_json=""
release_status="$(curl -sS -o /dev/null -w '%{http_code}' -H "Authorization: token ${GITEA_TOKEN}" "$release_url" || true)"
if [[ "$release_status" == "200" ]] && release_json="$(api_get "$release_url" 2>/dev/null)"; then
log "Release 已存在:$TAG"
else
log "创建 Release$TAG"
title_json="$(printf '%s' "$TITLE" | json_escape)"
notes_json="$(printf '%s' "$NOTES" | json_escape)"
payload="{\"tag_name\":\"${TAG}\",\"target_commitish\":\"${TARGET}\",\"name\":${title_json},\"body\":${notes_json},\"draft\":false,\"prerelease\":${PRERELEASE}}"
create_result="$(api_post_json_with_status "$(api_url releases)" "$payload")" || fail "创建 Release 请求失败"
create_status="${create_result##*$'\n'}"
release_json="${create_result%$'\n'*}"
[[ "$create_status" == "201" || "$create_status" == "200" ]] || fail "创建 Release 失败HTTP 状态码:$create_status"
fi
release_id="$(printf '%s' "$release_json" | release_id_from_json)"
for package in "${PACKAGES[@]}"; do
name="$(basename "$package")"
log "上传附件:$name"
curl -fsS -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-F "attachment=@${package}" \
"$(api_url "releases/${release_id}/assets")?name=${name}" >/dev/null
done
cat <<EOF
Release 发布完成:
${GITEA_URL%/}/${OWNER}/${REPO}/releases/tag/${TAG}
EOF