Github Actions - Using a matrix

DongHwan·2022년 5월 2일
0

Github Actions

목록 보기
6/7

Github Actions으로 CI를 진행할 떄, 여러가지 환경에 대해 테스트를 진행할 필요가 있을 수 있다. 예를들면 노드 버전이 14일 때와 16일 때 모두를 테스트하고 싶을 수 있다. 이런 경우 matrix strategy를 사용하여 같은 Job에 대해 여러 환경에서 테스트를 진행해볼 수 있다. 또한, matrix strategy가 적용된 Job에서는 matrix Context와 strategy Context를 사용하여 필요한 정보들을 가져올 수 있다.

Matrix Strategy

Matrix Strategy란?

매트릭스 전략은 하나의 Job 정의만 사용하면서 여러가지 변수들의 조합을 사용한 실행이 가능하도록 해준다. 예를들자면 앞에서 얘기했던 것처럼 하나의 Job에 대해 여러 OS 환경이나 언어 버전을 사용하여 테스트를 진행할 수 있게 해준다.

Using a Matrix Strategy

jobs.<job_id>.strategy.matrix 구문을 사용하여 여러가지의 Job 설정의 매트릭스를 정의할 수 있다. 매트릭스 내부에서 배열을 원소로 가지는 한개 이상의 변수들을 설정해줄 수 있다. 이렇게 변수를 설정해주면, 정의된 변수들의 가능한 모든 조합의 수만큼 Job을 실행해준다. 아래 예시를 보자.

jobs:
  test-job:
  	runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [14, 16]
    steps:
      - use: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}

test-job의 matrix strategy로 node-version 변수에 원소가 14와 16인 배열을 할당한 것을 볼 수 있다. 그렇다면 matrix에 정의된 변수들의 모든 가능한 조합의 수는 node-version이 14인 경우와 16인 경우로 2개이다. 즉, test-job은 총 2번 실행되며, 각 실행에서 node-version에는 14와 16이 들어가게 된다.

가장 아랫부분을 보면 ${{ matrix.node-version }} 구문을 볼 수 있는데, 이것이 matrix Context가 사용된 부분이다. matrix Context는 matrix.<변수명>의 형식으로 사용하며, 이를 통해 각 실행에서 변수에 할당된 값을 가져올 수 있다.

jobs:
  test-job:
  	runs-on: ${{ matrix.os }}
    strategy:
      matrix:
      	os: [ubuntu-latest, window-latest]
        node-version: [14, 16]
    steps:
      - use: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}

이번 예시에서는 2개의 변수에 대해 각각 길이가 2인 배열을 할당해주었다. 이 경우 가능한 조합의 수는 다음과 같다.

  • os: ubuntu-latest, node-version: 14
  • os: ubuntu-latest, node-version: 16
  • os: window-latest, node-version: 14
  • os: window-latest, node-version: 16

즉, 경우의 수는 총 4이기에 test-job은 총 4번 실행된다. 또한 각 실행에서 osnode-version에는 위 4가지 경우가 각각 할당된다.

include

jobs.<job_id>.strategy.matrix.include 구문을 사용하여 매트릭스 설정을 확장하거나 새로운 설정을 추가할 수 있다. include는 오브젝트의 배열을 값으로 가진다.

include 배열의 각 오브젝트는 key: value의 형식의 페어들을 가진다. 이 페어들과 기존 매트릭스 조합을 비교한 뒤, 기존 매트릭스 조합에 페어들을 추가하거나 혹은 새로운 매트릭스 조합을 만든다. 그 기준은 다음과 같다.

  • 만약 기존 매트릭스 조합에 key가 있고 value 역시 같은 조합이 있다면 해당되는 조합에만 추가된다.
    • 같은 key를 가지는 페어들이 여럿 있다면, 해당되는 모든 페어들의 value 역시 같아야 추가된다.
    • 만약 같은 key를 가지는 페어들 중 하나라도 value가 다르다면 추가되지 않는다.
  • 만약 기존 매트릭스 조합의 key가 해당 오브젝트의 모든 페어들의 key와 일치하는 것이 전혀 없다면, 모든 기존 매트릭스 조합에 대해 추가된다.
  • 만약 기존 매트릭스 조합에 key가 있는데, value가 같은 조합이 전혀 없다면 새로운 매트릭스 조합으로 추가된다.
    • key, value가 모두 같은 페어가 있더라도, 단 한개의 페어라도 위 조건에 걸리면 해당된다.
    • 기존 매트릭스 조합의 수가 10개일 때, 이 10개에 대해 모두 해당해야 새롭게 추가된다.

또한 기존의 매트릭스 조합의 값은 덮어쓰지 않지만, include로 인해 추가된 값은 덮어써질 수 있다.

예시 1

strategy:
  matrix:
    피자: [페퍼로니, 불고기]
    사이드: [감자튀김, 치즈볼]
    include:
      - 음료: 콜라
      - 피자: 불고기
        할인: 10%
      - 피자: 하와이안

설명만으로는 이해하기 어려우니 예시를 보자. 우선 기존 매트릭스 조합의 모든 값은 다음과 같다.

  • 피자: 페퍼로니, 사이드: 감자튀김
  • 피자: 페퍼로니, 사이드: 치즈볼
  • 피자: 불고기, 사이드: 감자튀김
  • 피자: 불고기, 사이드: 치즈볼

이제 include 구문을 보자. include는 배열의 앞부터 차례대로 값들을 검사한다. 그러니 우선 음료: 콜라부터 검사를 해보자. 앞에서 설명했던 기준 중 2번째에 속한다. 해당 오브젝트의 모든 페어들의 키, 즉 음료와 일치하는 키가 기존 매트릭스 조합에는 없다. 그러니 모든 기존 매트릭스 조합에 추가한다.

  • 피자: 페퍼로니, 사이드: 감자튀김, 음료: 콜라
  • 피자: 페퍼로니, 사이드: 치즈볼, 음료: 콜라
  • 피자: 불고기, 사이드: 감자튀김, 음료: 콜라
  • 피자: 불고기, 사이드: 치즈볼, 음료: 콜라

이제 피자: 불고기, 할인: 10%를 보자. 이번에는 첫번째 기준에 속한다. 피자: 불고기라는 페어가 기존 매트릭스 조합 중 3번째와 4번째 조합에 일치하는 것을 알 수 있다. 즉, 해당되는 조합에 추가한다.

  • 피자: 페퍼로니, 사이드: 감자튀김, 음료: 콜라
  • 피자: 페퍼로니, 사이드: 치즈볼, 음료: 콜라
  • 피자: 불고기, 사이드: 감자튀김, 음료: 콜라, 할인: 10%
  • 피자: 불고기, 사이드: 치즈볼, 음료: 콜라, 할인: 10%

마지막으로 피자: 하와이안를 보자. 이 경우는 3번째 기준에 속한다. 피자라는 키는 기존 매트릭스 조합이 가지고 있지만, 하와이안이라는 값을 가지는 조합은 전혀 없다. 그러니 새로운 매트릭스 조합으로 추가한다.

  • 피자: 페퍼로니, 사이드: 감자튀김, 음료: 콜라
  • 피자: 페퍼로니, 사이드: 치즈볼, 음료: 콜라
  • 피자: 불고기, 사이드: 감자튀김, 음료: 콜라, 할인: 10%
  • 피자: 불고기, 사이드: 치즈볼, 음료: 콜라, 할인: 10%
  • 피자: 하와이안

위 조합이 최종 결과물이다. 이런식으로 include를 사용하여 기존 매트릭스 조합에 특정 값을 추가하거나 아예 새로운 조합을 추가할 수 있다.

예시 2

strategy:
  matrix:
    fruit: [apple, pear]
    animal: [cat, dog]
    include:
      - color: green
      - color: pink
        animal: cat
      - fruit: apple
        shape: circle
      - fruit: banana
      - fruit: banana
        animal: cat

조금 더 어려운 예시를 보자. 기존 매트릭스 조합은 다음과 같다.

  • fruit: apple, animal: cat
  • fruit: apple, animal: dog
  • fruit: pear, animal: cat
  • fruit: pear, animal: dog

color: green은 2번째 경우이다. 모든 조합에 대해 추가된다.

  • fruit: apple, animal: cat, color: green
  • fruit: apple, animal: dog, color: green
  • fruit: pear, animal: cat, color: green
  • fruit: pear, animal: dog, color: green

color: pink, animal: cat은 첫번째 경우이다. animalcat인 조합에만 추가된다. 또한 앞에서 설명한 것처럼 include로 인해 추가된 값의 경우 덮어쓰기가 가능하기 때문에 기존 color: green을 덮어쓴다.

  • fruit: apple, animal: cat, color: pink
  • fruit: apple, animal: dog, color: green
  • fruit: pear, animal: cat, color: pink
  • fruit: pear, animal: dog, color: green

fruit: apple, shape: circle은 첫번째 경우이다.

  • fruit: apple, animal: cat, color: pink, shape: circle
  • fruit: apple, animal: dog, color: green, shape: circle
  • fruit: pear, animal: cat, color: pink
  • fruit: pear, animal: dog, color: green

fruit: banana은 세번째 경우이다. 일치하는 것이 전혀 없다. 그러니 새로운 조합으로 추가해주자.

  • fruit: apple, animal: cat, color: pink, shape: circle
  • fruit: apple, animal: dog, color: green, shape: circle
  • fruit: pear, animal: cat, color: pink
  • fruit: pear, animal: dog, color: green
  • fruit: banana

fruit: banana, animal: cat 역시도 세번째 경우이다. 이전 단계에서 추가된 fruit: banana와 일치하지만, 이것은 기존의 매트릭스 조합이 아닌 추가된 매트릭스 조합이다. include는 새롭게 추가된 매트릭스 조합 혹은 값이 아닌 기존의 매트릭스 조합에 대해서만 비교한다. 그래서 세번째 경우로 판단하는 것이다.

  • fruit: apple, animal: cat, color: pink, shape: circle
  • fruit: apple, animal: dog, color: green, shape: circle
  • fruit: pear, animal: cat, color: pink
  • fruit: pear, animal: dog, color: green
  • fruit: banana
  • fruit: banana, animal: cat

최종 결과물은 위 조합이 된다.

예시 3

strategy:
  matrix:
    피자: [페퍼로니, 불고기]
    include:
      - 음료: 콜라
      - 피자: 불고기
        음료: 사이다
      - 할인: 50%
        음료: 콜라

바로 이전 예시에서 언급했던 것처럼 include의 비교는 기존 매트릭스 조합에 대해 수행한다. 이것에 대해 예시를 통해 조금 더 알아보자.

  • 피자: 페퍼로니, 음료: 콜라
  • 피자: 불고기, 음료: 사이다

음료: 콜라피자: 불고기, 음료: 사이다를 거치고 난 이후의 매트릭스 조합은 위와 같다. 그렇다면 이후에 할인: 50%, 음료: 콜라를 검사하면 어떻게 될까? 위 매트릭스 조합을 사용하여 검사한다면 음료가 콜라인 조합에 할인: 50%가 추가될 것이다.

  • 피자: 페퍼로니, 음료: 콜라, 할인: 50%
  • 피자: 불고기, 음료: 콜라, 할인: 50%

그러나 실제 실행 결과는 위와 같다. 기존 매트릭스 조합에는 음료라는 키를 가지는 페어가 없기 때문에 2번째 경우에 해당되고, 모든 조합에 대해 페어가 추가된다. 또한, 새롭게 추가된 값은 덮어쓰기가 된다고 했으니 음료: 사이다는 덮어쓰기되어 음료: 콜라가 된다.

include는 기존 매트릭스 조합에 대해서만 검사한다는 점을 주의해두자.

exclude

exclude는 include와 반대로 기존 매트릭스 조합들 중 일부를 제거하는데 사용한다. exclude에 정의된 오브젝트와 부분적으로 일치하는 조합이 있다면, 해당 조합을 제거한다.

strategy:
  matrix:
    os: [macos-latest, windows-latest]
    version: [12, 14, 16]
    environment: [staging, production]
    exclude:
      - os: macos-latest
        version: 12
        environment: production
      - os: windows-latest
        version: 16

위 예시에서 기존 조합의 개수는 12개이다. 그러나 exclude에 정의된 오브젝트와 일치하는 조합을 제거하면 9개가 된다.

우선 첫번째 오브젝트와 완벽히 일치하는 조합을 1개 제거할 수 있다.
다음으로 두번째 오브젝트인 os: windows-latest, version: 16과 부분적으로 일치하는 2개의 조합을 제거할 수 있다.

참고로 includeexclude가 완료된 이후에 진행된다. 즉, exclude를 통해 제거된 조합이 include 단계에서 추가될 수도 있다.

max-parallel

strategy:
  max-parallel: 2
  matrix:
    os: [ubuntu-latest, window-latest]
    node-version: [14, 16]

기본적으로는 Github는 가용한 모든 러너를 사용해서 Job들을 병렬적으로 수행한다. 하지만 matrix strategy가 사용된 Job에서는 max-parallel을 통해 동시에 실행할 Job의 개수를 설정해줄 수 있다. 위 예시에서는 동시에 실행될 수 있는 Job의 개수가 최대 2개이다.

fail-fast

strategy:
  fail-fast: true
  matrix:
    os: [ubuntu-latest, window-latest]
    node-version: [14, 16]

fail-fasttrue로 설정되어 있는 경우, 어느 한 Job이 실패했을 때 다른 모든 Job들을 캔슬시킨다. 기본값은 true이다.

Context

이렇게 설정한 Matrix Strategy들을 워크플로우 파일에서 다루기 위해서는 Context를 사용하면 된다. matrix Context와 strategy Context를 사용해서 매트릭스 전략으로 설정한 값들을 활용할 수 있다.

matrix Context

이전에 설명했던 것처럼 matrix.<변수명>의 형식으로 사용할 수 있다. 각 Job 실행마다 할당된 값들이 저장되어 있다.

strategy Context

strategy Context는 현재 실행되고 있는 Job의 매트릭스 실행 전략에 관한 정보들이 들어있다.

  • strategy.fail-fast
  • strategy.max-parallel
  • strategy.job-index
  • strategy.job-total

위 4가지 속성을 가지고 있으며, fail-fastmax-parallel은 각각 설정한 값들이 들어가있다.

job-index는 매트릭스 조합들에서 현재 실행되고 있는 job의 인덱스이다. 첫번째 job의 인덱스는 0이다. job-total은 매트릭스 조합의 총 개수이다.

총총

Matrix Strategy는 여러가지 환경에서 테스트를 진행해볼 필요가 있을 때 매우 좋은 기능이 될 것이다. 잘 활용하여 중복된 코드를 줄이고 더 편리한 CI 환경을 구축해보자.

profile
날 어떻게 한줄로 소개해~

0개의 댓글