Skip to content

fix: support wildcard file paths in project includes - #1914

Open
firecow wants to merge 2 commits into
masterfrom
fix/wildcard-project-include-file
Open

fix: support wildcard file paths in project includes#1914
firecow wants to merge 2 commits into
masterfrom
fix/wildcard-project-include-file

Conversation

@firecow

@firecow firecow commented Aug 4, 2026

Copy link
Copy Markdown
Owner

A wildcard in include:project:file expanded to several files, but cp targeted a literal destination path so the fetch failed with is not a directory, and the subsequent load used that same literal path instead of the matches. Fixes #1642.


Summary by cubic

Support wildcard file paths in project includes. Expands globs and copies matched files into the destination directory with deterministic order to avoid “is not a directory” errors.

  • Bug Fixes
    • Expand include:project:file globs with globbySync, sort matches, and load each file.
    • Copy matched files to the destination directory using cp <src> <dir>/; tests for templates/[bt]*.yml verify build and test jobs are included.

Written for commit 4ace621. Summary will update on new commits.

Review in cubic

The glob expanded to several files but cp targeted a literal destination
path, and the later load used that same literal path instead of the
matches.
@firecow firecow self-assigned this Aug 4, 2026
@sonarqubecloud

sonarqubecloud Bot commented Aug 4, 2026

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found and verified against the latest diff

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="tests/test-cases/include-project-file-wildcard/integration.test.ts">

<violation number="1" location="tests/test-cases/include-project-file-wildcard/integration.test.ts:20">
P2: This test (and its .gitlab-ci.yml fixture) depend on a live external GitLab project `components/go` and its `templates/build.yml`/`templates/test.yml` content via a real network fetch, so it will fail when offline or whenever that external project changes. Consider hosting the included project fixtures locally (e.g. a git project-include that resolves to checkout-able content) so the test is hermetic and asserts the wildcard behavior against files the repo controls.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

stateDir: ".gitlab-ci-local-include-project-file-wildcard",
}, writeStreams);

const jobNames = writeStreams.stdoutLines

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This test (and its .gitlab-ci.yml fixture) depend on a live external GitLab project components/go and its templates/build.yml/templates/test.yml content via a real network fetch, so it will fail when offline or whenever that external project changes. Consider hosting the included project fixtures locally (e.g. a git project-include that resolves to checkout-able content) so the test is hermetic and asserts the wildcard behavior against files the repo controls.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/test-cases/include-project-file-wildcard/integration.test.ts, line 20:

<comment>This test (and its .gitlab-ci.yml fixture) depend on a live external GitLab project `components/go` and its `templates/build.yml`/`templates/test.yml` content via a real network fetch, so it will fail when offline or whenever that external project changes. Consider hosting the included project fixtures locally (e.g. a git project-include that resolves to checkout-able content) so the test is hermetic and asserts the wildcard behavior against files the repo controls.</comment>

<file context>
@@ -0,0 +1,26 @@
+        stateDir: ".gitlab-ci-local-include-project-file-wildcard",
+    }, writeStreams);
+
+    const jobNames = writeStreams.stdoutLines
+        .filter(l => /^(build|test)\s/.test(l))
+        .map(l => l.split(/\s+/)[0])
</file context>

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/parser-includes.ts">

<violation number="1" location="src/parser-includes.ts:153">
P3: Switching the match sort to `String#localeCompare` makes the order of included project files depend on the host runtime's locale (via the Intl collator), whereas the previous default `.sort()` was locale-independent and deterministic. Because these matches are concatenated into `includeDatas` and pipeline config can be merged/overridden in that order, a developer machine with a different locale could resolve a slightly different pipeline than CI for the same inputs. If the goal was stable ordering, keep the locale-invariant default `.sort()` (or pass an explicit `{numeric: true, sensitivity: 'base'}` if case-insensitivity is intended); otherwise project includes should order consistently regardless of locale.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/parser-includes.ts
includeDatas = includeDatas.concat(await this.init(fileDoc, opts));
const includeDir = `${cwd}/${stateDir}/includes/${gitData.remote.host}/${value["project"]}/${value["ref"] || "HEAD"}`;
const normalizedFile = fileValue.replace(/^\/+/, "");
const matches = globbySync(normalizedFile, {cwd: includeDir, absolute: true}).sort((a, b) => a.localeCompare(b));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Switching the match sort to String#localeCompare makes the order of included project files depend on the host runtime's locale (via the Intl collator), whereas the previous default .sort() was locale-independent and deterministic. Because these matches are concatenated into includeDatas and pipeline config can be merged/overridden in that order, a developer machine with a different locale could resolve a slightly different pipeline than CI for the same inputs. If the goal was stable ordering, keep the locale-invariant default .sort() (or pass an explicit {numeric: true, sensitivity: 'base'} if case-insensitivity is intended); otherwise project includes should order consistently regardless of locale.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/parser-includes.ts, line 153:

<comment>Switching the match sort to `String#localeCompare` makes the order of included project files depend on the host runtime's locale (via the Intl collator), whereas the previous default `.sort()` was locale-independent and deterministic. Because these matches are concatenated into `includeDatas` and pipeline config can be merged/overridden in that order, a developer machine with a different locale could resolve a slightly different pipeline than CI for the same inputs. If the goal was stable ordering, keep the locale-invariant default `.sort()` (or pass an explicit `{numeric: true, sensitivity: 'base'}` if case-insensitivity is intended); otherwise project includes should order consistently regardless of locale.</comment>

<file context>
@@ -150,7 +150,7 @@ export class ParserIncludes {
                     const includeDir = `${cwd}/${stateDir}/includes/${gitData.remote.host}/${value["project"]}/${value["ref"] || "HEAD"}`;
                     const normalizedFile = fileValue.replace(/^\/+/, "");
-                    const matches = globbySync(normalizedFile, {cwd: includeDir, absolute: true}).sort();
+                    const matches = globbySync(normalizedFile, {cwd: includeDir, absolute: true}).sort((a, b) => a.localeCompare(b));
                     const filePaths = matches.length > 0 ? matches : [`${includeDir}/${normalizedFile}`];
                     for (const filePath of filePaths) {
</file context>
Suggested change
const matches = globbySync(normalizedFile, {cwd: includeDir, absolute: true}).sort((a, b) => a.localeCompare(b));
const matches = globbySync(normalizedFile, {cwd: includeDir, absolute: true}).sort();

Sign up for free to 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.

Project include could not be fetched when remote include is http(s)

1 participant