mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-06 05:17:42 +00:00
0d9f9e381a
* fix: use correct tag reference in release workflow wait-for-artifacts step - Change ref from github.ref to needs.release-check.outputs.tag - Fix issue where wait-on-check-action receives full git reference (refs/tags/1.0.0-alpha.21) instead of clean tag name (1.0.0-alpha.21) - This resolves timeout errors when waiting for build artifacts during release process Fixes the release workflow failure for tag 1.0.0-alpha.21 * refactor: use workflow_run trigger for release workflow instead of push - Replace push trigger with workflow_run to eliminate timing issues - Release workflow now triggers only after Build workflow completes successfully - Remove wait-for-artifacts step completely (no longer needed) - Add should_release condition to control release execution - Support both tag pushes and manual releases via workflow_dispatch - Align with docker.yml pattern for better reliability This completely resolves the release workflow timeout issues by ensuring build artifacts are always available before the release process starts. Fixes the fundamental timing issue where release.yml and build.yml were racing against each other when triggered by the same tag push.
395 lines
14 KiB
YAML
395 lines
14 KiB
YAML
# Copyright 2024 RustFS Team
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
name: Release
|
|
|
|
on:
|
|
# Automatically triggered when build workflow completes successfully
|
|
workflow_run:
|
|
workflows: ["Build and Release"]
|
|
types: [completed]
|
|
branches: [main]
|
|
# Manual trigger for standalone release creation
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: "Tag to create release for"
|
|
required: true
|
|
type: string
|
|
|
|
env:
|
|
CARGO_TERM_COLOR: always
|
|
|
|
jobs:
|
|
# Determine release type and check if we should proceed
|
|
release-check:
|
|
name: Release Type Check
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
tag: ${{ steps.check.outputs.tag }}
|
|
version: ${{ steps.check.outputs.version }}
|
|
is_prerelease: ${{ steps.check.outputs.is_prerelease }}
|
|
release_type: ${{ steps.check.outputs.release_type }}
|
|
should_release: ${{ steps.check.outputs.should_release }}
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Determine release type
|
|
id: check
|
|
run: |
|
|
should_release=false
|
|
tag=""
|
|
version=""
|
|
is_prerelease=false
|
|
release_type="release"
|
|
|
|
if [[ "${{ github.event_name }}" == "workflow_run" ]]; then
|
|
# Triggered by build workflow completion
|
|
echo "🔗 Triggered by build workflow completion"
|
|
|
|
# Only proceed if the build workflow was successful
|
|
if [[ "${{ github.event.workflow_run.conclusion }}" != "success" ]]; then
|
|
echo "❌ Build workflow failed (conclusion: ${{ github.event.workflow_run.conclusion }}), skipping release"
|
|
should_release=false
|
|
else
|
|
echo "✅ Build workflow succeeded, checking if this is a tag push"
|
|
|
|
# Check if this was triggered by a tag push
|
|
if [[ "${{ github.event.workflow_run.event }}" == "push" ]]; then
|
|
# Extract tag from head_branch for tag pushes
|
|
head_branch="${{ github.event.workflow_run.head_branch }}"
|
|
if [[ "$head_branch" =~ ^refs/tags/ ]]; then
|
|
tag="${head_branch#refs/tags/}"
|
|
should_release=true
|
|
echo "🏷️ Tag push detected: $tag"
|
|
else
|
|
echo "⏭️ Not a tag push, skipping release (branch: $head_branch)"
|
|
should_release=false
|
|
fi
|
|
else
|
|
echo "⏭️ Not a push event, skipping release (event: ${{ github.event.workflow_run.event }})"
|
|
should_release=false
|
|
fi
|
|
fi
|
|
|
|
echo "🔄 Release triggered by workflow_run:"
|
|
echo " 📋 Conclusion: ${{ github.event.workflow_run.conclusion }}"
|
|
echo " 🌿 Branch: ${{ github.event.workflow_run.head_branch }}"
|
|
echo " 📎 SHA: ${{ github.event.workflow_run.head_sha }}"
|
|
echo " 🎯 Event: ${{ github.event.workflow_run.event }}"
|
|
|
|
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
|
# Manual trigger
|
|
tag="${{ github.event.inputs.tag }}"
|
|
should_release=true
|
|
echo "🎯 Manual release triggered for tag: $tag"
|
|
fi
|
|
|
|
# Process tag if we should proceed
|
|
if [[ "$should_release" == "true" && -n "$tag" ]]; then
|
|
version="$tag"
|
|
|
|
# Check if this is a prerelease
|
|
if [[ "$tag" == *"alpha"* ]] || [[ "$tag" == *"beta"* ]] || [[ "$tag" == *"rc"* ]]; then
|
|
is_prerelease=true
|
|
if [[ "$tag" == *"alpha"* ]]; then
|
|
release_type="alpha"
|
|
elif [[ "$tag" == *"beta"* ]]; then
|
|
release_type="beta"
|
|
elif [[ "$tag" == *"rc"* ]]; then
|
|
release_type="rc"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
echo "should_release=$should_release" >> $GITHUB_OUTPUT
|
|
echo "tag=$tag" >> $GITHUB_OUTPUT
|
|
echo "version=$version" >> $GITHUB_OUTPUT
|
|
echo "is_prerelease=$is_prerelease" >> $GITHUB_OUTPUT
|
|
echo "release_type=$release_type" >> $GITHUB_OUTPUT
|
|
|
|
echo "📊 Release Summary:"
|
|
echo " - Should release: $should_release"
|
|
echo " - Tag: $tag"
|
|
echo " - Version: $version"
|
|
echo " - Is prerelease: $is_prerelease"
|
|
echo " - Release type: $release_type"
|
|
|
|
# Create GitHub Release
|
|
create-release:
|
|
name: Create GitHub Release
|
|
needs: release-check
|
|
if: needs.release-check.outputs.should_release == 'true'
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
outputs:
|
|
release_id: ${{ steps.create.outputs.release_id }}
|
|
release_url: ${{ steps.create.outputs.release_url }}
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Create GitHub Release
|
|
id: create
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
TAG="${{ needs.release-check.outputs.tag }}"
|
|
VERSION="${{ needs.release-check.outputs.version }}"
|
|
IS_PRERELEASE="${{ needs.release-check.outputs.is_prerelease }}"
|
|
RELEASE_TYPE="${{ needs.release-check.outputs.release_type }}"
|
|
|
|
# Check if release already exists
|
|
if gh release view "$TAG" >/dev/null 2>&1; then
|
|
echo "Release $TAG already exists"
|
|
RELEASE_ID=$(gh release view "$TAG" --json databaseId --jq '.databaseId')
|
|
RELEASE_URL=$(gh release view "$TAG" --json url --jq '.url')
|
|
else
|
|
# Get release notes from tag message
|
|
RELEASE_NOTES=$(git tag -l --format='%(contents)' "${TAG}")
|
|
if [[ -z "$RELEASE_NOTES" || "$RELEASE_NOTES" =~ ^[[:space:]]*$ ]]; then
|
|
if [[ "$IS_PRERELEASE" == "true" ]]; then
|
|
RELEASE_NOTES="Pre-release ${VERSION} (${RELEASE_TYPE})"
|
|
else
|
|
RELEASE_NOTES="Release ${VERSION}"
|
|
fi
|
|
fi
|
|
|
|
# Create release title
|
|
if [[ "$IS_PRERELEASE" == "true" ]]; then
|
|
TITLE="RustFS $VERSION (${RELEASE_TYPE})"
|
|
else
|
|
TITLE="RustFS $VERSION"
|
|
fi
|
|
|
|
# Create the release
|
|
PRERELEASE_FLAG=""
|
|
if [[ "$IS_PRERELEASE" == "true" ]]; then
|
|
PRERELEASE_FLAG="--prerelease"
|
|
fi
|
|
|
|
gh release create "$TAG" \
|
|
--title "$TITLE" \
|
|
--notes "$RELEASE_NOTES" \
|
|
$PRERELEASE_FLAG \
|
|
--draft
|
|
|
|
RELEASE_ID=$(gh release view "$TAG" --json databaseId --jq '.databaseId')
|
|
RELEASE_URL=$(gh release view "$TAG" --json url --jq '.url')
|
|
fi
|
|
|
|
echo "release_id=$RELEASE_ID" >> $GITHUB_OUTPUT
|
|
echo "release_url=$RELEASE_URL" >> $GITHUB_OUTPUT
|
|
echo "Created release: $RELEASE_URL"
|
|
|
|
# Download and prepare release assets
|
|
prepare-assets:
|
|
name: Prepare Release Assets
|
|
needs: [release-check, create-release]
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
assets_prepared: ${{ steps.prepare.outputs.assets_prepared }}
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Download artifacts from build workflow
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
path: ./artifacts
|
|
pattern: rustfs-*
|
|
merge-multiple: true
|
|
|
|
- name: Prepare release assets
|
|
id: prepare
|
|
run: |
|
|
VERSION="${{ needs.release-check.outputs.version }}"
|
|
TAG="${{ needs.release-check.outputs.tag }}"
|
|
|
|
mkdir -p ./release-assets
|
|
|
|
# Copy and verify artifacts
|
|
ASSETS_COUNT=0
|
|
for file in ./artifacts/rustfs-*.zip; do
|
|
if [[ -f "$file" ]]; then
|
|
cp "$file" ./release-assets/
|
|
ASSETS_COUNT=$((ASSETS_COUNT + 1))
|
|
fi
|
|
done
|
|
|
|
if [[ $ASSETS_COUNT -eq 0 ]]; then
|
|
echo "❌ No artifacts found!"
|
|
exit 1
|
|
fi
|
|
|
|
cd ./release-assets
|
|
|
|
# Generate checksums
|
|
if ls *.zip >/dev/null 2>&1; then
|
|
sha256sum *.zip > SHA256SUMS
|
|
sha512sum *.zip > SHA512SUMS
|
|
fi
|
|
|
|
# TODO: Add GPG signing for signatures
|
|
# For now, create placeholder signature files
|
|
for file in *.zip; do
|
|
echo "# Signature for $file" > "${file}.asc"
|
|
echo "# GPG signature will be added in future versions" >> "${file}.asc"
|
|
done
|
|
|
|
echo "assets_prepared=true" >> $GITHUB_OUTPUT
|
|
|
|
echo "📦 Prepared assets:"
|
|
ls -la
|
|
|
|
echo "🔢 Asset count: $ASSETS_COUNT"
|
|
|
|
- name: Upload prepared assets
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: release-assets-${{ needs.release-check.outputs.tag }}
|
|
path: ./release-assets/
|
|
retention-days: 30
|
|
|
|
# Upload assets to GitHub Release
|
|
upload-assets:
|
|
name: Upload Release Assets
|
|
needs: [release-check, create-release, prepare-assets]
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- name: Download prepared assets
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: release-assets-${{ needs.release-check.outputs.tag }}
|
|
path: ./release-assets
|
|
|
|
- name: Upload to GitHub Release
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
TAG="${{ needs.release-check.outputs.tag }}"
|
|
|
|
cd ./release-assets
|
|
|
|
# Upload all files
|
|
for file in *; do
|
|
if [[ -f "$file" ]]; then
|
|
echo "📤 Uploading $file..."
|
|
gh release upload "$TAG" "$file" --clobber
|
|
fi
|
|
done
|
|
|
|
echo "✅ All assets uploaded successfully"
|
|
|
|
# Update latest.json for stable releases only
|
|
update-latest:
|
|
name: Update Latest Version
|
|
needs: [release-check, upload-assets]
|
|
if: needs.release-check.outputs.is_prerelease == 'false'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Update latest.json
|
|
env:
|
|
OSS_ACCESS_KEY_ID: ${{ secrets.ALICLOUDOSS_KEY_ID }}
|
|
OSS_ACCESS_KEY_SECRET: ${{ secrets.ALICLOUDOSS_KEY_SECRET }}
|
|
run: |
|
|
if [[ -z "$OSS_ACCESS_KEY_ID" ]]; then
|
|
echo "⚠️ OSS credentials not available, skipping latest.json update"
|
|
exit 0
|
|
fi
|
|
|
|
VERSION="${{ needs.release-check.outputs.version }}"
|
|
TAG="${{ needs.release-check.outputs.tag }}"
|
|
|
|
# Install ossutil
|
|
OSSUTIL_VERSION="2.1.1"
|
|
OSSUTIL_ZIP="ossutil-${OSSUTIL_VERSION}-linux-amd64.zip"
|
|
OSSUTIL_DIR="ossutil-${OSSUTIL_VERSION}-linux-amd64"
|
|
|
|
curl -o "$OSSUTIL_ZIP" "https://gosspublic.alicdn.com/ossutil/v2/${OSSUTIL_VERSION}/${OSSUTIL_ZIP}"
|
|
unzip "$OSSUTIL_ZIP"
|
|
chmod +x "${OSSUTIL_DIR}/ossutil"
|
|
|
|
# Create latest.json
|
|
cat > latest.json << EOF
|
|
{
|
|
"version": "${VERSION}",
|
|
"tag": "${TAG}",
|
|
"release_date": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
|
"release_type": "stable",
|
|
"download_url": "https://github.com/${{ github.repository }}/releases/tag/${TAG}"
|
|
}
|
|
EOF
|
|
|
|
# Upload to OSS
|
|
./${OSSUTIL_DIR}/ossutil cp latest.json oss://rustfs-version/latest.json --force
|
|
|
|
echo "✅ Updated latest.json for stable release $VERSION"
|
|
|
|
# Publish release (remove draft status)
|
|
publish-release:
|
|
name: Publish Release
|
|
needs: [release-check, create-release, upload-assets]
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Update release notes and publish
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
TAG="${{ needs.release-check.outputs.tag }}"
|
|
VERSION="${{ needs.release-check.outputs.version }}"
|
|
IS_PRERELEASE="${{ needs.release-check.outputs.is_prerelease }}"
|
|
RELEASE_TYPE="${{ needs.release-check.outputs.release_type }}"
|
|
|
|
# Get original release notes from tag
|
|
ORIGINAL_NOTES=$(git tag -l --format='%(contents)' "${TAG}")
|
|
if [[ -z "$ORIGINAL_NOTES" || "$ORIGINAL_NOTES" =~ ^[[:space:]]*$ ]]; then
|
|
if [[ "$IS_PRERELEASE" == "true" ]]; then
|
|
ORIGINAL_NOTES="Pre-release ${VERSION} (${RELEASE_TYPE})"
|
|
else
|
|
ORIGINAL_NOTES="Release ${VERSION}"
|
|
fi
|
|
fi
|
|
|
|
# Use release notes template if available
|
|
if [[ -f ".github/workflows/release-notes-template.md" ]]; then
|
|
# Substitute variables in template
|
|
sed -e "s/\${VERSION}/$TAG/g" \
|
|
-e "s/\${VERSION_CLEAN}/$VERSION/g" \
|
|
-e "s/\${ORIGINAL_NOTES}/$(echo "$ORIGINAL_NOTES" | sed 's/[[\.*^$()+?{|]/\\&/g')/g" \
|
|
.github/workflows/release-notes-template.md > enhanced_notes.md
|
|
|
|
# Update release notes
|
|
gh release edit "$TAG" --notes-file enhanced_notes.md
|
|
fi
|
|
|
|
# Publish the release (remove draft status)
|
|
gh release edit "$TAG" --draft=false
|
|
|
|
echo "🎉 Released $TAG successfully!"
|
|
echo "📄 Release URL: ${{ needs.create-release.outputs.release_url }}"
|