Skip to content

Merge remote-tracking branch 'upstream/master' #10

Merge remote-tracking branch 'upstream/master'

Merge remote-tracking branch 'upstream/master' #10

Workflow file for this run

name: Go-Release
# 触发条件配置
on:
push:
# 针对 master 分支的普通提交也触发
branches:
- "master"
paths:
- "internal/app/version.go"
# 权限配置:允许脚本写入仓库内容(用于发布 Release)
permissions:
contents: write
packages: write
env:
NAME: ${{ github.event.repository.name }}
jobs:
check-version:
if: github.actor == 'haierkeys'
runs-on: ubuntu-latest
outputs:
should_release: ${{ steps.check.outputs.should_release }}
release_tag: ${{ steps.check.outputs.release_tag }}
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.ref }}
fetch-depth: 0
- name: Check Version
id: check
run: |
# 从 internal/app/version.go (HEAD) 读取当前版本
# 预期格式: var Version string = "0.0.1"
CURRENT_VERSION=$(grep -E 'Version\s+string' internal/app/version.go | awk -F '"' '{print $2}')
echo "当前版本 (HEAD): $CURRENT_VERSION"
# 从 internal/app/version.go (HEAD~1) 获取上一个版本
# 使用 git show 获取上一次提交的文件内容
# 注意: 我们将其包裹在一个块中以处理 HEAD~1 可能不存在的情况 (例如: 初始提交)
if git rev-parse --verify HEAD~1 >/dev/null 2>&1; then
PREV_FILE_CONTENT=$(git show HEAD~1:internal/app/version.go)
PREV_VERSION=$(echo "$PREV_FILE_CONTENT" | grep -E 'Version\s+string' | awk -F '"' '{print $2}')
else
PREV_VERSION="0.0.0"
fi
# 如果 PREV_VERSION 为空 (例如: grep 失败), 默认为 0.0.0
if [ -z "$PREV_VERSION" ]; then
PREV_VERSION="0.0.0"
fi
echo "上一个版本 (HEAD~1): $PREV_VERSION"
# 规范化版本以进行比较 (如果存在 'v' 前缀则移除)
V_LAST=${PREV_VERSION#v}
V_CURR=${CURRENT_VERSION#v}
# 比较版本
if [ "$V_CURR" != "$V_LAST" ]; then
# 使用 sort -V 确定当前版本是否严格大于旧版本
NEWER_VERSION=$(echo -e "$V_LAST\n$V_CURR" | sort -V | tail -n 1)
if [ "$NEWER_VERSION" == "$V_CURR" ] && [ "$NEWER_VERSION" != "$V_LAST" ]; then
echo "检测到新版本: $V_CURR > $V_LAST"
echo "should_release=true" >> $GITHUB_OUTPUT
echo "release_tag=$V_CURR" >> $GITHUB_OUTPUT
else
echo "版本 $V_CURR 不大于 $V_LAST。跳过发布..."
echo "should_release=false" >> $GITHUB_OUTPUT
fi
else
echo "版本匹配 ($V_CURR == $V_LAST)。跳过发布..."
echo "should_release=false" >> $GITHUB_OUTPUT
fi
prepare-message:
needs: check-version
if: needs.check-version.outputs.should_release == 'true' && github.actor == 'haierkeys'
runs-on: ubuntu-latest
outputs:
commit_msg: ${{ steps.trans.outputs.commit_msg }}
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.ref }}
fetch-depth: 0
- name: Prepare Commit Message
id: trans
run: |
# 获取提交文本信息
msg=$(git log -1 --pretty=%B)
# 设置 Python 进行翻译
pip install deep-translator > /dev/null 2>&1 || true
# 运行翻译脚本
export COMMIT_MSG="$msg"
echo "commit_msg<<EOF" >> $GITHUB_OUTPUT
if [ -f "scripts/translate_commit.py" ]; then
python3 scripts/translate_commit.py >> $GITHUB_OUTPUT
else
echo "未找到翻译脚本,使用原始消息"
echo "$msg" >> $GITHUB_OUTPUT
fi
echo "EOF" >> $GITHUB_OUTPUT
create-release:
needs: [check-version, prepare-message]
if: needs.check-version.outputs.should_release == 'true' && github.actor == 'haierkeys'
name: Create Release
runs-on: ubuntu-latest
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
steps:
- name: Create Release
id: create_release
uses: softprops/action-gh-release@v2
env:
token: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ needs.check-version.outputs.release_tag }}
name: ${{ needs.check-version.outputs.release_tag }}
draft: false
prerelease: false
generate_release_notes: true
body: ${{ needs.prepare-message.outputs.commit_msg }}
target_commitish: ${{ github.sha }} # 明确指定在当前分支的 commit 上创建 tag
overwrite_files: true
build-binaries:
needs: [check-version, prepare-message, create-release]
if: needs.check-version.outputs.should_release == 'true' && github.actor == 'haierkeys'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ github.ref }}
fetch-depth: 0
- uses: actions/setup-go@v6
with:
go-version-file: 'go.mod'
- name: Check Go Version
run: go version
- name: Go Build Prepare
run: go install github.com/mitchellh/gox@latest
- name: Go Build Multi-platform
run: make gox-all
- name: Create Changelog
env:
COMMIT_MSG: ${{ needs.prepare-message.outputs.commit_msg }}
run: |
echo "${COMMIT_MSG}" > ./build/changelog.txt
- name: Create GZip Archives for All Platforms
env:
RELEASE_BASENAME: ${{ env.NAME }}-${{ needs.check-version.outputs.release_tag }}
run: |
# 为所有平台创建 tar.gz 包
# Create tar.gz packages for all platforms
declare -a PLATFORMS=("darwin_amd64" "darwin_arm64" "linux_amd64" "linux_arm64" "windows_amd64")
for PLATFORM in "${PLATFORMS[@]}"; do
GOOS=$(echo "$PLATFORM" | cut -d'_' -f1)
GOARCH=$(echo "$PLATFORM" | cut -d'_' -f2)
ARCHIVE_NAME="${RELEASE_BASENAME}-${GOOS}-${GOARCH}.tar.gz"
echo "Creating archive: ${ARCHIVE_NAME}"
tar -czvf "./build/${ARCHIVE_NAME}" ./config -C "./build/${PLATFORM}/" .
done
- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
name: build_file
path: ./build/
- name: Upload Config Artifacts
uses: actions/upload-artifact@v4
with:
name: config
path: ./config
- name: Upload Release Archives
uses: actions/upload-artifact@v4
with:
name: release_archives
path: |
./build/${{ env.NAME }}-${{ needs.check-version.outputs.release_tag }}-*.tar.gz
./build/changelog.txt
push-docker:
needs: [check-version, build-binaries,create-release]
if: needs.check-version.outputs.should_release == 'true' && github.actor == 'haierkeys'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Download Build Artifacts
uses: actions/download-artifact@v4
with:
name: build_file
path: ./build/
- name: Download Config Artifacts
uses: actions/download-artifact@v4
with:
name: config
path: ./config
- name: Set Environment Variables
run: |
# NAME is already set globally
# Use the tag from check-version
TAG_VERSION=${{ needs.check-version.outputs.release_tag }}
echo "TAG_VERSION=${TAG_VERSION}" >> ${GITHUB_ENV}
echo "IMAGE_TAG=${TAG_VERSION}" >> ${GITHUB_ENV}
echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> ${GITHUB_ENV}
echo "GIT_COMMIT=$(git rev-parse --short HEAD)" >> ${GITHUB_ENV}
- name: Append 'latest' tag if on main branch
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
run: echo "IMAGE_TAG=${{ env.IMAGE_TAG }},latest" >> ${GITHUB_ENV}
- uses: docker/setup-qemu-action@v2
- uses: docker/setup-buildx-action@v2
- name: Docker Build & Publish to GitHub Container Registry
uses: elgohr/Publish-Docker-Github-Action@v5
with:
dockerfile: docker/Dockerfile
name: ${{ github.actor }}/${{ env.NAME }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
platforms: linux/amd64,linux/arm64
registry: ghcr.io
snapshot: false
tags: "${{ env.IMAGE_TAG }}"
buildargs: |
VERSION=${{ env.TAG_VERSION }}
BUILD_DATE=${{ env.BUILD_DATE }}
GIT_COMMIT=${{ env.GIT_COMMIT }}
- name: Docker Build & Publish to DockerHub
uses: elgohr/Publish-Docker-Github-Action@v5
with:
dockerfile: docker/Dockerfile
name: ${{ github.actor }}/${{ env.NAME }}
username: ${{ github.actor }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
platforms: linux/amd64,linux/arm64
snapshot: false
tags: "${{ env.IMAGE_TAG }}"
buildargs: |
VERSION=${{ env.TAG_VERSION }}
BUILD_DATE=${{ env.BUILD_DATE }}
GIT_COMMIT=${{ env.GIT_COMMIT }}
- name: Docker Build & Publish to CNB
uses: elgohr/Publish-Docker-Github-Action@v5
with:
dockerfile: docker/Dockerfile
name: haierkeys/${{ env.NAME }}
username: ${{ secrets.CNB_USERNAME }}
password: ${{ secrets.CNB_TOKEN }}
platforms: linux/amd64,linux/arm64
registry: docker.cnb.cool
snapshot: false
tags: "${{ env.IMAGE_TAG }}"
buildargs: |
VERSION=${{ env.TAG_VERSION }}
BUILD_DATE=${{ env.BUILD_DATE }}
GIT_COMMIT=${{ env.GIT_COMMIT }}
push-release-files:
needs: [create-release, build-binaries, check-version]
if: needs.check-version.outputs.should_release == 'true'
runs-on: ubuntu-latest
steps:
- name: Download Release Archives
uses: actions/download-artifact@v4
with:
name: release_archives
path: ./archives/
- name: Upload Archives to GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.check-version.outputs.release_tag }}
files: ./archives/*
push-cnb-release:
needs: [check-version, prepare-message, build-binaries, create-release]
if: needs.check-version.outputs.should_release == 'true'
name: Push CNB Release
runs-on: ubuntu-latest
env:
CNB_REPO: haierkeys/fast-note-sync-service
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ github.ref }}
fetch-depth: 0
- name: Push Tag to CNB
env:
CNB_TOKEN: ${{ secrets.CNB_TOKEN }}
RELEASE_TAG: ${{ needs.check-version.outputs.release_tag }}
run: |
# 确保拉取了最新的 tag 信息
git fetch --tags
git remote add cnb "https://cnb:${CNB_TOKEN}@cnb.cool/${CNB_REPO}.git"
# 直接推送已存在的 tag
git push cnb "${RELEASE_TAG}" --force
- name: Download Release Archives
uses: actions/download-artifact@v4
with:
name: release_archives
path: ./archives/
- name: Create CNB Release and Upload Assets
env:
CNB_TOKEN: ${{ secrets.CNB_TOKEN }}
RELEASE_TAG: ${{ needs.check-version.outputs.release_tag }}
RELEASE_BODY: ${{ needs.prepare-message.outputs.commit_msg }}
run: |
set -e
# ============================================================
# 第一步: 创建 CNB Release
# Step 1: Create CNB Release
# ============================================================
echo "::group::Creating CNB Release: ${RELEASE_TAG}"
RELEASE_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \
-H "Accept: application/vnd.cnb.api+json" \
-H "Authorization: Bearer ${CNB_TOKEN}" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg tag "${RELEASE_TAG}" \
--arg name "${RELEASE_TAG}" \
--arg body "${RELEASE_BODY}" \
'{tag_name: $tag, name: $name, body: $body, prerelease: false, draft: false}')" \
"https://api.cnb.cool/${CNB_REPO}/-/releases")
HTTP_CODE=$(echo "$RELEASE_RESPONSE" | tail -1)
RESPONSE_BODY=$(echo "$RELEASE_RESPONSE" | sed '$d')
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
RELEASE_ID=$(echo "$RESPONSE_BODY" | jq -r '.id')
echo "CNB Release created successfully, ID: ${RELEASE_ID}"
else
echo "::warning::Failed to create CNB Release (HTTP ${HTTP_CODE}), attempting to fetch existing release..."
# 尝试获取已存在的 Release / Try to get existing release
LIST_RESPONSE=$(curl -s \
-H "Accept: application/vnd.cnb.api+json" \
-H "Authorization: Bearer ${CNB_TOKEN}" \
"https://api.cnb.cool/${CNB_REPO}/-/releases")
RELEASE_ID=$(echo "$LIST_RESPONSE" | jq -r ".[] | select(.tag_name==\"${RELEASE_TAG}\") | .id")
if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "null" ]; then
echo "::error::Cannot create or find CNB Release for tag ${RELEASE_TAG}"
exit 1
fi
echo "Found existing CNB Release, ID: ${RELEASE_ID}"
fi
echo "::endgroup::"
# ============================================================
# 第二步: 并行上传所有已打包的构建产物
# Step 2: Parallel upload all pre-built release archives
# ============================================================
for FILE_PATH in ./archives/*; do
(
FILE_NAME=$(basename "$FILE_PATH")
echo "Uploading ${FILE_NAME}..."
FILE_SIZE=$(stat -c%s "$FILE_PATH")
# 2a. 获取上传 URL / Get upload URL
UPLOAD_RESPONSE=$(curl -s -X POST \
-H "Accept: application/vnd.cnb.api+json" \
-H "Authorization: Bearer ${CNB_TOKEN}" \
-H "Content-Type: application/json" \
-d "$(jq -n \
--arg name "${FILE_NAME}" \
--argjson size ${FILE_SIZE} \
'{asset_name: $name, size: $size, overwrite: true}')" \
"https://api.cnb.cool/${CNB_REPO}/-/releases/${RELEASE_ID}/asset-upload-url")
UPLOAD_URL=$(echo "$UPLOAD_RESPONSE" | jq -r '.upload_url')
VERIFY_URL=$(echo "$UPLOAD_RESPONSE" | jq -r '.verify_url')
if [ -z "$UPLOAD_URL" ] || [ "$UPLOAD_URL" = "null" ]; then
echo "::error::Failed to get upload URL for ${FILE_NAME}"
echo "Response: ${UPLOAD_RESPONSE}"
exit 1
fi
# 2b. 上传文件内容 / Upload file content
echo "Uploading ${FILE_NAME} to: ${UPLOAD_URL}"
CONTENT_TYPE="application/gzip"
if [[ "${FILE_NAME}" == *.txt ]]; then
CONTENT_TYPE="text/plain"
fi
UPLOAD_RESULT=$(curl -s -w "\n%{http_code}" -X PUT \
-H "Content-Type: ${CONTENT_TYPE}" \
--data-binary @"$FILE_PATH" \
"$UPLOAD_URL")
UPLOAD_HTTP_CODE=$(echo "$UPLOAD_RESULT" | tail -1)
if [ "$UPLOAD_HTTP_CODE" -ne 200 ] && [ "$UPLOAD_HTTP_CODE" -ne 201 ]; then
echo "::error::Failed to upload ${FILE_NAME} (HTTP ${UPLOAD_HTTP_CODE})"
exit 1
fi
# 2c. 确认上传完成 / Confirm upload
echo "Confirming upload for ${FILE_NAME}..."
CONFIRM_RESULT=$(curl -s -w "\n%{http_code}" -X POST \
-H "Accept: application/vnd.cnb.api+json" \
-H "Authorization: Bearer ${CNB_TOKEN}" \
"${VERIFY_URL}")
CONFIRM_HTTP_CODE=$(echo "$CONFIRM_RESULT" | tail -1)
if [ "$CONFIRM_HTTP_CODE" -ne 200 ] && [ "$CONFIRM_HTTP_CODE" -ne 201 ]; then
echo "::error::Failed to confirm upload for ${FILE_NAME} (HTTP ${CONFIRM_HTTP_CODE})"
exit 1
fi
echo "✅ ${FILE_NAME} uploaded successfully"
) &
done
# 等待所有后台任务完成
wait
echo "🎉 All assets uploaded to CNB Release!"