Действия Github: как использовать стратегию / матрицу со скриптом

У меня есть рабочий процесс, в котором должен быть цикл для шагов, который идеально подходит для стратегии / матрицы.

Единственная проблема в том, что стратегия / матрица должна быть установлена ​​константой.

Можно ли использовать матрицу стратегий с выводом скрипта?

name: tests
on: [push]

jobs:
  test:
    runs-on: ${{ ubuntu-latest }}
    strategy:
      fail-fast: false
      matrix:
        versions: $(./script.py)

    steps:
    - uses: actions/checkout@v2
 .......

person Ramon Medeiros    schedule 30.01.2020    source источник


Ответы (2)


Вы можете сгенерировать матрицу в JSON в одном задании и установить ее для второго задания.

GitHub добавил эту функцию в апреле: https://github.blog/changelog/2020-04-15-github-actions-new-workflow-features/

Пример рабочего процесса

name: build
on: push
jobs:
  job1:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
    - id: set-matrix
      run: echo "::set-output name=matrix::{\"include\":[{\"project\":\"foo\",\"config\":\"Debug\"},{\"project\":\"bar\",\"config\":\"Release\"}]}"
  job2:
    needs: job1
    runs-on: ubuntu-latest
    strategy:
      matrix: ${{fromJson(needs.job1.outputs.matrix)}}
    steps:
    - run: echo ${{ matrix.project }}
    - run: echo ${{ matrix.config }}

Первое задание устанавливает для выходной переменной matrix значение JSON, которое содержит две конфигурации:

{
  "include": [
    {
      "project": "foo",
      "config": "Debug"
    },
    {
      "project": "bar",
      "config": "Release"
    }
  ]
}

Эквивалент в .yml:

  job2:
    strategy:
      matrix:
        include:
        - project: foo
          config: Debug
        - project: bar
          config: Release

Не забудьте экранировать кавычки \" и вывести JSON в одну строку.

Более сложный пример рабочего процесса

Он обнаруживает измененные files и запускает задание сборки для измененных каталогов. Если имя каталога начинается с имени ОС, он использует это имя как добавляемое.

name: Build
on: [push, pull_request]

jobs:

  generate-matrix:
    name: Generate matrix for build
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - uses: actions/checkout@v2
      - name: Check changed files
        id: diff
        run: |
          # See https://github.community/t/check-pushed-file-changes-with-git-diff-tree-in-github-actions/17220/10
          if [ $GITHUB_BASE_REF ]; then
            # Pull Request
            git fetch origin $GITHUB_BASE_REF --depth=1
            export DIFF=$( git diff --name-only origin/$GITHUB_BASE_REF $GITHUB_SHA )
            echo "Diff between origin/$GITHUB_BASE_REF and $GITHUB_SHA"
          else
            # Push
            git fetch origin ${{ github.event.before }} --depth=1
            export DIFF=$( git diff --name-only ${{ github.event.before }} $GITHUB_SHA )
            echo "Diff between ${{ github.event.before }} and $GITHUB_SHA"
          fi
          echo "$DIFF"
          # Escape newlines (replace \n with %0A)
          echo "::set-output name=diff::$( echo "$DIFF" | sed ':a;N;$!ba;s/\n/%0A/g' )"
      - name: Set matrix for build
        id: set-matrix
        run: |
          # See https://stackoverflow.com/a/62953566/11948346
          DIFF="${{ steps.diff.outputs.diff }}"
          JSON="{\"include\":["

          # Loop by lines
          while read path; do
            # Set $directory to substring before /
            directory="$( echo $path | cut -d'/' -f1 -s )"

            if [ -z "$directory" ]; then
              continue # Exclude root directory
            elif [ "$directory" == docs ]; then
              continue # Exclude docs directory
            elif [ "$path" == *.rst ]; then
              continue # Exclude *.rst files
            fi

            # Set $os. "ubuntu-latest" by default. if directory starts with windows, then "windows-latest"
            os="ubuntu-latest"
            if [ "$directory" == windows* ]; then
              os="windows-latest"
            fi

            # Add build to the matrix only if it is not already included
            JSONline="{\"directory\": \"$directory\", \"os\": \"$os\"},"
            if [[ "$JSON" != *"$JSONline"* ]]; then
              JSON="$JSON$JSONline"
            fi
          done <<< "$DIFF"

          # Remove last "," and add closing brackets
          if [[ $JSON == *, ]]; then
            JSON="${JSON%?}"
          fi
          JSON="$JSON]}"
          echo $JSON

          # Set output
          echo "::set-output name=matrix::$( echo "$JSON" )"

  build:
    name: Build "${{ matrix.directory }}" on ${{ matrix.os }}
    needs: generate-matrix
    strategy:
      matrix: ${{fromJson(needs.generate-matrix.outputs.matrix)}}
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v2
      - name: Build
        run: |
          cd ${{ matrix.directory }}
          echo "${{ matrix.directory }} ${{ matrix.os }}"
person ArtemSBulgakov    schedule 17.07.2020

Добавив новый пример, это был действительно полезный ответ. Спасибо @ArtemSBulgakov!

Здесь используется Github strategy.matrix из Github Actions с fromJson для сбора только каталогов в запросе на слияние с изменениями и выполнения обзора синтаксиса и обзора формата Terraform с помощью https://github.com/dflook/terraform-github-actions

---
name: Check Syntax
on: [pull_request]

jobs:
  generate-matrix:
    name: Generate matrix for build
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: Check changed files
        id: diff
        run: |
          # See https://github.community/t/check-pushed-file-changes-with-git-diff-tree-in-github-actions/17220/10
          export DIFF=$( git diff --dirstat=files,0,cumulative ${{ github.event.pull_request.base.sha }} | awk -F ' ' '{print $2}' )
          echo "$DIFF"
          # Escape newlines (replace \n with %0A)
          echo "::set-output name=diff::$( echo "$DIFF" | sed ':a;N;$!ba;s/\n/%0A/g' )"
      - name: Set matrix for build
        id: set-matrix
        run: |
          # See https://stackoverflow.com/a/62953566/11948346
          DIFF="${{ steps.diff.outputs.diff }}"
          JSON="{\"tfpaths\":["

          # Loop by lines
          while read path; do
          # Add item to the matrix only if it is not already included
          JSONline="\"$path\","
          if [[ "$JSON" != *"$JSONline"* ]]; then
          JSON="$JSON$JSONline"
          fi
          done <<< "$DIFF"

          # Remove last "," and add closing brackets
          if [[ $JSON == *, ]]; then
          JSON="${JSON%?}"
          fi
          JSON="$JSON]}"
          echo $JSON
          # Set output
          echo "::set-output name=matrix::$( echo "$JSON" )"

  validate:
    name: Check Terraform syntax on "${{ matrix.tfpaths }}"
    needs: generate-matrix
    strategy:
      matrix: ${{fromJson(needs.generate-matrix.outputs.matrix)}}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: terraform validate
        uses: dflook/terraform-validate@v1
        with:
          path: ${{ matrix.tfpaths }}

  check-format:
    name: Check Terraform format on "${{ matrix.tfpaths }}"
    needs: generate-matrix
    strategy:
      matrix: ${{fromJson(needs.generate-matrix.outputs.matrix)}}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: terraform fmt
        uses: dflook/terraform-fmt-check@v1
        with:
          path: ${{ matrix.tfpaths }}

person julian-alarcon    schedule 04.11.2020