👷 ci(desktop): add S3 publish for canary/nightly and extract reusable action (#12721)

👷 ci(desktop): extract S3 publish logic into reusable composite action

- Create `.github/actions/desktop-publish-s3/` composite action for S3 upload
- Add `publish-s3` job to canary and nightly workflows (previously missing)
- Refactor stable workflow to use the shared action
- Fix canary/nightly builds not uploading to S3 despite UPDATE_SERVER_URL being set
This commit is contained in:
Innei
2026-03-05 17:23:44 +08:00
committed by GitHub
parent 51c857e4a5
commit 2ebac4679c
4 changed files with 186 additions and 123 deletions
@@ -0,0 +1,139 @@
name: Desktop Publish to S3
description: Upload desktop release artifacts to S3 update server
inputs:
channel:
description: 'Update channel (stable, canary, nightly)'
required: true
version:
description: 'Release version (e.g., 2.1.29-canary.1)'
required: true
aws-access-key-id:
description: 'AWS access key ID'
required: true
aws-secret-access-key:
description: 'AWS secret access key'
required: true
s3-bucket:
description: 'S3 bucket name'
required: true
s3-region:
description: 'S3 region (defaults to us-east-1)'
required: false
default: 'us-east-1'
s3-endpoint:
description: 'Custom S3 endpoint (for R2/MinIO etc.)'
required: false
default: ''
runs:
using: composite
steps:
- name: Download merged artifacts
uses: actions/download-artifact@v7
with:
name: merged-release
path: release
- name: List artifacts to upload
shell: bash
run: |
echo "📦 Artifacts to upload to S3:"
ls -lah release/
echo ""
echo "📋 Version: ${{ inputs.version }}, Channel: ${{ inputs.channel }}"
- name: Upload to S3
shell: bash
env:
AWS_ACCESS_KEY_ID: ${{ inputs.aws-access-key-id }}
AWS_SECRET_ACCESS_KEY: ${{ inputs.aws-secret-access-key }}
AWS_REGION: ${{ inputs.s3-region }}
S3_BUCKET: ${{ inputs.s3-bucket }}
S3_ENDPOINT: ${{ inputs.s3-endpoint }}
CHANNEL: ${{ inputs.channel }}
VERSION: ${{ inputs.version }}
run: |
if [ -z "$S3_BUCKET" ]; then
echo "⚠️ S3 bucket is not configured, skipping S3 upload"
exit 0
fi
# 构建端点参数
ENDPOINT_ARG=""
if [ -n "$S3_ENDPOINT" ]; then
ENDPOINT_ARG="--endpoint-url $S3_ENDPOINT"
echo "📡 Using custom S3 endpoint: $S3_ENDPOINT"
fi
echo "🚀 Uploading to S3 bucket: $S3_BUCKET"
echo "📁 Target path: s3://$S3_BUCKET/$CHANNEL/"
echo ""
# 1. 上传安装包到版本目录
echo "📦 Uploading release files to s3://$S3_BUCKET/$CHANNEL/$VERSION/"
for file in release/*.dmg release/*.zip release/*.exe release/*.AppImage release/*.deb release/*.rpm release/*.snap release/*.tar.gz; do
if [ -f "$file" ]; then
filename=$(basename "$file")
echo " ↗️ $filename"
aws s3 cp "$file" "s3://$S3_BUCKET/$CHANNEL/$VERSION/$filename" $ENDPOINT_ARG
fi
done
# 2. 创建 {channel}*.yml (从 latest*.yml 复制,URL 加版本目录前缀)
# electron-updater 在对应 channel 时会找 {channel}-mac.yml
echo ""
echo "📋 Creating ${CHANNEL}*.yml files from latest*.yml..."
for yml in release/latest*.yml; do
if [ -f "$yml" ]; then
channel_name=$(basename "$yml" | sed "s/latest/$CHANNEL/")
# url: xxx.dmg -> url: {VERSION}/xxx.dmg
sed "s|url: |url: $VERSION/|g" "$yml" > "release/$channel_name"
echo " 📄 Created $channel_name from $(basename $yml) with URL prefix: $VERSION/"
fi
done
# 3. 创建 renderer manifest (仅 stable 渠道有 renderer tar)
RENDERER_TAR="release/lobehub-renderer.tar.gz"
if [ -f "$RENDERER_TAR" ]; then
echo ""
echo "📋 Creating renderer manifest..."
RENDERER_SHA512=$(shasum -a 512 "$RENDERER_TAR" | awk '{print $1}' | xxd -r -p | base64)
RENDERER_SIZE=$(stat -f%z "$RENDERER_TAR" 2>/dev/null || stat -c%s "$RENDERER_TAR")
RELEASE_DATE=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
cat > "release/${CHANNEL}-renderer.yml" <<EOF
version: $VERSION
files:
- url: $VERSION/lobehub-renderer.tar.gz
sha512: $RENDERER_SHA512
size: $RENDERER_SIZE
path: $VERSION/lobehub-renderer.tar.gz
sha512: $RENDERER_SHA512
releaseDate: '$RELEASE_DATE'
EOF
echo " 📄 Created ${CHANNEL}-renderer.yml"
fi
# 4. 上传 manifest 到根目录和版本目录
# 根目录: electron-updater 需要,每次发版覆盖
# 版本目录: 作为存档保留
echo ""
echo "📋 Uploading manifest files..."
for yml in release/${CHANNEL}*.yml release/latest*.yml; do
if [ -f "$yml" ]; then
filename=$(basename "$yml")
echo " ↗️ $filename -> s3://$S3_BUCKET/$CHANNEL/$filename"
aws s3 cp "$yml" "s3://$S3_BUCKET/$CHANNEL/$filename" $ENDPOINT_ARG
echo " ↗️ $filename -> s3://$S3_BUCKET/$CHANNEL/$VERSION/$filename (archive)"
aws s3 cp "$yml" "s3://$S3_BUCKET/$CHANNEL/$VERSION/$filename" $ENDPOINT_ARG
fi
done
echo ""
echo "✅ S3 upload completed!"
echo ""
echo "📋 Files in s3://$S3_BUCKET/$CHANNEL/:"
aws s3 ls "s3://$S3_BUCKET/$CHANNEL/" $ENDPOINT_ARG || true
echo ""
echo "📋 Files in s3://$S3_BUCKET/$CHANNEL/$VERSION/:"
aws s3 ls "s3://$S3_BUCKET/$CHANNEL/$VERSION/" $ENDPOINT_ARG || true
@@ -346,6 +346,25 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# ============================================
# 发布到 S3 更新服务器
# ============================================
publish-s3:
needs: [merge-mac-files, calculate-version]
name: Publish to S3
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/desktop-publish-s3
with:
channel: canary
version: ${{ needs.calculate-version.outputs.version }}
aws-access-key-id: ${{ secrets.UPDATE_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.UPDATE_AWS_SECRET_ACCESS_KEY }}
s3-bucket: ${{ secrets.UPDATE_S3_BUCKET }}
s3-region: ${{ secrets.UPDATE_S3_REGION }}
s3-endpoint: ${{ secrets.UPDATE_S3_ENDPOINT }}
# ============================================
# 清理旧的 Canary Releases (保留最近 7 个)
# ============================================
@@ -344,6 +344,25 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# ============================================
# 发布到 S3 更新服务器
# ============================================
publish-s3:
needs: [merge-mac-files, calculate-version]
name: Publish to S3
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/desktop-publish-s3
with:
channel: nightly
version: ${{ needs.calculate-version.outputs.version }}
aws-access-key-id: ${{ secrets.UPDATE_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.UPDATE_AWS_SECRET_ACCESS_KEY }}
s3-bucket: ${{ secrets.UPDATE_S3_BUCKET }}
s3-region: ${{ secrets.UPDATE_S3_REGION }}
s3-endpoint: ${{ secrets.UPDATE_S3_ENDPOINT }}
# ============================================
# 清理旧的 Nightly Releases (保留最近 7 个)
# ============================================
+9 -123
View File
@@ -349,16 +349,6 @@ jobs:
# ============================================
# 发布到 S3 更新服务器
# ============================================
# S3 目录结构:
# s3://bucket/
# stable/
# stable-mac.yml ← electron-updater 检查更新 (stable channel)
# stable.yml ← Windows (stable channel)
# stable-linux.yml ← Linux (stable channel)
# latest-mac.yml ← fallback for GitHub provider
# {version}/ ← 版本目录
# *.dmg, *.zip, *.exe, ...
# ============================================
publish-s3:
needs: [merge-mac-files, check-stable]
name: Publish to S3
@@ -366,117 +356,13 @@ jobs:
# 手动触发时可选择跳过
if: ${{ !(github.event_name == 'workflow_dispatch' && inputs.skip_s3_upload) }}
steps:
- name: Download merged artifacts
uses: actions/download-artifact@v7
- uses: actions/checkout@v6
- uses: ./.github/actions/desktop-publish-s3
with:
name: merged-release
path: release
- name: List artifacts to upload
run: |
echo "📦 Artifacts to upload to S3:"
ls -lah release/
echo ""
echo "📋 Version: ${{ needs.check-stable.outputs.version }}"
- name: Upload to S3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.UPDATE_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.UPDATE_AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.UPDATE_S3_REGION || 'us-east-1' }}
S3_BUCKET: ${{ secrets.UPDATE_S3_BUCKET }}
S3_ENDPOINT: ${{ secrets.UPDATE_S3_ENDPOINT }}
VERSION: ${{ needs.check-stable.outputs.version }}
run: |
if [ -z "$S3_BUCKET" ]; then
echo "⚠️ UPDATE_S3_BUCKET is not configured, skipping S3 upload"
echo ""
echo "To enable S3 upload, configure the following secrets:"
echo " - UPDATE_AWS_ACCESS_KEY_ID"
echo " - UPDATE_AWS_SECRET_ACCESS_KEY"
echo " - UPDATE_S3_BUCKET"
echo " - UPDATE_S3_REGION (optional, defaults to us-east-1)"
echo " - UPDATE_S3_ENDPOINT (optional, for S3-compatible services)"
exit 0
fi
# 构建端点参数
ENDPOINT_ARG=""
if [ -n "$S3_ENDPOINT" ]; then
ENDPOINT_ARG="--endpoint-url $S3_ENDPOINT"
echo "📡 Using custom S3 endpoint: $S3_ENDPOINT"
fi
echo "🚀 Uploading to S3 bucket: $S3_BUCKET"
echo "📁 Target path: s3://$S3_BUCKET/stable/"
echo ""
# 1. 上传安装包到版本目录
echo "📦 Uploading release files to s3://$S3_BUCKET/stable/$VERSION/"
for file in release/*.dmg release/*.zip release/*.exe release/*.AppImage release/*.deb release/*.rpm release/*.snap release/*.tar.gz; do
if [ -f "$file" ]; then
filename=$(basename "$file")
echo " ↗️ $filename"
aws s3 cp "$file" "s3://$S3_BUCKET/stable/$VERSION/$filename" $ENDPOINT_ARG
fi
done
# 2. 创建 stable*.yml (从 latest*.yml 复制,并修改 URL 加上版本目录前缀)
# electron-updater 在 channel=stable 时会找 stable-mac.yml
# S3 目录结构: stable/{version}/xxx.dmg,所以 URL 需要加上 {version}/ 前缀
echo ""
echo "📋 Creating stable*.yml files from latest*.yml..."
for yml in release/latest*.yml; do
if [ -f "$yml" ]; then
stable_name=$(basename "$yml" | sed 's/latest/stable/')
# 复制并修改 URL: 给所有 url 字段加上版本目录前缀
# url: xxx.dmg -> url: {VERSION}/xxx.dmg
sed "s|url: |url: $VERSION/|g" "$yml" > "release/$stable_name"
echo " 📄 Created $stable_name from $(basename $yml) with URL prefix: $VERSION/"
fi
done
# 3. 创建 renderer manifest (用于验证 renderer tar 完整性)
echo ""
echo "📋 Creating renderer manifest..."
RENDERER_TAR="release/lobehub-renderer.tar.gz"
if [ -f "$RENDERER_TAR" ]; then
RENDERER_SHA512=$(shasum -a 512 "$RENDERER_TAR" | awk '{print $1}' | xxd -r -p | base64)
RENDERER_SIZE=$(stat -f%z "$RENDERER_TAR" 2>/dev/null || stat -c%s "$RENDERER_TAR")
RELEASE_DATE=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
echo "version: $VERSION" > "release/stable-renderer.yml"
echo "files:" >> "release/stable-renderer.yml"
echo " - url: $VERSION/lobehub-renderer.tar.gz" >> "release/stable-renderer.yml"
echo " sha512: $RENDERER_SHA512" >> "release/stable-renderer.yml"
echo " size: $RENDERER_SIZE" >> "release/stable-renderer.yml"
echo "path: $VERSION/lobehub-renderer.tar.gz" >> "release/stable-renderer.yml"
echo "sha512: $RENDERER_SHA512" >> "release/stable-renderer.yml"
echo "releaseDate: '$RELEASE_DATE'" >> "release/stable-renderer.yml"
echo " 📄 Created stable-renderer.yml with SHA512 checksum"
else
echo " ⚠️ Renderer tar not found, skipping manifest creation"
fi
# 4. 上传 manifest 到根目录和版本目录
# 根目录: electron-updater 需要,会被每次发版覆盖
# 版本目录: 作为存档保留
echo ""
echo "📋 Uploading manifest files..."
for yml in release/stable*.yml release/latest*.yml; do
if [ -f "$yml" ]; then
filename=$(basename "$yml")
echo " ↗️ $filename -> s3://$S3_BUCKET/stable/$filename"
aws s3 cp "$yml" "s3://$S3_BUCKET/stable/$filename" $ENDPOINT_ARG
echo " ↗️ $filename -> s3://$S3_BUCKET/stable/$VERSION/$filename (archive)"
aws s3 cp "$yml" "s3://$S3_BUCKET/stable/$VERSION/$filename" $ENDPOINT_ARG
fi
done
echo ""
echo "✅ S3 upload completed!"
echo ""
echo "📋 Files in s3://$S3_BUCKET/stable/:"
aws s3 ls "s3://$S3_BUCKET/stable/" $ENDPOINT_ARG || true
echo ""
echo "📋 Files in s3://$S3_BUCKET/stable/$VERSION/:"
aws s3 ls "s3://$S3_BUCKET/stable/$VERSION/" $ENDPOINT_ARG || true
channel: stable
version: ${{ needs.check-stable.outputs.version }}
aws-access-key-id: ${{ secrets.UPDATE_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.UPDATE_AWS_SECRET_ACCESS_KEY }}
s3-bucket: ${{ secrets.UPDATE_S3_BUCKET }}
s3-region: ${{ secrets.UPDATE_S3_REGION }}
s3-endpoint: ${{ secrets.UPDATE_S3_ENDPOINT }}