Files
IPTables-Management/.gitea/workflows/release.yml
ahdoawhfo e4ef47c901 Drop apt, pull shellcheck from GitHub releases
act_runner's job containers live on a temporary bridge network that
does not inherit the runner's own egress path, so apt-get against
Canonical mirrors can time out even on a US host. Remove the apt step,
rely on the tools baked into gitea/runner-images, and fetch the
shellcheck static binary over HTTPS when it is missing.

Also add a short network diagnostics step to make future egress
issues obvious at a glance.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 13:54:15 +08:00

278 lines
10 KiB
YAML
Raw 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.
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
env:
# 仓库使用 SHA-256 对象格式actions/checkout 内部 `git init` 需在此模式下运行,否则 fetch 会报
# `mismatched algorithms: client sha1; server sha256`。
GIT_DEFAULT_HASH: sha256
steps:
- name: Checkout (full history)
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Network diagnostics
run: |
set +e
echo "=== DNS ==="
cat /etc/resolv.conf 2>/dev/null | head -5 || true
echo "=== Route ==="
ip route 2>/dev/null | head -3 || true
echo "=== Egress probe (5s connect timeout) ==="
for url in \
https://github.com \
https://objects.githubusercontent.com \
https://mirrors.aliyun.com \
http://archive.ubuntu.com \
http://security.ubuntu.com \
; do
code=$(curl -sS -o /dev/null -w '%{http_code}' -m 5 --connect-timeout 5 "$url" || echo TIMEOUT)
printf ' %-45s -> %s\n' "$url" "$code"
done
- name: Ensure required tools (shellcheck via GitHub release)
run: |
set -euo pipefail
# 镜像 gitea/runner-images:ubuntu-latest 已自带 curl / jq / tar / sha256sum。
# 唯一通常缺失的是 shellcheck从 GitHub releases 拉静态二进制即可,不走 apt。
for tool in curl jq tar sha256sum; do
command -v "$tool" >/dev/null || {
echo "::error::基础工具 $tool 不在 PATH 中,镜像异常。请更换 runner 镜像。" >&2
exit 1
}
done
if command -v shellcheck >/dev/null 2>&1; then
echo "shellcheck 已就绪:$(shellcheck --version | awk '/^version:/{print $2}')"
exit 0
fi
SC_VER=v0.10.0
case "$(uname -m)" in
x86_64) SC_ARCH=x86_64 ;;
aarch64) SC_ARCH=aarch64 ;;
*) echo "::error::不支持的架构: $(uname -m)" >&2; exit 1 ;;
esac
URL="https://github.com/koalaman/shellcheck/releases/download/${SC_VER}/shellcheck-${SC_VER}.linux.${SC_ARCH}.tar.xz"
echo "下载 $URL"
curl -fsSL --retry 3 --connect-timeout 15 -o /tmp/shellcheck.tar.xz "$URL"
tar -xJf /tmp/shellcheck.tar.xz -C /tmp
if [[ $EUID -ne 0 ]] && command -v sudo >/dev/null 2>&1; then
SUDO=sudo
else
SUDO=
fi
$SUDO install -m 0755 "/tmp/shellcheck-${SC_VER}/shellcheck" /usr/local/bin/shellcheck
shellcheck --version | awk '/^version:/{print "shellcheck 已安装:" $2}'
- 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