Skip to content

Sync Release to Aliyun OSS #22

Sync Release to Aliyun OSS

Sync Release to Aliyun OSS #22

Workflow file for this run

# .github/workflows/sync-to-oss.yml
name: Sync Release to Aliyun OSS
on:
release:
types: [ published ]
workflow_dispatch:
inputs:
tag_name:
description: 'Release tag to sync (e.g. v1.2.3)'
required: true
type: string
permissions:
contents: read
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Resolve Tag
id: resolve
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
# Determine tag: release payload or manual dispatch input
if [[ -n "${{ github.event.release && github.event.release.tag_name || '' }}" ]]; then
TAG_NAME="${{ github.event.release.tag_name }}"
RELEASE_URL="${{ github.event.release.html_url }}"
ASSETS_COUNT="${{ github.event.release.assets_count || 0 }}"
elif [[ -n "${{ inputs.tag_name || '' }}" ]]; then
TAG_NAME="${{ inputs.tag_name }}"
# Validate the tag exists and fetch release info
RELEASE_JSON=$(gh release view "$TAG_NAME" --repo "${{ github.repository }}" --json name,url,assets --jq '.')
RELEASE_URL=$(echo "$RELEASE_JSON" | jq -r '.url')
ASSETS_COUNT=$(echo "$RELEASE_JSON" | jq '.assets | length')
else
echo "::error::No release tag available"
exit 1
fi
echo "tag_name=${TAG_NAME}" >> "$GITHUB_OUTPUT"
echo "release_url=${RELEASE_URL}" >> "$GITHUB_OUTPUT"
echo "assets_count=${ASSETS_COUNT}" >> "$GITHUB_OUTPUT"
echo "Resolved release: ${TAG_NAME} (${ASSETS_COUNT} assets)"
- name: Checkout repository
uses: actions/checkout@v5
with:
ref: ${{ steps.resolve.outputs.tag_name }}
- name: Download Release Assets
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
TAG_NAME="${{ steps.resolve.outputs.tag_name }}"
mkdir -p release-assets
gh release download "$TAG_NAME" --repo "${{ github.repository }}" --dir release-assets
echo ""
echo "Assets downloaded:"
ls -lh release-assets/
- name: Install ossutil
run: |
set -euo pipefail
OSSUTIL_VERSION="2.2.1"
curl -sL "https://gosspublic.alicdn.com/ossutil/v2/${OSSUTIL_VERSION}/ossutil-${OSSUTIL_VERSION}-linux-amd64.zip" \
-o ossutil.zip
unzip -q ossutil.zip
mv "ossutil-${OSSUTIL_VERSION}-linux-amd64/ossutil" ./ossutil
chmod +x ossutil
./ossutil version
- name: Upload to OSS
env:
OSS_ENDPOINT: oss-cn-beijing.aliyuncs.com
OSS_REGION: cn-beijing
OSS_BUCKET: browser4
OSS_ACCESS_KEY_ID: ${{ secrets.OSS_ACCESS_KEY_ID }}
OSS_ACCESS_KEY_SECRET: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
run: |
set -euo pipefail
TAG_NAME="${{ steps.resolve.outputs.tag_name }}"
uploaded=0
failed=0
for asset in release-assets/*; do
[[ -f "$asset" ]] || continue
asset_name=$(basename "$asset")
oss_path="oss://${OSS_BUCKET}/releases/download/${TAG_NAME}/${asset_name}"
echo "Uploading: $asset_name → $oss_path"
if ./ossutil cp "$asset" "$oss_path" \
-e "$OSS_ENDPOINT" \
--region "$OSS_REGION" \
--acl public-read \
--retry-times 3; then
((uploaded++)) || true
else
echo "::error::Failed to upload $asset_name"
((failed++)) || true
fi
done
echo ""
echo "Upload complete: ${uploaded} succeeded, ${failed} failed"
if [[ $failed -gt 0 ]]; then
echo "::error::${failed} asset(s) failed to upload"
exit 1
fi
echo "✅ All ${uploaded} release assets synced to OSS"
- name: Upload CLI installer scripts to OSS
env:
OSS_ENDPOINT: oss-cn-beijing.aliyuncs.com
OSS_REGION: cn-beijing
OSS_BUCKET: browser4
OSS_ACCESS_KEY_ID: ${{ secrets.OSS_ACCESS_KEY_ID }}
OSS_ACCESS_KEY_SECRET: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
run: |
set -euo pipefail
TAG_NAME="${{ steps.resolve.outputs.tag_name }}"
SCRIPTS_DIR="cli/scripts"
OSS_SCRIPTS_PREFIX="oss://${OSS_BUCKET}/scripts"
OSS_VERSIONED_PREFIX="oss://${OSS_BUCKET}/releases/download/${TAG_NAME}"
uploaded=0
failed=0
for script in install-browser4-cli.ps1 install-browser4-cli.sh; do
src="${SCRIPTS_DIR}/${script}"
if [[ ! -f "$src" ]]; then
echo "::error::Script not found: $src"
((failed++)) || true
continue
fi
# 1) Upload to convenience URL (unversioned — always latest)
dest_latest="${OSS_SCRIPTS_PREFIX}/${script}"
echo "Uploading: ${script} → ${dest_latest}"
if ./ossutil cp "$src" "$dest_latest" \
-e "$OSS_ENDPOINT" \
--region "$OSS_REGION" \
--acl public-read \
--retry-times 3 \
--force; then
echo " https://${OSS_BUCKET}.${OSS_ENDPOINT}/scripts/${script}"
else
echo "::error::Failed to upload ${script} to scripts/"
((failed++)) || true
continue
fi
# 2) Upload to versioned release path
dest_versioned="${OSS_VERSIONED_PREFIX}/${script}"
echo "Uploading: ${script} → ${dest_versioned}"
if ./ossutil cp "$src" "$dest_versioned" \
-e "$OSS_ENDPOINT" \
--region "$OSS_REGION" \
--acl public-read \
--retry-times 3; then
echo " https://${OSS_BUCKET}.${OSS_ENDPOINT}/releases/download/${TAG_NAME}/${script}"
else
echo "::error::Failed to upload ${script} to versioned path"
((failed++)) || true
continue
fi
# 3) Copy into release-assets/ so the symlink step picks it up
cp "$src" "release-assets/${script}"
echo "Staged ${script} in release-assets/ for latest symlink"
((uploaded++)) || true
done
echo ""
echo "CLI scripts upload: ${uploaded} succeeded, ${failed} failed"
if [[ $failed -gt 0 ]]; then
echo "::error::${failed} CLI installer script(s) failed to upload"
exit 1
fi
echo "📜 CLI installer scripts synced to OSS"
- name: Create latest symlinks
env:
OSS_ENDPOINT: oss-cn-beijing.aliyuncs.com
OSS_REGION: cn-beijing
OSS_BUCKET: browser4
OSS_ACCESS_KEY_ID: ${{ secrets.OSS_ACCESS_KEY_ID }}
OSS_ACCESS_KEY_SECRET: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
run: |
set -euo pipefail
TAG_NAME="${{ steps.resolve.outputs.tag_name }}"
created=0
failed=0
for asset in release-assets/*; do
[[ -f "$asset" ]] || continue
asset_name=$(basename "$asset")
# Symlink key and its target object key (relative to bucket root)
symlink_key="releases/latest/download/${asset_name}"
target_key="releases/download/${TAG_NAME}/${asset_name}"
echo "Creating symlink: ${symlink_key} → ${target_key}"
if ./ossutil api put-symlink \
--bucket "$OSS_BUCKET" \
--key "$symlink_key" \
--symlink-target "$target_key" \
--object-acl public-read \
-e "$OSS_ENDPOINT" \
--region "$OSS_REGION" \
--retry-times 3; then
((created++)) || true
else
echo "::error::Failed to create symlink for $asset_name"
((failed++)) || true
fi
done
echo ""
echo "Symlinks: ${created} created, ${failed} failed"
if [[ $failed -gt 0 ]]; then
echo "::error::${failed} symlink(s) failed to create"
exit 1
fi
echo "🔗 All ${created} latest symlinks created"
- name: Upload latest-release.json metadata
env:
OSS_ENDPOINT: oss-cn-beijing.aliyuncs.com
OSS_REGION: cn-beijing
OSS_BUCKET: browser4
OSS_ACCESS_KEY_ID: ${{ secrets.OSS_ACCESS_KEY_ID }}
OSS_ACCESS_KEY_SECRET: ${{ secrets.OSS_ACCESS_KEY_SECRET }}
run: |
set -euo pipefail
TAG_NAME="${{ steps.resolve.outputs.tag_name }}"
VERSION="${TAG_NAME#v}"
RELEASE_URL="${{ steps.resolve.outputs.release_url }}"
PUBLISHED_AT="${{ github.event.release.published_at || '' }}"
# Build the asset list (public, non-sensitive fields only).
ASSETS_JSON="[]"
if [ -d release-assets ]; then
ASSETS_JSON=$(
ls -l release-assets/ 2>/dev/null \
| tail -n +2 \
| awk '{printf "{\"name\":\"%s\",\"size\":%s},", $NF, $5}' \
| sed 's/,$//'
)
ASSETS_JSON="[${ASSETS_JSON}]"
fi
# Generate latest-release.json with public metadata only (no tokens, no secrets).
cat > latest-release.json << JSONEOF
{
"tag": "${TAG_NAME}",
"version": "${VERSION}",
"assets": ${ASSETS_JSON},
"published_at": "${PUBLISHED_AT}",
"release_url": "${RELEASE_URL}"
}
JSONEOF
echo "Generated latest-release.json:"
cat latest-release.json
OSS_META_PATH="oss://${OSS_BUCKET}/releases/latest-release.json"
echo "Uploading metadata to ${OSS_META_PATH}"
./ossutil cp latest-release.json "$OSS_META_PATH" \
-e "$OSS_ENDPOINT" \
--region "$OSS_REGION" \
--acl public-read \
--retry-times 3 \
--force
echo "📋 Release metadata published to OSS"
- name: Sync Summary
if: always()
run: |
{
echo "## ☁️ Aliyun OSS Sync"
echo ""
echo "- **Release**: ${{ steps.resolve.outputs.tag_name }}"
echo "- **Release URL**: ${{ steps.resolve.outputs.release_url }}"
echo "- **Assets**: ${{ steps.resolve.outputs.assets_count }}"
echo "- **OSS Bucket**: \`oss://browser4/releases/download/${{ steps.resolve.outputs.tag_name }}/\`"
echo "- **Latest symlink**: \`oss://browser4/releases/latest/download/\`"
echo "- **Release metadata**: \`https://browser4.oss-cn-beijing.aliyuncs.com/releases/latest-release.json\`"
echo "- **CLI installer scripts** (convenience — always latest):"
echo " - \`https://browser4.oss-cn-beijing.aliyuncs.com/scripts/install-browser4-cli.ps1\`"
echo " - \`https://browser4.oss-cn-beijing.aliyuncs.com/scripts/install-browser4-cli.sh\`"
echo "- **CLI installer scripts** (versioned):"
echo " - \`https://browser4.oss-cn-beijing.aliyuncs.com/releases/download/${{ steps.resolve.outputs.tag_name }}/install-browser4-cli.ps1\`"
echo " - \`https://browser4.oss-cn-beijing.aliyuncs.com/releases/download/${{ steps.resolve.outputs.tag_name }}/install-browser4-cli.sh\`"
echo "- **CLI installer scripts** (latest alias):"
echo " - \`https://browser4.oss-cn-beijing.aliyuncs.com/releases/latest/download/install-browser4-cli.ps1\`"
echo " - \`https://browser4.oss-cn-beijing.aliyuncs.com/releases/latest/download/install-browser4-cli.sh\`"
echo "- **Status**: ${{ job.status }}"
} >> "$GITHUB_STEP_SUMMARY"