Skip to content

feat: support per-target / per-feature gitignore destination routing ($gitignoreDestination)#1503

Open
dyoshikawa wants to merge 2 commits intomainfrom
codex/add-gitignore/gitattribute-settings-per-tool
Open

feat: support per-target / per-feature gitignore destination routing ($gitignoreDestination)#1503
dyoshikawa wants to merge 2 commits intomainfrom
codex/add-gitignore/gitattribute-settings-per-tool

Conversation

@dyoshikawa
Copy link
Copy Markdown
Owner

Motivation

Description

  • Add a reserved key "$gitignoreDestination" for object-form targets and support two values: "gitignore" (default) and "gitattributes", exposed as TARGET_GITIGNORE_DESTINATION_KEY and typed via GitignoreDestination in src/types/features.ts.
  • Implement Config#getGitignoreDestination(target, feature?) and parsing logic so tool-level and tool×feature-level values are resolved with feature-level winning when present (changes in src/config/config.ts).
  • Enhance gitignore entry resolution to return richer entries (entry + target(s) + feature) via resolveGitignoreEntries and update filterGitignoreEntries to use it (changes in src/cli/commands/gitignore-entries.ts).
  • Update the gitignore command to group resolved entries by destination and write Rulesync blocks into both .gitignore and .gitattributes as appropriate, preserving previous cleanup / up-to-date behavior and JSON capture (changes in src/cli/commands/gitignore.ts).
  • Add/adjust unit tests covering config precedence and destination behavior and update documentation and synced skill docs explaining $gitignoreDestination usage and precedence (tests in src/config/config.test.ts and src/cli/commands/gitignore.test.ts; docs in docs/guide/configuration.md, docs/reference/cli-commands.md, and synced skills/rulesync/*).

Testing

  • Ran the focused tests pnpm -s vitest run src/config/config.test.ts src/cli/commands/gitignore.test.ts src/cli/commands/gitignore-entries.test.ts and they passed locally.
  • Ran full code checks: pnpm run cicheck:code (format/lint/typecheck/tests) which passed after formatting adjustments, and the full test suite completed (vitest all tests passed).
  • pnpm run cicheck (content checks) failed on cspell due to transient/generated cache files (tsx-0/*) being picked up by the spell-checker in this environment; this is an environment artifact and not caused by the code changes.
  • Added unit tests asserting default destination, tool-level destination, feature-level override, and writing to .gitattributes when configured; these tests succeeded in the runs above.

Codex Task

Copilot AI review requested due to automatic review settings April 17, 2026 02:56
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds configuration-driven routing for rulesync gitignore output so entries can be written per tool / per feature into either .gitignore (default) or .gitattributes, enabling workflows like “don’t ignore generated tool files, but mark them via attributes”.

Changes:

  • Introduces $gitignoreDestination and Config#getGitignoreDestination() to resolve destination with feature-level precedence.
  • Enhances gitignore entry resolution to return richer metadata (entry + target(s) + feature) and updates the gitignore command to write to .gitignore and/or .gitattributes.
  • Adds unit tests and updates docs (and synced skill docs) describing the new routing behavior.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/types/features.ts Adds GitignoreDestination schema/type and expands feature value schema.
src/config/config.ts Defines $gitignoreDestination key constant and adds destination resolution API.
src/config/config.test.ts Adds tests for destination defaulting and precedence.
src/cli/commands/gitignore-entries.ts Adds resolveGitignoreEntries() returning entry metadata; adjusts validation warnings.
src/cli/commands/gitignore.ts Groups entries by destination and writes Rulesync blocks to .gitignore and .gitattributes.
src/cli/commands/gitignore.test.ts Updates mocks and adds a test for .gitattributes writing behavior.
docs/guide/configuration.md Documents $gitignoreDestination usage and precedence.
docs/reference/cli-commands.md Documents destination routing behavior for rulesync gitignore.
skills/rulesync/configuration.md Synced doc update describing $gitignoreDestination and options table.
skills/rulesync/cli-commands.md Synced doc update describing destination routing behavior.

Comment on lines +191 to +194
const gitattributesResult = await updateRulesyncFile({
filePath: gitattributesPath,
entries: gitattributesEntries,
});
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

Entries routed to .gitattributes are currently written as the same bare ignore-pattern strings used for .gitignore. In .gitattributes, a line without attributes has no effect, so this won’t achieve the intended behavior (e.g., marking paths as linguist-generated). Consider transforming entries for the gitattributes destination to include the desired attributes (and updating removeExistingRulesyncEntries / isRulesyncEntry so the command can reliably update/clean prior Rulesync-managed .gitattributes blocks).

Copilot uses AI. Check for mistakes.
Comment thread src/types/features.ts
Comment on lines +47 to +51
export const FeatureValueSchema = z.union([
z.boolean(),
FeatureOptionsSchema,
GitignoreDestinationSchema,
]);
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

FeatureValueSchema now allows the string literals "gitignore" / "gitattributes" for any per-feature key (e.g. targets.<tool>.rules: "gitattributes"), which previously would have been rejected at parse time. This will silently disable the feature (since isFeatureValueEnabled treats strings as disabled) and can hide config mistakes. Consider keeping GitignoreDestination out of generic FeatureValueSchema and instead validating $gitignoreDestination explicitly (e.g., as an optional reserved key in a dedicated schema/refinement), or add a runtime refinement that only permits these string values when the key is $gitignoreDestination.

Copilot uses AI. Check for mistakes.
Comment thread src/config/config.ts
Comment on lines +498 to +502
const perFeature: PerFeatureConfig = targetValue;
const toolLevel = Config.parseGitignoreDestination(
perFeature[TARGET_GITIGNORE_DESTINATION_KEY],
);
if (feature) {
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

With the new reserved $gitignoreDestination key living alongside feature keys inside the per-feature object, invalid types like true or {...} can still pass schema validation (since per-feature values accept booleans/objects) and may then be treated as an enabled feature key elsewhere (e.g., feature normalization iterates object entries). It would be safer to validate $gitignoreDestination’s type/value at config load time and ensure this reserved key is excluded from feature-key enumeration/normalization paths.

Copilot uses AI. Check for mistakes.
Comment on lines +108 to +109
gitattributes.add(entry.entry);
}
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

When a single registry entry applies to multiple tool targets, and those targets resolve to mixed destinations, the current logic will add the same pattern to both .gitattributes and .gitignore (because it checks destinations.has("gitattributes") and also destinations.has("gitignore")). This can unintentionally ignore files even if some targets were configured for .gitattributes specifically to avoid ignoring. Consider defining a deterministic precedence for mixed-target entries (e.g., prefer .gitattributes as the less destructive option, or emit a warning and require consistent destination across all targets for a shared entry).

Suggested change
gitattributes.add(entry.entry);
}
gitattributes.add(entry.entry);
continue;
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants