NPM 패키지 배포 자동화 w/Github Action

Jiwoo JEONG·2023년 1월 8일
2

개요

새롭게 이직한 회사는 npm package를 통해 디자인 시스템을 개발/배포/관리를 하고 있었다.
11월 React Native Seoul 정기 meet-up에 팀 동료들과 함께 참여하였고 fastlane을 통한 React Native 배포 자동화에 관한 발표를 듣고 디자인 시스템 패키지만이라도 자동 배포가 되었으면 좋겠다는 생각을 했다. 그리고 이전 회사에서 github action을 통해 NextJS build check 자동화를 구축해본 기억이 있어 github action을 통해 npm package 배포 자동화를 구축하는 방법론이 떠올라 적용 시켜보기로 하였다.

구현

구상

  • 기존 디자인 시스템의 큰 흐름은
    1. build를 통해 배포할 dist 디렉터리를 만든다.
    2. npm publish를 통해 세팅 되어 있는 npm package repository에 패키지를 배포한다.

    github action에서도 기존에 package.json에 script를 명령어로 사용할 수 있기 때문에 package.json의 명령어를 통해 배포 흐름을 만들 생각이다.

  • patch, minor, major 버저닝이 있어서 patch 버전 배포에 대해서는 develop 브랜치에 머지되면 자동으로 patch 버전을 하나 올려서 배포한다. minor, major에 대해서는 github action을 통해 배포하는 동료가 직접 버전을 입력할 수 있도록 할 것이다.

실제 구현

# github action name 
name: Auto Publish - patch update

# develop 브랜치에 push 되면 자동 patch update를 한다는 구현
on:
  push:
    branches: [ develop ]

# 실제 실행 구현부
jobs:
  # build 환경
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    strategy:
      matrix:
        node-version: [16.13.1]
    # 실행할 순서    
    steps:
      # github action에서 NodeJS 세팅을 위한 actions/setup-node@v2 action을 사용
      - uses: actions/checkout@v2
      - name: Set up NodeJS ${{ matrix.node-version }}
        uses: actions/setup-node@v2
        with:
          node-version: ${{ matrix.node-version }}
          registry-url: https://registry.npmjs.org/
      # yarn을 사용하기에 yarn을 global install하고 install dependencies 
      - name : Install Dependencies
        run: |
          npm install -g yarn
          npm install --legacy-peer-deps --save-dev --ignore-scripts install-peers
          yarn install
      # npm version을 patch 명령어를 통해 올리고, 리눅스 파이프라인 명령어를 통해 patch로 변경한 버전을 저장 
      - name : Patch
        run: |
          npm version patch > version.txt
      # 저장한 버전 파일을 읽어 변수로 사용하기 위해 외부 action을 사용 -> setps.{id}.outputs.content로 사용 가능
      - name: Read version.txt
        id: commit
        uses: juliangruber/read-file-action@v1
        with:
            path: ./version.txt
      # version을 변경한 package.json을 commit, 바뀐 버전으로 commit message 작성 후 push
      - name: Deploy and Push
        run: |
          git config --global user.name "${GITHUB_ACTOR}"
          git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com"
          git add package.json
          git commit -m "${{ (steps.commit.outputs.content) }}"
          echo ${{ (steps.commit.outputs.content) }}
          yarn deploy
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
      # slack 웹훅을 통해 채널에 전송
      - name: Send result to slack
        uses: Ilshidur/action-slack@2.0.2
        with:
          args: "버전 ➡️${{ (steps.commit.outputs.content) }}의 결과는 ➡️${{ job.status }} 에요"
        env:
          SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
        if: always()

어려움

1. github package ? npm package?

  • 처음엔 디자인 시스템 패키지가 github package인 줄 알았다. 그래서 registry-urlhttps://npm.pkg.github.com/로, NODE_AUTH_TOKEN을 github secret에 등록한(사실 github 개인 토큰 세팅에서 권한을 workflow도 허용하면 자동으로 찾아간다.)${{secrets.GITHUB_TOKEN}}으로 했었다. action을 통해 배포시 npm publish 명령어에서 unathorized 오류를 뱉었다.

2. develop에 commit을 push하지 못하는 상황

  • 추후에 설명할 해결책으로 1번을 해결한 이후 npm package는 배포가 되었다. 하지만 commit을 push하는 과정에서 오류가 났다. permission을 설정 안했더라...🤦‍♂️
  • 그런데 permission을 설정했는데도 github action에서는 unknown user라서 push하지 못했다. 그래서 git config를 통해 user를 설정했다.

3. commit message를 위한 버전 가져오기

  • npm patch를 통해 자동 버저닝은 하였으나 해당 버전을 commit message로 commit 하고 싶었다. 어떻게 가져올지 고민이 되었다. 처음에는 pacakge.json 자체를 읽어왔다. 버저닝 하나 때문에 package.json 전체를 읽고 version이 포함된 위치를 찾아서 그 버전을 가져오는게 과하다고 생각했고, npm patch에서 return하는 버전 관련 문자열을 사용하는 것이 좋겠다고 생각했다.

4. tsc error? cannot find module ?

  • 1, 2, 3 문제들 이전에 가장 먼저 발생한 에러였다. 모듈명: cannot find module.. github action에서 typescript를 위한 tsc, tsc-alias가 제대로 동작하지 않는 줄 알았다. 그리고 디자인 시스템 패키지에서는 tsc, tsc-alias가 잘 동작해서 github action의 step에 tsc, tsc-alias를 global하게 설치도 해보았다. 여전히 에러가 났고, 찾을 수 없는 모듈들을 꼼꼼히 살펴보았다... 공통점이 있었다 ...!

해결

1.github package ? npm package!

  • npm package 자동 배포를 위한 세팅으로 변경하였더니 해결했다! 그래서 registry-urlhttps://registry.npmjs.org/로, NODE_AUTH_TOKEN을 github secret에 등록한 npm repository token인 ${{ secrets.NPM_TOKEN }}으로 변경하여 해결하였다.

2. develop에 commit을 push하지 못하는 상황 ➣ github 세팅으로!

  • 아래와 같이 build setting에서 contents를 write할 수 있는 권한을 추가하여 해결하였다.
build:
	...
    permissions:
      contents: write
  • unknown user는 github action을 실행하게 한 actor의 정보를 action의 workflow의 user 정보로 아래와 같이 setting 하여 해결했다.
git config --global user.name "${GITHUB_ACTOR}"
git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com"

3. commit message를 위한 버전 가져오기 ➣ 리눅스 파이프라인 명령어로!

  • npm patch 명령어에서 return 해주는 버전을 리눅스의 파이프라인 명령어로 파일을 생성하였다. npm version patch > version.txt 를 통해 version.txt 파일에 생성하고, juliangruber/read-file-action@v1 외부 action을 사용하여 setps.{id}.outputs.content로 해당 action에서 읽어온 string을 commit message로 사용할 수 있도록 하였다.

4. tsc error? cannot find module ? ➣ peer-dependency

  • 모듈명: cannot find module 에러가 발생한 모듈들의 공통점은 모두 peer-dependency에 적혀있는 모듈들이었다. 그래서 다음과 같은 명령어를 github action에 추가하여 해결하였다.
npm install --legacy-peer-deps --save-dev --ignore-scripts install-peers

회고

  1. 캐싱을 통해 반복되는 동작은 빠르게 실행될 수 있도록 할 수 있을 것 같다! 캐싱할 수 있을 것 같은 부분은 node setting과 dependency 설치 정도!
  2. release-it 패키지를 동료분께서 알려주셨다. 이걸 통해 배포를 진행했다면 더욱 빠르고 편하게 할 수 있지 않았을까? 코어 모듈 패키지도 분리하여 작업을 진행 중이니 추후에 해당 패키지를 활용하여 CI/CD를 진행해보고 싶다.

마무리

  • 자동 배포에 있어 큰 설계는 내가 생각한 것과 같이 진행 되었다고 생각한다. 하지만 중간중간 예상치 못한 짜잘한 이슈들로 시간을 쏟았던 것 같다. 그래도 팀원들이 자동 배포 추가에 만족하는 것 같아서 뿌듯하다. 팀원들의 일하는 방식, 워크플로 개선에 관심이 있고 개선했다는 사실에 재미를 느꼈던 것 같다 ☺️

참고

profile
FE Developer as Efficiency Maker

0개의 댓글