Skip to content

Commit c9fd2f4

Browse files
committed
refactor: clean up init script version check
1 parent d50c791 commit c9fd2f4

13 files changed

+417
-28
lines changed

src/utils/create-app-task-run-init-script.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { ensureTargetPath } from './ensure-target-path'
44
import { GetArgsResult } from './get-args-result'
55
import { deleteInitScript, getInitScript, InitScript } from './get-init-script'
66
import { getPackageJson } from './get-package-json'
7-
import { initCheckVersion } from './init-check-version'
7+
import { initScriptVersion } from './init-script-version'
88
import { searchAndReplace } from './search-and-replace'
99
import { Task, taskFail } from './vendor/clack-tasks'
1010
import { namesValues } from './vendor/names'
@@ -23,7 +23,7 @@ export function createAppTaskRunInitScript(args: GetArgsResult): Task {
2323
log.warn(`Running init script`)
2424
}
2525

26-
await initCheckVersion(init)
26+
await initScriptVersion(init.versions, args.verbose)
2727
if (args.verbose) {
2828
log.warn(`initCheckVersion done`)
2929
}

src/utils/get-init-script.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ export function deleteInitScript(targetDirectory: string) {
2626
writeFileSync(path, JSON.stringify(contents, undefined, 2) + '\n')
2727
}
2828

29+
const InitScriptVersionsSchema = z.object({
30+
adb: z.string().optional(),
31+
anchor: z.string().optional(),
32+
solana: z.string().optional(),
33+
})
34+
2935
const InitScriptSchema = z
3036
.object({
3137
instructions: z.array(z.string()).optional(),
@@ -37,14 +43,9 @@ const InitScriptSchema = z
3743
}),
3844
)
3945
.optional(),
40-
versions: z
41-
.object({
42-
adb: z.string().optional(),
43-
anchor: z.string().optional(),
44-
solana: z.string().optional(),
45-
})
46-
.optional(),
46+
versions: InitScriptVersionsSchema.optional(),
4747
})
4848
.optional()
4949

5050
export type InitScript = z.infer<typeof InitScriptSchema>
51+
export type InitScriptVersions = z.infer<typeof InitScriptVersionsSchema>

src/utils/init-check-version.ts

Lines changed: 0 additions & 16 deletions
This file was deleted.
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@ import { bold, yellow } from 'picocolors'
33
import { getVersion } from './get-version'
44
import { validateVersion } from './validate-version'
55

6-
export async function initCheckVersionAdb(required: string) {
6+
export async function initScriptVersionAdb(required?: string, verbose = false) {
7+
if (!required) {
8+
return
9+
}
710
try {
811
const { valid, version } = validateVersion({ required, version: getVersion('adb') })
12+
if (verbose) {
13+
log.warn(`initScriptVersionAdb: required: ${required}, version: ${version ?? '*none*'}, valid: ${valid}`)
14+
}
915
if (!version) {
1016
log.warn(
1117
[
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@ import { bold, yellow } from 'picocolors'
33
import { getVersion } from './get-version'
44
import { validateVersion } from './validate-version'
55

6-
export async function initCheckVersionAnchor(required: string) {
6+
export async function initScriptVersionAnchor(required?: string, verbose = false) {
7+
if (!required) {
8+
return
9+
}
710
try {
811
const { valid, version } = validateVersion({ required, version: getVersion('anchor') })
12+
if (verbose) {
13+
log.warn(`initScriptVersionAnchor: required: ${required}, version: ${version ?? '*none*'}, valid: ${valid}`)
14+
}
915
if (!version) {
1016
log.warn(
1117
[
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@ import { bold, yellow } from 'picocolors'
33
import { getVersion } from './get-version'
44
import { validateVersion } from './validate-version'
55

6-
export async function initCheckVersionSolana(required: string) {
6+
export async function initScriptVersionSolana(required?: string, verbose = false) {
7+
if (!required) {
8+
return
9+
}
710
try {
811
const { valid, version } = validateVersion({ required, version: getVersion('solana') })
12+
if (verbose) {
13+
log.warn(`initScriptVersionSolana: required: ${required}, version: ${version ?? '*none*'}, valid: ${valid}`)
14+
}
915
if (!version) {
1016
log.warn(
1117
[

src/utils/init-script-version.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { log } from '@clack/prompts'
2+
import { InitScriptVersions } from './get-init-script'
3+
import { initScriptVersionAdb } from './init-script-version-adb'
4+
import { initScriptVersionAnchor } from './init-script-version-anchor'
5+
import { initScriptVersionSolana } from './init-script-version-solana'
6+
7+
export async function initScriptVersion(versions?: InitScriptVersions, verbose = false) {
8+
if (!versions) {
9+
if (verbose) {
10+
log.warn(`initScriptCheckVersion: no versions found`)
11+
}
12+
return
13+
}
14+
await initScriptVersionAdb(versions.adb, verbose)
15+
await initScriptVersionAnchor(versions.anchor, verbose)
16+
await initScriptVersionSolana(versions.solana, verbose)
17+
}

test/get-version.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import * as childProcess from 'node:child_process'
2+
import { beforeEach, describe, expect, it, vi } from 'vitest'
3+
import { getVersion, versionCommands } from '../src/utils/get-version'
4+
5+
// Mock the 'node:child_process' module to control the behavior of execSync
6+
vi.mock('node:child_process', () => ({
7+
execSync: vi.fn(),
8+
}))
9+
10+
describe('versionCommands', () => {
11+
it('should have the expected commands', () => {
12+
expect(Object.keys(versionCommands)).toEqual(['adb', 'anchor', 'avm', 'rust', 'solana'])
13+
})
14+
15+
it('should have correct structure for each command', () => {
16+
for (const cmd of Object.values(versionCommands)) {
17+
expect(cmd).toHaveProperty('command', expect.any(String))
18+
expect(cmd).toHaveProperty('name', expect.any(String))
19+
expect(cmd).toHaveProperty('regex', expect.any(RegExp))
20+
}
21+
})
22+
})
23+
24+
describe('getVersion', () => {
25+
beforeEach(() => {
26+
vi.resetAllMocks()
27+
})
28+
29+
it('should return version for known command', () => {
30+
;(childProcess.execSync as any).mockReturnValue('anchor-cli 0.24.2\n')
31+
const version = getVersion('anchor')
32+
expect(version).toBe('0.24.2')
33+
expect(childProcess.execSync).toHaveBeenCalledWith('anchor --version', { stdio: ['ignore', 'pipe', 'ignore'] })
34+
})
35+
36+
it('should throw error for unknown command', () => {
37+
expect(() => getVersion('unknown' as any)).toThrow('Unknown command unknown')
38+
})
39+
40+
it('should return undefined if parsing fails', () => {
41+
;(childProcess.execSync as any).mockReturnValue('Invalid output\n')
42+
const version = getVersion('anchor')
43+
expect(version).toBeUndefined()
44+
})
45+
})
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { log } from '@clack/prompts'
2+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
3+
import { getVersion } from '../src/utils/get-version'
4+
import { initScriptVersionAdb } from '../src/utils/init-script-version-adb'
5+
import { validateVersion } from '../src/utils/validate-version'
6+
7+
// Mock the dependencies
8+
vi.mock('../src/utils/get-version')
9+
vi.mock('../src/utils/validate-version')
10+
vi.mock('@clack/prompts', () => ({
11+
log: {
12+
warn: vi.fn(),
13+
},
14+
}))
15+
16+
describe('initScriptVersionAdb', () => {
17+
beforeEach(() => {
18+
vi.resetAllMocks()
19+
})
20+
21+
afterEach(() => {
22+
vi.clearAllMocks()
23+
})
24+
25+
it('should return early if no required version is provided', async () => {
26+
await initScriptVersionAdb()
27+
expect(getVersion).not.toHaveBeenCalled()
28+
expect(validateVersion).not.toHaveBeenCalled()
29+
expect(log.warn).not.toHaveBeenCalled()
30+
})
31+
32+
it('should log warning if adb version is not found', async () => {
33+
const required = '1.0.0'
34+
vi.mocked(getVersion).mockReturnValue(undefined)
35+
vi.mocked(validateVersion).mockReturnValue({ valid: false, version: undefined })
36+
await initScriptVersionAdb(required)
37+
expect(getVersion).toHaveBeenCalledWith('adb')
38+
expect(validateVersion).toHaveBeenCalledWith({ required, version: undefined })
39+
expect(log.warn).toHaveBeenCalledWith(expect.stringContaining('Could not find adb version. Please install adb.'))
40+
})
41+
42+
it('should log warning if adb version does not satisfy the requirement', async () => {
43+
const required = '1.0.0'
44+
const version = '0.9.0'
45+
vi.mocked(getVersion).mockReturnValue(version)
46+
vi.mocked(validateVersion).mockReturnValue({ valid: false, version })
47+
await initScriptVersionAdb(required)
48+
expect(getVersion).toHaveBeenCalledWith('adb')
49+
expect(validateVersion).toHaveBeenCalledWith({ required, version })
50+
expect(log.warn).toHaveBeenCalledWith(
51+
expect.stringContaining(`Found adb version ${version}. Expected adb version ${required}.`),
52+
)
53+
})
54+
55+
it('should not log warning if adb version satisfies the requirement', async () => {
56+
const required = '1.0.0'
57+
const version = '1.0.0'
58+
vi.mocked(getVersion).mockReturnValue(version)
59+
vi.mocked(validateVersion).mockReturnValue({ valid: true, version })
60+
await initScriptVersionAdb(required)
61+
expect(getVersion).toHaveBeenCalledWith('adb')
62+
expect(validateVersion).toHaveBeenCalledWith({ required, version })
63+
expect(log.warn).not.toHaveBeenCalled()
64+
})
65+
66+
it('should log verbose message if verbose is true', async () => {
67+
const required = '1.0.0'
68+
const version = '1.0.0'
69+
vi.mocked(getVersion).mockReturnValue(version)
70+
vi.mocked(validateVersion).mockReturnValue({ valid: true, version })
71+
await initScriptVersionAdb(required, true)
72+
expect(getVersion).toHaveBeenCalledWith('adb')
73+
expect(validateVersion).toHaveBeenCalledWith({ required, version })
74+
expect(log.warn).toHaveBeenCalledWith(
75+
`initScriptVersionAdb: required: ${required}, version: ${version}, valid: true`,
76+
)
77+
})
78+
79+
it('should log error if an exception occurs', async () => {
80+
const required = '1.0.0'
81+
const error = new Error('Test error')
82+
vi.mocked(getVersion).mockImplementation(() => {
83+
throw error
84+
})
85+
await initScriptVersionAdb(required)
86+
expect(log.warn).toHaveBeenCalledWith(`Error ${error}`)
87+
})
88+
})
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { log } from '@clack/prompts'
2+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
3+
import { getVersion } from '../src/utils/get-version'
4+
import { initScriptVersionAnchor } from '../src/utils/init-script-version-anchor'
5+
import { validateVersion } from '../src/utils/validate-version'
6+
7+
// Mock the dependencies
8+
vi.mock('../src/utils/get-version')
9+
vi.mock('../src/utils/validate-version')
10+
vi.mock('@clack/prompts', () => ({
11+
log: {
12+
warn: vi.fn(),
13+
},
14+
}))
15+
16+
describe('initScriptVersionAnchor', () => {
17+
beforeEach(() => {
18+
vi.resetAllMocks()
19+
})
20+
21+
afterEach(() => {
22+
vi.clearAllMocks()
23+
})
24+
25+
it('should return early if no required version is provided', async () => {
26+
await initScriptVersionAnchor()
27+
expect(getVersion).not.toHaveBeenCalled()
28+
expect(validateVersion).not.toHaveBeenCalled()
29+
expect(log.warn).not.toHaveBeenCalled()
30+
})
31+
32+
it('should log warning if anchor version is not found', async () => {
33+
const required = '1.0.0'
34+
vi.mocked(getVersion).mockReturnValue(undefined)
35+
vi.mocked(validateVersion).mockReturnValue({ valid: false, version: undefined })
36+
await initScriptVersionAnchor(required)
37+
expect(getVersion).toHaveBeenCalledWith('anchor')
38+
expect(validateVersion).toHaveBeenCalledWith({ required, version: undefined })
39+
expect(log.warn).toHaveBeenCalledWith(
40+
expect.stringContaining('Could not find Anchor version. Please install Anchor.'),
41+
)
42+
})
43+
44+
it('should log warning if anchor version does not satisfy the requirement', async () => {
45+
const required = '1.0.0'
46+
const version = '0.9.0'
47+
vi.mocked(getVersion).mockReturnValue(version)
48+
vi.mocked(validateVersion).mockReturnValue({ valid: false, version })
49+
await initScriptVersionAnchor(required)
50+
expect(getVersion).toHaveBeenCalledWith('anchor')
51+
expect(validateVersion).toHaveBeenCalledWith({ required, version })
52+
expect(log.warn).toHaveBeenCalledWith(
53+
expect.stringContaining(`Found Anchor version ${version}. Expected Anchor version ${required}.`),
54+
)
55+
})
56+
57+
it('should not log warning if anchor version satisfies the requirement', async () => {
58+
const required = '1.0.0'
59+
const version = '1.0.0'
60+
vi.mocked(getVersion).mockReturnValue(version)
61+
vi.mocked(validateVersion).mockReturnValue({ valid: true, version })
62+
await initScriptVersionAnchor(required)
63+
expect(getVersion).toHaveBeenCalledWith('anchor')
64+
expect(validateVersion).toHaveBeenCalledWith({ required, version })
65+
expect(log.warn).not.toHaveBeenCalled()
66+
})
67+
68+
it('should log verbose message if verbose is true', async () => {
69+
const required = '1.0.0'
70+
const version = '1.0.0'
71+
vi.mocked(getVersion).mockReturnValue(version)
72+
vi.mocked(validateVersion).mockReturnValue({ valid: true, version })
73+
await initScriptVersionAnchor(required, true)
74+
expect(getVersion).toHaveBeenCalledWith('anchor')
75+
expect(validateVersion).toHaveBeenCalledWith({ required, version })
76+
expect(log.warn).toHaveBeenCalledWith(
77+
`initScriptVersionAnchor: required: ${required}, version: ${version}, valid: true`,
78+
)
79+
})
80+
81+
it('should log error if an exception occurs', async () => {
82+
const required = '1.0.0'
83+
const error = new Error('Test error')
84+
vi.mocked(getVersion).mockImplementation(() => {
85+
throw error
86+
})
87+
await initScriptVersionAnchor(required)
88+
expect(log.warn).toHaveBeenCalledWith(`Error ${error}`)
89+
})
90+
})

0 commit comments

Comments
 (0)