# 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: # Second layer: Business logic level checks (handling build strategy) 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 }} steps: - name: Determine build strategy id: check run: | should_build=false build_type="none" # Business logic: when we need to build if [[ "${{ github.event_name }}" == "schedule" ]] || \ [[ "${{ github.event_name }}" == "workflow_dispatch" ]] || \ [[ "${{ github.event.inputs.force_build }}" == "true" ]] || \ [[ "${{ contains(github.event.head_commit.message, '--build') }}" == "true" ]]; then should_build=true build_type="development" fi # Always build for tag pushes (version releases) if [[ "${{ startsWith(github.ref, 'refs/tags/') }}" == "true" ]]; then should_build=true build_type="release" echo "🏷️ Tag detected: forcing release build" fi echo "should_build=$should_build" >> $GITHUB_OUTPUT echo "build_type=$build_type" >> $GITHUB_OUTPUT echo "Build needed: $should_build (type: $build_type)" # 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 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: | PACKAGE_NAME="rustfs-${{ matrix.target }}" # 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 "Package created: ${PACKAGE_NAME}.zip" - 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: needs.build-check.outputs.build_type == 'release' && env.OSS_ACCESS_KEY_ID != '' 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: | # Install ossutil (platform-specific) case "${{ matrix.platform }}" in linux|macos) sudo -v ; curl https://gosspublic.alicdn.com/ossutil/install.sh | sudo bash OSSUTIL_BIN=ossutil ;; # windows) # ζš‚δΈζ”―ζŒ Windows ossutil # ;; esac # Upload the package file directly to OSS echo "Uploading ${{ steps.package.outputs.package_file }} to OSS..." $OSSUTIL_BIN cp "${{ steps.package.outputs.package_file }}" oss://rustfs-artifacts/artifacts/rustfs/ --force # Create latest.json (only for the first Linux build to avoid duplication) if [[ "${{ matrix.target }}" == "x86_64-unknown-linux-musl" ]]; then VERSION="${GITHUB_REF#refs/tags/v}" echo "{\"version\":\"${VERSION}\",\"release_date\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}" > latest.json $OSSUTIL_BIN cp latest.json oss://rustfs-version/latest.json --force fi # Release management release: name: GitHub Release needs: [build-check, build-rustfs] if: always() && needs.build-check.outputs.build_type == 'release' runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - name: Download all artifacts uses: actions/download-artifact@v4 with: path: ./release-artifacts - name: Prepare release assets id: release_prep run: | VERSION="${GITHUB_REF#refs/tags/}" VERSION_CLEAN="${VERSION#v}" echo "version=${VERSION}" >> $GITHUB_OUTPUT echo "version_clean=${VERSION_CLEAN}" >> $GITHUB_OUTPUT # Organize artifacts mkdir -p ./release-files # Copy all artifacts (.zip files) find ./release-artifacts -name "*.zip" -exec cp {} ./release-files/ \; # Generate checksums for all files cd ./release-files if ls *.zip >/dev/null 2>&1; then sha256sum *.zip >> SHA256SUMS sha512sum *.zip >> SHA512SUMS fi cd .. # Display what we're releasing echo "=== Release Files ===" ls -la ./release-files/ - name: Create GitHub Release env: GH_TOKEN: ${{ github.token }} run: | VERSION="${{ steps.release_prep.outputs.version }}" VERSION_CLEAN="${{ steps.release_prep.outputs.version_clean }}" # Check if release already exists if gh release view "$VERSION" >/dev/null 2>&1; then echo "Release $VERSION already exists, skipping creation" else # Get release notes from tag message RELEASE_NOTES=$(git tag -l --format='%(contents)' "${VERSION}") if [[ -z "$RELEASE_NOTES" || "$RELEASE_NOTES" =~ ^[[:space:]]*$ ]]; then RELEASE_NOTES="Release ${VERSION_CLEAN}" fi # Determine if this is a prerelease PRERELEASE_FLAG="" if [[ "$VERSION" == *"alpha"* ]] || [[ "$VERSION" == *"beta"* ]] || [[ "$VERSION" == *"rc"* ]]; then PRERELEASE_FLAG="--prerelease" fi # Create the release only if it doesn't exist gh release create "$VERSION" \ --title "RustFS $VERSION_CLEAN" \ --notes "$RELEASE_NOTES" \ $PRERELEASE_FLAG fi - name: Upload release assets env: GH_TOKEN: ${{ github.token }} run: | VERSION="${{ steps.release_prep.outputs.version }}" cd ./release-files # Upload all binary files for file in *.zip; do if [[ -f "$file" ]]; then echo "Uploading $file..." gh release upload "$VERSION" "$file" --clobber fi done # Upload checksum files if [[ -f "SHA256SUMS" ]]; then echo "Uploading SHA256SUMS..." gh release upload "$VERSION" "SHA256SUMS" --clobber fi if [[ -f "SHA512SUMS" ]]; then echo "Uploading SHA512SUMS..." gh release upload "$VERSION" "SHA512SUMS" --clobber fi - name: Update release notes env: GH_TOKEN: ${{ github.token }} run: | VERSION="${{ steps.release_prep.outputs.version }}" VERSION_CLEAN="${{ steps.release_prep.outputs.version_clean }}" # Check if release already has custom notes (not auto-generated) EXISTING_NOTES=$(gh release view "$VERSION" --json body --jq '.body' 2>/dev/null || echo "") # Only update if release notes are empty or auto-generated if [[ -z "$EXISTING_NOTES" ]] || [[ "$EXISTING_NOTES" == *"Release ${VERSION_CLEAN}"* ]]; then echo "Updating release notes for $VERSION" # Get original release notes from tag ORIGINAL_NOTES=$(git tag -l --format='%(contents)' "${VERSION}") if [[ -z "$ORIGINAL_NOTES" || "$ORIGINAL_NOTES" =~ ^[[:space:]]*$ ]]; then ORIGINAL_NOTES="Release ${VERSION_CLEAN}" fi # Create comprehensive release notes cat > enhanced_notes.md << EOF ## RustFS ${VERSION_CLEAN} ${ORIGINAL_NOTES} --- ### πŸš€ Quick Download **Linux (Static Binaries - No Dependencies):** \`\`\`bash # x86_64 (Intel/AMD) curl -LO https://github.com/rustfs/rustfs/releases/download/${VERSION}/rustfs-x86_64-unknown-linux-musl.zip unzip rustfs-x86_64-unknown-linux-musl.zip sudo mv rustfs /usr/local/bin/ # ARM64 (Graviton, Apple Silicon VMs) curl -LO https://github.com/rustfs/rustfs/releases/download/${VERSION}/rustfs-aarch64-unknown-linux-musl.zip unzip rustfs-aarch64-unknown-linux-musl.zip sudo mv rustfs /usr/local/bin/ \`\`\` **macOS:** \`\`\`bash # Apple Silicon (M1/M2/M3) curl -LO https://github.com/rustfs/rustfs/releases/download/${VERSION}/rustfs-aarch64-apple-darwin.zip unzip rustfs-aarch64-apple-darwin.zip sudo mv rustfs /usr/local/bin/ # Intel curl -LO https://github.com/rustfs/rustfs/releases/download/${VERSION}/rustfs-x86_64-apple-darwin.zip unzip rustfs-x86_64-apple-darwin.zip sudo mv rustfs /usr/local/bin/ \`\`\` ### πŸ“ Available Downloads | Platform | Architecture | File | Description | |----------|-------------|------|-------------| | Linux | x86_64 | \`rustfs-x86_64-unknown-linux-musl.zip\` | Static binary, no dependencies | | Linux | ARM64 | \`rustfs-aarch64-unknown-linux-musl.zip\` | Static binary, no dependencies | | macOS | Apple Silicon | \`rustfs-aarch64-apple-darwin.zip\` | Native binary, ZIP archive | | macOS | Intel | \`rustfs-x86_64-apple-darwin.zip\` | Native binary, ZIP archive | ### πŸ” Verification Download checksums and verify your download: \`\`\`bash # Download checksums curl -LO https://github.com/rustfs/rustfs/releases/download/${VERSION}/SHA256SUMS # Verify (Linux) sha256sum -c SHA256SUMS --ignore-missing # Verify (macOS) shasum -a 256 -c SHA256SUMS --ignore-missing \`\`\` ### πŸ› οΈ System Requirements - **Linux**: Any distribution with glibc 2.17+ (CentOS 7+, Ubuntu 16.04+) - **macOS**: 10.15+ (Catalina or later) - **Windows**: Windows 10 version 1809 or later ### πŸ“š Documentation - [Installation Guide](https://github.com/rustfs/rustfs#installation) - [Quick Start](https://github.com/rustfs/rustfs#quick-start) - [Configuration](https://github.com/rustfs/rustfs/blob/main/docs/) - [API Documentation](https://docs.rs/rustfs) ### πŸ†˜ Support - πŸ› [Report Issues](https://github.com/rustfs/rustfs/issues) - πŸ’¬ [Community Discussions](https://github.com/rustfs/rustfs/discussions) - πŸ“– [Documentation](https://github.com/rustfs/rustfs/tree/main/docs) EOF # Update the release with enhanced notes gh release edit "$VERSION" --notes-file enhanced_notes.md else echo "Release $VERSION already has custom notes, skipping update to preserve manual edits" fi