Skip to content
Merged
284 changes: 284 additions & 0 deletions .github/workflows/engine-release-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
name: Engine release check

# chdb-core publishes an engine and dispatches here; this runs the suite against
# that engine and records the verdict in an issue. It gates nothing — the engine
# has already shipped by the time this starts.
#
# The regular test job builds against the engine this repository pinned in
# update_libchdb.sh, so it stays green through any change chdb-core makes after
# that pin. The addon's C++ does get a compile error out of a changed signature,
# but only against the header it was handed, and a struct that changes layout
# without changing its declaration produces no error at all.
#
# One Node version per platform on purpose: what is under test is the C ABI, and
# that does not vary by Node version. Platform does vary, so all four stay.

on:
repository_dispatch:
types: [chdb-core-release]
workflow_dispatch:
inputs:
engine_version:
description: "chdb-core release tag, e.g. v26.5.0"
required: true

permissions:
contents: read

env:
npm_config_fetch_retries: "5"
npm_config_fetch_retry_mintimeout: "20000"
npm_config_fetch_retry_maxtimeout: "120000"
npm_config_fetch_timeout: "600000"

jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, macos-14, macos-15-intel]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4

- name: Resolve the engine version
shell: bash
env:
ENGINE_VERSION: ${{ github.event.client_payload.tag || github.event.inputs.engine_version }}
run: |
if [ -z "$ENGINE_VERSION" ]; then
echo "::error::no engine version in the dispatch payload or the manual input"
exit 1
fi
# The version arrives from a dispatch payload or a typed input, then flows
# into a URL, a branch name, a commit message and a sed replacement. Any
# character outside this set belongs to no chdb-core release tag, and an
# & or | reaching sed would quietly rewrite the wrong thing.
case "$ENGINE_VERSION" in
*[!A-Za-z0-9._+-]*)
echo "::error::refusing engine version '$ENGINE_VERSION': letters, digits and . _ + - only"
exit 1 ;;
esac
echo "CHDB_ENGINE_VERSION=$ENGINE_VERSION" >> "$GITHUB_ENV"
echo "Testing against chdb-core $ENGINE_VERSION"

- uses: actions/setup-python@v5
with:
python-version: "3.11"

- uses: actions/setup-node@v4
with:
node-version: 20.x
cache: npm

- name: Install JS deps (no compile-on-install)
run: npm install --ignore-scripts

- name: Fetch the published engine
run: npm run libchdb

- name: Build (addon + dist)
run: npm run build

- name: Exercise the freshly built addon (not the published prebuilt)
# loadNative() prefers the published @chdb/lib-<platform> subpackage,
# which carries its own engine and would mask the one under test.
shell: bash
run: rm -rf node_modules/@chdb/lib-*

- name: Test (v2 mocha + v3 vitest)
run: npm run test:all

# Green means the engine can be adopted, not that it has been. Adoption is a
# one-line change to a pinned version and goes through review like any other
# dependency bump; this only writes the line. LIBCHDB_NPM_VERSION is left
# alone — it tracks the npm subpackage, not the engine.
propose_bump:
needs: test
if: needs.test.result == 'success'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
outputs:
pr: ${{ steps.bump.outputs.pr }}
unproposed: ${{ steps.bump.outputs.unproposed }}
steps:
# The commit the suite actually ran against, not whatever the default branch
# has become since. github.sha is fixed for the whole run, so this is the
# same tree the test job exercised; a default branch that moved during a
# long matrix would otherwise put the new pin on untested code while the
# pull request claims the suite passed.
- uses: actions/checkout@v4
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
with:
ref: ${{ github.sha }}

- id: bump
name: Open a PR moving the pin to this engine
env:
GH_TOKEN: ${{ github.token }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
ENGINE_VERSION: ${{ github.event.client_payload.tag || github.event.inputs.engine_version }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail

# test rejects these too, but this is the step that interpolates the
# version into sed replacements and a branch name.
case "$ENGINE_VERSION" in
*[!A-Za-z0-9._+-]*)
echo "::error::refusing engine version '$ENGINE_VERSION'"
exit 1 ;;
esac

# Only when the tested commit is still the tip of the default branch.
# Anything else means merging the bump would adopt commits no run
# exercised against this engine, and the bump carries no CI to catch it.
# Declining and saying why beats a pull request claiming more than the
# run established.
rel=$(gh api "repos/$GITHUB_REPOSITORY/compare/$DEFAULT_BRANCH...$GITHUB_SHA" --jq .status)
if [ "$rel" != identical ]; then
echo "unproposed=The tested commit $GITHUB_SHA is $rel relative to $DEFAULT_BRANCH, so nothing was proposed" >> "$GITHUB_OUTPUT"
echo "declining to propose a bump: $rel"
exit 0
fi

current=$(grep -E '^CHDB_ENGINE_PIN=' update_libchdb.sh | cut -d= -f2)
if [ "$current" = "$ENGINE_VERSION" ]; then
echo "already pinned to $ENGINE_VERSION, nothing to propose"
exit 0
fi

branch="engine-pin-$ENGINE_VERSION"
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
if [ "$(gh pr list --head "$branch" --state open --json number --jq 'length')" != 0 ]; then
echo "a PR for $ENGINE_VERSION is already open"
exit 0
fi

git switch -c "$branch"
sed -i "s|^CHDB_ENGINE_PIN=.*|CHDB_ENGINE_PIN=$ENGINE_VERSION|" update_libchdb.sh
git -c user.name="github-actions[bot]" \
-c user.email="41898282+github-actions[bot]@users.noreply.github.com" \
commit -am "Move the engine pin from $current to $ENGINE_VERSION"
# The branch can already exist on the remote: a bump PR closed without
# merging leaves it behind, and a plain push is then rejected as a
# non-fast-forward, silently costing the adoption PR. No open PR uses it
# — that was checked above — and its only content is one generated line,
# so replacing it is safe.
if git ls-remote --exit-code --heads origin "$branch" >/dev/null 2>&1; then
echo "$branch is left over from an earlier attempt, replacing it"
git push --force -u origin "$branch"
else
git push -u origin "$branch"
fi

{
echo "The release check ran the v2 and v3 suites against \`$ENGINE_VERSION\` on"
echo "all four platforms and they passed, so the engine can be adopted. This"
echo "moves the pin $current → \`$ENGINE_VERSION\`."
echo
echo "\`LIBCHDB_NPM_VERSION\` is untouched. Publishing new \`@chdb/lib-<platform>\`"
echo "subpackages carrying this engine is a separate decision."
echo
echo "$RUN_URL"
echo
echo "Based on $GITHUB_SHA, the commit that run tested."
echo
echo "No checks will appear here. GitHub does not start workflow runs for"
echo "commits a workflow pushed with \`GITHUB_TOKEN\`, and running CI on this"
echo "branch would exercise the same suites against the same engine the check"
echo "just used."
} > pr-body.md

url=$(gh pr create --base "$DEFAULT_BRANCH" --head "$branch" \
--title "Move the engine pin to $ENGINE_VERSION" \
--body-file pr-body.md)
echo "pr=$url" >> "$GITHUB_OUTPUT"
echo "$url"

report:
needs: [test, propose_bump]
if: always()
runs-on: ubuntu-latest
permissions:
issues: write
steps:
- name: Open an issue with the verdict
env:
GH_TOKEN: ${{ github.token }}
# This job has nothing checked out, and gh does not read
# GITHUB_REPOSITORY. Without this it cannot tell which repository to
# open the issue in and every run reports nothing.
GH_REPO: ${{ github.repository }}
RESULT: ${{ needs.test.result }}
BUMP_PR: ${{ needs.propose_bump.outputs.pr }}
BUMP_RESULT: ${{ needs.propose_bump.result }}
BUMP_UNPROPOSED: ${{ needs.propose_bump.outputs.unproposed }}
ENGINE_VERSION: ${{ github.event.client_payload.tag || github.event.inputs.engine_version }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -euo pipefail

# A green suite whose bump could not be opened is not a green run. Closing
# on needs.test.result alone would file it as "nothing to adopt" and leave
# the broken automation with no signal at all.
bump_broke=0
if [ "$RESULT" != success ]; then
verdict="FAILS"
keep=1
elif [ "$BUMP_RESULT" = failure ] || [ "$BUMP_RESULT" = cancelled ]; then
verdict="passes, bump PR did not open"
keep=1
bump_broke=1
elif [ -n "$BUMP_UNPROPOSED" ]; then
verdict="passes, no bump proposed"
keep=1
else
verdict="passes"
keep=0
fi

{
if [ "$bump_broke" = 1 ]; then
echo "chdb-node passes against chdb-core \`$ENGINE_VERSION\`, but the bump PR did not open."
elif [ -n "$BUMP_UNPROPOSED" ]; then
echo "chdb-node passes against chdb-core \`$ENGINE_VERSION\`, but no bump was proposed."
else
echo "chdb-node $verdict against chdb-core \`$ENGINE_VERSION\`."
fi
echo
echo "$RUN_URL"
if [ -n "$BUMP_PR" ]; then
echo
echo "Adopting it: $BUMP_PR"
elif [ -n "$BUMP_UNPROPOSED" ]; then
echo
echo "$BUMP_UNPROPOSED. The engine is fine and the pin is unchanged; rerun"
echo "the check once the default branch stops moving, or move the pin by hand."
elif [ "$bump_broke" = 1 ]; then
echo
echo "The engine is fine; the automation is not. The pull request moving the"
echo "pin could not be opened, so this issue stays open. The usual cause is"
echo "this repository having \"Allow GitHub Actions to create and approve pull"
echo "requests\" turned off; the other is the branch push being rejected. The"
echo "pin is unchanged either way, and moving it by hand is one line."
fi
if [ "$RESULT" != success ]; then
echo
echo "This does not mean the pinned engine is broken — update_libchdb.sh is"
echo "untouched. It means adopting \`$ENGINE_VERSION\` needs addon work first."
echo "Start with the C declarations the addon uses against"
echo "\`programs/local/chdb.h\` at this tag."
fi
echo
echo "cc @auxten @wudidapaopao @ShawnChen-Sirius"
} > body.md

url=$(gh issue create \
--title "Engine check: chdb-core $ENGINE_VERSION — $verdict" \
--body-file body.md)
echo "$url"

if [ "$keep" = 0 ]; then
gh issue close "$url" --comment "Green, closing. The run is linked above."
fi
10 changes: 9 additions & 1 deletion update_libchdb.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,15 @@ set -e

# Pre-release engine for the 3.1.0-rc.1 test line (carries the written-rows
# accessors the raw/streaming insert needs; absent in the v26.5.0 stable line).
LATEST_RELEASE=v26.5.1-rc.1
#
# Keep the pin on its own line and literal: the release check greps for it when
# it proposes a bump.
CHDB_ENGINE_PIN=v26.5.1-rc.1

# CHDB_ENGINE_VERSION overrides the pin, which is how the release check runs the
# suite against an engine this repository has not adopted yet. It is a different
# thing from CHDB_LIB_VERSION below, which names the npm subpackage.
LATEST_RELEASE="${CHDB_ENGINE_VERSION:-$CHDB_ENGINE_PIN}"

# Version published for the @chdb/lib-<platform> native subpackages on npm.
# DECOUPLED from LATEST_RELEASE on purpose: chdb-core has no 26.5.2/26.5.3
Expand Down
Loading