Skip to content

Commit bb99ed9

Browse files
sorccuclaude
andauthored
feat(cli): support bun.lock text-based lockfile from Bun 1.2 (#1283)
* feat(cli): support bun.lock text-based lockfile from Bun 1.2 Bun 1.2 changed from a binary lockfile (bun.lockb) to a text-based lockfile (bun.lock). Change representativeLockfile to representativeLockfiles (string[]) so package managers can declare multiple lockfile names. Earlier entries in the list are preferred. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(cli): scope lockfile detection to sandbox root in fixture-sandbox Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 59b5232 commit bb99ed9

3 files changed

Lines changed: 35 additions & 58 deletions

File tree

packages/cli/src/services/__tests__/util.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ describe('util', () => {
3535
const basePath = path.resolve('/project')
3636
const makePm = (name: string): PackageManager => ({
3737
name,
38-
representativeLockfile: undefined,
38+
representativeLockfiles: [],
3939
representativeConfigFile: undefined,
4040
installCommand: () => ({ executable: name, args: ['install'], unsafeDisplayCommand: `${name} install` }),
4141
execCommand: (args: string[]) => ({ executable: name, args, unsafeDisplayCommand: `${name} ${args.join(' ')}` }),

packages/cli/src/services/check-parser/package-files/package-manager.ts

Lines changed: 27 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export interface AddCommandOptions {
2929

3030
export interface PackageManager {
3131
get name (): string
32-
get representativeLockfile (): string | undefined
32+
get representativeLockfiles (): string[]
3333
get representativeConfigFile (): string | undefined
3434
installCommand (): Runnable
3535
addCommand (options: AddCommandOptions): Runnable
@@ -44,9 +44,20 @@ export abstract class PackageManagerDetector {
4444
abstract get name (): string
4545
abstract detectUserAgent (userAgent: string): boolean
4646
abstract detectRuntime (): boolean
47-
abstract get representativeLockfile (): string | undefined
47+
abstract get representativeLockfiles (): string[]
4848
abstract get representativeConfigFile (): string | undefined
49-
abstract detectLockfile (dir: string): Promise<string>
49+
50+
async detectLockfile (dir: string): Promise<string> {
51+
for (const lockfile of this.representativeLockfiles) {
52+
try {
53+
return await accessR(path.join(dir, lockfile))
54+
} catch {
55+
continue
56+
}
57+
}
58+
throw new NotDetectedError()
59+
}
60+
5061
abstract detectConfigFile (dir: string): Promise<string>
5162
abstract detectExecutable (lookup: PathLookup): Promise<void>
5263
abstract installCommand (): Runnable
@@ -71,18 +82,14 @@ export class NpmDetector extends PackageManagerDetector implements PackageManage
7182
return false
7283
}
7384

74-
get representativeLockfile (): string {
75-
return 'package-lock.json'
85+
get representativeLockfiles (): string[] {
86+
return ['package-lock.json']
7687
}
7788

7889
get representativeConfigFile (): undefined {
7990
return
8091
}
8192

82-
async detectLockfile (dir: string): Promise<string> {
83-
return await accessR(path.join(dir, this.representativeLockfile))
84-
}
85-
8693
// eslint-disable-next-line require-await, @typescript-eslint/no-unused-vars
8794
async detectConfigFile (dir: string): Promise<string> {
8895
throw new NotDetectedError()
@@ -126,19 +133,14 @@ export class CNpmDetector extends PackageManagerDetector implements PackageManag
126133
return false
127134
}
128135

129-
get representativeLockfile (): undefined {
130-
return
136+
get representativeLockfiles (): string[] {
137+
return []
131138
}
132139

133140
get representativeConfigFile (): undefined {
134141
return
135142
}
136143

137-
// eslint-disable-next-line require-await
138-
async detectLockfile (): Promise<string> {
139-
throw new NotDetectedError()
140-
}
141-
142144
// eslint-disable-next-line require-await, @typescript-eslint/no-unused-vars
143145
async detectConfigFile (dir: string): Promise<string> {
144146
throw new NotDetectedError()
@@ -182,18 +184,14 @@ export class PNpmDetector extends PackageManagerDetector implements PackageManag
182184
return false
183185
}
184186

185-
get representativeLockfile (): string {
186-
return 'pnpm-lock.yaml'
187+
get representativeLockfiles (): string[] {
188+
return ['pnpm-lock.yaml']
187189
}
188190

189191
get representativeConfigFile (): string {
190192
return 'pnpm-workspace.yaml'
191193
}
192194

193-
async detectLockfile (dir: string): Promise<string> {
194-
return await accessR(path.join(dir, this.representativeLockfile))
195-
}
196-
197195
async detectConfigFile (dir: string): Promise<string> {
198196
return await accessR(path.join(dir, this.representativeConfigFile))
199197
}
@@ -307,18 +305,14 @@ export class YarnDetector extends PackageManagerDetector implements PackageManag
307305
return false
308306
}
309307

310-
get representativeLockfile (): string {
311-
return 'yarn.lock'
308+
get representativeLockfiles (): string[] {
309+
return ['yarn.lock']
312310
}
313311

314312
get representativeConfigFile (): undefined {
315313
return
316314
}
317315

318-
async detectLockfile (dir: string): Promise<string> {
319-
return await accessR(path.join(dir, this.representativeLockfile))
320-
}
321-
322316
// eslint-disable-next-line require-await, @typescript-eslint/no-unused-vars
323317
async detectConfigFile (dir: string): Promise<string> {
324318
throw new NotDetectedError()
@@ -362,18 +356,14 @@ export class DenoDetector extends PackageManagerDetector implements PackageManag
362356
return process.versions.deno !== undefined
363357
}
364358

365-
get representativeLockfile (): string {
366-
return 'deno.lock'
359+
get representativeLockfiles (): string[] {
360+
return ['deno.lock']
367361
}
368362

369363
get representativeConfigFile (): string {
370364
return 'deno.json'
371365
}
372366

373-
async detectLockfile (dir: string): Promise<string> {
374-
return await accessR(path.join(dir, this.representativeLockfile))
375-
}
376-
377367
async detectConfigFile (dir: string): Promise<string> {
378368
return await accessR(path.join(dir, this.representativeConfigFile))
379369
}
@@ -460,18 +450,14 @@ export class BunDetector extends PackageManagerDetector implements PackageManage
460450
return process.versions.bun !== undefined
461451
}
462452

463-
get representativeLockfile (): string {
464-
return 'bun.lockb'
453+
get representativeLockfiles (): string[] {
454+
return ['bun.lock', 'bun.lockb']
465455
}
466456

467457
get representativeConfigFile (): undefined {
468458
return
469459
}
470460

471-
async detectLockfile (dir: string): Promise<string> {
472-
return await accessR(path.join(dir, this.representativeLockfile))
473-
}
474-
475461
// eslint-disable-next-line require-await, @typescript-eslint/no-unused-vars
476462
async detectConfigFile (dir: string): Promise<string> {
477463
throw new NotDetectedError()
@@ -731,9 +717,7 @@ export async function detectNearestLockfile (
731717
}
732718
}
733719

734-
const lockfiles = detectors.reduce<string[]>((acc, detector) => {
735-
return acc.concat(detector.representativeLockfile ?? [])
736-
}, [])
720+
const lockfiles = detectors.flatMap(detector => detector.representativeLockfiles)
737721

738722
throw new NoLockfileFoundError(searchPaths, lockfiles)
739723
}

packages/cli/src/testing/fixture-sandbox.ts

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Debug from 'debug'
66

77
const debug = Debug('checkly:cli:testing:fixture-sandbox')
88

9-
import { detectNearestPackageJson, detectPackageManager, PackageManager } from '../services/check-parser/package-files/package-manager'
9+
import { detectNearestLockfile, detectNearestPackageJson, detectPackageManager, PackageManager } from '../services/check-parser/package-files/package-manager'
1010

1111
export interface CreateFixtureSandboxOptions {
1212
/**
@@ -113,7 +113,10 @@ export class FixtureSandbox {
113113
if (installPackages && injectPackedSelf) {
114114
debug('Injecting containing package')
115115

116-
const lockfile = packageManager.representativeLockfile
116+
const { lockfile } = await detectNearestLockfile(root, {
117+
detectors: [packageManager.detector()],
118+
root,
119+
})
117120

118121
// Take a backup of the original package.json so that we can restore
119122
// it later.
@@ -123,12 +126,7 @@ export class FixtureSandbox {
123126
)
124127

125128
// Same for the lockfile.
126-
if (lockfile) {
127-
await fs.cp(
128-
path.join(root, lockfile),
129-
path.join(root, `${lockfile}.backup`),
130-
)
131-
}
129+
await fs.cp(lockfile, `${lockfile}.backup`)
132130

133131
const packageJson = await detectNearestPackageJson(__dirname)
134132

@@ -153,12 +151,7 @@ export class FixtureSandbox {
153151
)
154152

155153
// Restore original lockfile.
156-
if (lockfile) {
157-
await fs.rename(
158-
path.join(root, `${lockfile}.backup`),
159-
path.join(root, lockfile),
160-
)
161-
}
154+
await fs.rename(`${lockfile}.backup`, lockfile)
162155
}
163156

164157
return new FixtureSandbox({

0 commit comments

Comments
 (0)