-
Notifications
You must be signed in to change notification settings - Fork 0
article3
Homebrew는 macOS를 위한 오픈 소스 패키지 관리자로, 개발자들 사이에서 필수 도구로 자리 잡았습니다. CLI 인터페이스를 통해 다양한 소프트웨어를 쉽게 설치, 업데이트, 관리할 수 있게 해주며, 의존성 문제도 자동으로 해결됩니다. 이러한 편의성 덕분에 Homebrew는 macOS 사용자들, 특히 개발자들에게 없어서는 안 될 도구가 되었습니다.
이번 글에서는 이전에 소개한 ALN(Amazing Lucky Numbers) 라이브러리를 macOS용 Homebrew 패키지로 만들고, TAP을 통해 bottle로 배포하는 과정을 상세히 다루겠습니다. Formula 작성, bottle 빌드, TAP 저장소 설정, 그리고 최종적으로 사용자들이 쉽게 설치할 수 있도록 패키지를 배포하는 방법까지 단계별로 설명하겠습니다.
Homebrew는 맥주 양조에서 영감을 받아 이름이 지어졌으며, 많은 용어들이 맥주 제조 과정과 관련이 있습니다. 실제로 brew 명령으로 패키지를 설치할 때 터미널에 맥주 아이콘이 표시됩니다.
각 용어에 대해 Homebrew에서의 의미와 맥주 양조에서의 의미를 함께 설명하면 다음과 같습니다.
-
Homebrew: macOS를 위한 오픈 소스 패키지 관리 시스템
- 가정에서 직접 만드는 수제 맥주
-
Brew: 패키지를 설치하거나 관리하는 주요 명령어
- 맥주를 만드는 과정 자체
-
Formula: 패키지 설치 방법을 정의한 Ruby 스크립트 파일
- 맥주 제조를 위한 재료와 방법을 기술한 레시피
-
Cellar: Homebrew가 패키지를 설치하는 디렉토리 (기본 위치: Intel mac - /usr/local/Cellar, Apple Silicon Mac - /opt/homebrew/Cellar)
- 맥주를 저장하고 숙성시키는 공간
-
Keg: Cellar 내의 특정 버전의 패키지 설치 디렉토리
- 맥주를 저장하고 서빙하는 데 사용되는 통
-
Tap: 공식 저장소 외에 사용자가 추가하여 사용할 수 있는 Formula 저장소
- 맥주를 따르는 데 사용되는 밸브나 꼭지
-
Cask: GUI 애플리케이션을 관리하기 위한 Homebrew의 확장 기능
- 대량의 맥주를 저장하고 운반하는 데 사용되는 큰 통
-
Bottle: 미리 컴파일된 패키지 버전으로, 설치 시간을 크게 단축시킴
- 맥주를 담아 판매하거나 보관하는 유리병
Homebrew 기반의 패키지를 만들어서 배포하는 과정을 맥주 용어로 다시 설명하면 아래와 같습니다.
- 패키지 생성 스크립트 정의
- 맥주 제조를 위한 재료와 방법을 기술한 레시피(Formula) 작성
- 패키지 빌드 및 저장소(Github Release)에 업로드
- 맥주를 제조한 후 유리병(Bottle)에 담아 준비
- Github 저장소를 이용해 Tap 추가 및 패키지 설치
- 맥주 양조장을 통해 맥주를 받아옴(Tap). 병으로 바로 받거나(Bottle) 레시피(Formula)로 직접 제조
Apple Silicon Mac 기준으로 Homebrew는 /opt/homebrew 디렉토리를 사용하는데, 세부 디렉토리는 아래와 같습니다.
-
/opt/homebrew/(Git 저장소): 이 디렉토리는 Homebrew의 루트 디렉토리이며, 동시에 Git 저장소입니다. 이를 통해 Homebrew 자체의 업데이트와 버전 관리가 이루어집니다. -
/opt/homebrew/bin/: Homebrew로 설치한 패키지의 실행 파일들이 심볼릭 링크로 위치합니다. -
/opt/homebrew/Cellar/: 실제 패키지들이 설치되는 장소입니다. 각 패키지는 자신의 하위 디렉토리를 가집니다. -
/opt/homebrew/Caskroom/: Cask로 설치된 GUI 애플리케이션들이 위치합니다. -
/opt/homebrew/etc/: 설정 파일들이 저장되는 디렉토리입니다. -
/opt/homebrew/include/: 헤더 파일들이 위치하는 디렉토리입니다. -
/opt/homebrew/lib/: 라이브러리 파일들이 위치하는 디렉토리입니다. -
/opt/homebrew/opt/: 현재 설치된 패키지들의 최신 버전에 대한 심볼릭 링크가 위치합니다. -
/opt/homebrew/sbin/: 시스템 관리자용 실행 파일들이 위치합니다. -
/opt/homebrew/share/: 공유 리소스(문서, 매뉴얼 페이지 등)가 저장되는 디렉토리입니다. -
/opt/homebrew/var/: 가변 데이터(로그 파일 등)가 저장되는 디렉토리입니다. -
/opt/homebrew/Homebrew/: Homebrew 코어의 Git 서브모듈입니다. Formula들의 정의도 이 안에 있습니다. -
/opt/homebrew/Frameworks/: 일부 애플리케이션에 필요한 프레임워크들이 설치되는 디렉토리입니다. -
/opt/homebrew/Library/Homebrew/: Homebrew의 Ruby 코드 대부분이 여기에 위치합니다. 이는 Homebrew의 핵심 기능을 구현하는 코드입니다. -
/opt/homebrew/Library/Taps/: 여기에는 탭(tap)된 저장소들이 위치합니다. 기본적으로 homebrew/core와 homebrew/cask가 포함되어 있으며, 사용자가 추가한 다른 탭들도 이 디렉토리에 위치하게 됩니다.
/opt/homebrew가 Git 저장소라는 점은 Homebrew의 자체 업데이트와 버전 관리를 용이하게 합니다. 사용자는 brew update 명령을 통해 이 저장소를 최신 상태로 유지할 수 있으며, 이는 Homebrew 시스템 전체의 일관성과 최신성을 보장합니다.
이러한 구조는 Homebrew가 패키지를 효율적으로 관리하고, 사용자 시스템과 독립적으로 운영될 수 있게 해줍니다. 각 디렉토리는 특정 목적을 가지고 있어, 패키지 관리를 체계적으로 할 수 있게 도와줍니다.
glib 패키지를 기준으로 어떻게 구성되는지 살펴보겠습니다. brew install glib 명령어로 패키지를 설치하게 되면 /opt/homebrew/Cellar 디렉토리 아래에 {name}/{version} 디렉토리가 생성되고 그 아래에 실제로 패키지가 포함하고 있는 파일들이 설치됩니다.
/opt/homebrew/Cellar
└── glib
└── 2.80.3
├── bin
├── etc
├── include
├── lib
└── share
그리고 각 파일들은 /opt/homebrew의 적절한 위치에 Symbolic link로 제공됩니다.
$ ls -l /opt/homebrew/bin/gdbus
/opt/homebrew/bin/gdbus -> ../Cellar/glib/2.80.3/bin/gdbus
$ ls -l /opt/homebrew/lib/libglib-2.0.dylib
/opt/homebrew/lib/libglib-2.0.dylib -> ../Cellar/glib/2.80.3/lib/libglib-2.0.dylib
$ ls -l /opt/homebrew/opt/glib
/opt/homebrew/opt/glib -> ../Cellar/glib/2.80.3Homebrew 패키지는 brew 도구를 이용해 설치, 제거할 수 있으며, 설치된 패키지 목록도 확인할 수 있습니다.
패키지 설치를 위한 기본적인 명령:
brew install <패키지명>: 패키지 설치
brew uninstall <패키지명>: 패키지 제거
brew update: Homebrew 자체와 공식 패키지 목록 업데이트
brew upgrade: 설치된 모든 패키지 업그레이드
brew list: 설치된 패키지 목록 확인
brew search <검색어>: 패키지 검색
brew info <패키지명>: 패키지 정보 확인
brew tap <user/repo>: Tap 추가
brew untap <tap>: Tap 제거
Formula, Tap 등 패키지 작성을 위한 개발자 명령:
brew tap-new <user/repo>: Tap 생성
brew create <URL>: Formula 생성
brew edit <formula>: Formula 편집
brew audit <formula>: Formula 문법 검사
brew style <formula>: Formula style 가이드 검사
전체 명령에 대한 설명은 https://docs.brew.sh/Manpage를 참고 바랍니다. 개발자를 위한 명령은 https://docs.brew.sh/Manpage#developer-commands를 통해 더 쉽게 찾아볼 수 있습니다.
이제 실제로 Homebrew 패키지를 만드는 과정을 살펴보겠습니다
Formula 작성을 위해 먼저 아래 명령을 통해 기본 작업 공간(homebrew/core 저장소 사용)을 준비합니다.
export HOMEBREW_NO_INSTALL_FROM_API=1
brew tap --force homebrew/core여기서 HOMEBREW_NO_INSTALL_FROM_API=1 환경 변수는 Homebrew가 API를 통해 패키지를 설치하는 것을 방지하고, 대신 로컬 Formula 파일을 사용하도록 합니다. brew tap --force homebrew/core 명령은 Homebrew의 핵심 Formula 저장소를 강제로 다시 탭(tap)하여 최신 상태로 유지합니다. 이 과정은 새로운 Formula를 개발하고 테스트하는 데 필수적인 단계입니다.
다음으로 아래와 같이 brew create 명령으로 패키징에 사용할 ALN 소스 압축파일을 지정합니다.
$ brew create https://github.com/webispy/aln/archive/refs/tags/v0.1.1.tar.gz
Formula name [aln]:Formula로 사용할 이름을 물어보면 원하는 이름을 입력합니다. 위의 예제에서는 자동으로 추천해준 aln을 그대로 사용했습니다.
설정하고 나면 소스 파일을 다운로드 받고 자동으로 기본 템플릿을 사용하여 만들어진 Formula 파일이 편집기와 함께 실행됩니다.
(Formula 파일은 /opt/homebrew/Library/Taps/homebrew/homebrew-core/Formula/a/aln.rb 에 생성됩니다.)
# Documentation: https://docs.brew.sh/Formula-Cookbook
# https://rubydoc.brew.sh/Formula
# PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST!
class Aln < Formula
desc "Amazing Lucky Numbers"
homepage "https://webispy.github.io/aln/"
url "https://github.com/webispy/aln/archive/refs/tags/v0.1.1.tar.gz"
sha256 "e1ca51e3153b0b7824b36417c0acd5f4057028992ef1af0cde753408cd21a276"
license "Apache-2.0"
# depends_on "cmake" => :build
def install
# Remove unrecognized options if they cause configure to fail
# https://rubydoc.brew.sh/Formula.html#std_configure_args-instance_method
system "./configure", "--disable-silent-rules", *std_configure_args
# system "cmake", "-S", ".", "-B", "build", *std_cmake_args
end
test do
# `test do` will create, run in and delete a temporary directory.
#
# This test will fail and we won't accept that! For Homebrew/homebrew-core
# this will need to be a test that verifies the functionality of the
# software. Run the test with `brew test aln`. Options passed
# to `brew install` such as `--HEAD` also need to be provided to `brew test`.
#
# The installed folder is not in the path, so use the entire path to any
# executables being tested: `system "#{bin}/program", "do", "something"`.
system "false"
end
end저장하고 편집기를 빠져나온 뒤, 아래와 같이 edit 명령을 입력하면 언제든지 다시 파일 내용을 수정할 수 있습니다.
brew edit aln이제 편집창에서 ALN 빌드에 맞게 수정해서 내용을 채워넣습니다. homebrew-core 저장소(https://github.com/Homebrew/homebrew-core/tree/master/Formula)를 참고하면 다양한 Formula 예제들을 참고할 수 있습니다.
ALN은 CMake 기반의 빌드 시스템을 사용하기 때문에 이에 대한 의존성 및 빌드 명령들을 작성합니다. 참고로, Homebrew에서 CMake 빌드 시스템을 지원하기 때문에 CMake 옵션으로 *std_cmake_args을 사용하면 기본적인 값들이 자동으로 채워집니다.
class Aln < Formula
desc "Amazing Lucky Numbers Library"
homepage "https://github.com/webispy/aln"
url "https://github.com/webispy/aln/archive/refs/tags/v0.1.0.tar.gz"
sha256 "8db44f88840ae7c93eb237e5aec9f8aa49c5c03bf29e3360f5eabed2f7729902"
license "Apache-2.0"
head "https://github.com/webispy/aln.git", branch: "master"
depends_on "cmake" => :build
depends_on "pkg-config" => :build
depends_on "glib"
def install
args = %W[
-DCMAKE_INSTALL_RPATH=#{rpath}
]
system "cmake", "-S", ".", "-B", "build", *args, *std_cmake_args
system "cmake", "--build", "build"
system "cmake", "--install", "build"
end
test do
system "#{bin}/aln"
end
end소스 압축 파일에 대한 sha256 체크섬의 경우 coreutils 패키지 설치 후 아래와 같이 sha256sum 명령으로 값을 얻을 수 있습니다.
$ brew install coreutils
$ sha256sum v0.1.0.tar.gz
8db44f88840ae7c93eb237e5aec9f8aa49c5c03bf29e3360f5eabed2f7729902 v0.1.0.tar.gz작성한 Formula 파일에 대해 문법에 문제가 없는지 아래 명령으로 검사할 수 있습니다.
$ brew audit -new aln
* GitHub repository not notable enough (<30 forks, <30 watchers and <75 stars)
Error: 1 problem in 1 formula detected.ALN 라이브러리가 유명하지 않기 때문에 문제가 있다는 에러가 발생했습니다. 패키지를 메인 저장소인 homebrew-core에 올리지 않고 별도 Tap을 통해 배포할 것이기 때문에 위 에러는 무시해도 됩니다.
작성한 Formula 파일의 스타일도 검사할 수 있습니다.
$ brew style aln
1 file inspected, no offenses detected이제 작성한 Formula를 이용해서 정상적으로 패키지 빌드 및 설치가 되는지 확인합니다. aln은 아직 Bottle로 배포된적이 없기 때문에 미리 컴파일된 바이너리 패키지가 존재하지 않습니다. 따라서 직접 빌드해서 설치하도록 --build-from-source 옵션을 추가해야 합니다.
$ brew install --build-from-source aln
==> Fetching dependencies for aln: cmake and glib
==> Fetching cmake
==> Downloading https://ghcr.io/v2/homebrew/core/cmake/manifests/3.30.0
############################################################################################################################################################################################################# 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/cmake/blobs/sha256:4eb265cf09f23ebab2f4b5cc463150a8cd1004b480e43496593bebec24eb49f6
############################################################################################################################################################################################################# 100.0%
==> Fetching glib
==> Downloading https://ghcr.io/v2/homebrew/core/glib/manifests/2.80.4
############################################################################################################################################################################################################# 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/glib/blobs/sha256:e52c5b1cfc4a9c37fbd697a29d37c96d778d0699d2051d167ca3fd76010c25e2
############################################################################################################################################################################################################# 100.0%
==> Fetching aln
==> Downloading https://github.com/webispy/aln/archive/refs/tags/v0.1.0.tar.gz
==> Downloading from https://codeload.github.com/webispy/aln/tar.gz/refs/tags/v0.1.0
##O=- # #
==> Installing dependencies for aln: cmake and glib
==> Installing aln dependency: cmake
==> Downloading https://ghcr.io/v2/homebrew/core/cmake/manifests/3.30.0
Already downloaded: /Users/work/Library/Caches/Homebrew/downloads/dce5c120f5a36a420d00e9c5a8262781cc00bb40d11f512da96d7bfd3a5e38cb--cmake-3.30.0.bottle_manifest.json
==> Pouring cmake--3.30.0.arm64_sonoma.bottle.tar.gz
🍺 /opt/homebrew/Cellar/cmake/3.30.0: 3,424 files, 55.3MB
==> Installing aln dependency: glib
==> Downloading https://ghcr.io/v2/homebrew/core/glib/manifests/2.80.4
Already downloaded: /Users/work/Library/Caches/Homebrew/downloads/f635cb07f35354f1ef636173e4d8f0e85a3bd09d85784c8639a201b1c5263742--glib-2.80.4.bottle_manifest.json
==> Pouring glib--2.80.4.arm64_sonoma.bottle.tar.gz
🍺 /opt/homebrew/Cellar/glib/2.80.4: 526 files, 36.2MBaln.rb Formula에서 의존성 패키지로 정의한 cmake와 glib 패키지가 자동으로 설치된 후 aln에 대해 빌드 및 설치가 진행됩니다.
==> Installing aln
==> cmake -S . -B build -DCMAKE_INSTALL_RPATH=@loader_path/../lib
==> cmake --build build
==> cmake --install build
🍺 /opt/homebrew/Cellar/aln/0.1.0: 12 files, 132.9KB, built in 22 seconds
==> Running `brew cleanup aln`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
Removing: /Users/work/Library/Caches/Homebrew/aln--0.1.1.tar.gz... (50.9KB)
==> Upgrading 2 dependents of upgraded formulae:
Disable this behaviour by setting HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
harfbuzz 8.5.0 -> 9.0.0, libass 0.17.2 -> 0.17.3
==> Downloading https://ghcr.io/v2/homebrew/core/harfbuzz/manifests/9.0.0
############################################################################################################################################################################################################# 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/libass/manifests/0.17.3
Already downloaded: /Users/work/Library/Caches/Homebrew/downloads/84606583aa38b5ab3bcd159983c1468927012bf37cf5d21cc8e3a9eb334b252d--libass-0.17.3.bottle_manifest.json
==> Checking for dependents of upgraded formulae...
==> No broken dependents found!빌드 및 설치가 문제없이 완료되었습니다. 테스트가 끝났으니 brew uninstall aln로 설치된 패키지 제거합니다.
이처럼 Formula 작성을 통해 기본적인 Homebrew 패키징 방법에 대해 알아보았으며, 기본 구조와 작동 방식을 이해할 수 있었습니다. 보다 자세한 내용은 https://docs.brew.sh/Formula-Cookbook 문서를 참고하시기 바랍니다.
실제 배포를 위해서는 몇 가지 추가 단계가 필요합니다. 이어지는 내용에서는 Tap을 통해 Formula를 배포하는 방법을 살펴보겠습니다. 또한, Github Actions를 사용하여 bottle을 자동으로 릴리즈하는 과정도 상세히 설명하겠습니다.
Homebrew는 기본적으로 Github repository를 통해 Formula를 관리하고 있으며, 컴파일된 패키지는 Github packages를 통해 배포합니다. 자세한 내용은 https://github.com/orgs/Homebrew/packages에서 확인할 수 있습니다.
위에서 brew install로 ALN 패키지를 설치할 때 의존성 패키지로 설치된 cmake를 예로 들면, 해당 패키지는 homebrew-core에서 제공되기 때문에 core/cmake라는 이름으로 배포되어 있습니다. 따라서, https://github.com/Homebrew/homebrew-core/pkgs/container/core%2Fcmake에서 배포된 모든 버전을 확인해 볼 수 있습니다. 세부 내용은 버전 선택 후 OS/Arch 탭에서 확인 가능합니다
또한, Tap을 위해 Github release와 연계하여 각 패키지별로 컴파일된 빌드 결과물인 bottle을 배포 및 다운로드할 수 있도록 모든 Github Actions 스크립트를 자체적으로 제공하고 있습니다.
brew tap-new <user/repo> 명령어 하나로 배포와 관련된 Github Actions 스크립트와 기본 Git 저장소를 한 번에 생성할 수 있습니다.
repo 이름에 aln을 입력하면 자동으로 이름 규칙에 따라 앞에 homebrew- 접두사가 추가됩니다. 따라서 실제 Github 저장소 이름은 webispy/homebrew-aln 이지만, Tap으로 사용할 때는 webispy/aln 이라는 이름을 사용합니다.
$ brew tap-new webispy/aln
Initialized empty Git repository in /opt/homebrew/Library/Taps/webispy/homebrew-aln/.git/
[main (root-commit) 6ccefd4] Create webispy/aln tap
3 files changed, 97 insertions(+)
create mode 100644 .github/workflows/publish.yml
create mode 100644 .github/workflows/tests.yml
create mode 100644 README.md
==> Created webispy/aln
/opt/homebrew/Library/Taps/webispy/homebrew-aln
When a pull request making changes to a formula (or formulae) becomes green
(all checks passed), then you can publish the built bottles.
To do so, label your PR as `pr-pull` and the workflow will be triggered.명령이 성공하면, /opt/homebrew/Library/Taps/webispy/homebrew-aln 디렉토리에 Git 저장소가 준비됩니다.
이제 Github 홈페이지에서 homebrew-aln 이라는 비어 있는 저장소를 생성한 뒤, 위에서 생성된 파일들을 업로드 하면 됩니다. (참고로, 개인적으로 homebrew-aln 저장소를 이미 가지고 있기 때문에 테스트를 위해 homebrew-haha로 화면을 캡쳐하였습니다.)

저장소에 업로드할 파일이 이미 준비되어 있기 때문에 다른 옵션 선택 없이 바로 Create repository 선택합니다.

저장소 생성이 완료되면 아래와 같이 기본 안내 화면이 나타납니다.

이제 저장소에 파일을 업로드 합니다. tap-new 명령 단계에서 커밋이 자동으로 만들어지기 때문에, remote를 추가한 후 바로 push 명령을 수행하면 됩니다.
cd /opt/homebrew/Library/Taps/webispy/homebrew-aln
git remote add origin git@github.com:webispy/homebrew-aln.git
git push -u origin main업로드 후 Github 저장소를 확인해 보면 파일들이 정상적으로 업로드된 것을 볼 수 있습니다. 또한, 빌드가 동작 중임을 알려주는 아이콘이 표시되는 것을 확인할 수 있는데, Actions 메뉴에서 진행중인 빌드를 확인할 수 있습니다.

이제 Actions를 선택해 확인해 보겠습니다. brew tap-new를 통해 자동 생성된 Github Actions의 workflow 항목들을 왼쪽에서 확인할 수 있으며, 현재 진행 중인 workflow 빌드 상태도 확인할 수 있습니다.

진행 중인 workflow를 선택해 세부 내용을 확인해보면, Jobs 항목에 3개의 아이템이 있는 것을 확인할 수 있습니다.
Github Actions에서는 다양한 빌드 실행 환경(Runner)를 제공하는데, brew tap-new 명령을 통해 생성된 스크립트에 따라 Ubuntu 22.04, macOS 13, macOS 14에서 빌드가 완료된 것을 확인할 수 있습니다.
참고로 Github Runner에서 제공하는 macOS 13 (Ventura) runner는 Intel Mac에서, macOS 14 (Sonoma) runner는 Apple Silicon Mac에서 실행됩니다. 따라서, Formula를 작성해서 업로드하면 두가지 Architecture를 지원하는 컴파일된 패키지(bottle)를 생성할 수 있습니다.

이제 기본적인 준비 과정은 모두 끝났습니다. 다음 단계에서 작성한 Formula를 업로드해보겠습니다.
brew tap-new를 통해 자동 생성된 Github Actions workflow에는 Pull request를 통해 Formula 파일을 검토 및 빌드하고, main 브랜치로 병합하는 기능이 포함되어 있습니다.
이전 단계에서 brew create로 생성하고 brew edit로 수정한 aln.rb Formula 파일을 배포하기 위해 Pull request를 만들어 업로드해 보겠습니다.
먼저 Pull request를 만들기 위해 브랜치를 생성합니다.
cd /opt/homebrew/Library/Taps/webispy/homebrew-aln
git checkout -b add_aln작성했던 aln.rb Formula 파일을 현재 저장소 디렉토리의 Formula/ 하위 디렉토리로 이동시킵니다.
mv /opt/homebrew/Library/Taps/homebrew/homebrew-core/Formula/a/aln.rb Formula커밋을 생성한 후 브랜치에 push 합니다.
git add Formula/aln.rb
git commit -m "Formula: add aln"
git push origin add_alnGithub 저장소 홈페이지에서 브랜치에 커밋이 추가되었음을 알리는 알림을 확인할 수 있습니다. Compare & pull request 를 선택합니다.

Pull request 작성 화면입니다. 필요시 설명을 추가할 수 있는데, 일단 Create pull request를 선택해 바로 PR(Pull Request)을 생성합니다.

PR이 생성되면 Github Actions workflow에 의해 빌드가 자동으로 수행됩니다. 아래 화면에 표시된 것과 같이 3개의 빌드가 진행중임을 확인할 수 있습니다.

빌드가 모두 성공적으로 끝나면 All checks have passed라고 표시됩니다. 이제 이 PR을 main 브랜치로 병합하면 되는데, brew tap-new를 통해 생성된 Github Actions workflow에는 이 병합 과정에 대한 자동화 스크립트가 포함되어 있습니다.
따라서, 직접 Merge pull request를 선택하지 말고 Labels를 통해 자동화 스크립트를 트리거 시켜야 합니다.

Github Actions workflows 중 .github/workflows/publish.yml 파일에 정의된 내용을 확인해 보면, 아래와 같이 pr-pull 이라는 라벨이 설정되면 동작하도록 작성되어 있습니다.
name: brew pr-pull
on:
pull_request_target:
types:
- labeled
jobs:
pr-pull:
if: contains(github.event.pull_request.labels.*.name, 'pr-pull')
...따라서, pr-pull 라벨을 선택하면 되는데, 기본적으로 Github 저장소 생성시 자동으로 제공되는 Labels 목록에 포함되어 있지 않기 때문에 직접 추가해야 합니다.
Label 추가를 위해 Issues 메뉴에서 Labels를 선택합니다.

현재 사용 가능한 Label 목록이 나타나는데, New label을 선택합니다.

Label 생성 화면에서 이름에 pr-pull을 입력한 뒤 Create label을 선택합니다. Label 색상은 기본값을 사용해도 되고 랜덤으로 선택하거나, 직접 색상 코드를 입력해도 됩니다.

이제 아래와 같이 Label 목록에 pr-pull이 추가되었습니다.

다시 Pull requests 화면으로 돌아가서 Labels 항목에 있는 톱니바퀴 아이콘을 선택한 뒤, 위에서 생성한 pr-pull 라벨을 선택합니다.

라벨이 선택되면, 위의 Workflow에 정의된 트리거에 의해 빌드가 추가적으로 수행됩니다.

빌드가 성공적으로 끝나면, Pull request가 자동으로 Closed 처리되고, main 브랜치에 반영되는데, Formula 파일의 bottle 부분이 아래와 같이 자동으로 채워진 상태로 추가됩니다.
...
bottle do
root_url "https://github.com/webispy/homebrew-haha/releases/download/aln-0.1.0"
sha256 cellar: :any, arm64_sonoma: "1521a642335a82a6e039109f22730476d7180e92a1fe6ffb04348e01a42503d9"
sha256 cellar: :any, ventura: "8143c23b5fb4650b31dc6ca90eaaa6c3ea15615ff405fed4a1c588bc3e6ecba9"
sha256 cellar: :any_skip_relocation, x86_64_linux: "1eb42a074a8698120b27d65d460dc2e1feb7a959a0edb3c20dd3190eeddb0221"
end
...
Bottle이 정상적으로 잘 배포되었는지 확인해 보겠습니다. 배포는 Github Releases를 통해 진행되는데, Github 저장소 기본 화면을 보면 오른쪽 Releases에 aln-0.1.0이 추가된 것을 확인할 수 있습니다.
상세 내용을 확인해보기 위해 Releases를 선택합니다.

아래와 같이 정상적으로 3개의 Bottle이 생성된 것을 확인할 수 있습니다.
- aln-0.1.0.arm64_sonoma.bottle.tar.gz (macOS 14 - Apple Silicon Mac)
- aln-0.1.0.ventura.bottle.tar.gz (macOS 13 - Intel Mac)
- aln-0.1.0.x86_64_linux.bottle.tar.gz (Linux - x86_64)

지금까지 Tap을 통해 Formula를 배포하는 방법에 대해 알아보았습니다. 다음 단계에서는 배포한 Formula가 정상적으로 설치되는지 확인해 보겠습니다.
이전 단계에서 Github Releases를 통해 배포한 Formula가 Homebrew를 통해 정상적으로 설치되는지 확인해 보겠습니다.
먼저 작업했던 tap을 제거하고 시작하겠습니다:
$ brew untap webispy/aln
Untapping webispy/aln...
Untapped 1 formula (15 files, 11.5KB).Tap에서 배포하는 Formula 설치시, Tap을 먼저 추가하고 Formula를 설치하거나 Formula 이름에 Tap을 포함시켜서 한번에 설치할 수 있습니다.
Tap을 먼저 추가하고 Formula 설치:
$ brew tap webispy/aln
Tapped 1 formula (15 files, 11.5KB).
$ brew install aln
==> Fetching webispy/aln/aln
==> Downloading https://github.com/webispy/homebrew-aln/releases/download/aln-0.1.0/aln-0.1.0.arm64_sonoma.bottle.tar.gz
Already downloaded: /Users/work/Library/Caches/Homebrew/downloads/5bcd7a6e2afabcaa8cab7b038840b65fe9c56b3f607fd87a841cf195a255fbed--aln-0.1.0.arm64_sonoma.bottle.tar.gz
==> Installing aln from webispy/aln
==> Pouring aln-0.1.0.arm64_sonoma.bottle.tar.gz
🍺 /opt/homebrew/Cellar/aln/0.1.0: 12 files, 151.5KB
==> Running `brew cleanup aln`...Formula 이름에 Tap을 포함시켜서 한번에 설치:
$ brew install webispy/aln/aln
Tapped 1 formula (15 files, 11.5KB).
==> Fetching webispy/aln/aln
==> Downloading https://github.com/webispy/homebrew-aln/releases/download/aln-0.1.0/aln-0.1.0.arm64_sonoma.bottle.tar.gz
Already downloaded: /Users/work/Library/Caches/Homebrew/downloads/5bcd7a6e2afabcaa8cab7b038840b65fe9c56b3f607fd87a841cf195a255fbed--aln-0.1.0.arm64_sonoma.bottle.tar.gz
==> Installing aln from webispy/aln
==> Pouring aln-0.1.0.arm64_sonoma.bottle.tar.gz
🍺 /opt/homebrew/Cellar/aln/0.1.0: 12 files, 151.5KB
==> Running `brew cleanup aln`...이렇게 해서 macOS에서 Homebrew Formula를 작성하고 TAP을 통해 bottle 패키지를 배포하는 과정을 살펴보았습니다. Homebrew의 다양한 기능과 TAP을 활용하면, 자신만의 패키지를 손쉽게 배포하고 관리할 수 있습니다. 이번 글이 여러분의 Homebrew 활용에 도움이 되길 바랍니다.