You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于文件夹变更触发Github Actions构建指定.NET项目Docker镜像

实现按需构建变更项目的Docker镜像

要实现仅构建变更文件夹对应的.NET项目,核心思路是先检测代码变更路径,再动态生成过滤后的构建矩阵(matrix),避免全量执行所有项目的构建任务。以下是具体实现方案和优化建议:

方案一:动态过滤构建矩阵(推荐)

通过修改你的prep任务,先检测变更路径,再过滤原始矩阵中未变更的项目,只输出需要构建的项目矩阵。

1. 修改prep任务,添加变更检测与矩阵过滤

prep:
  runs-on: ubuntu-latest
  outputs:
    matrix: ${{ steps.set-matrix.outputs.matrix }}
  steps:
    - name: 检出代码
      uses: actions/checkout@v4
      with:
        fetch-depth: 0  # 必须拉取完整历史,才能对比所有变更

    - name: 检测变更的项目路径
      id: changed-files
      uses: tj-actions/changed-files@v41
      with:
        files: |
          src/ServiceA/**
          src/ServiceB/**
          src/ServiceC/**
          src/Shared/**  # 若有共享类库,需加入检测

    - name: 生成过滤后的构建矩阵
      id: set-matrix
      run: |
        # 定义原始的全量项目矩阵(替换成你实际的项目配置)
        original_matrix='{
          "include": [
            {"name": "ServiceA", "context": "src/ServiceA", "dockerfile": "src/ServiceA/Dockerfile", "docker-image-name": "${{ env.REGISTRY }}/servicea"},
            {"name": "ServiceB", "context": "src/ServiceB", "dockerfile": "src/ServiceB/Dockerfile", "docker-image-name": "${{ env.REGISTRY }}/serviceb"},
            {"name": "ServiceC", "context": "src/ServiceC", "dockerfile": "src/ServiceC/Dockerfile", "docker-image-name": "${{ env.REGISTRY }}/servicec"}
          ]
        }'

        # 将变更路径转为数组
        changed_paths=(${{ steps.changed-files.outputs.all_changed_files }})

        # 标记是否有共享类库变更(若有)
        shared_changed=false
        for path in "${changed_paths[@]}"; do
          if [[ "$path" == "src/Shared"/* ]]; then
            shared_changed=true
            break
          fi
        done

        # 处理过滤逻辑:共享类库变更则全量构建,否则仅构建变更项目
        if [ "$shared_changed" = true ] || [ ${#changed_paths[@]} -eq 0 ]; then
          # 无变更或共享类库变更时,使用全量矩阵
          filtered_matrix="$original_matrix"
        else
          # 过滤出变更路径对应的项目
          filtered_include=()
          for item in $(echo "$original_matrix" | jq -r '.include[] | @base64'); do
            decoded=$(echo "$item" | base64 --decode)
            context=$(echo "$decoded" | jq -r '.context')
            # 检查当前项目路径是否在变更列表中
            for path in "${changed_paths[@]}"; do
              if [[ "$path" == "$context"/* ]]; then
                filtered_include+=("$decoded")
                break
              fi
            done
          done
          filtered_matrix=$(printf '%s\n' "${filtered_include[@]}" | jq -s '{include: .}')
        fi

        # 输出过滤后的矩阵
        echo "matrix=$filtered_matrix" >> "$GITHUB_OUTPUT"

2. 优化原构建任务

原build-and-push-image任务无需大幅修改,但可以优化依赖还原步骤,仅针对当前项目还原,提升速度:

build-and-push-image:
    name: "BUILD: ${{ matrix.name }}"
    runs-on: ubuntu-latest
    needs: prep
    strategy:
      matrix: ${{fromJson(needs.prep.outputs.matrix)}}
    permissions:
      contents: read
      packages: write

    steps:
      - name: 检出代码
        uses: actions/checkout@v4
      
      - name: 登录容器仓库
        uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: 提取Docker元数据(标签、标签)
        id: meta
        uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
        with:
          images: ${{ matrix.docker-image-name }}
          flavor: latest=true
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
      - name: 还原当前项目依赖
        shell: bash
        run: dotnet restore ${{ matrix.context }}
        
      - name: 构建并推送Docker镜像
        uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
        with:
          context: ${{matrix.context }}
          file: ${{ matrix.dockerfile }}
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

方案二:为单个任务添加路径过滤(简单但效率略低)

如果不想修改矩阵生成逻辑,也可以直接在构建任务中添加路径条件,仅当对应项目路径有变更时才执行任务:

build-and-push-image:
    name: "BUILD: ${{ matrix.name }}"
    runs-on: ubuntu-latest
    needs: prep
    strategy:
      matrix: ${{fromJson(needs.prep.outputs.matrix)}}
    permissions:
      contents: read
      packages: write
    # 仅当项目路径有变更或共享类库变更时执行
    if: |
      contains(steps.changed-files.outputs.all_changed_files, matrix.context) ||
      contains(steps.changed-files.outputs.all_changed_files, 'src/Shared')
    steps:
      - name: 检出代码
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      
      - name: 检测变更路径
        id: changed-files
        uses: tj-actions/changed-files@v41
        with:
          files: |
            src/**
      
      # 后续步骤同原任务...

注意:此方案会创建所有矩阵任务,但仅执行符合条件的任务,资源利用率略低于动态过滤矩阵方案。

额外优化建议

  1. Dockerfile缓存优化:将dotnet restore步骤移入Dockerfile,利用Docker层缓存减少重复还原时间:

    FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
    WORKDIR /src
    COPY ["ServiceA.csproj", "."]
    RUN dotnet restore "./ServiceA.csproj"
    COPY . .
    RUN dotnet build "ServiceA.csproj" -c Release -o /app/build
    
    FROM build AS publish
    RUN dotnet publish "ServiceA.csproj" -c Release -o /app/publish /p:UseAppHost=false
    
    FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
    WORKDIR /app
    COPY --from=publish /app/publish .
    ENTRYPOINT ["dotnet", "ServiceA.dll"]
    
  2. 手动全量构建支持:添加workflow_dispatch触发方式,允许手动触发全量构建:

    on:
      push:
        branches: [ main ]
      pull_request:
        branches: [ main ]
      workflow_dispatch:
        inputs:
          full_build:
            description: '是否执行全量构建'
            required: false
            default: 'false'
            type: boolean
    

    然后在prep任务的过滤逻辑中添加:

    if [ "${{ github.event.inputs.full_build }}" = "true" ]; then
      filtered_matrix="$original_matrix"
    elif [ "$shared_changed" = true ] || [ ${#changed_paths[@]} -eq 0 ]; then
      # 原逻辑...
    fi
    

内容的提问来源于stack exchange,提问作者Niranjan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 06:37:07