지라의 배포(deployments) 기능을 사용해볼까요?

깃헙 액션과 지라 배포를 연동해보았습니다. 언제, 어떤 기능이, 어느 서버에 배포됐는지 한 눈에 볼 수 있어서 좋아요.

지라의 배포(deployments) 기능을 사용해볼까요?

왜 사용하게 됐나?

깃헙을 지라와 연동한 후 프로젝트의 왼쪽 메뉴바에 '배포'라는 탭이 보이기 시작했습니다. 뭘까 싶어서 눌러봤지만 다음과 같은 안내 화면만 덩그러니 보였습니다.

어쩌라는거지

그래서 관심을 두지 않다가(더 살펴보기엔 귀찮아서요), 어느날 PM께서 이런 요구사항을 이야기하셨어요.

언제 어떤 기능이 어느 서버에 배포됐는지 알고 싶어요.

사실 깃헙에서 머지된 PR들을 살펴보면 어느정도 파악할 수는 있지만, 일목요연하게 보기 어렵긴 하죠. 그래서 지라의 배포 탭에 다시 관심을 가져보았습니다.

지라 배포 기능 소개

지라의 배포 기능을 알아보니 연동을 하고 나면 이런 멋진 화면을 볼 수 있다고 유혹하더라고요.

출처: https://support.atlassian.com/jira-software-cloud/docs/enable-deployments/

평소 궁금하기도 했고 프로젝트 가시성에도 도움을 주리라 생각해서 그리고 화면도 예뻐보이니 연동 작업을 해보기로 결정했습니다.

인덴트의 CI/CD 흐름도

인덴트의 CI/CD는 깃헙 액션을 사용하고 있으며, 아주 간단하게 표현해보면 아래 그림과 같은 흐름으로 진행됩니다. 새 PR을 만들면 CI에서 유닛 테스트 등을 진행하고요. 이 PR을 develop 브랜치와 main 브랜치에 머지하면, 개발 서버와 운영 서버에 자동으로 배포합니다.

PR을 만들면 CI까지만 실행하고, develop과 main 브랜치에 머지하면 CI 통과 후 해당 서버에 자동으로 배포됩니다.

이 흐름 마지막에 한 단계(초록색 원)를 추가하여 지라에 빌드 결과와 배포된 커밋 목록을 보내주기로 했습니다.

마지막 단계에서 빌드 결과와 배포된 커밋 목록을 전달합니다.

Github CI 설정

# 저희가 사용하는 깃헙 액션 파일에서 배포 연동에 관련된 내용만 추렸습니다.
name: Build And Deployment

on:
  push:
    branches:
      - main
      - develop

jobs:
  build:
    name: Build
    runs-on: ubuntu-latest
    steps:
      ...
      - name: Parse Jira Keys from Commit
        id: jira_keys
        if: always()
        uses: HighwayThree/jira-extract-issue-keys@master
        with:
          is-pull-request: ${{ github.event_name == 'pull_request' }}
          parse-all-commits: ${{ github.event_name == 'push' }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          
      - name: Confirm Deploy State and Jira Key Values
        if: always()
        run: |
          echo "BUILD_STATE=successful" >> $GITHUB_ENV
          echo "Jira Keys: ${{steps.jira_keys.outputs.jira-keys}}"
          
      - name: Failed Build
        if: failure()
        run: echo "BUILD_STATE=failed" >> $GITHUB_ENV

      - name: Push Build Info to Jira
        if: steps.jira_keys.outputs.jira-keys != ''
        uses: rohit-gohri/jira-ci-cd-integration@v0
        with:
          state: ${{ env.BUILD_STATE }}
          issue: "${{ steps.jira_keys.outputs.jira-keys }}"
          jira_instance: indentcorp
          client_id: ${{ secrets.JIRA_CLIENT_ID }}
          client_secret: ${{ secrets.JIRA_CLIENT_SECRET }}

  jira_dev_deployment:
    name: Jira Dev Deployment
    runs-on: ubuntu-latest
    if: github.event_name == 'push' &&  github.ref == 'refs/heads/develop'
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      ...
      - name: Parse Jira Keys from All Commits
        id: jira_keys
        if: always()
        uses: HighwayThree/jira-extract-issue-keys@master
        with:
          is-pull-request: ${{ github.event_name == 'pull_request' }}
          parse-all-commits: ${{ github.event_name == 'push' }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Confirm Deploy State and Jira Key Values
        if: always()
        run: |
          echo "BUILD_STATE=successful" >> $GITHUB_ENV
          echo "Jira Keys: ${{steps.jira_keys.outputs.jira-keys}}"

      - name: Failed Build
        if: failure()
        run: echo "BUILD_STATE=failed" >> $GITHUB_ENV

      - name: Push Deployment Info to Jira
        if: steps.jira_keys.outputs.jira-keys != ''
        uses: rohit-gohri/jira-ci-cd-integration@v0
        with:
          state: ${{ env.BUILD_STATE }}
          environment: dev
          issue: "${{ steps.jira_keys.outputs.jira-keys }}"
          jira_instance: indentcorp
          client_id: ${{ secrets.JIRA_CLIENT_ID }}
          client_secret: ${{ secrets.JIRA_CLIENT_SECRET }}

  jira_prod_deployment:
    name: Jira Prod Deployment
    runs-on: ubuntu-latest
    if: github.event_name == 'push' &&  github.ref == 'refs/heads/main'
    steps:
      ...
      - name: Parse Jira Keys from All Commits
        id: jira_keys
        if: always()
        uses: HighwayThree/jira-extract-issue-keys@master
        with:
          is-pull-request: ${{ github.event_name == 'pull_request' }}
          parse-all-commits: ${{ github.event_name == 'push' }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Confirm Deploy State and Jira Key Values
        if: always()
        run: |
          echo "BUILD_STATE=successful" >> $GITHUB_ENV
          echo "Jira Keys: ${{steps.jira_keys.outputs.jira-keys}}"

      - name: Failed Build
        if: failure()
        run: echo "BUILD_STATE=failed" >> $GITHUB_ENV

      - name: Push Deployment Info to Jira
        if: steps.jira_keys.outputs.jira-keys != ''
        uses: rohit-gohri/jira-ci-cd-integration@v0
        with:
          state: ${{ env.BUILD_STATE }}
          environment: production
          issue: "${{ steps.jira_keys.outputs.jira-keys }}"
          jira_instance: indentcorp
          client_id: ${{ secrets.JIRA_CLIENT_ID }}
          client_secret: ${{ secrets.JIRA_CLIENT_SECRET }}

빌드, 배포 때마다 지라에 관련 이슈 목록을 보내주기 위해, 깃헙 액션 마켓에서 찾은 두 액션을 활용했습니다.

jira-extract-issue-keys는  특정 커밋들의 메시지를 분석하여 이슈 번호를 추출하는 액션입니다. 이 액션이 PR에 대해 작동하는 경우(is-pull-request가 true일 때), PR에 속하는 모든 커밋에서 이슈 번호를 찾습니다.

jira-ci-cd-integration은 이번 배포에 포함할 이슈 번호들과 배포 결과를 지라에 전달합니다. 배포 결과를 계산하기 위해 배포 과정의 앞부분에서 BUILD_STATEsuccessful로  지정해두고, 유닛 테스트나 배포 과정에 문제가 생긴 경우(failure()) BUILD_STATEfailed로 변경했습니다.

jira_instance는 저희 회사가 사용하는 지라 클라우드 주소(https://indentcorp.atlassian.net)의 앞부분입니다.

environment는 배포 결과를 보내줄 때만 설정했습니다.

client_idclient_secret지라 설정 → 앱 → Oauth 자격 증명에서 발급할 수 있습니다.

톱니바퀴 아이콘을 누른 후 '앱' 메뉴를 선택하고
왼쪽 메뉴에서 'OAuth 자격 증명' 메뉴를 선택한 후 '새 자격 증명 만들기' 버튼을 누릅니다

앱 이름에는 원하는 이름을, 서버 기준 url에는 깃헙 조직의 주소를(이게 중요한지는 모르겠습니다), 권한 중에는 배포, 빌드, 개발 정보를 선택하고 '생성' 버튼을 누릅니다.

이렇게 생성한 client_idclient_secret을 깃헙의 Secrets에 각각 JIRA_CLIENT_ITJIRA_CLIENT_SECRET이라는 이름으로 저장합니다. (저는 저희 회사의 모든 저장소에 적용하려고 Organization의 Secrets에 저장했습니다.)

짜잔!

이제 깃헙 액션이 실행될 때마다 그 결과가 지라에 보내집니다. CI 빌드 정보와 배포 정보는 해당 이슈의 오른쪽 부분에 나타납니다.

개발 정보에 커밋과 풀 리퀘스트 외에 빌드 항목이 생겼고, 릴리즈 항목도 보입니다

빌드 항목을 클릭하면, 빌드 이력과 상세 정보를 확인할 수 있습니다.

빌드 항목을 클릭해보면 빌드 이력과 성공 여부가 보입니다. (빌드 이름이 좀 엉망이고, 테스트 결과를 제대로 연동하지 않았음을 글 쓰면서 깨달았네요.)

빌드 탭 오른쪽의 '배포' 항목을 클릭하면, 배포 이력과 상세 정보를 확인할 수 있습니다.

배포 항목을 클릭해보면 배포 이력과 성공 여부가 보입니다.

그리고 프로젝트 메뉴의 '배포' 항목을 눌러보면 이렇게 일목요연하게 배포 내역을 확인할 수도 있습니다.

아름다운 배포 내역

정리

이렇게 해서 PM님의 요구사항을 해결했습니다.

언제 어떤 기능이 어느 서버에 배포됐는지 알고 싶어요.

연동해놓고 보니 PM 뿐만 아니라 개발자들도 배포 내역 확인하기가 훨씬 편해졌고요. 각 배포에 대한 통계도 지라가 계산해주어서, 개선점을 더 빨리 파악할 수 있었습니다.

몇 번 배포하다보면 자동으로 계산되는 인사이트

삽질기

이렇게 연동하기까지 몇 가지 삽질을 겪었는데요. (한 번에 잘 됐다면 굳이 글로 정리하지 않았겠죠.)

1. App Token은 OAuth 키가 아니었다.

지라와 깃헙을 처음 연동할 때는 앱 토큰을 발급하여 간단히 연동할 수 있었는데요. 그래서 이번 작업을 진행할 때도 깃헙 액션들이 요구하는 client_id를 제 지라 아이디(회사 이메일)로 설정하고 client_secret에는 깃헙 연동용 앱 토큰을 넣어보았지만 안 되더라고요. (지라 문서가 서버용과 클라우드용으로 나뉘어 있어서 정보 찾기가 더 까다롭더군요.)

OAuth 키는 지라 설정 → 앱 → Oauth 자격 증명에서 발급할 수 있습니다. (위에서 그림과 함께 더 자세하게 설명해두었습니다.)

2. 제대로 작동하지 않는 깃헙 액션들

깃헙 액션 마켓플레이스에서 jira deployment로 검색해보면 몇 가지 액션들이 보일텐데요. 처음에는 설정하기 간편해보이는 것들을 사용해봤지만 지라 클라우드와는 잘 연동되지 않는 등 다양한 문제를 겪었습니다. 지라 클라우드를 사용하신다면 jira-ci-cd-integration를 사용하세요. 깃헙이 아닌 다른 CI 도구도 지원하더라고요. (실행 파일을 도커 이미지로 만들어두었네요.)

커밋 메시지에서 이슈 키를 검색하는 액션은 다른 것들도 잘 작동했지만 처음부터 사용했던 jira-extract-issue-keys를 계속 사용하게 되었고요. (사실 jira-extract-issue-key 개발자가 만든 jira-upload-deployment-infojira-upload-build-info도 사용해봤는데, 제가 테스트했을 땐 지라 인증이 계속 실패해서 포기했습니다.)

3. 커밋 메시지의 중요성

평소 커밋 메시지 관리를 잘 하지 않았다면, 배포 정보를 연동하기 위해 커밋 메시지에 신경쓰기가 귀찮을 수도 있습니다. 배포를 했는데 지라에 데이터가 제대로 보이지 않아서 확인해보니, 커밋 메시지에 이슈 키를 적지 않아서였다면 얼마나 허무하겠어요? 의미 있는 커밋 메시지를 남기는 연습을 평소에 해두시면 좋답니다. (배포 정보 연동과 상관 없이도 좋은 습관이니까요.)

결론

인덴트에서는 회의 결과나 비즈니스 방향성이 노션이나 슬랙에 잘 공유되는 편입니다. '공유'를 핵심 가치로 삼고 있기 때문인데요. 하지만 배포 이력이나 현황 같은 정보는 공유하기가 쉽지 않았고, 공유하더라도 파편화되어 공유한 의미가 퇴색되기 마련이었어요. 하지만 이번에 지라와 깃헙 액션 덕에 손쉽게 대시보드를 구성할 수 있었습니다.

이 작업을 하면서, 정보란 단순히 '공유'하기만 해서는 모든 구성원에게 자연스레 전달되지 않는다는 점을 다시 한 번 배웠네요. 앞으로도 인덴트의 구성원으로써 동료에게 도움이 되는 '공유'라는 가치를 지키고자 계속 노력하려 합니다.