diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..231ed0a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,59 @@ +name: Release + +# Builds the fmsg binary for each platform and attaches the archives to the +# GitHub release. Runs when a release is published; run it by hand with a tag +# to (re)build an existing release's binaries. +on: + release: + types: [published] + workflow_dispatch: + inputs: + tag: + description: Release tag to build, e.g. v0.3.0 + required: true + +permissions: + contents: write + +jobs: + binaries: + runs-on: ubuntu-latest + env: + TAG: ${{ github.event.release.tag_name || inputs.tag }} + steps: + - uses: actions/checkout@v7 + with: + ref: ${{ env.TAG }} + + - name: Set up Go + uses: actions/setup-go@v7 + with: + go-version: "1.27.x" + + - name: Build + run: | + set -euo pipefail + mkdir -p dist + for target in linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64 windows/arm64; do + os=${target%/*} + arch=${target#*/} + bin=fmsg + [ "$os" = windows ] && bin=fmsg.exe + out="build/${os}_${arch}" + mkdir -p "$out" + CGO_ENABLED=0 GOOS=$os GOARCH=$arch go build -trimpath \ + -ldflags "-s -w -X github.com/markmnl/fmsg-cli/cmd.version=$TAG" \ + -o "$out/$bin" . + cp LICENSE README.md "$out/" + if [ "$os" = windows ]; then + (cd "$out" && zip -q "$GITHUB_WORKSPACE/dist/fmsg_${os}_${arch}.zip" "$bin" LICENSE README.md) + else + tar -C "$out" -czf "dist/fmsg_${os}_${arch}.tar.gz" "$bin" LICENSE README.md + fi + done + (cd dist && sha256sum * > checksums.txt) + + - name: Upload to the release + env: + GH_TOKEN: ${{ github.token }} + run: gh release upload "$TAG" dist/* --clobber diff --git a/README.md b/README.md index c5dcdf4..277dfb0 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,26 @@ Command-line interface to [fmsg-webapi](https://github.com/markmnl/fmsg-webapi) fronting a fmsgd instance. -## Requirements +## Install -- Go 1.27 or newer +Download the `fmsg` binary for your platform from the +[latest release](https://github.com/markmnl/fmsg-cli/releases/latest), e.g. on +Linux (x86-64): -## Build +```sh +curl -fsSL https://github.com/markmnl/fmsg-cli/releases/latest/download/fmsg_linux_amd64.tar.gz | tar -xz fmsg +sudo mv fmsg /usr/local/bin/ +fmsg --version +``` + +Archives are named `fmsg__` for `linux`, `darwin` (macOS) and +`windows` (a `.zip`), on `amd64` and `arm64`; `checksums.txt` has their +SHA-256 sums. Publishing a GitHub release builds and attaches them +(`.github/workflows/release.yml`). + +## Build from source + +Requires Go 1.27 or newer. ```sh go build -o fmsg diff --git a/cmd/root.go b/cmd/root.go index dfd3638..27d8858 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -6,15 +6,33 @@ import ( "errors" "fmt" "os" + "runtime/debug" "slices" "unicode" "github.com/spf13/cobra" ) +// version is set by release builds with +// -ldflags "-X github.com/markmnl/fmsg-cli/cmd.version=v1.2.3". +var version = "" + +// buildVersion reports the release version, falling back to the module +// version recorded by `go install ...@version`, then "dev". +func buildVersion() string { + if version != "" { + return version + } + if info, ok := debug.ReadBuildInfo(); ok && info.Main.Version != "" && info.Main.Version != "(devel)" { + return info.Main.Version + } + return "dev" +} + var rootCmd = &cobra.Command{ - Use: "fmsg", - Short: "fmsg — command-line interface to an fmsg messaging server", + Use: "fmsg", + Version: buildVersion(), + Short: "fmsg — command-line interface to an fmsg messaging server", Long: `fmsg is a CLI that communicates with an fmsg-webapi server. Before using any command, authenticate with: