본문 바로가기
source-code/etc

[Github Actions] PR 병합 시, 자동으로 package publish 하기

by mattew4483 2024. 3. 26.
728x90
반응형

Backgrounds

현재 사내 서비스에서 공통적으로 쓰이는 모듈들을 github package로 제공하고 있습니다.

 

git flow 전략에 따라 develop - staging - production 환경으로 구성되어 있으며,

각 개발 사항을 develop branch에 병합한 뒤, staging 환경에서 테스트한 후, production branch에 병합합니다.

 

이때 해당 패키지의 새로운 버전을 publish 하기 위해서는 다음과 같은 과정이 필요합니다.

  1. production 브랜치 내 PR 생성 → review 및 merge
  2. 개발자 local 환경에서 production branch 이동 → build + publish
  3. 해당 배포 사항 직접 공지

 

Problems

위 과정에는 다음과 같은 문제점이 존재합니다.

  • PR 병합과 별개로 build가 이뤄지다 보니 해당 개발자 local 환경에 따라 build 결과물이 달라질 가능성이 존재
  • 패키지 업데이트 시, 매번 직접 publish 명령어를 실행하는 문제
  • 배포 후 slack 등을 통해 직접 알림 하는 문제

 

Solutions

위와 같은 문제점을 해결하기 위해 

build  publish (패키지 업데이트) → release (tag 및 github releaes 생성) 의 과정을 자동화하고자 했습니다.

 

팀 내부적으로

  1. production branch의 결과물을 publish에 사용한다
  2. production branch는 PR을 통해서만 변경사항이 발생한다 

라는 규칙이 존재했기 때문에

 

  • git actions 적용
  • production branch에 PR이 병합될 경우, workflow 실행
  • 해당 workflow를 통해 build + 버전 업 + publish + release 자동화
  • release 시 slack 메시지 전송

의 흐름으로 기존의 publish 과정을 자동화할 수 있으리라 생각했습니다!

 

Implements

1. workflows 생성

workflow를 생성합니다.

 

// publish-release.yml

name: Publish-Release

on:
  pull_request:
    branches: ['production']
    types: [closed]

해당 workflow는

1) production branch에서 2) PR이 close 될 때 실행!

 

이때 정확한 workflow 실행 조건은 PR이 단순 종료된 것이 아닌, 정상적으로 병합되었을 때이므로...

 

// publish-release.yml

name: Publish-Release

on:
  pull_request:
    branches: ['production']
    types: [closed]

jobs:
  build_and_publish:
    runs-on: ubuntu-latest
    if: github.event.pull_request.merged == true

해당 job에 merge 여부 조건을 추가해 줬습니다.

 

2. 기본 steps 작성

// publish-release.yml

name: Publish-Release

on:
  pull_request:
    branches: ['production']
    types: [closed]

jobs:
  build_and_publish:
    runs-on: ubuntu-latest
    if: github.event.pull_request.merged == true
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Set up Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '20'

      - name: Create .npmrc
        run: |
          echo "//npm.pkg.github.com/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc

      - name: Get Env
        run: |
          touch ./.env.production
          echo "${{secrets.PRODUCTION_ENV}}" > ./.env.production
        shell: bash

 

기본 step들을 작성해 준 모습이며, env와 관련된 부분들은(Create .npmrc, Get Env)

2024.03.25 - [source-code/etc] - [Github Actions] Workflows에서 복수개 env variables 사용하기

 

[Github Actions] Workflows에서 복수개 env variables 사용하기

배경 github actions를 통해 사내 npm 패키지를 자동으로 빌드-배포-릴리즈 하고자 했습니다. production branch에 버전과 관련된 PR이 병합되면 패키지 버전 변경 → build → publish → release 를 수행하는 work

23life.tistory.com

위 글을 참고하면 됩니다!

 

3. package 버전 업데이트 하기

현재 패키지 매니저로 yarn을 사용하고 있는데

yarn의 경우(npm도 마찬가지지만) 이전 버전과 동일한 값으로 패키지 업데이트를 할 수 없습니다!

존재하는 버전으로 업데이트 시 에러가 발생!

 

하지만 제가 원하는 것은 PR 병합 시 해당 workflow에서 자동으로 publish를 실행하는 것이었으므로...

  1. PR 생성 시 title에 업데이트할 version을 명시한다 (xxx.xxx.xxx 형태)
  2. PR 병합 후 workflow에서 PR title 속 version 정보를 조회한다
  3. 해당 version 정보로 패키지를 업데이트한다

위 단계를 통해 새로운 버전으로 패키지 업데이트가 이뤄질 수 있도록 했습니다.

즉 다음과 같은 title의 PR이 병합될 경우, 1.3.3으로 패키지 버전이 업데이트 됩니다

 

// publish-release.yml

name: Publish-Release

on:
  pull_request:
    branches: ['production']
    types: [closed]

jobs:
  build_and_publish:
    runs-on: ubuntu-latest
    if: github.event.pull_request.merged == true
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Set up Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '20'

      - name: Create .npmrc
        run: |
          echo "//npm.pkg.github.com/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc

      - name: Get Env
        run: |
          touch ./.env.production
          echo "${{secrets.PRODUCTION_ENV}}" > ./.env.production
        shell: bash
        
      - name: Extract version from commit message
        run: |
          VERSION=$(echo '${{ github.event.pull_request.title }}' | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
          echo "##[set-output name=version;]$VERSION"
        id: extract_version_name


      - name: Update package version
        run: yarn version --new-version ${{ steps.extract_version_name.outputs.version }} --no-git-tag-version

      - name: Publish package
        run: yarn publish

Extract version from commit message step 에서 

해당 PR의 title에 접근(github.event.pull_request.title),

버저닝 관련 문자열을 추출해 version 이라는 변수에 저 정했습니다!

 

이후 Update package version 에서

이전 extract_version_name step에서 저장한 버전을 조회(steps.extract_version_name.outputs.version)한 뒤,

yarn version --new-version 명령어를 통해 해당 값으로 새로운 버전을 업데이트해줬습니다!

(위 명령어 실행 시 package.json의 version 값이 갱신됩니다)

 

이후 yarn publish 명령어를 사용하면, 정상적으로 패키지 배포가 이뤄짐을 확인할 수 있습니다!

// package.json
"scripts": {
    "build:prod": "tsc && DOTENV_CONFIG_PATH=.env.production node -r dotenv/config scripts/esbuild.config.js",
    "prepublish": "yarn build:prod && yarn publish"
},

저 같은 경우 package.json 내 prepublish에 build도 실행했기 때문에

step에서 yarn publish만 실행해 줘도, 새롭게 build 한 결과물이 publish 되었습니다.

(그렇지 않다면, workflow에 publish전 build를 실행하는 step을 추가하면 되겠죠)

 

4. tag 추가 및 release

패키지가 업데이트된 경우, 해당 패키지 사용자들에게 공유가 필요한데

→ github release를 통해 릴리즈 노트를 작성하면 되겠죠!

// publish-release.yml

name: Publish-Release

on:
  pull_request:
    branches: ['production']
    types: [closed]

jobs:
  build_and_publish:
    runs-on: ubuntu-latest
    if: github.event.pull_request.merged == true
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Set up Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '20'

      - name: Create .npmrc
        run: |
          echo "//npm.pkg.github.com/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc

      - name: Get Env
        run: |
          touch ./.env.production
          echo "${{secrets.PRODUCTION_ENV}}" > ./.env.production
        shell: bash
        
      - name: Extract version from commit message
        run: |
          VERSION=$(echo '${{ github.event.pull_request.title }}' | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
          echo "##[set-output name=version;]$VERSION"
        id: extract_version_name


      - name: Update package version
        run: yarn version --new-version ${{ steps.extract_version_name.outputs.version }} --no-git-tag-version

      - name: Publish package
        run: yarn publish
        
      - name: Create release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ steps.extract_version_name.outputs.version }}
          release_name: v${{ steps.extract_version_name.outputs.version }}
          body: ${{ github.event.pull_request.body }}
          draft: false
          prerelease: false

 

Create release 에서 actions/create-release@v1 를 사용해 release를 생성해 준 모습!

이때 해당 릴리즈 노트의 body 값으로, 병합된 PR의 body 데이터를 사용했습니다.

 


slack과 해당 branch를 연동해 release를 구독하면, 업데이트 사항을 알림받을 수도 있겠죠

PR 병합만 했을 뿐인데

build  패키지 버전 업 → publish → tagging 및 releaes note 작성까지 자동으로 완료되었습니다. 성공!

728x90
반응형