diff --git a/.github/actions/npm-setup/action.yml b/.github/actions/npm-setup/action.yml index df34da377..df787100c 100644 --- a/.github/actions/npm-setup/action.yml +++ b/.github/actions/npm-setup/action.yml @@ -9,8 +9,9 @@ inputs: description: "Node.js version to use" required: true workspace: - description: "Workspace to install" - required: true + description: "Workspace to install. Leave empty to install every workspace" + required: false + default: "" outputs: workspace_path: @@ -24,7 +25,10 @@ runs: shell: bash id: set-workspace run: | - if [ "${{ inputs.workspace }}" = "testcontainers" ]; then + if [ -z "${{ inputs.workspace }}" ]; then + workspace_path="" + cache_paths=$'node_modules\npackages/testcontainers/node_modules\npackages/modules/*/node_modules' + elif [ "${{ inputs.workspace }}" = "testcontainers" ]; then workspace_path="packages/testcontainers" cache_paths=$'node_modules\npackages/testcontainers/node_modules' else @@ -51,12 +55,17 @@ runs: id: npm-cache with: path: ${{ steps.set-workspace.outputs.cache_paths }} - key: npm-v2-${{ inputs.runner }}-node-${{ inputs.node-version }}-${{ inputs.workspace }}-${{ hashFiles('package-lock.json') }} + key: npm-v2-${{ inputs.runner }}-node-${{ inputs.node-version }}-${{ inputs.workspace || 'all-workspaces' }}-${{ hashFiles('package-lock.json') }} - name: Install dependencies if: steps.npm-cache.outputs.cache-hit != 'true' shell: bash - run: npm ci --workspace "${WORKSPACE_PATH}" --include-workspace-root + run: | + if [ -n "${WORKSPACE_PATH}" ]; then + npm ci --workspace "${WORKSPACE_PATH}" --include-workspace-root + else + npm ci + fi - name: Save dependencies cache if: steps.npm-cache.outputs.cache-hit != 'true' diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index cf2ba23b3..b9fc5877a 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -80,6 +80,22 @@ jobs: WORKSPACE_PATH: ${{ steps.npm-install-modules.outputs.workspace_path }} run: npm run lint:ci + knip: + # Knip analyses every workspace together and reads the manifests of their installed dependencies, so it runs + # once with every workspace installed instead of per module. + name: Knip + runs-on: ubuntu-24.04 + steps: + - name: Code checkout + uses: actions/checkout@v7 + - name: Install Node and Dependencies + uses: ./.github/actions/npm-setup + with: + runner: ubuntu-24.04 + node-version: 24.x + - name: Find unused files, exports and dependencies + run: npm run knip + compile: if: ${{ needs.detect-modules.outputs.modules_count != '0' }} name: Compile @@ -207,6 +223,7 @@ jobs: needs: - detect-modules - lint + - knip - compile - smoke-test - smoke-test-bun diff --git a/AGENTS.md b/AGENTS.md index 043db2c2d..aa70e5d0f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,6 +24,7 @@ It captures practical rules that prevent avoidable CI and PR churn. - If a public API changes, update the relevant docs in the same PR. - If new types are made part of the public API, export them from the package's `index.ts` in the same PR. +- Only what a package's `index.ts` exports is public API. `npm run knip` fails on any other export that no other file uses: drop the `export` keyword, or export it from `index.ts` if consumers need it. - If new learnings or misunderstandings are discovered, propose an `AGENTS.md` update in the same PR. - In docs Markdown, keep `` blocks tight with no blank lines between the markers and the include line, or the rendered snippet will contain blank lines between code lines. - Tests should verify observable behavior changes, not only internal/config state. @@ -86,7 +87,7 @@ reviewers can follow the reasoning. 1. Start from `main`. 2. Create a branch prefixed with `/` (for example `claude/fix-exec-output-truncation`). The PR title must not carry such prefixes (see step 9). 3. Implement scoped changes only. -4. Run required checks: `npm run format`, `npm run lint`, `npm run check-compiles` when touching `packages/testcontainers` APIs consumed by modules, and targeted tests. +4. Run required checks: `npm run format`, `npm run lint`, `npm run knip`, `npm run check-compiles` when touching `packages/testcontainers` APIs consumed by modules, and targeted tests. - When working in a fresh git worktree, dependencies are not installed (`node_modules` is absent), so verification commands (tests, `lint`, `format`, `check-compiles`) will fail with "Cannot find module" errors. Run `npm ci` once before verifying. `npm ci` only populates `node_modules` and must not modify `package-lock.json`; if it does, treat that as drift to investigate. 5. Verify git diff only contains intended files. 6. Never commit, push, or post on GitHub (issues, PRs, or comments) without first sharing the proposed diff/message and getting explicit user approval. diff --git a/knip.jsonc b/knip.jsonc new file mode 100644 index 000000000..4d272cd79 --- /dev/null +++ b/knip.jsonc @@ -0,0 +1,33 @@ +{ + "$schema": "https://unpkg.com/knip@6/schema-jsonc.json", + "workspaces": { + ".": { + // Loaded by a