Recently, I built a CLI tool called BulkPR for my job. It’s a simple app, but it works for what I needed. However, one challenge I faced was distribution. My colleagues use different systems-some on Windows, some on MacOS-and I need a way to ensure the tool worked smoothly across all environments.
The Problem: Cross-Platform Distribution with Docker and Go
At first, I tried to solve the cross-platform issue by using Go’s built-in GOOS
and GOARCH
environment variables to build different binaries for each platform. This approach worked in theory, but I didn’t have access to the devices I needed to test on, so just made a workflow for that.
name: Build
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
os: [linux, windows, darwin]
arch: [amd64]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.23"
- name: Build the executable
run: |
GOOS=${{ matrix.os }} GOARCH=${{ matrix.arch }} go build -o bulkpr-${{ matrix.os }}-${{ matrix.arch }} main.go
- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
name: bulkpr-${{ matrix.os }}-${{ matrix.arch }}
path: bulkpr-${{ matrix.os }}-${{ matrix.arch }}
Around the same time, I was working on a open-source project and needed to set up development environment using Docker. This got me thinking: maybe I could use Docker to distribute the app. But there was still one challenge: my CLI uses gh auth
under thee hood. This made it more complicated since I need to manage Github authentication across environments.
The Revelation: Github CLI Extensions
Then it hit me: if my tool already use gh auth
, why not make it a part of the Github CLI ecosystem as an extension? This would simplify the authentication process and, more importantly, it would make distribution much easier.
Migrating to Github CLI Extension
The migration process turned out to be surprisingly straightforward.
- Renaming the Project
Since GitHub CLI extensions need to start withgh-
, I renamed my project from bulkpr to gh-bulkpr. - Setting Up the Extension
Next, I created the executable for my app and added it as a GitHub CLI extension using thegh extension add .
command. - Testing and Deploying
After making suer everything worked, I push it to GitHub. Then, I set up a workflow to automatically distribute the app.
name: Release
on:
push:
tags:
- "v*"
workflow_dispatch:
permissions:
contents: write
id-token: write
attestations: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: cli/gh-extension-precompile@v2
with:
generate_attestations: true
go_version_file: go.mod
- Distribution Made Easy
Now, any of my colleagues can easily install the app
gh extension add l-lumin/gh-bulkpr
With that, the installation process is incredibly simpler.
Conclusion
At first, migrating my app to a GitHub extension felt like I was losing the original idea. However, it ended up saving me a lot overhead by solving distribution and authentication issues across systems.
Check Out the Project
You can find gh-bulkpr on GitHub.