Files
ERP/.gitea/workflows/release.yml
T
Qiufeng d3892320dd
Signed Release / release (push) Successful in 9m24s
feat: add managed online updates
2026-08-04 20:05:50 +08:00

154 lines
6.8 KiB
YAML

name: Signed Release
on:
push:
tags:
- "v*"
permissions:
contents: read
releases: write
jobs:
release:
runs-on: ubuntu-latest
env:
GITEA_BASE_URL: ${{ github.server_url }}
GITEA_REPOSITORY: ${{ github.repository }}
GITEA_ALLOW_INSECURE_HTTP: ${{ vars.ERP_RELEASE_ALLOW_INSECURE_HTTP }}
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
RELEASE_PRIVATE_KEY_B64: ${{ secrets.RELEASE_PRIVATE_KEY_B64 }}
NODE_OPTIONS: --max-old-space-size=8192
steps:
- name: Check out source
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Java 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
- name: Build, sign, and publish release
shell: bash
run: |
set -euo pipefail
tag="${GITHUB_REF_NAME:?missing tag name}"
version="${tag#v}"
[[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$ ]] \
|| { printf 'invalid release tag: %s\n' "$tag" >&2; exit 2; }
api_base="${GITEA_BASE_URL:?missing GITEA_BASE_URL repository variable}"
repository="${GITEA_REPOSITORY:-awaioi/ERP}"
case "$api_base" in
https://*) curl_protocols=(--proto '=https' --proto-redir '=https') ;;
http://*)
[[ "${GITEA_ALLOW_INSECURE_HTTP:-0}" == "1" || "${GITEA_ALLOW_INSECURE_HTTP:-0}" == "true" ]] \
|| { printf 'GITEA_BASE_URL must use HTTPS\n' >&2; exit 1; }
curl_protocols=(--proto '=http,https' --proto-redir '=http,https')
;;
*) printf 'invalid GITEA_BASE_URL\n' >&2; exit 1 ;;
esac
[[ "$repository" =~ ^[^/[:space:]]+/[^/[:space:]]+$ ]] \
|| { printf 'invalid GITEA_REPOSITORY\n' >&2; exit 1; }
[[ -n "${GITEA_TOKEN:-}" ]] || { printf 'missing built-in GITEA_TOKEN\n' >&2; exit 1; }
[[ -n "${RELEASE_PRIVATE_KEY_B64:-}" ]] \
|| { printf 'missing RELEASE_PRIVATE_KEY_B64 secret\n' >&2; exit 1; }
umask 077
key_file="${RUNNER_TEMP:-/tmp}/kaidi-erp-release-key.pem"
cleanup() { rm -f "$key_file" release.json release-payload.json release-notes.md; }
trap cleanup EXIT
printf '%s' "$RELEASE_PRIVATE_KEY_B64" | base64 --decode > "$key_file"
export ERP_RELEASE_PRIVATE_KEY_FILE="$key_file"
bash tests/release-scripts.test.sh
(
cd oa-backend
./gradlew test installerTest
)
bash scripts/package-release.sh "$version"
previous_tag="$(git describe --tags --match 'v[0-9]*' --abbrev=0 "${tag}^" 2>/dev/null || true)"
change_range="$tag"
[[ -z "$previous_tag" ]] || change_range="$previous_tag..$tag"
{
printf '## 更新内容\n\n'
if ! git log --no-merges --format='- %s (`%h`)' "$change_range"; then
printf -- '- Kaidi ERP %s 正式发布\n' "$version"
fi
printf '\n## 安全校验\n\n'
printf -- '- 安装包:`kaidi-erp-%s.tar.gz`\n' "$version"
printf -- '- 完整性:SHA-256\n'
printf -- '- 发布签名:Ed25519\n'
if [[ -n "$previous_tag" ]]; then
printf '\n上一个正式版本:`%s`\n' "$previous_tag"
fi
} > release-notes.md
owner="${repository%%/*}"
repo="${repository#*/}"
release_api="${api_base%/}/api/v1/repos/$owner/$repo/releases"
auth_header="Authorization: token $GITEA_TOKEN"
status="$(curl "${curl_protocols[@]}" --silent --show-error --location \
--output release.json --write-out '%{http_code}' \
--header "$auth_header" --header 'Accept: application/json' \
"$release_api/tags/$tag")"
python3 - "$tag" release-notes.md > release-payload.json <<'PY'
import json, sys
tag = sys.argv[1]
with open(sys.argv[2], encoding="utf-8") as handle:
notes = handle.read().strip()
print(json.dumps({
"tag_name": tag,
"name": f"Kaidi ERP {tag}",
"body": notes,
"draft": False,
"prerelease": "-" in tag.split("+", 1)[0],
}, separators=(",", ":")))
PY
if [[ "$status" == "404" ]]; then
curl "${curl_protocols[@]}" --fail-with-body --silent --show-error --location --retry 3 \
--header "$auth_header" --header 'Content-Type: application/json' \
--data-binary @release-payload.json --output release.json "$release_api"
elif [[ "$status" == "200" ]]; then
release_id="$(python3 -c 'import json; print(json.load(open("release.json"))["id"])')"
curl "${curl_protocols[@]}" --fail-with-body --silent --show-error --location --retry 3 \
--request PATCH --header "$auth_header" --header 'Content-Type: application/json' \
--data-binary @release-payload.json --output release.json "$release_api/$release_id"
else
printf 'Gitea release lookup returned HTTP %s\n' "$status" >&2
cat release.json >&2
exit 1
fi
release_id="$(python3 -c 'import json; print(json.load(open("release.json"))["id"])')"
curl "${curl_protocols[@]}" --fail-with-body --silent --show-error --location --retry 3 \
--header "$auth_header" --header 'Accept: application/json' \
--output release.json "$release_api/$release_id"
for asset in "dist/kaidi-erp-$version.tar.gz" "dist/kaidi-erp-installer-$version.jar" dist/SHA256SUMS dist/SHA256SUMS.sig; do
name="$(basename "$asset")"
encoded_name="$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$name")"
existing_id="$(python3 - "$name" <<'PY'
import json, sys
release = json.load(open("release.json"))
print(next((item["id"] for item in release.get("assets", []) if item.get("name") == sys.argv[1]), ""))
PY
)"
if [[ -n "$existing_id" ]]; then
curl "${curl_protocols[@]}" --fail-with-body --silent --show-error --location --retry 3 \
--request DELETE --header "$auth_header" \
"$release_api/$release_id/assets/$existing_id"
fi
curl "${curl_protocols[@]}" --fail-with-body --silent --show-error --location --retry 3 \
--request POST --header "$auth_header" \
--form "attachment=@$asset" \
"$release_api/$release_id/assets?name=$encoded_name" >/dev/null
done
printf 'Published %s release %s\n' "$repository" "$tag"