diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..b748dd4 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,64 @@ +name: release + +on: + push: + tags: + - "v*" + workflow_dispatch: + inputs: + tag_name: + description: "Existing release tag to publish, for example v0.1.0" + required: true + type: string + +permissions: + contents: write + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" + NODE_VERSION: "24" + PNPM_VERSION: "11.0.7" + +jobs: + release: + name: GoReleaser + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - name: Check out + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ inputs.tag_name || github.ref }} + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Set up pnpm + uses: pnpm/action-setup@v4 + with: + version: ${{ env.PNPM_VERSION }} + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Run local gate + run: pnpm check + + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + distribution: goreleaser + version: "~> v2" + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100644 index 0000000..aacfffe --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,91 @@ +version: 2 + +project_name: clickclack + +before: + hooks: + - pnpm build + +builds: + - id: clickclack + main: ./apps/api/cmd/clickclack + binary: clickclack + env: + - CGO_ENABLED=0 + goos: + - linux + - windows + - darwin + - freebsd + goarch: + - amd64 + - arm64 + flags: + - -trimpath + ldflags: + - >- + -s -w + -X main.version={{ .Version }} + -X main.commit={{ .ShortCommit }} + -X main.date={{ .Date }} + +archives: + - id: bundles + ids: + - clickclack + name_template: >- + {{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{- if eq .Arch "arm64" -}}aarch64{{- else -}}{{ .Arch }}{{- end -}} + formats: + - tar.gz + format_overrides: + - goos: windows + formats: + - zip + files: + - LICENSE + - README.md + - SPEC.md + - CHANGELOG.md + - docs/**/* + +checksum: + name_template: "sha256sums.txt" + algorithm: sha256 + +snapshot: + version_template: "{{ incpatch .Version }}-next" + +changelog: + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" + - "^ci:" + - "^chore:" + - "^Merge pull request" + - "^Merge branch" + +nfpms: + - id: linux-packages + ids: + - clickclack + package_name: clickclack + file_name_template: "{{ .ConventionalFileName }}" + homepage: https://clickclack.chat + maintainer: OpenClaw + description: Self-hostable chat with Slack-style threads, durable realtime, OpenAPI, and a TypeScript SDK. + license: MIT + formats: + - deb + - rpm + bindir: /usr/bin + section: utils + priority: optional + contents: + - src: ./README.md + dst: /usr/share/doc/clickclack/README.md + - src: ./LICENSE + dst: /usr/share/doc/clickclack/LICENSE + - src: ./SPEC.md + dst: /usr/share/doc/clickclack/SPEC.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 546c34a..ffc10ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,3 +17,5 @@ quickstart CTA contrast in dark mode. - Split GitHub Actions into explicit Go, TypeScript, Playwright, and Docker gates, with `gofmt` and `oxfmt --check` enforced in CI. +- Added GoReleaser config and release workflow for Linux, macOS, Windows, and + FreeBSD archives, plus Linux `.deb` and `.rpm` packages. diff --git a/README.md b/README.md index 04deb1d..da16823 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,8 @@ short `read_when` hint at the top — open the one that matches your change. - [Data model](docs/data-model.md) — tables, IDs, invariants. - [CLI](docs/cli.md), [Agent-friendly CLI](docs/agent-friendly-cli.md), [Configuration](docs/configuration.md), - [Deployment](docs/deployment.md), [Development](docs/development.md). + [Deployment](docs/deployment.md), [Development](docs/development.md), + [Releasing](docs/releasing.md). - [TypeScript SDK](docs/sdk.md). Per-feature docs: @@ -156,6 +157,7 @@ pnpm coverage # Go coverage with 90% gate pnpm test:e2e # Playwright pnpm fmt # gofmt + oxfmt write pnpm fmt:check # gofmt + oxfmt check, CI-compatible +goreleaser release --snapshot --clean # local release smoke test ``` ## Deployment diff --git a/apps/api/cmd/clickclack/main.go b/apps/api/cmd/clickclack/main.go index e4ffb42..55e1600 100644 --- a/apps/api/cmd/clickclack/main.go +++ b/apps/api/cmd/clickclack/main.go @@ -17,6 +17,12 @@ import ( sqlitestore "github.com/openclaw/clickclack/apps/api/internal/store/sqlite" ) +var ( + version = "dev" + commit = "none" + date = "unknown" +) + func main() { if err := run(); err != nil { log.Fatal(err) @@ -39,6 +45,9 @@ func run() error { return backup(os.Args[2:]) case "export": return exportData(os.Args[2:]) + case "version": + fmt.Printf("clickclack %s (%s, %s)\n", version, commit, date) + return nil default: return client(os.Args[1:]) } diff --git a/docs/README.md b/docs/README.md index b8dc925..efc8a40 100644 --- a/docs/README.md +++ b/docs/README.md @@ -70,6 +70,7 @@ it for anything that isn't a local clone. - [Configuration](configuration.md) — flag/env/file precedence. - [Deployment](deployment.md) — single binary, Docker, data layout, OAuth. - [Development](development.md) — pnpm scripts, monorepo layout, gates. +- [Releasing](releasing.md) — GoReleaser targets, artifacts, and tag flow. ## Look under the hood diff --git a/docs/deployment.md b/docs/deployment.md index 0bb2237..12c3c6a 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -30,6 +30,22 @@ The Go build step requires the SPA `dist/` to be present because `webassets` uses `go:embed`. The `pnpm build` script copies `apps/web/dist` into `apps/api/internal/webassets/dist`; CI must run it before `go build`. +## Releases + +GoReleaser is configured in `.goreleaser.yml`. It builds `clickclack` for +Linux, macOS, Windows, and FreeBSD on `amd64` and `arm64`, with Windows +archives emitted as `.zip` and the others as `.tar.gz`. Linux `.deb` and +`.rpm` packages are generated through nfpm. + +```sh +pnpm install +goreleaser release --snapshot --clean +``` + +The GoReleaser config runs `pnpm build` before compiling so the embedded SPA +is refreshed. Publishing is handled by `.github/workflows/release.yml` on +`v*` tags or manual dispatch with an existing tag. + ## Docker The provided `Dockerfile` is multi-stage: diff --git a/docs/development.md b/docs/development.md index 4273b00..61378e6 100644 --- a/docs/development.md +++ b/docs/development.md @@ -55,6 +55,7 @@ The Vite dev server proxies `/api` and `/api/realtime/ws` to `localhost:8080`. | `pnpm fmt` | `gofmt` + `oxfmt` over Go and TS/Svelte. | | `pnpm fmt:check` | CI-compatible formatting check with `gofmt -l` and `oxfmt --check`. | | `pnpm lint` | `oxlint` over web, SDK, examples, and tests. | +| `goreleaser release --snapshot --clean` | Local release smoke test for all configured OS/arch targets. | | `pnpm typecheck` | `tsgo --noEmit -p tsconfig.json` for root Playwright config/tests. | | `pnpm test` | `go test ./... && pnpm build`. | | `pnpm test:e2e` | Playwright suite in `tests/e2e`. | diff --git a/docs/install.md b/docs/install.md index e55575d..090e3e6 100644 --- a/docs/install.md +++ b/docs/install.md @@ -53,8 +53,21 @@ docker run --rm -v clickclack-data:/app/data clickclack \ ## Pre-built binaries -There are no published release artifacts yet — V1 ships from source. Once -binaries land, this page will list the canonical install line. +GitHub releases publish `clickclack` archives for Linux, macOS, Windows, and +FreeBSD on `amd64` and `arm64`, plus Linux `.deb` and `.rpm` packages. + +```sh +# macOS/Linux tarball shape +tar -xzf clickclack___.tar.gz +./clickclack version + +# Linux packages +sudo dpkg -i clickclack__amd64.deb +sudo rpm -i clickclack--1.x86_64.rpm +``` + +Release archives include `LICENSE`, `README.md`, `SPEC.md`, `CHANGELOG.md`, +and the docs tree. Checksums are published as `sha256sums.txt`. ## What you get diff --git a/docs/releasing.md b/docs/releasing.md new file mode 100644 index 0000000..41d0c12 --- /dev/null +++ b/docs/releasing.md @@ -0,0 +1,46 @@ +--- +read_when: + - cutting a ClickClack release + - changing GoReleaser, package artifacts, or release automation +--- + +# Releasing + +ClickClack uses GoReleaser v2. The config is `.goreleaser.yml`; the GitHub +Actions publisher is `.github/workflows/release.yml`. + +## Local Smoke Test + +```sh +pnpm install +goreleaser check +goreleaser release --snapshot --clean +``` + +The snapshot build runs `pnpm build`, then cross-compiles `clickclack` for: + +- `linux/amd64` +- `linux/arm64` +- `darwin/amd64` +- `darwin/arm64` +- `windows/amd64` +- `windows/arm64` +- `freebsd/amd64` +- `freebsd/arm64` + +It also emits Linux `.deb` and `.rpm` packages and `sha256sums.txt`. + +## Publish + +Push a semver tag: + +```sh +git tag v0.1.0 +git push origin v0.1.0 +``` + +The release workflow checks out the tag, installs Go and pnpm, runs +`pnpm check`, then runs `goreleaser release --clean` with `GITHUB_TOKEN`. + +Manual release dispatch is available for an existing tag through the +`release` workflow's `tag_name` input. diff --git a/scripts/build-docs-site.mjs b/scripts/build-docs-site.mjs index a97f661..f9e86be 100644 --- a/scripts/build-docs-site.mjs +++ b/scripts/build-docs-site.mjs @@ -38,6 +38,7 @@ const sections = [ "configuration.md", "deployment.md", "development.md", + "releasing.md", "sdk.md", ]], ["Reference", [