From 6f93e21da9baec2a43cc087d456481e7b8f882b9 Mon Sep 17 00:00:00 2001 From: sdairs Date: Mon, 18 May 2026 18:43:53 +0100 Subject: [PATCH 1/5] Phase 1: cargo-binstall compatibility + crates.io readiness - Release workflow now produces clickhousectl-{target}-v{version}.tar.gz archives containing a directory of the same name with the binary inside, matching the cargo-binstall naming convention. Smoke test and install.sh updated to consume the new archive layout. - Add publish-crates job to release.yml that publishes both crates on tag (requires CARGO_REGISTRY_TOKEN secret). - Add description / license / repository / keywords / categories / [package.metadata.binstall] to clickhousectl. Correct cloud-api license MIT -> Apache-2.0 to match the repo LICENSE. - README: document cargo binstall, cargo install, and the new archive naming for direct downloads. Issue: #188 --- .github/workflows/release.yml | 96 ++++++++++++++++++-------- README.md | 24 ++++++- crates/clickhouse-cloud-api/Cargo.toml | 6 +- crates/clickhousectl/Cargo.toml | 11 +++ install.sh | 12 +++- 5 files changed, 116 insertions(+), 33 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7b75e3e..88125c2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,14 +65,24 @@ jobs: echo "$ldd_output" | grep -qE "not a dynamic executable|statically linked" echo "Static linking verified." - - name: Rename binary - run: cp target/${{ matrix.target }}/release/clickhousectl clickhousectl-${{ matrix.target }} + - name: Compute version + id: version + run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" + + - name: Package archive + run: | + VERSION="${{ steps.version.outputs.version }}" + TARGET="${{ matrix.target }}" + DIR="clickhousectl-${TARGET}-v${VERSION}" + mkdir "$DIR" + cp "target/${TARGET}/release/clickhousectl" "$DIR/" + tar -czf "${DIR}.tar.gz" "$DIR" - name: Upload artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: clickhousectl-${{ matrix.target }} - path: clickhousectl-${{ matrix.target }} + name: clickhousectl-${{ matrix.target }}-v${{ steps.version.outputs.version }} + path: clickhousectl-${{ matrix.target }}-v${{ steps.version.outputs.version }}.tar.gz smoke-test: name: Smoke test (${{ matrix.distro }}) @@ -81,34 +91,39 @@ jobs: strategy: fail-fast: false matrix: - include: - - distro: ubuntu:20.04 - artifact: clickhousectl-x86_64-unknown-linux-musl - - distro: ubuntu:22.04 - artifact: clickhousectl-x86_64-unknown-linux-musl - - distro: ubuntu:24.04 - artifact: clickhousectl-x86_64-unknown-linux-musl - - distro: debian:bullseye - artifact: clickhousectl-x86_64-unknown-linux-musl - - distro: debian:bookworm - artifact: clickhousectl-x86_64-unknown-linux-musl - - distro: centos:7 - artifact: clickhousectl-x86_64-unknown-linux-musl - - distro: amazonlinux:2 - artifact: clickhousectl-x86_64-unknown-linux-musl - - distro: alpine:3.18 - artifact: clickhousectl-x86_64-unknown-linux-musl + distro: + - ubuntu:20.04 + - ubuntu:22.04 + - ubuntu:24.04 + - debian:bullseye + - debian:bookworm + - centos:7 + - amazonlinux:2 + - alpine:3.18 + env: + TARGET: x86_64-unknown-linux-musl steps: + - name: Compute version + id: version + run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" + - name: Download artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: ${{ matrix.artifact }} + name: clickhousectl-${{ env.TARGET }}-v${{ steps.version.outputs.version }} + + - name: Extract archive + run: | + VERSION="${{ steps.version.outputs.version }}" + DIR="clickhousectl-${TARGET}-v${VERSION}" + tar -xzf "${DIR}.tar.gz" + chmod +x "${DIR}/clickhousectl" + echo "BIN_PATH=${PWD}/${DIR}/clickhousectl" >> "$GITHUB_ENV" - name: Run smoke test in ${{ matrix.distro }} run: | - chmod +x ${{ matrix.artifact }} docker run --rm \ - -v "$PWD/${{ matrix.artifact }}:/usr/local/bin/clickhousectl:ro" \ + -v "${BIN_PATH}:/usr/local/bin/clickhousectl:ro" \ ${{ matrix.distro }} \ sh -c 'clickhousectl --version && clickhousectl --help' @@ -128,15 +143,42 @@ jobs: with: path: artifacts - - name: Collect binaries + - name: Collect archives run: | mkdir release - for dir in artifacts/clickhousectl-*/; do - cp "$dir"/* release/ + for dir in artifacts/clickhousectl-*-v*/; do + cp "$dir"/*.tar.gz release/ done + ls -l release/ - name: Create GitHub Release env: GH_TOKEN: ${{ github.token }} TAG: ${{ github.ref_name }} run: gh release create "$TAG" --generate-notes release/* + + publish-crates: + name: Publish to crates.io + needs: release + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable @ 2026-03-27 + + - name: Publish clickhouse-cloud-api + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + run: cargo publish -p clickhouse-cloud-api + + - name: Wait for crates.io index propagation + run: sleep 30 + + - name: Publish clickhousectl + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + run: cargo publish -p clickhousectl diff --git a/README.md b/README.md index c75a71b..260a6ec 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,32 @@ curl https://clickhouse.com/cli | sh The install script will download the correct version for your OS and install to `~/.local/bin/clickhousectl`. A `chctl` alias is also created automatically for convenience. -### From source +### `cargo binstall` + +If you already have [`cargo-binstall`](https://github.com/cargo-bins/cargo-binstall), this pulls the prebuilt binary from GitHub Releases: + +```bash +cargo binstall clickhousectl +``` + +### From crates.io + +Builds from source: ```bash -cargo install --path . +cargo install clickhousectl ``` +### From this repo + +```bash +cargo install --path crates/clickhousectl +``` + +### Direct download + +Prebuilt archives for each release are attached to the [GitHub release](https://github.com/ClickHouse/clickhousectl/releases). Archives are named `clickhousectl-{target}-v{version}.tar.gz` and contain a single directory of the same name with the `clickhousectl` binary inside. Supported targets: `x86_64-unknown-linux-musl`, `aarch64-unknown-linux-musl`, `x86_64-apple-darwin`, `aarch64-apple-darwin`. + ## Local ### Installing and managing ClickHouse versions diff --git a/crates/clickhouse-cloud-api/Cargo.toml b/crates/clickhouse-cloud-api/Cargo.toml index f0b432c..a108f43 100644 --- a/crates/clickhouse-cloud-api/Cargo.toml +++ b/crates/clickhouse-cloud-api/Cargo.toml @@ -3,7 +3,11 @@ name = "clickhouse-cloud-api" version = "0.2.0" edition = "2024" description = "Typed Rust client for the ClickHouse Cloud API" -license = "MIT" +license = "Apache-2.0" +repository = "https://github.com/ClickHouse/clickhousectl" +homepage = "https://github.com/ClickHouse/clickhousectl" +keywords = ["clickhouse", "cloud", "api", "client"] +categories = ["api-bindings", "database"] [dependencies] reqwest = { version = "0.13", default-features = false, features = ["json", "query", "rustls"] } diff --git a/crates/clickhousectl/Cargo.toml b/crates/clickhousectl/Cargo.toml index da2409c..57759ec 100644 --- a/crates/clickhousectl/Cargo.toml +++ b/crates/clickhousectl/Cargo.toml @@ -2,6 +2,17 @@ name = "clickhousectl" version = "0.2.0" edition = "2024" +description = "The official ClickHouse CLI: local ClickHouse version manager and ClickHouse Cloud control plane." +license = "Apache-2.0" +repository = "https://github.com/ClickHouse/clickhousectl" +homepage = "https://github.com/ClickHouse/clickhousectl" +keywords = ["clickhouse", "cli", "database", "cloud"] +categories = ["command-line-utilities", "database"] + +[package.metadata.binstall] +pkg-url = "{ repo }/releases/download/v{ version }/{ name }-{ target }-v{ version }{ archive-suffix }" +pkg-fmt = "tgz" +bin-dir = "{ name }-{ target }-v{ version }/{ bin }{ binary-ext }" [dependencies] clap = { version = "4", features = ["derive"] } diff --git a/install.sh b/install.sh index b4fd582..f0e8894 100755 --- a/install.sh +++ b/install.sh @@ -40,12 +40,18 @@ if [ -z "$LATEST" ]; then fi echo "Latest release: $LATEST" -# Download binary -DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${LATEST}/clickhousectl-${TARGET}" +# Download archive +ARCHIVE_NAME="clickhousectl-${TARGET}-${LATEST}.tar.gz" +DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${LATEST}/${ARCHIVE_NAME}" echo "Downloading ${DOWNLOAD_URL}..." mkdir -p "$INSTALL_DIR" -curl -fsSL "$DOWNLOAD_URL" -o "${INSTALL_DIR}/${BINARY_NAME}" +TMPDIR="$(mktemp -d)" +trap 'rm -rf "$TMPDIR"' EXIT + +curl -fsSL "$DOWNLOAD_URL" -o "${TMPDIR}/${ARCHIVE_NAME}" +tar -xzf "${TMPDIR}/${ARCHIVE_NAME}" -C "$TMPDIR" +mv "${TMPDIR}/clickhousectl-${TARGET}-${LATEST}/${BINARY_NAME}" "${INSTALL_DIR}/${BINARY_NAME}" chmod +x "${INSTALL_DIR}/${BINARY_NAME}" echo "Installed ${BINARY_NAME} to ${INSTALL_DIR}/${BINARY_NAME}" From c153440c5b553bef1314288d29b6614d4fdc1745 Mon Sep 17 00:00:00 2001 From: sdairs Date: Mon, 18 May 2026 18:50:35 +0100 Subject: [PATCH 2/5] Phase 2 (npm scope): npm wrapper package + OIDC publish workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds an npm/ wrapper package that downloads the matching prebuilt clickhousectl binary from the GitHub release at install time, and a publish-npm job in release.yml that publishes it to npm using OIDC trusted publishing (no long-lived NPM_TOKEN). Single-package postinstall layout (vs. dist's subpackage approach) — simpler to reason about and decoupled from any future cargo-dist migration. Exposes both `clickhousectl` and `chctl` bin commands. publish-crates is now idempotent for clickhouse-cloud-api: it skips the publish step when the version is already on crates.io, so the API client can lag behind clickhousectl version bumps. Phase 2 brew / shell / PS installers and the full cargo-dist migration are intentionally deferred — npm-only is the scope of this commit. One-time setup the maintainer still needs to do for the next tag: - Squat the `clickhousectl` name on crates.io (cargo publish) and npm (manual seed publish with a granular token). - Configure the npm trusted publisher on npmjs.com pointing at ClickHouse/clickhousectl + release.yml + publish-npm. - Add CARGO_REGISTRY_TOKEN repo secret. Issue: #188 --- .github/workflows/release.yml | 44 ++++++++++++++- AGENTS.md | 3 +- CLAUDE.md | 2 +- README.md | 8 +++ npm/README.md | 27 +++++++++ npm/bin/cli.js | 29 ++++++++++ npm/install.js | 100 ++++++++++++++++++++++++++++++++++ npm/package.json | 40 ++++++++++++++ 8 files changed, 249 insertions(+), 4 deletions(-) create mode 100644 npm/README.md create mode 100644 npm/bin/cli.js create mode 100644 npm/install.js create mode 100644 npm/package.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 88125c2..cbf77dd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -170,15 +170,55 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable @ 2026-03-27 - - name: Publish clickhouse-cloud-api + - name: Publish clickhouse-cloud-api (skip if version already on crates.io) env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} - run: cargo publish -p clickhouse-cloud-api + run: | + VERSION=$(cargo pkgid -p clickhouse-cloud-api | sed 's/.*[#@]//') + if curl -fsSI "https://crates.io/api/v1/crates/clickhouse-cloud-api/${VERSION}" >/dev/null 2>&1; then + echo "clickhouse-cloud-api@${VERSION} already published; skipping." + echo "SKIP_API_PROPAGATION=1" >> "$GITHUB_ENV" + else + cargo publish -p clickhouse-cloud-api + fi - name: Wait for crates.io index propagation + if: env.SKIP_API_PROPAGATION != '1' run: sleep 30 - name: Publish clickhousectl env: CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} run: cargo publish -p clickhousectl + + publish-npm: + name: Publish to npm + needs: release + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') + # `id-token: write` is required for npm OIDC trusted publishing. Do NOT + # set NODE_AUTH_TOKEN below — per npm docs, even an empty value forces + # token-based auth and short-circuits the OIDC flow. + permissions: + id-token: write + contents: read + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Setup Node + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: '22' + registry-url: 'https://registry.npmjs.org' + + - name: Align package version with tag + working-directory: npm + run: | + VERSION="${GITHUB_REF_NAME#v}" + npm version "$VERSION" --no-git-tag-version --allow-same-version + + - name: Publish + working-directory: npm + run: npm publish --provenance --access public diff --git a/AGENTS.md b/AGENTS.md index 5b7f8bd..13e2b8f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -97,7 +97,8 @@ cargo add -p clickhouse-cloud-api url - If the user references a GitHub issue (e.g. "work on issue 3"), use `gh issue view 3` to get the details, then create a branch like `issue-3-short-description`. - Update `README.md` and any relevant documentation as part of the change — PRs should include doc updates for new or changed functionality. - Commit to the branch, push, and create a PR with `gh pr create`. -- Releases are done by tagging `main` (e.g. `git tag v0.1.4 && git push origin v0.1.4`), which triggers the GitHub Actions release workflow. Ensure version is updated in `crates/clickhousectl/Cargo.toml`. +- Releases are done by tagging `main` (e.g. `git tag v0.1.4 && git push origin v0.1.4`), which triggers the GitHub Actions release workflow. Before tagging: bump `version` in `crates/clickhousectl/Cargo.toml` (always) and `crates/clickhouse-cloud-api/Cargo.toml` (if the API client changed — the publish step skips crates.io if the version is unchanged). `npm/package.json` is bumped automatically by the workflow. +- Release-time secrets/config: `CARGO_REGISTRY_TOKEN` repo secret for crates.io; npm publishing uses OIDC trusted publishing (configured one-time on npmjs.com against this repo + `release.yml` + the `publish-npm` job). For the very first npm publish, seed the package by running `npm publish` locally with a granular token, then configure the trusted publisher and revoke the token. ## Testing locally diff --git a/CLAUDE.md b/CLAUDE.md index 3b5bed5..d8f2a8e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -137,7 +137,7 @@ cargo add -p clickhouse-cloud-api url - If the user references a GitHub issue (e.g. "work on issue 3"), use `gh issue view 3` to get the details, then create a branch like `issue-3-short-description`. - Update `README.md` and any relevant documentation as part of the change — PRs should include doc updates for new or changed functionality. - Commit to the branch, push, and create a PR with `gh pr create`. -- Releases are done by tagging `main` (e.g. `git tag v0.1.4 && git push origin v0.1.4`), which triggers the GitHub Actions release workflow. Ensure version is updated in `crates/clickhousectl/Cargo.toml`. +- Releases are done by tagging `main` (e.g. `git tag v0.1.4 && git push origin v0.1.4`), which triggers the GitHub Actions release workflow. Bump `version` in `crates/clickhousectl/Cargo.toml` (always) and `crates/clickhouse-cloud-api/Cargo.toml` (only when the API client changed; publish step skips if unchanged). `npm/package.json` is bumped automatically by the workflow. Release-time secrets: `CARGO_REGISTRY_TOKEN` for crates.io; npm uses OIDC trusted publishing (configured one-time on npmjs.com against this repo, `release.yml`, and the `publish-npm` job). ## Testing locally diff --git a/README.md b/README.md index 260a6ec..2f64ff7 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,14 @@ If you already have [`cargo-binstall`](https://github.com/cargo-bins/cargo-binst cargo binstall clickhousectl ``` +### npm + +```bash +npm install -g clickhousectl +``` + +This installs an npm wrapper package that downloads the matching prebuilt binary from GitHub Releases at install time. Both `clickhousectl` and `chctl` are exposed as commands. If you use `npm install --ignore-scripts`, the download is skipped — fall back to one of the other install paths. + ### From crates.io Builds from source: diff --git a/npm/README.md b/npm/README.md new file mode 100644 index 0000000..e594a30 --- /dev/null +++ b/npm/README.md @@ -0,0 +1,27 @@ +# clickhousectl + +The official ClickHouse CLI: local ClickHouse version manager and ClickHouse Cloud control plane. + +```bash +npm install -g clickhousectl +clickhousectl --help +``` + +This npm package is a thin wrapper that downloads the prebuilt `clickhousectl` binary for your platform from [GitHub Releases](https://github.com/ClickHouse/clickhousectl/releases) at install time. It is published in lock-step with the release tag. + +Supported platforms: + +- Linux x86_64 (musl) +- Linux aarch64 (musl) +- macOS x86_64 +- macOS arm64 + +For full documentation, see the [project repository](https://github.com/ClickHouse/clickhousectl). + +## Installation flags + +`clickhousectl` requires npm's postinstall step to fetch the binary. If you use `npm install --ignore-scripts`, the binary won't be downloaded and the `clickhousectl` command will fail with a helpful error. Re-run install without `--ignore-scripts`, or grab the binary directly from GitHub Releases. + +## License + +Apache-2.0 diff --git a/npm/bin/cli.js b/npm/bin/cli.js new file mode 100644 index 0000000..039a283 --- /dev/null +++ b/npm/bin/cli.js @@ -0,0 +1,29 @@ +#!/usr/bin/env node +// Thin shim that execs the platform-specific clickhousectl binary that +// install.js downloaded into ../vendor at npm install time. + +const { spawn } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +const binaryName = process.platform === 'win32' ? 'clickhousectl.exe' : 'clickhousectl'; +const binaryPath = path.join(__dirname, '..', 'vendor', binaryName); + +if (!fs.existsSync(binaryPath)) { + console.error( + `clickhousectl: binary not found at ${binaryPath}.\n` + + `The postinstall step may have been skipped (e.g. npm --ignore-scripts) ` + + `or failed. Reinstall with scripts enabled, or download manually from ` + + `https://github.com/ClickHouse/clickhousectl/releases` + ); + process.exit(1); +} + +const child = spawn(binaryPath, process.argv.slice(2), { stdio: 'inherit' }); +child.on('exit', (code, signal) => { + if (signal) { + process.kill(process.pid, signal); + } else { + process.exit(code ?? 1); + } +}); diff --git a/npm/install.js b/npm/install.js new file mode 100644 index 0000000..e0d7e2e --- /dev/null +++ b/npm/install.js @@ -0,0 +1,100 @@ +#!/usr/bin/env node +// Downloads the platform-appropriate clickhousectl binary from the matching +// GitHub release and places it next to bin/clickhousectl. Invoked as the +// package's postinstall script. + +const fs = require('fs'); +const path = require('path'); +const https = require('https'); +const { URL } = require('url'); +const { spawnSync } = require('child_process'); + +const REPO = 'ClickHouse/clickhousectl'; +const PLATFORM_MAP = { + 'linux-x64': 'x86_64-unknown-linux-musl', + 'linux-arm64': 'aarch64-unknown-linux-musl', + 'darwin-x64': 'x86_64-apple-darwin', + 'darwin-arm64': 'aarch64-apple-darwin', +}; + +function resolveTarget() { + const key = `${process.platform}-${process.arch}`; + const target = PLATFORM_MAP[key]; + if (!target) { + throw new Error( + `clickhousectl: unsupported platform/arch "${key}". ` + + `Supported: ${Object.keys(PLATFORM_MAP).join(', ')}` + ); + } + return target; +} + +function get(url) { + return new Promise((resolve, reject) => { + const req = https.get(url, { headers: { 'User-Agent': 'clickhousectl-npm-installer' } }, (res) => { + if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { + res.resume(); + const next = new URL(res.headers.location, url).toString(); + resolve(get(next)); + return; + } + if (res.statusCode !== 200) { + res.resume(); + reject(new Error(`GET ${url} -> ${res.statusCode}`)); + return; + } + resolve(res); + }); + req.on('error', reject); + }); +} + +async function download(url, dest) { + const res = await get(url); + await new Promise((resolve, reject) => { + const out = fs.createWriteStream(dest); + res.pipe(out); + out.on('finish', () => out.close(resolve)); + out.on('error', reject); + res.on('error', reject); + }); +} + +async function main() { + // npm install with --ignore-scripts will skip this entirely, which is the + // documented escape hatch for users who don't want network access on install. + const pkg = require('./package.json'); + const version = pkg.version; + const target = resolveTarget(); + const archiveName = `clickhousectl-${target}-v${version}.tar.gz`; + const url = `https://github.com/${REPO}/releases/download/v${version}/${archiveName}`; + + const vendorDir = path.join(__dirname, 'vendor'); + fs.mkdirSync(vendorDir, { recursive: true }); + const archivePath = path.join(vendorDir, archiveName); + + console.log(`clickhousectl: downloading ${url}`); + await download(url, archivePath); + + // The archive contains a single directory `clickhousectl-{target}-v{version}/` + // with `clickhousectl` inside. --strip-components=1 unpacks the binary + // directly into vendorDir. + const extract = spawnSync( + 'tar', + ['-xzf', archivePath, '-C', vendorDir, '--strip-components=1'], + { stdio: 'inherit' } + ); + if (extract.status !== 0) { + throw new Error(`tar exited with status ${extract.status}`); + } + fs.unlinkSync(archivePath); + + const binaryPath = path.join(vendorDir, 'clickhousectl'); + fs.chmodSync(binaryPath, 0o755); + console.log(`clickhousectl: installed ${binaryPath}`); +} + +main().catch((err) => { + console.error(`clickhousectl install failed: ${err.message}`); + process.exit(1); +}); diff --git a/npm/package.json b/npm/package.json new file mode 100644 index 0000000..c739486 --- /dev/null +++ b/npm/package.json @@ -0,0 +1,40 @@ +{ + "name": "clickhousectl", + "version": "0.2.0", + "description": "The official ClickHouse CLI: local ClickHouse version manager and ClickHouse Cloud control plane.", + "homepage": "https://github.com/ClickHouse/clickhousectl", + "repository": { + "type": "git", + "url": "git+https://github.com/ClickHouse/clickhousectl.git" + }, + "license": "Apache-2.0", + "bin": { + "clickhousectl": "bin/cli.js", + "chctl": "bin/cli.js" + }, + "scripts": { + "postinstall": "node install.js" + }, + "files": [ + "bin/cli.js", + "install.js", + "README.md" + ], + "os": [ + "linux", + "darwin" + ], + "cpu": [ + "x64", + "arm64" + ], + "engines": { + "node": ">=18" + }, + "keywords": [ + "clickhouse", + "cli", + "database", + "cloud" + ] +} From e564289ec03703c591340ce47ff2712f6b18887f Mon Sep 17 00:00:00 2001 From: sdairs Date: Mon, 18 May 2026 19:04:43 +0100 Subject: [PATCH 3/5] update descriptions --- crates/clickhousectl/Cargo.toml | 2 +- npm/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/clickhousectl/Cargo.toml b/crates/clickhousectl/Cargo.toml index 57759ec..270ad3b 100644 --- a/crates/clickhousectl/Cargo.toml +++ b/crates/clickhousectl/Cargo.toml @@ -2,7 +2,7 @@ name = "clickhousectl" version = "0.2.0" edition = "2024" -description = "The official ClickHouse CLI: local ClickHouse version manager and ClickHouse Cloud control plane." +description = "The CLI for ClickHouse: local and cloud." license = "Apache-2.0" repository = "https://github.com/ClickHouse/clickhousectl" homepage = "https://github.com/ClickHouse/clickhousectl" diff --git a/npm/package.json b/npm/package.json index c739486..c520247 100644 --- a/npm/package.json +++ b/npm/package.json @@ -1,7 +1,7 @@ { "name": "clickhousectl", "version": "0.2.0", - "description": "The official ClickHouse CLI: local ClickHouse version manager and ClickHouse Cloud control plane.", + "description": "The CLI for ClickHouse: local and cloud.", "homepage": "https://github.com/ClickHouse/clickhousectl", "repository": { "type": "git", From 2c9b1a994f1173abfbcb2a5872bbeb9d729bdeca Mon Sep 17 00:00:00 2001 From: sdairs Date: Mon, 18 May 2026 19:30:06 +0100 Subject: [PATCH 4/5] npm: mark bin/cli.js executable in tree; gitignore test artifacts chmod +x on the shim file matches how npm will land it on install, and makes `./bin/cli.js` directly invokable when developing locally. Plus ignore the npm/vendor, package-lock, *.tgz, and node_modules paths produced when packing or running install.js by hand. --- .gitignore | 4 ++++ npm/bin/cli.js | 0 2 files changed, 4 insertions(+) mode change 100644 => 100755 npm/bin/cli.js diff --git a/.gitignore b/.gitignore index d6ba027..871f067 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ /target +/npm/node_modules/ +/npm/vendor/ +/npm/package-lock.json +/npm/*.tgz .env /.env /.env.local diff --git a/npm/bin/cli.js b/npm/bin/cli.js old mode 100644 new mode 100755 From 46bab4eb66b8783deec9272a4122d734f2842768 Mon Sep 17 00:00:00 2001 From: sdairs Date: Mon, 18 May 2026 19:33:31 +0100 Subject: [PATCH 5/5] release.yml: gate the release job on tag refs Lets us trigger workflow_dispatch on a branch to validate the build matrix, static-linking check, smoke tests, and archive format without risking a junk GitHub Release named after the branch. publish-crates and publish-npm already had this guard; release didn't. --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cbf77dd..02e20eb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -131,6 +131,7 @@ jobs: name: Create Release needs: [build, smoke-test] runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') permissions: contents: write steps: