-
Notifications
You must be signed in to change notification settings - Fork 6
Add npm publishing and update documentation #719
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
24db015
dd7342b
c43ed83
153ff0d
a79527b
9cd8341
0d56678
110bed9
0731aaf
ceea475
3390c14
8d539fa
3121294
f0ab843
5834afb
b09a04a
1a8be2d
3b4efbc
fd4d77c
7d3eb03
92bc42b
a4798c9
9fa3c32
a2221b5
119cd7d
f7866ed
da52c02
dbbefa8
6c960ed
42b73f6
3dc8c38
8d0fefc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,13 +7,21 @@ on: | |
| - '.github/workflows/install-script-tests.yml' | ||
| - 'bin/test_install_script.sh' | ||
| - 'bin/test_install_script_over_homebrew.sh' | ||
| - 'npm/**' | ||
| - '.goreleaser.yml' | ||
| - 'scripts/npm-publish.sh' | ||
| pull_request: | ||
| paths: | ||
| - 'install-cli.sh' | ||
| - '.github/workflows/install-script-tests.yml' | ||
| - 'bin/test_install_script.sh' | ||
| - 'bin/test_install_script_over_homebrew.sh' | ||
| - 'npm/**' | ||
| - '.goreleaser.yml' | ||
| - 'scripts/npm-publish.sh' | ||
| workflow_dispatch: | ||
| release: | ||
| types: [published] | ||
jbrejner marked this conversation as resolved.
Show resolved
Hide resolved
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Confirm:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| jobs: | ||
| test-script: | ||
|
|
@@ -63,4 +71,34 @@ jobs: | |
| shell: bash | ||
| run: | | ||
| chmod +x install-cli.sh | ||
| bash bin/test_install_script_over_homebrew.sh --token ${{ secrets.GITHUB_TOKEN }} | ||
| bash bin/test_install_script_over_homebrew.sh --token ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| # Note: this job installs from the public npm registry, so on push/PR | ||
| # it tests the currently published version — not the code being changed. | ||
| # That still catches regressions. The release trigger is what tests new releases. | ||
| test-npm: | ||
| name: Test npm install on ${{ matrix.os }} | ||
| runs-on: ${{ matrix.os }} | ||
| strategy: | ||
| matrix: | ||
| os: | ||
| - ubuntu-latest # linux/x64 | ||
| - ubuntu-24.04-arm # linux/arm64 | ||
| - macos-latest # darwin/arm64 | ||
| - windows-latest # win32/x64 | ||
| - windows-11-arm # win32/arm64 | ||
|
|
||
| steps: | ||
| - name: Install @kosli/cli via npm | ||
| shell: bash | ||
| run: | | ||
| TAG="${{ github.event.release.tag_name }}" | ||
| if [[ "${{ github.event_name }}" == "release" && "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | ||
| npm install -g @kosli/cli@latest | ||
| else | ||
| npm install -g @kosli/cli@snapshot | ||
| fi | ||
|
|
||
| - name: Verify kosli binary works | ||
| shell: bash | ||
| run: kosli version | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,164 @@ | ||||||
| # 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 | ||||||
| │ ├── bin/kosli # JS shim that detects the platform and runs the binary | ||||||
| │ ├── install.js # postinstall script that validates the binary | ||||||
| │ └── package.json # declares optionalDependencies for all platforms | ||||||
| ├── cli-darwin-arm64/ # @kosli/cli-darwin-arm64 | ||||||
| │ ├── bin/kosli # the native binary — see below | ||||||
| │ └── package.json # declares os/cpu fields for platform filtering | ||||||
| ├── cli-darwin-x64/ # @kosli/cli-darwin-x64 | ||||||
| │ ├── bin/kosli # the native binary — see below | ||||||
| │ └── package.json # declares os/cpu fields for platform filtering | ||||||
| ├── cli-linux-arm/ # @kosli/cli-linux-arm | ||||||
| │ ├── bin/kosli # the native binary — see below | ||||||
| │ └── package.json # declares os/cpu fields for platform filtering | ||||||
| ├── cli-linux-arm64/ # @kosli/cli-linux-arm64 | ||||||
| │ ├── bin/kosli # the native binary — see below | ||||||
| │ └── package.json # declares os/cpu fields for platform filtering | ||||||
| ├── cli-linux-x64/ # @kosli/cli-linux-x64 | ||||||
| │ ├── bin/kosli # the native binary — see below | ||||||
| │ └── package.json # declares os/cpu fields for platform filtering | ||||||
| ├── cli-win32-arm64/ # @kosli/cli-win32-arm64 | ||||||
| │ ├── bin/kosli.exe # the native binary — see below | ||||||
jbrejner marked this conversation as resolved.
Show resolved
Hide resolved
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Tree diagram formatting. Two
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The tree is correct as-is. cli-win32-arm64 uses ├── (not last) and cli-win32-x64 uses └── (last item). No change needed. |
||||||
| │ └── package.json # declares os/cpu fields for platform filtering | ||||||
| └── cli-win32-x64/ # @kosli/cli-win32-x64 | ||||||
| ├── bin/kosli.exe # the native binary — see below | ||||||
| └── package.json # declares os/cpu fields for platform filtering | ||||||
| ``` | ||||||
|
|
||||||
| ## 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. | ||||||
|
|
||||||
| > **`npx` is not supported.** `npx @kosli/cli` does not install optional dependencies, so the platform binary is never fetched and the command fails. Always install the package before running 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. | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| //registry.npmjs.org/:_authToken=${NPM_TOKEN} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # @kosli/cli-darwin-arm64 | ||
|
|
||
| This is the macOS ARM64 platform binary for the Kosli CLI (Apple Silicon). **Do not install this package directly.** | ||
|
|
||
| Install the main package instead, which selects the right binary for your platform automatically: | ||
|
|
||
| ```sh | ||
| npm install -g @kosli/cli | ||
| ``` | ||
|
|
||
| See the [Kosli CLI repository](https://github.com/kosli-dev/cli) for documentation and source code. |
Uh oh!
There was an error while loading. Please reload this page.