From 4fb38fb614ccb24b05b845c5bf26921025179f9a Mon Sep 17 00:00:00 2001 From: David de Boer Date: Fri, 24 Jul 2026 15:30:55 +0200 Subject: [PATCH 1/2] ci: trigger the Docker image publish from GitHub Releases, not tag pushes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - A multi-package nx release pushes all its tags in one batch, and GitHub emits no tag-push events at all when more than three tags arrive at once – so the tag trigger silently never fired (observed on the release that tagged 12 packages: zero Docker runs) - Trigger on the GitHub Releases nx release creates instead (one event per package, no batch suppression), with a job guard passing only the image-shipping packages - workflow_dispatch stays as the manual escape hatch - Align ADR 15/16 and the package READMEs with the new trigger --- .github/workflows/docker.yml | 17 +++++++++++++---- ...s-a-docker-image-built-from-the-workspace.md | 9 ++++++--- ...e-search-indexer-as-a-config-driven-image.md | 2 +- packages/search-api-server/README.md | 2 +- packages/search-indexer/README.md | 2 +- 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 6ed9cbbf..74e7a623 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,10 +1,12 @@ name: Docker +# Triggered by the GitHub Releases nx release creates, NOT by tag pushes: a +# multi-package release pushes all its tags in one batch, and GitHub emits no +# tag-push events at all when more than three tags arrive at once – so a tag +# trigger would silently never fire for this monorepo. on: - push: - tags: - - '@lde/search-api-server@*' - - '@lde/search-indexer@*' + release: + types: [published] workflow_dispatch: inputs: ref: @@ -23,6 +25,13 @@ concurrency: jobs: publish-image: + # Every released package fires a release event; only the image-shipping + # packages get past this guard (keep it in sync with the packages that + # have a Dockerfile). + if: >- + github.event_name == 'workflow_dispatch' || + startsWith(github.event.release.tag_name, '@lde/search-api-server@') || + startsWith(github.event.release.tag_name, '@lde/search-indexer@') runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 diff --git a/docs/decisions/0015-ship-the-served-search-api-as-a-docker-image-built-from-the-workspace.md b/docs/decisions/0015-ship-the-served-search-api-as-a-docker-image-built-from-the-workspace.md index 7e4a3cd1..36e3c77b 100644 --- a/docs/decisions/0015-ship-the-served-search-api-as-a-docker-image-built-from-the-workspace.md +++ b/docs/decisions/0015-ship-the-served-search-api-as-a-docker-image-built-from-the-workspace.md @@ -63,9 +63,12 @@ crashed at startup (dataset-register#2128/#2130). We adopt its end state. schema and probed over HTTP (`/health`, `/graphql?sdl`) in `nx affected`, so both build-time and runtime-only failures (the `ERR_MODULE_NOT_FOUND` class) fail the PR, not production. -- **Publishing is tag-triggered but registry-independent**: the release run’s - `@lde/search-api-server@` tag triggers the Docker workflow, which - checks out that commit, rebuilds and smoke-tests the image, and pushes +- **Publishing is release-triggered but registry-independent**: the GitHub + Release nx release creates for `@lde/search-api-server@` triggers + the Docker workflow (a _tag_ trigger can never fire here: a multi-package + release pushes more than three tags at once, and GitHub then emits no + tag-push events), which checks out that commit, rebuilds and smoke-tests + the image, and pushes `ghcr.io/ldelements/search-api-server:` and `:latest`. Image tags stay aligned with the package’s semver; `nx release`’s own Docker support (experimental, calendar-versioned, and unable to both npm- and diff --git a/docs/decisions/0016-ship-the-search-indexer-as-a-config-driven-image.md b/docs/decisions/0016-ship-the-search-indexer-as-a-config-driven-image.md index 88aef1fe..ff001573 100644 --- a/docs/decisions/0016-ship-the-search-indexer-as-a-config-driven-image.md +++ b/docs/decisions/0016-ship-the-search-indexer-as-a-config-driven-image.md @@ -41,7 +41,7 @@ QLever the pipeline controls. `@lde/search-pipeline` without breaking its engine-agnosticism. Published to npm and shipped as `ghcr.io/ldelements/search-indexer`, reusing ADR 15’s entire delivery pattern (workspace-built image, `docker:smoke` CI gate, - release-tag-triggered publish). + release-triggered publish). - **The schema-module loader moves to `@lde/search/module`** and both images use it, implementing the shared-mount symmetry in code: one loader, one validation, one error vocabulary. Consumer-specific optional exports diff --git a/packages/search-api-server/README.md b/packages/search-api-server/README.md index 2bde904f..9fd79365 100644 --- a/packages/search-api-server/README.md +++ b/packages/search-api-server/README.md @@ -119,7 +119,7 @@ npx nx run @lde/search-api-server:docker:build # → packages-search-api-serve npx nx run @lde/search-api-server:docker:smoke # boots it and probes /health + ?sdl ``` -CI runs `docker:smoke` for affected PRs; each release tag rebuilds and pushes +CI runs `docker:smoke` for affected PRs; each release rebuilds and pushes `ghcr.io/ldelements/search-api-server:` (`.github/workflows/docker.yml`). ## Programmatic use diff --git a/packages/search-indexer/README.md b/packages/search-indexer/README.md index 15cdc6d0..b3f39a8f 100644 --- a/packages/search-indexer/README.md +++ b/packages/search-indexer/README.md @@ -114,7 +114,7 @@ npx nx run @lde/search-indexer:docker:build # → packages-search-indexer npx nx run @lde/search-indexer:docker:smoke # boots it with --check ``` -CI runs `docker:smoke` for affected PRs; each release tag rebuilds and pushes +CI runs `docker:smoke` for affected PRs; each release rebuilds and pushes `ghcr.io/ldelements/search-indexer:` (`.github/workflows/docker.yml`). ## Programmatic use From 16aae9e804d54cb3702d477375d57494d765712d Mon Sep 17 00:00:00 2001 From: David de Boer Date: Sat, 25 Jul 2026 07:58:21 +0200 Subject: [PATCH 2/2] docs: correct the first-release version note for the zero-major scheme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 0.0.0 lands at 0.0.1 for plain feat commits; 0.1.0 only when the history carries a breaking-marked commit – the earlier observation conflated the two --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 2633ba19..cf7b3da5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -100,7 +100,7 @@ The `@nx/js:library` generator’s output diverges from the conventions in this - `name` → `@lde/` - `description` – write something useful - `repository.directory` → `packages/` - - `version` → `0.0.0` (do NOT keep the sibling’s version). The first CI release bumps from the manifest over the package’s full history, so `0.0.0` lands it at `0.1.0` (observed with `search-typesense` and `text-normalization`), while a manifest pre-set to `0.1.0` shipped `0.2.0` (`pipeline-shacl-sampler`). This must be in place before the PR merges – see [Releasing a new package](#releasing-a-new-package). + - `version` → `0.0.0` (do NOT keep the sibling’s version). The first CI release bumps from the manifest over the package’s full history under the zero-major scheme (minor = breaking, patch = feature/fix), so `0.0.0` lands at `0.0.1` for plain `feat` commits (`search-api-server`, `search-indexer`) and at `0.1.0` only when the history carries a breaking-marked commit (`search-typesense`, `text-normalization`); a manifest pre-set to `0.1.0` overshoots (`pipeline-shacl-sampler` shipped `0.2.0`). This must be in place before the PR merges – see [Releasing a new package](#releasing-a-new-package). - `dependencies` and `peerDependencies` – replace with what the new package actually needs 4. **Replace the source.** Empty out `src/` and `test/`, write the new code. 5. **Update `tsconfig.lib.json` `references`** to match the new package’s actual `@lde/*` peers.