티스토리 뷰

반응형


안녕하세요. 오늘은 제가 현재 현업에 종사하고 있는 똑똑한개발자의 시스템 팀으로서 모노레포(Monorepo) 환경에서 효율적인 배포 플로우를 구축한 경험들을 공유하고자 합니다. 

 

제목이 조금 심심해서 고민하던 중, 어릴 적 즐겨보던 [무서운게 딱 좋아] 시리즈가 생각이 났어요.. 스물아홉의 전 [귀찮은게 질색이야] 편으로 써볼까 합니다. 

 

조금 개인적인 이야기를 쓰자면 어릴 적 제 별명이 √2(루트2, 2의 제곱근) 였어요. 친구들과 코너 길에서 길을 걸을 때 "대각선으로 걸어다니면√2를 절약할 수 있어" 라고 했더니 이후로 친구들이 그렇게 부르고는 했었습니다. 학교가는 길도 신호등 시간까지 기억하고 시간 맞춰 등교하기도 하고요. 유난이었죠.. 지금은 윤리적인 사고가 쌓여서 그렇게까지 하지는 않지만 (그 때는 잔디를 밟고 대각선으로 가고 그랬어요), 아무튼 여전히 효율적인 작업을 추구하는 편입니다. 

 

당연히 일을 할 때도 그렇고요. 일을 할 때는 저 뿐만 아니라 아마 모두가 좋아하시는 단어이지 않을까 싶습니다. 그래서 저는 개발자로서 귀찮음을 도와주었던 작업, 도구, 방법 등 종류를 가리지 않고 [귀찮은건 질색이야] 시리즈를 올려볼 생각입니다. 꼭 기술적인 부분이 아니더라도요. 

 

서론이 조금 길었습니다. 거두절미하고 오늘 이 글에서는 모노레포를 관리하면서, Changesets을 통해 패키지 배포 자동화를 어떻게 구현했는지 소개해드리겠습니다. (기본적인 배포 플로우 설명은 덤!)

 


 

모노레포란 여러 패키지, 애플리케이션, 또는 모듈을 하나의 대규모 저장소에서 관리할 수 있도록 구성한 환경을 말합니다. 똑똑한개발자의 모노레포에는 npm에 배포된 다양한 패키지들, 보일러플레이트, 그리고 패키지 문서를 위한 앱 등이 포함되어 있습니다. 여기서 패키지들은 26개를 관리하고 있습니다.

틈새 어필: @toktokhan-dev 패키지들을 확인해 보세요!

 

이렇게 많은 패키지를 각기 버전 관리하고 배포하는 것은 굉장히 번거로운 작업입니다. 일일이 수동으로 처리해야 할까요? 한두 개 정도는 금방 하겠지만 무려 26개나 되는걸요..😅

toktokhan-dev package list

 

사실 이 부분에 있어서 저희는 처음부터 자동화 작업을 고려하고 있었습니다. 이미 모노레포를 사용하기 이전부터 Semantic Release라는 버전관리 툴을 사용하고 있었어요. 여기서 말하는 배포 자동화를 시킨다는 게 어디서부터 어디까지 일까요? 자세히 설명드리기 위해서 하나의 패키지가 배포되는 과정을 설명드릴게요.

 

패키지 수정부터 배포까지

1. 패키지 수정

@toktokhan-dev/cli-plugin-gen-route-pages라는 패키지가 있습니다. 해당 패키지는 @toktokhan-dev/cli 에 등록할 수 있는 플러그인으로, nextjs 프레임워크의 page 라우터 버전에서 사용할 수 있어요. 이 패키지를 사용하면  pages 폴더를 조회하여 route 경로를 포함한 객체를 생성해 줍니다. 타이핑으로 경로를 가져오는 것이 아닌, 객체의 key 값을 가져옴으로써 편의성과 안정성을 제공하고 있는 패키지입니다. 

 

아래의 경로를 

pages
├── index.tsx
├── login
│   └── index.tsx
└── post
    └── [id].tsx

 

이렇게 객체 상수로 변환을 해줍니다. 

export const ROUTES = {
  MAIN: "/",
  LOGIN_MAIN: "/login",
  SOCIAL_CALLBACK: "/social/callback",
  POST: {
   dynamic_id: {
     MAIN: "/post/[id]",
   }
  }
}
};

 

위의 변환된 객체 상수에서 이상한 점이 보이시나요? dynamic id에 해당하는 경로의 key값이 소문자로 변환이 되었습니다. 이는 일관되지 않은 변환 결과로 이슈로 판단이 되네요. 대문자로 수정을 해줍니다. 

issue fix

 

2. 버전 업데이트

이제 수정한 내용을 반영하여 패키지 버전을 업데이트할 차례입니다. Node.js 생태계에서는 npm을 통해 패키지를 관리하며, 이는 Semantic Versioning을 따릅니다. 따라서, 이번 수정 사항에 맞게 적절한 버전으로 업데이트를 진행해야 합니다.

 

이번 수정은 간단한 버그 수정이며, 새로운 기능을 추가한 것은 아니기 때문에 PATCH 버전에 해당합니다. 현재 해당 패키지의 버전이 v0.0.10이라면,  v0.0.11로 업데이트하는 것이 적절합니다.

package.json version

 

 

3. Changelog 작성 및 Release 및 Tag 등록

이후에는 어떤 변경사항이 발생했는지, Release Note와 ChangeLog를 를 적어주면 되는데요.

수동 작업 기준으로 설명을 드리면, Release를 만들기 위해서는 tag등록도 필요하고, Changelog를 만들기 위해서는 하나의 CHANGELOG.md에 버전과 변경 내용을 써줘야 합니다. 아래 이미지처럼요.

(좌) Release (우) Changelog

 

4. 배포

모든 준비가 완료되었으니, 비로소 배포를 할 수 있게 되었습니다. npm publish 명령어를 사용하면 package.json버전을 읽어 배포가 됩니다. 

 

자동화의 필요성: Changesets

지금까지 하나의 패키지를 배포하는 과정을 설명드렸습니다. Changelog나 Release 같은 작업이 배포 과정에서 꼭 필요한 요소는 아닙니다. 하지만 누구나 사용할 수 있는 공개된 패키지라면, 사용자에게 버전 업데이트 내용을 문서로 전달하는 작업은 필수적이라고 생각합니다. 게다가 로그가 쌓이면 개발자 입장에서 관리도 훨씬 편리해지죠.

 

만약 이 과정이 자동화될 수 있다면 얼마나 좋을까요? 이제 Changesets를 소개할 때가 된 것 같네요😉

 

Changesets 소개 

Changesets는 프로젝트에서 버전 관리와 변경 로그 생성을 도와주는 도구입니다. 앞서 설명드린 배포 과정의 2~4단계를 자동으로 처리해 줍니다..🫶 물론, Changesets의 장점은 이 뿐만이 아닙니다. 다른 장점들은 이전에 사용했던 Semantic-release와 비교해 가며 설명드릴게요.

  • semantic-release는 커밋 메시지 기반으로 버전을 자동으로 결정하지만, Changesets은 개발자가 직접 변경 사항에 대한 설명과 버전 업데이트의 종류(major, minor, patch)를 결정할 수 있습니다.
  • semantic-release는 별도의 플러그인을 통해 모노레포를 지원하지만, Changesets은 기본적으로 모노레포를 지원합니다.
  • semantic-release는 CI 환경에서 main브랜치에 병합될 때마다 자동으로 버전을 업데이트하지만 Changesets은./changesets폴더의 임시 md파일을 읽어 해당 md파일이 포함된 커밋이 병합이 되면, [Version Packages]라는 PR생성을 통해 배포여부를 결정할 수 있습니다.
    note. 이 기능은 Changesets GitHub App & Changesets GitHub Action의 조합으로 사용할 수 있습니다.
보일러플레이트 모노레포 적용기 참고

 

 

직접 느낀 Changesets 장점

제가 Semantic-release에서 changesets으로 변경하게 된 이유, 제가 만든 툴은 아니지만 어필하고 싶은 changesets의 장점은

 

개발자가 직접 변경 사항에 대한 설명과 버전 업데이트의 종류(major, minor, patch)를 결정할 수 있으며, 커밋 기반으로 md파일을 쌓을 수 있고(중요) 이 커밋들이 main(기준 브랜치)에 병합이 되면, [Version Packages] PR이 생성되고, 그 PR을 머지하기 전까지는 계속 해당 PR에 커밋기반 md정보가 쌓이며, 개발자가 merge를 하면 비로소 배포가 된다는 점...!입니다. (장점이 많아 문장 호흡이 기네요🤣)

 

단점이란 게 있다면 공식 문서가 너무나 간단합니다. 문서조차 md파일입니다. 그렇다고 구현하기에 부족한 문서는 아닙니다. 커뮤니티도 활성화되어있고요. (Changesets 공식문서) 

또 Semantic-release은 slack action bot을 제공하는데, changesets은 따로 구현해야 한다는 점도 조금 아쉽긴 한 부분이네요.

 

그리고 Changesets은 단독으로 사용하기보다는 Changesets Github AppChangesets Github Action과 통합하여 사용해야만 제가 말씀드렸던 장점들에 공감하실 수 있을 것 같습니다. 

 

 

 

Changesets 배포 과정 

준비. changesets 설치 및 config 설정

자세한 설치와 설정 과정은 생략되었습니다. 실 사용하실 분들께서는 Changesets 공식문서를 참고해 주세요.

{
  "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
  "changelog": [
    "@changesets/changelog-github", 
    { "repo": "TOKTOKHAN-DEV/toktokhan-dev" }
  ],
  "commit": false,
  "fixed": [],

  "linked": [],
  "access": "public",
  "baseBranch": "main",
  "updateInternalDependencies": "patch",
  "ignore": ["Toktoken", "@toktokhan-dev/docs"]
}

config.json 에서 changelog에 대해 

1. 변경사항 문서 작성

터미널에서 pnpm changeset 명령어를 입력하면, Changesets가 지정된 패키지 스코프 안에서 변경사항을 감지하고 대화형 프롬프트를 실행합니다. 변경사항이 있는 패키지가 우선으로 뜨기 때문에 선택도 편하고, 다음 프롬프트로 넘어가게 되면 버전 종류(major, minor, patch)도 지정할 수 있습니다. 심지어 간략하게 description을 작성할 수도 있습니다. 

Changeset 변경사항 문서 작성

 

2. 변경사항 커밋

변경 사항을 문서화하면. changeset 경로에 임의의 md 파일이 생성됩니다. 이 파일을 커밋에 포함시키면 되며, 커밋 메시지는 변경 사항을 잘 설명할 수 있도록 작성하는 것이 좋습니다. 저희는 사내 CLI 플러그인을 통해 이 md 파일의 내용을 읽어, 커밋 시 자동으로 메시지 입력을 제안하는 기능을 개발했습니다. (패키지 보러 가기)

(좌) 생성된 md (우) @toktokhan-dev/cli-plugin-commit

3. Pull Request 생성

변경사항을 커밋한 후, 메인 브랜치로의 변경 사항을 병합하기 위해 Pull Request를 생성합니다. 이 PR에서 Changesets가 생성한 문서가 자동으로 포함되어 배포될 준비가 됩니다. 

Version Packages PR

4. PR 머지 및 자동 배포

PR을 머지하면 Changesets는 main 브랜치에 병합된 문서들을 바탕으로 자동으로 버전을 업데이트하고, Changelog 및 Release 노트를 생성해 줍니다. 이때 1번의 과정에서 생성하고 커밋한 md파일은 삭제됩니다. (해당 md파일은 단순 문서 작성 용도로만 쓰인 임시 파일이기 때문이에요.)

PR merge

5. 배포

이후에는 새롭게 업데이트된 패키지가 NPM에 배포되게 됩니다. 

Publish npm Package

 

 

Tips

Tip #1 : 기여자에게 감사 태그 및 관련 PR 링크를 자동으로 추가할 수 있어요.

"@changesets/changelog-github" 모듈을 사용하면, CHANGELOG.md와 Release note에 기여자에게 감사태그와, 관련 PR링크까지 걸어줍니다. 다만 '@changesets/cli'를 설치하면 제공되는 '@changesets/chagelog-git'모듈과는 역할이 다르니 별도 패키지 설치가 필요합니다.  (Docs-changesets/changelog )

 

// ./changeset/config.json
{
 ...
 "changelog": [
    "@changesets/changelog-github",
    { "repo": "TOKTOKHAN-DEV/toktokhan-dev" }
  ],
 }

Tip #2: npm에 배포하고 싶지는 않은데 버전관리는 하고 싶어요.

Changesets의 tag 명령어를 사용하면 npm에 패키지를 게시하지 않고도 버전 관리를 할 수 있습니다. 저희 사내 프런트엔드 템플릿은 Git 태그를 통해 버전 관리를 하고 있으며, 이를 활용해 각 버전별로 템플릿을 관리하고 다운로드할 수 있는 Tokit도 개발했습니다.

[틈새 어필] Tokit 은 똑똑한개발자에서 관리하는 프런트엔드 보일러 템플릿을 관리하고, 로컬 환경에 설치하기 위한 CLI tool입니다. create-react-app처럼 커멘드라인 한 줄로 쉽게 설치가 가능하며 원격 레포지토리에 생성하고, 연동시킬 수 있는 옵션이 있습니다. [Tokit 가이드 보러 가기]

// .github/workflows/release.yml
name: Release
...
jobs:
  release:
	...
    steps:
      ...
      - name: Create Release Pull Request
        id: changesets
        uses: changesets/action@v1
        with:
          publish: pnpm changeset tag
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      ...

 

Tip #3: 배포가 되면 슬랙 방에 알림을 보내고 싶어요.

Changesets는 슬랙 액션 기능을 제공하지 않습니다🥲 하지만 Git Action Context를 통해 배포 성공 여부, pr number, 패키지 정보를 제공해 줍니다. 이를 활용하여 슬랙 알림도 자동화했습니다. (Docs-Changesets actions-outputs)

slack 알림 템플릿은 webhook을 통해 구현하였습니다. 

// .github/workflows/release.yml
name: Release
...
jobs:
  release:
	...
    steps:
      ...
      - name: Slack notification
        if: steps.changesets.outputs.published == 'true'
        run: pnpm slack ${{ steps.pr.outputs.pull_request_number }} '${{steps.changesets.outputs.publishedPackages}}'
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
        continue-on-error: true

      ...

 

마무리

어떠한 일을 진행하는 데에 있어서 자동화는 생산성과 정확성을 위해 중요한 부분이라고 생각합니다. 그만큼 좋은 도구들이 너무 많아, 자동화 이전의 개발자들분들은 얼마나 반복적이고 힘든 작업을 했을지 새삼 대단하게 느껴집니다.

자동화를 통해 많은 작업이 편리해지지만, 때때로 예기치 못한 상황에서는 수동적인 해결이 필요할 때가 있습니다. 이럴 때 근본적인 이해가 뒷받침되어야만 유연하게 대처할 수 있습니다.

저 또한 앞으로도 유용한 도구들을 효과적으로 활용하되, 기본 원칙에 충실하며 안정적이고 효율적인 개발 환경을 구축해 나가야겠다고 생각합니다.

 

References

 

 

 

 

 

반응형

'git > monorepo' 카테고리의 다른 글

[monorepo] 보일러플레이트 모노레포 적용기  (0) 2024.03.13