如何在GitHub Actions可复用工作流中处理不同needs与if条件
问题描述
我的GitHub Actions工作流包含多个高度重复的任务,想通过复用逻辑减少冗余,但每个任务的needs和if条件不一样,不知道怎么适配。原任务示例如下:
test-1: name: test-1 strategy: matrix: shard: [1, 2, 3] runs-on: ubuntu-latest timeout-minutes: 10 needs: [test-0] if: | always() && (needs.test-0.result == 'success') steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v3.5.1 with: node-version: '16.x' - name: Set Env variable env: HOST: ${{needs.test-0.outputs.UI_URL}} run: | echo "DB=${{ secrets.DB }}" >> $GITHUB_ENV echo "HOST=$HOST" >> $GITHUB_ENV - name: Install dependencies run: npm install --prefix src/test-1/ - name: Install Playwright run: cd src/test-1/; npx playwright@1.31.2 install chromium - name: Run Playwright run: cd src/test-1/ ; command="npx playwright test --shard=${{ matrix.shard }}/${{ strategy.job-total }} ./playwright/test-1"; $command || $command test-2: name: test-2 strategy: matrix: shard: [1, 2, 3] runs-on: ubuntu-latest timeout-minutes: 10 needs: [test-0] if: | always() && (needs.test-0.result == 'success') steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v3.5.1 with: node-version: '16.x' - name: Set Env variable env: HOST: ${{needs.test-0.outputs.UI_URL}} run: | echo "DB=${{ secrets.DB }}" >> $GITHUB_ENV echo "HOST=$HOST" >> $GITHUB_ENV - name: Install dependencies run: npm install --prefix src/test-2/ - name: Install Playwright run: cd src/test-2/; npx playwright@1.31.2 install chromium - name: Run Playwright run: cd src/test-2/ ; command="npx playwright test --shard=${{ matrix.shard }}/${{ strategy.job-total }} ./playwright/test-2"; $command || $command test-3: name: test-3 strategy: matrix: shard: [1, 2, 3] runs-on: ubuntu-latest timeout-minutes: 10 needs: [test-0, test-4] if: | always() && (needs.test-0.result == 'success') && (needs.test-4.result == 'success') steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v3.5.1 with: node-version: '16.x' - name: Set Env variable env: HOST: ${{needs.test-0.outputs.UI_URL}} run: | echo "DB=${{ secrets.DB }}" >> $GITHUB_ENV echo "HOST=$HOST" >> $GITHUB_ENV - name: Install dependencies run: npm install --prefix src/test-3/ - name: Install Playwright run: cd src/test-3/; npx playwright@1.31.2 install chromium - name: Run Playwright run: cd src/test-3/ ; command="npx playwright test --shard=${{ matrix.shard }}/${{ strategy.job-total }} ./playwright/test-3"; $command || $command
解决方案
针对不同needs和if条件的场景,有两种主流重构方式,核心思路是把重复的步骤逻辑封装,将差异化的needs、if留在任务级别定义:
方案1:使用可复用工作流
把完整的测试任务逻辑(包括策略、运行环境、步骤)封装成可复用工作流,调用时仅传入测试名称、传递必要密钥,needs和if直接在调用方任务中定义。
步骤1:创建可复用工作流文件
在.github/workflows/目录下新建reusable-playwright-test.yml:
name: Reusable Playwright Test on: workflow_call: inputs: test-name: required: true type: string secrets: DB: required: true jobs: playwright-test: name: ${{ inputs.test-name }} strategy: matrix: shard: [1, 2, 3] runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v3.5.1 with: node-version: '16.x' - name: Set Env variable env: HOST: ${{ needs.test-0.outputs.UI_URL }} run: | echo "DB=${{ secrets.DB }}" >> $GITHUB_ENV echo "HOST=$HOST" >> $GITHUB_ENV - name: Install dependencies run: npm install --prefix src/${{ inputs.test-name }}/ - name: Install Playwright run: cd src/${{ inputs.test-name }}/; npx playwright@1.31.2 install chromium - name: Run Playwright run: cd src/${{ inputs.test-name }}/ ; command="npx playwright test --shard=${{ matrix.shard }}/${{ strategy.job-total }} ./playwright/${{ inputs.test-name }}"; $command || $command
步骤2:在主工作流中调用
name: Main Workflow on: [push, pull_request] jobs: test-0: # 保留原test-0的定义,确保输出UI_URL outputs: UI_URL: ${{ steps.deploy.outputs.ui-url }} test-1: needs: [test-0] if: | always() && (needs.test-0.result == 'success') uses: ./.github/workflows/reusable-playwright-test.yml with: test-name: test-1 secrets: DB: ${{ secrets.DB }} test-2: needs: [test-0] if: | always() && (needs.test-0.result == 'success') uses: ./.github/workflows/reusable-playwright-test.yml with: test-name: test-2 secrets: DB: ${{ secrets.DB }} test-3: needs: [test-0, test-4] if: | always() && (needs.test-0.result == 'success') && (needs.test-4.result == 'success') uses: ./.github/workflows/reusable-playwright-test.yml with: test-name: test-3 secrets: DB: ${{ secrets.DB }} test-4: # 保留原test-4的定义
方案2:使用复合动作
仅封装重复的步骤逻辑,任务的strategy、runs-on、needs、if等属性仍在主工作流中定义,适合需要微调任务属性的场景。
步骤1:创建复合动作文件
在.github/actions/目录下新建playwright-test/action.yml:
name: 'Playwright Test Setup & Run' description: '封装Playwright测试的重复步骤' inputs: test-name: description: '测试套件名称' required: true type: string secrets: DB: required: true runs: using: "composite" steps: - uses: actions/checkout@v1 shell: bash - uses: actions/setup-node@v3.5.1 with: node-version: '16.x' - name: Set Env variable env: HOST: ${{ needs.test-0.outputs.UI_URL }} DB_SECRET: ${{ secrets.DB }} run: | echo "DB=$DB_SECRET" >> $GITHUB_ENV echo "HOST=$HOST" >> $GITHUB_ENV shell: bash - name: Install dependencies run: npm install --prefix src/${{ inputs.test-name }}/ shell: bash - name: Install Playwright run: cd src/${{ inputs.test-name }}/; npx playwright@1.31.2 install chromium shell: bash - name: Run Playwright run: cd src/${{ inputs.test-name }}/ ; command="npx playwright test --shard=${{ matrix.shard }}/${{ strategy.job-total }} ./playwright/${{ inputs.test-name }}"; $command || $command shell: bash
步骤2:在主工作流中使用
name: Main Workflow on: [push, pull_request] jobs: test-0: # 保留原test-0的定义,确保输出UI_URL outputs: UI_URL: ${{ steps.deploy.outputs.ui-url }} test-1: name: test-1 strategy: matrix: shard: [1, 2, 3] runs-on: ubuntu-latest timeout-minutes: 10 needs: [test-0] if: | always() && (needs.test-0.result == 'success') steps: - uses: ./.github/actions/playwright-test with: test-name: test-1 secrets: DB: ${{ secrets.DB }} test-2: name: test-2 strategy: matrix: shard: [1, 2, 3] runs-on: ubuntu-latest timeout-minutes: 10 needs: [test-0] if: | always() && (needs.test-0.result == 'success') steps: - uses: ./.github/actions/playwright-test with: test-name: test-2 secrets: DB: ${{ secrets.DB }} test-3: name: test-3 strategy: matrix: shard: [1, 2, 3] runs-on: ubuntu-latest timeout-minutes: 10 needs: [test-0, test-4] if: | always() && (needs.test-0.result == 'success') && (needs.test-4.result == 'success') steps: - uses: ./.github/actions/playwright-test with: test-name: test-3 secrets: DB: ${{ secrets.DB }} test-4: # 保留原test-4的定义
方案对比
- 可复用工作流:封装度更高,调用方代码更简洁,适合所有测试任务属性(如shard数量、运行环境)一致的场景。
- 复合动作:灵活性更强,允许单个任务自定义
strategy、timeout-minutes等属性,适合需要局部微调的场景。
内容的提问来源于stack exchange,提问作者gamechanger17
相关产品推荐
相关产品推荐

