Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
FURY_TOKEN: ${{ secrets.FURY_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

- uses: actions/upload-artifact@v4
with:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ docs.kosli.com/resources/_gen/*
docs.kosli.com/content/client_reference/kosli*
docs.kosli.com/public/
docs.kosli.com/.netlify
npm/cli*/bin/*
npm/*/kosli*.tgz
*.tar.gz
*~
/.idea
Expand Down
25 changes: 22 additions & 3 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ project_name: kosli
before:
hooks:
- go mod tidy
- rm -rf npm/cli-*/bin
- find npm -name "*.tgz" -delete
builds:
- id: kosli
binary: kosli
Expand All @@ -27,6 +29,19 @@ builds:
- goos: windows
goarch: arm
main: ./cmd/kosli/
hooks:
post:
- cmd: >-
bash -c '
OS="{{ .Os }}";
ARCH="{{ .Arch }}";
[ "$OS" = "windows" ] && OS="win32";
[ "$ARCH" = "amd64" ] && ARCH="x64";
EXT="";
[ "{{ .Os }}" = "windows" ] && EXT=".exe";
mkdir -p npm/cli-${OS}-${ARCH}/bin &&
cp "{{ .Path }}" npm/cli-${OS}-${ARCH}/bin/kosli${EXT} &&
chmod +x npm/cli-${OS}-${ARCH}/bin/kosli${EXT}'

archives:
-
Expand All @@ -37,11 +52,9 @@ archives:
- goos: windows
formats: [zip]


# docs for nfpm can be found here: https://goreleaser.com/customization/nfpm/
nfpms:
- id: kosli

# You can change the file name of the package.
#
# Default:`{{ .PackageName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}`
Expand Down Expand Up @@ -80,9 +93,15 @@ nfpms:
# GoReleaser will automatically add the binaries.
contents:
# The src and dst attributes also supports name templates
- src: dist/{{ .ProjectName }}_{{ .Os }}_{{ if .Amd64 }}{{ .Arch }}_v1{{ else if .Arm }}{{ .Arch }}_6{{ else if eq .Arch "arm64" }}{{ .Arch }}_v8.0{{ else }}{{ .Arch }}{{ end }}/kosli
- src: dist/{{ .ProjectName }}_{{ .Os }}_{{ if .Amd64 }}{{ .Arch }}_v1{{ else if .Arm }}{{ .Arch }}_6{{ else }}{{ .Arch }}{{ end }}/kosli
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentional change? This removes the {{ else if eq .Arch "arm64" }}{{ .Arch }}_v8.0 clause from the nfpms contents.src template. This changes the expected path for arm64 Linux .deb/.rpm packages from dist/kosli_linux_arm64_v8.0/kosli to dist/kosli_linux_arm64/kosli.

If GoReleaser still produces the _v8.0 suffixed directory, this will break Linux ARM64 .deb/.rpm packaging. Please confirm this matches the directory names GoReleaser actually creates with the version you're using.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Is the arm64 _v8.0 suffix removal intentional? The previous template had {{ else if eq .Arch "arm64" }}{{ .Arch }}_v8.0 which matched GoReleaser's default directory naming for arm64 builds. Removing it changes the expected path from dist/kosli_linux_arm64_v8.0/kosli to dist/kosli_linux_arm64/kosli.

This was also flagged in commit ee7fb466 ("Update goreleaser config to fix arm64 package #711"). If your GoReleaser version no longer produces the _v8.0 suffix, this is fine — but please confirm this matches the actual directory names GoReleaser creates, otherwise Linux ARM64 .deb/.rpm packaging will break.

dst: /usr/local/bin/kosli

after:
hooks:
- cmd: bash scripts/npm-publish.sh "{{ .Version }}"{{ if or .IsSnapshot (not .IsRelease) }} --dry-run{{ end }}
# after hooks suppresses output by default. You need to add output: true to the hook to see the script's messages.
output: true

publishers:
- name: fury.io
# by specifying `packages` id here goreleaser will only use this publisher
Expand Down
12 changes: 10 additions & 2 deletions docs.kosli.com/content/getting_started/install.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
---
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Leading space in frontmatter delimiter. Line 1 is --- (with a leading space) instead of ---. This will break Hugo's frontmatter parsing — the page won't render correctly.

Suggested change
---
---

title: "Part 2: Install Kosli CLI"
bookCollapseSection: false
weight: 220
Expand Down Expand Up @@ -89,6 +89,15 @@ sudo mv kosli /usr/local/bin/kosli

{{< /tab >}}

{{< tab "NPM" >}}
You can install Kosli CLI system-wide with `npm` from the default registry <https://registry.npmjs.org>

```shell {.command}
npm install -g @kosli/cli
```

{{< /tab >}}

{{< tab "From source" >}}
You can build Kosli CLI from source by running:
```shell {.command}
Expand All @@ -100,7 +109,6 @@ make build

{{< /tabs >}}


## Verifying the installation worked

Run this command:
Expand Down
162 changes: 162 additions & 0 deletions npm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# NPM Packaging

This directory contains the npm package structure for distributing the Kosli CLI via npm, following the same pattern used by [esbuild](https://github.com/evanw/esbuild).

## Structure

```
npm/
├── wrapper/ # @kosli/cli — the package users install
│ ├── package.json # declares optionalDependencies for all platforms
│ ├── bin/kosli # JS shim that detects the platform and runs the binary
│ └── install.js # postinstall script that validates the binary
├── cli-linux-x64/ # @kosli/cli-linux-x64
│ ├── package.json # declares os/cpu fields for platform filtering
│ └── bin/kosli # the native binary — see below
├── cli-linux-arm64/ # @kosli/cli-linux-arm64
│ ├── package.json # declares os/cpu fields for platform filtering
│ └── bin/kosli # the native binary — see below
├── cli-linux-arm/ # @kosli/cli-linux-arm
│ ├── package.json # declares os/cpu fields for platform filtering
│ └── bin/kosli # the native binary — see below
├── cli-darwin-x64/ # @kosli/cli-darwin-x64
│ ├── package.json # declares os/cpu fields for platform filtering
│ └── bin/kosli # the native binary — see below
├── cli-darwin-arm64/ # @kosli/cli-darwin-arm64
│ ├── package.json # declares os/cpu fields for platform filtering
│ └── bin/kosli # the native binary — see below
├── cli-win32-x64/ # @kosli/cli-win32-x64
│ ├── package.json # declares os/cpu fields for platform filtering
│ └── bin/kosli[.exe] # the native binary — see below
└── cli-win32-arm64/ # @kosli/cli-win32-arm64
├── package.json # declares os/cpu fields for platform filtering
└── bin/kosli[.exe] # the native binary — see below
```

## How it works

Users install a single package:

```sh
npm install @kosli/cli
```

or if using in continuous integration you can install globally:

```sh
npm install -g @kosli/cli
```

npm resolves the `optionalDependencies` declared in the wrapper's `package.json` and installs only the platform-specific package that matches the current OS and CPU architecture — all non-matching packages are silently skipped. The wrapper's `bin/kosli` JS shim then locates the binary inside the installed platform package and executes it.

## The `bin/` directories are populated by goreleaser

The platform package `bin/` directories are **not committed to git**. They are populated automatically during the release process by a post-build hook in [`.goreleaser.yml`](../.goreleaser.yml):

```yaml
hooks:
post:
- cmd: >-
bash -c '
OS="{{ .Os }}";
ARCH="{{ .Arch }}";
[ "$OS" = "windows" ] && OS="win32";
[ "$ARCH" = "amd64" ] && ARCH="x64";
EXT="";
[ "{{ .Os }}" = "windows" ] && EXT=".exe";
mkdir -p npm/cli-${OS}-${ARCH}/bin &&
cp "{{ .Path }}" npm/cli-${OS}-${ARCH}/bin/kosli${EXT} &&
chmod +x npm/cli-${OS}-${ARCH}/bin/kosli${EXT}'
```

This hook runs once per build target immediately after goreleaser compiles the binary. It applies the following naming conventions:

| goreleaser | npm package dir |
|------------|-----------------|
| `linux` | `linux` |
| `darwin` | `darwin` |
| `windows` | `win32` |
| `amd64` | `x64` |
| `arm64` | `arm64` |
| `arm` | `arm` |

Windows binaries are copied as `kosli.exe`; all others as `kosli`. The `windows/arm` combination is excluded from builds.

The `before` hooks in `.goreleaser.yml` clean up stale artifacts before each build run:

```yaml
before:
hooks:
- rm -rf npm/cli-*/bin
- find npm -name "*.tgz" -delete
```

## Publishing

Packages are published to the [npm public registry](https://registry.npmjs.org). Platform packages must be published before the wrapper, since the wrapper's `optionalDependencies` references them by version. After a goreleaser build has populated the `bin/` directories:

```sh
# Publish platform packages first
(cd npm/cli-linux-x64 && npm publish)
(cd npm/cli-linux-arm64 && npm publish)
(cd npm/cli-linux-arm && npm publish)
(cd npm/cli-darwin-x64 && npm publish)
(cd npm/cli-darwin-arm64 && npm publish)
(cd npm/cli-win32-x64 && npm publish)
(cd npm/cli-win32-arm64 && npm publish)

# Then publish the wrapper
(cd npm/wrapper && npm publish)
```

Each package directory contains an `.npmrc` that sets the auth token:

```text
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
```

## Automated Publishing with npm-publish.sh

The `scripts/npm-publish.sh` script automates the npm packaging and publishing process. It injects the version into all `package.json` files, packs each package into a `.tgz`, and optionally publishes them.

### Usage

```bash
scripts/npm-publish.sh <version> [--dry-run]
```

### Arguments

- `<version>`: Required. A SemVer string — either `X.Y.Z` (stable) or `X.Y.Z-TAG` (pre-release).
- `--dry-run` (optional second argument): Pack packages but skip publishing.

### Behavior

1. Injects `<version>` into the `version` field of all `package.json` files.
2. Updates the `optionalDependencies` version references in `npm/wrapper/package.json` to match.
3. Runs `npm pack` on each platform package, then on the wrapper.
4. Unless `--dry-run` is set, runs `npm publish --tag <tag>` on each package.

The dist-tag is determined by the version format:

| Version format | npm dist-tag |
|----------------|--------------|
| `X.Y.Z` | `latest` |
| `X.Y.Z-*` | `snapshot` |

### Integration with GoReleaser

GoReleaser calls this script automatically via the `after` hook once all platform binaries have been built and copied into the `bin/` directories:

```yaml
after:
hooks:
- cmd: bash scripts/npm-publish.sh "{{ .Version }}" ...
output: true
```

The script output is surfaced in the goreleaser log (`output: true`).

## Versioning

All packages share the same version number. When releasing, `npm-publish.sh` updates it automatically in all eight `package.json` files — the seven platform packages and the wrapper — as well as the `optionalDependencies` version pins in `npm/wrapper/package.json`. There is no need to edit these files manually.
1 change: 1 addition & 0 deletions npm/cli-darwin-arm64/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
1 change: 1 addition & 0 deletions npm/cli-darwin-arm64/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is the macOS ARM 64-bit binary for the Kosli CLI (Apple Silicon). See https://github.com/kosli-dev/cli for details.
20 changes: 20 additions & 0 deletions npm/cli-darwin-arm64/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@kosli/cli-darwin-arm64",
"version": "0.0.0",
"description": "macOS arm64 binary for @kosli/cli",
"license": "MIT",
"os": [
"darwin"
],
"cpu": [
"arm64"
],
"bin": {"kosli": "bin/kosli"},
"files": [
"bin/"
],
"publishConfig": {
"registry": "https://registry.npmjs.org",
"access": "public"
}
}
1 change: 1 addition & 0 deletions npm/cli-darwin-x64/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
1 change: 1 addition & 0 deletions npm/cli-darwin-x64/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is the macOS 64-bit binary for the Kosli CLI. See https://github.com/kosli-dev/cli for details.
20 changes: 20 additions & 0 deletions npm/cli-darwin-x64/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@kosli/cli-darwin-x64",
"version": "0.0.0",
"description": "macOS x64 binary for @kosli/cli",
"license": "MIT",
"os": [
"darwin"
],
"cpu": [
"x64"
],
"bin": {"kosli": "bin/kosli"},
"files": [
"bin/"
],
"publishConfig": {
"registry": "https://registry.npmjs.org",
"access": "public"
}
}
1 change: 1 addition & 0 deletions npm/cli-linux-arm/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
1 change: 1 addition & 0 deletions npm/cli-linux-arm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is the Linux ARM 32-bit binary for the Kosli CLI. See https://github.com/kosli-dev/cli for details.
20 changes: 20 additions & 0 deletions npm/cli-linux-arm/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@kosli/cli-linux-arm",
"version": "0.0.0",
"description": "Linux arm binary for @kosli/cli",
"license": "MIT",
"os": [
"linux"
],
"cpu": [
"arm"
],
"bin": {"kosli": "bin/kosli"},
"files": [
"bin/"
],
"publishConfig": {
"registry": "https://registry.npmjs.org",
"access": "public"
}
}
1 change: 1 addition & 0 deletions npm/cli-linux-arm64/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
1 change: 1 addition & 0 deletions npm/cli-linux-arm64/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is the Linux ARM 64-bit binary for the Kosli CLI. See https://github.com/kosli-dev/cli for details.
20 changes: 20 additions & 0 deletions npm/cli-linux-arm64/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@kosli/cli-linux-arm64",
"version": "0.0.0",
"description": "Linux arm64 binary for @kosli/cli",
"license": "MIT",
"os": [
"linux"
],
"cpu": [
"arm64"
],
"bin": {"kosli": "bin/kosli"},
"files": [
"bin/"
],
"publishConfig": {
"registry": "https://registry.npmjs.org",
"access": "public"
}
}
1 change: 1 addition & 0 deletions npm/cli-linux-x64/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
1 change: 1 addition & 0 deletions npm/cli-linux-x64/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is the Linux 64-bit binary for the Kosli CLI. See https://github.com/kosli-dev/cli for details.
20 changes: 20 additions & 0 deletions npm/cli-linux-x64/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@kosli/cli-linux-x64",
"version": "0.0.0",
"description": "Linux x64 binary for @kosli/cli",
"license": "MIT",
"os": [
"linux"
],
"cpu": [
"x64"
],
"bin": {"kosli": "bin/kosli"},
"files": [
"bin/"
],
"publishConfig": {
"registry": "https://registry.npmjs.org",
"access": "public"
}
}
1 change: 1 addition & 0 deletions npm/cli-win32-arm64/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
Loading
Loading