From 5167278b0614966c4a540f550eb33e35a16a7b56b216cfb7e9edc5cd246382f7 Mon Sep 17 00:00:00 2001 From: ahdoawhfo Date: Fri, 17 Apr 2026 13:15:03 +0800 Subject: [PATCH] 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-. Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitea/workflows/release.yml | 225 +++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 .gitea/workflows/release.yml diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..54fe29e --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,225 @@ +name: Build and Release + +on: + workflow_dispatch: + inputs: + version: + description: '版本号 (留空则自动生成 v-)' + 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