프로젝트 관리와 개발 업무가 압도적으로 복잡할 때가 있습니다. 이슈가 산적한 가운데 우선순위를 분류하고, 여러 요청 사항을 관리하는 일이 거대한 벽처럼 느껴질 때도 있죠.

GitLab의 Triage 기능은 이러한 어려움을 해결하는 데 도움이 되는데요. 이 기능은 개발자와 프로젝트 관리자가 효과적으로 이슈를 정리하고, 우선순위를 설정하며, 작업 흐름을 최적화하도록 설계되었습니다. 이로써 매일 수십, 수백 개의 이슈와 Merge Request로 넘쳐나는 대시보드를 체계적으로 관리하도록 지원하죠.

GitLab의 Triage 기능은 ‘이슈 트래커’ 이상의 가치를 제공할 수 있고요. 이 기능은 프로젝트 관리의 효율성을 높이는 데 기여할 수도 있습니다. 이 글에서는 Triage 기능을 자세히 살펴보고요. Triage 기능으로 GitLab에서 이슈 관리를 자동화하고, Triage 작업을 GitLab CI/CD 파이프라인에 통합하는 방법을 알아보려 합니다. Triage 기능을 사용해 이슈 관리를 자동화하면 팀의 반응 시간을 줄이고, 프로젝트 관리 방식을 향상하는 데 도움이 됩니다.

Triage란?

Triage 기능이 관리하는 각 요소 | 인포그랩 GitLab
Triage 기능이 관리하는 각 요소

GitLab의 Triage 기능은 GitLab에서 제공하는 에픽(Epics), 이슈(Issues), Merge Request(MR), 브랜치(Branch) 등을 관리합니다. 이는 복잡한 프로젝트 환경을 관리하도록 설계되었고요. 사용자 정의 규칙을 설정하여 자동으로 이슈를 분류하고, 적절한 레이블을 적용하도록 지원하죠.

특히 Triage 기능은 대규모 프로젝트나 여러 팀의 협업 환경에서 진가를 발휘합니다. 예를 들어, 새로운 기능 요청, 버그 수정, 성능 개선 등 다양한 이슈를 빠르게 식별하고, 적절한 팀 또는 개인에게 이를 할당해 프로젝트 관리의 효율성을 향상하도록 돕죠. 또한 이 도구는 지속적 통합/지속적 배포(CI/CD) 파이프라인과 통합해 개발 과정을 자동화하고 최적화하도록 기여합니다.

Triage 기능 이해하기

Triage 기능의 핵심은 '조건(Conditions)'과 '작업(Actions)'을 설정하는 겁니다. 사용자는 Triage 기능을 사용해 특정 조건(예: 레이블, 마일스톤, 작성자 등)을 기반으로 이슈를 필터링하고, 이에 따라 다양한 작업(예: 레이블 변경, 이슈 닫기, 댓글 추가)이 자동으로 실행되도록 설정할 수 있죠.

Conditions

이슈에 Due Date를 적용하는 설정 중 Conditions 하이라이트 | 인포그랩 GitLab
이슈에 Due Date를 적용하는 설정 중 Conditions 하이라이트

Conditions는 이슈나 Merge Request에 적용될 특정 규칙을 정의하는 기준입니다. 프로젝트 관리자는 Conditions를 사용해 자동화된 프로세스를 설정하고, 이슈를 더 효율적으로 분류하며, 관리할 수 있죠. 이러한 조건은 레이블, 마일스톤, 작성자, 이슈 상태 등 다양한 요소에 기반할 수 있고요. 사용자 필요에 맞게 조건을 맞춤 설정할 수도 있습니다.

예를 들어, 필수 레이블이 붙지 않은 이슈나 특정 레이블이 붙은 이슈에만 작업하도록 Conditions로 설정할 수 있는데요. 이로써 사용자는 이슈에 필수 레이블을 빠르게 적용할 수 있고요. 아울러 조건을 서로 결합하여 더 복잡한 규칙을 생성할 수 있는데요. 예를 들어 'S::3 (심각도)' 레이블을 붙이면, 심각도 레이블에 따라 프로젝트 마감 기한(Due Date)을 설정할 수도 있습니다.

Actions

이슈에 Due Date를 적용하는 설정 중 Actions 하이라이트 | 인포그랩 GitLab
이슈에 Due Date를 적용하는 설정 중 Actions 하이라이트

Actions는 설정한 'Conditions'에 따라 자동으로 실행되는 특정 작업입니다. 이 기능은 프로젝트 관리자와 팀원이 반복 작업을 자동화해 시간을 절약하고, 효율성을 높이도록 지원합니다. Actions는 조건에 부합하는 이슈나 Merge Request에 수행할 수 있는 다양한 작업으로 구성되는데요. 이슈 닫기, 레이블 변경, 자동 댓글 추가, Due Date 설정 작업 등이 여기에 포함됩니다.

예를 들어, 특정 레이블이 붙은 이슈에 자동으로 다른 레이블을 추가하거나, 이슈 관리자에게 미비한 동작과 관련해 코멘트를 보낼 수 있고요. 모든 이슈와 관련해 요약 보고서를 생성할 수도 있죠. Actions는 프로젝트의 다양한 요구사항에 맞춰 맞춤 설정할 수 있고요. 이는 복잡한 프로젝트에서 이슈 관리의 부담을 크게 줄여줍니다. 이 기능은 이슈 해결 과정의 투명성과 추적 가능성을 향상하는 데도 도움이 되고요.

Triage 기능으로 이슈 관리 자동화하기

Triage 기능을 사용하면 이슈를 자동으로 분류하고, 각 이슈에 적절한 레이블을 적용할 수 있는데요. 이 기능으로 이슈 관리를 자동화하는 과정을 순서대로 살펴보겠습니다.

  1. 이슈 규칙을 작성합니다. 이슈 규칙은 아래와 같습니다.

    1. 이슈 관련 실제 작업

      1. ‘중요도’, ‘심각도’, ‘상태’ 등 필수 Label(레이블) 설정
      2. 심각도 레이블에 따른 Due Date(마감일) 설정
      3. Assignee(담당자) 설정 권고
      resource_rules:
      issues:
      rules:
      - name: 필수 레이블 적용
      conditions:
      forbidden_labels:
      - triage
      ruby: |
      !has_severity_label? || !has_priority_label? || !has_status_label?
      state: opened
      actions:
      comment: |
      #{'/label ~status::todo' unless has_status_label?}
      #{'/label ~S::3' unless has_severity_label?}
      #{'/label ~P::3' unless has_priority_label?}

      - name: Due Date 적용
      conditions:
      forbidden_labels:
      - triage
      labels:
      - S::{ 1, 2, 3 }
      ruby: |
      !has_due_date?
      state: opened
      actions:
      comment: |
      #{'/due ' + (Date.today + 1).strftime('%Y-%m-%d') if has_s1_label?}
      #{'/due ' + (Date.today + 2).strftime('%Y-%m-%d') if has_s2_label?}
      #{'/due ' + (Date.today + 3).strftime('%Y-%m-%d') if has_s3_label?}

      - name: Assignee 적용
      conditions:
      ruby: |
      !has_assignee?
      forbidden_labels:
      - triage
      state: opened
      actions:
      comment: |
      {{author}} Assignee가 누락되었습니다.
    2. 이슈 보고서 작성

      resource_rules:
      issues:
      ...(중략)...

      summaries:
      - name: Issue Summary
      rules:
      - name: 2주일 동안 업데이트가 없는 이슈
      conditions:
      date:
      attribute: updated_at
      condition: older_than
      interval_type: days # minutes # days
      interval: 14 # 2 # 14
      state: opened
      forbidden_labels:
      - triage
      limits:
      most_recent: 100
      actions:
      summarize:
      title: 2주일 동안 업데이트가 없는 {{type}}
      item: "- [ ] [{{title}}]({{web_url}}) {{updated_at}}"
      summary: |
      {{title}}를 관리하세요.

      {{items}}

      - name: 제품/서비스 및 팀 Label이 없는 이슈
      conditions:
      forbidden_labels:
      - triage
      - InfoGrab
      - team::devops, team::product, team::success
      state: opened
      limits:
      most_recent: 100
      actions:
      summarize:
      title: 제품/서비스 및 팀 Label이 없는 {{type}}
      item: "- [ ] [{{title}}]({{web_url}}) {{labels}}"
      summary: |
      {{title}}를 관리하세요.

      {{items}}

      - name: Milestone이 없는 이슈
      conditions:
      milestone: none
      state: opened
      forbidden_labels:
      - triage
      limits:
      most_recent: 100
      actions:
      summarize:
      title: Milestone이 없는 {{type}}
      item: "- [ ] [{{title}}]({{web_url}}) {{milestone}}"
      summary: |
      {{title}}를 관리하세요.

      {{items}}

      actions:
      summarize:
      title: |
      #{resource[:type].capitalize} 총 요약
      destination: gitlab-meetup-2023.11/automation/triage
      redact_confidential_resources: false
      summary: |
      {{title}}

      {{items}}

      /label ~triage
  2. Ruby 코드를 작성합니다. 이 코드는 Triage 기능을 확장하기 위해 사용하는데요. 작성한 기능은 아래와 같습니다.

    1. Label 존재 여부 파악

      module Label
      def labels
      resource[:labels]
      end

      def has_severity_label?
      labels.grep(/^S::\d+$/).any?
      end

      def has_s1_label?
      labels.grep(/^S::1+$/).any?
      end

      def has_s2_label?
      labels.grep(/^S::2+$/).any?
      end

      def has_s3_label?
      labels.grep(/^S::3+$/).any?
      end

      def has_priority_label?
      labels.grep(/^P::\d+$/).any?
      end

      def has_status_label?
      labels.grep(/^Status::{todo, doing, reviewing, done}+$/).any?
      end
      end
    2. Assignee 할당 여부 파악

      module Assignee
      def assignee
      resource[:assignees]
      end

      def has_assignee?
      assignee.any?
      end

      end
    3. Due Date 설정 여부 파악

      module Due_date
      def due_date
      resource[:due_date]
      end

      def has_due_date?
      !due_date.nil?
      end

      end

    4. 코드 포함

      Gitlab::Triage::Resource::Context.include(Label, Assignee, Due_date)
  3. 아래 명령어로 Triage를 설치합니다.

    gem install gitlab-triage

    :::note참조 gem 명령으로 패키지를 설치하려면 Ruby를 설치해야 합니다. :::

  4. gitlab-triage 명령어를 실행합니다. 필요한 변수는 아래와 같은데요.

    1. GITLAB_API_TOKEN: 프로젝트에 생성된 이슈를 API로 수정할 권한이 있는 토큰이 필요합니다(예: glpat-qF_P..(중략)..SK).
    2. CI_SERVER_URL: GitLab을 설치해서 사용하면 해당 서버 URL을 입력해야 합니다(예: https://gitlab.dev.infograb.io).
    3. SOURCE: 바라보는 대상이 그룹인지, 프로젝트인지 설정합니다(예: group or project).
    4. SOURCE_ID: 바라보는 대상을 지정합니다(예: Group/<Group or Project>).
    5. TRIAGE_POLICY: 사용할 정책을 지정합니다(예: ./issues/.triage-issue.yml).
    6. TRIAGE_PLUGIN: 사용할 Ruby 코드를 지정합니다(예: ./plugins/plugin.rb).
gitlab-triage --token ${GITLAB_API_TOKEN} --host-url ${CI_SERVER_URL} \
--source ${SOURCE} --source-id ${SOURCE_ID} \
-f ${TRIAGE_POLICY} -r ${TRIAGE_PLUGIN} -d

:::note참조 dry-run 옵션으로 명령을 사용하면, 실제 실행하지 않고 동작을 확인할 수 있습니다. :::

gitlab-triage --dry-run --token ${GITLAB_API_TOKEN} --host-url ${CI_SERVER_URL} \
--source ${SOURCE} --source-id ${SOURCE_ID} \
-f ${TRIAGE_POLICY} -r ${TRIAGE_PLUGIN} -d
  1. 동작을 확인합니다.

    1. 아래는 아무것도 설정하지 않은 이슈입니다.
      GitLab의 해당 이슈 초기 상태 화면 | 인포그랩 GitLab
      GitLab의 해당 이슈 초기 상태 화면

    2. Triage 기능이 동작한 뒤 Label, Due Date, Comment에 자동화가 이뤄진 걸 볼 수 있습니다.
      GitLab에서 Triage 기능을 실행한 후 이슈 상태 화면 | 인포그랩 GitLab
      GitLab에서 Triage 기능을 실행한 후 이슈 상태 화면

  2. Triage 프로젝트에 이슈 요약 보고서가 생성되어 이슈 상태를 한눈에 볼 수 있습니다.

    Triage 기능으로 생성된, 이슈 요약 정보를 담은 GitLab 이슈 페이지 화면 | 인포그랩 GitLab
    Triage 기능으로 생성된, 이슈 요약 정보를 담은 GitLab 이슈 페이지 화면

Triage 작업을 CI/CD 파이프라인에 통합하기

GitLab에서는 Triage 작업을 CI/CD 파이프라인에 통합할 수 있는데요. Triage 작업을 파이프라인으로 구성한 다음, 파이프라인 스케줄러에 등록하면 자동으로 동작합니다. 그 방법을 차례대로 살펴보겠습니다.

파이프라인 작성

파이프라인 코드는 아래와 같습니다. gitlab-triage 도구를 사용하여 이슈를 분류하고요. 코드는 triage-dry-runtriage-run 단계로 구성되어 있습니다. 각 단계는 사용자 정의 변수와 함께 gitlab-triage를 실행하여 TRIAGE_POLICY에 따라 GitLab 그룹 또는 프로젝트의 이슈를 관리합니다.

image: ruby:3.0

stages:
- triage-dry-run
- triage-run

variables:
TRIAGE_PLUGIN: ./plugins/plugin.rb

.dry-run_triage: &dry-run_triage
stage: triage-dry-run
script:
- gem install gitlab-triage
- gitlab-triage --help
- echo $CI_SERVER_URL
- echo $SOURCE
- echo $SOURCE_ID
- echo $TRIAGE_POLICY
- echo $TRIAGE_PLUGIN
- gitlab-triage --dry-run --token ${GITLAB_API_TOKEN} --host-url ${CI_SERVER_URL} --source ${SOURCE} --source-id ${SOURCE_ID} -f ${TRIAGE_POLICY} -r ${TRIAGE_PLUGIN} -d
rules:
- if: '$CI_PIPELINE_SOURCE != "schedule"'

.run_triage: &run_triage
stage: triage-run
script:
- gem install gitlab-triage
- echo ${GITLAB_API_TOKEN}
- gitlab-triage --token ${GITLAB_API_TOKEN} --host-url ${CI_SERVER_URL} --source ${SOURCE} --source-id ${SOURCE_ID} -f ${TRIAGE_POLICY} -r ${TRIAGE_PLUGIN} -d
when: manual
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
- when: manual

dry-run:triage:issue:
<<: *dry-run_triage
variables:
SOURCE: <group or project>
SOURCE_ID: <group>/<group or project>
TRIAGE_POLICY: issues/.triage-issue.yml

run:triage:issue:
<<: *run_triage
variables:
SOURCE: <group or project>
SOURCE_ID: <group>/<group or project>
TRIAGE_POLICY: issues/.triage-issue.yml

파이프라인은 아래와 같이 생성됩니다.

GitLab에 생성된 Triage 작업 관련 파이프라인 화면 | 인포그랩 GitLab
GitLab에 생성된 Triage 작업 관련 파이프라인 화면

triage-run Job을 실행하면 앞서 본 것과 같이 Label, Due Date, Comment에 자동화가 이뤄지고요. 앞서 봤던 이슈 요약 페이지가 여기서도 생성된 걸 확인할 수 있습니다.

GitLab에서 Triage 기능이 실행된 후 이슈 상태 화면 | 인포그랩 GitLab
GitLab에서 Triage 기능이 실행된 후 이슈 상태 화면

Triage 기능으로 생성된, 이슈 요약 정보를 담은 GitLab 이슈 페이지 화면 | 인포그랩 GitLab
Triage 기능으로 생성된, 이슈 요약 정보를 담은 GitLab 이슈 페이지 화면

파이프라인 스케줄 설정

스케줄 기능을 사용하면 해당 파이프라인을 주기적으로 실행할 수 있습니다. 설정 내용은 아래 이미지와 같고요. 매주 평일 오후 12시마다 파이프라인이 동작하도록 설정했습니다.

GitLab의 파이프라인 스케줄 설정 화면 | 인포그랩 GitLab
GitLab의 파이프라인 스케줄 설정 화면

아래 이미지를 보면 파이프라인 스케줄이 잘 동작하는 걸 확인할 수 있습니다. Triage 작업이 파이프라인 스케줄에 따라 자동으로 동작하는 거죠.

GitLab의 파이프라인 스케줄 동작 확인 화면 | 인포그랩 GitLab
GitLab의 파이프라인 스케줄 동작 확인 화면

맺음말

지금까지 GitLab의 Triage 기능을 활용해 이슈 관리를 개선하는 방법을 살펴보았습니다. Triage 기능은 이슈 관리를 넘어서 에픽, MR, 브랜치 관리 등 다양한 영역에 효과적으로 활용할 수 있는데요. 이 기능을 사용하면 프로젝트 관리의 효율성을 크게 향상할 수 있고요. 파이프라인과 통합하면 Triage 기능의 효과는 더 커질 수 있습니다.

저는 지난 11월 ‘GitLab 코리아 밋업’에서 Triage 기능을 활용해 이슈, MR을 관리하는 방법과 Code Review Bot과 통합해 Value Stream Management(VSM)를 개선하는 방법을 발표, 시연한 바 있는데요. 이또한 Triage 기능의 가능성을 확장한 예시가 될 수 있습니다. Triage 기능을 효과적으로 활용하는 분이 계시다면 여러분의 경험과 활용법을 인포그랩에도 공유해 주세요.

인포그랩은 GitLab 및 DevOps에 대한 맞춤 기술 지원을 제공합니다. GitLab(Omnibus/Cloud Native Hybrid) 구축 관련한 지원이 필요하시면 문의하기 로 연락 주십시오.