Fix qmd: multi-pattern checkouts index 0 files due to comma-joined patterns#22673
Fix qmd: multi-pattern checkouts index 0 files due to comma-joined patterns#22673
Conversation
…ions, add per-pattern logging and compile-time validation Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> Agent-Logs-Url: https://github.com/github/gh-aw/sessions/2f5695a3-96e0-429b-85e7-39402fdf3157
There was a problem hiding this comment.
Pull request overview
Fixes qmd indexing producing 0 indexed files when multiple glob patterns were provided for a single checkout by avoiding comma-joined patterns and adding earlier validation/logging.
Changes:
- Update qmd indexing action to register one qmd collection per glob pattern (instead of comma-joining patterns).
- Add best-effort per-pattern match counting and improve “0 files indexed” diagnostics.
- Add compile-time warnings for empty/comma-containing qmd
pathsand expand unit test coverage for multi-pattern checkouts.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
pkg/workflow/qmd.go |
Adds compile-time validation/warnings for common qmd glob pattern mistakes. |
actions/setup/js/qmd_index.cjs |
Splits multi-pattern checkouts into multiple collections and logs per-pattern match counts. |
actions/setup/js/qmd_index.test.cjs |
Adds tests covering multi-pattern naming behavior and dotfile pattern handling; makes an assertion less brittle. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const files = globSync(pattern, { cwd: basePath }); | ||
| return Array.isArray(files) ? files.length : null; |
There was a problem hiding this comment.
countGlobMatches() logs "file(s) matched" but the current globSync() call will also return directory matches for patterns like docs/**, so the count can be misleading. Consider calling globSync(pattern, { cwd: basePath, withFileTypes: true }) and counting only entries where dirent.isFile() (or otherwise filtering out directories) so the logged number reflects files.
| const files = globSync(pattern, { cwd: basePath }); | |
| return Array.isArray(files) ? files.length : null; | |
| const entries = globSync(pattern, { cwd: basePath, withFileTypes: true }); | |
| if (!Array.isArray(entries)) return null; | |
| const fileCount = entries.filter((entry) => | |
| entry && typeof entry.isFile === "function" ? entry.isFile() : true | |
| ).length; | |
| return fileCount; |
| @@ -139,22 +163,36 @@ async function main() { | |||
| const rawPath = checkout.path; | |||
| const resolvedPath = resolveEnvVars(rawPath); | |||
| const patterns = checkout.patterns || ["**/*.md"]; | |||
There was a problem hiding this comment.
const patterns = checkout.patterns || ["**/*.md"]; will not apply the default when checkout.patterns is an empty array (which is truthy). That results in zero collections being registered for that checkout. Consider defaulting when the array is missing or empty (e.g., Array.isArray(checkout.patterns) && checkout.patterns.length > 0 ? checkout.patterns : ["**/*.md"]).
| const patterns = checkout.patterns || ["**/*.md"]; | |
| const patterns = | |
| Array.isArray(checkout.patterns) && checkout.patterns.length > 0 | |
| ? checkout.patterns | |
| : ["**/*.md"]; |
| // For single-pattern checkouts keep the original name; for multi-pattern checkouts | ||
| // append "-0", "-1", … to ensure collection names are unique in the qmd store. | ||
| const colName = patterns.length === 1 ? checkout.name : `${checkout.name}-${pi}`; | ||
|
|
||
| let hitInfo = ""; | ||
| if (pathExists) { | ||
| const count = countGlobMatches(resolvedPath, pattern); | ||
| hitInfo = count !== null ? ` (${count} file(s) matched)` : ""; | ||
| } | ||
| core.info(` -> collection "${colName}": pattern="${pattern}"${hitInfo}`); | ||
|
|
||
| collections[colName] = { | ||
| path: resolvedPath, | ||
| pattern, | ||
| ...(checkout.context ? { context: { "/": checkout.context } } : {}), | ||
| }; | ||
| } |
There was a problem hiding this comment.
When deriving colName for multi-pattern checkouts, the code can silently overwrite an existing entry in collections if another checkout already uses the same name (e.g. a separate checkout named repo-0 collides with repo pattern index 0). Consider detecting collisions before assignment and either failing fast with a clear error or generating a guaranteed-unique name (e.g. include the checkout index in the suffix).
The qmd indexing job produced 0 indexed files when a checkout declared multiple
pathspatterns. The patterns were joined with commas into a single string (e.g."docs/**,.github/agents/**,.github/aw/**") and passed as onepatternto the SDK — which treats it as a literal glob and matches nothing.Changes
actions/setup/js/qmd_index.cjsrepo-0,repo-1, …).countGlobMatches()uses Node.js 22+fs.globSyncto count matched files per pattern before handing off to the SDK, logged as-> collection "gh-aw-0": pattern="docs/**" (142 file(s) matched). Errors are surfaced viacore.debug().pkg/workflow/qmd.govalidateQmdPatterns()warns atgh aw compiletime for empty patterns and patterns containing commas (common mistake), catching the mistake before the workflow ever runs. Only validates user-provided paths.actions/setup/js/qmd_index.test.cjs.github/agents/**)stringContaining(inconsistent with all other tests in the file)Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
https://api.github.com/graphql/usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw GO111MODULE 64/bin/go git rev-�� --show-toplevel erignore /usr/bin/git -json GO111MODULE 64/bin/go git(http block)/usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw GO111MODULE de git rev-�� --show-toplevel go /usr/bin/git -json GO111MODULE 64/bin/go git(http block)https://api.github.com/repos/actions/ai-inference/git/ref/tags/v1/usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE /usr/lib/php/sessionclean GOINSECURE GOMOD GOMODCACHE /usr/lib/php/sessionclean(http block)/usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha --write **/*.cjs /opt/hostedtoolcache/uv/0.11.0/x86_64/sh **/*.json --ignore-path ../../../.pretti--show-toplevel sh -c "prettier" --write '../../../**/*.json' '!../../../pkg/workflow/js/**/*.json' --ignore-path ../.git go /home/REDACTED/node_modules/.bin/node -json GO111MODULE 64/bin/go node(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v3/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha -json GO111MODULE ache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE ache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha *.json' '!../../../pkg/workflow/js/**/*.json' --ignore-path ../../../.prettierignore GO111MODULE 0/x64/lib/node_modules/npm/node_modules/@npmcli/run-script/lib/node-gyp-bin/node GOINSECURE GOMOD GOMODCACHE go tion�� ting Go code..." GO111MODULE k/_temp/uv-python-dir/node GOINSECURE GOMOD GOMODCACHE sh(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v5/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE erignore m/_n�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha -json GO111MODULE /usr/bin/git GOINSECURE GOMOD GOMODCACHE git rev-�� --show-toplevel GOPROXY /usr/bin/git GOSUMDB GOWORK 64/bin/go git(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel node /usr/bin/git prettier --check 64/bin/go git rev-�� --show-toplevel go 86_64/node -e -f 64/bin/go git(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v6/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha -json GO111MODULE(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel go /usr/bin/git -json GO111MODULE 64/bin/go git rev-�� --show-toplevel sh /usr/bin/git "prettier" --chegit GOPROXY 64/bin/go git(http block)https://api.github.com/repos/actions/github-script/git/ref/tags/v8/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha --show-toplevel go /usr/bin/git -json GO111MODULE 64/bin/go git rev-�� --show-toplevel sh /usr/bin/git "prettier" --chegit GOPROXY 64/bin/go git(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha a9bb7eb1db202a6e3840330d313f16d009573a63:actions/setup/js/qmd_index.cjs sh /home/REDACTED/node_modules/.bin/sh ./../.prettieriggit git 64/bin/go sh -c "prettier" --write '**/*.cjs' '**/*.ts' '**/*.json' --ignore-path ../../../.prettierignore node /opt/hostedtoolcache/node/24.14.0/x64/lib/node_modules/npm/node_modules/@npmcli/run-script/lib/n--show-toplevel --write ../../../**/*.jsrev-parse run-script/lib/n--show-toplevel sh(http block)https://api.github.com/repos/actions/setup-go/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha a9bb7eb1db202a6e3840330d313f16d009573a63:pkg/workflow/qmd.go node js ./../.prettieriggit scripts/**/*.js 64/bin/go sh -c "prettier" --write '**/*.cjs' '**/*.ts' '**/*.json' --ignore-path ../../../.pret.prettierignore node /usr/local/bin/sh --write ../../../**/*.jsrev-parse 64/bin/go sh(http block)https://api.github.com/repos/actions/setup-node/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go clean; fi GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha a9bb7eb1db202a6e3840330d313f16d009573a63:pkg/workflow/qmd.go js /home/REDACTED/work/_temp/uv-python-dir/sh ./../.prettieriggit scripts/**/*.js 64/bin/go sh -c "prettier" --write '**/*.cjs' '**/*.ts' '**/*.json' --ignore-patINVALID,NEW node /home/REDACTED/.dotnet/tools/sh --write ../../../**/*.jsrev-parse 64/bin/go sh(http block)https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq .object.sha heck '**/*.cjs' '**/*.ts' '**/*.json' --ignore-path ../../../.pr**/*.json GO111MODULE tions/setup/node_modules/.bin/sh GOINSECURE GOMOD GOMODCACHE go env .go .go 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile(http block)https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.0.0/usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.0.0 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.0.0 --jq .object.sha */*.ts' '**/*.json' --ignore-patACCEPT GO111MODULE k/gh-aw/node_modules/.bin/node GOINSECURE GOMOD GOMODCACHE go m/_n�� */*.json' '!../../../pkg/workflow/js/**/*.json' --ignore-path GO111MODULE ache/go/1.25.0/x64/bin/git GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.2.3/usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.2.3 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.2.3 --jq .object.sha */*.ts' '**/*.json' --ignore-patACCEPT GO111MODULE 0/x64/bin/sh GOINSECURE GOMOD GOMODCACHE go m/_n�� */*.json' '!../../../pkg/workflow/js/**/*.json' --ignore-path GO111MODULE ndor/bin/bash GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.0.0/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD GOMODCACHE go env heck '**/*.cjs' GOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go /pre�� on' --ignore-path ../../../.pret.prettierignore GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/nonexistent/action/git/ref/tags/v999.999.999/usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD GOMODCACHE go env heck '**/*.cjs' GOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go /pre�� on' --ignore-path ../../../.pret.prettierignore GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)If you need me to access, download, or install something from one of these locations, you can either:
🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.