From 0d00c5293554897854de0e7d6ee5cf5382bb8804 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 22 Jun 2026 21:08:23 +0000 Subject: [PATCH 1/3] Run skills E2E QA on release-branch PRs (#875) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary QA workflows should validate every PR targeting the `release` branch. All test/examples workflows already do (their path filters match the version bump a release PR always carries under `packages/**`/`package-lock.json`), but `e2e-skills` was the only QA workflow with **no `pull_request` trigger at all** — it never ran on any PR. - **`e2e-skills.yml`**: add a path-free `pull_request` trigger scoped to the `release` branch, so the skills packaging E2E runs unconditionally on release-branch PRs. ```yaml pull_request: branches: - release ``` A path-free `branches: [release]` trigger is used because GitHub ANDs `branches` + `paths` within a single `pull_request` trigger, and a workflow cannot declare two — this guarantees the suite runs regardless of which files changed. Out of scope (separate lifecycles, left unchanged): `upstream-sql-tests` (nightly upstream-compat harness) and `tests-skill-rowbinary-parser` (independently-versioned `@clickhouse/rowbinary` package, not published by `publish.yml`). ## Checklist - [ ] For significant changes, documentation in https://github.com/ClickHouse/clickhouse-docs was updated with further explanations or tutorials Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- .github/workflows/e2e-skills.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/e2e-skills.yml b/.github/workflows/e2e-skills.yml index 1ad18db0b..ea0a22579 100644 --- a/.github/workflows/e2e-skills.yml +++ b/.github/workflows/e2e-skills.yml @@ -11,6 +11,12 @@ on: - packages/client-common/package.json - packages/client-node/package.json - packages/client-web/package.json + # Always validate the full skills packaging E2E on pull requests that target + # the release branch, regardless of which paths changed, so every release is + # gated by the same QA suite as the other test workflows. + pull_request: + branches: + - release jobs: skills-packaging: From 63d042c99137948fd9978c9e83b69473f78f9822 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Mon, 22 Jun 2026 23:22:04 +0200 Subject: [PATCH 2/3] Deprecate @clickhouse/client-common and split the release workflows into per-package jobs (#845) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary `@clickhouse/client-common` requires platform hacks to serve both Node.js and Web well, and no longer pulls its weight as a separately-published package. This bundles the shared sources directly into each client, marks common deprecated, and restructures the bump/publish workflows into explicit per-package jobs. ## Changes ### Bundle common into each client - `packages/client-node/src/common` and `packages/client-web/src/common` are git-tracked symlinks to `packages/client-common/src`; both clients import via relative paths (`./common/index`) and compile their own copy into `dist/common`. - Dropped the `@clickhouse/client-common` dependency from both client `package.json` files — the clients are now self-contained. ### Mark common deprecated - `@deprecated` package-level notice in `client-common/src/index.ts`, a DEPRECATED package description, a CHANGELOG migration note (under `1.22.0`), and an `npm deprecate` step in `RELEASING.md`. ### Per-package release workflows - `bump-version.yml` and `publish.yml` are each split into **one job per package**, selected by a required `package` input (`@clickhouse/client`, `@clickhouse/client-web`, or `@clickhouse/client-common`). There is no `all` option — release a package by dispatching its workflow; to release several, dispatch once per package. The automatic `head` publish (on push to `release`) still runs a job per package and releases them all together. - Version bumping is inlined into the jobs (`npm version` + the `src/version.ts` rewrite); the shared `.scripts/update_version.sh` and the short-lived `head_version.sh` helper were removed. `RELEASING.md` is rewritten to be workflow-driven. - Manual publishes are scoped by package in the concurrency group so dispatching one does not cancel another; each per-package publish job builds and publishes only its own workspace and pushes a package-scoped git tag via `.scripts/push_release_tag.sh`. The `e2e` job runs whenever `@clickhouse/client` is published (head or manual), since the downstream test project imports it. ## Checklist - [x] A human-readable description of the changes was provided to include in CHANGELOG --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Peter Leonov Co-authored-by: Claude Opus 4.8 (1M context) --- .github/workflows/bump-version.yml | 152 ++++++++-- .github/workflows/publish.yml | 277 +++++++++++++++--- .scripts/push_release_tag.sh | 23 ++ .scripts/smoke_test_pack.sh | 44 +++ .scripts/update_version.sh | 28 -- AGENTS.md | 4 + CHANGELOG.md | 5 + RELEASING.md | 52 ++-- package-lock.json | 8 +- packages/client-common/package.json | 2 +- packages/client-common/src/index.ts | 9 + packages/client-node/package.json | 4 +- packages/client-node/src/client.ts | 8 +- packages/client-node/src/common | 1 + packages/client-node/src/config.ts | 4 +- .../client-node/src/connection/compression.ts | 4 +- .../src/connection/create_connection.ts | 2 +- .../src/connection/node_base_connection.ts | 6 +- .../node_custom_agent_connection.ts | 2 +- .../src/connection/node_http_connection.ts | 2 +- .../src/connection/node_https_connection.ts | 2 +- .../client-node/src/connection/socket_pool.ts | 2 +- packages/client-node/src/connection/stream.ts | 2 +- packages/client-node/src/index.ts | 12 +- packages/client-node/src/result_set.ts | 6 +- packages/client-node/src/utils/encoder.ts | 4 +- packages/client-web/package.json | 4 +- packages/client-web/src/client.ts | 4 +- packages/client-web/src/common | 1 + packages/client-web/src/config.ts | 2 +- .../src/connection/web_connection.ts | 4 +- packages/client-web/src/index.ts | 12 +- packages/client-web/src/result_set.ts | 6 +- packages/client-web/src/utils/encoder.ts | 8 +- tests/e2e/smoke/check.cjs | 25 ++ tests/e2e/smoke/check.mjs | 28 ++ 36 files changed, 574 insertions(+), 185 deletions(-) create mode 100755 .scripts/push_release_tag.sh create mode 100755 .scripts/smoke_test_pack.sh delete mode 100755 .scripts/update_version.sh create mode 120000 packages/client-node/src/common create mode 120000 packages/client-web/src/common create mode 100644 tests/e2e/smoke/check.cjs create mode 100644 tests/e2e/smoke/check.mjs diff --git a/.github/workflows/bump-version.yml b/.github/workflows/bump-version.yml index 8f76be39c..e320676ae 100644 --- a/.github/workflows/bump-version.yml +++ b/.github/workflows/bump-version.yml @@ -1,5 +1,10 @@ name: "bump-version" +# Manually bump a single package's version and open a release PR against main. +# Each package has its own job; the required `package` input selects which one +# runs. Packages are versioned independently, so there is no "bump everything" +# option - dispatch the workflow once per package you want to release. + on: workflow_dispatch: inputs: @@ -11,14 +16,26 @@ on: - patch - minor - major + package: + description: "Package to bump" + required: true + type: choice + options: + - "@clickhouse/client" + - "@clickhouse/client-web" + # The common package is deprecated, but can still be bumped on its own. + - "@clickhouse/client-common" permissions: {} concurrency: group: ${{ github.repository }}-${{ github.workflow }} cancel-in-progress: false + jobs: - bump: + bump_client: + name: "Bump @clickhouse/client" + if: inputs.package == '@clickhouse/client' runs-on: ubuntu-latest permissions: contents: write @@ -34,41 +51,134 @@ jobs: with: node-version: 24 - - name: Calculate new version + - name: Bump version id: version env: BUMP_TYPE: ${{ inputs.bump_type }} run: | - CURRENT=$(node -p "require('./packages/client-common/package.json').version") - NEW=$(CURRENT="$CURRENT" node -e " - const m = process.env.CURRENT.match(/^(\d+)\.(\d+)\.(\d+)$/); - if (!m) throw new Error('Version ' + process.env.CURRENT + ' is not a strict x.y.z release; bump manually.'); - const [, major, minor, patch] = m.map(Number); - if (process.env.BUMP_TYPE === 'major') process.stdout.write((major+1) + '.0.0'); - else if (process.env.BUMP_TYPE === 'minor') process.stdout.write(major + '.' + (minor+1) + '.0'); - else process.stdout.write(major + '.' + minor + '.' + (patch+1)); - ") + CURRENT=$(node -p "require('./packages/client-node/package.json').version") + npm --workspace @clickhouse/client version --no-git-tag-version "$BUMP_TYPE" + NEW=$(node -p "require('./packages/client-node/package.json').version") + echo "export default \"$NEW\";" > packages/client-node/src/version.ts echo "current=$CURRENT" >> "$GITHUB_OUTPUT" echo "new=$NEW" >> "$GITHUB_OUTPUT" - - name: Bump version in packages - run: .scripts/update_version.sh "${{ steps.version.outputs.new }}" + - name: Commit, push branch, and open PR + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NEW: ${{ steps.version.outputs.new }} + CURRENT: ${{ steps.version.outputs.current }} + BUMP_TYPE: ${{ inputs.bump_type }} + run: | + BRANCH="release-client-${NEW}" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git checkout -b "$BRANCH" + git add . + git commit -m "chore: bump @clickhouse/client version to ${NEW}" + git push origin "$BRANCH" + gh pr create \ + --title "chore: bump @clickhouse/client version to ${NEW}" \ + --body "Bumps \`@clickhouse/client\` from \`${CURRENT}\` to \`${NEW}\` (${BUMP_TYPE} bump)." \ + --base main \ + --head "$BRANCH" - - name: Commit and push branch + bump_client_web: + name: "Bump @clickhouse/client-web" + if: inputs.package == '@clickhouse/client-web' + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Checkout repository + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + ref: main + + - name: Setup Node.js + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version: 24 + + - name: Bump version + id: version + env: + BUMP_TYPE: ${{ inputs.bump_type }} run: | + CURRENT=$(node -p "require('./packages/client-web/package.json').version") + npm --workspace @clickhouse/client-web version --no-git-tag-version "$BUMP_TYPE" + NEW=$(node -p "require('./packages/client-web/package.json').version") + echo "export default \"$NEW\";" > packages/client-web/src/version.ts + echo "current=$CURRENT" >> "$GITHUB_OUTPUT" + echo "new=$NEW" >> "$GITHUB_OUTPUT" + + - name: Commit, push branch, and open PR + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NEW: ${{ steps.version.outputs.new }} + CURRENT: ${{ steps.version.outputs.current }} + BUMP_TYPE: ${{ inputs.bump_type }} + run: | + BRANCH="release-client-web-${NEW}" git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git checkout -b "release-${{ steps.version.outputs.new }}" + git checkout -b "$BRANCH" git add . - git commit -m "chore: bump version to ${{ steps.version.outputs.new }}" - git push origin "release-${{ steps.version.outputs.new }}" + git commit -m "chore: bump @clickhouse/client-web version to ${NEW}" + git push origin "$BRANCH" + gh pr create \ + --title "chore: bump @clickhouse/client-web version to ${NEW}" \ + --body "Bumps \`@clickhouse/client-web\` from \`${CURRENT}\` to \`${NEW}\` (${BUMP_TYPE} bump)." \ + --base main \ + --head "$BRANCH" + + bump_client_common: + name: "Bump @clickhouse/client-common (deprecated)" + if: inputs.package == '@clickhouse/client-common' + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Checkout repository + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + ref: main - - name: Create pull request + - name: Setup Node.js + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version: 24 + + - name: Bump version + id: version + env: + BUMP_TYPE: ${{ inputs.bump_type }} + run: | + CURRENT=$(node -p "require('./packages/client-common/package.json').version") + npm --workspace @clickhouse/client-common version --no-git-tag-version "$BUMP_TYPE" + NEW=$(node -p "require('./packages/client-common/package.json').version") + echo "export default \"$NEW\";" > packages/client-common/src/version.ts + echo "current=$CURRENT" >> "$GITHUB_OUTPUT" + echo "new=$NEW" >> "$GITHUB_OUTPUT" + + - name: Commit, push branch, and open PR env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NEW: ${{ steps.version.outputs.new }} + CURRENT: ${{ steps.version.outputs.current }} + BUMP_TYPE: ${{ inputs.bump_type }} run: | + BRANCH="release-client-common-${NEW}" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git checkout -b "$BRANCH" + git add . + git commit -m "chore: bump @clickhouse/client-common version to ${NEW}" + git push origin "$BRANCH" gh pr create \ - --title "chore: bump version to ${{ steps.version.outputs.new }}" \ - --body "Bumps version from \`${{ steps.version.outputs.current }}\` to \`${{ steps.version.outputs.new }}\` (${{ inputs.bump_type }} bump)." \ + --title "chore: bump @clickhouse/client-common version to ${NEW}" \ + --body "Bumps \`@clickhouse/client-common\` from \`${CURRENT}\` to \`${NEW}\` (${BUMP_TYPE} bump)." \ --base main \ - --head "release-${{ steps.version.outputs.new }}" + --head "$BRANCH" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 63743dbab..968207041 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -7,27 +7,52 @@ name: "publish" # The `main` branch is reserved for development and does not publish. # For both it uses NPM OIDC authentication with provenance support. # +# The manual ("latest") trigger takes a required `package` input and runs the +# matching per-package job, so a single package can be published on its own - +# for example, a final release of the deprecated `@clickhouse/client-common`. +# The automatic head publish runs one per-package job for every package (each +# computes its own `-head..` version from its package.json). +# +# Before each Node.js client publish, a smoke test packs the freshly built +# package into a tarball, installs that tarball into a throwaway app, and runs +# ESM + CJS checks against it (.scripts/smoke_test_pack.sh). This catches +# packaging problems before anything reaches npm. +# # After a successful publish, the `e2e` job waits for the freshly published # version to become available on the npm registry, installs that exact -# version into a tiny downstream project, and verifies it is usable. +# version into a tiny downstream project, and verifies it is usable. It only +# runs when `@clickhouse/client` was published (the head job or the client job). permissions: contents: read id-token: write # Required for npm OIDC authentication and provenance concurrency: - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} + # Scope manual publishes by package so dispatching a release for one package + # does not cancel an in-progress release of another. `github.event.inputs` is + # empty for the head (push) trigger, so head runs still share a single group. + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}-${{ github.event.inputs.package }} cancel-in-progress: true on: # for the latest workflow workflow_dispatch: + inputs: + package: + description: "Package to publish" + required: true + type: choice + options: + - "@clickhouse/client" + - "@clickhouse/client-web" + # The common package is deprecated, but can still be published on its own. + - "@clickhouse/client-common" # for the head workflow push: branches: - release # Only run the head publishing workflow when files relevant to the - # published packages change. The web and node packages depend on the - # common package, so any change under packages/** triggers an + # published packages change. The web and node packages bundle the + # common package sources, so any change under packages/** triggers an # all-or-nothing publish of every package. paths: - "packages/**" @@ -37,16 +62,17 @@ on: - "README.md" - "LICENSE" - "skills/**" - - ".scripts/update_version.sh" - ".github/workflows/publish.yml" jobs: - head: + head_client: + name: "Publish @clickhouse/client (head)" if: github.ref == 'refs/heads/release' && github.event_name == 'push' runs-on: ubuntu-latest environment: npm-publish outputs: version: ${{ steps.version.outputs.version }} + packages: "@clickhouse/client" steps: - name: Checkout repository uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 @@ -63,24 +89,101 @@ jobs: - name: Set head pre-release version id: version run: | - BASE_VERSION=$(node -p "require('./packages/client-common/package.json').version") + BASE_VERSION=$(node -p "require('./packages/client-node/package.json').version") HEAD_VERSION="${BASE_VERSION}-head.${GITHUB_SHA::7}.${GITHUB_RUN_ATTEMPT}" echo "Setting version to: $HEAD_VERSION" - .scripts/update_version.sh "$HEAD_VERSION" + npm --workspace @clickhouse/client version --no-git-tag-version "$HEAD_VERSION" + echo "export default \"$HEAD_VERSION\";" > packages/client-node/src/version.ts echo "version=$HEAD_VERSION" >> "$GITHUB_OUTPUT" - - name: Build packages - run: npm --workspaces run build + - name: Build the package + run: npm --workspace @clickhouse/client run build - - name: Publish packages with head tag + - name: Smoke test the packed tarball + run: .scripts/smoke_test_pack.sh @clickhouse/client + + - name: Publish @clickhouse/client with head tag run: | - npm --workspaces publish \ + npm --workspace @clickhouse/client publish \ --access public \ --provenance \ --tag head - latest: - if: github.ref == 'refs/heads/release' && github.event_name == 'workflow_dispatch' + head_client_web: + name: "Publish @clickhouse/client-web (head)" + if: github.ref == 'refs/heads/release' && github.event_name == 'push' + runs-on: ubuntu-latest + environment: npm-publish + steps: + - name: Checkout repository + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Setup Node.js + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version: 24 + registry-url: "https://registry.npmjs.org" + + - name: Install dependencies + run: npm ci + + - name: Set head pre-release version + run: | + BASE_VERSION=$(node -p "require('./packages/client-web/package.json').version") + HEAD_VERSION="${BASE_VERSION}-head.${GITHUB_SHA::7}.${GITHUB_RUN_ATTEMPT}" + echo "Setting version to: $HEAD_VERSION" + npm --workspace @clickhouse/client-web version --no-git-tag-version "$HEAD_VERSION" + echo "export default \"$HEAD_VERSION\";" > packages/client-web/src/version.ts + + - name: Build the package + run: npm --workspace @clickhouse/client-web run build + + - name: Publish @clickhouse/client-web with head tag + run: | + npm --workspace @clickhouse/client-web publish \ + --access public \ + --provenance \ + --tag head + + head_client_common: + name: "Publish @clickhouse/client-common (head)" + if: github.ref == 'refs/heads/release' && github.event_name == 'push' + runs-on: ubuntu-latest + environment: npm-publish + steps: + - name: Checkout repository + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Setup Node.js + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version: 24 + registry-url: "https://registry.npmjs.org" + + - name: Install dependencies + run: npm ci + + - name: Set head pre-release version + run: | + BASE_VERSION=$(node -p "require('./packages/client-common/package.json').version") + HEAD_VERSION="${BASE_VERSION}-head.${GITHUB_SHA::7}.${GITHUB_RUN_ATTEMPT}" + echo "Setting version to: $HEAD_VERSION" + npm --workspace @clickhouse/client-common version --no-git-tag-version "$HEAD_VERSION" + echo "export default \"$HEAD_VERSION\";" > packages/client-common/src/version.ts + + - name: Build the package + run: npm --workspace @clickhouse/client-common run build + + - name: Publish @clickhouse/client-common with head tag + run: | + npm --workspace @clickhouse/client-common publish \ + --access public \ + --provenance \ + --tag head + + publish_client: + name: "Publish @clickhouse/client" + if: github.ref == 'refs/heads/release' && github.event_name == 'workflow_dispatch' && inputs.package == '@clickhouse/client' runs-on: ubuntu-latest environment: npm-publish permissions: @@ -88,6 +191,7 @@ jobs: id-token: write # Required for npm OIDC authentication and provenance outputs: version: ${{ steps.version.outputs.version }} + packages: "@clickhouse/client" steps: - name: Checkout repository uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 @@ -104,40 +208,125 @@ jobs: - name: Get the release version id: version run: | - BASE_VERSION=$(node -p "require('./packages/client-common/package.json').version") + BASE_VERSION=$(node -p "require('./packages/client-node/package.json').version") echo "Using version: $BASE_VERSION" echo "version=$BASE_VERSION" >> "$GITHUB_OUTPUT" - - name: Build packages - run: npm --workspaces run build + - name: Build the package + run: npm --workspace @clickhouse/client run build + + - name: Smoke test the packed tarball + run: .scripts/smoke_test_pack.sh @clickhouse/client - - name: Publish packages to the latest tag (implicit) + - name: Publish @clickhouse/client to the latest tag (implicit) run: | - npm --workspaces publish \ + npm --workspace @clickhouse/client publish \ --access public \ --provenance - name: Create and push release git tag env: RELEASE_VERSION: ${{ steps.version.outputs.version }} + run: .scripts/push_release_tag.sh "client-${RELEASE_VERSION}" + + publish_client_web: + name: "Publish @clickhouse/client-web" + if: github.ref == 'refs/heads/release' && github.event_name == 'workflow_dispatch' && inputs.package == '@clickhouse/client-web' + runs-on: ubuntu-latest + environment: npm-publish + permissions: + contents: write # Required to push the release git tag + id-token: write # Required for npm OIDC authentication and provenance + outputs: + version: ${{ steps.version.outputs.version }} + packages: "@clickhouse/client-web" + steps: + - name: Checkout repository + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Setup Node.js + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version: 24 + registry-url: "https://registry.npmjs.org" + + - name: Install dependencies + run: npm ci + + - name: Get the release version + id: version run: | - if git ls-remote --exit-code --tags origin "refs/tags/${RELEASE_VERSION}" >/dev/null 2>&1; then - echo "Tag ${RELEASE_VERSION} already exists on origin; skipping." - exit 0 - fi - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git tag -a "${RELEASE_VERSION}" -m "Release ${RELEASE_VERSION}" - git push origin "refs/tags/${RELEASE_VERSION}" + BASE_VERSION=$(node -p "require('./packages/client-web/package.json').version") + echo "Using version: $BASE_VERSION" + echo "version=$BASE_VERSION" >> "$GITHUB_OUTPUT" + + - name: Build the package + run: npm --workspace @clickhouse/client-web run build + + - name: Publish @clickhouse/client-web to the latest tag (implicit) + run: | + npm --workspace @clickhouse/client-web publish \ + --access public \ + --provenance + + - name: Create and push release git tag + env: + RELEASE_VERSION: ${{ steps.version.outputs.version }} + run: .scripts/push_release_tag.sh "client-web-${RELEASE_VERSION}" + + publish_client_common: + name: "Publish @clickhouse/client-common (deprecated)" + if: github.ref == 'refs/heads/release' && github.event_name == 'workflow_dispatch' && inputs.package == '@clickhouse/client-common' + runs-on: ubuntu-latest + environment: npm-publish + permissions: + contents: write # Required to push the release git tag + id-token: write # Required for npm OIDC authentication and provenance + outputs: + version: ${{ steps.version.outputs.version }} + packages: "@clickhouse/client-common" + steps: + - name: Checkout repository + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Setup Node.js + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version: 24 + registry-url: "https://registry.npmjs.org" + + - name: Install dependencies + run: npm ci + + - name: Get the release version + id: version + run: | + BASE_VERSION=$(node -p "require('./packages/client-common/package.json').version") + echo "Using version: $BASE_VERSION" + echo "version=$BASE_VERSION" >> "$GITHUB_OUTPUT" + + - name: Build the package + run: npm --workspace @clickhouse/client-common run build + + - name: Publish @clickhouse/client-common to the latest tag (implicit) + run: | + npm --workspace @clickhouse/client-common publish \ + --access public \ + --provenance + + - name: Create and push release git tag + env: + RELEASE_VERSION: ${{ steps.version.outputs.version }} + run: .scripts/push_release_tag.sh "client-common-${RELEASE_VERSION}" e2e: name: e2e (node ${{ matrix.node }}) - needs: [head, latest] - # Run when at least one of the publish jobs succeeded. The other one is - # skipped (not failed) by its `if:` condition for this trigger. + needs: [head_client, publish_client] + # The e2e project imports `@clickhouse/client`, so it only runs when the + # Node.js client was published - either via the head job or the client job. if: | always() && - (needs.head.result == 'success' || needs.latest.result == 'success') + (needs.head_client.result == 'success' || needs.publish_client.result == 'success') runs-on: ubuntu-latest strategy: fail-fast: true @@ -147,7 +336,8 @@ jobs: run: working-directory: tests/e2e/install env: - PUBLISHED_VERSION: ${{ needs.head.outputs.version || needs.latest.outputs.version }} + PUBLISHED_VERSION: ${{ needs.head_client.outputs.version || needs.publish_client.outputs.version }} + PUBLISHED_PACKAGES: ${{ needs.head_client.outputs.packages || needs.publish_client.outputs.packages }} steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 @@ -157,18 +347,18 @@ jobs: node-version: ${{ matrix.node }} registry-url: "https://registry.npmjs.org" - - name: Wait for ${{ needs.head.outputs.version || needs.latest.outputs.version }} to be available on npm + - name: Wait for ${{ env.PUBLISHED_VERSION }} to be available on npm run: | set -euo pipefail if [ -z "${PUBLISHED_VERSION}" ]; then echo "PUBLISHED_VERSION is empty; cannot wait for npm publication." >&2 exit 1 fi - packages=( - "@clickhouse/client-common" - "@clickhouse/client" - "@clickhouse/client-web" - ) + if [ -z "${PUBLISHED_PACKAGES}" ]; then + echo "PUBLISHED_PACKAGES is empty; cannot wait for npm publication." >&2 + exit 1 + fi + read -r -a packages <<< "${PUBLISHED_PACKAGES}" # Poll the registry for up to ~5 minutes per package. New versions # usually surface in seconds, but the registry CDN can lag. max_attempts=60 @@ -196,10 +386,13 @@ jobs: - name: Install the packages at the published version run: | - npm install \ - "@clickhouse/client@${PUBLISHED_VERSION}" \ - "@clickhouse/client-common@${PUBLISHED_VERSION}" \ - "@clickhouse/client-web@${PUBLISHED_VERSION}" + set -euo pipefail + read -r -a packages <<< "${PUBLISHED_PACKAGES}" + specs=() + for pkg in "${packages[@]}"; do + specs+=("${pkg}@${PUBLISHED_VERSION}") + done + npm install "${specs[@]}" - name: Type check run: npx tsc --noEmit diff --git a/.scripts/push_release_tag.sh b/.scripts/push_release_tag.sh new file mode 100755 index 000000000..e05500566 --- /dev/null +++ b/.scripts/push_release_tag.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Create and push an annotated release git tag, skipping if it already exists +# on origin. Single-package releases use a package-scoped tag (e.g. +# `client-web-1.2.3`) so they do not collide with the shared release tag. + +set -euo pipefail + +tag=${1:-} +if [ -z "$tag" ]; then + echo "Usage: $0 " >&2 + exit 1 +fi + +if git ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then + echo "Tag ${tag} already exists on origin; skipping." + exit 0 +fi + +git config user.name "github-actions[bot]" +git config user.email "41898282+github-actions[bot]@users.noreply.github.com" +git tag -a "${tag}" -m "Release ${tag}" +git push origin "refs/tags/${tag}" diff --git a/.scripts/smoke_test_pack.sh b/.scripts/smoke_test_pack.sh new file mode 100755 index 000000000..33c217f34 --- /dev/null +++ b/.scripts/smoke_test_pack.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# +# Pre-publish smoke test. +# +# Packs an already-built workspace into a tarball, installs that tarball into a +# throwaway app (install-from-artifact only, exactly as a downstream consumer +# would), and runs ESM + CJS checks against it. This catches packaging problems +# - missing files, broken exports, unexpected transitive deps - before the +# package is published to npm, rather than after. +# +# Usage: .scripts/smoke_test_pack.sh [workspace] +# workspace defaults to @clickhouse/client. +# +# Run from the repository root, after `npm run build` (or a per-workspace build). +set -euo pipefail + +WORKSPACE="${1:-@clickhouse/client}" +REPO="$(pwd)" +SMOKE_DIR="$REPO/tests/e2e/smoke" + +APP="$(mktemp -d)/smoke-app" +mkdir -p "$APP" +# Clean up the throwaway app even if a check fails. +trap 'rm -rf "$(dirname "$APP")"' EXIT + +TARBALL="$(npm pack -w "$WORKSPACE" --pack-destination "$APP" --json \ + | node -e "console.log(JSON.parse(require('fs').readFileSync(0))[0].filename)")" +echo "Packed $WORKSPACE -> $TARBALL" + +cp "$SMOKE_DIR/check.mjs" "$SMOKE_DIR/check.cjs" "$APP/" +cd "$APP" +npm init -y >/dev/null +npm install "./$TARBALL" + +echo "--- installed @clickhouse packages ---" +ls node_modules/@clickhouse/ + +echo "--- ESM check ---" +node check.mjs +echo "--- CJS check ---" +node check.cjs + +cd "$REPO" +echo "Smoke test passed for $WORKSPACE." diff --git a/.scripts/update_version.sh b/.scripts/update_version.sh deleted file mode 100755 index 7f4ca3278..000000000 --- a/.scripts/update_version.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -version=${1:-} -if [ -z "$version" ]; then - echo "Usage: $0 " - exit 1 -fi - -echo "Setting the version to: $version" - -for package in packages/client-node packages/client-web; do - if [ -f "$package/package.json" ]; then - echo "Updating client-common version in $package/package.json" - json=$(cat "$package/package.json") - echo "$json" | jq --arg version "$version" '.dependencies["@clickhouse/client-common"] = $version' > "$package/package.json" - fi -done - -for package in packages/client-common packages/client-node packages/client-web; do - if [ -f "$package/package.json" ]; then - echo "Updating version in $package/src/version.ts" - echo "export default \"$version\";" > "$package/src/version.ts" - fi -done - -npm --workspaces version --no-git-tag-version "$version" diff --git a/AGENTS.md b/AGENTS.md index 01ff68904..a24d8cf5e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -29,6 +29,10 @@ The source packages under [`packages/`](packages) are: - `client-common` — platform-agnostic shared code (config, query-param formatting, multipart assembly, URL handling, result sets, etc.). It must not depend on Node.js-only or Web-only APIs. + The published `@clickhouse/client-common` package is **deprecated**: `client-node` and `client-web` + no longer depend on it and instead bundle its sources via the `src/common` symlink + (`packages/client-node/src/common` and `packages/client-web/src/common` both point to + `packages/client-common/src`), importing from it with relative paths (e.g. `./common/index`). - `client-node` (`@clickhouse/client`) — the Node.js client. - `client-web` (`@clickhouse/client-web`) — the Web/edge client. diff --git a/CHANGELOG.md b/CHANGELOG.md index a30fc3a0b..f006bce2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ # 1.22.0 +## Migration Notes + +- The `@clickhouse/client-common` package is deprecated. `@clickhouse/client` (Node.js) and `@clickhouse/client-web` (Web) no longer depend on it; the shared code is now bundled into each client package. Everything previously importable from `@clickhouse/client-common` should be imported from `@clickhouse/client` or `@clickhouse/client-web` instead. The `@clickhouse/client-common` package itself will no longer receive updates. ([#845]) + ## New features - (Node.js) The `compression.request` / `compression.response` client options now accept an explicit codec via an object, in addition to the existing boolean: `true` keeps gzip (backwards compatible), and `{ codec: "zstd" }` selects zstd. The object form is intentionally extensible for future codecs and codec-specific options. zstd typically yields a similar-or-better ratio than gzip at noticeably lower CPU cost (gzip/DEFLATE is comparatively CPU-heavy and decompressed single-threaded by the ClickHouse server), and it uses the built-in `zlib` zstd support, so it requires **Node.js >= 22.15.0** (`@clickhouse/client` throws a clear error at client creation otherwise). Response decompression is driven by the server's actual `Content-Encoding`, so it degrades gracefully. The request object form also accepts an optional `level` (`{ codec, level }`) to set the codec-specific compression level (zlib level for gzip, zstd compression level for zstd); the response compression level is controlled by the server. Supported only by `@clickhouse/client` (Node.js); `@clickhouse/client-web` rejects the `zstd` codec at client creation. @@ -70,6 +74,7 @@ await client.query({ [#825]: https://github.com/ClickHouse/clickhouse-js/pull/825 [#827]: https://github.com/ClickHouse/clickhouse-js/pull/827 [#828]: https://github.com/ClickHouse/clickhouse-js/pull/828 +[#845]: https://github.com/ClickHouse/clickhouse-js/pull/845 [#864]: https://github.com/ClickHouse/clickhouse-js/pull/864 ## Bug Fixes diff --git a/RELEASING.md b/RELEASING.md index a5c9d9274..93f527df8 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -1,44 +1,28 @@ # Release process -Tools required: +Tools required (for verifying a published build and promoting npm tags locally): - Node.js >= `20.x` - NPM >= `11.x` -- jq (https://stedolan.github.io/jq/) -We prefer to keep versions the same across the packages, and release all at once, even if there were no changes in some. +Packages are versioned and released independently. Release one package at a time; to release several, repeat the steps below for each. Versions are bumped through the GitHub Actions workflows — there is no local version-bump script. -Bump the version: +## Bump the version -```bash -# get the current version -cat packages/client-common/package.json | grep '"version":' -# update the version appropriately and set it to the environment variable -export NEW_VERSION=[new_version] -``` +Run the [`bump-version`](.github/workflows/bump-version.yml) workflow from the GitHub Actions tab. Select: -Make sure that the working directory is up to date and clean: +- `package` — the package to release: `@clickhouse/client`, `@clickhouse/client-web`, or `@clickhouse/client-common` (the last is deprecated, but can still be cut a final standalone release). +- `bump_type` — `patch`, `minor`, or `major`. -```bash -git checkout main -git pull -git clean -dfX -``` +The workflow computes the next version, bumps that package's `package.json` and `src/version.ts`, and opens a release PR against `main`. -```bash -git checkout -b release-$NEW_VERSION -.scripts/update_version.sh "$NEW_VERSION" -``` +Review and merge the PR into `main`. -Commit the version update and push it to the repository: +## Publish the `head` build -```bash -git add . -git commit -m "chore: bump version to $NEW_VERSION" -git push -u origin release-$NEW_VERSION -``` +The signed `head` build is published by the [`publish`](.github/workflows/publish.yml) workflow on push to the long-lived `release` branch — not on merge to `main`. After the bump PR is merged, update `release` from `main` (open a PR from `main` into `release` and merge it). That push triggers the `head` publish for every package. -Create a PR and merge it. Wait for the CI/CD pipeline to publish a signed `head` version. +## Test the `head` build After the package is published it can be tested in a separate project by installing it with the `head` tag: @@ -48,16 +32,24 @@ npm install @clickhouse/client@head and run a simple e2e test: https://github.com/ClickHouse/clickhouse-js/actions/workflows/npm.yml -Promote the `head` tag to `latest`: +## Promote the `head` tag to `latest` + +Run this for the package(s) you released: ```bash -npm dist-tag add @clickhouse/client-common@head latest npm dist-tag add @clickhouse/client@head latest npm dist-tag add @clickhouse/client-web@head latest +npm dist-tag add @clickhouse/client-common@head latest +``` + +Mark the deprecated `@clickhouse/client-common` package as such on npm (it is no longer used by `@clickhouse/client` or `@clickhouse/client-web`; the shared code is bundled into each client package): + +```bash +npm deprecate @clickhouse/client-common "This package is deprecated and no longer used by @clickhouse/client or @clickhouse/client-web. Import everything from @clickhouse/client (Node.js) or @clickhouse/client-web (Web) instead." ``` Check that the packages have been published correctly: -Then create a new release in GitHub for `$NEW_VERSION` and include the corresponding changelog notes. +Then create a new release in GitHub for the published version and include the corresponding changelog notes. All done, thanks! diff --git a/package-lock.json b/package-lock.json index 84678bc89..eb4e6e5f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7199,9 +7199,6 @@ "name": "@clickhouse/client", "version": "1.23.0", "license": "Apache-2.0", - "dependencies": { - "@clickhouse/client-common": "1.23.0" - }, "devDependencies": { "simdjson": "^0.9.2" }, @@ -7212,10 +7209,7 @@ "packages/client-web": { "name": "@clickhouse/client-web", "version": "1.23.0", - "license": "Apache-2.0", - "dependencies": { - "@clickhouse/client-common": "1.23.0" - } + "license": "Apache-2.0" }, "tests/clickhouse-test-runner": { "name": "@clickhouse/clickhouse-test-runner", diff --git a/packages/client-common/package.json b/packages/client-common/package.json index 10c76ed79..187b11982 100644 --- a/packages/client-common/package.json +++ b/packages/client-common/package.json @@ -1,6 +1,6 @@ { "name": "@clickhouse/client-common", - "description": "Official JS client for ClickHouse DB - common types", + "description": "DEPRECATED: this package is no longer used by @clickhouse/client or @clickhouse/client-web; the shared code is now bundled into each client package. Install @clickhouse/client (Node.js) or @clickhouse/client-web (Web) instead.", "homepage": "https://clickhouse.com", "version": "1.23.0", "license": "Apache-2.0", diff --git a/packages/client-common/src/index.ts b/packages/client-common/src/index.ts index 3b86b3989..a3ce616be 100644 --- a/packages/client-common/src/index.ts +++ b/packages/client-common/src/index.ts @@ -1,3 +1,12 @@ +/** + * @deprecated The `@clickhouse/client-common` package is deprecated. It is no longer used by + * `@clickhouse/client` or `@clickhouse/client-web`; the shared code is bundled into each client + * package instead. Import everything from `@clickhouse/client` (Node.js) or + * `@clickhouse/client-web` (Web) instead. + * + * @packageDocumentation + */ + /** Should be re-exported by the implementation */ export { type BaseQueryParams, diff --git a/packages/client-node/package.json b/packages/client-node/package.json index bd592db8b..d275b92de 100644 --- a/packages/client-node/package.json +++ b/packages/client-node/package.json @@ -47,9 +47,7 @@ "lint:fix": "eslint . --fix", "build": "rm -rf dist; tsc" }, - "dependencies": { - "@clickhouse/client-common": "1.23.0" - }, + "dependencies": {}, "devDependencies": { "simdjson": "^0.9.2" } diff --git a/packages/client-node/src/client.ts b/packages/client-node/src/client.ts index 93f0ef4e1..e57482fc3 100644 --- a/packages/client-node/src/client.ts +++ b/packages/client-node/src/client.ts @@ -1,9 +1,5 @@ -import type { - DataFormat, - IsSame, - QueryParamsWithFormat, -} from "@clickhouse/client-common"; -import { ClickHouseClient } from "@clickhouse/client-common"; +import type { DataFormat, IsSame, QueryParamsWithFormat } from "./common/index"; +import { ClickHouseClient } from "./common/index"; import type Stream from "stream"; import type { NodeClickHouseClientConfigOptions } from "./config"; import { NodeConfigImpl } from "./config"; diff --git a/packages/client-node/src/common b/packages/client-node/src/common new file mode 120000 index 000000000..d35367737 --- /dev/null +++ b/packages/client-node/src/common @@ -0,0 +1 @@ +../../client-common/src \ No newline at end of file diff --git a/packages/client-node/src/config.ts b/packages/client-node/src/config.ts index 2e1a42f2d..ff7e5ffdc 100644 --- a/packages/client-node/src/config.ts +++ b/packages/client-node/src/config.ts @@ -4,13 +4,13 @@ import type { ImplementationDetails, JSONHandling, ResponseHeaders, -} from "@clickhouse/client-common"; +} from "./common/index"; import { type BaseClickHouseClientConfigOptions, type CompressionMethod, type ConnectionParams, numberConfigURLValue, -} from "@clickhouse/client-common"; +} from "./common/index"; import type http from "http"; import type https from "node:https"; import type Stream from "stream"; diff --git a/packages/client-node/src/connection/compression.ts b/packages/client-node/src/connection/compression.ts index 0854bff92..546a9c113 100644 --- a/packages/client-node/src/connection/compression.ts +++ b/packages/client-node/src/connection/compression.ts @@ -1,5 +1,5 @@ -import type { LogWriter, RequestCompression } from "@clickhouse/client-common"; -import { ClickHouseLogLevel } from "@clickhouse/client-common"; +import type { LogWriter, RequestCompression } from "../common/index"; +import { ClickHouseLogLevel } from "../common/index"; import type Http from "http"; import Stream from "stream"; import Zlib from "zlib"; diff --git a/packages/client-node/src/connection/create_connection.ts b/packages/client-node/src/connection/create_connection.ts index 8a8e31ca8..8e3470245 100644 --- a/packages/client-node/src/connection/create_connection.ts +++ b/packages/client-node/src/connection/create_connection.ts @@ -1,4 +1,4 @@ -import type { ConnectionParams } from "@clickhouse/client-common"; +import type { ConnectionParams } from "../common/index"; import type http from "http"; import type https from "node:https"; import type { diff --git a/packages/client-node/src/connection/node_base_connection.ts b/packages/client-node/src/connection/node_base_connection.ts index 337508ac0..3608ff532 100644 --- a/packages/client-node/src/connection/node_base_connection.ts +++ b/packages/client-node/src/connection/node_base_connection.ts @@ -12,7 +12,7 @@ import type { ConnPingResult, ConnQueryResult, ResponseHeaders, -} from "@clickhouse/client-common"; +} from "../common/index"; import { buildMultipartBody, serializeQueryParamsForUrl, @@ -23,8 +23,8 @@ import { transformUrl, withHttpSettings, ClickHouseLogLevel, -} from "@clickhouse/client-common"; -import { type ConnPingParams } from "@clickhouse/client-common"; +} from "../common/index"; +import { type ConnPingParams } from "../common/index"; import crypto from "crypto"; import type Http from "http"; import type Https from "node:https"; diff --git a/packages/client-node/src/connection/node_custom_agent_connection.ts b/packages/client-node/src/connection/node_custom_agent_connection.ts index 6000be525..4d8073044 100644 --- a/packages/client-node/src/connection/node_custom_agent_connection.ts +++ b/packages/client-node/src/connection/node_custom_agent_connection.ts @@ -3,7 +3,7 @@ import Https from "https"; import type { NodeConnectionParams } from "./node_base_connection"; import type { RequestParams } from "./socket_pool"; import { NodeBaseConnection } from "./node_base_connection"; -import { withCompressionHeaders } from "@clickhouse/client-common"; +import { withCompressionHeaders } from "../common/index"; export class NodeCustomAgentConnection extends NodeBaseConnection { private readonly httpRequestFn: typeof Http.request | typeof Https.request; diff --git a/packages/client-node/src/connection/node_http_connection.ts b/packages/client-node/src/connection/node_http_connection.ts index 12edaa884..d2071f249 100644 --- a/packages/client-node/src/connection/node_http_connection.ts +++ b/packages/client-node/src/connection/node_http_connection.ts @@ -1,4 +1,4 @@ -import { withCompressionHeaders } from "@clickhouse/client-common"; +import { withCompressionHeaders } from "../common/index"; import Http from "http"; import type { NodeConnectionParams } from "./node_base_connection"; import type { RequestParams } from "./socket_pool"; diff --git a/packages/client-node/src/connection/node_https_connection.ts b/packages/client-node/src/connection/node_https_connection.ts index d9a35319d..3247e8ddb 100644 --- a/packages/client-node/src/connection/node_https_connection.ts +++ b/packages/client-node/src/connection/node_https_connection.ts @@ -2,7 +2,7 @@ import { type ConnBaseQueryParams, isCredentialsAuth, withCompressionHeaders, -} from "@clickhouse/client-common"; +} from "../common/index"; import type Http from "http"; import Https from "https"; import type { NodeConnectionParams } from "./node_base_connection"; diff --git a/packages/client-node/src/connection/socket_pool.ts b/packages/client-node/src/connection/socket_pool.ts index 6e2a42823..260d35017 100644 --- a/packages/client-node/src/connection/socket_pool.ts +++ b/packages/client-node/src/connection/socket_pool.ts @@ -15,7 +15,7 @@ import { type JSONHandling, type CompressionMethod, type RequestCompression, -} from "@clickhouse/client-common"; +} from "../common/index"; import { getAsText, isStream } from "../utils"; import { createRequestCompressor, diff --git a/packages/client-node/src/connection/stream.ts b/packages/client-node/src/connection/stream.ts index 142689073..9423b1b2c 100644 --- a/packages/client-node/src/connection/stream.ts +++ b/packages/client-node/src/connection/stream.ts @@ -2,7 +2,7 @@ import { type LogWriter, type ConnOperation, ClickHouseLogLevel, -} from "@clickhouse/client-common"; +} from "../common/index"; import type Stream from "stream"; export interface Context { diff --git a/packages/client-node/src/index.ts b/packages/client-node/src/index.ts index a73f1a037..ba04008b0 100644 --- a/packages/client-node/src/index.ts +++ b/packages/client-node/src/index.ts @@ -7,7 +7,7 @@ export { type NodeClickHouseClientConfigOptions as ClickHouseClientConfigOptions export { ResultSet, type StreamReadable } from "./result_set"; export { drainStream } from "./connection/stream"; -/** Re-export @clickhouse/client-common types */ +/** Re-export common (formerly @clickhouse/client-common) types */ export { type BaseClickHouseClientConfigOptions, type BaseQueryParams, @@ -61,14 +61,14 @@ export { type ClickHouseSpanAttributes, type ClickHouseSpanStatus, type ClickHouseSpanName, -} from "@clickhouse/client-common"; +} from "./common/index"; /** - * Re-export @clickhouse/client-common runtime values. + * Re-export common (formerly @clickhouse/client-common) runtime values. * * These are intentionally re-exported through local bindings (rather than a direct - * `export { ... } from '@clickhouse/client-common'`) so that the `@deprecated` JSDoc tags - * applied to them in `@clickhouse/client-common` are NOT propagated to consumers of this package. + * `export { ... } from './common/index'`) so that the `@deprecated` JSDoc tags + * applied to them in `./common/index` are NOT propagated to consumers of this package. * Importing these values from `@clickhouse/client` is the recommended, non-deprecated path. */ import { @@ -92,7 +92,7 @@ import { ClickHouseSpanStatusCode as ClickHouseSpanStatusCode_, ClickHouseSpanKind as ClickHouseSpanKind_, defaultJSONHandling as defaultJSONHandling_, -} from "@clickhouse/client-common"; +} from "./common/index"; export const ClickHouseError = ClickHouseError_; export type ClickHouseError = ClickHouseError_; diff --git a/packages/client-node/src/result_set.ts b/packages/client-node/src/result_set.ts index 3d97c16ef..6c1f6347c 100644 --- a/packages/client-node/src/result_set.ts +++ b/packages/client-node/src/result_set.ts @@ -8,19 +8,19 @@ import type { ResultJSONType, ResultStream, Row, -} from "@clickhouse/client-common"; +} from "./common/index"; import { extractErrorAtTheEndOfChunk, defaultJSONHandling, EXCEPTION_TAG_HEADER_NAME, CARET_RETURN, recordSpanError, -} from "@clickhouse/client-common"; +} from "./common/index"; import { isNotStreamableJSONFamily, isStreamableJSONFamily, validateStreamFormat, -} from "@clickhouse/client-common"; +} from "./common/index"; import { Buffer } from "buffer"; import type { Readable, TransformCallback } from "stream"; import Stream, { Transform } from "stream"; diff --git a/packages/client-node/src/utils/encoder.ts b/packages/client-node/src/utils/encoder.ts index 0bda89e5b..63fc3a082 100644 --- a/packages/client-node/src/utils/encoder.ts +++ b/packages/client-node/src/utils/encoder.ts @@ -3,8 +3,8 @@ import type { InsertValues, JSONHandling, ValuesEncoder, -} from "@clickhouse/client-common"; -import { encodeJSON, isSupportedRawFormat } from "@clickhouse/client-common"; +} from "../common/index"; +import { encodeJSON, isSupportedRawFormat } from "../common/index"; import Stream from "stream"; import { isStream, mapStream } from "./stream"; diff --git a/packages/client-web/package.json b/packages/client-web/package.json index a25d0a77e..ce37e87e3 100644 --- a/packages/client-web/package.json +++ b/packages/client-web/package.json @@ -30,7 +30,5 @@ "lint:fix": "eslint . --fix", "build": "rm -rf dist; tsc" }, - "dependencies": { - "@clickhouse/client-common": "1.23.0" - } + "dependencies": {} } diff --git a/packages/client-web/src/client.ts b/packages/client-web/src/client.ts index 653adeea8..f8cb5697b 100644 --- a/packages/client-web/src/client.ts +++ b/packages/client-web/src/client.ts @@ -10,8 +10,8 @@ import type { InsertResult, IsSame, QueryParamsWithFormat, -} from "@clickhouse/client-common"; -import { ClickHouseClient } from "@clickhouse/client-common"; +} from "./common/index"; +import { ClickHouseClient } from "./common/index"; import type { WebClickHouseClientConfigOptions } from "./config"; import { WebImpl } from "./config"; import type { ResultSet } from "./result_set"; diff --git a/packages/client-web/src/common b/packages/client-web/src/common new file mode 120000 index 000000000..d35367737 --- /dev/null +++ b/packages/client-web/src/common @@ -0,0 +1 @@ +../../client-common/src \ No newline at end of file diff --git a/packages/client-web/src/config.ts b/packages/client-web/src/config.ts index 289e315bc..a5e457b24 100644 --- a/packages/client-web/src/config.ts +++ b/packages/client-web/src/config.ts @@ -7,7 +7,7 @@ import type { ImplementationDetails, JSONHandling, ResponseHeaders, -} from "@clickhouse/client-common"; +} from "./common/index"; import { WebConnection } from "./connection"; import { ResultSet } from "./result_set"; import { WebValuesEncoder } from "./utils"; diff --git a/packages/client-web/src/connection/web_connection.ts b/packages/client-web/src/connection/web_connection.ts index 6ea633c71..3698059be 100644 --- a/packages/client-web/src/connection/web_connection.ts +++ b/packages/client-web/src/connection/web_connection.ts @@ -8,7 +8,7 @@ import type { ConnPingResult, ConnQueryResult, ResponseHeaders, -} from "@clickhouse/client-common"; +} from "../common/index"; import { buildMultipartBody, serializeQueryParamsForUrl, @@ -21,7 +21,7 @@ import { transformUrl, withCompressionHeaders, withHttpSettings, -} from "@clickhouse/client-common"; +} from "../common/index"; import { getAsText } from "../utils"; type WebInsertParams = Omit< diff --git a/packages/client-web/src/index.ts b/packages/client-web/src/index.ts index b283af44b..6cd07a9e7 100644 --- a/packages/client-web/src/index.ts +++ b/packages/client-web/src/index.ts @@ -6,7 +6,7 @@ export { createClient } from "./client"; export { type WebClickHouseClientConfigOptions as ClickHouseClientConfigOptions } from "./config"; export { ResultSet } from "./result_set"; -/** Re-export @clickhouse/client-common types */ +/** Re-export common (formerly @clickhouse/client-common) types */ export { type BaseClickHouseClientConfigOptions, type BaseQueryParams, @@ -60,14 +60,14 @@ export { type ClickHouseSpanAttributes, type ClickHouseSpanStatus, type ClickHouseSpanName, -} from "@clickhouse/client-common"; +} from "./common/index"; /** - * Re-export @clickhouse/client-common runtime values. + * Re-export common (formerly @clickhouse/client-common) runtime values. * * These are intentionally re-exported through local bindings (rather than a direct - * `export { ... } from '@clickhouse/client-common'`) so that the `@deprecated` JSDoc tags - * applied to them in `@clickhouse/client-common` are NOT propagated to consumers of this package. + * `export { ... } from './common/index'`) so that the `@deprecated` JSDoc tags + * applied to them in `./common/index` are NOT propagated to consumers of this package. * Importing these values from `@clickhouse/client-web` is the recommended, non-deprecated path. */ import { @@ -91,7 +91,7 @@ import { ClickHouseSpanStatusCode as ClickHouseSpanStatusCode_, ClickHouseSpanKind as ClickHouseSpanKind_, defaultJSONHandling as defaultJSONHandling_, -} from "@clickhouse/client-common"; +} from "./common/index"; export const ClickHouseError = ClickHouseError_; export type ClickHouseError = ClickHouseError_; diff --git a/packages/client-web/src/result_set.ts b/packages/client-web/src/result_set.ts index 3c57cbd7e..8a1fb1578 100644 --- a/packages/client-web/src/result_set.ts +++ b/packages/client-web/src/result_set.ts @@ -8,17 +8,17 @@ import type { ResultJSONType, ResultStream, Row, -} from "@clickhouse/client-common"; +} from "./common/index"; import { CARET_RETURN, extractErrorAtTheEndOfChunk, recordSpanError, -} from "@clickhouse/client-common"; +} from "./common/index"; import { isNotStreamableJSONFamily, isStreamableJSONFamily, validateStreamFormat, -} from "@clickhouse/client-common"; +} from "./common/index"; import { getAsText } from "./utils"; const NEWLINE = 0x0a as const; diff --git a/packages/client-web/src/utils/encoder.ts b/packages/client-web/src/utils/encoder.ts index b4f7b3a6b..4901035a5 100644 --- a/packages/client-web/src/utils/encoder.ts +++ b/packages/client-web/src/utils/encoder.ts @@ -1,9 +1,5 @@ -import type { - DataFormat, - InsertValues, - ValuesEncoder, -} from "@clickhouse/client-common"; -import { encodeJSON, type JSONHandling } from "@clickhouse/client-common"; +import type { DataFormat, InsertValues, ValuesEncoder } from "../common/index"; +import { encodeJSON, type JSONHandling } from "../common/index"; import { isStream } from "./stream"; export class WebValuesEncoder implements ValuesEncoder { diff --git a/tests/e2e/smoke/check.cjs b/tests/e2e/smoke/check.cjs new file mode 100644 index 000000000..967450a21 --- /dev/null +++ b/tests/e2e/smoke/check.cjs @@ -0,0 +1,25 @@ +// Pre-publish smoke test (CommonJS). +// +// Same intent as check.mjs, but resolves the package via `require()` to cover +// the CJS entry point of the published artifact. +const assert = require("node:assert"); +const { + parseColumnType, + SettingsMap, + ClickHouseError, +} = require("@clickhouse/client"); + +const t = parseColumnType("Array(String)"); +console.log('parseColumnType("Array(String)") =>', JSON.stringify(t)); +assert.equal(t.type, "Array"); +assert.equal(t.value.columnType, "String"); + +const sm = SettingsMap.from({ max_block_size: "1000" }); +console.log("SettingsMap.toString() =>", sm.toString()); +assert.equal(typeof sm.toString(), "string"); + +assert.equal(typeof ClickHouseError, "function"); + +console.log( + "OK (CJS): all common-origin imports resolved and executed from the installed package", +); diff --git a/tests/e2e/smoke/check.mjs b/tests/e2e/smoke/check.mjs new file mode 100644 index 000000000..ee45713c0 --- /dev/null +++ b/tests/e2e/smoke/check.mjs @@ -0,0 +1,28 @@ +// Pre-publish smoke test (ESM). +// +// Imports symbols that originate in the (now bundled) `common` sources and are +// re-exported from `@clickhouse/client` via `./common/index`. Exercising them +// from a tarball install proves the bundled common code is compiled into the +// published artifact and usable by consumers - without `@clickhouse/client-common` +// as a runtime dependency. +import { + parseColumnType, + SettingsMap, + ClickHouseError, +} from "@clickhouse/client"; +import assert from "node:assert"; + +const t = parseColumnType("Nullable(UInt64)"); +console.log('parseColumnType("Nullable(UInt64)") =>', JSON.stringify(t)); +assert.equal(t.type, "Nullable"); +assert.equal(t.value.columnType, "UInt64"); + +const sm = SettingsMap.from({ max_block_size: "1000" }); +console.log("SettingsMap.toString() =>", sm.toString()); +assert.equal(typeof sm.toString(), "string"); + +assert.equal(typeof ClickHouseError, "function"); + +console.log( + "OK (ESM): all common-origin imports resolved and executed from the installed package", +); From d60648b9c21212bf3780d0ffbb9fd3dccf09ce5e Mon Sep 17 00:00:00 2001 From: Peter Leonov Date: Mon, 22 Jun 2026 23:40:56 +0200 Subject: [PATCH 3/3] Address PR #876 review comments (#878) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Addresses the Copilot review comments on #876. - **CHANGELOG.md** — moved the `@clickhouse/client-common` deprecation *Migration Notes* from the `1.22.0` heading to the unreleased `1.23.0` heading, since that observable change (node/web no longer depend on client-common) ships in this release. - **RELEASING.md** — clarified the npm `11.x` requirement: it's newer than the npm bundled with Node.js `20.x`/`22.x` (`10.x`); either upgrade npm in place or use Node.js `24.x` (which ships npm `11.x`). - **tests/e2e/smoke/check.mjs** / **check.cjs** — use `assert.strictEqual` instead of loose `assert.equal`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 8 ++++---- RELEASING.md | 2 +- tests/e2e/smoke/check.cjs | 8 ++++---- tests/e2e/smoke/check.mjs | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f006bce2d..3140c1a67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,15 @@ # 1.23.0 +## Migration Notes + +- The `@clickhouse/client-common` package is deprecated. `@clickhouse/client` (Node.js) and `@clickhouse/client-web` (Web) no longer depend on it; the shared code is now bundled into each client package. Everything previously importable from `@clickhouse/client-common` should be imported from `@clickhouse/client` or `@clickhouse/client-web` instead. The `@clickhouse/client-common` package itself will no longer receive updates. ([#845]) + ## New features - (Node.js) Added a RowBinary reader library and agent skill under [`skills/clickhouse-js-node-rowbinary-parser`](./skills/clickhouse-js-node-rowbinary-parser). It ships type-specific, monomorphizable building blocks for decoding `RowBinary` / `RowBinaryWithNames` / `RowBinaryWithNamesAndTypes` streams (full-buffer and chunked), plus a skill that guides an agent to generate bespoke high-performance parsers from a query's column types. The skill is bundled into `@clickhouse/client` (registered in `agents.skills`) and is also published independently as the [`@clickhouse/rowbinary`](https://www.npmjs.com/package/@clickhouse/rowbinary) package. A matching RowBinary writer is planned. ([#864]) # 1.22.0 -## Migration Notes - -- The `@clickhouse/client-common` package is deprecated. `@clickhouse/client` (Node.js) and `@clickhouse/client-web` (Web) no longer depend on it; the shared code is now bundled into each client package. Everything previously importable from `@clickhouse/client-common` should be imported from `@clickhouse/client` or `@clickhouse/client-web` instead. The `@clickhouse/client-common` package itself will no longer receive updates. ([#845]) - ## New features - (Node.js) The `compression.request` / `compression.response` client options now accept an explicit codec via an object, in addition to the existing boolean: `true` keeps gzip (backwards compatible), and `{ codec: "zstd" }` selects zstd. The object form is intentionally extensible for future codecs and codec-specific options. zstd typically yields a similar-or-better ratio than gzip at noticeably lower CPU cost (gzip/DEFLATE is comparatively CPU-heavy and decompressed single-threaded by the ClickHouse server), and it uses the built-in `zlib` zstd support, so it requires **Node.js >= 22.15.0** (`@clickhouse/client` throws a clear error at client creation otherwise). Response decompression is driven by the server's actual `Content-Encoding`, so it degrades gracefully. The request object form also accepts an optional `level` (`{ codec, level }`) to set the codec-specific compression level (zlib level for gzip, zstd compression level for zstd); the response compression level is controlled by the server. Supported only by `@clickhouse/client` (Node.js); `@clickhouse/client-web` rejects the `zstd` codec at client creation. diff --git a/RELEASING.md b/RELEASING.md index 93f527df8..f1ffa5f6d 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -3,7 +3,7 @@ Tools required (for verifying a published build and promoting npm tags locally): - Node.js >= `20.x` -- NPM >= `11.x` +- npm >= `11.x` — newer than the npm bundled with Node.js `20.x`/`22.x` (`10.x`). Either upgrade npm in place (`npm install -g npm@latest`) or use Node.js `24.x`, which already ships npm `11.x`. Packages are versioned and released independently. Release one package at a time; to release several, repeat the steps below for each. Versions are bumped through the GitHub Actions workflows — there is no local version-bump script. diff --git a/tests/e2e/smoke/check.cjs b/tests/e2e/smoke/check.cjs index 967450a21..024016fb5 100644 --- a/tests/e2e/smoke/check.cjs +++ b/tests/e2e/smoke/check.cjs @@ -11,14 +11,14 @@ const { const t = parseColumnType("Array(String)"); console.log('parseColumnType("Array(String)") =>', JSON.stringify(t)); -assert.equal(t.type, "Array"); -assert.equal(t.value.columnType, "String"); +assert.strictEqual(t.type, "Array"); +assert.strictEqual(t.value.columnType, "String"); const sm = SettingsMap.from({ max_block_size: "1000" }); console.log("SettingsMap.toString() =>", sm.toString()); -assert.equal(typeof sm.toString(), "string"); +assert.strictEqual(typeof sm.toString(), "string"); -assert.equal(typeof ClickHouseError, "function"); +assert.strictEqual(typeof ClickHouseError, "function"); console.log( "OK (CJS): all common-origin imports resolved and executed from the installed package", diff --git a/tests/e2e/smoke/check.mjs b/tests/e2e/smoke/check.mjs index ee45713c0..b5dc82a5c 100644 --- a/tests/e2e/smoke/check.mjs +++ b/tests/e2e/smoke/check.mjs @@ -14,14 +14,14 @@ import assert from "node:assert"; const t = parseColumnType("Nullable(UInt64)"); console.log('parseColumnType("Nullable(UInt64)") =>', JSON.stringify(t)); -assert.equal(t.type, "Nullable"); -assert.equal(t.value.columnType, "UInt64"); +assert.strictEqual(t.type, "Nullable"); +assert.strictEqual(t.value.columnType, "UInt64"); const sm = SettingsMap.from({ max_block_size: "1000" }); console.log("SettingsMap.toString() =>", sm.toString()); -assert.equal(typeof sm.toString(), "string"); +assert.strictEqual(typeof sm.toString(), "string"); -assert.equal(typeof ClickHouseError, "function"); +assert.strictEqual(typeof ClickHouseError, "function"); console.log( "OK (ESM): all common-origin imports resolved and executed from the installed package",