@take-out/scripts 0.0.92 ā 0.0.94
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/package.json +4 -2
- package/src/build-initial.ts +76 -81
- package/src/clean.ts +21 -21
- package/src/cmd.ts +82 -0
- package/src/dev-tunnel.ts +138 -159
- package/src/ensure-port.ts +62 -70
- package/src/ensure-tunnel.ts +13 -9
- package/src/env-pull.ts +49 -47
- package/src/env-update.ts +143 -175
- package/src/exec-with-env.ts +14 -11
- package/src/helpers/args.ts +4 -4
- package/src/helpers/get-test-env.ts +5 -3
- package/src/node-version-check.ts +9 -5
- package/src/release.ts +439 -394
- package/src/sst-get-environment.ts +5 -1
- package/src/typecheck.ts +19 -16
- package/src/up.ts +355 -374
- package/src/update-changelog.ts +39 -43
- package/src/update-local-env.ts +139 -158
- package/src/wait-for-dev.ts +21 -20
package/src/up.ts
CHANGED
|
@@ -1,66 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
* @description Upgrade packages by name (takeout, tamagui, one, zero, better-auth)
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
8
|
-
import { join } from 'node:path'
|
|
9
|
-
|
|
10
|
-
import { $ } from 'bun'
|
|
11
|
-
|
|
12
|
-
let globalTag: string | undefined
|
|
13
|
-
const packagePatterns: string[] = []
|
|
14
|
-
|
|
15
|
-
const args = process.argv.slice(2)
|
|
16
|
-
|
|
17
|
-
// check if first arg is a named upgrade set
|
|
18
|
-
const rootDir = process.cwd()
|
|
19
|
-
const rootPackageJson = JSON.parse(readFileSync(join(rootDir, 'package.json'), 'utf-8'))
|
|
20
|
-
const upgradeSets: Record<string, string[]> = rootPackageJson.upgradeSets || {}
|
|
21
|
-
|
|
22
|
-
for (let i = 0; i < args.length; i++) {
|
|
23
|
-
const arg = args[i]!
|
|
24
|
-
if (arg.startsWith('--tag=')) {
|
|
25
|
-
const tagValue = arg.split('=')[1]
|
|
26
|
-
if (tagValue) {
|
|
27
|
-
globalTag = tagValue
|
|
28
|
-
} else {
|
|
29
|
-
console.error('Error: --tag option requires a value. Example: --tag=canary')
|
|
30
|
-
process.exit(1)
|
|
31
|
-
}
|
|
32
|
-
} else if (arg === '--tag') {
|
|
33
|
-
console.error('Error: --tag option requires a value and must use = syntax.')
|
|
34
|
-
console.error('Correct usage: --tag=canary')
|
|
35
|
-
console.error('Example: bun tko up --tag=canary react react-dom')
|
|
36
|
-
process.exit(1)
|
|
37
|
-
} else if (arg === '--canary') {
|
|
38
|
-
globalTag = 'canary'
|
|
39
|
-
} else if (arg === '--rc') {
|
|
40
|
-
globalTag = 'rc'
|
|
41
|
-
} else if (arg in upgradeSets) {
|
|
42
|
-
// expand named upgrade set to its patterns
|
|
43
|
-
packagePatterns.push(...upgradeSets[arg]!)
|
|
44
|
-
} else {
|
|
45
|
-
packagePatterns.push(arg)
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (packagePatterns.length === 0) {
|
|
50
|
-
const setNames = Object.keys(upgradeSets)
|
|
51
|
-
if (setNames.length > 0) {
|
|
52
|
-
console.info('Usage: bun tko up <target|pattern> [options]')
|
|
53
|
-
console.info(`\nAvailable upgrade sets: ${setNames.join(', ')}`)
|
|
54
|
-
console.info('\nOr provide package patterns directly:')
|
|
55
|
-
console.info(' bun tko up @vxrn/* vxrn')
|
|
56
|
-
console.info(' bun tko up --tag=canary react react-dom')
|
|
57
|
-
} else {
|
|
58
|
-
console.error('Please provide at least one package pattern to update.')
|
|
59
|
-
console.error('Example: bun tko up @vxrn/* vxrn')
|
|
60
|
-
console.error('Or with a tag: bun tko up --tag=canary @vxrn/* vxrn')
|
|
61
|
-
}
|
|
62
|
-
process.exit(1)
|
|
63
|
-
}
|
|
3
|
+
import { cmd } from './cmd'
|
|
64
4
|
|
|
65
5
|
interface PackageJson {
|
|
66
6
|
dependencies?: Record<string, string>
|
|
@@ -69,383 +9,424 @@ interface PackageJson {
|
|
|
69
9
|
optionalDependencies?: Record<string, string>
|
|
70
10
|
}
|
|
71
11
|
|
|
72
|
-
|
|
73
|
-
|
|
12
|
+
await cmd`upgrade packages by name or pattern`
|
|
13
|
+
.args('--tag string --canary boolean --rc boolean')
|
|
14
|
+
.run(async ({ args, $, path, fs }) => {
|
|
15
|
+
const { existsSync, readdirSync, readFileSync, writeFileSync, rmSync } =
|
|
16
|
+
await import('node:fs')
|
|
17
|
+
|
|
18
|
+
let globalTag: string | undefined = args.tag
|
|
19
|
+
if (args.canary) globalTag = 'canary'
|
|
20
|
+
if (args.rc) globalTag = 'rc'
|
|
21
|
+
|
|
22
|
+
const packagePatterns: string[] = []
|
|
23
|
+
const rootDir = process.cwd()
|
|
24
|
+
const rootPackageJson = JSON.parse(readFileSync(path.join(rootDir, 'package.json'), 'utf-8'))
|
|
25
|
+
const upgradeSets: Record<string, string[]> = rootPackageJson.upgradeSets || {}
|
|
26
|
+
|
|
27
|
+
for (const arg of args.rest) {
|
|
28
|
+
if (arg in upgradeSets) {
|
|
29
|
+
// expand named upgrade set to its patterns
|
|
30
|
+
packagePatterns.push(...upgradeSets[arg]!)
|
|
31
|
+
} else {
|
|
32
|
+
packagePatterns.push(arg)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
74
35
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
36
|
+
if (packagePatterns.length === 0) {
|
|
37
|
+
const setNames = Object.keys(upgradeSets)
|
|
38
|
+
if (setNames.length > 0) {
|
|
39
|
+
console.info('Usage: bun tko up <target|pattern> [options]')
|
|
40
|
+
console.info(`\nAvailable upgrade sets: ${setNames.join(', ')}`)
|
|
41
|
+
console.info('\nOr provide package patterns directly:')
|
|
42
|
+
console.info(' bun tko up @vxrn/* vxrn')
|
|
43
|
+
console.info(' bun tko up --tag canary react react-dom')
|
|
44
|
+
} else {
|
|
45
|
+
console.error('Please provide at least one package pattern to update.')
|
|
46
|
+
console.error('Example: bun tko up @vxrn/* vxrn')
|
|
47
|
+
console.error('Or with a tag: bun tko up --tag canary @vxrn/* vxrn')
|
|
48
|
+
}
|
|
49
|
+
process.exit(1)
|
|
50
|
+
}
|
|
78
51
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const packageJson = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf-8'))
|
|
82
|
-
if (packageJson.workspaces) {
|
|
83
|
-
let workspacePaths: string[] = []
|
|
52
|
+
function findPackageJsonFiles(dir: string): string[] {
|
|
53
|
+
const results: string[] = []
|
|
84
54
|
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
} else if (packageJson.workspaces.packages) {
|
|
88
|
-
workspacePaths = packageJson.workspaces.packages
|
|
55
|
+
if (existsSync(path.join(dir, 'package.json'))) {
|
|
56
|
+
results.push(path.join(dir, 'package.json'))
|
|
89
57
|
}
|
|
90
58
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
59
|
+
// check if it's a monorepo with workspaces
|
|
60
|
+
try {
|
|
61
|
+
const packageJson = JSON.parse(
|
|
62
|
+
readFileSync(path.join(dir, 'package.json'), 'utf-8')
|
|
63
|
+
)
|
|
64
|
+
if (packageJson.workspaces) {
|
|
65
|
+
let workspacePaths: string[] = []
|
|
66
|
+
|
|
67
|
+
if (Array.isArray(packageJson.workspaces)) {
|
|
68
|
+
workspacePaths = packageJson.workspaces
|
|
69
|
+
} else if (packageJson.workspaces.packages) {
|
|
70
|
+
workspacePaths = packageJson.workspaces.packages
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
for (const workspace of workspacePaths) {
|
|
74
|
+
// handle glob patterns like "packages/*", "code/**/*", "./code/ui/**/*"
|
|
75
|
+
const normalizedWorkspace = workspace.replace(/^\.\//, '')
|
|
76
|
+
|
|
77
|
+
if (normalizedWorkspace.includes('**')) {
|
|
78
|
+
// nested glob pattern - use glob to find all package.json files
|
|
79
|
+
const baseDir = normalizedWorkspace.split('**')[0]!.replace(/\/$/, '')
|
|
80
|
+
const basePath = path.join(dir, baseDir)
|
|
81
|
+
|
|
82
|
+
if (existsSync(basePath)) {
|
|
83
|
+
const findPackages = (searchDir: string) => {
|
|
84
|
+
try {
|
|
85
|
+
const entries = readdirSync(searchDir, { withFileTypes: true })
|
|
86
|
+
for (const entry of entries) {
|
|
87
|
+
if (entry.isDirectory() && entry.name !== 'node_modules') {
|
|
88
|
+
const subPath = path.join(searchDir, entry.name)
|
|
89
|
+
const pkgPath = path.join(subPath, 'package.json')
|
|
90
|
+
if (existsSync(pkgPath)) {
|
|
91
|
+
results.push(pkgPath)
|
|
92
|
+
}
|
|
93
|
+
// recurse into subdirectories
|
|
94
|
+
findPackages(subPath)
|
|
95
|
+
}
|
|
110
96
|
}
|
|
111
|
-
|
|
112
|
-
|
|
97
|
+
} catch (_e) {
|
|
98
|
+
// ignore permission errors
|
|
113
99
|
}
|
|
114
100
|
}
|
|
115
|
-
|
|
116
|
-
// ignore permission errors
|
|
101
|
+
findPackages(basePath)
|
|
117
102
|
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
103
|
+
} else if (normalizedWorkspace.includes('*')) {
|
|
104
|
+
// simple glob pattern like "packages/*"
|
|
105
|
+
const workspaceDir = normalizedWorkspace.replace(/\/\*$/, '')
|
|
106
|
+
if (existsSync(path.join(dir, workspaceDir))) {
|
|
107
|
+
const subdirs = readdirSync(path.join(dir, workspaceDir), {
|
|
108
|
+
withFileTypes: true,
|
|
109
|
+
})
|
|
110
|
+
.filter((dirent) => dirent.isDirectory())
|
|
111
|
+
.map((dirent) => path.join(dir, workspaceDir, dirent.name))
|
|
112
|
+
|
|
113
|
+
for (const subdir of subdirs) {
|
|
114
|
+
if (existsSync(path.join(subdir, 'package.json'))) {
|
|
115
|
+
results.push(path.join(subdir, 'package.json'))
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
// exact path like "code/tamagui.dev" or "./code/sandbox"
|
|
121
|
+
const pkgPath = path.join(dir, normalizedWorkspace, 'package.json')
|
|
122
|
+
if (existsSync(pkgPath)) {
|
|
123
|
+
results.push(pkgPath)
|
|
132
124
|
}
|
|
133
125
|
}
|
|
134
126
|
}
|
|
135
|
-
} else {
|
|
136
|
-
// exact path like "code/tamagui.dev" or "./code/sandbox"
|
|
137
|
-
const pkgPath = join(dir, normalizedWorkspace, 'package.json')
|
|
138
|
-
if (existsSync(pkgPath)) {
|
|
139
|
-
results.push(pkgPath)
|
|
140
|
-
}
|
|
141
127
|
}
|
|
128
|
+
} catch (_error) {
|
|
129
|
+
// ignore errors parsing package.json
|
|
142
130
|
}
|
|
143
|
-
}
|
|
144
|
-
} catch (_error) {
|
|
145
|
-
// ignore errors parsing package.json
|
|
146
|
-
}
|
|
147
131
|
|
|
148
|
-
|
|
149
|
-
}
|
|
132
|
+
return results
|
|
133
|
+
}
|
|
150
134
|
|
|
151
|
-
function extractDependencies(packageJsonPath: string): string[] {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
135
|
+
function extractDependencies(packageJsonPath: string): string[] {
|
|
136
|
+
try {
|
|
137
|
+
const content = readFileSync(packageJsonPath, 'utf-8')
|
|
138
|
+
const packageJson = JSON.parse(content) as PackageJson
|
|
155
139
|
|
|
156
|
-
|
|
140
|
+
const deps: string[] = []
|
|
157
141
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
142
|
+
const addNonWorkspaceDeps = (depsObject: Record<string, string> | undefined) => {
|
|
143
|
+
if (!depsObject) return
|
|
144
|
+
for (const [name, version] of Object.entries(depsObject)) {
|
|
145
|
+
// skip workspace dependencies
|
|
146
|
+
if (!version.startsWith('workspace:')) {
|
|
147
|
+
deps.push(name)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
164
150
|
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
151
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
152
|
+
addNonWorkspaceDeps(packageJson.dependencies)
|
|
153
|
+
addNonWorkspaceDeps(packageJson.devDependencies)
|
|
154
|
+
addNonWorkspaceDeps(packageJson.peerDependencies)
|
|
155
|
+
addNonWorkspaceDeps(packageJson.optionalDependencies)
|
|
172
156
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
157
|
+
return deps
|
|
158
|
+
} catch (error) {
|
|
159
|
+
console.error(`Error parsing ${packageJsonPath}:`, error)
|
|
160
|
+
return []
|
|
161
|
+
}
|
|
162
|
+
}
|
|
179
163
|
|
|
180
|
-
function doesPackageMatchPattern(packageName: string, pattern: string): boolean {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
164
|
+
function doesPackageMatchPattern(packageName: string, pattern: string): boolean {
|
|
165
|
+
if (pattern.includes('*')) {
|
|
166
|
+
const regex = new RegExp(`^${pattern.replace(/\*/g, '.*')}$`)
|
|
167
|
+
return regex.test(packageName)
|
|
168
|
+
}
|
|
169
|
+
return packageName === pattern
|
|
170
|
+
}
|
|
187
171
|
|
|
188
|
-
function updatePackageJsonVersions(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
): number {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
172
|
+
function updatePackageJsonVersions(
|
|
173
|
+
packageJsonPath: string,
|
|
174
|
+
packagesToUpdate: string[],
|
|
175
|
+
versionMap: Map<string, string>
|
|
176
|
+
): number {
|
|
177
|
+
const content = readFileSync(packageJsonPath, 'utf-8')
|
|
178
|
+
const packageJson = JSON.parse(content) as PackageJson
|
|
179
|
+
let updatedCount = 0
|
|
180
|
+
|
|
181
|
+
const updateDeps = (depsObject: Record<string, string> | undefined) => {
|
|
182
|
+
if (!depsObject) return
|
|
183
|
+
for (const pkg of packagesToUpdate) {
|
|
184
|
+
const current = depsObject[pkg]
|
|
185
|
+
if (current && !current.startsWith('workspace:')) {
|
|
186
|
+
const newVersion = versionMap.get(pkg)
|
|
187
|
+
if (newVersion) {
|
|
188
|
+
// for tagged versions (canary, rc, etc), use exact version (no prefix)
|
|
189
|
+
// otherwise preserve version prefix (^, ~, >=, etc)
|
|
190
|
+
if (globalTag) {
|
|
191
|
+
depsObject[pkg] = newVersion
|
|
192
|
+
} else {
|
|
193
|
+
// wildcard "*" means newly added placeholder, use ^ prefix
|
|
194
|
+
if (current === '*') {
|
|
195
|
+
depsObject[pkg] = `^${newVersion}`
|
|
196
|
+
updatedCount++
|
|
197
|
+
continue
|
|
198
|
+
}
|
|
199
|
+
const prefixMatch = current.match(/^([^\d]*)/)
|
|
200
|
+
const prefix = prefixMatch?.[1] || ''
|
|
201
|
+
depsObject[pkg] = `${prefix}${newVersion}`
|
|
202
|
+
}
|
|
212
203
|
updatedCount++
|
|
213
|
-
continue
|
|
214
204
|
}
|
|
215
|
-
const prefixMatch = current.match(/^([^\d]*)/)
|
|
216
|
-
const prefix = prefixMatch?.[1] || ''
|
|
217
|
-
depsObject[pkg] = `${prefix}${newVersion}`
|
|
218
205
|
}
|
|
219
|
-
updatedCount++
|
|
220
206
|
}
|
|
221
207
|
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
208
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
209
|
+
updateDeps(packageJson.dependencies)
|
|
210
|
+
updateDeps(packageJson.devDependencies)
|
|
211
|
+
updateDeps(packageJson.peerDependencies)
|
|
212
|
+
updateDeps(packageJson.optionalDependencies)
|
|
229
213
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
214
|
+
if (updatedCount > 0) {
|
|
215
|
+
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n')
|
|
216
|
+
}
|
|
233
217
|
|
|
234
|
-
|
|
235
|
-
}
|
|
218
|
+
return updatedCount
|
|
219
|
+
}
|
|
236
220
|
|
|
237
|
-
async function updatePackages(
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
) {
|
|
242
|
-
try {
|
|
243
|
-
rmSync(`node_modules/vite`, {
|
|
244
|
-
recursive: true,
|
|
245
|
-
force: true,
|
|
246
|
-
})
|
|
247
|
-
} catch (_e) {
|
|
248
|
-
// ignore if vite is not there
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// collect all unique packages to update
|
|
252
|
-
const allPackages = new Set<string>()
|
|
253
|
-
for (const { packages } of packagesByWorkspace.values()) {
|
|
254
|
-
packages.forEach((pkg) => allPackages.add(pkg))
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// fetch versions for all packages (with tag if specified)
|
|
258
|
-
const versionMap = new Map<string, string>()
|
|
259
|
-
console.info(`\nš Fetching versions for ${allPackages.size} package(s)...`)
|
|
260
|
-
|
|
261
|
-
await Promise.all(
|
|
262
|
-
[...allPackages].map(async (pkg) => {
|
|
221
|
+
async function updatePackages(
|
|
222
|
+
packagesByWorkspace: Map<string, { dir: string; packages: string[] }>,
|
|
223
|
+
rootDir: string,
|
|
224
|
+
packageJsonFiles: string[]
|
|
225
|
+
) {
|
|
263
226
|
try {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}
|
|
271
|
-
} catch {
|
|
272
|
-
if (globalTag) {
|
|
273
|
-
console.info(` ā ${pkg}@${globalTag} not found, skipping`)
|
|
274
|
-
} else {
|
|
275
|
-
console.info(` ā ${pkg} not found, skipping`)
|
|
276
|
-
}
|
|
227
|
+
rmSync(`node_modules/vite`, {
|
|
228
|
+
recursive: true,
|
|
229
|
+
force: true,
|
|
230
|
+
})
|
|
231
|
+
} catch (_e) {
|
|
232
|
+
// ignore if vite is not there
|
|
277
233
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
234
|
+
|
|
235
|
+
// collect all unique packages to update
|
|
236
|
+
const allPackages = new Set<string>()
|
|
237
|
+
for (const { packages } of packagesByWorkspace.values()) {
|
|
238
|
+
packages.forEach((pkg) => allPackages.add(pkg))
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// fetch versions for all packages (with tag if specified)
|
|
242
|
+
const versionMap = new Map<string, string>()
|
|
243
|
+
console.info(`\nš Fetching versions for ${allPackages.size} package(s)...`)
|
|
244
|
+
|
|
245
|
+
await Promise.all(
|
|
246
|
+
[...allPackages].map(async (pkg) => {
|
|
247
|
+
try {
|
|
248
|
+
const tag = globalTag || 'latest'
|
|
249
|
+
const result = await $`npm view ${pkg}@${tag} version`.quiet()
|
|
250
|
+
const version = result.text().trim()
|
|
251
|
+
if (version) {
|
|
252
|
+
versionMap.set(pkg, version)
|
|
253
|
+
console.info(` ā ${pkg}@${tag} ā ${version}`)
|
|
254
|
+
}
|
|
255
|
+
} catch {
|
|
256
|
+
if (globalTag) {
|
|
257
|
+
console.info(` ā ${pkg}@${globalTag} not found, skipping`)
|
|
258
|
+
} else {
|
|
259
|
+
console.info(` ā ${pkg} not found, skipping`)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
})
|
|
299
263
|
)
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
console.info(
|
|
303
|
-
|
|
264
|
+
|
|
265
|
+
if (versionMap.size === 0) {
|
|
266
|
+
console.info(`\nā ļø No packages found to update`)
|
|
267
|
+
return
|
|
304
268
|
}
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
269
|
+
|
|
270
|
+
// update all package.json files directly
|
|
271
|
+
console.info(`\nš¦ Updating ${packageJsonFiles.length} package.json file(s)...`)
|
|
272
|
+
let totalUpdates = 0
|
|
273
|
+
|
|
274
|
+
for (const packageJsonPath of packageJsonFiles) {
|
|
275
|
+
const packagesInWorkspace =
|
|
276
|
+
packagesByWorkspace.get(getWorkspaceName(packageJsonPath, rootDir))?.packages || []
|
|
277
|
+
|
|
278
|
+
if (packagesInWorkspace.length > 0) {
|
|
279
|
+
const updates = updatePackageJsonVersions(
|
|
280
|
+
packageJsonPath,
|
|
281
|
+
packagesInWorkspace,
|
|
282
|
+
versionMap
|
|
283
|
+
)
|
|
284
|
+
if (updates > 0) {
|
|
285
|
+
const name = getWorkspaceName(packageJsonPath, rootDir)
|
|
286
|
+
console.info(` ā ${name}: ${updates} package(s)`)
|
|
287
|
+
totalUpdates += updates
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
console.info(`\nš Updated ${totalUpdates} dependency version(s)`)
|
|
293
|
+
|
|
294
|
+
console.info(`\nāļø Running 'bun install'...`)
|
|
295
|
+
$.cwd(rootDir)
|
|
320
296
|
try {
|
|
321
|
-
await $`bun pm cache rm`.quiet()
|
|
322
297
|
await $`bun install`
|
|
323
298
|
console.info('ā
Done!')
|
|
324
|
-
} catch (
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
299
|
+
} catch (error: any) {
|
|
300
|
+
const stderr = error.stderr?.toString() || error.message || ''
|
|
301
|
+
// check if it's a version resolution error (common after new publish)
|
|
302
|
+
if (stderr.includes('No version matching') || stderr.includes('failed to resolve')) {
|
|
303
|
+
console.info(`ā ļø Version not in cache, clearing cache and retrying...`)
|
|
304
|
+
try {
|
|
305
|
+
await $`bun pm cache rm`.quiet()
|
|
306
|
+
await $`bun install`
|
|
307
|
+
console.info('ā
Done!')
|
|
308
|
+
} catch (retryError: any) {
|
|
309
|
+
const retryStderr = retryError.stderr?.toString() || retryError.message || ''
|
|
310
|
+
console.error(
|
|
311
|
+
`šØ 'bun install' failed after cache clear: ${retryStderr.split('\n')[0]}`
|
|
312
|
+
)
|
|
313
|
+
}
|
|
314
|
+
} else {
|
|
315
|
+
console.error(`šØ 'bun install' failed: ${stderr.split('\n')[0]}`)
|
|
316
|
+
}
|
|
329
317
|
}
|
|
330
|
-
} else {
|
|
331
|
-
console.error(`šØ 'bun install' failed: ${stderr.split('\n')[0]}`)
|
|
332
318
|
}
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
319
|
|
|
336
|
-
function getWorkspaceName(packageJsonPath: string, rootDir: string): string {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
320
|
+
function getWorkspaceName(packageJsonPath: string, rootDir: string): string {
|
|
321
|
+
const dir = packageJsonPath.replace('/package.json', '')
|
|
322
|
+
if (dir === rootDir) return 'root'
|
|
323
|
+
return dir.replace(rootDir + '/', '')
|
|
324
|
+
}
|
|
341
325
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
console.info(`Found ${packageJsonFiles.length} package.json files`)
|
|
326
|
+
const packageJsonFiles = findPackageJsonFiles(rootDir)
|
|
327
|
+
console.info(`Found ${packageJsonFiles.length} package.json files`)
|
|
345
328
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
329
|
+
// get workspace package names to exclude from updates
|
|
330
|
+
const workspacePackageNames = new Set<string>()
|
|
331
|
+
for (const packageJsonPath of packageJsonFiles) {
|
|
332
|
+
if (packageJsonPath === path.join(rootDir, 'package.json')) continue
|
|
350
333
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
334
|
+
try {
|
|
335
|
+
const content = readFileSync(packageJsonPath, 'utf-8')
|
|
336
|
+
const packageJson = JSON.parse(content)
|
|
337
|
+
if (packageJson.name) {
|
|
338
|
+
workspacePackageNames.add(packageJson.name)
|
|
339
|
+
}
|
|
340
|
+
} catch (_error) {
|
|
341
|
+
// ignore errors
|
|
356
342
|
}
|
|
357
|
-
} catch (_error) {
|
|
358
|
-
// ignore errors
|
|
359
343
|
}
|
|
360
|
-
}
|
|
361
344
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
345
|
+
console.info(
|
|
346
|
+
`Found ${workspacePackageNames.size} workspace packages to exclude from updates`
|
|
347
|
+
)
|
|
365
348
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
349
|
+
// build map of packages to update per workspace
|
|
350
|
+
const packagesByWorkspace = new Map<string, { dir: string; packages: string[] }>()
|
|
351
|
+
const allMatchingDeps = new Set<string>()
|
|
369
352
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
353
|
+
for (const packageJsonPath of packageJsonFiles) {
|
|
354
|
+
const deps = extractDependencies(packageJsonPath)
|
|
355
|
+
const matchingDeps: string[] = []
|
|
373
356
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
357
|
+
for (const dep of deps) {
|
|
358
|
+
// skip workspace packages
|
|
359
|
+
if (workspacePackageNames.has(dep)) continue
|
|
377
360
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
361
|
+
for (const pattern of packagePatterns) {
|
|
362
|
+
if (doesPackageMatchPattern(dep, pattern)) {
|
|
363
|
+
matchingDeps.push(dep)
|
|
364
|
+
allMatchingDeps.add(dep)
|
|
365
|
+
break
|
|
366
|
+
}
|
|
383
367
|
}
|
|
384
368
|
}
|
|
385
|
-
}
|
|
386
369
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
370
|
+
if (matchingDeps.length > 0) {
|
|
371
|
+
const dir = packageJsonPath.replace('/package.json', '')
|
|
372
|
+
const name = getWorkspaceName(packageJsonPath, rootDir)
|
|
373
|
+
packagesByWorkspace.set(name, { dir, packages: matchingDeps })
|
|
374
|
+
}
|
|
391
375
|
}
|
|
392
|
-
}
|
|
393
376
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
377
|
+
if (allMatchingDeps.size === 0) {
|
|
378
|
+
// no existing deps matched, but exact patterns (no wildcards) can be added fresh
|
|
379
|
+
const exactPatterns = packagePatterns.filter((p) => !p.includes('*'))
|
|
380
|
+
if (exactPatterns.length === 0) {
|
|
381
|
+
console.info(
|
|
382
|
+
`Found 0 dependencies matching patterns: ${packagePatterns.join(', ')}`
|
|
383
|
+
)
|
|
384
|
+
console.info('No matching packages found to update.')
|
|
385
|
+
return
|
|
386
|
+
}
|
|
404
387
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
388
|
+
// add as new dependencies to the root package.json
|
|
389
|
+
console.info(`No existing deps found, adding to root: ${exactPatterns.join(', ')}`)
|
|
390
|
+
const rootPkgPath = path.join(rootDir, 'package.json')
|
|
408
391
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
392
|
+
for (const pkg of exactPatterns) {
|
|
393
|
+
allMatchingDeps.add(pkg)
|
|
394
|
+
}
|
|
412
395
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
396
|
+
packagesByWorkspace.set('root', {
|
|
397
|
+
dir: rootDir,
|
|
398
|
+
packages: exactPatterns,
|
|
399
|
+
})
|
|
417
400
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
401
|
+
// insert placeholder so updatePackageJsonVersions can set the real version
|
|
402
|
+
const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf-8'))
|
|
403
|
+
if (!rootPkg.dependencies) {
|
|
404
|
+
rootPkg.dependencies = {}
|
|
405
|
+
}
|
|
406
|
+
for (const pkg of exactPatterns) {
|
|
407
|
+
if (!rootPkg.dependencies[pkg] && !rootPkg.devDependencies?.[pkg]) {
|
|
408
|
+
rootPkg.dependencies[pkg] = '*'
|
|
409
|
+
}
|
|
426
410
|
}
|
|
411
|
+
writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2) + '\n')
|
|
412
|
+
} else {
|
|
413
|
+
console.info(
|
|
414
|
+
`Found ${allMatchingDeps.size} dependencies matching patterns: ${packagePatterns.join(', ')}`
|
|
415
|
+
)
|
|
416
|
+
console.info(`Found matches in ${packagesByWorkspace.size} workspace(s)`)
|
|
427
417
|
}
|
|
428
|
-
writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, 2) + '\n')
|
|
429
|
-
} else {
|
|
430
|
-
console.info(
|
|
431
|
-
`Found ${allMatchingDeps.size} dependencies matching patterns: ${packagePatterns.join(', ')}`
|
|
432
|
-
)
|
|
433
|
-
console.info(`Found matches in ${packagesByWorkspace.size} workspace(s)`)
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
if (globalTag) {
|
|
437
|
-
console.info(`š·ļø Using tag '${globalTag}'`)
|
|
438
|
-
}
|
|
439
418
|
|
|
440
|
-
|
|
419
|
+
if (globalTag) {
|
|
420
|
+
console.info(`š·ļø Using tag '${globalTag}'`)
|
|
421
|
+
}
|
|
441
422
|
|
|
442
|
-
|
|
443
|
-
if (packagePatterns.includes('@rocicorp/zero')) {
|
|
444
|
-
console.info('\nš Updating local env for Zero...')
|
|
445
|
-
await $`bun tko run update-local-env`
|
|
446
|
-
}
|
|
423
|
+
await updatePackages(packagesByWorkspace, rootDir, packageJsonFiles)
|
|
447
424
|
|
|
448
|
-
|
|
449
|
-
|
|
425
|
+
// special handling for zero - update ZERO_VERSION in .env
|
|
426
|
+
if (packagePatterns.includes('@rocicorp/zero')) {
|
|
427
|
+
console.info('\nš Updating local env for Zero...')
|
|
428
|
+
await $`bun tko run update-local-env`
|
|
429
|
+
}
|
|
450
430
|
|
|
451
|
-
|
|
431
|
+
console.info('\nš Dependency update complete!')
|
|
432
|
+
})
|