mirror of
https://github.com/rustfs/rustfs.git
synced 2026-01-17 01:30:33 +00:00
- Add version input parameter to docker.yml workflow_dispatch - Support main-latest, latest, dev-xxx, and specific version patterns - Remove complex fallback mechanism from all Dockerfile variants - Add clear error handling with helpful user guidance - Create main-latest versions for development builds - Ensure Docker builds require explicit VERSION parameter - Update all Docker variants (production, alpine, ubuntu) consistently This change solves the build dependency issue where Docker builds could fail when expected binary artifacts don't exist, by providing a clean version selection mechanism without unpredictable fallbacks.
451 lines
17 KiB
YAML
451 lines
17 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: Build and Release
|
|
|
|
on:
|
|
push:
|
|
tags: ["*.*.*"]
|
|
branches: [main]
|
|
paths-ignore:
|
|
- "**.md"
|
|
- "**.txt"
|
|
- ".github/**"
|
|
- "docs/**"
|
|
- "deploy/**"
|
|
- "scripts/dev_*.sh"
|
|
- "LICENSE*"
|
|
- "README*"
|
|
- "**/*.png"
|
|
- "**/*.jpg"
|
|
- "**/*.svg"
|
|
- ".gitignore"
|
|
- ".dockerignore"
|
|
pull_request:
|
|
branches: [main]
|
|
paths-ignore:
|
|
- "**.md"
|
|
- "**.txt"
|
|
- ".github/**"
|
|
- "docs/**"
|
|
- "deploy/**"
|
|
- "scripts/dev_*.sh"
|
|
- "LICENSE*"
|
|
- "README*"
|
|
- "**/*.png"
|
|
- "**/*.jpg"
|
|
- "**/*.svg"
|
|
- ".gitignore"
|
|
- ".dockerignore"
|
|
schedule:
|
|
- cron: "0 0 * * 0" # Weekly on Sunday at midnight UTC
|
|
workflow_dispatch:
|
|
inputs:
|
|
force_build:
|
|
description: "Force build even without changes"
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
|
|
env:
|
|
CARGO_TERM_COLOR: always
|
|
RUST_BACKTRACE: 1
|
|
# Optimize build performance
|
|
CARGO_INCREMENTAL: 0
|
|
|
|
jobs:
|
|
# Build strategy check - determine build type based on trigger
|
|
build-check:
|
|
name: Build Strategy Check
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
should_build: ${{ steps.check.outputs.should_build }}
|
|
build_type: ${{ steps.check.outputs.build_type }}
|
|
version: ${{ steps.check.outputs.version }}
|
|
short_sha: ${{ steps.check.outputs.short_sha }}
|
|
is_prerelease: ${{ steps.check.outputs.is_prerelease }}
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Determine build strategy
|
|
id: check
|
|
run: |
|
|
should_build=false
|
|
build_type="none"
|
|
version=""
|
|
short_sha=""
|
|
is_prerelease=false
|
|
|
|
# Get short SHA for all builds
|
|
short_sha=$(git rev-parse --short HEAD)
|
|
|
|
# Determine build type based on trigger
|
|
if [[ "${{ startsWith(github.ref, 'refs/tags/') }}" == "true" ]]; then
|
|
# Tag push - release or prerelease
|
|
should_build=true
|
|
tag_name="${GITHUB_REF#refs/tags/}"
|
|
version="${tag_name}"
|
|
|
|
# Check if this is a prerelease
|
|
if [[ "$tag_name" == *"alpha"* ]] || [[ "$tag_name" == *"beta"* ]] || [[ "$tag_name" == *"rc"* ]]; then
|
|
build_type="prerelease"
|
|
is_prerelease=true
|
|
echo "🚀 Prerelease build detected: $tag_name"
|
|
else
|
|
build_type="release"
|
|
echo "📦 Release build detected: $tag_name"
|
|
fi
|
|
elif [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
|
|
# Main branch push - development build
|
|
should_build=true
|
|
build_type="development"
|
|
version="dev-${short_sha}"
|
|
echo "🛠️ Development build detected"
|
|
elif [[ "${{ github.event_name }}" == "schedule" ]] || \
|
|
[[ "${{ github.event_name }}" == "workflow_dispatch" ]] || \
|
|
[[ "${{ github.event.inputs.force_build }}" == "true" ]] || \
|
|
[[ "${{ contains(github.event.head_commit.message, '--build') }}" == "true" ]]; then
|
|
# Scheduled or manual build
|
|
should_build=true
|
|
build_type="development"
|
|
version="dev-${short_sha}"
|
|
echo "⚡ Manual/scheduled build detected"
|
|
fi
|
|
|
|
echo "should_build=$should_build" >> $GITHUB_OUTPUT
|
|
echo "build_type=$build_type" >> $GITHUB_OUTPUT
|
|
echo "version=$version" >> $GITHUB_OUTPUT
|
|
echo "short_sha=$short_sha" >> $GITHUB_OUTPUT
|
|
echo "is_prerelease=$is_prerelease" >> $GITHUB_OUTPUT
|
|
|
|
echo "📊 Build Summary:"
|
|
echo " - Should build: $should_build"
|
|
echo " - Build type: $build_type"
|
|
echo " - Version: $version"
|
|
echo " - Short SHA: $short_sha"
|
|
echo " - Is prerelease: $is_prerelease"
|
|
|
|
# Build RustFS binaries
|
|
build-rustfs:
|
|
name: Build RustFS
|
|
needs: [build-check]
|
|
if: needs.build-check.outputs.should_build == 'true'
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 60
|
|
env:
|
|
RUSTFLAGS: ${{ matrix.cross == 'false' && '-C target-cpu=native' || '' }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
# Linux builds
|
|
- os: ubuntu-latest
|
|
target: x86_64-unknown-linux-musl
|
|
cross: false
|
|
platform: linux
|
|
- os: ubuntu-latest
|
|
target: aarch64-unknown-linux-musl
|
|
cross: true
|
|
platform: linux
|
|
# macOS builds
|
|
- os: macos-latest
|
|
target: aarch64-apple-darwin
|
|
cross: false
|
|
platform: macos
|
|
- os: macos-latest
|
|
target: x86_64-apple-darwin
|
|
cross: false
|
|
platform: macos
|
|
# # Windows builds (temporarily disabled)
|
|
# - os: windows-latest
|
|
# target: x86_64-pc-windows-msvc
|
|
# cross: false
|
|
# platform: windows
|
|
# - os: windows-latest
|
|
# target: aarch64-pc-windows-msvc
|
|
# cross: true
|
|
# platform: windows
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Setup Rust environment
|
|
uses: ./.github/actions/setup
|
|
with:
|
|
rust-version: stable
|
|
target: ${{ matrix.target }}
|
|
cache-shared-key: build-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }}
|
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
cache-save-if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') }}
|
|
install-cross-tools: ${{ matrix.cross }}
|
|
|
|
- name: Download static console assets
|
|
run: |
|
|
mkdir -p ./rustfs/static
|
|
if [[ "${{ matrix.platform }}" == "windows" ]]; then
|
|
curl.exe -L "https://dl.rustfs.com/artifacts/console/rustfs-console-latest.zip" -o console.zip --retry 3 --retry-delay 5 --max-time 300
|
|
if [[ $? -eq 0 ]]; then
|
|
unzip -o console.zip -d ./rustfs/static
|
|
rm console.zip
|
|
else
|
|
echo "Warning: Failed to download console assets, continuing without them"
|
|
echo "// Static assets not available" > ./rustfs/static/empty.txt
|
|
fi
|
|
else
|
|
chmod +w ./rustfs/static/LICENSE || true
|
|
curl -L "https://dl.rustfs.com/artifacts/console/rustfs-console-latest.zip" \
|
|
-o console.zip --retry 3 --retry-delay 5 --max-time 300
|
|
if [[ $? -eq 0 ]]; then
|
|
unzip -o console.zip -d ./rustfs/static
|
|
rm console.zip
|
|
else
|
|
echo "Warning: Failed to download console assets, continuing without them"
|
|
echo "// Static assets not available" > ./rustfs/static/empty.txt
|
|
fi
|
|
fi
|
|
|
|
- name: Build RustFS
|
|
run: |
|
|
# Force rebuild by touching build.rs
|
|
touch rustfs/build.rs
|
|
|
|
if [[ "${{ matrix.cross }}" == "true" ]]; then
|
|
if [[ "${{ matrix.platform }}" == "windows" ]]; then
|
|
# Use cross for Windows ARM64
|
|
cargo install cross --git https://github.com/cross-rs/cross
|
|
cross build --release --target ${{ matrix.target }} -p rustfs --bins
|
|
else
|
|
# Use zigbuild for Linux ARM64
|
|
cargo zigbuild --release --target ${{ matrix.target }} -p rustfs --bins
|
|
fi
|
|
else
|
|
cargo build --release --target ${{ matrix.target }} -p rustfs --bins
|
|
fi
|
|
|
|
- name: Create release package
|
|
id: package
|
|
shell: bash
|
|
run: |
|
|
BUILD_TYPE="${{ needs.build-check.outputs.build_type }}"
|
|
VERSION="${{ needs.build-check.outputs.version }}"
|
|
SHORT_SHA="${{ needs.build-check.outputs.short_sha }}"
|
|
|
|
# Extract platform and arch from target
|
|
TARGET="${{ matrix.target }}"
|
|
PLATFORM="${{ matrix.platform }}"
|
|
|
|
# Map target to architecture
|
|
case "$TARGET" in
|
|
*x86_64*)
|
|
ARCH="x86_64"
|
|
;;
|
|
*aarch64*|*arm64*)
|
|
ARCH="aarch64"
|
|
;;
|
|
*armv7*)
|
|
ARCH="armv7"
|
|
;;
|
|
*)
|
|
ARCH="unknown"
|
|
;;
|
|
esac
|
|
|
|
# Generate package name based on build type
|
|
if [[ "$BUILD_TYPE" == "development" ]]; then
|
|
# Development build: rustfs-${platform}-${arch}-dev-${short_sha}.zip
|
|
PACKAGE_NAME="rustfs-${PLATFORM}-${ARCH}-dev-${SHORT_SHA}"
|
|
else
|
|
# Release/Prerelease build: rustfs-${platform}-${arch}-v${version}.zip
|
|
PACKAGE_NAME="rustfs-${PLATFORM}-${ARCH}-v${VERSION}"
|
|
fi
|
|
|
|
# Create zip packages for all platforms
|
|
# Ensure zip is available
|
|
if ! command -v zip &> /dev/null; then
|
|
if [[ "${{ matrix.os }}" == "ubuntu-latest" ]]; then
|
|
sudo apt-get update && sudo apt-get install -y zip
|
|
fi
|
|
fi
|
|
|
|
cd target/${{ matrix.target }}/release
|
|
zip "../../../${PACKAGE_NAME}.zip" rustfs
|
|
cd ../../..
|
|
|
|
echo "package_name=${PACKAGE_NAME}" >> $GITHUB_OUTPUT
|
|
echo "package_file=${PACKAGE_NAME}.zip" >> $GITHUB_OUTPUT
|
|
echo "build_type=${BUILD_TYPE}" >> $GITHUB_OUTPUT
|
|
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
|
|
|
echo "📦 Package created: ${PACKAGE_NAME}.zip"
|
|
echo "🔧 Build type: ${BUILD_TYPE}"
|
|
echo "📊 Version: ${VERSION}"
|
|
|
|
- name: Upload artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: ${{ steps.package.outputs.package_name }}
|
|
path: ${{ steps.package.outputs.package_file }}
|
|
retention-days: ${{ startsWith(github.ref, 'refs/tags/') && 30 || 7 }}
|
|
|
|
- name: Upload to Aliyun OSS
|
|
if: env.OSS_ACCESS_KEY_ID != '' && (needs.build-check.outputs.build_type == 'release' || needs.build-check.outputs.build_type == 'prerelease' || needs.build-check.outputs.build_type == 'development')
|
|
env:
|
|
OSS_ACCESS_KEY_ID: ${{ secrets.ALICLOUDOSS_KEY_ID }}
|
|
OSS_ACCESS_KEY_SECRET: ${{ secrets.ALICLOUDOSS_KEY_SECRET }}
|
|
OSS_REGION: cn-beijing
|
|
OSS_ENDPOINT: https://oss-cn-beijing.aliyuncs.com
|
|
run: |
|
|
BUILD_TYPE="${{ needs.build-check.outputs.build_type }}"
|
|
|
|
# Install ossutil (platform-specific)
|
|
OSSUTIL_VERSION="2.1.1"
|
|
case "${{ matrix.platform }}" in
|
|
linux)
|
|
if [[ "$(uname -m)" == "arm64" ]]; then
|
|
ARCH="arm64"
|
|
else
|
|
ARCH="amd64"
|
|
fi
|
|
OSSUTIL_ZIP="ossutil-${OSSUTIL_VERSION}-linux-${ARCH}.zip"
|
|
OSSUTIL_DIR="ossutil-${OSSUTIL_VERSION}-linux-${ARCH}"
|
|
|
|
curl -o "$OSSUTIL_ZIP" "https://gosspublic.alicdn.com/ossutil/v2/${OSSUTIL_VERSION}/${OSSUTIL_ZIP}"
|
|
unzip "$OSSUTIL_ZIP"
|
|
mv "${OSSUTIL_DIR}/ossutil" /usr/local/bin/
|
|
rm -rf "$OSSUTIL_DIR" "$OSSUTIL_ZIP"
|
|
chmod +x /usr/local/bin/ossutil
|
|
OSSUTIL_BIN=ossutil
|
|
;;
|
|
macos)
|
|
if [[ "$(uname -m)" == "arm64" ]]; then
|
|
ARCH="arm64"
|
|
else
|
|
ARCH="amd64"
|
|
fi
|
|
OSSUTIL_ZIP="ossutil-${OSSUTIL_VERSION}-mac-${ARCH}.zip"
|
|
OSSUTIL_DIR="ossutil-${OSSUTIL_VERSION}-mac-${ARCH}"
|
|
|
|
curl -o "$OSSUTIL_ZIP" "https://gosspublic.alicdn.com/ossutil/v2/${OSSUTIL_VERSION}/${OSSUTIL_ZIP}"
|
|
unzip "$OSSUTIL_ZIP"
|
|
mv "${OSSUTIL_DIR}/ossutil" /usr/local/bin/
|
|
rm -rf "$OSSUTIL_DIR" "$OSSUTIL_ZIP"
|
|
chmod +x /usr/local/bin/ossutil
|
|
OSSUTIL_BIN=ossutil
|
|
;;
|
|
esac
|
|
|
|
# Determine upload path based on build type
|
|
if [[ "$BUILD_TYPE" == "development" ]]; then
|
|
OSS_PATH="oss://rustfs-artifacts/artifacts/rustfs/dev/"
|
|
echo "📤 Uploading development build to OSS dev directory"
|
|
else
|
|
OSS_PATH="oss://rustfs-artifacts/artifacts/rustfs/release/"
|
|
echo "📤 Uploading release build to OSS release directory"
|
|
fi
|
|
|
|
# Upload the package file to OSS
|
|
echo "Uploading ${{ steps.package.outputs.package_file }} to $OSS_PATH..."
|
|
$OSSUTIL_BIN cp "${{ steps.package.outputs.package_file }}" "$OSS_PATH" --force
|
|
|
|
# For release and prerelease builds, also create a latest version
|
|
if [[ "$BUILD_TYPE" == "release" ]] || [[ "$BUILD_TYPE" == "prerelease" ]]; then
|
|
# Extract platform and arch from package name
|
|
PACKAGE_NAME="${{ steps.package.outputs.package_name }}"
|
|
|
|
# Create latest version filename
|
|
# Convert from rustfs-linux-x86_64-v1.0.0 to rustfs-linux-x86_64-latest
|
|
LATEST_NAME=$(echo "$PACKAGE_NAME" | sed 's/-v[0-9].*$/-latest/')
|
|
LATEST_FILE="${LATEST_NAME}.zip"
|
|
|
|
# Copy the original file to latest version
|
|
cp "${{ steps.package.outputs.package_file }}" "$LATEST_FILE"
|
|
|
|
# Upload the latest version
|
|
echo "Uploading latest version: $LATEST_FILE to $OSS_PATH..."
|
|
$OSSUTIL_BIN cp "$LATEST_FILE" "$OSS_PATH" --force
|
|
|
|
echo "✅ Latest version uploaded: $LATEST_FILE"
|
|
fi
|
|
|
|
# For development builds on main branch, also create a main-latest version
|
|
if [[ "$BUILD_TYPE" == "development" ]] && [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
|
|
# Extract platform and arch from package name
|
|
PACKAGE_NAME="${{ steps.package.outputs.package_name }}"
|
|
|
|
# Create main-latest version filename
|
|
# Convert from rustfs-linux-x86_64-dev-abc123 to rustfs-linux-x86_64-main-latest
|
|
MAIN_LATEST_NAME=$(echo "$PACKAGE_NAME" | sed 's/-dev-[a-f0-9]\{7\}$/-main-latest/')
|
|
MAIN_LATEST_FILE="${MAIN_LATEST_NAME}.zip"
|
|
|
|
# Copy the original file to main-latest version
|
|
cp "${{ steps.package.outputs.package_file }}" "$MAIN_LATEST_FILE"
|
|
|
|
# Upload the main-latest version
|
|
echo "Uploading main-latest version: $MAIN_LATEST_FILE to $OSS_PATH..."
|
|
$OSSUTIL_BIN cp "$MAIN_LATEST_FILE" "$OSS_PATH" --force
|
|
|
|
echo "✅ Main-latest version uploaded: $MAIN_LATEST_FILE"
|
|
|
|
# Also create a generic main-latest for Docker builds
|
|
if [[ "${{ matrix.platform }}" == "linux" ]]; then
|
|
DOCKER_MAIN_LATEST_NAME="rustfs-linux-${{ matrix.target == 'x86_64-unknown-linux-musl' && 'x86_64' || 'aarch64' }}-main-latest"
|
|
DOCKER_MAIN_LATEST_FILE="${DOCKER_MAIN_LATEST_NAME}.zip"
|
|
|
|
cp "${{ steps.package.outputs.package_file }}" "$DOCKER_MAIN_LATEST_FILE"
|
|
$OSSUTIL_BIN cp "$DOCKER_MAIN_LATEST_FILE" "$OSS_PATH" --force
|
|
echo "✅ Docker main-latest version uploaded: $DOCKER_MAIN_LATEST_FILE"
|
|
fi
|
|
fi
|
|
|
|
echo "✅ Upload completed successfully"
|
|
|
|
# Build summary
|
|
build-summary:
|
|
name: Build Summary
|
|
needs: [build-check, build-rustfs]
|
|
if: always() && needs.build-check.outputs.should_build == 'true'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Build completion summary
|
|
run: |
|
|
BUILD_TYPE="${{ needs.build-check.outputs.build_type }}"
|
|
VERSION="${{ needs.build-check.outputs.version }}"
|
|
|
|
echo "🎉 Build completed successfully!"
|
|
echo "📦 Build type: $BUILD_TYPE"
|
|
echo "🔢 Version: $VERSION"
|
|
echo ""
|
|
|
|
case "$BUILD_TYPE" in
|
|
"development")
|
|
echo "🛠️ Development build artifacts have been uploaded to OSS dev directory"
|
|
echo "⚠️ This is a development build - not suitable for production use"
|
|
;;
|
|
"release")
|
|
echo "🚀 Release build artifacts have been uploaded to OSS release directory"
|
|
echo "✅ This build is ready for production use"
|
|
echo "🏷️ GitHub Release will be created automatically by the release workflow"
|
|
;;
|
|
"prerelease")
|
|
echo "🧪 Prerelease build artifacts have been uploaded to OSS release directory"
|
|
echo "⚠️ This is a prerelease build - use with caution"
|
|
echo "🏷️ GitHub Release will be created automatically by the release workflow"
|
|
;;
|
|
esac
|