@guiho/mirror 3.0.0-alpha.4 → 3.0.0-alpha.8
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/jsr.json +1 -1
- package/library/cli.d.ts +4 -0
- package/library/cli.d.ts.map +1 -1
- package/library/cli.js +58 -6
- package/library/flags.d.ts.map +1 -1
- package/library/flags.js +2 -1
- package/library/guiho-mirror-bin.js +0 -0
- package/library/types.d.ts +1 -0
- package/library/types.d.ts.map +1 -1
- package/package.json +26 -28
- package/bin/mirror.exe +0 -0
- package/source/adapters.ts +0 -176
- package/source/cli.ts +0 -285
- package/source/config.ts +0 -224
- package/source/errors.ts +0 -17
- package/source/executor.ts +0 -39
- package/source/flags.ts +0 -84
- package/source/guiho-mirror-bin.ts +0 -8
- package/source/guiho-mirror.spec.ts +0 -501
- package/source/guiho-mirror.ts +0 -44
- package/source/plan.ts +0 -98
- package/source/reporter.ts +0 -127
- package/source/types.ts +0 -128
- package/source/version.ts +0 -39
|
@@ -1,501 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { afterEach, describe, expect, test } from 'bun:test'
|
|
6
|
-
import { mkdir, mkdtemp, rm } from 'node:fs/promises'
|
|
7
|
-
import { tmpdir } from 'node:os'
|
|
8
|
-
import { join } from 'node:path'
|
|
9
|
-
import {
|
|
10
|
-
applyVersionPlan,
|
|
11
|
-
buildVersionPlan,
|
|
12
|
-
loadMirrorConfig,
|
|
13
|
-
parseMirrorCliOptions,
|
|
14
|
-
readJsrName,
|
|
15
|
-
readJsrVersion,
|
|
16
|
-
readPackageName,
|
|
17
|
-
readPackageVersion,
|
|
18
|
-
renderGitTag,
|
|
19
|
-
resolveNextVersion,
|
|
20
|
-
validateMirrorConfig,
|
|
21
|
-
versionFromTag,
|
|
22
|
-
writeJsrVersion,
|
|
23
|
-
writePackageVersion,
|
|
24
|
-
} from './guiho-mirror'
|
|
25
|
-
|
|
26
|
-
const temporaryDirectories: string[] = []
|
|
27
|
-
|
|
28
|
-
afterEach(async () => {
|
|
29
|
-
await Promise.all(temporaryDirectories.splice(0).map((path) => rm(path, { recursive: true, force: true })))
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
describe('Mirror v3', () => {
|
|
33
|
-
test('parses operational and override flags', () => {
|
|
34
|
-
const options = parseMirrorCliOptions([
|
|
35
|
-
'--source',
|
|
36
|
-
'package.json',
|
|
37
|
-
'--output',
|
|
38
|
-
'package.json',
|
|
39
|
-
'--output=jsr.json,git',
|
|
40
|
-
'--package-file=custom-package.json',
|
|
41
|
-
'--jsr-file',
|
|
42
|
-
'custom-jsr.json',
|
|
43
|
-
'--preid',
|
|
44
|
-
'alpha',
|
|
45
|
-
'--dry-run',
|
|
46
|
-
'--commit',
|
|
47
|
-
'--push',
|
|
48
|
-
'--allow-dirty',
|
|
49
|
-
'--yes',
|
|
50
|
-
])
|
|
51
|
-
|
|
52
|
-
expect(options).toMatchObject({
|
|
53
|
-
source: 'package.json',
|
|
54
|
-
output: ['package.json', 'jsr.json', 'git'],
|
|
55
|
-
packageFile: 'custom-package.json',
|
|
56
|
-
jsrFile: 'custom-jsr.json',
|
|
57
|
-
preid: 'alpha',
|
|
58
|
-
dryRun: true,
|
|
59
|
-
commit: true,
|
|
60
|
-
push: true,
|
|
61
|
-
allowDirty: true,
|
|
62
|
-
yes: true,
|
|
63
|
-
})
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
test('expands short flag aliases -dy and -y', () => {
|
|
67
|
-
const options = parseMirrorCliOptions(['-dy', '-y'])
|
|
68
|
-
|
|
69
|
-
expect(options.dryRun).toBe(true)
|
|
70
|
-
expect(options.yes).toBe(true)
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
test('discovers explicit, root, and nested configs with root precedence', async () => {
|
|
74
|
-
const cwd = await createTempDir()
|
|
75
|
-
await mkdir(join(cwd, 'config'), { recursive: true })
|
|
76
|
-
await writeText(join(cwd, 'explicit.toml'), packageConfig({ output: ['jsr.json'], source: 'jsr.json' }))
|
|
77
|
-
await writeText(join(cwd, 'mirror.config.toml'), packageConfig({ output: ['package.json'] }))
|
|
78
|
-
await writeText(join(cwd, 'config', 'mirror.config.toml'), gitConfig())
|
|
79
|
-
|
|
80
|
-
const explicit = await loadMirrorConfig({ cwd, config: 'explicit.toml' })
|
|
81
|
-
const root = await loadMirrorConfig({ cwd })
|
|
82
|
-
|
|
83
|
-
await rm(join(cwd, 'mirror.config.toml'))
|
|
84
|
-
const nested = await loadMirrorConfig({ cwd })
|
|
85
|
-
|
|
86
|
-
expect(explicit.configPath).toBe(join(cwd, 'explicit.toml'))
|
|
87
|
-
expect(explicit.version.source).toBe('jsr.json')
|
|
88
|
-
expect(root.configPath).toBe(join(cwd, 'mirror.config.toml'))
|
|
89
|
-
expect(root.version.source).toBe('package.json')
|
|
90
|
-
expect(nested.configPath).toBe(join(cwd, 'config', 'mirror.config.toml'))
|
|
91
|
-
expect(nested.version.source).toBe('git')
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
test('validates schema, adapter names, project name sources, and tag templates', async () => {
|
|
95
|
-
const cwd = await createPackageAndJsrFixture()
|
|
96
|
-
|
|
97
|
-
await writeText(join(cwd, 'mirror.config.toml'), 'schema = 2\n')
|
|
98
|
-
await expect(loadMirrorConfig({ cwd })).rejects.toThrow('schema')
|
|
99
|
-
|
|
100
|
-
await writeText(join(cwd, 'mirror.config.toml'), packageConfig({ output: ['npm'] }))
|
|
101
|
-
await expect(loadMirrorConfig({ cwd })).rejects.toThrow('version.output')
|
|
102
|
-
|
|
103
|
-
await writeText(join(cwd, 'mirror.config.toml'), packageConfig({ output: ['package.json'], nameSource: 'git' }))
|
|
104
|
-
await expect(loadMirrorConfig({ cwd })).rejects.toThrow('project.name_source')
|
|
105
|
-
|
|
106
|
-
await initializeGitRepository(cwd)
|
|
107
|
-
await writeText(join(cwd, 'mirror.config.toml'), packageConfig({ output: ['git'], tagTemplate: 'release-{version}' }))
|
|
108
|
-
await expect(validateMirrorConfig({ cwd })).rejects.toThrow('Unsupported Git tag template')
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
test('merges CLI overrides over config values', async () => {
|
|
112
|
-
const cwd = await createPackageAndJsrFixture()
|
|
113
|
-
await writeText(join(cwd, 'custom-package.json'), JSON.stringify({ name: 'custom-package', version: '2.0.0' }, null, 2))
|
|
114
|
-
await writeText(join(cwd, 'custom-jsr.json'), JSON.stringify({ name: 'custom-jsr', version: '2.3.0' }, null, 2))
|
|
115
|
-
await writeText(join(cwd, 'mirror.config.toml'), packageConfig({ output: ['package.json'], preid: 'beta' }))
|
|
116
|
-
|
|
117
|
-
const config = await loadMirrorConfig({
|
|
118
|
-
cwd,
|
|
119
|
-
source: 'jsr.json',
|
|
120
|
-
output: ['jsr.json', 'git'],
|
|
121
|
-
packageFile: 'custom-package.json',
|
|
122
|
-
jsrFile: 'custom-jsr.json',
|
|
123
|
-
preid: 'alpha',
|
|
124
|
-
push: true,
|
|
125
|
-
allowDirty: true,
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
expect(config.version.source).toBe('jsr.json')
|
|
129
|
-
expect(config.version.output).toEqual(['jsr.json', 'git'])
|
|
130
|
-
expect(config.package.path).toBe('custom-package.json')
|
|
131
|
-
expect(config.jsr.path).toBe('custom-jsr.json')
|
|
132
|
-
expect(config.version.prereleaseId).toBe('alpha')
|
|
133
|
-
expect(config.git.commit).toBe(true)
|
|
134
|
-
expect(config.git.push).toBe(true)
|
|
135
|
-
expect(config.git.allowDirty).toBe(true)
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
test('reads and writes package and JSR names and versions', async () => {
|
|
139
|
-
const cwd = await createPackageAndJsrFixture()
|
|
140
|
-
await writeText(join(cwd, 'mirror.config.toml'), packageConfig({ output: ['package.json', 'jsr.json'] }))
|
|
141
|
-
const config = await loadMirrorConfig({ cwd })
|
|
142
|
-
|
|
143
|
-
expect(await readPackageName(config)).toBe('@guiho/mirror')
|
|
144
|
-
expect(await readJsrName(config)).toBe('@guiho/mirror')
|
|
145
|
-
expect(await readPackageVersion(config)).toBe('1.0.0')
|
|
146
|
-
expect(await readJsrVersion(config)).toBe('1.0.0')
|
|
147
|
-
|
|
148
|
-
await writePackageVersion(config, '1.0.1')
|
|
149
|
-
await writeJsrVersion(config, '1.0.1')
|
|
150
|
-
|
|
151
|
-
expect(await readPackageVersion(config)).toBe('1.0.1')
|
|
152
|
-
expect(await readJsrVersion(config)).toBe('1.0.1')
|
|
153
|
-
})
|
|
154
|
-
|
|
155
|
-
test('resolves semantic version targets and prerelease identifiers', () => {
|
|
156
|
-
expect(resolveNextVersion('1.0.0', 'patch')).toBe('1.0.1')
|
|
157
|
-
expect(resolveNextVersion('1.0.0', 'prepatch')).toBe('1.0.1-0')
|
|
158
|
-
expect(resolveNextVersion('1.0.0', 'prepatch', 'alpha')).toBe('1.0.1-alpha.0')
|
|
159
|
-
expect(resolveNextVersion('1.0.0', '2.3.4')).toBe('2.3.4')
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
test('extracts and renders versions with supported Git tag templates', () => {
|
|
163
|
-
expect(versionFromTag('v{version}', 'v1.2.3')).toBe('1.2.3')
|
|
164
|
-
expect(versionFromTag('{name}@{version}', '@guiho/mirror@1.2.3', '@guiho/mirror')).toBe('1.2.3')
|
|
165
|
-
expect(versionFromTag('v{version}', 'not-a-version')).toBeUndefined()
|
|
166
|
-
expect(renderGitTag('v{version}', '1.2.3')).toBe('v1.2.3')
|
|
167
|
-
expect(renderGitTag('{name}@{version}', '1.2.3', '@guiho/mirror')).toBe('@guiho/mirror@1.2.3')
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
test('plans package and JSR file outputs', async () => {
|
|
171
|
-
const cwd = await createPackageAndJsrFixture()
|
|
172
|
-
await writeText(join(cwd, 'mirror.config.toml'), packageConfig({ output: ['package.json', 'jsr.json'] }))
|
|
173
|
-
|
|
174
|
-
const plan = await buildVersionPlan('patch', { cwd })
|
|
175
|
-
|
|
176
|
-
expect(plan.currentVersion).toBe('1.0.0')
|
|
177
|
-
expect(plan.nextVersion).toBe('1.0.1')
|
|
178
|
-
expect(plan.actions.map((action) => action.type)).toEqual(['write-file', 'write-file'])
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
test('applies package and JSR file outputs outside Git', async () => {
|
|
182
|
-
const cwd = await createPackageAndJsrFixture()
|
|
183
|
-
await writeText(join(cwd, 'mirror.config.toml'), packageConfig({ output: ['package.json', 'jsr.json'] }))
|
|
184
|
-
|
|
185
|
-
const result = await applyVersionPlan('minor', { cwd, yes: true })
|
|
186
|
-
|
|
187
|
-
expect(result.applied).toBe(true)
|
|
188
|
-
expect(await readPackageVersion(await loadMirrorConfig({ cwd }))).toBe('1.1.0')
|
|
189
|
-
expect(await readJsrVersion(await loadMirrorConfig({ cwd }))).toBe('1.1.0')
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
test('dry-run apply does not mutate files and does not require confirmation', async () => {
|
|
193
|
-
const cwd = await createPackageAndJsrFixture()
|
|
194
|
-
await writeText(join(cwd, 'mirror.config.toml'), packageConfig({ output: ['package.json'] }))
|
|
195
|
-
|
|
196
|
-
const result = await applyVersionPlan('patch', { cwd, dryRun: true })
|
|
197
|
-
|
|
198
|
-
expect(result.applied).toBe(false)
|
|
199
|
-
expect(result.dryRun).toBe(true)
|
|
200
|
-
expect(await readPackageVersion(await loadMirrorConfig({ cwd }))).toBe('1.0.0')
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
test('reads the current version from matching Git tags', async () => {
|
|
204
|
-
const cwd = await createGitFixture()
|
|
205
|
-
await git(cwd, 'tag', 'v1.0.0')
|
|
206
|
-
await git(cwd, 'tag', 'v1.2.0')
|
|
207
|
-
await writeText(join(cwd, 'mirror.config.toml'), gitConfig())
|
|
208
|
-
|
|
209
|
-
const plan = await buildVersionPlan('patch', { cwd })
|
|
210
|
-
|
|
211
|
-
expect(plan.currentVersion).toBe('1.2.0')
|
|
212
|
-
expect(plan.nextVersion).toBe('1.2.1')
|
|
213
|
-
expect(plan.gitTag).toBe('v1.2.1')
|
|
214
|
-
})
|
|
215
|
-
|
|
216
|
-
test('requires commit or push when file outputs and Git tag output are combined', async () => {
|
|
217
|
-
const cwd = await createPackageAndJsrFixture()
|
|
218
|
-
await initializeGitRepository(cwd)
|
|
219
|
-
await writeText(join(cwd, 'mirror.config.toml'), packageConfig({ output: ['package.json', 'git'] }))
|
|
220
|
-
|
|
221
|
-
await expect(buildVersionPlan('patch', { cwd })).rejects.toThrow('requires --commit or --push')
|
|
222
|
-
|
|
223
|
-
const packageJson = await Bun.file(join(cwd, 'package.json')).json()
|
|
224
|
-
expect(packageJson.version).toBe('1.0.0')
|
|
225
|
-
})
|
|
226
|
-
|
|
227
|
-
test('fails on dirty Git worktrees unless allow-dirty is set', async () => {
|
|
228
|
-
const cwd = await createPackageAndJsrFixture()
|
|
229
|
-
await initializeGitRepository(cwd)
|
|
230
|
-
await writeText(join(cwd, 'mirror.config.toml'), packageConfig({ output: ['package.json'] }))
|
|
231
|
-
await commitAll(cwd, 'Add Mirror config')
|
|
232
|
-
await writeText(join(cwd, 'README.md'), '# dirty fixture\n')
|
|
233
|
-
|
|
234
|
-
await expect(applyVersionPlan('patch', { cwd, yes: true })).rejects.toThrow('dirty')
|
|
235
|
-
expect(await readPackageVersion(await loadMirrorConfig({ cwd }))).toBe('1.0.0')
|
|
236
|
-
|
|
237
|
-
const result = await applyVersionPlan('patch', { cwd, yes: true, allowDirty: true })
|
|
238
|
-
expect(result.applied).toBe(true)
|
|
239
|
-
expect(await readPackageVersion(await loadMirrorConfig({ cwd }))).toBe('1.0.1')
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
test('applies file output, release commit, and Git tag with --commit', async () => {
|
|
243
|
-
const cwd = await createPackageAndJsrFixture()
|
|
244
|
-
await initializeGitRepository(cwd)
|
|
245
|
-
await writeText(join(cwd, 'mirror.config.toml'), packageConfig({ output: ['package.json', 'git'] }))
|
|
246
|
-
await commitAll(cwd, 'Add Mirror config')
|
|
247
|
-
|
|
248
|
-
const result = await applyVersionPlan('patch', { cwd, commit: true, yes: true })
|
|
249
|
-
|
|
250
|
-
expect(result.applied).toBe(true)
|
|
251
|
-
expect(await readPackageVersion(await loadMirrorConfig({ cwd }))).toBe('1.0.1')
|
|
252
|
-
expect((await gitText(cwd, 'tag', '--list')).trim()).toBe('@guiho/mirror@1.0.1')
|
|
253
|
-
expect((await gitText(cwd, 'status', '--porcelain')).trim()).toBe('')
|
|
254
|
-
})
|
|
255
|
-
|
|
256
|
-
test('push implies commit and pushes the release tag', async () => {
|
|
257
|
-
const remote = await createBareGitRepository()
|
|
258
|
-
const cwd = await createPackageAndJsrFixture()
|
|
259
|
-
await initializeGitRepository(cwd)
|
|
260
|
-
await git(cwd, 'remote', 'add', 'origin', remote)
|
|
261
|
-
await git(cwd, 'push', '-u', 'origin', 'HEAD')
|
|
262
|
-
await writeText(join(cwd, 'mirror.config.toml'), packageConfig({ output: ['package.json', 'git'] }))
|
|
263
|
-
await commitAll(cwd, 'Add Mirror config')
|
|
264
|
-
|
|
265
|
-
const result = await applyVersionPlan('patch', { cwd, push: true, yes: true })
|
|
266
|
-
|
|
267
|
-
expect(result.plan.commitEnabled).toBe(true)
|
|
268
|
-
expect(result.plan.pushEnabled).toBe(true)
|
|
269
|
-
expect((await gitText(remote, 'tag', '--list')).trim()).toBe('@guiho/mirror@1.0.1')
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
test('git-only releases with --commit create tags without empty commits', async () => {
|
|
273
|
-
const cwd = await createGitFixture()
|
|
274
|
-
await git(cwd, 'tag', 'v1.0.0')
|
|
275
|
-
await writeText(join(cwd, 'mirror.config.toml'), gitConfig())
|
|
276
|
-
await commitAll(cwd, 'Add Mirror config')
|
|
277
|
-
const commitsBefore = (await gitText(cwd, 'rev-list', '--count', 'HEAD')).trim()
|
|
278
|
-
|
|
279
|
-
const result = await applyVersionPlan('patch', { cwd, commit: true, yes: true })
|
|
280
|
-
|
|
281
|
-
expect(result.applied).toBe(true)
|
|
282
|
-
expect((await gitText(cwd, 'rev-list', '--count', 'HEAD')).trim()).toBe(commitsBefore)
|
|
283
|
-
expect((await gitText(cwd, 'tag', '--list')).trim().split(/\r?\n/).sort()).toEqual(['v1.0.0', 'v1.0.1'])
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
test('runs CLI config show and config check', async () => {
|
|
287
|
-
const cwd = await createGitFixture()
|
|
288
|
-
await writeText(join(cwd, 'mirror.config.toml'), gitConfig())
|
|
289
|
-
|
|
290
|
-
const show = await runMirrorCli('config', 'show', '--cwd', cwd)
|
|
291
|
-
const check = await runMirrorCli('config', 'check', '--cwd', cwd)
|
|
292
|
-
|
|
293
|
-
expect(show.exitCode).toBe(0)
|
|
294
|
-
expect(show.stdout).toContain('source: git')
|
|
295
|
-
expect(check.exitCode).toBe(0)
|
|
296
|
-
expect(check.stdout.trim()).toBe('ok')
|
|
297
|
-
})
|
|
298
|
-
|
|
299
|
-
test('runs the top-level CLI as successful help output', async () => {
|
|
300
|
-
const result = await runMirrorCli()
|
|
301
|
-
|
|
302
|
-
expect(result.exitCode).toBe(0)
|
|
303
|
-
expect(result.stdout).toMatch(/mirror v\d+\.\d+\.\d+/)
|
|
304
|
-
expect(result.stdout).toContain('USAGE')
|
|
305
|
-
})
|
|
306
|
-
|
|
307
|
-
test('runs CLI help without ANSI colors when no-color is set', async () => {
|
|
308
|
-
const result = await runMirrorCli('--no-color', '--help')
|
|
309
|
-
|
|
310
|
-
expect(result.exitCode).toBe(0)
|
|
311
|
-
expect(result.stdout).toContain('USAGE')
|
|
312
|
-
expect(result.stdout).not.toContain('\u001B[')
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
test('runs CLI version current, next, plan, and apply', async () => {
|
|
316
|
-
const cwd = await createPackageAndJsrFixture()
|
|
317
|
-
await writeText(join(cwd, 'mirror.config.toml'), packageConfig({ output: ['package.json'] }))
|
|
318
|
-
|
|
319
|
-
const current = await runMirrorCli('version', 'current', '--cwd', cwd)
|
|
320
|
-
const next = await runMirrorCli('version', 'next', 'patch', '--cwd', cwd)
|
|
321
|
-
const plan = await runMirrorCli('version', 'plan', 'patch', '--cwd', cwd)
|
|
322
|
-
const apply = await runMirrorCli('version', 'apply', 'patch', '--cwd', cwd, '--yes')
|
|
323
|
-
|
|
324
|
-
expect(current.exitCode).toBe(0)
|
|
325
|
-
expect(current.stdout.trim()).toBe('1.0.0')
|
|
326
|
-
expect(next.exitCode).toBe(0)
|
|
327
|
-
expect(next.stdout.trim()).toBe('1.0.1')
|
|
328
|
-
expect(plan.exitCode).toBe(0)
|
|
329
|
-
expect(plan.stdout).toContain('next: 1.0.1')
|
|
330
|
-
expect(apply.exitCode).toBe(0)
|
|
331
|
-
expect(apply.stdout).toContain('next: 1.0.1')
|
|
332
|
-
expect(apply.stdout).toContain('applied: true')
|
|
333
|
-
expect(await readPackageVersion(await loadMirrorConfig({ cwd }))).toBe('1.0.1')
|
|
334
|
-
})
|
|
335
|
-
|
|
336
|
-
test('runs CLI source and repeated output overrides', async () => {
|
|
337
|
-
const cwd = await createPackageAndJsrFixture()
|
|
338
|
-
await writeText(join(cwd, 'mirror.config.toml'), packageConfig({ output: ['package.json'] }))
|
|
339
|
-
|
|
340
|
-
const result = await runMirrorCli(
|
|
341
|
-
'version',
|
|
342
|
-
'plan',
|
|
343
|
-
'patch',
|
|
344
|
-
'--cwd',
|
|
345
|
-
cwd,
|
|
346
|
-
'--source',
|
|
347
|
-
'package.json',
|
|
348
|
-
'--output',
|
|
349
|
-
'package.json',
|
|
350
|
-
'--output',
|
|
351
|
-
'jsr.json',
|
|
352
|
-
)
|
|
353
|
-
|
|
354
|
-
expect(result.exitCode).toBe(0)
|
|
355
|
-
expect(result.stdout).toContain('output: package.json, jsr.json')
|
|
356
|
-
expect(result.stdout).toContain('next: 1.0.1')
|
|
357
|
-
})
|
|
358
|
-
})
|
|
359
|
-
|
|
360
|
-
const createTempDir = async () => {
|
|
361
|
-
const path = await mkdtemp(join(tmpdir(), 'guiho-mirror-'))
|
|
362
|
-
temporaryDirectories.push(path)
|
|
363
|
-
return path
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
const createPackageAndJsrFixture = async () => {
|
|
367
|
-
const cwd = await createTempDir()
|
|
368
|
-
await writeJson(join(cwd, 'package.json'), {
|
|
369
|
-
name: '@guiho/mirror',
|
|
370
|
-
version: '1.0.0',
|
|
371
|
-
})
|
|
372
|
-
await writeJson(join(cwd, 'jsr.json'), {
|
|
373
|
-
name: '@guiho/mirror',
|
|
374
|
-
version: '1.0.0',
|
|
375
|
-
exports: './source/guiho-mirror.ts',
|
|
376
|
-
})
|
|
377
|
-
return cwd
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
const createGitFixture = async () => {
|
|
381
|
-
const cwd = await createTempDir()
|
|
382
|
-
await initializeGitRepository(cwd)
|
|
383
|
-
return cwd
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
const createBareGitRepository = async () => {
|
|
387
|
-
const cwd = await createTempDir()
|
|
388
|
-
await git(cwd, 'init', '--bare')
|
|
389
|
-
return cwd
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
const initializeGitRepository = async (cwd: string) => {
|
|
393
|
-
await git(cwd, 'init')
|
|
394
|
-
await git(cwd, 'config', 'user.email', 'mirror@example.com')
|
|
395
|
-
await git(cwd, 'config', 'user.name', 'Mirror Test')
|
|
396
|
-
await writeText(join(cwd, 'README.md'), '# fixture\n')
|
|
397
|
-
await git(cwd, 'add', '.')
|
|
398
|
-
await git(cwd, 'commit', '-m', 'Initial commit')
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const commitAll = async (cwd: string, message: string) => {
|
|
402
|
-
await git(cwd, 'add', '.')
|
|
403
|
-
await git(cwd, 'commit', '-m', message)
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
const writeText = async (path: string, content: string) => {
|
|
407
|
-
await Bun.write(path, content)
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
const writeJson = async (path: string, object: Record<string, unknown>) => {
|
|
411
|
-
await writeText(path, `${JSON.stringify(object, null, 2)}\n`)
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
const packageConfig = ({
|
|
415
|
-
output,
|
|
416
|
-
source = 'package.json',
|
|
417
|
-
nameSource = 'package.json',
|
|
418
|
-
tagTemplate = '{name}@{version}',
|
|
419
|
-
preid = '',
|
|
420
|
-
}: {
|
|
421
|
-
output: string[]
|
|
422
|
-
source?: string
|
|
423
|
-
nameSource?: string
|
|
424
|
-
tagTemplate?: string
|
|
425
|
-
preid?: string
|
|
426
|
-
}) => `schema = 1
|
|
427
|
-
|
|
428
|
-
[project]
|
|
429
|
-
name_source = "${nameSource}"
|
|
430
|
-
|
|
431
|
-
[version]
|
|
432
|
-
scheme = "semver"
|
|
433
|
-
source = "${source}"
|
|
434
|
-
output = [${output.map((value) => `"${value}"`).join(', ')}]
|
|
435
|
-
prerelease_id = "${preid}"
|
|
436
|
-
|
|
437
|
-
[package]
|
|
438
|
-
path = "package.json"
|
|
439
|
-
|
|
440
|
-
[jsr]
|
|
441
|
-
path = "jsr.json"
|
|
442
|
-
|
|
443
|
-
[git]
|
|
444
|
-
tag_template = "${tagTemplate}"
|
|
445
|
-
commit = false
|
|
446
|
-
push = false
|
|
447
|
-
allow_dirty = false
|
|
448
|
-
`
|
|
449
|
-
|
|
450
|
-
const gitConfig = () => `schema = 1
|
|
451
|
-
|
|
452
|
-
[project]
|
|
453
|
-
name = "fixture"
|
|
454
|
-
|
|
455
|
-
[version]
|
|
456
|
-
scheme = "semver"
|
|
457
|
-
source = "git"
|
|
458
|
-
output = ["git"]
|
|
459
|
-
prerelease_id = ""
|
|
460
|
-
|
|
461
|
-
[git]
|
|
462
|
-
tag_template = "v{version}"
|
|
463
|
-
commit = false
|
|
464
|
-
push = false
|
|
465
|
-
allow_dirty = false
|
|
466
|
-
`
|
|
467
|
-
|
|
468
|
-
const git = async (cwd: string, ...args: string[]) => {
|
|
469
|
-
const result = Bun.spawn(['git', ...args], { cwd, stdout: 'pipe', stderr: 'pipe' })
|
|
470
|
-
const exitCode = await result.exited
|
|
471
|
-
|
|
472
|
-
if (exitCode !== 0) {
|
|
473
|
-
// @ts-expect-error
|
|
474
|
-
throw new Error(`git ${args.join(' ')} failed: ${await result.stderr.text()}`)
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
const gitText = async (cwd: string, ...args: string[]) => {
|
|
479
|
-
const result = Bun.spawn(['git', ...args], { cwd, stdout: 'pipe', stderr: 'pipe' })
|
|
480
|
-
const exitCode = await result.exited
|
|
481
|
-
// @ts-expect-error
|
|
482
|
-
const stdout = await result.stdout.text()
|
|
483
|
-
|
|
484
|
-
if (exitCode !== 0) {
|
|
485
|
-
// @ts-expect-error
|
|
486
|
-
throw new Error(`git ${args.join(' ')} failed: ${await result.stderr.text()}`)
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
return stdout
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
const runMirrorCli = async (...args: string[]) => {
|
|
493
|
-
const result = Bun.spawn(['bun', join(import.meta.dir, 'guiho-mirror-bin.ts'), ...args], {
|
|
494
|
-
stdout: 'pipe',
|
|
495
|
-
stderr: 'pipe',
|
|
496
|
-
})
|
|
497
|
-
// @ts-expect-error
|
|
498
|
-
const [exitCode, stdout, stderr] = await Promise.all([result.exited, result.stdout.text(), result.stderr.text()])
|
|
499
|
-
|
|
500
|
-
return { exitCode, stdout, stderr }
|
|
501
|
-
}
|
package/source/guiho-mirror.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export type {
|
|
6
|
-
MirrorAdapterName,
|
|
7
|
-
MirrorCliOptions,
|
|
8
|
-
MirrorConfig,
|
|
9
|
-
MirrorExecutionResult,
|
|
10
|
-
MirrorFormat,
|
|
11
|
-
MirrorRawConfig,
|
|
12
|
-
MirrorVersionPlan,
|
|
13
|
-
MirrorVersionPlanAction,
|
|
14
|
-
MirrorVersionTarget,
|
|
15
|
-
} from './types'
|
|
16
|
-
|
|
17
|
-
export { MirrorError, invariant } from './errors'
|
|
18
|
-
export { parseMirrorCliOptions } from './flags'
|
|
19
|
-
export { createInitConfig, discoverMirrorConfig, loadMirrorConfig, normalizeMirrorConfig, writeInitConfig } from './config'
|
|
20
|
-
export { assertValidSemver, isMirrorReleaseTarget, mirrorReleaseTargets, resolveNextVersion, sortSemverDescending } from './version'
|
|
21
|
-
export {
|
|
22
|
-
createGitCommit,
|
|
23
|
-
createGitTag,
|
|
24
|
-
ensureAdapterFiles,
|
|
25
|
-
assertSupportedGitTagTemplate,
|
|
26
|
-
isGitDirty,
|
|
27
|
-
isGitRepository,
|
|
28
|
-
readCurrentVersion,
|
|
29
|
-
readGitVersion,
|
|
30
|
-
readJsrName,
|
|
31
|
-
readJsrVersion,
|
|
32
|
-
readPackageName,
|
|
33
|
-
readPackageVersion,
|
|
34
|
-
renderGitTag,
|
|
35
|
-
resolveProjectName,
|
|
36
|
-
supportedGitTagTemplates,
|
|
37
|
-
versionFromTag,
|
|
38
|
-
writeJsrVersion,
|
|
39
|
-
writePackageVersion,
|
|
40
|
-
} from './adapters'
|
|
41
|
-
export { buildVersionPlan, releaseLabel, resolveFileOutputPaths, validateMirrorConfig } from './plan'
|
|
42
|
-
export { applyVersionPlan, executeVersionPlan } from './executor'
|
|
43
|
-
export { mirrorBanner, reportConfig, reportConfigSchema, reportExecution, reportExecutionSummary, reportPlan, reportValue } from './reporter'
|
|
44
|
-
export { createMirrorCommand, runMirrorCli } from './cli'
|
package/source/plan.ts
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { relative } from 'node:path'
|
|
6
|
-
import type { MirrorCliOptions, MirrorConfig, MirrorVersionPlan, MirrorVersionPlanAction } from './types'
|
|
7
|
-
import { MirrorError } from './errors'
|
|
8
|
-
import { loadMirrorConfig, relativeFromCwd, resolveMirrorPath } from './config'
|
|
9
|
-
import { ensureAdapterFiles, readCurrentVersion, renderGitTag, resolveProjectName } from './adapters'
|
|
10
|
-
import { resolveNextVersion } from './version'
|
|
11
|
-
|
|
12
|
-
export const validateMirrorConfig = async (options: MirrorCliOptions = {}): Promise<MirrorConfig> => {
|
|
13
|
-
const config = await loadMirrorConfig(options)
|
|
14
|
-
await ensureAdapterFiles(config)
|
|
15
|
-
|
|
16
|
-
const projectName = await resolveProjectName(config)
|
|
17
|
-
|
|
18
|
-
if (config.version.source === 'git' || config.version.output.includes('git')) {
|
|
19
|
-
renderGitTag(config.git.tagTemplate, '0.0.0', projectName)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return config
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const buildVersionPlan = async (target: string, options: MirrorCliOptions = {}): Promise<MirrorVersionPlan> => {
|
|
26
|
-
const config = await validateMirrorConfig(options)
|
|
27
|
-
|
|
28
|
-
const projectName = await resolveProjectName(config)
|
|
29
|
-
const currentVersion = await readCurrentVersion(config, projectName)
|
|
30
|
-
const nextVersion = resolveNextVersion(currentVersion, target, config.version.prereleaseId)
|
|
31
|
-
const fileOutputPaths = resolveFileOutputPaths(config)
|
|
32
|
-
const commitEnabled = config.git.commit
|
|
33
|
-
const pushEnabled = config.git.push
|
|
34
|
-
const actions: MirrorVersionPlanAction[] = []
|
|
35
|
-
|
|
36
|
-
for (const path of fileOutputPaths) {
|
|
37
|
-
actions.push({
|
|
38
|
-
type: 'write-file',
|
|
39
|
-
adapter: path.endsWith(config.package.path) ? 'package.json' : 'jsr.json',
|
|
40
|
-
path,
|
|
41
|
-
currentVersion,
|
|
42
|
-
nextVersion,
|
|
43
|
-
})
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const gitTag = config.version.output.includes('git') ? renderGitTag(config.git.tagTemplate, nextVersion, projectName) : undefined
|
|
47
|
-
|
|
48
|
-
if (fileOutputPaths.length > 0 && gitTag && !commitEnabled && !pushEnabled) {
|
|
49
|
-
throw new MirrorError('Git tag output with file outputs requires --commit or --push so the tag points at the version commit.')
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (commitEnabled && fileOutputPaths.length > 0) {
|
|
53
|
-
actions.push({
|
|
54
|
-
type: 'git-commit',
|
|
55
|
-
message: releaseLabel(nextVersion, projectName),
|
|
56
|
-
paths: fileOutputPaths.map((path) => relative(config.cwd, path)),
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (gitTag) actions.push({ type: 'git-tag', tag: gitTag })
|
|
61
|
-
|
|
62
|
-
if (pushEnabled) {
|
|
63
|
-
actions.push({
|
|
64
|
-
type: 'git-push',
|
|
65
|
-
includeCommit: fileOutputPaths.length > 0,
|
|
66
|
-
includeTags: Boolean(gitTag),
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
cwd: config.cwd,
|
|
72
|
-
configPath: config.configPath,
|
|
73
|
-
source: config.version.source,
|
|
74
|
-
output: config.version.output,
|
|
75
|
-
currentVersion,
|
|
76
|
-
nextVersion,
|
|
77
|
-
project: { name: projectName },
|
|
78
|
-
commitEnabled,
|
|
79
|
-
pushEnabled,
|
|
80
|
-
allowDirty: config.git.allowDirty,
|
|
81
|
-
fileOutputPaths,
|
|
82
|
-
gitTag,
|
|
83
|
-
actions,
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export const resolveFileOutputPaths = (config: MirrorConfig) => {
|
|
88
|
-
const paths: string[] = []
|
|
89
|
-
|
|
90
|
-
if (config.version.output.includes('package.json')) paths.push(resolveMirrorPath(config.cwd, config.package.path))
|
|
91
|
-
if (config.version.output.includes('jsr.json')) paths.push(resolveMirrorPath(config.cwd, config.jsr.path))
|
|
92
|
-
|
|
93
|
-
return paths
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export const releaseLabel = (version: string, projectName?: string) => (projectName ? `${projectName}@${version}` : `v${version}`)
|
|
97
|
-
|
|
98
|
-
export const planPathForDisplay = (plan: MirrorVersionPlan, path: string) => relativeFromCwd(plan.cwd, path)
|