Go

Golang 멀티 모듈 리포지토리와 효과적인 버전 관리 전략

드리프트2 2024. 10. 6. 21:40

Golang 멀티 모듈 리포지토리와 효과적인 버전 관리 전략


서론

안녕하세요, Golang 개발자 여러분!

 

오늘은 멀티 모듈 리포지토리(Multi-module Repository)버전 관리에 대해 심도 있게 다뤄보려고 합니다.

 

최근 많은 프로젝트들이 Monorepo 방식을 채택하면서 여러 모듈을 하나의 리포지토리에서 관리하고 있는데요, 이 과정에서 발생하는 다양한 도전 과제들을 어떻게 해결할 수 있는지 함께 알아보겠습니다.

 

이 글을 통해 여러분의 프로젝트 관리에 새로운 관점을 제공하고자 합니다.

 

함께 시작해볼까요?


 

멀티 모듈 리포지토리란?

멀티 모듈 리포지토리는 하나의 Git 리포지토리 내에 여러 개의 Go 모듈이 존재하는 구조를 의미합니다.

 

공식 문서(Go Modules FAQ)에 따르면, 리포지토리 내에 여러 개의 go.mod 파일이 존재하는 상태를 말합니다.

 

아래는 그 구조의 예시입니다.

my-repo
|-- bar
|-- foo
|   |-- rop
|   `-- yut
|-- go.mod
`-- mig
    |-- go.mod
    `-- vub

 

알아볼까요?

 

멀티 모듈 리포지토리는 각 모듈이 독립적으로 관리되기 때문에, 서로 다른 팀이 각기 다른 모듈을 개발할 때 매우 유용합니다.

 

모든 모듈이 항상 최신 버전을 사용한다면 루트에 go.mod 하나만 있는 것도 가능하지만, 모듈 간의 의존성을 명확히 하고자 할 때 멀티 모듈 구성이 큰 도움이 됩니다.

 


태그 작성 방법

멀티 모듈 리포지토리에서는 각 모듈에 대한 태그를 작성할 때, 리포지토리 루트 디렉토리로부터의 상대 경로를 프리픽스로 붙여야 합니다.

 

예를 들어, 다음과 같은 리포지토리가 있을 때:

my-repo
|-- .git
|-- go.mod
`-- mig
    |-- go.mod

 

태그는 다음과 같이 작성됩니다.

  • v0.0.1my-repo/go.mod
  • mig/v0.0.1my-repo/mig/go.mod

이러한 상대 경로 프리픽스를 태그에 포함시키는 방식은 일반적인 버전 관리 도구에서는 별로 지원되지 않는 것 같아, 직접 도구를 만들어 사용하게 되었습니다.

 

혹시 이와 유사한 도구를 알고 계신 분이 있다면 댓글로 공유해 주세요!


 

gump 도구를 활용한 태그 관리

멀티 모듈 리포지토리의 태그를 효율적으로 관리하기 위해 gump라는 도구를 사용합니다.

 

이 도구를 통해 각 모듈에 대해 손쉽게 태그를 작성하고 푸시할 수 있습니다.

 

설치 방법:

go get -u github.com/takashabe/gump/cmd/gump

 

태그 작성 및 푸시 예시:

$ pwd
/home/developer/projects/my-repo/mig/vub
$ gump -g="../../.." --patch -p
✔  create tag mig/v0.0.1
✔  push tag mig/v0.0.1
$ git tag -l | grep mig/v0.0.1
mig/v0.0.1

 

알아볼까요?

gump 도구를 사용하면 멀티 모듈 리포지토리의 복잡한 태그 관리를 간편하게 할 수 있습니다.

 

특히, 각 모듈마다 별도의 태그를 부여해야 할 때 유용하게 활용됩니다.

 


 

효과적인 버전 관리 전략

멀티 모듈 리포지토리를 운영하면 다음과 같은 버전 관리 정책을 따르는게 좋습니다.

 

1. 엄격한 SemVer 운영은 하지 않기

저희는 오픈 소스 라이브러리를 개발하는 것이 아니라 내부 프로젝트를 관리하고 있기 때문에, 엄격한 SemVer(유의적 버전 관리)를 따르지 않습니다.

 

대신, 최소한의 버전 고정을 통해 예기치 않은 빌드 실패를 방지하고 있습니다.

 

이는 각 모듈이 특정 버전에 의존하도록 고정함으로써, 의존성 충돌을 줄이고 안정적인 개발 환경을 유지하기 위함입니다.

 

2. 개발 중 수동으로 패치 버전 올리기

개발 중에는 패치 버전을 수동으로 올려서 현재 개발 중인 버전으로 관리합니다.

 

예를 들어, 각 모듈에 Makefile을 배치하여 make bump 명령어를 통해 패치 버전을 올리는 방식으로 운영하고 있습니다.

 

# Makefile 예시
bump:
    gump --git-dir . --gomod-dir mig/vub --patch

 

이렇게 하면 의존성 모듈 간의 빈번한 버전 업그레이드를 방지할 수 있으며, 필요에 따라 replace 지시어를 사용하여 특정 모듈을 임시로 교체할 수도 있습니다.

 

3. 기본 브랜치에 머지 시 자동으로 마이너 버전 올리기

모듈별 변경 사항이 기본 브랜치(master)에 머지될 때 자동으로 마이너 버전을 올려 안정적인 릴리스 버전으로 관리합니다.

 

이를 위해 GitHub Actions를 활용하여, pull request가 master에 머지될 때 해당 모듈의 버전을 자동으로 bump하는 워크플로우를 설정했습니다.

 

GitHub Actions 예시:

# .github/workflows/bump.yaml
on:
  pull_request:
    types:
      - closed

jobs:
  bump-version:
    if: github.event.pull_request.merged == true && github.base_ref == 'master'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Bump version
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          modules=$(./hack/list-diff-modules.sh ${{ github.event.pull_request.base.sha }})
          for m in $modules; do
            gump --git-dir . --gomod-dir $m --minor
          done

 

스크립트 예시:

# hack/list-diff-modules.sh
commit=$1
modules=$(find . -type f -name "go.mod")
diffs=()
for m in $modules; do
  m_dir=$(dirname $m)
  m_dir=${m_dir#./}
  if ! git diff $commit --quiet --relative=$m_dir; then
    diffs+=($m_dir)
  fi
done
echo ${diffs[@]}

 

알아볼까요?

 

이와 같은 자동화된 버전 관리 전략을 통해, 팀 내 각 모듈의 변경 사항을 체계적으로 관리하고, 안정적인 배포를 유지할 수 있습니다.

 


결론

Go 언어의 멀티 모듈 리포지토리와 버전 관리 전략에 대해 알아보았습니다.

 

초기에는 다소 복잡하게 느껴질 수 있지만, 효율적인 도구와 명확한 정책을 통해 체계적으로 관리할 수 있습니다.

 

특히, gump와 같은 도구를 활용하면 태그 관리가 훨씬 간편해지며, 팀의 버전 관리 정책을 명확히 설정함으로써 프로젝트의 안정성과 생산성을 높일 수 있습니다.

 

멀티 모듈 리포지토리 사례는 아직 많지 않지만, 저희의 경험을 바탕으로 더 많은 개발자들이 효과적으로 활용할 수 있기를 바랍니다.