Skip to content

Commit fea8765

Browse files
committed
Fix test failures
1 parent e121c32 commit fea8765

11 files changed

+109
-55
lines changed

npm_and_yarn/lib/dependabot/npm_and_yarn/dependency_files_filterer.rb

+2-3
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,7 @@ def package_required_lockfile?(lockfile)
8282

8383
sig { params(lockfile: DependencyFile).returns(T::Boolean) }
8484
def workspaces_lockfile?(lockfile)
85-
return false unless ["yarn.lock", "package-lock.json", "pnpm-lock.yaml",
86-
Bun::LOCKFILE_NAME].include?(lockfile.name)
85+
return false unless ["yarn.lock", "package-lock.json", "pnpm-lock.yaml", "bun.lock"].include?(lockfile.name)
8786

8887
return false unless parsed_root_package_json["workspaces"] || dependency_files.any? do |file|
8988
file.name.end_with?("pnpm-workspace.yaml") && File.dirname(file.name) == File.dirname(lockfile.name)
@@ -150,7 +149,7 @@ def lockfile?(file)
150149
"yarn.lock",
151150
"pnpm-lock.yaml",
152151
"npm-shrinkwrap.json",
153-
Bun::LOCKFILE_NAME
152+
"bun.lock"
154153
)
155154
end
156155
end

npm_and_yarn/lib/dependabot/npm_and_yarn/file_parser/bun_lock.rb

+75-42
Original file line numberDiff line numberDiff line change
@@ -19,40 +19,61 @@ def initialize(dependency_file)
1919

2020
sig { returns(T::Hash[String, T.untyped]) }
2121
def parsed
22+
return @content if @content
23+
2224
# Since bun.lock is a JSONC file, which is a subset of YAML, we can use YAML to parse it
23-
json_obj = YAML.load(T.must(@dependency_file.content))
24-
@parsed ||= T.let(json_obj, T.nilable(T::Hash[String, T.untyped]))
25-
rescue Psych::SyntaxError
26-
raise Dependabot::DependencyFileNotParseable.new(@dependency_file.path, "Invalid bun.lock file")
25+
content = YAML.load(T.must(@dependency_file.content))
26+
raise_invalid!("expected to be an object") unless content.is_a?(Hash)
27+
28+
version = content["lockfileVersion"]
29+
raise_invalid!("expected 'lockfileVersion' to be an integer") unless version.is_a?(Integer)
30+
raise_invalid!("expected 'lockfileVersion' to be >= 0") unless version >= 0
31+
unless version.zero?
32+
raise_invalid!(<<~ERROR
33+
unsupported 'lockfileVersion' = #{version}, please open an issue with Dependabot to support this:
34+
https://github.com/dependabot/dependabot/issues/new
35+
ERROR
36+
)
37+
end
38+
39+
@content = content
40+
rescue Psych::SyntaxError => e
41+
raise_invalid!("malformed JSONC at line #{e.line}, column #{e.column}")
42+
end
43+
44+
sig { returns(Integer) }
45+
def version
46+
parsed["lockfileVersion"]
2747
end
2848

2949
sig { returns(Dependabot::FileParsers::Base::DependencySet) }
3050
def dependencies
3151
dependency_set = Dependabot::FileParsers::Base::DependencySet.new
3252

33-
lockfile_version = parsed["lockfileVersion"]
34-
if lockfile_version.zero?
35-
packages = parsed["packages"]
36-
raise_invalid_lock!("expected 'packages' to be an object") unless packages.is_a?(Hash)
53+
# bun.lock v0 format:
54+
# https://github.com/oven-sh/bun/blob/c130df6c589fdf28f9f3c7f23ed9901140bc9349/src/install/bun.lock.zig#L595-L605
55+
56+
packages = parsed["packages"]
57+
raise_invalid!("expected 'packages' to be an object") unless packages.is_a?(Hash)
3758

38-
packages.each do |key, details|
39-
raise_invalid_lock!("expected 'packages.#{key}' to be an array") unless details.is_a?(Array)
59+
packages.each do |key, details|
60+
raise_invalid!("expected 'packages.#{key}' to be an array") unless details.is_a?(Array)
4061

41-
entry = details.first
42-
raise_invalid_lock!("expected 'packages.#{key}[0]' to be a string") unless entry.is_a?(String)
62+
resolution = details.first
63+
raise_invalid!("expected 'packages.#{key}[0]' to be a string") unless resolution.is_a?(String)
4364

44-
name, version = entry.split(/(?<=\w)\@/)
45-
next if name.empty? || version.start_with?("workspace:")
65+
name, version = resolution.split(/(?<=\w)\@/)
66+
next if name.empty?
4667

47-
dependency_set << Dependency.new(
48-
name: name,
49-
version: version,
50-
package_manager: "npm_and_yarn",
51-
requirements: []
52-
)
53-
end
54-
else
55-
raise_invalid_lock!("expected 'lockfileVersion' to be 0")
68+
semver = Version.semver_for(version)
69+
next unless semver
70+
71+
dependency_set << Dependency.new(
72+
name: name,
73+
version: semver.to_s,
74+
package_manager: "npm_and_yarn",
75+
requirements: []
76+
)
5677
end
5778

5879
dependency_set
@@ -63,9 +84,6 @@ def dependencies
6384
.returns(T.nilable(T::Hash[String, T.untyped]))
6485
end
6586
def details(dependency_name, requirement, _manifest_name)
66-
lockfile_version = parsed["lockfileVersion"]
67-
return unless lockfile_version.zero?
68-
6987
packages = parsed["packages"]
7088
return unless packages.is_a?(Hash)
7189

@@ -77,39 +95,54 @@ def details(dependency_name, requirement, _manifest_name)
7795
# If there's only one entry for this dependency, use it, even if
7896
# the requirement in the lockfile doesn't match
7997
if candidates.one?
80-
format_details(lockfile_version, candidates.first)
98+
parse_details(candidates.first)
8199
else
82100
candidate = candidates.find do |label, _|
83101
label.scan(/(?<=\w)\@(?:npm:)?([^\s,]+)/).flatten.include?(requirement)
84102
end&.last
85-
format_details(lockfile_version, candidate)
103+
parse_details(candidate)
86104
end
87105
end
88106

89107
private
90108

91109
sig { params(message: String).void }
92-
def raise_invalid_lock!(message)
110+
def raise_invalid!(message)
93111
raise Dependabot::DependencyFileNotParseable.new(@dependency_file.path, "Invalid bun.lock file: #{message}")
94112
end
95113

96114
sig do
97-
params(lockfile_version: T.nilable(Integer),
98-
entry: T.nilable(T::Array[T.untyped])).returns(T.nilable(T::Hash[String, T.untyped]))
115+
params(entry: T.nilable(T::Array[T.untyped])).returns(T.nilable(T::Hash[String, T.untyped]))
99116
end
100-
def format_details(lockfile_version, entry)
101-
return unless lockfile_version.zero?
117+
def parse_details(entry)
102118
return unless entry.is_a?(Array)
103119

104-
label, registry, details, hash = entry
105-
name, version = label.split(/(?<=\w)\@/)
106-
{
107-
"name" => name,
108-
"version" => version,
109-
"registry" => registry,
110-
"details" => details,
111-
"hash" => hash
112-
}
120+
# Either:
121+
# - "{name}@{version}", registry, details, integrity
122+
# - "{name}@{resolution}", details
123+
resolution = entry.first
124+
return unless resolution.is_a?(String)
125+
126+
name, version = resolution.split(/(?<=\w)\@/)
127+
semver = Version.semver_for(version)
128+
129+
if semver
130+
registry, details, integrity = entry[1..3]
131+
{
132+
"name" => name,
133+
"version" => semver.to_s,
134+
"registry" => registry,
135+
"details" => details,
136+
"integrity" => integrity
137+
}
138+
else
139+
details = entry[1]
140+
{
141+
"name" => name,
142+
"resolution" => version,
143+
"details" => details
144+
}
145+
end
113146
end
114147
end
115148
end

npm_and_yarn/lib/dependabot/npm_and_yarn/file_parser/lockfile_parser.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def pnpm_locks
109109
def bun_locks
110110
@bun_locks ||= T.let(
111111
dependency_files
112-
.select { |f| f.name.end_with?(Bun::LOCKFILE_NAME) }, T.nilable(T::Array[DependencyFile])
112+
.select { |f| f.name.end_with?("bun.lock") }, T.nilable(T::Array[DependencyFile])
113113
)
114114
end
115115

npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ def pnpm_locks
194194
def bun_locks
195195
@bun_locks ||= T.let(
196196
filtered_dependency_files
197-
.select { |f| f.name.end_with?(Bun::LOCKFILE_NAME) },
197+
.select { |f| f.name.end_with?("bun.lock") },
198198
T.nilable(T::Array[Dependabot::DependencyFile])
199199
)
200200
end

npm_and_yarn/lib/dependabot/npm_and_yarn/package_manager.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ def deprecated?
227227

228228
sig { override.returns(T::Boolean) }
229229
def unsupported?
230-
version && version < MIN_SUPPORTED_VERSION
230+
supported_versions.all? { |supported| supported > version }
231231
end
232232
end
233233

npm_and_yarn/lib/dependabot/npm_and_yarn/sub_dependency_files_filterer.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def lockfile?(file)
6969
"yarn.lock",
7070
"npm-shrinkwrap.json",
7171
"pnpm-lock.yaml",
72-
Bun::LOCKFILE_NAME
72+
"bun.lock"
7373
)
7474
end
7575

npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/dependency_files_builder.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def pnpm_locks
5252
def bun_locks
5353
@bun_locks ||=
5454
dependency_files
55-
.select { |f| f.name.end_with?(Bun::LOCKFILE_NAME) }
55+
.select { |f| f.name.end_with?("bun.lock") }
5656
end
5757

5858
def root_yarn_lock
@@ -70,7 +70,7 @@ def root_pnpm_lock
7070
def root_bun_lock
7171
@root_bun_lock ||=
7272
dependency_files
73-
.find { |f| f.name == Bun::LOCKFILE_NAME }
73+
.find { |f| f.name == "bun.lock" }
7474
end
7575

7676
def shrinkwraps

npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/subdependency_version_resolver.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def update_subdependency_in_lockfile(lockfile)
6464
lockfile_name = Pathname.new(lockfile.name).basename.to_s
6565
path = Pathname.new(lockfile.name).dirname.to_s
6666

67-
updated_files = if lockfile.name.end_with?(Bun::LOCKFILE_NAME)
67+
updated_files = if lockfile.name.end_with?("bun.lock")
6868
run_bun_updater(path, lockfile_name)
6969
elsif lockfile.name.end_with?("yarn.lock") && Helpers.yarn_berry?(lockfile)
7070
run_yarn_berry_updater(path, lockfile_name)

npm_and_yarn/spec/dependabot/npm_and_yarn/file_fetcher_spec.rb

+20
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,20 @@
379379
body: nil,
380380
headers: json_header
381381
)
382+
stub_request(:get, File.join(url, "bun.lock?ref=sha"))
383+
.with(headers: { "Authorization" => "token token" })
384+
.to_return(
385+
status: 404,
386+
body: nil,
387+
headers: json_header
388+
)
389+
stub_request(:get, File.join(url, "packages/bun.lock?ref=sha"))
390+
.with(headers: { "Authorization" => "token token" })
391+
.to_return(
392+
status: 404,
393+
body: nil,
394+
headers: json_header
395+
)
382396
# FileFetcher will iterate trying to find `pnpm-lock.yaml` upwards in the folder tree
383397
stub_request(:get, File.join(url, "packages/pnpm-lock.yaml?ref=sha"))
384398
.with(headers: { "Authorization" => "token token" })
@@ -1304,6 +1318,12 @@
13041318
"pnpm-lock.yaml?ref=sha"
13051319
).with(headers: { "Authorization" => "token token" })
13061320
.to_return(status: 404)
1321+
stub_request(
1322+
:get,
1323+
"https://api.github.com/repos/gocardless/bump/contents/" \
1324+
"bun.lock?ref=sha"
1325+
).with(headers: { "Authorization" => "token token" })
1326+
.to_return(status: 404)
13071327
end
13081328

13091329
it "fetches package.json from the workspace dependencies" do

npm_and_yarn/spec/dependabot/npm_and_yarn/file_parser/lockfile_parser_spec.rb

+4-2
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@
328328
expect { dependencies }
329329
.to raise_error(Dependabot::DependencyFileNotParseable) do |error|
330330
expect(error.file_name).to eq("bun.lock")
331-
expect(error.message).to eq("Invalid bun.lock file")
331+
expect(error.message).to eq("Invalid bun.lock file: malformed JSONC at line 3, column 1")
332332
end
333333
end
334334
end
@@ -688,14 +688,16 @@
688688
let(:manifest_name) { "package.json" }
689689

690690
it "finds the dependency" do
691+
# rubocop:disable Layout/LineLength
691692
expect(lockfile_details).to eq({
692693
"name" => "fetch-factory",
693694
"version" => "0.0.1",
694695
"registry" => "",
695696
"details" => { "dependencies" => { "es6-promise" => "^3.0.2", "isomorphic-fetch" => "^2.1.1",
696697
"lodash" => "^3.10.1" } },
697-
"hash" => "sha512-gexRwqIhwzDJ2pJvL0UYfiZwW06/bdYWxAmswFFts7C87CF8i6liApihTk7TZFYMDcQjvvDIvyHv0q379z0aWA=="
698+
"integrity" => "sha512-gexRwqIhwzDJ2pJvL0UYfiZwW06/bdYWxAmswFFts7C87CF8i6liApihTk7TZFYMDcQjvvDIvyHv0q379z0aWA=="
698699
})
700+
# rubocop:enable Layout/LineLength
699701
end
700702
end
701703
end

npm_and_yarn/spec/dependabot/npm_and_yarn/file_updater/bun_lockfile_updater_spec.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
let(:files) { project_dependency_files(project_name) }
5757

5858
let(:bun_lock) do
59-
files.find { |f| f.name == Bun::LOCKFILE_NAME }
59+
files.find { |f| f.name == "bun.lock" }
6060
end
6161

6262
let(:tmp_path) { Dependabot::Utils::BUMP_TMP_DIR_PATH }

0 commit comments

Comments
 (0)