@eslint-config-snapshot/cli 0.1.0 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/package.json +10 -2
- package/project.json +2 -2
- package/src/index.ts +467 -467
- package/test/cli.integration.test.ts +167 -167
- package/test/cli.npm-isolated.integration.test.ts +76 -76
- package/test/cli.pnpm-isolated.integration.test.ts +49 -49
- package/test/cli.terminal.integration.test.ts +197 -197
- package/test/fixtures/npm-isolated-template/package.json +7 -7
- package/test/fixtures/npm-isolated-template/packages/ws-a/.eslintrc.cjs +1 -1
- package/test/fixtures/npm-isolated-template/packages/ws-a/src/index.ts +1 -1
- package/test/fixtures/npm-isolated-template/packages/ws-b/.eslintrc.cjs +1 -1
- package/test/fixtures/npm-isolated-template/packages/ws-b/src/index.ts +1 -1
- package/test/fixtures/repo/eslint-config-snapshot.config.mjs +1 -1
- package/test/fixtures/repo/package.json +1 -1
- package/test/fixtures/repo/packages/ws-a/package.json +1 -1
- package/test/fixtures/repo/packages/ws-a/src/index.ts +1 -1
- package/test/fixtures/repo/packages/ws-b/package.json +1 -1
- package/test/fixtures/repo/packages/ws-b/src/index.ts +1 -1
- package/tsconfig.json +12 -12
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { cp, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
|
|
2
|
-
import os from 'node:os'
|
|
3
|
-
import path from 'node:path'
|
|
4
|
-
import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
|
-
|
|
2
|
+
import os from 'node:os'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
|
+
|
|
6
6
|
import { parseInitPresetChoice, parseInitTargetChoice, runCli } from '../src/index.js'
|
|
7
|
-
|
|
8
|
-
const fixtureRoot = path.resolve('test/fixtures/repo')
|
|
9
|
-
|
|
10
|
-
afterAll(async () => {
|
|
11
|
-
await rm(path.join(fixtureRoot, '.eslint-config-snapshot'), { recursive: true, force: true })
|
|
12
|
-
})
|
|
13
|
-
|
|
7
|
+
|
|
8
|
+
const fixtureRoot = path.resolve('test/fixtures/repo')
|
|
9
|
+
|
|
10
|
+
afterAll(async () => {
|
|
11
|
+
await rm(path.join(fixtureRoot, '.eslint-config-snapshot'), { recursive: true, force: true })
|
|
12
|
+
})
|
|
13
|
+
|
|
14
14
|
beforeEach(async () => {
|
|
15
15
|
await rm(path.join(fixtureRoot, '.eslint-config-snapshot'), { recursive: true, force: true })
|
|
16
16
|
await mkdir(path.join(fixtureRoot, 'packages/ws-a/node_modules/eslint/bin'), { recursive: true })
|
|
@@ -34,7 +34,7 @@ beforeEach(async () => {
|
|
|
34
34
|
JSON.stringify({ name: 'eslint', version: '9.0.0' }, null, 2)
|
|
35
35
|
)
|
|
36
36
|
})
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
describe('cli integration', () => {
|
|
39
39
|
it('parses init interactive target choices from numeric and aliases', () => {
|
|
40
40
|
expect(parseInitTargetChoice('')).toBe('package-json')
|
|
@@ -56,70 +56,70 @@ describe('cli integration', () => {
|
|
|
56
56
|
})
|
|
57
57
|
|
|
58
58
|
it('snapshot writes deterministic snapshot files', async () => {
|
|
59
|
-
const code = await runCli('snapshot', fixtureRoot)
|
|
60
|
-
expect(code).toBe(0)
|
|
61
|
-
|
|
62
|
-
const snapshotRaw = await readFile(path.join(fixtureRoot, '.eslint-config-snapshot/default.json'), 'utf8')
|
|
63
|
-
const snapshot = JSON.parse(snapshotRaw)
|
|
64
|
-
|
|
65
|
-
expect(snapshot).toEqual({
|
|
66
|
-
formatVersion: 1,
|
|
67
|
-
groupId: 'default',
|
|
68
|
-
workspaces: ['packages/ws-a', 'packages/ws-b'],
|
|
69
|
-
rules: {
|
|
70
|
-
eqeqeq: ['error', 'always'],
|
|
71
|
-
'no-console': ['error'],
|
|
72
|
-
'no-debugger': ['off']
|
|
73
|
-
}
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
expect(snapshotRaw.endsWith('\n')).toBe(true)
|
|
77
|
-
expect(snapshotRaw.includes('src/index.ts')).toBe(false)
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
it('compare returns non-zero when snapshots changed', async () => {
|
|
81
|
-
expect(await runCli('snapshot', fixtureRoot)).toBe(0)
|
|
82
|
-
|
|
83
|
-
await writeFile(
|
|
84
|
-
path.join(fixtureRoot, 'packages/ws-a/node_modules/eslint/bin/eslint.js'),
|
|
85
|
-
"console.log(JSON.stringify({ rules: { 'no-console': 1, eqeqeq: 0 } }))\n"
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
const code = await runCli('compare', fixtureRoot)
|
|
89
|
-
expect(code).toBe(1)
|
|
90
|
-
})
|
|
91
|
-
|
|
59
|
+
const code = await runCli('snapshot', fixtureRoot)
|
|
60
|
+
expect(code).toBe(0)
|
|
61
|
+
|
|
62
|
+
const snapshotRaw = await readFile(path.join(fixtureRoot, '.eslint-config-snapshot/default.json'), 'utf8')
|
|
63
|
+
const snapshot = JSON.parse(snapshotRaw)
|
|
64
|
+
|
|
65
|
+
expect(snapshot).toEqual({
|
|
66
|
+
formatVersion: 1,
|
|
67
|
+
groupId: 'default',
|
|
68
|
+
workspaces: ['packages/ws-a', 'packages/ws-b'],
|
|
69
|
+
rules: {
|
|
70
|
+
eqeqeq: ['error', 'always'],
|
|
71
|
+
'no-console': ['error'],
|
|
72
|
+
'no-debugger': ['off']
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
expect(snapshotRaw.endsWith('\n')).toBe(true)
|
|
77
|
+
expect(snapshotRaw.includes('src/index.ts')).toBe(false)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('compare returns non-zero when snapshots changed', async () => {
|
|
81
|
+
expect(await runCli('snapshot', fixtureRoot)).toBe(0)
|
|
82
|
+
|
|
83
|
+
await writeFile(
|
|
84
|
+
path.join(fixtureRoot, 'packages/ws-a/node_modules/eslint/bin/eslint.js'),
|
|
85
|
+
"console.log(JSON.stringify({ rules: { 'no-console': 1, eqeqeq: 0 } }))\n"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
const code = await runCli('compare', fixtureRoot)
|
|
89
|
+
expect(code).toBe(1)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
92
|
it('status is minimal and exits 0 when clean', async () => {
|
|
93
|
-
await runCli('snapshot', fixtureRoot)
|
|
94
|
-
|
|
95
|
-
const writeSpy = vi.spyOn(process.stdout, 'write')
|
|
96
|
-
const code = await runCli('status', fixtureRoot)
|
|
97
|
-
expect(code).toBe(0)
|
|
93
|
+
await runCli('snapshot', fixtureRoot)
|
|
94
|
+
|
|
95
|
+
const writeSpy = vi.spyOn(process.stdout, 'write')
|
|
96
|
+
const code = await runCli('status', fixtureRoot)
|
|
97
|
+
expect(code).toBe(0)
|
|
98
98
|
expect(writeSpy).toHaveBeenCalledWith('clean\n')
|
|
99
99
|
})
|
|
100
|
-
|
|
101
|
-
it('print emits aggregated rules and exits 0', async () => {
|
|
102
|
-
const writeSpy = vi.spyOn(process.stdout, 'write')
|
|
103
|
-
const code = await runCli('print', fixtureRoot)
|
|
104
|
-
expect(code).toBe(0)
|
|
105
|
-
expect(writeSpy).toHaveBeenCalled()
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
it('print --short emits compact human-readable output', async () => {
|
|
109
|
-
const writeSpy = vi.spyOn(process.stdout, 'write')
|
|
110
|
-
const code = await runCli('print', fixtureRoot, ['--short'])
|
|
111
|
-
expect(code).toBe(0)
|
|
112
|
-
expect(writeSpy).toHaveBeenCalledWith(
|
|
113
|
-
`group: default
|
|
114
|
-
workspaces (2): packages/ws-a, packages/ws-b
|
|
115
|
-
rules (3): error 2, warn 0, off 1
|
|
116
|
-
eqeqeq: error "always"
|
|
117
|
-
no-console: error
|
|
118
|
-
no-debugger: off
|
|
119
|
-
`
|
|
120
|
-
)
|
|
121
|
-
})
|
|
122
|
-
|
|
100
|
+
|
|
101
|
+
it('print emits aggregated rules and exits 0', async () => {
|
|
102
|
+
const writeSpy = vi.spyOn(process.stdout, 'write')
|
|
103
|
+
const code = await runCli('print', fixtureRoot)
|
|
104
|
+
expect(code).toBe(0)
|
|
105
|
+
expect(writeSpy).toHaveBeenCalled()
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('print --short emits compact human-readable output', async () => {
|
|
109
|
+
const writeSpy = vi.spyOn(process.stdout, 'write')
|
|
110
|
+
const code = await runCli('print', fixtureRoot, ['--short'])
|
|
111
|
+
expect(code).toBe(0)
|
|
112
|
+
expect(writeSpy).toHaveBeenCalledWith(
|
|
113
|
+
`group: default
|
|
114
|
+
workspaces (2): packages/ws-a, packages/ws-b
|
|
115
|
+
rules (3): error 2, warn 0, off 1
|
|
116
|
+
eqeqeq: error "always"
|
|
117
|
+
no-console: error
|
|
118
|
+
no-debugger: off
|
|
119
|
+
`
|
|
120
|
+
)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
123
|
it('init creates scaffold config file when target=file', async () => {
|
|
124
124
|
const tmp = await mkdtemp(path.join(os.tmpdir(), 'snapshot-init-'))
|
|
125
125
|
const code = await runCli('init', tmp, ['--yes', '--target', 'file', '--preset', 'full'])
|
|
@@ -146,102 +146,102 @@ no-debugger: off
|
|
|
146
146
|
|
|
147
147
|
await rm(tmp, { recursive: true, force: true })
|
|
148
148
|
})
|
|
149
|
-
|
|
150
|
-
it('help prints usage and exits 0', async () => {
|
|
151
|
-
const writeSpy = vi.spyOn(process.stdout, 'write')
|
|
152
|
-
const code = await runCli('--help', fixtureRoot)
|
|
153
|
-
expect(code).toBe(0)
|
|
154
|
-
expect(writeSpy).toHaveBeenCalledWith(expect.stringContaining('Usage:'))
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
it('runs update mode without command', async () => {
|
|
149
|
+
|
|
150
|
+
it('help prints usage and exits 0', async () => {
|
|
151
|
+
const writeSpy = vi.spyOn(process.stdout, 'write')
|
|
152
|
+
const code = await runCli('--help', fixtureRoot)
|
|
153
|
+
expect(code).toBe(0)
|
|
154
|
+
expect(writeSpy).toHaveBeenCalledWith(expect.stringContaining('Usage:'))
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
it('runs update mode without command', async () => {
|
|
158
158
|
const writeSpy = vi.spyOn(process.stdout, 'write')
|
|
159
159
|
const code = await runCli(undefined, fixtureRoot, ['--update'])
|
|
160
160
|
expect(code).toBe(0)
|
|
161
161
|
expect(writeSpy).toHaveBeenCalledWith(expect.stringContaining('Baseline updated:'))
|
|
162
162
|
})
|
|
163
|
-
|
|
164
|
-
it('supports canonical check and update commands', async () => {
|
|
165
|
-
expect(await runCli('update', fixtureRoot)).toBe(0)
|
|
166
|
-
expect(await runCli('check', fixtureRoot)).toBe(0)
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
it('supports ordered multi-group matching with first match wins', async () => {
|
|
170
|
-
const tmp = await mkdtemp(path.join(os.tmpdir(), 'snapshot-cli-grouped-'))
|
|
171
|
-
await cp(fixtureRoot, tmp, { recursive: true })
|
|
172
|
-
|
|
173
|
-
await writeFile(
|
|
174
|
-
path.join(tmp, 'eslint-config-snapshot.config.mjs'),
|
|
175
|
-
`export default {
|
|
176
|
-
workspaceInput: { mode: 'manual', workspaces: ['packages/ws-a', 'packages/ws-b'] },
|
|
177
|
-
grouping: {
|
|
178
|
-
mode: 'match',
|
|
179
|
-
groups: [
|
|
180
|
-
{ name: 'modern', match: ['packages/**', '!packages/ws-b'] },
|
|
181
|
-
{ name: 'legacy', match: ['packages/ws-b'] }
|
|
182
|
-
]
|
|
183
|
-
},
|
|
184
|
-
sampling: {
|
|
185
|
-
maxFilesPerWorkspace: 8,
|
|
186
|
-
includeGlobs: ['**/*.ts'],
|
|
187
|
-
excludeGlobs: ['**/node_modules/**'],
|
|
188
|
-
hintGlobs: []
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
`
|
|
192
|
-
)
|
|
193
|
-
|
|
194
|
-
const code = await runCli('snapshot', tmp)
|
|
195
|
-
expect(code).toBe(0)
|
|
196
|
-
|
|
197
|
-
const modern = JSON.parse(await readFile(path.join(tmp, '.eslint-config-snapshot/modern.json'), 'utf8'))
|
|
198
|
-
const legacy = JSON.parse(await readFile(path.join(tmp, '.eslint-config-snapshot/legacy.json'), 'utf8'))
|
|
199
|
-
|
|
200
|
-
expect(modern.workspaces).toEqual(['packages/ws-a'])
|
|
201
|
-
expect(modern.rules).toEqual({
|
|
202
|
-
eqeqeq: ['error', 'always'],
|
|
203
|
-
'no-console': ['warn']
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
expect(legacy.workspaces).toEqual(['packages/ws-b'])
|
|
207
|
-
expect(legacy.rules).toEqual({
|
|
208
|
-
'no-console': ['error'],
|
|
209
|
-
'no-debugger': ['off']
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
await rm(tmp, { recursive: true, force: true })
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
it('supports standalone mode with workspace path group ids', async () => {
|
|
216
|
-
const tmp = await mkdtemp(path.join(os.tmpdir(), 'snapshot-cli-standalone-'))
|
|
217
|
-
await cp(fixtureRoot, tmp, { recursive: true })
|
|
218
|
-
|
|
219
|
-
await writeFile(
|
|
220
|
-
path.join(tmp, 'eslint-config-snapshot.config.mjs'),
|
|
221
|
-
`export default {
|
|
222
|
-
workspaceInput: { mode: 'manual', workspaces: ['packages/ws-a', 'packages/ws-b'] },
|
|
223
|
-
grouping: { mode: 'standalone' },
|
|
224
|
-
sampling: {
|
|
225
|
-
maxFilesPerWorkspace: 8,
|
|
226
|
-
includeGlobs: ['**/*.ts'],
|
|
227
|
-
excludeGlobs: ['**/node_modules/**'],
|
|
228
|
-
hintGlobs: []
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
`
|
|
232
|
-
)
|
|
233
|
-
|
|
234
|
-
const snapshotCode = await runCli('snapshot', tmp)
|
|
235
|
-
expect(snapshotCode).toBe(0)
|
|
236
|
-
|
|
237
|
-
const wsAPath = path.join(tmp, '.eslint-config-snapshot/packages/ws-a.json')
|
|
238
|
-
const wsBPath = path.join(tmp, '.eslint-config-snapshot/packages/ws-b.json')
|
|
239
|
-
expect(JSON.parse(await readFile(wsAPath, 'utf8')).groupId).toBe('packages/ws-a')
|
|
240
|
-
expect(JSON.parse(await readFile(wsBPath, 'utf8')).groupId).toBe('packages/ws-b')
|
|
241
|
-
|
|
242
|
-
const compareCode = await runCli('compare', tmp)
|
|
243
|
-
expect(compareCode).toBe(0)
|
|
244
|
-
|
|
245
|
-
await rm(tmp, { recursive: true, force: true })
|
|
246
|
-
})
|
|
247
|
-
})
|
|
163
|
+
|
|
164
|
+
it('supports canonical check and update commands', async () => {
|
|
165
|
+
expect(await runCli('update', fixtureRoot)).toBe(0)
|
|
166
|
+
expect(await runCli('check', fixtureRoot)).toBe(0)
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
it('supports ordered multi-group matching with first match wins', async () => {
|
|
170
|
+
const tmp = await mkdtemp(path.join(os.tmpdir(), 'snapshot-cli-grouped-'))
|
|
171
|
+
await cp(fixtureRoot, tmp, { recursive: true })
|
|
172
|
+
|
|
173
|
+
await writeFile(
|
|
174
|
+
path.join(tmp, 'eslint-config-snapshot.config.mjs'),
|
|
175
|
+
`export default {
|
|
176
|
+
workspaceInput: { mode: 'manual', workspaces: ['packages/ws-a', 'packages/ws-b'] },
|
|
177
|
+
grouping: {
|
|
178
|
+
mode: 'match',
|
|
179
|
+
groups: [
|
|
180
|
+
{ name: 'modern', match: ['packages/**', '!packages/ws-b'] },
|
|
181
|
+
{ name: 'legacy', match: ['packages/ws-b'] }
|
|
182
|
+
]
|
|
183
|
+
},
|
|
184
|
+
sampling: {
|
|
185
|
+
maxFilesPerWorkspace: 8,
|
|
186
|
+
includeGlobs: ['**/*.ts'],
|
|
187
|
+
excludeGlobs: ['**/node_modules/**'],
|
|
188
|
+
hintGlobs: []
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
`
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
const code = await runCli('snapshot', tmp)
|
|
195
|
+
expect(code).toBe(0)
|
|
196
|
+
|
|
197
|
+
const modern = JSON.parse(await readFile(path.join(tmp, '.eslint-config-snapshot/modern.json'), 'utf8'))
|
|
198
|
+
const legacy = JSON.parse(await readFile(path.join(tmp, '.eslint-config-snapshot/legacy.json'), 'utf8'))
|
|
199
|
+
|
|
200
|
+
expect(modern.workspaces).toEqual(['packages/ws-a'])
|
|
201
|
+
expect(modern.rules).toEqual({
|
|
202
|
+
eqeqeq: ['error', 'always'],
|
|
203
|
+
'no-console': ['warn']
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
expect(legacy.workspaces).toEqual(['packages/ws-b'])
|
|
207
|
+
expect(legacy.rules).toEqual({
|
|
208
|
+
'no-console': ['error'],
|
|
209
|
+
'no-debugger': ['off']
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
await rm(tmp, { recursive: true, force: true })
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
it('supports standalone mode with workspace path group ids', async () => {
|
|
216
|
+
const tmp = await mkdtemp(path.join(os.tmpdir(), 'snapshot-cli-standalone-'))
|
|
217
|
+
await cp(fixtureRoot, tmp, { recursive: true })
|
|
218
|
+
|
|
219
|
+
await writeFile(
|
|
220
|
+
path.join(tmp, 'eslint-config-snapshot.config.mjs'),
|
|
221
|
+
`export default {
|
|
222
|
+
workspaceInput: { mode: 'manual', workspaces: ['packages/ws-a', 'packages/ws-b'] },
|
|
223
|
+
grouping: { mode: 'standalone' },
|
|
224
|
+
sampling: {
|
|
225
|
+
maxFilesPerWorkspace: 8,
|
|
226
|
+
includeGlobs: ['**/*.ts'],
|
|
227
|
+
excludeGlobs: ['**/node_modules/**'],
|
|
228
|
+
hintGlobs: []
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
`
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
const snapshotCode = await runCli('snapshot', tmp)
|
|
235
|
+
expect(snapshotCode).toBe(0)
|
|
236
|
+
|
|
237
|
+
const wsAPath = path.join(tmp, '.eslint-config-snapshot/packages/ws-a.json')
|
|
238
|
+
const wsBPath = path.join(tmp, '.eslint-config-snapshot/packages/ws-b.json')
|
|
239
|
+
expect(JSON.parse(await readFile(wsAPath, 'utf8')).groupId).toBe('packages/ws-a')
|
|
240
|
+
expect(JSON.parse(await readFile(wsBPath, 'utf8')).groupId).toBe('packages/ws-b')
|
|
241
|
+
|
|
242
|
+
const compareCode = await runCli('compare', tmp)
|
|
243
|
+
expect(compareCode).toBe(0)
|
|
244
|
+
|
|
245
|
+
await rm(tmp, { recursive: true, force: true })
|
|
246
|
+
})
|
|
247
|
+
})
|
|
@@ -4,29 +4,29 @@ import os from 'node:os'
|
|
|
4
4
|
import path from 'node:path'
|
|
5
5
|
import { setTimeout as delay } from 'node:timers/promises'
|
|
6
6
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
|
7
|
-
|
|
8
|
-
const templateRoot = path.resolve('test/fixtures/npm-isolated-template')
|
|
9
|
-
const cliDist = path.resolve('dist/index.js')
|
|
10
|
-
|
|
11
|
-
let fixtureRoot = ''
|
|
12
|
-
|
|
13
|
-
function npmCmd(): string {
|
|
14
|
-
const base = path.dirname(process.execPath)
|
|
15
|
-
return process.platform === 'win32' ? path.join(base, 'npm.cmd') : path.join(base, 'npm')
|
|
16
|
-
}
|
|
17
|
-
|
|
7
|
+
|
|
8
|
+
const templateRoot = path.resolve('test/fixtures/npm-isolated-template')
|
|
9
|
+
const cliDist = path.resolve('dist/index.js')
|
|
10
|
+
|
|
11
|
+
let fixtureRoot = ''
|
|
12
|
+
|
|
13
|
+
function npmCmd(): string {
|
|
14
|
+
const base = path.dirname(process.execPath)
|
|
15
|
+
return process.platform === 'win32' ? path.join(base, 'npm.cmd') : path.join(base, 'npm')
|
|
16
|
+
}
|
|
17
|
+
|
|
18
18
|
function run(command: string, args: string[], cwd: string): { status: number; stdout: string; stderr: string } {
|
|
19
|
-
const proc = spawnSync(command, args, {
|
|
20
|
-
cwd,
|
|
21
|
-
encoding: 'utf8',
|
|
22
|
-
env: { ...process.env },
|
|
23
|
-
shell: process.platform === 'win32'
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
status: proc.status ?? 1,
|
|
28
|
-
stdout: proc.stdout ?? '',
|
|
29
|
-
stderr: `${proc.stderr ?? ''}${proc.error ? `\n${String(proc.error)}` : ''}`
|
|
19
|
+
const proc = spawnSync(command, args, {
|
|
20
|
+
cwd,
|
|
21
|
+
encoding: 'utf8',
|
|
22
|
+
env: { ...process.env },
|
|
23
|
+
shell: process.platform === 'win32'
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
status: proc.status ?? 1,
|
|
28
|
+
stdout: proc.stdout ?? '',
|
|
29
|
+
stderr: `${proc.stderr ?? ''}${proc.error ? `\n${String(proc.error)}` : ''}`
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -45,16 +45,16 @@ async function runWithRetry(
|
|
|
45
45
|
}
|
|
46
46
|
return lastResult
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
describe('cli npm-isolated integration', () => {
|
|
50
|
-
beforeAll(async () => {
|
|
51
|
-
const tmpBase = await mkdtemp(path.join(os.tmpdir(), 'snapshot-npm-it-'))
|
|
52
|
-
fixtureRoot = path.join(tmpBase, 'repo')
|
|
53
|
-
await cp(templateRoot, fixtureRoot, { recursive: true })
|
|
54
|
-
|
|
55
|
-
const wsA = path.join(fixtureRoot, 'packages/ws-a')
|
|
56
|
-
const wsB = path.join(fixtureRoot, 'packages/ws-b')
|
|
57
|
-
|
|
48
|
+
|
|
49
|
+
describe('cli npm-isolated integration', () => {
|
|
50
|
+
beforeAll(async () => {
|
|
51
|
+
const tmpBase = await mkdtemp(path.join(os.tmpdir(), 'snapshot-npm-it-'))
|
|
52
|
+
fixtureRoot = path.join(tmpBase, 'repo')
|
|
53
|
+
await cp(templateRoot, fixtureRoot, { recursive: true })
|
|
54
|
+
|
|
55
|
+
const wsA = path.join(fixtureRoot, 'packages/ws-a')
|
|
56
|
+
const wsB = path.join(fixtureRoot, 'packages/ws-b')
|
|
57
|
+
|
|
58
58
|
const installA = await runWithRetry(npmCmd(), ['install', '--no-audit', '--no-fund', '--workspaces=false'], wsA)
|
|
59
59
|
expect(installA.status, `${installA.stdout}\n${installA.stderr}`).toBe(0)
|
|
60
60
|
await access(path.join(wsA, 'node_modules/eslint/package.json'))
|
|
@@ -63,47 +63,47 @@ describe('cli npm-isolated integration', () => {
|
|
|
63
63
|
expect(installB.status, `${installB.stdout}\n${installB.stderr}`).toBe(0)
|
|
64
64
|
await access(path.join(wsB, 'node_modules/eslint/package.json'))
|
|
65
65
|
}, 180000)
|
|
66
|
-
|
|
67
|
-
afterAll(async () => {
|
|
68
|
-
if (fixtureRoot) {
|
|
69
|
-
await rm(path.dirname(fixtureRoot), { recursive: true, force: true })
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
it('runs commands in isolated subprocesses with workspace-local npm eslint', async () => {
|
|
74
|
-
const snapshot = run(process.execPath, [cliDist, 'snapshot'], fixtureRoot)
|
|
75
|
-
expect(snapshot.status, snapshot.stderr).toBe(0)
|
|
76
|
-
|
|
77
|
-
const snapshotRaw = await readFile(path.join(fixtureRoot, '.eslint-config-snapshot/default.json'), 'utf8')
|
|
78
|
-
const parsed = JSON.parse(snapshotRaw)
|
|
79
|
-
expect(parsed).toEqual({
|
|
80
|
-
formatVersion: 1,
|
|
81
|
-
groupId: 'default',
|
|
82
|
-
workspaces: ['packages/ws-a', 'packages/ws-b'],
|
|
83
|
-
rules: {
|
|
84
|
-
eqeqeq: ['error', 'always'],
|
|
85
|
-
'no-console': ['error'],
|
|
86
|
-
'no-debugger': ['off']
|
|
87
|
-
}
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
const compareClean = run(process.execPath, [cliDist, 'compare'], fixtureRoot)
|
|
91
|
-
expect(compareClean.status, compareClean.stdout + compareClean.stderr).toBe(0)
|
|
92
|
-
|
|
93
|
-
const statusClean = run(process.execPath, [cliDist, 'status'], fixtureRoot)
|
|
94
|
-
expect(statusClean.status).toBe(0)
|
|
95
|
-
expect(statusClean.stdout).toContain('clean')
|
|
96
|
-
|
|
97
|
-
const printOut = run(process.execPath, [cliDist, 'print'], fixtureRoot)
|
|
98
|
-
expect(printOut.status, printOut.stderr).toBe(0)
|
|
99
|
-
expect(printOut.stdout).toContain('"groupId": "default"')
|
|
100
|
-
|
|
101
|
-
await writeFile(
|
|
102
|
-
path.join(fixtureRoot, 'packages/ws-a/.eslintrc.cjs'),
|
|
103
|
-
"module.exports = { root: true, rules: { 'no-console': 'warn', eqeqeq: 'off' } }\n"
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
const compareChanged = run(process.execPath, [cliDist, 'compare'], fixtureRoot)
|
|
107
|
-
expect(compareChanged.status).toBe(1)
|
|
108
|
-
}, 180000)
|
|
109
|
-
})
|
|
66
|
+
|
|
67
|
+
afterAll(async () => {
|
|
68
|
+
if (fixtureRoot) {
|
|
69
|
+
await rm(path.dirname(fixtureRoot), { recursive: true, force: true })
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('runs commands in isolated subprocesses with workspace-local npm eslint', async () => {
|
|
74
|
+
const snapshot = run(process.execPath, [cliDist, 'snapshot'], fixtureRoot)
|
|
75
|
+
expect(snapshot.status, snapshot.stderr).toBe(0)
|
|
76
|
+
|
|
77
|
+
const snapshotRaw = await readFile(path.join(fixtureRoot, '.eslint-config-snapshot/default.json'), 'utf8')
|
|
78
|
+
const parsed = JSON.parse(snapshotRaw)
|
|
79
|
+
expect(parsed).toEqual({
|
|
80
|
+
formatVersion: 1,
|
|
81
|
+
groupId: 'default',
|
|
82
|
+
workspaces: ['packages/ws-a', 'packages/ws-b'],
|
|
83
|
+
rules: {
|
|
84
|
+
eqeqeq: ['error', 'always'],
|
|
85
|
+
'no-console': ['error'],
|
|
86
|
+
'no-debugger': ['off']
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
const compareClean = run(process.execPath, [cliDist, 'compare'], fixtureRoot)
|
|
91
|
+
expect(compareClean.status, compareClean.stdout + compareClean.stderr).toBe(0)
|
|
92
|
+
|
|
93
|
+
const statusClean = run(process.execPath, [cliDist, 'status'], fixtureRoot)
|
|
94
|
+
expect(statusClean.status).toBe(0)
|
|
95
|
+
expect(statusClean.stdout).toContain('clean')
|
|
96
|
+
|
|
97
|
+
const printOut = run(process.execPath, [cliDist, 'print'], fixtureRoot)
|
|
98
|
+
expect(printOut.status, printOut.stderr).toBe(0)
|
|
99
|
+
expect(printOut.stdout).toContain('"groupId": "default"')
|
|
100
|
+
|
|
101
|
+
await writeFile(
|
|
102
|
+
path.join(fixtureRoot, 'packages/ws-a/.eslintrc.cjs'),
|
|
103
|
+
"module.exports = { root: true, rules: { 'no-console': 'warn', eqeqeq: 'off' } }\n"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
const compareChanged = run(process.execPath, [cliDist, 'compare'], fixtureRoot)
|
|
107
|
+
expect(compareChanged.status).toBe(1)
|
|
108
|
+
}, 180000)
|
|
109
|
+
})
|
|
@@ -4,10 +4,10 @@ import os from 'node:os'
|
|
|
4
4
|
import path from 'node:path'
|
|
5
5
|
import { setTimeout as delay } from 'node:timers/promises'
|
|
6
6
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
|
|
7
|
-
|
|
8
|
-
const templateRoot = path.resolve('test/fixtures/npm-isolated-template')
|
|
9
|
-
const cliDist = path.resolve('dist/index.js')
|
|
10
|
-
|
|
7
|
+
|
|
8
|
+
const templateRoot = path.resolve('test/fixtures/npm-isolated-template')
|
|
9
|
+
const cliDist = path.resolve('dist/index.js')
|
|
10
|
+
|
|
11
11
|
let fixtureRoot = ''
|
|
12
12
|
|
|
13
13
|
type RunResult = {
|
|
@@ -43,8 +43,8 @@ function run(command: string, args: string[], cwd: string): RunResult {
|
|
|
43
43
|
encoding: 'utf8',
|
|
44
44
|
env: { ...process.env },
|
|
45
45
|
shell: process.platform === 'win32'
|
|
46
|
-
})
|
|
47
|
-
|
|
46
|
+
})
|
|
47
|
+
|
|
48
48
|
return {
|
|
49
49
|
status: proc.status ?? 1,
|
|
50
50
|
stdout: proc.stdout ?? '',
|
|
@@ -87,16 +87,16 @@ async function runPnpmWithRetry(args: string[], cwd: string, retries = 2): Promi
|
|
|
87
87
|
|
|
88
88
|
return lastResult
|
|
89
89
|
}
|
|
90
|
-
|
|
91
|
-
describe('cli pnpm-isolated integration', () => {
|
|
92
|
-
beforeAll(async () => {
|
|
93
|
-
const tmpBase = await mkdtemp(path.join(os.tmpdir(), 'snapshot-pnpm-it-'))
|
|
94
|
-
fixtureRoot = path.join(tmpBase, 'repo')
|
|
95
|
-
await cp(templateRoot, fixtureRoot, { recursive: true })
|
|
96
|
-
|
|
97
|
-
const wsA = path.join(fixtureRoot, 'packages/ws-a')
|
|
98
|
-
const wsB = path.join(fixtureRoot, 'packages/ws-b')
|
|
99
|
-
|
|
90
|
+
|
|
91
|
+
describe('cli pnpm-isolated integration', () => {
|
|
92
|
+
beforeAll(async () => {
|
|
93
|
+
const tmpBase = await mkdtemp(path.join(os.tmpdir(), 'snapshot-pnpm-it-'))
|
|
94
|
+
fixtureRoot = path.join(tmpBase, 'repo')
|
|
95
|
+
await cp(templateRoot, fixtureRoot, { recursive: true })
|
|
96
|
+
|
|
97
|
+
const wsA = path.join(fixtureRoot, 'packages/ws-a')
|
|
98
|
+
const wsB = path.join(fixtureRoot, 'packages/ws-b')
|
|
99
|
+
|
|
100
100
|
const installA = await runPnpmWithRetry(['install', '--ignore-workspace', '--no-frozen-lockfile'], wsA)
|
|
101
101
|
expect(installA.status, `${installA.stdout}\n${installA.stderr}`).toBe(0)
|
|
102
102
|
await access(path.join(wsA, 'node_modules/eslint/package.json'))
|
|
@@ -105,36 +105,36 @@ describe('cli pnpm-isolated integration', () => {
|
|
|
105
105
|
expect(installB.status, `${installB.stdout}\n${installB.stderr}`).toBe(0)
|
|
106
106
|
await access(path.join(wsB, 'node_modules/eslint/package.json'))
|
|
107
107
|
}, 180000)
|
|
108
|
-
|
|
109
|
-
afterAll(async () => {
|
|
110
|
-
if (fixtureRoot) {
|
|
111
|
-
await rm(path.dirname(fixtureRoot), { recursive: true, force: true })
|
|
112
|
-
}
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
it('runs commands with workspace-local eslint installed by pnpm in isolated mode', async () => {
|
|
116
|
-
const snapshot = run(process.execPath, [cliDist, 'snapshot'], fixtureRoot)
|
|
117
|
-
expect(snapshot.status, snapshot.stderr).toBe(0)
|
|
118
|
-
|
|
119
|
-
const snapshotRaw = await readFile(path.join(fixtureRoot, '.eslint-config-snapshot/default.json'), 'utf8')
|
|
120
|
-
const parsed = JSON.parse(snapshotRaw)
|
|
121
|
-
expect(parsed).toEqual({
|
|
122
|
-
formatVersion: 1,
|
|
123
|
-
groupId: 'default',
|
|
124
|
-
workspaces: ['packages/ws-a', 'packages/ws-b'],
|
|
125
|
-
rules: {
|
|
126
|
-
eqeqeq: ['error', 'always'],
|
|
127
|
-
'no-console': ['error'],
|
|
128
|
-
'no-debugger': ['off']
|
|
129
|
-
}
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
await writeFile(
|
|
133
|
-
path.join(fixtureRoot, 'packages/ws-a/.eslintrc.cjs'),
|
|
134
|
-
"module.exports = { root: true, rules: { 'no-console': 'warn', eqeqeq: 'off' } }\n"
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
const compareChanged = run(process.execPath, [cliDist, 'compare'], fixtureRoot)
|
|
138
|
-
expect(compareChanged.status).toBe(1)
|
|
139
|
-
}, 180000)
|
|
140
|
-
})
|
|
108
|
+
|
|
109
|
+
afterAll(async () => {
|
|
110
|
+
if (fixtureRoot) {
|
|
111
|
+
await rm(path.dirname(fixtureRoot), { recursive: true, force: true })
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('runs commands with workspace-local eslint installed by pnpm in isolated mode', async () => {
|
|
116
|
+
const snapshot = run(process.execPath, [cliDist, 'snapshot'], fixtureRoot)
|
|
117
|
+
expect(snapshot.status, snapshot.stderr).toBe(0)
|
|
118
|
+
|
|
119
|
+
const snapshotRaw = await readFile(path.join(fixtureRoot, '.eslint-config-snapshot/default.json'), 'utf8')
|
|
120
|
+
const parsed = JSON.parse(snapshotRaw)
|
|
121
|
+
expect(parsed).toEqual({
|
|
122
|
+
formatVersion: 1,
|
|
123
|
+
groupId: 'default',
|
|
124
|
+
workspaces: ['packages/ws-a', 'packages/ws-b'],
|
|
125
|
+
rules: {
|
|
126
|
+
eqeqeq: ['error', 'always'],
|
|
127
|
+
'no-console': ['error'],
|
|
128
|
+
'no-debugger': ['off']
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
await writeFile(
|
|
133
|
+
path.join(fixtureRoot, 'packages/ws-a/.eslintrc.cjs'),
|
|
134
|
+
"module.exports = { root: true, rules: { 'no-console': 'warn', eqeqeq: 'off' } }\n"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
const compareChanged = run(process.execPath, [cliDist, 'compare'], fixtureRoot)
|
|
138
|
+
expect(compareChanged.status).toBe(1)
|
|
139
|
+
}, 180000)
|
|
140
|
+
})
|