From 1ea45afcd748886c50be189b45fb4a2e09af7074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=AD=A3=E8=B6=85?= Date: Thu, 17 Jul 2025 04:51:08 +0800 Subject: [PATCH] feat: Implement precise Docker build triggering using workflow_run event (#233) * fix: correct YAML indentation error in docker workflow - Fix incorrect indentation at line 237 in .github/workflows/docker.yml - Step 'Extract metadata and generate tags' had 12 spaces instead of 6 - This was causing YAML syntax validation to fail * fix: restore unified build-rustfs task with correct YAML syntax - Revert complex job separation back to single build-rustfs task - Maintain Linux and macOS builds in unified matrix - Fix YAML indentation and syntax issues - Docker builds will use only Linux binaries as designed in Dockerfile * feat: implement precise Docker build triggering using workflow_run - Use workflow_run event to trigger Docker builds independently - Add precise Linux build status checking via GitHub API - Only trigger Docker builds when both Linux architectures succeed - Remove coupling between build.yml and docker.yml workflows - Improve TARGETPLATFORM consistency in Dockerfile This resolves the issue where Docker builds would trigger even if Linux ARM64 builds failed, causing missing binary artifacts during multi-architecture Docker image creation. --- .github/workflows/build.yml | 28 +++--- .github/workflows/docker.yml | 160 +++++++++++++++++++++++------------ Dockerfile | 15 ++-- 3 files changed, 124 insertions(+), 79 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f3e5d45e..cc9a299a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -242,7 +242,7 @@ jobs: 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 + # Use zigbuild for other cross-compilation cargo zigbuild --release --target ${{ matrix.target }} -p rustfs --bins fi else @@ -456,6 +456,13 @@ jobs: echo "๐Ÿ”ข Version: $VERSION" echo "" + # Check build status + BUILD_STATUS="${{ needs.build-rustfs.result }}" + + echo "๐Ÿ“Š Build Results:" + echo " ๐Ÿ“ฆ All platforms: $BUILD_STATUS" + echo "" + case "$BUILD_TYPE" in "development") echo "๐Ÿ› ๏ธ Development build artifacts have been uploaded to OSS dev directory" @@ -477,21 +484,8 @@ jobs: echo "๐Ÿณ Docker Images:" if [[ "${{ github.event.inputs.build_docker }}" == "false" ]]; then echo "โญ๏ธ Docker image build was skipped (binary only build)" + elif [[ "$BUILD_STATUS" == "success" ]]; then + echo "๐Ÿ”„ Docker images will be built and pushed automatically via workflow_run event" else - echo "๐Ÿ”„ Docker images will be built and pushed automatically using the binary artifacts" + echo "โŒ Docker image build will be skipped due to build failure" fi - - # Call Docker workflow after successful build - call-docker-build: - name: Build And Push Docker Images - needs: [build-check, build-rustfs] - if: needs.build-check.outputs.should_build == 'true' && github.event.inputs.build_docker != 'false' - uses: ./.github/workflows/docker.yml - with: - build_type: ${{ needs.build-check.outputs.build_type }} - version: ${{ needs.build-check.outputs.version }} - short_sha: ${{ needs.build-check.outputs.short_sha }} - is_prerelease: ${{ needs.build-check.outputs.is_prerelease }} - push_images: true - force_rebuild: false - secrets: inherit diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index ccca8e1a..73e9f8a6 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -17,45 +17,29 @@ # This workflow builds Docker images using pre-built binaries from the build workflow. # # Trigger Types: -# 1. workflow_call: Called by build.yml after binary build completes (primary use) +# 1. workflow_run: Automatically triggered when "Build and Release" workflow completes # 2. workflow_dispatch: Manual trigger for standalone Docker builds # -# Architecture: -# build.yml (binaries) -> docker.yml (images) -> registry +# Key Features: +# - Only triggers when Linux builds (x86_64 + aarch64) are successful +# - Independent of macOS/Windows build status +# - Uses workflow_run event for precise control name: Docker Images +# Permissions needed for workflow_run event and GitHub API access +permissions: + contents: read + actions: read + packages: write + on: - # Called by build.yml after binary build completes - workflow_call: - inputs: - build_type: - description: "Build type: development, release, or prerelease" - required: true - type: string - version: - description: "Version to build" - required: true - type: string - short_sha: - description: "Short commit SHA" - required: true - type: string - is_prerelease: - description: "Whether this is a prerelease" - required: true - type: boolean - push_images: - description: "Push images to registries" - required: false - default: true - type: boolean - force_rebuild: - description: "Force rebuild even if binary exists" - required: false - default: false - type: boolean - # Manual trigger with same parameters as build.yml for consistency + # Automatically triggered when build workflow completes + workflow_run: + workflows: ["Build and Release"] + types: [completed] + branches: [main] + # Manual trigger with same parameters for consistency workflow_dispatch: inputs: push_images: @@ -82,7 +66,7 @@ env: DOCKER_PLATFORMS: linux/amd64,linux/arm64 jobs: - # Docker build strategy check + # Check if we should build Docker images build-check: name: Docker Build Check runs-on: ubuntu-latest @@ -94,48 +78,106 @@ jobs: short_sha: ${{ steps.check.outputs.short_sha }} is_prerelease: ${{ steps.check.outputs.is_prerelease }} create_latest: ${{ steps.check.outputs.create_latest }} + linux_builds_success: ${{ steps.check.outputs.linux_builds_success }} steps: - name: Checkout repository uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Check build conditions + - name: Check build conditions and Linux build status id: check run: | - should_build=true # Always build when called + should_build=false should_push=false build_type="none" version="" short_sha="" is_prerelease=false create_latest=false + linux_builds_success=false - if [[ "${{ github.event_name }}" == "workflow_call" ]]; then - # Called by build.yml - use provided parameters - build_type="${{ inputs.build_type }}" - version="${{ inputs.version }}" - short_sha="${{ inputs.short_sha }}" - is_prerelease="${{ inputs.is_prerelease }}" - should_push="${{ inputs.push_images }}" + if [[ "${{ github.event_name }}" == "workflow_run" ]]; then + # Triggered by build workflow completion + echo "๐Ÿ”— Triggered by build workflow completion" - # Determine create_latest based on build_type - if [[ "$build_type" == "release" ]] && [[ "$is_prerelease" == "false" ]]; then - create_latest=true + # Check if the triggering workflow was successful + if [[ "${{ github.event.workflow_run.conclusion }}" != "success" ]]; then + echo "โŒ Build workflow failed, skipping Docker build" + exit 0 fi - echo "๐Ÿ”— Called by build workflow:" - echo " ๐Ÿ“‹ Build type: $build_type" - echo " ๐Ÿ”ข Version: $version" - echo " ๐Ÿ“Ž Short SHA: $short_sha" - echo " ๐Ÿงช Is prerelease: $is_prerelease" - echo " ๐Ÿš€ Push images: $should_push" + # Get workflow run details via GitHub API to check Linux build status + echo "๐Ÿ” Checking Linux build status from workflow run..." + + # Use GitHub API to get detailed job information + WORKFLOW_RUN_ID="${{ github.event.workflow_run.id }}" + + # Get jobs from the workflow run + echo "๐Ÿ“ก Fetching job details for workflow run: $WORKFLOW_RUN_ID" + + # Check if Linux builds were successful using GitHub API + JOBS_RESPONSE=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/actions/runs/$WORKFLOW_RUN_ID/jobs") + + # Extract Linux build job status + LINUX_X64_SUCCESS=$(echo "$JOBS_RESPONSE" | jq -r '.jobs[] | select(.name | contains("x86_64-unknown-linux-musl")) | .conclusion') + LINUX_ARM64_SUCCESS=$(echo "$JOBS_RESPONSE" | jq -r '.jobs[] | select(.name | contains("aarch64-unknown-linux-musl")) | .conclusion') + + echo "๐Ÿง Linux build status:" + echo " x86_64: $LINUX_X64_SUCCESS" + echo " aarch64: $LINUX_ARM64_SUCCESS" + + # Only proceed if both Linux builds are successful + if [[ "$LINUX_X64_SUCCESS" == "success" ]] && [[ "$LINUX_ARM64_SUCCESS" == "success" ]]; then + linux_builds_success=true + should_build=true + should_push=true + echo "โœ… Both Linux builds successful, proceeding with Docker build" + else + linux_builds_success=false + should_build=false + echo "โŒ Linux builds not both successful, skipping Docker build" + echo " x86_64 status: $LINUX_X64_SUCCESS" + echo " aarch64 status: $LINUX_ARM64_SUCCESS" + fi + + # Extract version info from commit message or use commit SHA + short_sha=$(echo "${{ github.event.workflow_run.head_sha }}" | cut -c1-7) + + # Determine build type based on branch and commit + if [[ "${{ github.event.workflow_run.head_branch }}" == "main" ]]; then + build_type="development" + version="dev-${short_sha}" + elif [[ "${{ github.event.workflow_run.event }}" == "push" ]] && [[ "${{ github.event.workflow_run.head_branch }}" =~ ^refs/tags/ ]]; then + # Tag push + tag_name="${{ github.event.workflow_run.head_branch }}" + version="${tag_name#refs/tags/}" + if [[ "$version" == *"alpha"* ]] || [[ "$version" == *"beta"* ]] || [[ "$version" == *"rc"* ]]; then + build_type="prerelease" + is_prerelease=true + else + build_type="release" + create_latest=true + fi + else + build_type="development" + version="dev-${short_sha}" + fi + + echo "๐Ÿ”„ Build 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 with version input + # Manual trigger input_version="${{ github.event.inputs.version }}" version="${input_version}" should_push="${{ github.event.inputs.push_images }}" + linux_builds_success=true # Assume true for manual builds + should_build=true # Get short SHA short_sha=$(git rev-parse --short HEAD) @@ -183,6 +225,12 @@ jobs: esac fi + # Only proceed if Linux builds were successful + if [[ "$linux_builds_success" != "true" ]]; then + echo "โŒ Linux builds not successful, skipping Docker image build" + should_build=false + fi + echo "should_build=$should_build" >> $GITHUB_OUTPUT echo "should_push=$should_push" >> $GITHUB_OUTPUT echo "build_type=$build_type" >> $GITHUB_OUTPUT @@ -190,6 +238,7 @@ jobs: echo "short_sha=$short_sha" >> $GITHUB_OUTPUT echo "is_prerelease=$is_prerelease" >> $GITHUB_OUTPUT echo "create_latest=$create_latest" >> $GITHUB_OUTPUT + echo "linux_builds_success=$linux_builds_success" >> $GITHUB_OUTPUT echo "๐Ÿณ Docker Build Summary:" echo " - Should build: $should_build" @@ -199,15 +248,16 @@ jobs: echo " - Short SHA: $short_sha" echo " - Is prerelease: $is_prerelease" echo " - Create latest: $create_latest" + echo " - Linux builds success: $linux_builds_success" # Build multi-arch Docker images # Strategy: Build images using pre-built binaries from dl.rustfs.com # Supports both release and dev channel binaries based on build context - # Note: Dockerfile.source is available for local development but not used in CI/CD + # Only runs when Linux builds (x86_64 + aarch64) are successful build-docker: name: Build Docker Images needs: build-check - if: needs.build-check.outputs.should_build == 'true' + if: needs.build-check.outputs.should_build == 'true' && needs.build-check.outputs.linux_builds_success == 'true' runs-on: ubuntu-latest timeout-minutes: 60 steps: diff --git a/Dockerfile b/Dockerfile index 4d7a7724..31999bef 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,9 @@ # Multi-stage build for RustFS production image FROM alpine:latest AS build -# Build arguments -ARG TARGETARCH +# Build arguments - use TARGETPLATFORM for consistency with Dockerfile.source +ARG TARGETPLATFORM +ARG BUILDPLATFORM ARG RELEASE=latest ARG CHANNEL=release @@ -18,11 +19,11 @@ RUN apk add --no-cache \ # Create build directory WORKDIR /build -# Map TARGETARCH to architecture format used in builds -RUN case "${TARGETARCH}" in \ - "amd64") ARCH="x86_64" ;; \ - "arm64") ARCH="aarch64" ;; \ - *) echo "Unsupported architecture: ${TARGETARCH}" && exit 1 ;; \ +# Map TARGETPLATFORM to architecture format used in builds +RUN case "${TARGETPLATFORM}" in \ + "linux/amd64") ARCH="x86_64" ;; \ + "linux/arm64") ARCH="aarch64" ;; \ + *) echo "Unsupported platform: ${TARGETPLATFORM}" && exit 1 ;; \ esac && \ echo "ARCH=${ARCH}" > /build/arch.env