From f2176ddf99db667a65b07e11536fd5edbc260fc2 Mon Sep 17 00:00:00 2001 From: Jason Jin Date: Thu, 29 Oct 2026 10:07:11 -0700 Subject: [PATCH 1/2] Add release builds with GoReleaser Tagging vX.Y.Z now publishes a GitHub release with binaries for macOS, Linux and Windows (amd64/arm64) plus checksums, and updates a Homebrew cask in funkyhq/homebrew-tap once HOMEBREW_TAP_TOKEN is set. - main moves to cmd/funky, so `go install .../cmd/funky@latest` installs a `funky` binary instead of `cli`. - `funky --version` reports the release version, the module version for `go install`, or "dev". - CI runs vet and tests and a snapshot release build on every PR. Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/workflows/ci.yml | 36 +++++++++++++++++++++ .github/workflows/release.yml | 28 ++++++++++++++++ .gitignore | 1 + .goreleaser.yaml | 61 +++++++++++++++++++++++++++++++++++ README.md | 30 ++++++++++++++++- main.go => cmd/funky/main.go | 5 +-- cmd/root.go | 17 ++++++++++ 7 files changed, 173 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 .goreleaser.yaml rename main.go => cmd/funky/main.go (61%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..5badfd5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,36 @@ +name: CI + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-go@v7 + with: + go-version-file: go.mod + - run: go vet ./... + - run: go test -race ./... + + # Builds every release target without publishing, so a broken + # .goreleaser.yaml shows up here instead of on a tag. + release-snapshot: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + - uses: actions/setup-go@v7 + with: + go-version-file: go.mod + - uses: goreleaser/goreleaser-action@v7 + with: + version: "~> v2" + args: release --snapshot --clean diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..74e624a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,28 @@ +name: Release + +on: + push: + tags: ["v*"] + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 # the changelog needs the previous tag + - uses: actions/setup-go@v7 + with: + go-version-file: go.mod + - run: go test ./... + - uses: goreleaser/goreleaser-action@v7 + with: + version: "~> v2" + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # A fine-grained token with contents: write on funkyhq/homebrew-tap. + HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..849ddff --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +dist/ diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..6156919 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,61 @@ +# Release builds: push a vX.Y.Z tag and .github/workflows/release.yml runs +# `goreleaser release`. Check changes locally with +# `goreleaser release --snapshot --clean`. +version: 2 + +project_name: funky + +builds: + - main: ./cmd/funky + binary: funky + env: + # Static binaries: the keychain libraries need no cgo on any OS. + - CGO_ENABLED=0 + goos: [darwin, linux, windows] + goarch: [amd64, arm64] + flags: [-trimpath] + ldflags: + - -s -w -X github.com/funkyhq/cli/cmd.version={{ .Version }} + +archives: + # No version in the names, so releases/latest/download/ always + # points at the newest build (for install scripts and docs). + - name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}" + formats: [tar.gz] + format_overrides: + - goos: windows + formats: [zip] + +checksum: + name_template: checksums.txt + +changelog: + use: github + filters: + exclude: + - "^docs:" + - "^test:" + +release: + # A tag like v0.2.0-rc.1 is published as a pre-release. + prerelease: auto + +homebrew_casks: + - name: funky + binaries: [funky] + homepage: https://funky.dev + description: Manage Funky agents as code + repository: + owner: funkyhq + name: homebrew-tap + token: "{{ .Env.HOMEBREW_TAP_TOKEN }}" + # Until the tap and its token exist, release without it. + skip_upload: '{{ if isEnvSet "HOMEBREW_TAP_TOKEN" }}auto{{ else }}true{{ end }}' + hooks: + post: + # The binary isn't signed or notarized yet; without this, macOS + # refuses to run a cask-installed binary. + install_steps: | + on_macos do + run "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "{{ .StagedPath }}/funky"] + end diff --git a/README.md b/README.md index e922fb0..e02d123 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,24 @@ Manage [Funky Cloud](https://platform.funky.dev) agents as code. Describe each agent in a YAML file, then `funky apply` creates or updates it — like Terraform, for agent configs. +## Install + +```bash +brew install funkyhq/tap/funky +``` + +Or download a binary for macOS, Linux or Windows from the +[latest release](https://github.com/funkyhq/cli/releases/latest), or, with Go installed: + ```bash -go install github.com/funkyhq/cli@latest # installs as `cli`; or `go build -o funky .` +go install github.com/funkyhq/cli/cmd/funky@latest +``` + +`funky --version` shows the installed version. + +## Quick start +```bash funky login # opens your browser: sign in, pick a project, approve this machine funky init # creates agents/ $EDITOR agents/researcher.yaml @@ -63,7 +78,20 @@ precedence over a login. ```bash go test ./... +go run ./cmd/funky --help ``` `FUNKY_API_URL`, `FUNKY_CONSOLE_URL` and `FUNKY_PLATFORM_URL` point the CLI at non-production services; `FUNKY_CONFIG_DIR` moves where the login is saved. + +## Releasing + +Push a version tag; the release workflow builds every platform with +[GoReleaser](https://goreleaser.com), publishes a GitHub release and updates the Homebrew tap: + +```bash +git tag v0.1.0 && git push origin v0.1.0 +``` + +A tag with a suffix (`v0.2.0-rc.1`) becomes a pre-release and skips the tap. To try the build +locally: `goreleaser release --snapshot --clean` (output in `dist/`). diff --git a/main.go b/cmd/funky/main.go similarity index 61% rename from main.go rename to cmd/funky/main.go index 737e1fb..26e9cc3 100644 --- a/main.go +++ b/cmd/funky/main.go @@ -1,7 +1,4 @@ -/* -Copyright © 2026 NAME HERE - -*/ +// Command funky manages Funky agents as code. package main import "github.com/funkyhq/cli/cmd" diff --git a/cmd/root.go b/cmd/root.go index 6e43832..a422e0c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "os" + "runtime/debug" "strings" "github.com/spf13/cobra" @@ -26,9 +27,25 @@ infrastructure: describe each agent in agents/.yaml, then run In CI, set FUNKY_API_KEY to a key from https://platform.funky.dev/api-keys instead of logging in; it takes precedence over a login.`, + Version: buildVersion(), SilenceUsage: true, } +// version is set by release builds (-ldflags "-X ...cmd.version=1.2.3"). +var version = "" + +// buildVersion is the release version, or the module version `go install` +// records, or "dev" for a local build. +func buildVersion() string { + if version != "" { + return version + } + if info, ok := debug.ReadBuildInfo(); ok && info.Main.Version != "" && info.Main.Version != "(devel)" { + return strings.TrimPrefix(info.Main.Version, "v") + } + return "dev" +} + // Execute adds all child commands to the root command and sets flags appropriately. // This is called by main.main(). It only needs to happen once to the rootCmd. func Execute() { From a3dbc8d64ae031b867e7eae08b42322bc09a4a94 Mon Sep 17 00:00:00 2001 From: Jason Jin Date: Thu, 29 Oct 2026 10:36:40 -0700 Subject: [PATCH 2/2] Drop the Homebrew tap; npm comes next Co-Authored-By: Claude Opus 5.5 (1M context) --- .github/workflows/release.yml | 2 -- .goreleaser.yaml | 20 -------------------- README.md | 10 +++------- 3 files changed, 3 insertions(+), 29 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 74e624a..fc2fcde 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,5 +24,3 @@ jobs: args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # A fine-grained token with contents: write on funkyhq/homebrew-tap. - HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 6156919..2d7776c 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -39,23 +39,3 @@ changelog: release: # A tag like v0.2.0-rc.1 is published as a pre-release. prerelease: auto - -homebrew_casks: - - name: funky - binaries: [funky] - homepage: https://funky.dev - description: Manage Funky agents as code - repository: - owner: funkyhq - name: homebrew-tap - token: "{{ .Env.HOMEBREW_TAP_TOKEN }}" - # Until the tap and its token exist, release without it. - skip_upload: '{{ if isEnvSet "HOMEBREW_TAP_TOKEN" }}auto{{ else }}true{{ end }}' - hooks: - post: - # The binary isn't signed or notarized yet; without this, macOS - # refuses to run a cask-installed binary. - install_steps: | - on_macos do - run "/usr/bin/xattr", args: ["-dr", "com.apple.quarantine", "{{ .StagedPath }}/funky"] - end diff --git a/README.md b/README.md index e02d123..9b74284 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,7 @@ file, then `funky apply` creates or updates it — like Terraform, for agent con ## Install -```bash -brew install funkyhq/tap/funky -``` - -Or download a binary for macOS, Linux or Windows from the +Download a binary for macOS, Linux or Windows from the [latest release](https://github.com/funkyhq/cli/releases/latest), or, with Go installed: ```bash @@ -87,11 +83,11 @@ services; `FUNKY_CONFIG_DIR` moves where the login is saved. ## Releasing Push a version tag; the release workflow builds every platform with -[GoReleaser](https://goreleaser.com), publishes a GitHub release and updates the Homebrew tap: +[GoReleaser](https://goreleaser.com) and publishes a GitHub release: ```bash git tag v0.1.0 && git push origin v0.1.0 ``` -A tag with a suffix (`v0.2.0-rc.1`) becomes a pre-release and skips the tap. To try the build +A tag with a suffix (`v0.2.0-rc.1`) becomes a pre-release. To try the build locally: `goreleaser release --snapshot --clean` (output in `dist/`).