fix(ci): build the API image from the repository root - #70

Merged
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context
Aug 28, 2026
Merged

fix(ci): build the API image from the repository root#70
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The failure

The ghcr job was the only leg of run 33198050069 to fail on the v0.1.0 release. All three packages reached PyPI, the tag, the GitHub Release and the versioned docs all succeeded; only the image build did not:

"/packages/adapter-sdk": not found
"/packages/api": not found
"/packages/nl2sql": not found
ERROR: failed to build: failed to solve: failed to compute cache key

Cause: the build context does not match the Dockerfile's COPY paths

packages/api/Dockerfile installs the three packages from their local sources and writes its COPY paths relative to the repository root:

COPY ./packages/adapter-sdk /app/packages/adapter-sdk
COPY ./packages/nl2sql /app/packages/nl2sql
COPY ./packages/api /app/packages/api

COPY resolves against the build context, and the workflow set context: packages/api. So buildx looked for packages/api/packages/adapter-sdk, which does not exist — hence "not found" for all three.

The Dockerfile was changed in Task 13 to install from local paths (nothing was on PyPI yet); the workflow's context was never updated to match. The demo stack has had this right all along — packages/nl2sql/src/nl2sql/cli/demo/schemas.py generates context: .. with dockerfile: packages/api/Dockerfile. The workflow was the outlier.

The fix points the context at the repository root and names the Dockerfile explicitly (both are documented inputs of docker/build-push-action@v6):

context: .file: packages/api/Dockerfile

The stale comment above the job — which claimed the Dockerfile installs from PyPI — is corrected. needs: pypi is kept deliberately, but for a different reason than before: the image build no longer depends on PyPI, so the dependency now only ensures the image is published for a release that actually reached PyPI.

The .dockerignore is new, and why

There was no .dockerignore at the repo root or in packages/api. With context: ., the entire working tree is sent to the daemon. On CI the checkout is clean so it would have worked, but it is wasteful there and slow-to-broken on a developer machine, where the tree includes .venv-dev/ (857 MB), chroma_db/ (94 MB), site/, data/, logs/, .git/, __pycache__/ and stale build/, dist/ and *.egg-info directories — 993 MB in total on this checkout.

The ignore list was chosen against what the build actually needs. Only packages/adapter-sdk, packages/nl2sql and packages/api are COPYed, so of the three manifests:

  • packages/nl2sql/pyproject.toml declares readme = "README.md", and packages/nl2sql/README.md must survive — a missing readme fails the wheel build. It is not excluded, and the built image's nl2sql-engine metadata carries Description-Content-Type: text/markdown with the README body, which proves it was picked up.
  • packages/adapter-sdk/pyproject.toml declares no readme and the package has no README.md.
  • packages/api/pyproject.toml declares no readme (it has a README.md, but nothing references it).

Patterns are matched against the path relative to the context root, so repo-level directories are named directly and anything that also appears inside a package (build, dist, *.egg-info, __pycache__, .pytest_cache) is prefixed with **/. data/ is excluded safely — the demo stack bind-mounts it at run time, it is never copied at build time.

Local build evidence

CI cannot verify this: no workflow builds the image on a PR. The verification is a local build from a clean context.

docker build -f packages/api/Dockerfile -t nl2sql-api:test .
  • Result: succeeds (BUILD_EXIT=0). Same command failed with the "not found" error before, using the old context.
  • Context transferred:890.43 kB (plus a 1.06 kB .dockerignore), down from a 993 MB working tree.
  • Final image size: 1.67 GB.
  • Installed from local sources, not PyPI — the build log shows Processing ./packages/adapter-sdk, Processing ./packages/nl2sql, Processing ./packages/api, then Building wheel for nl2sql-adapter-sdk / nl2sql-engine / nl2sql-api (pyproject.toml). There is no Downloading nl2sql... line anywhere.
$ docker run --rm nl2sql-api:test python -c "import nl2sql, nl2sql_api; print('ok')"
ok
$ docker run --rm nl2sql-api:test pip show nl2sql-engine | head -3
Name: nl2sql-engine
Version: 0.1.0
Summary: Natural-language-to-SQL engine, CLI and database adapters

nl2sql-api and nl2sql-adapter-sdk are also 0.1.0. The [postgres,mysql] extras resolved (import psycopg2, pymysql succeeds) and nl2sql --help runs. Starting the container reaches uvicorn and application startup, then stops at datasource configuration, which is expected — the image needs configs/ and live databases mounted at run time, exactly as the demo stack provides.

Nothing was pushed, dispatched, re-run or tagged.

Docs

  • docs/development/releasing.md — the ghcr step described the Dockerfile as installing from PyPI. Corrected, with the context requirement and the reason needs: pypi stays.
  • docs/getting_started/docker.md — already told readers to build from the repo root; it now says why, and describes the new .dockerignore.
  • docs/deployment/docker.md needed no change: it covers deploying the service, not building the image.

mkdocs build --strict is clean, from a throwaway venv built from requirements-docs.txt.

Baselines

Unchanged: unit 231 passed, 1 skipped, 47 deselected; key-free integration 28 passed.

Out of scope, reported not fixed

packages/api/Dockerfile.dev is genuinely broken and is not touched here. Ten of its twenty COPY lines reference paths deleted in the Task 10 packaging collapse — packages/core, packages/adapter-sqlalchemy and packages/adapters/{mssql,mysql,postgres,sqlite} — and a build fails the same way this bug did:

ERROR: failed to solve: failed to compute cache key: ... "/packages/adapters/sqlite/src": not found

Nothing references it: no workflow, no compose file, no doc, and no code path. It should be deleted, but that is a separate decision and a separate PR.

@nadeem4
nadeem4 merged commit 495c1c3 into mainAug 28, 2026
8 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@nadeem4
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(ci): build the API image from the repository root - #70

Merged
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context
Aug 28, 2026
Merged

fix(ci): build the API image from the repository root#70
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The failure

The ghcr job was the only leg of run 33198050069 to fail on the v0.1.0 release. All three packages reached PyPI, the tag, the GitHub Release and the versioned docs all succeeded; only the image build did not:

"/packages/adapter-sdk": not found
"/packages/api": not found
"/packages/nl2sql": not found
ERROR: failed to build: failed to solve: failed to compute cache key

Cause: the build context does not match the Dockerfile's COPY paths

packages/api/Dockerfile installs the three packages from their local sources and writes its COPY paths relative to the repository root:

COPY ./packages/adapter-sdk /app/packages/adapter-sdk
COPY ./packages/nl2sql /app/packages/nl2sql
COPY ./packages/api /app/packages/api

COPY resolves against the build context, and the workflow set context: packages/api. So buildx looked for packages/api/packages/adapter-sdk, which does not exist — hence "not found" for all three.

The Dockerfile was changed in Task 13 to install from local paths (nothing was on PyPI yet); the workflow's context was never updated to match. The demo stack has had this right all along — packages/nl2sql/src/nl2sql/cli/demo/schemas.py generates context: .. with dockerfile: packages/api/Dockerfile. The workflow was the outlier.

The fix points the context at the repository root and names the Dockerfile explicitly (both are documented inputs of docker/build-push-action@v6):

context: .file: packages/api/Dockerfile

The stale comment above the job — which claimed the Dockerfile installs from PyPI — is corrected. needs: pypi is kept deliberately, but for a different reason than before: the image build no longer depends on PyPI, so the dependency now only ensures the image is published for a release that actually reached PyPI.

The .dockerignore is new, and why

There was no .dockerignore at the repo root or in packages/api. With context: ., the entire working tree is sent to the daemon. On CI the checkout is clean so it would have worked, but it is wasteful there and slow-to-broken on a developer machine, where the tree includes .venv-dev/ (857 MB), chroma_db/ (94 MB), site/, data/, logs/, .git/, __pycache__/ and stale build/, dist/ and *.egg-info directories — 993 MB in total on this checkout.

The ignore list was chosen against what the build actually needs. Only packages/adapter-sdk, packages/nl2sql and packages/api are COPYed, so of the three manifests:

  • packages/nl2sql/pyproject.toml declares readme = "README.md", and packages/nl2sql/README.md must survive — a missing readme fails the wheel build. It is not excluded, and the built image's nl2sql-engine metadata carries Description-Content-Type: text/markdown with the README body, which proves it was picked up.
  • packages/adapter-sdk/pyproject.toml declares no readme and the package has no README.md.
  • packages/api/pyproject.toml declares no readme (it has a README.md, but nothing references it).

Patterns are matched against the path relative to the context root, so repo-level directories are named directly and anything that also appears inside a package (build, dist, *.egg-info, __pycache__, .pytest_cache) is prefixed with **/. data/ is excluded safely — the demo stack bind-mounts it at run time, it is never copied at build time.

Local build evidence

CI cannot verify this: no workflow builds the image on a PR. The verification is a local build from a clean context.

docker build -f packages/api/Dockerfile -t nl2sql-api:test .
  • Result: succeeds (BUILD_EXIT=0). Same command failed with the "not found" error before, using the old context.
  • Context transferred:890.43 kB (plus a 1.06 kB .dockerignore), down from a 993 MB working tree.
  • Final image size: 1.67 GB.
  • Installed from local sources, not PyPI — the build log shows Processing ./packages/adapter-sdk, Processing ./packages/nl2sql, Processing ./packages/api, then Building wheel for nl2sql-adapter-sdk / nl2sql-engine / nl2sql-api (pyproject.toml). There is no Downloading nl2sql... line anywhere.
$ docker run --rm nl2sql-api:test python -c "import nl2sql, nl2sql_api; print('ok')"
ok
$ docker run --rm nl2sql-api:test pip show nl2sql-engine | head -3
Name: nl2sql-engine
Version: 0.1.0
Summary: Natural-language-to-SQL engine, CLI and database adapters

nl2sql-api and nl2sql-adapter-sdk are also 0.1.0. The [postgres,mysql] extras resolved (import psycopg2, pymysql succeeds) and nl2sql --help runs. Starting the container reaches uvicorn and application startup, then stops at datasource configuration, which is expected — the image needs configs/ and live databases mounted at run time, exactly as the demo stack provides.

Nothing was pushed, dispatched, re-run or tagged.

Docs

  • docs/development/releasing.md — the ghcr step described the Dockerfile as installing from PyPI. Corrected, with the context requirement and the reason needs: pypi stays.
  • docs/getting_started/docker.md — already told readers to build from the repo root; it now says why, and describes the new .dockerignore.
  • docs/deployment/docker.md needed no change: it covers deploying the service, not building the image.

mkdocs build --strict is clean, from a throwaway venv built from requirements-docs.txt.

Baselines

Unchanged: unit 231 passed, 1 skipped, 47 deselected; key-free integration 28 passed.

Out of scope, reported not fixed

packages/api/Dockerfile.dev is genuinely broken and is not touched here. Ten of its twenty COPY lines reference paths deleted in the Task 10 packaging collapse — packages/core, packages/adapter-sqlalchemy and packages/adapters/{mssql,mysql,postgres,sqlite} — and a build fails the same way this bug did:

ERROR: failed to solve: failed to compute cache key: ... "/packages/adapters/sqlite/src": not found

Nothing references it: no workflow, no compose file, no doc, and no code path. It should be deleted, but that is a separate decision and a separate PR.

@nadeem4
nadeem4 merged commit 495c1c3 into mainAug 28, 2026
8 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@nadeem4
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ci): build the API image from the repository root - #70

Merged
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context
Aug 28, 2026
Merged

fix(ci): build the API image from the repository root#70
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The failure

The ghcr job was the only leg of run 33198050069 to fail on the v0.1.0 release. All three packages reached PyPI, the tag, the GitHub Release and the versioned docs all succeeded; only the image build did not:

"/packages/adapter-sdk": not found
"/packages/api": not found
"/packages/nl2sql": not found
ERROR: failed to build: failed to solve: failed to compute cache key

Cause: the build context does not match the Dockerfile's COPY paths

packages/api/Dockerfile installs the three packages from their local sources and writes its COPY paths relative to the repository root:

COPY ./packages/adapter-sdk /app/packages/adapter-sdk
COPY ./packages/nl2sql /app/packages/nl2sql
COPY ./packages/api /app/packages/api

COPY resolves against the build context, and the workflow set context: packages/api. So buildx looked for packages/api/packages/adapter-sdk, which does not exist — hence "not found" for all three.

The Dockerfile was changed in Task 13 to install from local paths (nothing was on PyPI yet); the workflow's context was never updated to match. The demo stack has had this right all along — packages/nl2sql/src/nl2sql/cli/demo/schemas.py generates context: .. with dockerfile: packages/api/Dockerfile. The workflow was the outlier.

The fix points the context at the repository root and names the Dockerfile explicitly (both are documented inputs of docker/build-push-action@v6):

context: .file: packages/api/Dockerfile

The stale comment above the job — which claimed the Dockerfile installs from PyPI — is corrected. needs: pypi is kept deliberately, but for a different reason than before: the image build no longer depends on PyPI, so the dependency now only ensures the image is published for a release that actually reached PyPI.

The .dockerignore is new, and why

There was no .dockerignore at the repo root or in packages/api. With context: ., the entire working tree is sent to the daemon. On CI the checkout is clean so it would have worked, but it is wasteful there and slow-to-broken on a developer machine, where the tree includes .venv-dev/ (857 MB), chroma_db/ (94 MB), site/, data/, logs/, .git/, __pycache__/ and stale build/, dist/ and *.egg-info directories — 993 MB in total on this checkout.

The ignore list was chosen against what the build actually needs. Only packages/adapter-sdk, packages/nl2sql and packages/api are COPYed, so of the three manifests:

  • packages/nl2sql/pyproject.toml declares readme = "README.md", and packages/nl2sql/README.md must survive — a missing readme fails the wheel build. It is not excluded, and the built image's nl2sql-engine metadata carries Description-Content-Type: text/markdown with the README body, which proves it was picked up.
  • packages/adapter-sdk/pyproject.toml declares no readme and the package has no README.md.
  • packages/api/pyproject.toml declares no readme (it has a README.md, but nothing references it).

Patterns are matched against the path relative to the context root, so repo-level directories are named directly and anything that also appears inside a package (build, dist, *.egg-info, __pycache__, .pytest_cache) is prefixed with **/. data/ is excluded safely — the demo stack bind-mounts it at run time, it is never copied at build time.

Local build evidence

CI cannot verify this: no workflow builds the image on a PR. The verification is a local build from a clean context.

docker build -f packages/api/Dockerfile -t nl2sql-api:test .
  • Result: succeeds (BUILD_EXIT=0). Same command failed with the "not found" error before, using the old context.
  • Context transferred:890.43 kB (plus a 1.06 kB .dockerignore), down from a 993 MB working tree.
  • Final image size: 1.67 GB.
  • Installed from local sources, not PyPI — the build log shows Processing ./packages/adapter-sdk, Processing ./packages/nl2sql, Processing ./packages/api, then Building wheel for nl2sql-adapter-sdk / nl2sql-engine / nl2sql-api (pyproject.toml). There is no Downloading nl2sql... line anywhere.
$ docker run --rm nl2sql-api:test python -c "import nl2sql, nl2sql_api; print('ok')"
ok
$ docker run --rm nl2sql-api:test pip show nl2sql-engine | head -3
Name: nl2sql-engine
Version: 0.1.0
Summary: Natural-language-to-SQL engine, CLI and database adapters

nl2sql-api and nl2sql-adapter-sdk are also 0.1.0. The [postgres,mysql] extras resolved (import psycopg2, pymysql succeeds) and nl2sql --help runs. Starting the container reaches uvicorn and application startup, then stops at datasource configuration, which is expected — the image needs configs/ and live databases mounted at run time, exactly as the demo stack provides.

Nothing was pushed, dispatched, re-run or tagged.

Docs

  • docs/development/releasing.md — the ghcr step described the Dockerfile as installing from PyPI. Corrected, with the context requirement and the reason needs: pypi stays.
  • docs/getting_started/docker.md — already told readers to build from the repo root; it now says why, and describes the new .dockerignore.
  • docs/deployment/docker.md needed no change: it covers deploying the service, not building the image.

mkdocs build --strict is clean, from a throwaway venv built from requirements-docs.txt.

Baselines

Unchanged: unit 231 passed, 1 skipped, 47 deselected; key-free integration 28 passed.

Out of scope, reported not fixed

packages/api/Dockerfile.dev is genuinely broken and is not touched here. Ten of its twenty COPY lines reference paths deleted in the Task 10 packaging collapse — packages/core, packages/adapter-sqlalchemy and packages/adapters/{mssql,mysql,postgres,sqlite} — and a build fails the same way this bug did:

ERROR: failed to solve: failed to compute cache key: ... "/packages/adapters/sqlite/src": not found

Nothing references it: no workflow, no compose file, no doc, and no code path. It should be deleted, but that is a separate decision and a separate PR.

@nadeem4
nadeem4 merged commit 495c1c3 into mainAug 28, 2026
8 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@nadeem4
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ci): build the API image from the repository root - #70

Merged
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context
Aug 28, 2026
Merged

fix(ci): build the API image from the repository root#70
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The failure

The ghcr job was the only leg of run 33198050069 to fail on the v0.1.0 release. All three packages reached PyPI, the tag, the GitHub Release and the versioned docs all succeeded; only the image build did not:

"/packages/adapter-sdk": not found
"/packages/api": not found
"/packages/nl2sql": not found
ERROR: failed to build: failed to solve: failed to compute cache key

Cause: the build context does not match the Dockerfile's COPY paths

packages/api/Dockerfile installs the three packages from their local sources and writes its COPY paths relative to the repository root:

COPY ./packages/adapter-sdk /app/packages/adapter-sdk
COPY ./packages/nl2sql /app/packages/nl2sql
COPY ./packages/api /app/packages/api

COPY resolves against the build context, and the workflow set context: packages/api. So buildx looked for packages/api/packages/adapter-sdk, which does not exist — hence "not found" for all three.

The Dockerfile was changed in Task 13 to install from local paths (nothing was on PyPI yet); the workflow's context was never updated to match. The demo stack has had this right all along — packages/nl2sql/src/nl2sql/cli/demo/schemas.py generates context: .. with dockerfile: packages/api/Dockerfile. The workflow was the outlier.

The fix points the context at the repository root and names the Dockerfile explicitly (both are documented inputs of docker/build-push-action@v6):

context: .file: packages/api/Dockerfile

The stale comment above the job — which claimed the Dockerfile installs from PyPI — is corrected. needs: pypi is kept deliberately, but for a different reason than before: the image build no longer depends on PyPI, so the dependency now only ensures the image is published for a release that actually reached PyPI.

The .dockerignore is new, and why

There was no .dockerignore at the repo root or in packages/api. With context: ., the entire working tree is sent to the daemon. On CI the checkout is clean so it would have worked, but it is wasteful there and slow-to-broken on a developer machine, where the tree includes .venv-dev/ (857 MB), chroma_db/ (94 MB), site/, data/, logs/, .git/, __pycache__/ and stale build/, dist/ and *.egg-info directories — 993 MB in total on this checkout.

The ignore list was chosen against what the build actually needs. Only packages/adapter-sdk, packages/nl2sql and packages/api are COPYed, so of the three manifests:

  • packages/nl2sql/pyproject.toml declares readme = "README.md", and packages/nl2sql/README.md must survive — a missing readme fails the wheel build. It is not excluded, and the built image's nl2sql-engine metadata carries Description-Content-Type: text/markdown with the README body, which proves it was picked up.
  • packages/adapter-sdk/pyproject.toml declares no readme and the package has no README.md.
  • packages/api/pyproject.toml declares no readme (it has a README.md, but nothing references it).

Patterns are matched against the path relative to the context root, so repo-level directories are named directly and anything that also appears inside a package (build, dist, *.egg-info, __pycache__, .pytest_cache) is prefixed with **/. data/ is excluded safely — the demo stack bind-mounts it at run time, it is never copied at build time.

Local build evidence

CI cannot verify this: no workflow builds the image on a PR. The verification is a local build from a clean context.

docker build -f packages/api/Dockerfile -t nl2sql-api:test .
  • Result: succeeds (BUILD_EXIT=0). Same command failed with the "not found" error before, using the old context.
  • Context transferred:890.43 kB (plus a 1.06 kB .dockerignore), down from a 993 MB working tree.
  • Final image size: 1.67 GB.
  • Installed from local sources, not PyPI — the build log shows Processing ./packages/adapter-sdk, Processing ./packages/nl2sql, Processing ./packages/api, then Building wheel for nl2sql-adapter-sdk / nl2sql-engine / nl2sql-api (pyproject.toml). There is no Downloading nl2sql... line anywhere.
$ docker run --rm nl2sql-api:test python -c "import nl2sql, nl2sql_api; print('ok')"
ok
$ docker run --rm nl2sql-api:test pip show nl2sql-engine | head -3
Name: nl2sql-engine
Version: 0.1.0
Summary: Natural-language-to-SQL engine, CLI and database adapters

nl2sql-api and nl2sql-adapter-sdk are also 0.1.0. The [postgres,mysql] extras resolved (import psycopg2, pymysql succeeds) and nl2sql --help runs. Starting the container reaches uvicorn and application startup, then stops at datasource configuration, which is expected — the image needs configs/ and live databases mounted at run time, exactly as the demo stack provides.

Nothing was pushed, dispatched, re-run or tagged.

Docs

  • docs/development/releasing.md — the ghcr step described the Dockerfile as installing from PyPI. Corrected, with the context requirement and the reason needs: pypi stays.
  • docs/getting_started/docker.md — already told readers to build from the repo root; it now says why, and describes the new .dockerignore.
  • docs/deployment/docker.md needed no change: it covers deploying the service, not building the image.

mkdocs build --strict is clean, from a throwaway venv built from requirements-docs.txt.

Baselines

Unchanged: unit 231 passed, 1 skipped, 47 deselected; key-free integration 28 passed.

Out of scope, reported not fixed

packages/api/Dockerfile.dev is genuinely broken and is not touched here. Ten of its twenty COPY lines reference paths deleted in the Task 10 packaging collapse — packages/core, packages/adapter-sqlalchemy and packages/adapters/{mssql,mysql,postgres,sqlite} — and a build fails the same way this bug did:

ERROR: failed to solve: failed to compute cache key: ... "/packages/adapters/sqlite/src": not found

Nothing references it: no workflow, no compose file, no doc, and no code path. It should be deleted, but that is a separate decision and a separate PR.

@nadeem4
nadeem4 merged commit 495c1c3 into mainAug 28, 2026
8 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@nadeem4
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(ci): build the API image from the repository root - #70

Merged
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context
Aug 28, 2026
Merged

fix(ci): build the API image from the repository root#70
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The failure

The ghcr job was the only leg of run 33198050069 to fail on the v0.1.0 release. All three packages reached PyPI, the tag, the GitHub Release and the versioned docs all succeeded; only the image build did not:

"/packages/adapter-sdk": not found
"/packages/api": not found
"/packages/nl2sql": not found
ERROR: failed to build: failed to solve: failed to compute cache key

Cause: the build context does not match the Dockerfile's COPY paths

packages/api/Dockerfile installs the three packages from their local sources and writes its COPY paths relative to the repository root:

COPY ./packages/adapter-sdk /app/packages/adapter-sdk
COPY ./packages/nl2sql /app/packages/nl2sql
COPY ./packages/api /app/packages/api

COPY resolves against the build context, and the workflow set context: packages/api. So buildx looked for packages/api/packages/adapter-sdk, which does not exist — hence "not found" for all three.

The Dockerfile was changed in Task 13 to install from local paths (nothing was on PyPI yet); the workflow's context was never updated to match. The demo stack has had this right all along — packages/nl2sql/src/nl2sql/cli/demo/schemas.py generates context: .. with dockerfile: packages/api/Dockerfile. The workflow was the outlier.

The fix points the context at the repository root and names the Dockerfile explicitly (both are documented inputs of docker/build-push-action@v6):

context: .file: packages/api/Dockerfile

The stale comment above the job — which claimed the Dockerfile installs from PyPI — is corrected. needs: pypi is kept deliberately, but for a different reason than before: the image build no longer depends on PyPI, so the dependency now only ensures the image is published for a release that actually reached PyPI.

The .dockerignore is new, and why

There was no .dockerignore at the repo root or in packages/api. With context: ., the entire working tree is sent to the daemon. On CI the checkout is clean so it would have worked, but it is wasteful there and slow-to-broken on a developer machine, where the tree includes .venv-dev/ (857 MB), chroma_db/ (94 MB), site/, data/, logs/, .git/, __pycache__/ and stale build/, dist/ and *.egg-info directories — 993 MB in total on this checkout.

The ignore list was chosen against what the build actually needs. Only packages/adapter-sdk, packages/nl2sql and packages/api are COPYed, so of the three manifests:

  • packages/nl2sql/pyproject.toml declares readme = "README.md", and packages/nl2sql/README.md must survive — a missing readme fails the wheel build. It is not excluded, and the built image's nl2sql-engine metadata carries Description-Content-Type: text/markdown with the README body, which proves it was picked up.
  • packages/adapter-sdk/pyproject.toml declares no readme and the package has no README.md.
  • packages/api/pyproject.toml declares no readme (it has a README.md, but nothing references it).

Patterns are matched against the path relative to the context root, so repo-level directories are named directly and anything that also appears inside a package (build, dist, *.egg-info, __pycache__, .pytest_cache) is prefixed with **/. data/ is excluded safely — the demo stack bind-mounts it at run time, it is never copied at build time.

Local build evidence

CI cannot verify this: no workflow builds the image on a PR. The verification is a local build from a clean context.

docker build -f packages/api/Dockerfile -t nl2sql-api:test .
  • Result: succeeds (BUILD_EXIT=0). Same command failed with the "not found" error before, using the old context.
  • Context transferred:890.43 kB (plus a 1.06 kB .dockerignore), down from a 993 MB working tree.
  • Final image size: 1.67 GB.
  • Installed from local sources, not PyPI — the build log shows Processing ./packages/adapter-sdk, Processing ./packages/nl2sql, Processing ./packages/api, then Building wheel for nl2sql-adapter-sdk / nl2sql-engine / nl2sql-api (pyproject.toml). There is no Downloading nl2sql... line anywhere.
$ docker run --rm nl2sql-api:test python -c "import nl2sql, nl2sql_api; print('ok')"
ok
$ docker run --rm nl2sql-api:test pip show nl2sql-engine | head -3
Name: nl2sql-engine
Version: 0.1.0
Summary: Natural-language-to-SQL engine, CLI and database adapters

nl2sql-api and nl2sql-adapter-sdk are also 0.1.0. The [postgres,mysql] extras resolved (import psycopg2, pymysql succeeds) and nl2sql --help runs. Starting the container reaches uvicorn and application startup, then stops at datasource configuration, which is expected — the image needs configs/ and live databases mounted at run time, exactly as the demo stack provides.

Nothing was pushed, dispatched, re-run or tagged.

Docs

  • docs/development/releasing.md — the ghcr step described the Dockerfile as installing from PyPI. Corrected, with the context requirement and the reason needs: pypi stays.
  • docs/getting_started/docker.md — already told readers to build from the repo root; it now says why, and describes the new .dockerignore.
  • docs/deployment/docker.md needed no change: it covers deploying the service, not building the image.

mkdocs build --strict is clean, from a throwaway venv built from requirements-docs.txt.

Baselines

Unchanged: unit 231 passed, 1 skipped, 47 deselected; key-free integration 28 passed.

Out of scope, reported not fixed

packages/api/Dockerfile.dev is genuinely broken and is not touched here. Ten of its twenty COPY lines reference paths deleted in the Task 10 packaging collapse — packages/core, packages/adapter-sqlalchemy and packages/adapters/{mssql,mysql,postgres,sqlite} — and a build fails the same way this bug did:

ERROR: failed to solve: failed to compute cache key: ... "/packages/adapters/sqlite/src": not found

Nothing references it: no workflow, no compose file, no doc, and no code path. It should be deleted, but that is a separate decision and a separate PR.

@nadeem4
nadeem4 merged commit 495c1c3 into mainAug 28, 2026
8 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@nadeem4
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ci): build the API image from the repository root - #70

Merged
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context
Aug 28, 2026
Merged

fix(ci): build the API image from the repository root#70
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The failure

The ghcr job was the only leg of run 33198050069 to fail on the v0.1.0 release. All three packages reached PyPI, the tag, the GitHub Release and the versioned docs all succeeded; only the image build did not:

"/packages/adapter-sdk": not found
"/packages/api": not found
"/packages/nl2sql": not found
ERROR: failed to build: failed to solve: failed to compute cache key

Cause: the build context does not match the Dockerfile's COPY paths

packages/api/Dockerfile installs the three packages from their local sources and writes its COPY paths relative to the repository root:

COPY ./packages/adapter-sdk /app/packages/adapter-sdk
COPY ./packages/nl2sql /app/packages/nl2sql
COPY ./packages/api /app/packages/api

COPY resolves against the build context, and the workflow set context: packages/api. So buildx looked for packages/api/packages/adapter-sdk, which does not exist — hence "not found" for all three.

The Dockerfile was changed in Task 13 to install from local paths (nothing was on PyPI yet); the workflow's context was never updated to match. The demo stack has had this right all along — packages/nl2sql/src/nl2sql/cli/demo/schemas.py generates context: .. with dockerfile: packages/api/Dockerfile. The workflow was the outlier.

The fix points the context at the repository root and names the Dockerfile explicitly (both are documented inputs of docker/build-push-action@v6):

context: .file: packages/api/Dockerfile

The stale comment above the job — which claimed the Dockerfile installs from PyPI — is corrected. needs: pypi is kept deliberately, but for a different reason than before: the image build no longer depends on PyPI, so the dependency now only ensures the image is published for a release that actually reached PyPI.

The .dockerignore is new, and why

There was no .dockerignore at the repo root or in packages/api. With context: ., the entire working tree is sent to the daemon. On CI the checkout is clean so it would have worked, but it is wasteful there and slow-to-broken on a developer machine, where the tree includes .venv-dev/ (857 MB), chroma_db/ (94 MB), site/, data/, logs/, .git/, __pycache__/ and stale build/, dist/ and *.egg-info directories — 993 MB in total on this checkout.

The ignore list was chosen against what the build actually needs. Only packages/adapter-sdk, packages/nl2sql and packages/api are COPYed, so of the three manifests:

  • packages/nl2sql/pyproject.toml declares readme = "README.md", and packages/nl2sql/README.md must survive — a missing readme fails the wheel build. It is not excluded, and the built image's nl2sql-engine metadata carries Description-Content-Type: text/markdown with the README body, which proves it was picked up.
  • packages/adapter-sdk/pyproject.toml declares no readme and the package has no README.md.
  • packages/api/pyproject.toml declares no readme (it has a README.md, but nothing references it).

Patterns are matched against the path relative to the context root, so repo-level directories are named directly and anything that also appears inside a package (build, dist, *.egg-info, __pycache__, .pytest_cache) is prefixed with **/. data/ is excluded safely — the demo stack bind-mounts it at run time, it is never copied at build time.

Local build evidence

CI cannot verify this: no workflow builds the image on a PR. The verification is a local build from a clean context.

docker build -f packages/api/Dockerfile -t nl2sql-api:test .
  • Result: succeeds (BUILD_EXIT=0). Same command failed with the "not found" error before, using the old context.
  • Context transferred:890.43 kB (plus a 1.06 kB .dockerignore), down from a 993 MB working tree.
  • Final image size: 1.67 GB.
  • Installed from local sources, not PyPI — the build log shows Processing ./packages/adapter-sdk, Processing ./packages/nl2sql, Processing ./packages/api, then Building wheel for nl2sql-adapter-sdk / nl2sql-engine / nl2sql-api (pyproject.toml). There is no Downloading nl2sql... line anywhere.
$ docker run --rm nl2sql-api:test python -c "import nl2sql, nl2sql_api; print('ok')"
ok
$ docker run --rm nl2sql-api:test pip show nl2sql-engine | head -3
Name: nl2sql-engine
Version: 0.1.0
Summary: Natural-language-to-SQL engine, CLI and database adapters

nl2sql-api and nl2sql-adapter-sdk are also 0.1.0. The [postgres,mysql] extras resolved (import psycopg2, pymysql succeeds) and nl2sql --help runs. Starting the container reaches uvicorn and application startup, then stops at datasource configuration, which is expected — the image needs configs/ and live databases mounted at run time, exactly as the demo stack provides.

Nothing was pushed, dispatched, re-run or tagged.

Docs

  • docs/development/releasing.md — the ghcr step described the Dockerfile as installing from PyPI. Corrected, with the context requirement and the reason needs: pypi stays.
  • docs/getting_started/docker.md — already told readers to build from the repo root; it now says why, and describes the new .dockerignore.
  • docs/deployment/docker.md needed no change: it covers deploying the service, not building the image.

mkdocs build --strict is clean, from a throwaway venv built from requirements-docs.txt.

Baselines

Unchanged: unit 231 passed, 1 skipped, 47 deselected; key-free integration 28 passed.

Out of scope, reported not fixed

packages/api/Dockerfile.dev is genuinely broken and is not touched here. Ten of its twenty COPY lines reference paths deleted in the Task 10 packaging collapse — packages/core, packages/adapter-sqlalchemy and packages/adapters/{mssql,mysql,postgres,sqlite} — and a build fails the same way this bug did:

ERROR: failed to solve: failed to compute cache key: ... "/packages/adapters/sqlite/src": not found

Nothing references it: no workflow, no compose file, no doc, and no code path. It should be deleted, but that is a separate decision and a separate PR.

@nadeem4
nadeem4 merged commit 495c1c3 into mainAug 28, 2026
8 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@nadeem4
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(ci): build the API image from the repository root - #70

Merged
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context
Aug 28, 2026
Merged

fix(ci): build the API image from the repository root#70
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The failure

The ghcr job was the only leg of run 33198050069 to fail on the v0.1.0 release. All three packages reached PyPI, the tag, the GitHub Release and the versioned docs all succeeded; only the image build did not:

"/packages/adapter-sdk": not found
"/packages/api": not found
"/packages/nl2sql": not found
ERROR: failed to build: failed to solve: failed to compute cache key

Cause: the build context does not match the Dockerfile's COPY paths

packages/api/Dockerfile installs the three packages from their local sources and writes its COPY paths relative to the repository root:

COPY ./packages/adapter-sdk /app/packages/adapter-sdk
COPY ./packages/nl2sql /app/packages/nl2sql
COPY ./packages/api /app/packages/api

COPY resolves against the build context, and the workflow set context: packages/api. So buildx looked for packages/api/packages/adapter-sdk, which does not exist — hence "not found" for all three.

The Dockerfile was changed in Task 13 to install from local paths (nothing was on PyPI yet); the workflow's context was never updated to match. The demo stack has had this right all along — packages/nl2sql/src/nl2sql/cli/demo/schemas.py generates context: .. with dockerfile: packages/api/Dockerfile. The workflow was the outlier.

The fix points the context at the repository root and names the Dockerfile explicitly (both are documented inputs of docker/build-push-action@v6):

context: .file: packages/api/Dockerfile

The stale comment above the job — which claimed the Dockerfile installs from PyPI — is corrected. needs: pypi is kept deliberately, but for a different reason than before: the image build no longer depends on PyPI, so the dependency now only ensures the image is published for a release that actually reached PyPI.

The .dockerignore is new, and why

There was no .dockerignore at the repo root or in packages/api. With context: ., the entire working tree is sent to the daemon. On CI the checkout is clean so it would have worked, but it is wasteful there and slow-to-broken on a developer machine, where the tree includes .venv-dev/ (857 MB), chroma_db/ (94 MB), site/, data/, logs/, .git/, __pycache__/ and stale build/, dist/ and *.egg-info directories — 993 MB in total on this checkout.

The ignore list was chosen against what the build actually needs. Only packages/adapter-sdk, packages/nl2sql and packages/api are COPYed, so of the three manifests:

  • packages/nl2sql/pyproject.toml declares readme = "README.md", and packages/nl2sql/README.md must survive — a missing readme fails the wheel build. It is not excluded, and the built image's nl2sql-engine metadata carries Description-Content-Type: text/markdown with the README body, which proves it was picked up.
  • packages/adapter-sdk/pyproject.toml declares no readme and the package has no README.md.
  • packages/api/pyproject.toml declares no readme (it has a README.md, but nothing references it).

Patterns are matched against the path relative to the context root, so repo-level directories are named directly and anything that also appears inside a package (build, dist, *.egg-info, __pycache__, .pytest_cache) is prefixed with **/. data/ is excluded safely — the demo stack bind-mounts it at run time, it is never copied at build time.

Local build evidence

CI cannot verify this: no workflow builds the image on a PR. The verification is a local build from a clean context.

docker build -f packages/api/Dockerfile -t nl2sql-api:test .
  • Result: succeeds (BUILD_EXIT=0). Same command failed with the "not found" error before, using the old context.
  • Context transferred:890.43 kB (plus a 1.06 kB .dockerignore), down from a 993 MB working tree.
  • Final image size: 1.67 GB.
  • Installed from local sources, not PyPI — the build log shows Processing ./packages/adapter-sdk, Processing ./packages/nl2sql, Processing ./packages/api, then Building wheel for nl2sql-adapter-sdk / nl2sql-engine / nl2sql-api (pyproject.toml). There is no Downloading nl2sql... line anywhere.
$ docker run --rm nl2sql-api:test python -c "import nl2sql, nl2sql_api; print('ok')"
ok
$ docker run --rm nl2sql-api:test pip show nl2sql-engine | head -3
Name: nl2sql-engine
Version: 0.1.0
Summary: Natural-language-to-SQL engine, CLI and database adapters

nl2sql-api and nl2sql-adapter-sdk are also 0.1.0. The [postgres,mysql] extras resolved (import psycopg2, pymysql succeeds) and nl2sql --help runs. Starting the container reaches uvicorn and application startup, then stops at datasource configuration, which is expected — the image needs configs/ and live databases mounted at run time, exactly as the demo stack provides.

Nothing was pushed, dispatched, re-run or tagged.

Docs

  • docs/development/releasing.md — the ghcr step described the Dockerfile as installing from PyPI. Corrected, with the context requirement and the reason needs: pypi stays.
  • docs/getting_started/docker.md — already told readers to build from the repo root; it now says why, and describes the new .dockerignore.
  • docs/deployment/docker.md needed no change: it covers deploying the service, not building the image.

mkdocs build --strict is clean, from a throwaway venv built from requirements-docs.txt.

Baselines

Unchanged: unit 231 passed, 1 skipped, 47 deselected; key-free integration 28 passed.

Out of scope, reported not fixed

packages/api/Dockerfile.dev is genuinely broken and is not touched here. Ten of its twenty COPY lines reference paths deleted in the Task 10 packaging collapse — packages/core, packages/adapter-sqlalchemy and packages/adapters/{mssql,mysql,postgres,sqlite} — and a build fails the same way this bug did:

ERROR: failed to solve: failed to compute cache key: ... "/packages/adapters/sqlite/src": not found

Nothing references it: no workflow, no compose file, no doc, and no code path. It should be deleted, but that is a separate decision and a separate PR.

@nadeem4
nadeem4 merged commit 495c1c3 into mainAug 28, 2026
8 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@nadeem4
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(ci): build the API image from the repository root - #70

Merged
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context
Aug 28, 2026
Merged

fix(ci): build the API image from the repository root#70
nadeem4 merged 1 commit into
mainfrom
fix/ghcr-build-context

Conversation

@nadeem4

Copy link
Copy Markdown
Owner

The failure

The ghcr job was the only leg of run 33198050069 to fail on the v0.1.0 release. All three packages reached PyPI, the tag, the GitHub Release and the versioned docs all succeeded; only the image build did not:

"/packages/adapter-sdk": not found
"/packages/api": not found
"/packages/nl2sql": not found
ERROR: failed to build: failed to solve: failed to compute cache key

Cause: the build context does not match the Dockerfile's COPY paths

packages/api/Dockerfile installs the three packages from their local sources and writes its COPY paths relative to the repository root:

COPY ./packages/adapter-sdk /app/packages/adapter-sdk
COPY ./packages/nl2sql /app/packages/nl2sql
COPY ./packages/api /app/packages/api

COPY resolves against the build context, and the workflow set context: packages/api. So buildx looked for packages/api/packages/adapter-sdk, which does not exist — hence "not found" for all three.

The Dockerfile was changed in Task 13 to install from local paths (nothing was on PyPI yet); the workflow's context was never updated to match. The demo stack has had this right all along — packages/nl2sql/src/nl2sql/cli/demo/schemas.py generates context: .. with dockerfile: packages/api/Dockerfile. The workflow was the outlier.

The fix points the context at the repository root and names the Dockerfile explicitly (both are documented inputs of docker/build-push-action@v6):

context: .file: packages/api/Dockerfile

The stale comment above the job — which claimed the Dockerfile installs from PyPI — is corrected. needs: pypi is kept deliberately, but for a different reason than before: the image build no longer depends on PyPI, so the dependency now only ensures the image is published for a release that actually reached PyPI.

The .dockerignore is new, and why

There was no .dockerignore at the repo root or in packages/api. With context: ., the entire working tree is sent to the daemon. On CI the checkout is clean so it would have worked, but it is wasteful there and slow-to-broken on a developer machine, where the tree includes .venv-dev/ (857 MB), chroma_db/ (94 MB), site/, data/, logs/, .git/, __pycache__/ and stale build/, dist/ and *.egg-info directories — 993 MB in total on this checkout.

The ignore list was chosen against what the build actually needs. Only packages/adapter-sdk, packages/nl2sql and packages/api are COPYed, so of the three manifests:

  • packages/nl2sql/pyproject.toml declares readme = "README.md", and packages/nl2sql/README.md must survive — a missing readme fails the wheel build. It is not excluded, and the built image's nl2sql-engine metadata carries Description-Content-Type: text/markdown with the README body, which proves it was picked up.
  • packages/adapter-sdk/pyproject.toml declares no readme and the package has no README.md.
  • packages/api/pyproject.toml declares no readme (it has a README.md, but nothing references it).

Patterns are matched against the path relative to the context root, so repo-level directories are named directly and anything that also appears inside a package (build, dist, *.egg-info, __pycache__, .pytest_cache) is prefixed with **/. data/ is excluded safely — the demo stack bind-mounts it at run time, it is never copied at build time.

Local build evidence

CI cannot verify this: no workflow builds the image on a PR. The verification is a local build from a clean context.

docker build -f packages/api/Dockerfile -t nl2sql-api:test .
  • Result: succeeds (BUILD_EXIT=0). Same command failed with the "not found" error before, using the old context.
  • Context transferred:890.43 kB (plus a 1.06 kB .dockerignore), down from a 993 MB working tree.
  • Final image size: 1.67 GB.
  • Installed from local sources, not PyPI — the build log shows Processing ./packages/adapter-sdk, Processing ./packages/nl2sql, Processing ./packages/api, then Building wheel for nl2sql-adapter-sdk / nl2sql-engine / nl2sql-api (pyproject.toml). There is no Downloading nl2sql... line anywhere.
$ docker run --rm nl2sql-api:test python -c "import nl2sql, nl2sql_api; print('ok')"
ok
$ docker run --rm nl2sql-api:test pip show nl2sql-engine | head -3
Name: nl2sql-engine
Version: 0.1.0
Summary: Natural-language-to-SQL engine, CLI and database adapters

nl2sql-api and nl2sql-adapter-sdk are also 0.1.0. The [postgres,mysql] extras resolved (import psycopg2, pymysql succeeds) and nl2sql --help runs. Starting the container reaches uvicorn and application startup, then stops at datasource configuration, which is expected — the image needs configs/ and live databases mounted at run time, exactly as the demo stack provides.

Nothing was pushed, dispatched, re-run or tagged.

Docs

  • docs/development/releasing.md — the ghcr step described the Dockerfile as installing from PyPI. Corrected, with the context requirement and the reason needs: pypi stays.
  • docs/getting_started/docker.md — already told readers to build from the repo root; it now says why, and describes the new .dockerignore.
  • docs/deployment/docker.md needed no change: it covers deploying the service, not building the image.

mkdocs build --strict is clean, from a throwaway venv built from requirements-docs.txt.

Baselines

Unchanged: unit 231 passed, 1 skipped, 47 deselected; key-free integration 28 passed.

Out of scope, reported not fixed

packages/api/Dockerfile.dev is genuinely broken and is not touched here. Ten of its twenty COPY lines reference paths deleted in the Task 10 packaging collapse — packages/core, packages/adapter-sqlalchemy and packages/adapters/{mssql,mysql,postgres,sqlite} — and a build fails the same way this bug did:

ERROR: failed to solve: failed to compute cache key: ... "/packages/adapters/sqlite/src": not found

Nothing references it: no workflow, no compose file, no doc, and no code path. It should be deleted, but that is a separate decision and a separate PR.

@nadeem4
nadeem4 merged commit 495c1c3 into mainAug 28, 2026
8 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@nadeem4