# 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 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