dependabot-vcpkg 0.389.0 → 0.390.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89e6a1875def8d22cf5ca09c168b4139c553adf1a35b4b207903b334a0c2307b
4
- data.tar.gz: be872546e8c76d60e7798601b2fea7aa417b7d85f715830fe00c2805fa130ea4
3
+ metadata.gz: bc65886cc56d34d9e32ca3dfe8a5ebcf25219d48b6c8276a62975974d1327bf8
4
+ data.tar.gz: ac856f5a7eaf627129324fd03ae4379eca0667370a63db31ed6f9e3073d3ea87
5
5
  SHA512:
6
- metadata.gz: 56c33fa02e255ab3fd840af1d38de768f005841b0d43b175b1ea4d00e003adbeb24c5840fb1b694f6cf47a55baa3ab57387c69331672ac5d24882dd69101abf6
7
- data.tar.gz: dbfcdef51f9ac5e998b32f3e4f9b670ea794ad84492bc1c15dd079dbe8559b9b221445e9636402211ea8b55c159ccabb94f8d6b78f98943c08196144ac8c4880
6
+ metadata.gz: 6ef838b9a47174b9fb9b664115d5688391446a7104533ec5e06ed894917b0c680bf0be1d6c35de8b99bbfd1a90eedcd7d92b43622b1db1011bae7fff8a3448c3
7
+ data.tar.gz: 6015c043d8bec0d168028712c3455195d40df263dd691eddcdf63b8c35e1a32ef13f6e8ac563cfac74eb53b6a1264ddc46a11d758d8bdc3415ce9513757768c7
@@ -10,7 +10,10 @@ require "dependabot/logger"
10
10
 
11
11
  require "dependabot/vcpkg"
12
12
  require "dependabot/vcpkg/language"
13
+ require "dependabot/vcpkg/manifest_baseline"
14
+ require "dependabot/vcpkg/package/versions_database"
13
15
  require "dependabot/vcpkg/package_manager"
16
+ require "dependabot/vcpkg/version"
14
17
 
15
18
  module Dependabot
16
19
  module Vcpkg
@@ -124,7 +127,7 @@ module Dependabot
124
127
 
125
128
  sig do
126
129
  params(
127
- dep: T.untyped,
130
+ dep: Object,
128
131
  dependency_file: Dependabot::DependencyFile
129
132
  )
130
133
  .returns(T.nilable(Dependabot::Dependency))
@@ -132,40 +135,95 @@ module Dependabot
132
135
  def parse_port_dependency(dep:, dependency_file:)
133
136
  case dep
134
137
  when String
135
- # Simple string dependency like "curl" - log and skip
136
- Dependabot.logger.warn("Skipping vcpkg dependency '#{dep}' without version>= constraint")
137
- nil
138
+ build_port_dependency(name: dep, constraint: nil, dependency_file:)
138
139
  when Hash
139
140
  name = dep["name"]
140
- version_constraint = dep["version>="]
141
-
142
141
  return nil unless name.is_a?(String)
143
142
 
144
- unless version_constraint
145
- Dependabot.logger.warn("Skipping vcpkg dependency '#{name}' without version>= constraint")
146
- return nil
147
- end
148
-
149
- # Parse version and optional port-version
150
- version, _port_version = parse_version_with_port(version_constraint)
151
-
152
- Dependabot::Dependency.new(
153
- name:,
154
- version:,
155
- package_manager: "vcpkg",
156
- requirements: [{
157
- requirement: ">=#{version_constraint}",
158
- groups: [],
159
- source: nil,
160
- file: dependency_file.name
161
- }]
162
- )
143
+ constraint = dep[VCPKG_VERSION_CONSTRAINT_KEY]
144
+ build_port_dependency(name:, constraint: constraint.is_a?(String) ? constraint : nil, dependency_file:)
163
145
  else
164
146
  Dependabot.logger.warn("Skipping unknown vcpkg dependency format: #{dep.inspect}")
165
147
  nil
166
148
  end
167
149
  end
168
150
 
151
+ # A port's version comes from its `version>=` constraint, the registry baseline, or both.
152
+ # vcpkg installs the lowest version satisfying every constraint, so where both are present
153
+ # the effective version is the higher of the two.
154
+ sig do
155
+ params(
156
+ name: String,
157
+ constraint: T.nilable(String),
158
+ dependency_file: Dependabot::DependencyFile
159
+ )
160
+ .returns(T.nilable(Dependabot::Dependency))
161
+ end
162
+ def build_port_dependency(name:, constraint:, dependency_file:)
163
+ version = effective_port_version(name:, constraint:)
164
+
165
+ unless version
166
+ Dependabot.logger.warn("Skipping vcpkg dependency '#{name}' without version>= constraint")
167
+ return nil
168
+ end
169
+
170
+ Dependabot::Dependency.new(
171
+ name:,
172
+ version: version.to_s,
173
+ package_manager: "vcpkg",
174
+ requirements: [{
175
+ requirement: constraint && ">=#{constraint}",
176
+ groups: [],
177
+ source: nil,
178
+ file: dependency_file.name
179
+ }]
180
+ )
181
+ end
182
+
183
+ sig { params(name: String, constraint: T.nilable(String)).returns(T.nilable(Dependabot::Vcpkg::Version)) }
184
+ def effective_port_version(name:, constraint:)
185
+ constraint_version = constraint && Version.correct?(constraint) ? Version.new(constraint) : nil
186
+ baseline_version = baseline_port_version(name)
187
+
188
+ return constraint_version unless baseline_version
189
+ return baseline_version unless constraint_version
190
+ return constraint_version unless constraint_version.comparable_with?(baseline_version)
191
+
192
+ [constraint_version, baseline_version].max
193
+ end
194
+
195
+ sig { params(name: String).returns(T.nilable(Dependabot::Vcpkg::Version)) }
196
+ def baseline_port_version(name)
197
+ ref = builtin_baseline_ref
198
+ return nil unless ref
199
+
200
+ versions_database.baseline_version_for(port: name, ref:)
201
+ end
202
+
203
+ # The commit the manifest pins the built-in registry to. Ports resolved from any other
204
+ # registry are left alone, because the versions database shipped with the image only
205
+ # describes the built-in one.
206
+ sig { returns(T.nilable(String)) }
207
+ def builtin_baseline_ref
208
+ manifest_baseline.ref
209
+ end
210
+
211
+ sig { returns(Dependabot::Vcpkg::ManifestBaseline) }
212
+ def manifest_baseline
213
+ @manifest_baseline ||= T.let(
214
+ Dependabot::Vcpkg::ManifestBaseline.new(dependency_files:),
215
+ T.nilable(Dependabot::Vcpkg::ManifestBaseline)
216
+ )
217
+ end
218
+
219
+ sig { returns(Dependabot::Vcpkg::Package::VersionsDatabase) }
220
+ def versions_database
221
+ @versions_database ||= T.let(
222
+ Dependabot::Vcpkg::Package::VersionsDatabase.new,
223
+ T.nilable(Dependabot::Vcpkg::Package::VersionsDatabase)
224
+ )
225
+ end
226
+
169
227
  sig do
170
228
  params(
171
229
  registry: T::Hash[String, T.untyped],
@@ -230,15 +288,6 @@ module Dependabot
230
288
  end
231
289
  end
232
290
 
233
- sig { params(version_string: String).returns([String, T.nilable(String)]) }
234
- def parse_version_with_port(version_string)
235
- if version_string.include?("#")
236
- version_string.split("#", 2).then { |parts| [parts[0] || "", parts[1]] }
237
- else
238
- [version_string, nil]
239
- end
240
- end
241
-
242
291
  # A project relying on a global vcpkg install has no baseline to update.
243
292
  # Synthesize one so the updater adds it to the manifest; later runs keep it
244
293
  # current. See https://github.com/dependabot/dependabot-core/issues/13051
@@ -7,6 +7,8 @@ require "sorbet-runtime"
7
7
  require "dependabot/file_updaters"
8
8
  require "dependabot/file_updaters/base"
9
9
  require "dependabot/vcpkg"
10
+ require "dependabot/vcpkg/manifest_baseline"
11
+ require "dependabot/vcpkg/version"
10
12
 
11
13
  module Dependabot
12
14
  module Vcpkg
@@ -19,7 +21,7 @@ module Dependabot
19
21
 
20
22
  # Handle vcpkg.json
21
23
  vcpkg_json_file = get_original_file(VCPKG_JSON_FILENAME)
22
- if vcpkg_json_file&.then { |file| file_changed?(file) }
24
+ if vcpkg_json_file && rewrite?(vcpkg_json_file)
23
25
  updated_files << updated_file(
24
26
  file: vcpkg_json_file,
25
27
  content: updated_vcpkg_json_content(vcpkg_json_file)
@@ -28,7 +30,7 @@ module Dependabot
28
30
 
29
31
  # Handle vcpkg-configuration.json
30
32
  vcpkg_config_file = get_original_file(VCPKG_CONFIGURATION_JSON_FILENAME)
31
- if vcpkg_config_file&.then { |file| file_changed?(file) }
33
+ if vcpkg_config_file && rewrite?(vcpkg_config_file)
32
34
  updated_files << updated_file(
33
35
  file: vcpkg_config_file,
34
36
  content: updated_vcpkg_configuration_json_content(vcpkg_config_file)
@@ -40,6 +42,14 @@ module Dependabot
40
42
 
41
43
  private
42
44
 
45
+ # A security fix can move the baseline in a file that none of the updated dependencies
46
+ # declare a requirement against, so that file needs rewriting even though `file_changed?`
47
+ # says otherwise.
48
+ sig { params(file: Dependabot::DependencyFile).returns(T::Boolean) }
49
+ def rewrite?(file)
50
+ file_changed?(file) || security_baseline&.fetch(:file) == file.name
51
+ end
52
+
43
53
  sig { override.void }
44
54
  def check_required_files
45
55
  return if get_original_file(VCPKG_JSON_FILENAME) || get_original_file(VCPKG_CONFIGURATION_JSON_FILENAME)
@@ -57,6 +67,8 @@ module Dependabot
57
67
  .select { |_, requirement| requirement }
58
68
  .each { |dependency, _| update_dependency_in_content(parsed_content, dependency, file.name) }
59
69
 
70
+ apply_security_baseline(parsed_content, file.name)
71
+
60
72
  JSON.pretty_generate(parsed_content)
61
73
  rescue JSON::ParserError
62
74
  raise Dependabot::DependencyFileNotParseable, file.path
@@ -72,6 +84,8 @@ module Dependabot
72
84
  .select { |_, requirement| requirement }
73
85
  .each { |dependency, _| update_registry_dependency_in_content(parsed_content, dependency, file.name) }
74
86
 
87
+ apply_security_baseline(parsed_content, file.name)
88
+
75
89
  JSON.pretty_generate(parsed_content)
76
90
  rescue JSON::ParserError
77
91
  raise Dependabot::DependencyFileNotParseable, file.path
@@ -83,24 +97,125 @@ module Dependabot
83
97
  when VCPKG_DEFAULT_BASELINE_DEPENDENCY_NAME
84
98
  update_baseline_in_content(content, dependency, filename)
85
99
  else
86
- update_port_dependency_in_content(content, dependency)
100
+ update_port_dependency_in_content(content, dependency, filename)
87
101
  end
88
102
  end
89
103
 
90
104
  sig { params(content: T::Hash[String, T.untyped], dependency: Dependabot::Dependency, filename: String).void }
91
105
  def update_baseline_in_content(content, dependency, filename)
92
- update_baseline_field(content, dependency, filename, "builtin-baseline")
106
+ update_baseline_field(content, dependency, filename, VCPKG_BUILTIN_BASELINE_KEY)
93
107
  end
94
108
 
109
+ sig { params(content: T::Hash[String, T.untyped], dependency: Dependabot::Dependency, filename: String).void }
110
+ def update_port_dependency_in_content(content, dependency, filename)
111
+ case remediation_for(dependency, filename)
112
+ when :override then apply_override(content, dependency)
113
+ # A baseline bump moves the port's version floor, so the port entry needs no change.
114
+ when :baseline then nil
115
+ else update_version_constraint(content, dependency)
116
+ end
117
+ end
118
+
119
+ sig do
120
+ params(dependency: Dependabot::Dependency, filename: String).returns(T.nilable(Symbol))
121
+ end
122
+ def remediation_for(dependency, filename)
123
+ requirement = dependency.requirements.find { |r| r[:file] == filename }
124
+ metadata = requirement&.dig(:metadata)
125
+ return nil unless metadata.is_a?(Hash)
126
+
127
+ metadata[:security_remediation]
128
+ end
129
+
130
+ sig { params(content: T::Hash[String, T.untyped], dependency: Dependabot::Dependency).void }
131
+ def update_version_constraint(content, dependency)
132
+ entries = content[VCPKG_DEPENDENCIES_KEY]
133
+ return unless entries.is_a?(Array)
134
+
135
+ index = entries.index { |entry| port_entry_name(entry) == dependency.name }
136
+ return unless index
137
+
138
+ entry = entries[index]
139
+ # A port declared as a bare string has to become an object to carry a constraint.
140
+ entry = { "name" => entry } if entry.is_a?(String)
141
+ return unless entry.is_a?(Hash)
142
+
143
+ entry[VCPKG_VERSION_CONSTRAINT_KEY] = dependency.version
144
+ entries[index] = entry
145
+ end
146
+
147
+ # vcpkg cannot compare versions across schemes, so when no safe version shares the current
148
+ # one's scheme, the only way to move the port is to pin it outright. `version` is the
149
+ # scheme-agnostic key, and the port version belongs in it as a `#N` suffix: the separate
150
+ # `port-version` key and the scheme-specific keys are both deprecated.
151
+ # See https://learn.microsoft.com/vcpkg/reference/vcpkg-json#overrides
95
152
  sig { params(content: T::Hash[String, T.untyped], dependency: Dependabot::Dependency).void }
96
- def update_port_dependency_in_content(content, dependency)
97
- # Update the dependencies array
98
- dependencies_array = content["dependencies"]
99
- return unless dependencies_array.is_a?(Array)
100
-
101
- # Find and update the specific dependency using more functional approach
102
- target_dep = dependencies_array.find { _1.is_a?(Hash) && _1["name"] == dependency.name }
103
- target_dep&.[]=("version>=", dependency.version)
153
+ def apply_override(content, dependency)
154
+ entry = { "name" => dependency.name, "version" => dependency.version }
155
+
156
+ overrides = content[VCPKG_OVERRIDES_KEY]
157
+ unless overrides.is_a?(Array)
158
+ overrides = []
159
+ content[VCPKG_OVERRIDES_KEY] = overrides
160
+ end
161
+
162
+ index = overrides.index { |override| override.is_a?(Hash) && override["name"] == dependency.name }
163
+ index ? overrides[index] = entry : overrides << entry
164
+ end
165
+
166
+ sig { params(entry: T.untyped).returns(T.nilable(String)) }
167
+ def port_entry_name(entry)
168
+ return entry if entry.is_a?(String)
169
+ return nil unless entry.is_a?(Hash)
170
+
171
+ name = entry["name"]
172
+ name.is_a?(String) ? name : nil
173
+ end
174
+
175
+ # Where the fix wants the registry baseline moved to, if anywhere.
176
+ sig { returns(T.nilable(T::Hash[Symbol, String])) }
177
+ def security_baseline
178
+ return @security_baseline if @looked_up_security_baseline
179
+
180
+ @looked_up_security_baseline = T.let(true, T.nilable(T::Boolean))
181
+ @security_baseline = T.let(build_security_baseline, T.nilable(T::Hash[Symbol, String]))
182
+ end
183
+
184
+ sig { returns(T.nilable(T::Hash[Symbol, String])) }
185
+ def build_security_baseline
186
+ commit_sha = dependencies
187
+ .flat_map(&:requirements)
188
+ .filter_map { |requirement| requirement.dig(:metadata, :baseline_commit_sha) }
189
+ .first
190
+ return nil unless commit_sha.is_a?(String)
191
+
192
+ location = manifest_baseline.location
193
+ return nil unless location
194
+
195
+ { file: location.first, commit_sha: }
196
+ end
197
+
198
+ sig { params(content: T::Hash[String, T.untyped], filename: String).void }
199
+ def apply_security_baseline(content, filename)
200
+ baseline = security_baseline
201
+ return unless baseline && baseline[:file] == filename
202
+
203
+ path = T.must(manifest_baseline.location).last
204
+ key = path.last
205
+ return unless key
206
+
207
+ target = T.must(path[0...-1]).reduce(content) { |node, segment| node.is_a?(Hash) ? node[segment] : nil }
208
+ return unless target.is_a?(Hash)
209
+
210
+ target[key] = baseline[:commit_sha]
211
+ end
212
+
213
+ sig { returns(Dependabot::Vcpkg::ManifestBaseline) }
214
+ def manifest_baseline
215
+ @manifest_baseline ||= T.let(
216
+ Dependabot::Vcpkg::ManifestBaseline.new(dependency_files:),
217
+ T.nilable(Dependabot::Vcpkg::ManifestBaseline)
218
+ )
104
219
  end
105
220
 
106
221
  sig { params(content: T::Hash[String, T.untyped], dependency: Dependabot::Dependency, filename: String).void }
@@ -0,0 +1,112 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "json"
5
+ require "sorbet-runtime"
6
+
7
+ require "dependabot/dependency_file"
8
+
9
+ require "dependabot/vcpkg"
10
+
11
+ module Dependabot
12
+ module Vcpkg
13
+ # Finds the commit a manifest pins the built-in registry to.
14
+ #
15
+ # This ignores any other registry, because the versions database shipped with the updater image
16
+ # only describes the built-in one.
17
+ class ManifestBaseline
18
+ extend T::Sig
19
+
20
+ sig { params(dependency_files: T::Array[Dependabot::DependencyFile]).void }
21
+ def initialize(dependency_files:)
22
+ @dependency_files = dependency_files
23
+ @ref = T.let(nil, T.nilable(String))
24
+ @resolved = T.let(false, T::Boolean)
25
+ end
26
+
27
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
28
+ attr_reader :dependency_files
29
+
30
+ sig { returns(T.nilable(String)) }
31
+ def ref
32
+ return @ref if @resolved
33
+
34
+ @resolved = true
35
+ @ref = manifest_builtin_baseline || default_registry_builtin_baseline
36
+ end
37
+
38
+ # The file the baseline lives in, and the JSON path to it, so an updater knows what to
39
+ # rewrite.
40
+ sig { returns(T.nilable([String, T::Array[String]])) }
41
+ def location
42
+ return [T.must(vcpkg_manifest_file).name, [VCPKG_BUILTIN_BASELINE_KEY]] if manifest_builtin_baseline
43
+ return nil unless default_registry_builtin_baseline
44
+
45
+ [T.must(vcpkg_configuration_file).name, %w(default-registry baseline)]
46
+ end
47
+
48
+ private
49
+
50
+ sig { returns(T.nilable(String)) }
51
+ def manifest_builtin_baseline
52
+ manifest = vcpkg_manifest_file
53
+ return nil unless manifest
54
+
55
+ baseline = parsed_json(manifest)&.dig(VCPKG_BUILTIN_BASELINE_KEY)
56
+ baseline.is_a?(String) ? baseline : nil
57
+ end
58
+
59
+ sig { returns(T.nilable(String)) }
60
+ def default_registry_builtin_baseline
61
+ registry = default_registry
62
+ return nil unless registry
63
+ return nil unless builtin_registry?(registry)
64
+
65
+ baseline = registry["baseline"]
66
+ baseline.is_a?(String) ? baseline : nil
67
+ end
68
+
69
+ sig { returns(T.nilable(T::Hash[String, Object])) }
70
+ def default_registry
71
+ config = vcpkg_configuration_file
72
+ return nil unless config
73
+
74
+ registry = parsed_json(config)&.dig("default-registry")
75
+ registry.is_a?(Hash) ? registry : nil
76
+ end
77
+
78
+ sig { params(registry: T::Hash[String, Object]).returns(T::Boolean) }
79
+ def builtin_registry?(registry)
80
+ return true if registry["kind"] == "builtin"
81
+ return false unless registry["kind"] == "git"
82
+
83
+ repository = registry["repository"]
84
+ return false unless repository.is_a?(String)
85
+
86
+ official = [VCPKG_DEFAULT_REGISTRY_REPOSITORY, VCPKG_DEFAULT_BASELINE_URL]
87
+ official.include?(repository.delete_suffix("/"))
88
+ end
89
+
90
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
91
+ def vcpkg_manifest_file
92
+ dependency_files.find { |file| file.name == VCPKG_JSON_FILENAME }
93
+ end
94
+
95
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
96
+ def vcpkg_configuration_file
97
+ dependency_files.find { |file| file.name == VCPKG_CONFIGURATION_JSON_FILENAME }
98
+ end
99
+
100
+ sig { params(file: Dependabot::DependencyFile).returns(T.nilable(T::Hash[String, Object])) }
101
+ def parsed_json(file)
102
+ content = file.content
103
+ return nil unless content
104
+
105
+ parsed = JSON.parse(content)
106
+ parsed.is_a?(Hash) ? parsed : nil
107
+ rescue JSON::ParserError
108
+ nil
109
+ end
110
+ end
111
+ end
112
+ end
@@ -12,6 +12,7 @@ require "dependabot/shared_helpers"
12
12
  require "dependabot/update_checkers/base"
13
13
 
14
14
  require "dependabot/vcpkg"
15
+ require "dependabot/vcpkg/package/versions_database"
15
16
  require "dependabot/vcpkg/version"
16
17
 
17
18
  module Dependabot
@@ -22,16 +23,21 @@ module Dependabot
22
23
 
23
24
  sig do
24
25
  params(
25
- dependency: Dependabot::Dependency
26
+ dependency: Dependabot::Dependency,
27
+ versions_database: Dependabot::Vcpkg::Package::VersionsDatabase
26
28
  ).void
27
29
  end
28
- def initialize(dependency:)
30
+ def initialize(dependency:, versions_database: Dependabot::Vcpkg::Package::VersionsDatabase.new)
29
31
  @dependency = dependency
32
+ @versions_database = versions_database
30
33
  end
31
34
 
32
35
  sig { returns(Dependabot::Dependency) }
33
36
  attr_reader :dependency
34
37
 
38
+ sig { returns(Dependabot::Vcpkg::Package::VersionsDatabase) }
39
+ attr_reader :versions_database
40
+
35
41
  sig { returns(T.nilable(Dependabot::Package::PackageDetails)) }
36
42
  def fetch
37
43
  if registry_dependency?
@@ -75,88 +81,14 @@ module Dependabot
75
81
 
76
82
  sig { returns(T.nilable(Dependabot::Package::PackageDetails)) }
77
83
  def fetch_port_releases
78
- fetch_port_versions_from_git
79
- .filter_map { |version_info| create_port_package_release(version_info) }
80
- .reverse
81
- .uniq(&:version)
82
- .then do |releases|
83
- Dependabot::Package::PackageDetails.new(
84
- dependency: dependency,
85
- releases: releases
86
- )
87
- end
88
- end
89
-
90
- sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
91
- def fetch_port_versions_from_git
92
- port_path = "ports/#{dependency.name}/vcpkg.json"
93
- vcpkg_repo_path = "/opt/vcpkg"
94
-
95
- # Get each commit that modified the port's vcpkg.json
96
- git_log_cmd = [
97
- "git", "log", "--format=%H", "--follow", "--", port_path
98
- ]
84
+ release_dates = versions_database.release_dates_for(dependency.name)
99
85
 
100
- Dir.chdir(vcpkg_repo_path) do
101
- log_output = Dependabot::SharedHelpers.run_shell_command(git_log_cmd.join(" "))
86
+ releases = versions_database
87
+ .versions_for(dependency.name)
88
+ .map { |port_version| create_port_package_release(port_version, release_dates) }
89
+ .uniq(&:version)
102
90
 
103
- log_output.lines.map(&:strip).filter_map do |line|
104
- next if line.empty?
105
-
106
- commit_sha = line.strip
107
- next unless commit_sha.match?(/\A[0-9a-f]{40}\z/) # Validate SHA format
108
-
109
- # Get the vcpkg.json content for this commit
110
- version_info = extract_version_from_commit(commit_sha, port_path)
111
- version_info[:commit_sha] = commit_sha if version_info
112
- version_info
113
- end
114
- end
115
- rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
116
- Dependabot.logger.warn("Failed to fetch port versions for #{dependency.name}: #{e.message}")
117
- []
118
- end
119
-
120
- sig { params(commit_sha: String, file_path: String).returns(T.nilable(T::Hash[Symbol, T.untyped])) }
121
- def extract_version_from_commit(commit_sha, file_path)
122
- show_cmd = ["git", "show", "#{commit_sha}:#{file_path}"]
123
-
124
- file_content = Dependabot::SharedHelpers.run_shell_command(show_cmd.join(" "))
125
- parsed_json = JSON.parse(file_content)
126
-
127
- version = parsed_json["version"]
128
- port_version = parsed_json["port-version"] || 0
129
-
130
- return nil unless version
131
-
132
- # Combine version and port-version
133
- full_version = port_version.zero? ? version : "#{version}##{port_version}"
134
-
135
- {
136
- version: version,
137
- port_version: port_version,
138
- full_version: full_version,
139
- commit_date: get_commit_date(commit_sha)
140
- }
141
- rescue JSON::ParserError => e
142
- Dependabot.logger.warn("Failed to parse vcpkg.json for commit #{commit_sha}: #{e.message}")
143
- nil
144
- rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
145
- Dependabot.logger.warn("Failed to show file #{file_path} for commit #{commit_sha}: #{e.message}")
146
- nil
147
- end
148
-
149
- sig { params(commit_sha: String).returns(T.nilable(Time)) }
150
- def get_commit_date(commit_sha)
151
- date_cmd = ["git", "show", "--no-patch", "--format=%ci", commit_sha]
152
- date_output = Dependabot::SharedHelpers.run_shell_command(date_cmd.join(" "))
153
- Time.parse(date_output.strip)
154
- rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
155
- Dependabot.logger.warn("Failed to get commit date for #{commit_sha}: #{e.message}")
156
- nil
157
- rescue ArgumentError => e
158
- Dependabot.logger.warn("Invalid date format for commit #{commit_sha}: #{e.message}")
159
- nil
91
+ Dependabot::Package::PackageDetails.new(dependency: dependency, releases: releases)
160
92
  end
161
93
 
162
94
  sig { params(tag_info: T::Hash[Symbol, T.untyped]).returns(Dependabot::Package::PackageRelease) }
@@ -173,17 +105,27 @@ module Dependabot
173
105
  )
174
106
  end
175
107
 
176
- sig { params(version_info: T::Hash[Symbol, T.untyped]).returns(Dependabot::Package::PackageRelease) }
177
- def create_port_package_release(version_info)
108
+ sig do
109
+ params(
110
+ port_version: Dependabot::Vcpkg::Package::VersionsDatabase::PortVersion,
111
+ release_dates: T::Hash[String, Time]
112
+ ).returns(Dependabot::Package::PackageRelease)
113
+ end
114
+ def create_port_package_release(port_version, release_dates)
115
+ version = port_version.version
116
+ git_tree = port_version.git_tree
117
+
178
118
  Dependabot::Package::PackageRelease.new(
179
- version: Dependabot::Vcpkg::Version.new(version_info.fetch(:full_version)),
180
- tag: version_info.fetch(:full_version),
181
- url: "#{Vcpkg::VCPKG_DEFAULT_BASELINE_URL}/tree/#{version_info[:commit_sha]}/ports/#{dependency.name}",
182
- released_at: version_info[:commit_date],
119
+ version: version,
120
+ tag: version.to_s,
121
+ url: "#{Vcpkg::VCPKG_DEFAULT_REGISTRY_REPOSITORY}/tree/" \
122
+ "#{Vcpkg::VCPKG_DEFAULT_BASELINE_DEFAULT_BRANCH}/ports/#{dependency.name}",
123
+ released_at: git_tree && release_dates[git_tree],
183
124
  details: {
184
- "commit_sha" => version_info[:commit_sha],
185
- "base_version" => version_info[:version],
186
- "port_version" => version_info[:port_version]
125
+ "scheme" => port_version.scheme,
126
+ "base_version" => version.text,
127
+ "port_version" => version.port_version,
128
+ "git_tree" => git_tree
187
129
  }
188
130
  )
189
131
  end