rules를 사용하여 작업 실행 시기 지정

Tier: Free, Premium, Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated

파이프라인에서 작업을 포함하거나 제외시키기 위해 rules를 사용하세요.

첫 번째 매칭될 때까지 규칙이 순서대로 평가됩니다. 매칭되는 항목을 찾으면, 작업은 설정에 따라 파이프라인에서 포함되거나 제외됩니다.

규칙에서 dotenv 변수를 사용할 수 없습니다. 규칙은 작업 실행 전에 평가되기 때문입니다.

향후 키워드 개선에 대한 논의는 규칙을 개선하는 에픽에서 진행 중이며, 누구나 제안이나 요청을 추가할 수 있습니다.

rules 예제

다음 예제는 작업이 특정 경우에만 실행되도록 if를 사용하여 정의합니다:

job:
  script: echo "Hello, Rules!"
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      when: manual
      allow_failure: true
    - if: $CI_PIPELINE_SOURCE == "schedule"
  • 파이프라인이 병합 요청용일 경우, 첫 번째 규칙이 매칭되어 작업은 병합 요청 파이프라인에 다음과 같은 속성으로 추가됩니다:
    • when: manual (수동 작업)
    • allow_failure: true (수동 작업이 실행되지 않아도 파이프라인은 계속 실행됨)
  • 파이프라인이 병합 요청용이 아닌 경우, 첫 번째 규칙은 매칭되지 않고 두 번째 규칙이 평가됩니다.
  • 파이프라인이 예약된 파이프라인용인 경우, 두 번째 규칙이 매칭되어 작업이 예약된 파이프라인에 추가됩니다. 속성이 정의되지 않았으므로 기본값으로 추가됩니다:
    • when: on_success (기본값)
    • allow_failure: false (기본값)
  • 나머지 경우에는 규칙이 매칭되지 않아 작업은 다른 파이프라인에 추가되지 않습니다.

또는 몇 가지 경우에 작업을 제외한 후 나머지 경우에만 실행하도록 규칙 집합을 정의할 수도 있습니다:

job:
  script: echo "Hello, Rules!"
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      when: never
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - when: on_success
  • 파이프라인이 병합 요청용인 경우, 작업은 파이프라인에 추가되지 않습니다.
  • 파이프라인이 예약된 파이프라인용인 경우, 작업은 파이프라인에 추가되지 않습니다.
  • 나머지 경우에는 when: on_success와 함께 작업이 파이프라인에 추가됩니다.

경고: 최종 규칙으로 when 절을 사용하면(단, when: never를 제외한 경우), 동시에 두 개의 파이프라인이 시작될 수 있습니다. 푸시 파이프라인과 병합 요청 파이프라인은 동일한 이벤트(오픈된 병합 요청용 소스 브랜치로의 푸시)에 의해 트리거될 수 있습니다. 자세한 내용은 중복 파이프라인 방지를 참조하세요.

예약된 파이프라인용 작업 실행

파이프라인이 예약되었을 때에만 작업이 실행되도록 구성할 수 있습니다. 예를 들어:

job:on-schedule:
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
  script:
    - make world

job:
  rules:
    - if: $CI_PIPELINE_SOURCE == "push"
  script:
    - make build

이 예제에서 make world은 예약된 파이프라인에서 실행되고, make build는 브랜치와 태그 파이프라인에서 실행됩니다.

브랜치가 비어 있는 경우 작업 건너뛰기

rules:changes:compare_to를 사용하여 브랜치가 비어 있는 경우 작업을 건너뛸 수 있으며, 이는 CI/CD 리소스를 절약합니다. 이 구성은 브랜치를 기본 브랜치와 비교하는데, 브랜치가:

  • 변경된 파일이 없으면 작업을 실행하지 않음
  • 변경된 파일이 있으면 작업을 실행함

예를 들어, main을 기본 브랜치로 하는 프로젝트의 경우:

job:
  script:
    - echo "이 작업은 빈 브랜치에 대해서만 실행합니다"
  rules:
    - if: $CI_COMMIT_BRANCH
      changes:
        compare_to: 'refs/heads/main'
        paths:
          - '**/*'

이 작업의 규칙은 현재 브랜치의 모든 파일과 경로(**/*)를 main 브랜치와 비교합니다. 이 규칙이 매칭되면 브랜치의 파일에 변경 사항이 있을 때만 작업을 실행하게 됩니다.

사전 정의된 변수를 사용하는 일반적인 if

rules:if 절은 특히 사전 정의 CI/CD 변수와 함께 자주 사용됩니다, 특히 CI_PIPELINE_SOURCE 사전 정의 변수와 함께 사용됩니다.

다음 예제는 작업을 예약된 파이프라인이나 푸시 파이프라인(브랜치 또는 태그에 대한)으로 수동 작업으로 실행되도록 설정합니다(when: on_success는 기본값입니다). 그 외의 파이프라인 유형에 작업을 추가하지 않습니다.

job:
  script: echo "Hello, Rules!"
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: manual
      allow_failure: true
    - if: $CI_PIPELINE_SOURCE == "push"

다음 예제는 작업을 병합 요청 파이프라인과 예약된 파이프라인에서 when: on_success로 실행하며, 다른 파이프라인 유형에서는 실행하지 않습니다.

job:
  script: echo "Hello, Rules!"
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_PIPELINE_SOURCE == "schedule"

자주 사용되는 다른 if 절:

  • if: $CI_COMMIT_TAG: 태그에 변경 사항이 푸시되었을 때
  • if: $CI_COMMIT_BRANCH: 어떤 브랜치에 변경 사항이 푸시되었을 때
  • if: $CI_COMMIT_BRANCH == "main": main에 변경 사항이 푸시되었을 때
  • if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH: 기본 브랜치에 변경 사항이 푸시되었을 때. 여러 프로젝트에 같은 구성을 사용하고 싶을 때 사용합니다.
  • if: $CI_COMMIT_BRANCH =~ /regex-expression/: 커밋 브랜치가 정규 표현식과 일치할 때
  • if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_COMMIT_TITLE =~ /Merge branch.*/: 커밋 브랜치가 기본 브랜치이고, 커밋 메시지 제목이 정규 표현식과 일치할 때. 예를 들어 병합 커밋의 기본 커밋 메시지는 Merge branch로 시작합니다.
  • if: $CUSTOM_VARIABLE == "value1": 사용자 정의 변수 CUSTOM_VARIABLE이 정확히 value1일 때

특정 파이프라인 유형에서만 작업 실행

미리 정의된 CI/CD 변수를 사용하여 rules에 결합하여 작업이 실행되어야 하는 파이프라인 유형을 선택할 수 있습니다.

다음 표에서 사용할 수 있는 일부 변수 및 변수가 제어할 수 있는 파이프라인 유형을 나열합니다.

변수 브랜치 태그 머지 요청 예약
CI_COMMIT_BRANCH    
CI_COMMIT_TAG     예 (예약된 파이프라인이 태그에 대해 구성되어 있는 경우)
CI_PIPELINE_SOURCE = push    
CI_PIPELINE_SOURCE = schedule      
CI_PIPELINE_SOURCE = merge_request_event      
CI_MERGE_REQUEST_IID      

예를 들어, 작업을 머지 요청 파이프라인 및 예약 파이프라인에만 실행되도록 구성하려면:

job1:
  script:
    - echo
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_PIPELINE_SOURCE == "schedule"
    - if: $CI_PIPELINE_SOURCE == "push"
      when: never

CI_PIPELINE_SOURCE 미리 정의된 변수

CI_PIPELINE_SOURCE 변수를 사용하여 다음 파이프라인 유형에 작업을 추가할 시기를 제어할 수 있습니다.

설명
api 파이프라인 API에 의해 트리거된 파이프라인에 대해.
chat GitLab ChatOps 명령을 사용하여 생성된 파이프라인에 대해.
external GitLab 이외의 CI 서비스를 사용할 때.
external_pull_request_event GitHub의 외부 풀 리퀘스트가 생성되거나 업데이트될 때.
merge_request_event 머지 요청이 생성되거나 업데이트될 때 생성된 파이프라인에 대해. 머지 요청 파이프라인, 머지 결과 파이프라인, 머지 트레인을 활성화하는 데 필요합니다.
ondemand_dast_scan DAST 온디맨드 스캔 파이프라인에 대해.
ondemand_dast_validation DAST 온디맨드 유효성 검사 파이프라인에 대해
parent_pipeline 상위/하위 파이프라인에 의해 트리거된 파이프라인에 대해. 자식 파이프라인 구성에서 사용하여 상위 파이프라인에 의해 트리거될 수 있습니다.
pipeline API 및 CI_JOB_TOKEN을 사용하여 생성된 다중 프로젝트 파이프라인에 대해.
push 브랜치 및 태그를 포함한 Git 푸시 이벤트에 의해 트리거된 파이프라인에 대해.
schedule 예약 파이프라인에 대해.
security_orchestration_policy 보안 오케스트레이션 정책 파이프라인에 대해
trigger 트리거 토큰을 사용하여 생성된 파이프라인에 대해.
web GitLab UI의 새 파이프라인을 선택하여 생성된 파이프라인에 대해. 프로젝트의 빌드 > 파이프라인 섹션에서 생성됩니다.
webide WebIDE를 사용하여 생성된 파이프라인에 대해

이 값들은 파이프라인 API 엔드포인트를 사용할 때 source 매개변수로 반환되는 값과 동일합니다.

복잡한 규칙

여러 rules 키워드인 if, changes, exists를 동일한 규칙에서 모두 사용할 수 있습니다. 규칙은 모든 포함된 키워드가 true로 평가될 때에만 true로 평가됩니다.

예를 들어:

docker build:
  script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
  rules:
    - if: $VAR == "string value"
      changes:  # 다음 경로 중 하나라도 수정된 파일과 일치하면 작업을 포함하고 when:manual로 설정합니다.
        - Dockerfile
        - docker/scripts/**/*
      when: manual
      allow_failure: true

만약 Dockerfile 파일이나 /docker/scripts에 있는 파일 중 하나가 변경되었으면서, 그리고 $VAR == “string value”이면, 작업은 수동으로 실행되고 실패해도 괜찮습니다.

&&||와 함께 괄호를 사용하여 더 복잡한 변수 표현식을 만들 수 있습니다.

job1:
  script:
    - echo 이 규칙은 괄호를 사용합니다.
  rules:
    - if: ($CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH == "develop") && $MY_VARIABLE

중복 파이프라인 피하기

작업이 rules을 사용하면 커밋을 브랜치로 푸시하는 것과 같은 단일 작업은 여러 파이프라인을 트리거할 수 있습니다. 실수로 그러한 유형의 파이프라인을 트리거하려면 명시적으로 규칙을 구성할 필요가 없습니다.

중복 파이프라인을 피하려면 다음을 수행할 수 있습니다:

  • workflow를 사용하여 실행될 수 있는 파이프라인 유형을 지정합니다.
  • 규칙을 작성하여 작업이 매우 구체적인 경우에만 실행되도록 하고 최종 when 규칙을 피합니다:

    job:
      script: echo "이 작업은 중복 파이프라인을 생성하지 않습니다!"
      rules:
        - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    

그외에도 중복 파이프라인을 피하기 위해 작업 규칙을 변경하여 푸시(브랜치) 파이프라인이나 머지 요청 파이프라인 중 하나를 회피할 수 있습니다. 그러나 workflow: rules 없이 - when: always 규칙을 사용하면 여전히 파이프라인 경고가 표시됩니다.

예를 들어, 다음은 중복 파이프라인을 트리거하지 않지만 workflow: rules 없이 권장되지는 않습니다:

job:
  script: echo "이 작업은 중복 파이프라인을 생성하지 않습니다!"
  rules:
    - if: $CI_PIPELINE_SOURCE == "push"
      when: never
    - when: always

또한 동일한 파이프라인에서 only/except 작업과 rules 작업을 섞어서 사용하지 마십시오. YAML 오류를 일으키지는 않지만 only/exceptrules의 다른 기본 동작으로 인해 해결하기 어려운 문제가 발생할 수 있습니다:

job-with-no-rules:
  script: echo "이 작업은 브랜치 파이프라인에서 실행됩니다."

job-with-rules:
  script: echo "이 작업은 머지 요청 파이프라인에서 실행됩니다."
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

브랜치에 푸시되는 모든 변경 사항에 대해 중복 파이프라인이 실행됩니다. 하나의 브랜치 파이프라인에서는 하나의 작업(job-with-no-rules)을 실행하고 또 다른 머지 요청 파이프라인에서는 다른 작업(job-with-rules)을 실행합니다. 규칙이 없는 작업은 기본적으로 except: merge_requests에 따라 동작하므로 job-with-no-rules은 머지 요청을 제외한 모든 상황에서 실행됩니다.

다양한 작업에서 규칙 재사용하기

!reference 태그를 사용하여 다른 작업에서 규칙을 재사용하세요. !reference 규칙을 일반 작업 정의 규칙과 결합할 수 있습니다. 예를 들어:

.default_rules:
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
      when: never
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH

job1:
  rules:
    - !reference [.default_rules, rules]
  script:
    - echo "이 작업은 기본 브랜치에 대해 실행되지만 스케줄에 대해서는 실행되지 않습니다."

job2:
  rules:
    - !reference [.default_rules, rules]
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
  script:
    - echo "이 작업은 기본 브랜치에 대해 실행되지만 스케줄에 대해서는 실행되지 않습니다."
    - echo "또한 병합 요청에 대해서도 실행됩니다."

CI/CD 변수 표현식

rules:if와 변수 표현식을 사용하여 작업이 파이프라인에 추가되는 시점을 제어하세요.

등호 연산자 ==!=를 사용하여 변수를 문자열과 비교할 수 있습니다. 단일 따옴표와 이중 따옴표 둘 다 유효합니다. 변수는 비교의 왼쪽에 있어야 합니다. 예를 들어:

  • if: $VARIABLE == "some value"
  • if: $VARIABLE != "some value"

두 변수의 값을 비교할 수 있습니다. 예를 들어:

  • if: $VARIABLE_1 == $VARIABLE_2
  • if: $VARIABLE_1 != $VARIABLE_2

null 키워드와 변수를 비교하여 해당 변수가 정의되었는지 확인할 수 있습니다. 예를 들어:

  • if: $VARIABLE == null
  • if: $VARIABLE != null

변수가 정의되었지만 비어있는지 확인할 수 있습니다. 예를 들어:

  • if: $VARIABLE == ""
  • if: $VARIABLE != ""

변수가 정의되고 비어있지 않은지를 확인하려면 표현식에서 변수 이름만 사용하세요. 예를 들어:

  • if: $VARIABLE

변수를 정규 표현식과 비교하기

=~!~ 연산자를 사용하여 변수 값에 정규 표현식 매칭을 할 수 있습니다. 정규 표현식을 사용하여 변수 패턴 매칭을 하면 RE2 정규 표현식 문법을 사용합니다.

표현식은 다음과 같을 때 true로 평가됩니다:

  • =~를 사용하여 일치하는 항목을 찾은 경우
  • !~를 사용하여 일치하는 항목을 찾지 못한 경우

예를 들어:

  • if: $VARIABLE =~ /^content.*/
  • if: $VARIABLE !~ /^content.*/

또한:

  • /./와 같은 단일 문자 정규 표현식은 지원되지 않으며 잘못된 표현식 구문 오류를 발생시킵니다.
  • 기본적으로 패턴 매칭은 대소문자를 구분합니다. 패턴을 대소문자 구분하지 않게 만들려면 i 플래그 수정자를 사용하세요. 예를 들어: /pattern/i.
  • 정규 표현식을 사용하여 태그나 브랜치 이름만 일치시킬 수 있습니다. 제공된 경우 리포지토리 경로는 항상 글자 그대로 일치합니다.
  • 전체 패턴은 반드시 /로 둘러싸여 있어야 합니다. 예를 들어, 모든 태그 이름 또는 브랜치 이름을 일치시키려면 issue-/.*/를 사용할 수 없지만 /issue-.*/을 사용할 수는 있습니다.
  • @ 기호는 참조의 리포지토리 경로를 나타냅니다. 정규 표현식으로 @ 문자를 일치시키려면 16진수 글자 코드 일치 \x40를 사용해야 합니다.
  • 정규 표현식이 태그 이름이나 브랜치 이름의 부분 문자열만 일치시키지 않도록 하려면 닻 ^$를 사용하세요. 예를 들어, /^issue-.*//^issue-/과 동일하지만, /issue/severe-issues라는 브랜치에도 일치합니다.

변수에 정규 표현식 저장하기

  • GitLab 15.0에서 도입, 기본값으로 비활성화된 ci_fix_rules_if_comparison_with_regexp_variable이라는 플래그와 함께.
  • GitLab 15.1에서 일반적으로 사용 가능, 기능 플래그 ci_fix_rules_if_comparison_with_regexp_variable이 제거되었습니다.

=~!~ 표현식의 오른쪽에 있는 변수는 정규 표현식으로 평가됩니다. 정규 표현식은 반드시 앞뒤로 슬래시(/)로 둘러싸여 있어야 합니다. 예를 들어:

variables:
  pattern: '/^ab.*/'

regex-job1:
  variables:
    teststring: 'abcde'
  script: echo "'abcde'가 /^ab.*/ 패턴과 일치하기 때문에 이 작업이 실행됩니다."
  rules:
    - if: '$teststring =~ $pattern'

regex-job2:
  variables:
    teststring: 'fghij'
  script: echo "'fghi'가 /^ab.*/ 패턴과 일치하지 않기 때문에 이 작업이 실행되지 않습니다."
  rules:
    - if: '$teststring =~ $pattern'

정규 표현식 내의 변수는 해결되지 않습니다. 예를 들어:

variables:
  string1: 'regex-job1'
  string2: 'regex-job2'
  pattern: '/$string2/'

regex-job1:
  script: echo "'string1' 변수가 정규 표현식 내에서 해결되지 않았기 때문에 이 작업이 실행되지 않습니다."
  rules:
    - if: '$CI_JOB_NAME =~ /$string1/'

regex-job2:
  script: echo "'pattern' 변수 내의 'string2' 변수가 해결되지 않았기 때문에 이 작업이 실행되지 않습니다."
  rules:
    - if: '$CI_JOB_NAME =~ $pattern'

변수 표현식을 결합하기

&& (그리고) 또는 || (또는)을 사용하여 여러 표현식을 결합할 수 있습니다. 예를 들어:

  • $VARIABLE1 =~ /^content.*/ && $VARIABLE2 == "something"
  • $VARIABLE1 =~ /^content.*/ && $VARIABLE2 =~ /thing$/ && $VARIABLE3
  • $VARIABLE1 =~ /^content.*/ || $VARIABLE2 =~ /thing$/ && $VARIABLE3

연산자의 우선순위는 Ruby 2.5 표준를 따르므로 &&||보다 먼저 평가됩니다.

소괄호를 사용하여 표현식을 그룹화할 수 있습니다. 소괄호는 &&||보다 우선순위가 높으므로 먼저 평가되고 결과가 나머지 표현식에 사용됩니다.

복잡한 조건을 만들려면 괄호를 중첩하여 사용하세요. 그리고 가장 안쪽의 표현식이 먼저 평가됩니다. 예를 들어:

  • ($VARIABLE1 =~ /^content.*/ || $VARIABLE2) && ($VARIABLE3 =~ /thing$/ || $VARIABLE4)
  • ($VARIABLE1 =~ /^content.*/ || $VARIABLE2 =~ /thing$) && $VARIABLE3
  • $CI_COMMIT_BRANCH == "my-branch" || (($VARIABLE1 == "thing" || $VARIABLE2 == "thing") && $VARIABLE3)

문제 해결

=~를 사용한 정규 표현식 매칭에서 예상치 못한 동작

=~ 문자를 사용할 때, 비교의 오른쪽에는 항상 유효한 정규 표현식이 포함되어 있는지 확인하십시오.

비교의 오른쪽이 / 문자로 둘러싸인 유효한 정규 표현식이 아닌 경우, 표현식은 예상치 않은 방식으로 평가됩니다. 이 경우 비교는 왼쪽이 오른쪽의 부분 문자열인지 확인합니다. 예를 들어, "23" =~ "1234"는 true로 평가되며, 이는 "23" =~ /1234/의 반대로, false로 평가됩니다.

파이프라인을 이러한 동작에 의존하도록 구성해서는 안 됩니다.