Skip to content

Commit 100d4f4

Browse files
feat(core): add .nx/self-healing to .gitignore (#34855)
## Summary - Self-healing auto-apply writes fix context to `.nx/self-healing/`, but that directory was not in `.gitignore`. This adds it via a migration and in the CAIA generator, following the same pattern as `.nx/polygraph`. ## Current Behavior The `.nx/self-healing` directory is not gitignored. Users who run self-healing auto-apply may accidentally commit generated fix context files. ## Expected Behavior `.nx/self-healing` is added to `.gitignore` automatically during `nx migrate` (via a new migration) and when running the CAIA setup generator. --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
1 parent 44db03a commit 100d4f4

File tree

5 files changed

+131
-1
lines changed

5 files changed

+131
-1
lines changed

packages/nx/migrations.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,12 @@
160160
"version": "22.6.0-beta.11",
161161
"description": "Prompts to enable usage analytics",
162162
"implementation": "./src/migrations/update-22-6-0/enable-analytics-prompt"
163+
},
164+
"22-7-0-add-self-healing-to-gitignore": {
165+
"cli": "nx",
166+
"version": "22.7.0-beta.0",
167+
"description": "Adds .nx/self-healing to .gitignore",
168+
"implementation": "./src/migrations/update-22-2-0/add-self-healing-to-gitignore"
163169
}
164170
}
165171
}

packages/nx/src/command-line/init/implementation/dot-nx/add-nx-scripts.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,12 @@ export function writeMinimalNxJson(host: Tree, version: string) {
8989

9090
export function updateGitIgnore(host: Tree) {
9191
let contents = host.read('.gitignore', 'utf-8') ?? '';
92-
['.nx/installation', '.nx/cache', '.nx/workspace-data'].forEach((file) => {
92+
[
93+
'.nx/installation',
94+
'.nx/cache',
95+
'.nx/workspace-data',
96+
'.nx/self-healing',
97+
].forEach((file) => {
9398
if (!contents.includes(file)) {
9499
contents = [contents, file].join('\n');
95100
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#### Add Self-Healing Directory to Git Ignore
2+
3+
Add gitignore entry for the `.nx/self-healing` directory, which stores local fix context generated by Nx's self-healing CI feature.
4+
5+
#### Sample Code Changes
6+
7+
Adds the following entry to the `.gitignore` file.
8+
9+
```text title=".gitignore"
10+
.nx/self-healing
11+
```
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { createTreeWithEmptyWorkspace } from '../../generators/testing-utils/create-tree-with-empty-workspace';
2+
import { Tree } from '../../generators/tree';
3+
import addSelfHealingToGitignore from './add-self-healing-to-gitignore';
4+
5+
describe('add-self-healing-to-gitignore migration', () => {
6+
let tree: Tree;
7+
8+
beforeEach(() => {
9+
tree = createTreeWithEmptyWorkspace();
10+
});
11+
12+
it('should not create .gitignore if it does not exist', async () => {
13+
tree.delete('.gitignore');
14+
15+
await addSelfHealingToGitignore(tree);
16+
17+
expect(tree.exists('.gitignore')).toBe(false);
18+
});
19+
20+
it('should add .nx/self-healing to existing .gitignore', async () => {
21+
tree.write('.gitignore', 'node_modules\ndist\n');
22+
23+
await addSelfHealingToGitignore(tree);
24+
25+
const gitignore = tree.read('.gitignore')?.toString();
26+
expect(gitignore).toContain('node_modules');
27+
expect(gitignore).toContain('.nx/self-healing');
28+
});
29+
30+
it('should not duplicate if .nx/self-healing is already present', async () => {
31+
tree.write('.gitignore', 'node_modules\n.nx/self-healing\n');
32+
33+
await addSelfHealingToGitignore(tree);
34+
35+
const gitignore = tree.read('.gitignore')?.toString();
36+
const matches = gitignore.match(/\.nx\/self-healing/g);
37+
expect(matches).toHaveLength(1);
38+
});
39+
40+
it('should not add if a broader pattern already covers it', async () => {
41+
tree.write('.gitignore', '.nx/\n');
42+
43+
await addSelfHealingToGitignore(tree);
44+
45+
const gitignore = tree.read('.gitignore')?.toString();
46+
expect(gitignore).not.toContain('.nx/self-healing');
47+
});
48+
49+
it('should skip for lerna workspaces without nx.json', async () => {
50+
tree.write('.gitignore', 'node_modules\n');
51+
tree.write('lerna.json', '{}');
52+
tree.delete('nx.json');
53+
54+
await addSelfHealingToGitignore(tree);
55+
56+
const gitignore = tree.read('.gitignore')?.toString();
57+
expect(gitignore).not.toContain('.nx/self-healing');
58+
});
59+
60+
it('should not skip for lerna workspaces that also have nx.json', async () => {
61+
tree.write('.gitignore', 'node_modules\n');
62+
tree.write('lerna.json', '{}');
63+
// nx.json already exists from createTreeWithEmptyWorkspace
64+
65+
await addSelfHealingToGitignore(tree);
66+
67+
const gitignore = tree.read('.gitignore')?.toString();
68+
expect(gitignore).toContain('.nx/self-healing');
69+
});
70+
71+
it('should add .nx/self-healing to .prettierignore if it exists', async () => {
72+
tree.write('.gitignore', 'node_modules\n');
73+
tree.write('.prettierignore', '/dist\n');
74+
75+
await addSelfHealingToGitignore(tree);
76+
77+
const prettierignore = tree.read('.prettierignore')?.toString();
78+
expect(prettierignore).toContain('.nx/self-healing');
79+
});
80+
81+
it('should not modify .prettierignore if it does not exist', async () => {
82+
tree.write('.gitignore', 'node_modules\n');
83+
84+
await addSelfHealingToGitignore(tree);
85+
86+
expect(tree.exists('.prettierignore')).toBe(false);
87+
});
88+
});
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available';
2+
import { Tree } from '../../generators/tree';
3+
import { addEntryToGitIgnore } from '../../utils/ignore';
4+
5+
export default async function addSelfHealingToGitignore(tree: Tree) {
6+
if (!tree.exists('.gitignore')) {
7+
return;
8+
}
9+
// Lerna users that don't use nx.json may not expect .nx directory changes
10+
if (tree.exists('lerna.json') && !tree.exists('nx.json')) {
11+
return;
12+
}
13+
addEntryToGitIgnore(tree, '.gitignore', '.nx/self-healing');
14+
15+
if (tree.exists('.prettierignore')) {
16+
addEntryToGitIgnore(tree, '.prettierignore', '.nx/self-healing');
17+
}
18+
19+
await formatChangedFilesWithPrettierIfAvailable(tree);
20+
}

0 commit comments

Comments
 (0)