Publish Personal Tools with Homebrew Tap 
Background 
Previously, I used Go's cobra/cobra library to develop a command-line tool, which greatly simplified many daily tasks. When colleagues saw this tool, they also wanted to try it. At first, I planned to distribute it directly via GitHub Actions, letting them download and use it themselves. However, since some colleagues have trouble accessing GitHub from within China and most of them are MacOS users, I decided to use the more convenient Homebrew for distribution. Homebrew is a very popular package manager on MacOS, making it easy to install and manage various software packages.
So, I decided to automate the tool's release using GitHub Actions and GoReleaser, and distribute it via Homebrew, so colleagues can simply run brew install to easily install and use the tool.

Packaging with GitHub Actions 
Before using GitHub Actions for packaging, we first need to create a tag for the project. This tag will be used to identify the version and trigger the GitHub Actions workflow.
Step 1: Tag the Project 
Use the following commands to create a tag and push it to the remote repository:
git tag v1.0.0
git push origin v1.0.1Now, our first version tag v1.0.0 is created and pushed to GitHub, ready for automated release.
Step 2: Configure GitHub Actions Workflow 
Next, we need to create a GitHub Actions workflow configuration file (.yml) in the project to define how to build, test, and release the tool. Here is a sample configuration:
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
name: Go
on:
  push:
    branches: [ "master" ]
    tags:
      - 'v*.*.*'
  pull_request:
    branches: [ "master" ]
jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        goos: [linux, darwin, windows]
        goarch: [amd64, arm64]
    steps:
    - uses: actions/checkout@v4
    - name: Set up Go
      uses: actions/setup-go@v4
      with:
        go-version: "1.22"
    - name: Build
      run: |
          mkdir -p ./dist/${{ matrix.goos }}_${{ matrix.goarch }}
          GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -o ./dist/${{ matrix.goos }}_${{ matrix.goarch }}/pf_tools-${{ matrix.goos }}_${{ matrix.goarch }}${{ matrix.goos == 'windows' && '.exe' || '' }} -v ./main.go
    - name: Test
      run: go test -v ./...
    - name: Upload artifacts
      uses: actions/upload-artifact@v3
      with:
        name: pf_tools-${{ matrix.goos }}_${{ matrix.goarch }}
        path: ./dist/${{ matrix.goos }}_${{ matrix.goarch }}/pf_tools*
  release:
    needs: [build]
    runs-on: ubuntu-latest
    steps:
      - name: Download Linux artifacts
        uses: actions/download-artifact@v3
        with:
          name: pf_tools-linux_amd64
          path: ./dist/linux_amd64/
      - name: Download artifacts
        uses: actions/download-artifact@v3
        with:
          name: pf_tools-darwin_amd64
          path: ./dist/darwin_amd64/
      - name: Download artifacts
        uses: actions/download-artifact@v3
        with:
          name: pf_tools-darwin_arm64
          path: ./dist/darwin_arm64/
      - name: Download artifacts
        uses: actions/download-artifact@v3
        with:
          name: pf_tools-windows_amd64
          path: ./dist/windows_amd64/
      - name: Create Release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: Release ${{ github.ref }}
          draft: false
          prerelease: false
      - name: Upload Release Asset Linux
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: ./dist/linux_amd64/pf_tools-linux_amd64
          asset_name: pf_tools-linux_amd64
          asset_content_type: application/octet-stream
      - name: Upload Release Asset macOS amd
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: ./dist/darwin_amd64/pf_tools-darwin_amd64
          asset_name: pf_tools-darwin_amd64
          asset_content_type: application/octet-stream
      - name: Upload Release Asset macOS arm
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: ./dist/darwin_arm64/pf_tools-darwin_arm64
          asset_name: pf_tools-darwin_arm64
          asset_content_type: application/octet-stream
      - name: Upload Release Asset Windows
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: ./dist/windows_amd64/pf_tools-windows_amd64.exe
          asset_name: pf_tools-windows_amd64.exe
          asset_content_type: application/octet-streamWith this GitHub Actions configuration, we can automatically build, test, and release the tool for various platforms (Linux, macOS, Windows), and publish the built binaries to the corresponding Release version.
The final Release contains the following files:
pf_tools-linux_amd64
pf_tools-darwin_amd64
pf_tools-windows_amd64.exe
Publish to Homebrew 
To allow other users to easily install and use our tool via Homebrew, we need to publish it to Homebrew.
Preparation 
In the previous steps, we have generated the tool binaries for each platform. Next, we need to copy the download links for these files and create a Ruby formula file (.rb), which will be used to define how to install our tool in Homebrew.

Create Homebrew Formula 
Run the following command to create an initial Homebrew formula file:
brew create https://github.com/PFinal-tool/pf_tools/releases/download/v1.0.0/pf_tools-darwin_amd64PS: If you get the error "No available tap homebrew/core.", it means homebrew/core is not installed. Run brew tap --force homebrew/core to install it.
After creating the formula, an initial .rb file will be generated, with content like this:
# Documentation: https://docs.brew.sh/Formula-Cookbook
#                https://rubydoc.brew.sh/Formula
# PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST!
class PfTools < Formula
  desc "A command-line tool developed with Go"
  homepage ""
  url "https://github.com/PFinal-tool/pf_tools/releases/download/v1.0.0/pf_tools-darwin_amd64"
  sha256 "ea263aa15e0b5376d1238fbe3d9c394cda335679ab4a0f44467a5cd6eb03334b"
  license "NOASSERTION"
  # 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 pf_tools`. 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
endThis is a configuration file for a single platform. To support multiple platforms, we need to modify it:
class PfTools < Formula
  desc "A collection of command-line tools"
  homepage "https://github.com/PFinal-tool/pf_tools"
  version "1.0.1"
