@regressionproof/cli 0.1.0 → 0.1.2
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 +16 -0
- package/package.json +3 -3
- package/src/components/Init.tsx +135 -16
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [0.1.2](https://github.com/sprucelabsai-community/regressionproof/compare/v0.1.1...v0.1.2) (2026-01-12)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @regressionproof/cli
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [0.1.1](https://github.com/sprucelabsai-community/regressionproof/compare/v0.1.0...v0.1.1) (2026-01-12)
|
|
15
|
+
|
|
16
|
+
**Note:** Version bump only for package @regressionproof/cli
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
6
22
|
# 0.1.0 (2026-01-12)
|
|
7
23
|
|
|
8
24
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@regressionproof/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"watch.tsc": "tsc -w"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@regressionproof/client": "^0.1.
|
|
36
|
+
"@regressionproof/client": "^0.1.2",
|
|
37
37
|
"dotenv": "^17.2.3",
|
|
38
38
|
"ink": "^5.1.0",
|
|
39
39
|
"ink-big-text": "^2.0.0",
|
|
@@ -56,5 +56,5 @@
|
|
|
56
56
|
"skill": {
|
|
57
57
|
"namespace": "regressionproof-cli"
|
|
58
58
|
},
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "0dc77840a646cb322901f05aa87eb3d2efa3e8d9"
|
|
60
60
|
}
|
package/src/components/Init.tsx
CHANGED
|
@@ -4,6 +4,8 @@ import { Box, Text, useApp } from 'ink'
|
|
|
4
4
|
import BigText from 'ink-big-text'
|
|
5
5
|
import TextInput from 'ink-text-input'
|
|
6
6
|
import React from 'react'
|
|
7
|
+
import { spawnSync } from 'node:child_process'
|
|
8
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
7
9
|
import ConfigManager, { Credentials } from '../config/ConfigManager.js'
|
|
8
10
|
import JestConfigurator, { JestConfigResult } from '../jest/JestConfigurator.js'
|
|
9
11
|
import { getRepoNameFromGit, toSlug } from '../utilities/slug.js'
|
|
@@ -30,7 +32,7 @@ class InitComponent extends React.Component<Props, State> {
|
|
|
30
32
|
if (existingCreds) {
|
|
31
33
|
this.state = {
|
|
32
34
|
name: defaultName,
|
|
33
|
-
step: '
|
|
35
|
+
step: 'installing',
|
|
34
36
|
availability: 'available',
|
|
35
37
|
errorMessage: '',
|
|
36
38
|
credentials: existingCreds,
|
|
@@ -52,12 +54,8 @@ class InitComponent extends React.Component<Props, State> {
|
|
|
52
54
|
// If we have a provided name and not already registered, start registration
|
|
53
55
|
if (this.props.projectName && this.state.step === 'registering') {
|
|
54
56
|
void this.register()
|
|
55
|
-
} else if (this.state.step === '
|
|
56
|
-
|
|
57
|
-
const jestConfigurator = new JestConfigurator()
|
|
58
|
-
const jestConfig = jestConfigurator.configure()
|
|
59
|
-
this.setState({ jestConfig })
|
|
60
|
-
setTimeout(() => this.props.exit(), 1000)
|
|
57
|
+
} else if (this.state.step === 'installing') {
|
|
58
|
+
void this.installAndConfigure()
|
|
61
59
|
} else {
|
|
62
60
|
void this.checkAvailability()
|
|
63
61
|
}
|
|
@@ -137,14 +135,7 @@ class InitComponent extends React.Component<Props, State> {
|
|
|
137
135
|
this.setState({ credentials })
|
|
138
136
|
|
|
139
137
|
this.configManager.saveCredentials(name, credentials)
|
|
140
|
-
|
|
141
|
-
this.setState({ step: 'configuring' })
|
|
142
|
-
|
|
143
|
-
const jestConfigurator = new JestConfigurator()
|
|
144
|
-
const jestConfig = jestConfigurator.configure()
|
|
145
|
-
this.setState({ jestConfig, step: 'success' })
|
|
146
|
-
|
|
147
|
-
setTimeout(() => this.props.exit(), 3000)
|
|
138
|
+
await this.installAndConfigure()
|
|
148
139
|
} catch (err) {
|
|
149
140
|
this.setState({
|
|
150
141
|
step: 'error',
|
|
@@ -153,6 +144,108 @@ class InitComponent extends React.Component<Props, State> {
|
|
|
153
144
|
}
|
|
154
145
|
}
|
|
155
146
|
|
|
147
|
+
private async installAndConfigure(): Promise<void> {
|
|
148
|
+
this.setState({ step: 'installing' })
|
|
149
|
+
const installResult = this.installDependencies()
|
|
150
|
+
if (!installResult.success) {
|
|
151
|
+
this.setState({
|
|
152
|
+
step: 'error',
|
|
153
|
+
errorMessage:
|
|
154
|
+
installResult.message ??
|
|
155
|
+
'Failed to install dependencies.',
|
|
156
|
+
})
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
this.setState({ step: 'configuring' })
|
|
161
|
+
const jestConfigurator = new JestConfigurator()
|
|
162
|
+
const jestConfig = jestConfigurator.configure()
|
|
163
|
+
this.setState({ jestConfig, step: 'success' })
|
|
164
|
+
|
|
165
|
+
setTimeout(() => this.props.exit(), 3000)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
private installDependencies(): InstallResult {
|
|
169
|
+
if (!existsSync('package.json')) {
|
|
170
|
+
return {
|
|
171
|
+
success: false,
|
|
172
|
+
message:
|
|
173
|
+
'No package.json found. regressionproof currently supports Node.js + Jest projects.',
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
let packageJson: {
|
|
178
|
+
dependencies?: Record<string, string>
|
|
179
|
+
devDependencies?: Record<string, string>
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
packageJson = JSON.parse(
|
|
184
|
+
readFileSync('package.json', 'utf8')
|
|
185
|
+
) as {
|
|
186
|
+
dependencies?: Record<string, string>
|
|
187
|
+
devDependencies?: Record<string, string>
|
|
188
|
+
}
|
|
189
|
+
} catch (err) {
|
|
190
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
191
|
+
return {
|
|
192
|
+
success: false,
|
|
193
|
+
message: `Failed to read package.json: ${message}`,
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const hasReporter = Boolean(
|
|
198
|
+
packageJson.dependencies?.['@regressionproof/jest-reporter'] ??
|
|
199
|
+
packageJson.devDependencies?.[
|
|
200
|
+
'@regressionproof/jest-reporter'
|
|
201
|
+
]
|
|
202
|
+
)
|
|
203
|
+
if (hasReporter) {
|
|
204
|
+
return { success: true }
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const packageManager = this.getPackageManager()
|
|
208
|
+
const result = spawnSync(
|
|
209
|
+
packageManager.command,
|
|
210
|
+
[...packageManager.args, '@regressionproof/jest-reporter'],
|
|
211
|
+
{
|
|
212
|
+
encoding: 'utf8',
|
|
213
|
+
shell: true,
|
|
214
|
+
}
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
if (result.error || result.status !== 0) {
|
|
218
|
+
const details =
|
|
219
|
+
result.stderr?.trim() ||
|
|
220
|
+
result.stdout?.trim() ||
|
|
221
|
+
result.error?.message
|
|
222
|
+
return {
|
|
223
|
+
success: false,
|
|
224
|
+
message: `Failed to install dependencies${
|
|
225
|
+
details ? `: ${details}` : ''
|
|
226
|
+
}`,
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return { success: true }
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
private getPackageManager(): PackageManager {
|
|
234
|
+
if (existsSync('pnpm-lock.yaml')) {
|
|
235
|
+
return { command: 'pnpm', args: ['add', '-D'] }
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (existsSync('yarn.lock')) {
|
|
239
|
+
return { command: 'yarn', args: ['add', '-D'] }
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (existsSync('package-lock.json')) {
|
|
243
|
+
return { command: 'npm', args: ['install', '-D'] }
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return { command: 'npm', args: ['install', '-D'] }
|
|
247
|
+
}
|
|
248
|
+
|
|
156
249
|
private renderStatusIndicator(): React.ReactNode {
|
|
157
250
|
const { availability, errorMessage } = this.state
|
|
158
251
|
|
|
@@ -188,6 +281,14 @@ class InitComponent extends React.Component<Props, State> {
|
|
|
188
281
|
)
|
|
189
282
|
}
|
|
190
283
|
|
|
284
|
+
private renderInstalling(): React.ReactElement {
|
|
285
|
+
return (
|
|
286
|
+
<Box flexDirection="column" padding={1}>
|
|
287
|
+
<Text color="yellow">Installing dependencies...</Text>
|
|
288
|
+
</Box>
|
|
289
|
+
)
|
|
290
|
+
}
|
|
291
|
+
|
|
191
292
|
private renderSuccess(): React.ReactElement {
|
|
192
293
|
const { name, credentials, jestConfig } = this.state
|
|
193
294
|
const configDir = this.configManager.getConfigDir(name)
|
|
@@ -285,6 +386,8 @@ class InitComponent extends React.Component<Props, State> {
|
|
|
285
386
|
switch (step) {
|
|
286
387
|
case 'registering':
|
|
287
388
|
return this.renderRegistering()
|
|
389
|
+
case 'installing':
|
|
390
|
+
return this.renderInstalling()
|
|
288
391
|
case 'configuring':
|
|
289
392
|
return this.renderConfiguring()
|
|
290
393
|
case 'success':
|
|
@@ -302,7 +405,13 @@ export default function Init(props: { projectName?: string }): React.ReactElemen
|
|
|
302
405
|
return <InitComponent exit={exit} projectName={props.projectName} />
|
|
303
406
|
}
|
|
304
407
|
|
|
305
|
-
type Step =
|
|
408
|
+
type Step =
|
|
409
|
+
| 'input'
|
|
410
|
+
| 'registering'
|
|
411
|
+
| 'installing'
|
|
412
|
+
| 'configuring'
|
|
413
|
+
| 'success'
|
|
414
|
+
| 'error'
|
|
306
415
|
type Availability = 'idle' | 'checking' | 'available' | 'taken' | 'error'
|
|
307
416
|
|
|
308
417
|
interface Props {
|
|
@@ -318,3 +427,13 @@ interface State {
|
|
|
318
427
|
credentials: Credentials | null
|
|
319
428
|
jestConfig: JestConfigResult | null
|
|
320
429
|
}
|
|
430
|
+
|
|
431
|
+
interface PackageManager {
|
|
432
|
+
command: string
|
|
433
|
+
args: string[]
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
interface InstallResult {
|
|
437
|
+
success: boolean
|
|
438
|
+
message?: string
|
|
439
|
+
}
|