mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-13 19:20:04 +00:00
👷 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:
@@ -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 个)
|
||||
# ============================================
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
Reference in New Issue
Block a user