From beed5494ee21bc202362c1025910a1dfc1880c3c Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 22 May 2026 09:17:21 +0530 Subject: [PATCH 01/15] ci: add Docker build and run tests for Node and Bun Build and health-check chronicle with basic example on both runtimes. Verifies server starts, pages render, and search API responds. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/ci.yml | 44 ++++++++++++++++++++++++++++++++++++++++ Dockerfile.bun | 26 ++++++++++++++++++++++++ Dockerfile.node | 26 ++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 Dockerfile.bun create mode 100644 Dockerfile.node diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7cc9e45a..0b1a7762 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,3 +31,47 @@ jobs: - name: Test run: bun test + + docker: + name: Docker (${{ matrix.runtime }}) + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + matrix: + include: + - runtime: bun + dockerfile: Dockerfile.bun + - runtime: node + dockerfile: Dockerfile.node + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Build image + run: docker build -f ${{ matrix.dockerfile }} -t chronicle-${{ matrix.runtime }} . + + - name: Run container + run: docker run -d --name chronicle-${{ matrix.runtime }} -p 3000:3000 chronicle-${{ matrix.runtime }} + + - name: Wait for server + run: | + for i in $(seq 1 30); do + if curl -sf http://localhost:3000/api/health > /dev/null 2>&1; then + echo "Server ready" + exit 0 + fi + sleep 2 + done + echo "Server failed to start" + docker logs chronicle-${{ matrix.runtime }} + exit 1 + + - name: Verify pages + run: | + curl -sf -o /dev/null -w "%{http_code}" http://localhost:3000/ | grep -q "307" + curl -sf http://localhost:3000/docs | grep -q 'id="root"' + curl -sf http://localhost:3000/api/search | grep -q '"url"' + + - name: Cleanup + if: always() + run: docker rm -f chronicle-${{ matrix.runtime }} || true diff --git a/Dockerfile.bun b/Dockerfile.bun new file mode 100644 index 00000000..6059f6e6 --- /dev/null +++ b/Dockerfile.bun @@ -0,0 +1,26 @@ +FROM oven/bun:1.3 AS deps +WORKDIR /app +COPY package.json bun.lock ./ +COPY packages/chronicle/package.json ./packages/chronicle/ +RUN bun install --frozen-lockfile + +FROM oven/bun:1.3 AS builder +WORKDIR /app +COPY --from=deps /app /app +COPY packages/chronicle ./packages/chronicle +COPY examples/basic ./examples/basic +RUN cd packages/chronicle && bun build-cli.ts +RUN cd packages/chronicle && chmod +x bin/chronicle.js +RUN ln -s /app/packages/chronicle/bin/chronicle.js /usr/local/bin/chronicle +RUN chronicle build --config examples/basic/chronicle.yaml --preset bun + +FROM oven/bun:1.3-slim AS runner +WORKDIR /app +COPY --from=builder /app/packages/chronicle /app/packages/chronicle +COPY --from=builder /app/examples/basic /app/examples/basic +COPY --from=deps /app/package.json /app/bun.lock /app/ +COPY --from=deps /app/node_modules /app/node_modules + +EXPOSE 3000 + +CMD ["bun", "/app/packages/chronicle/bin/chronicle.js", "start", "--config", "examples/basic/chronicle.yaml", "--port", "3000", "--host", "0.0.0.0"] diff --git a/Dockerfile.node b/Dockerfile.node new file mode 100644 index 00000000..ca5baa5d --- /dev/null +++ b/Dockerfile.node @@ -0,0 +1,26 @@ +FROM oven/bun:1.3 AS deps +WORKDIR /app +COPY package.json bun.lock ./ +COPY packages/chronicle/package.json ./packages/chronicle/ +RUN bun install --frozen-lockfile + +FROM oven/bun:1.3 AS builder +WORKDIR /app +COPY --from=deps /app /app +COPY packages/chronicle ./packages/chronicle +COPY examples/basic ./examples/basic +RUN cd packages/chronicle && bun build-cli.ts +RUN cd packages/chronicle && chmod +x bin/chronicle.js +RUN ln -s /app/packages/chronicle/bin/chronicle.js /usr/local/bin/chronicle +RUN chronicle build --config examples/basic/chronicle.yaml + +FROM node:22-slim AS runner +WORKDIR /app +COPY --from=builder /app/packages/chronicle /app/packages/chronicle +COPY --from=builder /app/examples/basic /app/examples/basic +COPY --from=deps /app/package.json /app/bun.lock /app/ +COPY --from=deps /app/node_modules /app/node_modules + +EXPOSE 3000 + +CMD ["node", "/app/packages/chronicle/bin/chronicle.js", "start", "--config", "examples/basic/chronicle.yaml", "--port", "3000", "--host", "0.0.0.0"] From 49e475de4991c73104cf34827a5313ecfec79757 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 22 May 2026 09:18:10 +0530 Subject: [PATCH 02/15] fix: move Dockerfiles to docker/ directory Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/ci.yml | 4 ++-- Dockerfile.bun => docker/Dockerfile.bun | 0 Dockerfile.node => docker/Dockerfile.node | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename Dockerfile.bun => docker/Dockerfile.bun (100%) rename Dockerfile.node => docker/Dockerfile.node (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0b1a7762..86e2da71 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,9 +40,9 @@ jobs: matrix: include: - runtime: bun - dockerfile: Dockerfile.bun + dockerfile: docker/Dockerfile.bun - runtime: node - dockerfile: Dockerfile.node + dockerfile: docker/Dockerfile.node steps: - name: Checkout uses: actions/checkout@v4 diff --git a/Dockerfile.bun b/docker/Dockerfile.bun similarity index 100% rename from Dockerfile.bun rename to docker/Dockerfile.bun diff --git a/Dockerfile.node b/docker/Dockerfile.node similarity index 100% rename from Dockerfile.node rename to docker/Dockerfile.node From 59a558afe6656a2e6245c78479c5e37d481bf15c Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 22 May 2026 09:21:05 +0530 Subject: [PATCH 03/15] fix: use node:24-slim and fix curl flags for redirect check Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/ci.yml | 6 +++--- docker/Dockerfile.node | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86e2da71..f5f792da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,9 +68,9 @@ jobs: - name: Verify pages run: | - curl -sf -o /dev/null -w "%{http_code}" http://localhost:3000/ | grep -q "307" - curl -sf http://localhost:3000/docs | grep -q 'id="root"' - curl -sf http://localhost:3000/api/search | grep -q '"url"' + curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/ | grep -q "307" + curl -sL http://localhost:3000/docs | grep -q 'id="root"' + curl -s http://localhost:3000/api/search | grep -q '"url"' - name: Cleanup if: always() diff --git a/docker/Dockerfile.node b/docker/Dockerfile.node index ca5baa5d..8a349e11 100644 --- a/docker/Dockerfile.node +++ b/docker/Dockerfile.node @@ -14,7 +14,7 @@ RUN cd packages/chronicle && chmod +x bin/chronicle.js RUN ln -s /app/packages/chronicle/bin/chronicle.js /usr/local/bin/chronicle RUN chronicle build --config examples/basic/chronicle.yaml -FROM node:22-slim AS runner +FROM node:24-slim AS runner WORKDIR /app COPY --from=builder /app/packages/chronicle /app/packages/chronicle COPY --from=builder /app/examples/basic /app/examples/basic From 88574b9a67cc7d8e685d1ae2fac69d57cac0d830 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 22 May 2026 09:27:41 +0530 Subject: [PATCH 04/15] fix: exclude test files from Nitro server bundle Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/chronicle/src/server/vite-config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/chronicle/src/server/vite-config.ts b/packages/chronicle/src/server/vite-config.ts index 7d96a6eb..88e2346b 100644 --- a/packages/chronicle/src/server/vite-config.ts +++ b/packages/chronicle/src/server/vite-config.ts @@ -73,6 +73,7 @@ export async function createViteConfig( nitro({ serverDir: path.resolve(packageRoot, 'src/server'), ...(preset && { preset }), + ignore: ['**/*.test.ts', '**/*.test.tsx', '**/*.spec.ts', '**/*.spec.tsx'], }), mdx({ default: defineFumadocsConfig({ From 7537bba0f372420b491991f1d09154a4de5edc0b Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 22 May 2026 09:28:18 +0530 Subject: [PATCH 05/15] fix: split verify steps for better CI debug output Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/ci.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f5f792da..971e803b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,11 +66,17 @@ jobs: docker logs chronicle-${{ matrix.runtime }} exit 1 - - name: Verify pages + - name: Verify redirect run: | - curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/ | grep -q "307" - curl -sL http://localhost:3000/docs | grep -q 'id="root"' - curl -s http://localhost:3000/api/search | grep -q '"url"' + STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/) + echo "Root status: $STATUS" + [ "$STATUS" = "307" ] + + - name: Verify docs page + run: curl -sL http://localhost:3000/docs | grep -q 'id="root"' + + - name: Verify search API + run: curl -s http://localhost:3000/api/search | grep -q '"url"' - name: Cleanup if: always() From 5218ec2ac4c8674474c3e2a14e2383febd1cb679 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 22 May 2026 09:32:24 +0530 Subject: [PATCH 06/15] fix: update CI checks to test index, page API, and search API Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/ci.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 971e803b..8e172526 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,14 +66,17 @@ jobs: docker logs chronicle-${{ matrix.runtime }} exit 1 - - name: Verify redirect + - name: Verify index run: | STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/) - echo "Root status: $STATUS" - [ "$STATUS" = "307" ] + echo "Index status: $STATUS" + [ "$STATUS" = "200" ] || [ "$STATUS" = "307" ] - - name: Verify docs page - run: curl -sL http://localhost:3000/docs | grep -q 'id="root"' + - name: Verify page API + run: | + STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:3000/api/page?slug=docs,getting-started") + echo "Page API status: $STATUS" + [ "$STATUS" = "200" ] - name: Verify search API run: curl -s http://localhost:3000/api/search | grep -q '"url"' From 34fce8b3b7717c547ddf6f7154eca03d3f387af5 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 22 May 2026 09:36:10 +0530 Subject: [PATCH 07/15] ci: add image optimization API test Add test PNG to basic example and verify /api/image endpoint in CI. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/ci.yml | 6 ++++++ examples/basic/content/docs/test-image.png | Bin 0 -> 69 bytes 2 files changed, 6 insertions(+) create mode 100644 examples/basic/content/docs/test-image.png diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e172526..119622b6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,6 +81,12 @@ jobs: - name: Verify search API run: curl -s http://localhost:3000/api/search | grep -q '"url"' + - name: Verify image API + run: | + STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:3000/api/image?url=/_content/docs/test-image.png&w=320") + echo "Image API status: $STATUS" + [ "$STATUS" = "200" ] + - name: Cleanup if: always() run: docker rm -f chronicle-${{ matrix.runtime }} || true diff --git a/examples/basic/content/docs/test-image.png b/examples/basic/content/docs/test-image.png new file mode 100644 index 0000000000000000000000000000000000000000..62a5f8f47fec02344e5bf9061888262f677cf5d6 GIT binary patch literal 69 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1SBVv2j2ryJf1F&Ar*6yf1E$Sz`)GN$Z+!C Rr1wB^22WQ%mvv4FO#seq5RCu; literal 0 HcmV?d00001 From 0eaed0cd5ee3beea5e7fee828039b67b010ff6ff Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 22 May 2026 09:38:11 +0530 Subject: [PATCH 08/15] ci: replace curl checks with node smoke test script 8 assertions: index, page API, search API, search query, image resize, image 400, image invalid width, image 404. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/ci.yml | 25 ++++--------- docker/smoke-test.mjs | 76 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 19 deletions(-) create mode 100644 docker/smoke-test.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 119622b6..0df8ddd0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,26 +66,13 @@ jobs: docker logs chronicle-${{ matrix.runtime }} exit 1 - - name: Verify index - run: | - STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/) - echo "Index status: $STATUS" - [ "$STATUS" = "200" ] || [ "$STATUS" = "307" ] - - - name: Verify page API - run: | - STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:3000/api/page?slug=docs,getting-started") - echo "Page API status: $STATUS" - [ "$STATUS" = "200" ] - - - name: Verify search API - run: curl -s http://localhost:3000/api/search | grep -q '"url"' + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 24 - - name: Verify image API - run: | - STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:3000/api/image?url=/_content/docs/test-image.png&w=320") - echo "Image API status: $STATUS" - [ "$STATUS" = "200" ] + - name: Smoke tests + run: node docker/smoke-test.mjs - name: Cleanup if: always() diff --git a/docker/smoke-test.mjs b/docker/smoke-test.mjs new file mode 100644 index 00000000..fd4af60d --- /dev/null +++ b/docker/smoke-test.mjs @@ -0,0 +1,76 @@ +import assert from 'node:assert/strict'; + +const BASE = process.env.BASE_URL || 'http://localhost:3000'; +let failed = 0; + +console.log(`Smoke tests against ${BASE}\n`); + +// index returns 200 or 307 +{ + const res = await fetch(`${BASE}/`); + assert.ok(res.status === 200 || res.status === 307, `index: expected 200 or 307, got ${res.status}`); + console.log(' ✓ index returns 200 or 307'); +} + +// page API returns frontmatter +{ + const res = await fetch(`${BASE}/api/page?slug=docs,getting-started`); + assert.equal(res.status, 200, `page API: expected 200, got ${res.status}`); + const data = await res.json(); + assert.ok(data.frontmatter, 'page API: missing frontmatter'); + assert.ok(data.frontmatter.title, 'page API: missing title'); + console.log(' ✓ page API returns frontmatter'); +} + +// search API returns results +{ + const res = await fetch(`${BASE}/api/search`); + assert.equal(res.status, 200, `search API: expected 200, got ${res.status}`); + const data = await res.json(); + assert.ok(Array.isArray(data), 'search API: expected array'); + assert.ok(data.length > 0, 'search API: expected results'); + assert.ok(data[0].url, 'search API: missing url'); + console.log(' ✓ search API returns results'); +} + +// search with query returns matches +{ + const res = await fetch(`${BASE}/api/search?query=getting`); + assert.equal(res.status, 200, `search query: expected 200, got ${res.status}`); + const data = await res.json(); + assert.ok(data.length > 0, 'search query: expected results'); + assert.ok(data[0].match, 'search query: missing match field'); + console.log(' ✓ search with query returns matches'); +} + +// image API resizes PNG +{ + const res = await fetch(`${BASE}/api/image?url=${encodeURIComponent('/_content/docs/test-image.png')}&w=320`); + assert.equal(res.status, 200, `image API: expected 200, got ${res.status}`); + const ct = res.headers.get('content-type'); + assert.ok(ct.startsWith('image/'), `image API: expected image content-type, got ${ct}`); + console.log(' ✓ image API resizes PNG'); +} + +// image API returns 400 for missing params +{ + const res = await fetch(`${BASE}/api/image`); + assert.equal(res.status, 400, `image 400: expected 400, got ${res.status}`); + console.log(' ✓ image API returns 400 for missing params'); +} + +// image API returns 400 for invalid width +{ + const res = await fetch(`${BASE}/api/image?url=${encodeURIComponent('/_content/docs/test-image.png')}&w=999`); + assert.equal(res.status, 400, `image invalid width: expected 400, got ${res.status}`); + console.log(' ✓ image API returns 400 for invalid width'); +} + +// image API returns 404 for missing image +{ + const res = await fetch(`${BASE}/api/image?url=${encodeURIComponent('/_content/does-not-exist.png')}&w=640`); + assert.equal(res.status, 404, `image 404: expected 404, got ${res.status}`); + console.log(' ✓ image API returns 404 for missing image'); +} + +console.log('\nALL PASSED'); From f1f2f1a062bfe2b70d312be7bf38d615cf759a5f Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 22 May 2026 09:38:39 +0530 Subject: [PATCH 09/15] fix: rename docker/ to docker-tests/ Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/ci.yml | 6 +++--- {docker => docker-tests}/Dockerfile.bun | 0 {docker => docker-tests}/Dockerfile.node | 0 {docker => docker-tests}/smoke-test.mjs | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename {docker => docker-tests}/Dockerfile.bun (100%) rename {docker => docker-tests}/Dockerfile.node (100%) rename {docker => docker-tests}/smoke-test.mjs (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0df8ddd0..633031f5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,9 +40,9 @@ jobs: matrix: include: - runtime: bun - dockerfile: docker/Dockerfile.bun + dockerfile: docker-tests/Dockerfile.bun - runtime: node - dockerfile: docker/Dockerfile.node + dockerfile: docker-tests/Dockerfile.node steps: - name: Checkout uses: actions/checkout@v4 @@ -72,7 +72,7 @@ jobs: node-version: 24 - name: Smoke tests - run: node docker/smoke-test.mjs + run: node docker-tests/smoke-test.mjs - name: Cleanup if: always() diff --git a/docker/Dockerfile.bun b/docker-tests/Dockerfile.bun similarity index 100% rename from docker/Dockerfile.bun rename to docker-tests/Dockerfile.bun diff --git a/docker/Dockerfile.node b/docker-tests/Dockerfile.node similarity index 100% rename from docker/Dockerfile.node rename to docker-tests/Dockerfile.node diff --git a/docker/smoke-test.mjs b/docker-tests/smoke-test.mjs similarity index 100% rename from docker/smoke-test.mjs rename to docker-tests/smoke-test.mjs From dd199c01b32a477f54bd642884e17fa78671a638 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 22 May 2026 09:39:08 +0530 Subject: [PATCH 10/15] ci: run Docker smoke tests only on pull requests Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 633031f5..4f06d221 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,6 +33,7 @@ jobs: run: bun test docker: + if: github.event_name == 'pull_request' name: Docker (${{ matrix.runtime }}) runs-on: ubuntu-latest timeout-minutes: 15 From 9bee5906f3514cc1d5a83afebf8602465bfd764a Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 22 May 2026 09:40:20 +0530 Subject: [PATCH 11/15] ci: move Docker smoke tests to separate pr.yaml workflow Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/ci.yml | 47 ------------------------------------ .github/workflows/pr.yaml | 51 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 47 deletions(-) create mode 100644 .github/workflows/pr.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4f06d221..7cc9e45a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,50 +31,3 @@ jobs: - name: Test run: bun test - - docker: - if: github.event_name == 'pull_request' - name: Docker (${{ matrix.runtime }}) - runs-on: ubuntu-latest - timeout-minutes: 15 - strategy: - matrix: - include: - - runtime: bun - dockerfile: docker-tests/Dockerfile.bun - - runtime: node - dockerfile: docker-tests/Dockerfile.node - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Build image - run: docker build -f ${{ matrix.dockerfile }} -t chronicle-${{ matrix.runtime }} . - - - name: Run container - run: docker run -d --name chronicle-${{ matrix.runtime }} -p 3000:3000 chronicle-${{ matrix.runtime }} - - - name: Wait for server - run: | - for i in $(seq 1 30); do - if curl -sf http://localhost:3000/api/health > /dev/null 2>&1; then - echo "Server ready" - exit 0 - fi - sleep 2 - done - echo "Server failed to start" - docker logs chronicle-${{ matrix.runtime }} - exit 1 - - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 24 - - - name: Smoke tests - run: node docker-tests/smoke-test.mjs - - - name: Cleanup - if: always() - run: docker rm -f chronicle-${{ matrix.runtime }} || true diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml new file mode 100644 index 00000000..426f1f76 --- /dev/null +++ b/.github/workflows/pr.yaml @@ -0,0 +1,51 @@ +name: pr + +on: + pull_request: + +jobs: + docker: + name: Docker (${{ matrix.runtime }}) + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + matrix: + include: + - runtime: bun + dockerfile: docker-tests/Dockerfile.bun + - runtime: node + dockerfile: docker-tests/Dockerfile.node + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Build image + run: docker build -f ${{ matrix.dockerfile }} -t chronicle-${{ matrix.runtime }} . + + - name: Run container + run: docker run -d --name chronicle-${{ matrix.runtime }} -p 3000:3000 chronicle-${{ matrix.runtime }} + + - name: Wait for server + run: | + for i in $(seq 1 30); do + if curl -sf http://localhost:3000/api/health > /dev/null 2>&1; then + echo "Server ready" + exit 0 + fi + sleep 2 + done + echo "Server failed to start" + docker logs chronicle-${{ matrix.runtime }} + exit 1 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 24 + + - name: Smoke tests + run: node docker-tests/smoke-test.mjs + + - name: Cleanup + if: always() + run: docker rm -f chronicle-${{ matrix.runtime }} || true From 7480a857e5dd2438c4c0d894feb77524d9d6e8b4 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 22 May 2026 09:40:48 +0530 Subject: [PATCH 12/15] ci: rename pr.yaml to docker-smoke-test.yaml Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/{pr.yaml => docker-smoke-test.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{pr.yaml => docker-smoke-test.yaml} (100%) diff --git a/.github/workflows/pr.yaml b/.github/workflows/docker-smoke-test.yaml similarity index 100% rename from .github/workflows/pr.yaml rename to .github/workflows/docker-smoke-test.yaml From abfa0c6e433d2b09e816fb0e2c3717c006dc5483 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 22 May 2026 09:54:52 +0530 Subject: [PATCH 13/15] fix: use npm/bun init + local install instead of global MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pack CLI as tarball, init project in runner, install locally. Tested on both Node and Bun — all 8 smoke tests pass. Co-Authored-By: Claude Opus 4.6 (1M context) --- docker-tests/Dockerfile.bun | 22 ++++++++-------------- docker-tests/Dockerfile.node | 22 ++++++++-------------- 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/docker-tests/Dockerfile.bun b/docker-tests/Dockerfile.bun index 6059f6e6..a419a2d0 100644 --- a/docker-tests/Dockerfile.bun +++ b/docker-tests/Dockerfile.bun @@ -1,26 +1,20 @@ -FROM oven/bun:1.3 AS deps +FROM oven/bun:1.3 AS builder WORKDIR /app COPY package.json bun.lock ./ COPY packages/chronicle/package.json ./packages/chronicle/ RUN bun install --frozen-lockfile - -FROM oven/bun:1.3 AS builder -WORKDIR /app -COPY --from=deps /app /app COPY packages/chronicle ./packages/chronicle -COPY examples/basic ./examples/basic RUN cd packages/chronicle && bun build-cli.ts -RUN cd packages/chronicle && chmod +x bin/chronicle.js -RUN ln -s /app/packages/chronicle/bin/chronicle.js /usr/local/bin/chronicle -RUN chronicle build --config examples/basic/chronicle.yaml --preset bun +RUN cd packages/chronicle && bun pm pack --destination /app FROM oven/bun:1.3-slim AS runner WORKDIR /app -COPY --from=builder /app/packages/chronicle /app/packages/chronicle -COPY --from=builder /app/examples/basic /app/examples/basic -COPY --from=deps /app/package.json /app/bun.lock /app/ -COPY --from=deps /app/node_modules /app/node_modules +RUN bun init -y +COPY --from=builder /app/raystack-chronicle-*.tgz ./chronicle.tgz +RUN bun add ./chronicle.tgz && rm chronicle.tgz +COPY examples/basic ./examples/basic +RUN bunx chronicle build --config examples/basic/chronicle.yaml --preset bun EXPOSE 3000 -CMD ["bun", "/app/packages/chronicle/bin/chronicle.js", "start", "--config", "examples/basic/chronicle.yaml", "--port", "3000", "--host", "0.0.0.0"] +CMD ["bunx", "chronicle", "start", "--config", "examples/basic/chronicle.yaml", "--port", "3000", "--host", "0.0.0.0"] diff --git a/docker-tests/Dockerfile.node b/docker-tests/Dockerfile.node index 8a349e11..ed2d776f 100644 --- a/docker-tests/Dockerfile.node +++ b/docker-tests/Dockerfile.node @@ -1,26 +1,20 @@ -FROM oven/bun:1.3 AS deps +FROM oven/bun:1.3 AS builder WORKDIR /app COPY package.json bun.lock ./ COPY packages/chronicle/package.json ./packages/chronicle/ RUN bun install --frozen-lockfile - -FROM oven/bun:1.3 AS builder -WORKDIR /app -COPY --from=deps /app /app COPY packages/chronicle ./packages/chronicle -COPY examples/basic ./examples/basic RUN cd packages/chronicle && bun build-cli.ts -RUN cd packages/chronicle && chmod +x bin/chronicle.js -RUN ln -s /app/packages/chronicle/bin/chronicle.js /usr/local/bin/chronicle -RUN chronicle build --config examples/basic/chronicle.yaml +RUN cd packages/chronicle && bun pm pack --destination /app FROM node:24-slim AS runner WORKDIR /app -COPY --from=builder /app/packages/chronicle /app/packages/chronicle -COPY --from=builder /app/examples/basic /app/examples/basic -COPY --from=deps /app/package.json /app/bun.lock /app/ -COPY --from=deps /app/node_modules /app/node_modules +RUN npm init -y +COPY --from=builder /app/raystack-chronicle-*.tgz ./chronicle.tgz +RUN npm install ./chronicle.tgz && rm chronicle.tgz +COPY examples/basic ./examples/basic +RUN npx chronicle build --config examples/basic/chronicle.yaml EXPOSE 3000 -CMD ["node", "/app/packages/chronicle/bin/chronicle.js", "start", "--config", "examples/basic/chronicle.yaml", "--port", "3000", "--host", "0.0.0.0"] +CMD ["npx", "chronicle", "start", "--config", "examples/basic/chronicle.yaml", "--port", "3000", "--host", "0.0.0.0"] From 56a0eb68d3cf4c6ce0545f5fdba81f3a1931567d Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 22 May 2026 09:57:47 +0530 Subject: [PATCH 14/15] fix: rename workflow name to docker-smoke-test Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/docker-smoke-test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-smoke-test.yaml b/.github/workflows/docker-smoke-test.yaml index 426f1f76..763487d9 100644 --- a/.github/workflows/docker-smoke-test.yaml +++ b/.github/workflows/docker-smoke-test.yaml @@ -1,4 +1,4 @@ -name: pr +name: docker-smoke-test on: pull_request: From 5550704ecce262652b50a496a9550e583f0dccdb Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 22 May 2026 10:12:46 +0530 Subject: [PATCH 15/15] fix: use /api/ready instead of /api/health for server readiness Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/docker-smoke-test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-smoke-test.yaml b/.github/workflows/docker-smoke-test.yaml index 763487d9..4b2c9dbd 100644 --- a/.github/workflows/docker-smoke-test.yaml +++ b/.github/workflows/docker-smoke-test.yaml @@ -28,7 +28,7 @@ jobs: - name: Wait for server run: | for i in $(seq 1 30); do - if curl -sf http://localhost:3000/api/health > /dev/null 2>&1; then + if curl -sf http://localhost:3000/api/ready > /dev/null 2>&1; then echo "Server ready" exit 0 fi