feat: consolidate rulesync entries in .gitignore - #668
Conversation
The gitignore command now removes existing rulesync entries from anywhere in the file and consolidates them all at the end. This ensures rulesync entries are always in one location for easier management. Also updates the header from "# Generated by rulesync - AI tool configuration files" to the shorter "# Generated by Rulesync". 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Apply the new gitignore consolidation behavior to the project's own .gitignore file. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR refactors the gitignore command to consolidate rulesync entries in .gitignore files. Instead of only appending missing entries, the command now removes any existing rulesync entries from anywhere in the file and consolidates them all at the end under a new shorter header. This ensures better organization and easier management of rulesync-related ignore rules.
Key Changes:
- Introduced logic to detect and remove existing rulesync entries (both with new and legacy headers) from .gitignore files
- Changed from incremental append behavior to full consolidation at end of file
- Updated header from "# Generated by rulesync - AI tool configuration files" to "# Generated by Rulesync"
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/cli/commands/gitignore.ts | Added helper functions to identify and remove existing rulesync entries, refactored main command to consolidate all rulesync entries at the end |
| src/cli/commands/gitignore.test.ts | Updated tests to verify consolidation behavior, removed unnecessary comments, updated expectations for new header text |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (inRulesyncBlock) { | ||
| if (trimmed === "") { | ||
| consecutiveEmptyLines++; | ||
| if (consecutiveEmptyLines >= 2) { | ||
| inRulesyncBlock = false; | ||
| consecutiveEmptyLines = 0; | ||
| } | ||
| continue; | ||
| } | ||
|
|
||
| if (isRulesyncEntry(line)) { | ||
| consecutiveEmptyLines = 0; | ||
| continue; | ||
| } | ||
|
|
||
| inRulesyncBlock = false; | ||
| consecutiveEmptyLines = 0; | ||
| } | ||
|
|
||
| if (isRulesyncEntry(line)) { | ||
| continue; | ||
| } | ||
|
|
||
| filteredLines.push(line); |
There was a problem hiding this comment.
The logic for handling empty lines within a rulesync block has a bug that removes user-added blank lines. When inside a rulesync block and encountering empty lines, they are skipped (line 110) without being preserved. If a non-rulesync entry is encountered after empty lines, the block is exited (line 118) and the non-rulesync entry is added (line 126), but the empty lines are lost. For example, with input like "# Generated by Rulesync\n**/.cursor/\n\nother-stuff/", the blank line separating sections will be removed, potentially degrading readability of the .gitignore file.
| it("should handle rulesync block in the middle of file", async () => { | ||
| const existingContent = `node_modules/ | ||
| # Generated by Rulesync | ||
| **/.cursor/ | ||
| **/.amazonq/ | ||
|
|
||
| other-stuff/ | ||
| dist/`; | ||
|
|
||
| vi.mocked(fileExists).mockResolvedValue(true); | ||
| vi.mocked(readFileContent).mockResolvedValue(existingContent); | ||
|
|
||
| await gitignoreCommand(); | ||
|
|
||
| const writeCall = vi.mocked(writeFileContent).mock.calls[0]; | ||
| expect(writeCall).toBeDefined(); | ||
| const content = writeCall![1]; | ||
|
|
||
| expect(content).toContain("node_modules/"); | ||
| expect(content).toContain("other-stuff/"); | ||
| expect(content).toContain("dist/"); | ||
|
|
||
| const rulesyncIndex = content.indexOf("# Generated by Rulesync"); | ||
| const otherStuffIndex = content.indexOf("other-stuff/"); | ||
| expect(rulesyncIndex).toBeGreaterThan(otherStuffIndex); | ||
| }); |
There was a problem hiding this comment.
The test doesn't verify that blank lines between rulesync entries and subsequent content are preserved. The test should check that the empty line at line 343 appears in the output content to ensure user formatting is maintained. Consider adding an assertion like: expect(content).toMatch(/**/.amazonq/\n\nother-stuff//)
Add **/.geminiignore pattern for Gemini CLI ignore files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add .gemini/settings.json with MCP server configurations for serena, context7, fetch, and rulesync-mcp. Also add .geminiignore pattern to .gitignore entries for generated files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added **/.claude/CLAUDE.md and **/.claude/rules/ to RULESYNC_IGNORE_ENTRIES - Updated test fixture to include **/.geminiignore entry 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary
# Generated by rulesync - AI tool configuration filesto the shorter# Generated by RulesyncTest plan
pnpm cicheck:code- all tests passpnpm cicheck- full check passes🤖 Generated with Claude Code