Add Gitea release workflow
Introduce .gitea/workflows/release.yml driven by workflow_dispatch. The pipeline runs shellcheck and unit tests, builds a tar.gz + sha256, generates release notes from git history, and publishes a Gitea Release via the API. Version defaults to v<YYYY.MM.DD>-<short-sha>. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
225
.gitea/workflows/release.yml
Normal file
225
.gitea/workflows/release.yml
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
name: Build and Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: '版本号 (留空则自动生成 v<YYYY.MM.DD>-<short-sha>)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
prerelease:
|
||||||
|
description: '标记为预发布 (Pre-release)'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- 'false'
|
||||||
|
- 'true'
|
||||||
|
draft:
|
||||||
|
description: '以草稿方式创建 Release (不对外公开)'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- 'false'
|
||||||
|
- 'true'
|
||||||
|
skip_tests:
|
||||||
|
description: '跳过单元测试 (紧急构建时使用)'
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- 'false'
|
||||||
|
- 'true'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout (full history)
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Install toolchain
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
sudo apt-get update -qq
|
||||||
|
DEBIAN_FRONTEND=noninteractive sudo apt-get install -y -qq \
|
||||||
|
shellcheck jq curl tar coreutils
|
||||||
|
|
||||||
|
- name: Run shellcheck
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
shellcheck iptables-forward.sh install.sh lib/*.sh tests/run_all.sh
|
||||||
|
|
||||||
|
- name: Run unit tests
|
||||||
|
if: ${{ inputs.skip_tests != 'true' }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
bash tests/run_all.sh --skip-integration
|
||||||
|
|
||||||
|
- name: Compute version metadata
|
||||||
|
id: ver
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
SHORT_SHA=$(git rev-parse --short=7 HEAD)
|
||||||
|
FULL_SHA=$(git rev-parse HEAD)
|
||||||
|
DATE=$(date -u +%Y.%m.%d)
|
||||||
|
BUILD_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
||||||
|
|
||||||
|
if [[ -n "${{ inputs.version }}" ]]; then
|
||||||
|
VERSION="${{ inputs.version }}"
|
||||||
|
else
|
||||||
|
VERSION="v${DATE}-${SHORT_SHA}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
TAG="${VERSION}"
|
||||||
|
TITLE="IPTables 端口转发管理工具 ${VERSION}"
|
||||||
|
ARTIFACT_BASE="iptables-forward-${VERSION}"
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "version=${VERSION}"
|
||||||
|
echo "tag=${TAG}"
|
||||||
|
echo "title=${TITLE}"
|
||||||
|
echo "artifact_base=${ARTIFACT_BASE}"
|
||||||
|
echo "short_sha=${SHORT_SHA}"
|
||||||
|
echo "full_sha=${FULL_SHA}"
|
||||||
|
echo "build_time=${BUILD_TIME}"
|
||||||
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
echo "准备构建: ${VERSION}"
|
||||||
|
|
||||||
|
- name: Ensure tag does not already exist
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
TAG='${{ steps.ver.outputs.tag }}'
|
||||||
|
if git ls-remote --exit-code --tags origin "refs/tags/${TAG}" >/dev/null 2>&1; then
|
||||||
|
echo "::error::Tag ${TAG} 已存在于远端。请手动传入新的 version 输入。"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Build release tarball
|
||||||
|
id: build
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
NAME='${{ steps.ver.outputs.artifact_base }}'
|
||||||
|
mkdir -p "dist/${NAME}"
|
||||||
|
cp iptables-forward.sh install.sh README.md "dist/${NAME}/"
|
||||||
|
cp -r lib "dist/${NAME}/"
|
||||||
|
[[ -f LICENSE ]] && cp LICENSE "dist/${NAME}/" || true
|
||||||
|
chmod 755 "dist/${NAME}/iptables-forward.sh" "dist/${NAME}/install.sh"
|
||||||
|
|
||||||
|
tar -czf "dist/${NAME}.tar.gz" -C dist "${NAME}"
|
||||||
|
( cd dist && sha256sum "${NAME}.tar.gz" > "${NAME}.tar.gz.sha256" )
|
||||||
|
|
||||||
|
ls -la dist/
|
||||||
|
|
||||||
|
- name: Generate changelog
|
||||||
|
id: changelog
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
PREV_TAG=$(git tag --list 'v*' --sort=-creatordate | head -n 1 || true)
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "## 构建信息"
|
||||||
|
echo ""
|
||||||
|
echo "- **版本**: \`${{ steps.ver.outputs.version }}\`"
|
||||||
|
echo "- **提交**: \`${{ steps.ver.outputs.full_sha }}\`"
|
||||||
|
echo "- **构建时间 (UTC)**: ${{ steps.ver.outputs.build_time }}"
|
||||||
|
echo "- **触发者**: @${{ github.actor }}"
|
||||||
|
echo ""
|
||||||
|
echo "## 变更记录"
|
||||||
|
echo ""
|
||||||
|
if [[ -n "${PREV_TAG}" ]]; then
|
||||||
|
echo "自 \`${PREV_TAG}\` 以来的提交:"
|
||||||
|
echo ""
|
||||||
|
git log "${PREV_TAG}..HEAD" --pretty='- %s (`%h`)' --no-merges || true
|
||||||
|
else
|
||||||
|
echo "首次发布,近 30 条提交:"
|
||||||
|
echo ""
|
||||||
|
git log -30 --pretty='- %s (`%h`)' --no-merges
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
echo "## 安装"
|
||||||
|
echo ""
|
||||||
|
echo '```bash'
|
||||||
|
echo "# 下载"
|
||||||
|
echo "wget ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.ver.outputs.tag }}/${{ steps.ver.outputs.artifact_base }}.tar.gz"
|
||||||
|
echo "wget ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.ver.outputs.tag }}/${{ steps.ver.outputs.artifact_base }}.tar.gz.sha256"
|
||||||
|
echo ""
|
||||||
|
echo "# 校验"
|
||||||
|
echo "sha256sum -c ${{ steps.ver.outputs.artifact_base }}.tar.gz.sha256"
|
||||||
|
echo ""
|
||||||
|
echo "# 解压并安装 (可选)"
|
||||||
|
echo "tar -xzf ${{ steps.ver.outputs.artifact_base }}.tar.gz"
|
||||||
|
echo "cd ${{ steps.ver.outputs.artifact_base }}"
|
||||||
|
echo "sudo ./install.sh # 链接到 /usr/local/bin/iptables-forward"
|
||||||
|
echo ""
|
||||||
|
echo "# 直接运行"
|
||||||
|
echo "sudo ./iptables-forward.sh"
|
||||||
|
echo '```'
|
||||||
|
} > dist/RELEASE_NOTES.md
|
||||||
|
|
||||||
|
cat dist/RELEASE_NOTES.md
|
||||||
|
|
||||||
|
- name: Create tag and Release via Gitea API
|
||||||
|
env:
|
||||||
|
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
GITEA_URL: ${{ github.server_url }}
|
||||||
|
REPO: ${{ github.repository }}
|
||||||
|
TAG: ${{ steps.ver.outputs.tag }}
|
||||||
|
TITLE: ${{ steps.ver.outputs.title }}
|
||||||
|
SHA: ${{ steps.ver.outputs.full_sha }}
|
||||||
|
ARTIFACT_BASE: ${{ steps.ver.outputs.artifact_base }}
|
||||||
|
PRERELEASE: ${{ inputs.prerelease }}
|
||||||
|
DRAFT: ${{ inputs.draft }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
BODY=$(jq -Rs . < dist/RELEASE_NOTES.md)
|
||||||
|
|
||||||
|
PAYLOAD=$(jq -nc \
|
||||||
|
--arg tag "$TAG" \
|
||||||
|
--arg sha "$SHA" \
|
||||||
|
--arg name "$TITLE" \
|
||||||
|
--argjson body "$BODY" \
|
||||||
|
--argjson prerelease "$PRERELEASE" \
|
||||||
|
--argjson draft "$DRAFT" \
|
||||||
|
'{tag_name: $tag, target_commitish: $sha, name: $name, body: $body, prerelease: $prerelease, draft: $draft}')
|
||||||
|
|
||||||
|
echo "Creating release: $TAG"
|
||||||
|
RESP=$(curl -sSfL -X POST \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "${PAYLOAD}" \
|
||||||
|
"${GITEA_URL}/api/v1/repos/${REPO}/releases")
|
||||||
|
|
||||||
|
RELEASE_ID=$(echo "$RESP" | jq -r '.id')
|
||||||
|
if [[ -z "${RELEASE_ID}" || "${RELEASE_ID}" == "null" ]]; then
|
||||||
|
echo "::error::创建 Release 失败。响应: ${RESP}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Release ID: ${RELEASE_ID}"
|
||||||
|
|
||||||
|
for asset in "dist/${ARTIFACT_BASE}.tar.gz" "dist/${ARTIFACT_BASE}.tar.gz.sha256"; do
|
||||||
|
fname=$(basename "$asset")
|
||||||
|
echo "Uploading $fname"
|
||||||
|
curl -sSfL -X POST \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
-F "attachment=@${asset};filename=${fname}" \
|
||||||
|
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${RELEASE_ID}/assets?name=${fname}" \
|
||||||
|
> /dev/null
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "完成: ${GITEA_URL}/${REPO}/releases/tag/${TAG}"
|
||||||
|
|
||||||
|
- name: Upload artifacts to workflow run (备份)
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{ steps.ver.outputs.artifact_base }}
|
||||||
|
path: |
|
||||||
|
dist/${{ steps.ver.outputs.artifact_base }}.tar.gz
|
||||||
|
dist/${{ steps.ver.outputs.artifact_base }}.tar.gz.sha256
|
||||||
|
dist/RELEASE_NOTES.md
|
||||||
|
retention-days: 30
|
||||||
Reference in New Issue
Block a user