dependabot-common 0.299.1 → 0.300.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: 0b3d1f5344de1095bf812f3f4c45c42b0e7820ebd3f560911e3c83ed5db8b0cc
4
- data.tar.gz: 9fd396e05f663104aa8af87bb1d72147474986d4bbb83c2e761cc75f3f5fa50f
3
+ metadata.gz: 430d17c9cd55d06157f1d17b68484d6eff404a01556ec23e7c135e6717ab8115
4
+ data.tar.gz: 59c83e71796d1001cce58205b36ad13878d15e7c20a414fd555725cf3512e1e9
5
5
  SHA512:
6
- metadata.gz: e57b416955fbc286b2567659fe431aaf4826c990d39719c500adf66aa101c843c5f234bbf4e11c70cc1f94e9db49e369933075c10bf334398e61591ba4625946
7
- data.tar.gz: bcd0d2e2e5290c70f4605411a43e64b22e410c33ba0fe8e2f8509476df3856c5d3ea741b54d341bc7f736fdacdc4ce8757a6bd5c36b2ef4deaf2f69fcfd05d5d
6
+ metadata.gz: 602fec245c2dd192286d03064a2254c86c8817cd2a284401a142714223d55c8374b55abe5f61b60d42d06acbb2efe1ad3ba494b2a639d850fe21b4d3c38b36ed
7
+ data.tar.gz: 5fbde394f4529f08fced5621d6b406d92f173410acb76a310051f93f4bdf80ed8934bc1bea3e431dfce1bfc45fc151436d40f0be4cf8105d1d3d052912452caa
@@ -12,6 +12,7 @@ require "dependabot/update_checkers/version_filters"
12
12
  require "dependabot/registry_client"
13
13
  require "dependabot/bundler"
14
14
  require "dependabot/package/package_details"
15
+ require "dependabot/package/release_cooldown_options"
15
16
 
16
17
  module Dependabot
17
18
  module Package
@@ -24,10 +25,10 @@ module Dependabot
24
25
  sig { returns(Dependabot::Dependency) }
25
26
  attr_reader :dependency
26
27
 
27
- sig { returns(T::Array[T.untyped]) }
28
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
28
29
  attr_reader :dependency_files
29
30
 
30
- sig { returns(T::Array[T.untyped]) }
31
+ sig { returns(T::Array[Dependabot::Credential]) }
31
32
  attr_reader :credentials
32
33
 
33
34
  sig { returns(T::Array[String]) }
@@ -36,6 +37,9 @@ module Dependabot
36
37
  sig { returns(T::Array[SecurityAdvisory]) }
37
38
  attr_reader :security_advisories
38
39
 
40
+ sig { returns(T.nilable(ReleaseCooldownOptions)) }
41
+ attr_reader :cooldown_options
42
+
39
43
  sig { returns(T::Hash[Symbol, T.untyped]) }
40
44
  attr_reader :options
41
45
 
@@ -46,6 +50,7 @@ module Dependabot
46
50
  credentials: T::Array[Dependabot::Credential],
47
51
  ignored_versions: T::Array[String],
48
52
  security_advisories: T::Array[Dependabot::SecurityAdvisory],
53
+ cooldown_options: T.nilable(ReleaseCooldownOptions),
49
54
  raise_on_ignored: T::Boolean,
50
55
  options: T::Hash[Symbol, T.untyped]
51
56
  ).void
@@ -56,6 +61,7 @@ module Dependabot
56
61
  credentials:,
57
62
  ignored_versions:,
58
63
  security_advisories:,
64
+ cooldown_options: nil,
59
65
  raise_on_ignored: false,
60
66
  options: {}
61
67
  )
@@ -64,6 +70,7 @@ module Dependabot
64
70
  @credentials = credentials
65
71
  @ignored_versions = ignored_versions
66
72
  @security_advisories = security_advisories
73
+ @cooldown_options = cooldown_options
67
74
  @raise_on_ignored = raise_on_ignored
68
75
  # It can be used by sub classes to pass options to the registry client
69
76
  @options = options
@@ -119,6 +126,7 @@ module Dependabot
119
126
  return unless version_hashes
120
127
 
121
128
  version_hashes = filter_yanked_versions(version_hashes)
129
+ version_hashes = filter_by_cooldown(version_hashes)
122
130
  versions = filter_unsupported_versions(version_hashes, language_version)
123
131
  versions = filter_prerelease_versions(versions)
124
132
  versions = filter_ignored_versions(versions)
@@ -135,6 +143,7 @@ module Dependabot
135
143
  return unless version_hashes
136
144
 
137
145
  version_hashes = filter_yanked_versions(version_hashes)
146
+ version_hashes = filter_by_cooldown(version_hashes)
138
147
  versions = filter_unsupported_versions(version_hashes, language_version)
139
148
  versions = filter_prerelease_versions(versions)
140
149
  versions = filter_ignored_versions(versions)
@@ -152,6 +161,7 @@ module Dependabot
152
161
  return unless version_hashes
153
162
 
154
163
  version_hashes = filter_yanked_versions(version_hashes)
164
+ version_hashes = filter_by_cooldown(version_hashes)
155
165
  versions = filter_unsupported_versions(version_hashes, language_version)
156
166
  # versions = filter_prerelease_versions(versions)
157
167
  versions = Dependabot::UpdateCheckers::VersionFilters.filter_vulnerable_versions(
@@ -176,6 +186,29 @@ module Dependabot
176
186
  filtered
177
187
  end
178
188
 
189
+ sig do
190
+ params(releases: T::Array[Dependabot::Package::PackageRelease])
191
+ .returns(T::Array[Dependabot::Package::PackageRelease])
192
+ end
193
+ def filter_by_cooldown(releases)
194
+ return releases unless cooldown_enabled?
195
+ return releases unless cooldown_options
196
+
197
+ current_version = dependency.version ? version_class.new(dependency.version) : nil
198
+
199
+ filtered = releases.reject do |release|
200
+ next false unless release.released_at
201
+
202
+ days = cooldown_days_for(current_version, release.version)
203
+ (Time.now.to_i - release.released_at.to_i) < (days * 24 * 60 * 60)
204
+ end
205
+
206
+ if releases.count > filtered.count
207
+ Dependabot.logger.info("Filtered out #{releases.count - filtered.count} versions due to cooldown")
208
+ end
209
+ filtered
210
+ end
211
+
179
212
  sig do
180
213
  params(
181
214
  releases: T::Array[Dependabot::Package::PackageRelease],
@@ -257,6 +290,41 @@ module Dependabot
257
290
  .select { |v| reqs.all? { |r| r.any? { |o| o.satisfied_by?(v) } } }
258
291
  end
259
292
 
293
+ sig { returns(T::Boolean) }
294
+ def cooldown_enabled?
295
+ false
296
+ end
297
+
298
+ sig do
299
+ params(
300
+ current_version: T.nilable(Dependabot::Version),
301
+ new_version: Dependabot::Version
302
+ ).returns(Integer)
303
+ end
304
+ def cooldown_days_for(current_version, new_version)
305
+ cooldown = @cooldown_options
306
+ return 0 if cooldown.nil?
307
+ return 0 unless cooldown_enabled?
308
+ return 0 unless cooldown.included?(dependency.name)
309
+ return cooldown.default_days if current_version.nil?
310
+
311
+ current_version_semver = current_version.semver_parts
312
+ new_version_semver = new_version.semver_parts
313
+
314
+ # If semver_parts is nil for either, return default cooldown
315
+ return cooldown.default_days if current_version_semver.nil? || new_version_semver.nil?
316
+
317
+ # Ensure values are always integers
318
+ current_major, current_minor, current_patch = current_version_semver
319
+ new_major, new_minor, new_patch = new_version_semver
320
+
321
+ # Determine cooldown based on version difference
322
+ return cooldown.major_days if new_major > current_major
323
+ return cooldown.minor_days if new_minor > current_minor
324
+ return cooldown.patch_days if new_patch > current_patch
325
+
326
+ cooldown.default_days
327
+ end
260
328
  sig { returns(T::Boolean) }
261
329
  def wants_prerelease?
262
330
  return version_class.new(dependency.version).prerelease? if dependency.version
@@ -0,0 +1,61 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Dependabot
7
+ module Package
8
+ class ReleaseCooldownOptions
9
+ extend T::Sig
10
+
11
+ sig do
12
+ params(
13
+ default_days: T.nilable(Integer),
14
+ major_days: T.nilable(Integer),
15
+ minor_days: T.nilable(Integer),
16
+ patch_days: T.nilable(Integer),
17
+ include: T.nilable(T::Array[String]),
18
+ exclude: T.nilable(T::Array[String])
19
+ ).void
20
+ end
21
+ def initialize(
22
+ default_days: 0, major_days: 0, minor_days: 0, patch_days: 0,
23
+ include: [], exclude: []
24
+ )
25
+ default_days ||= 0
26
+ major_days ||= 0
27
+ minor_days ||= 0
28
+ patch_days ||= 0
29
+ include ||= []
30
+ exclude ||= []
31
+
32
+ @default_days = T.let(default_days, Integer)
33
+ @major_days = T.let(major_days.positive? ? major_days : default_days, Integer)
34
+ @minor_days = T.let(minor_days.positive? ? minor_days : default_days, Integer)
35
+ @patch_days = T.let(patch_days.positive? ? patch_days : default_days, Integer)
36
+ @include = T.let(include.to_set, T::Set[String])
37
+ @exclude = T.let(exclude.to_set, T::Set[String])
38
+ end
39
+
40
+ sig { returns(Integer) }
41
+ attr_reader :default_days, :major_days, :minor_days, :patch_days
42
+
43
+ sig { returns(T::Set[String]) }
44
+ attr_reader :include, :exclude
45
+
46
+ sig { params(dependency_name: String).returns(T::Boolean) }
47
+ def included?(dependency_name)
48
+ return false if dependency_name.empty? || excluded?(dependency_name)
49
+
50
+ @include.empty? || @include.any? { |pattern| File.fnmatch?(pattern, dependency_name) }
51
+ end
52
+
53
+ private
54
+
55
+ sig { params(dependency_name: String).returns(T::Boolean) }
56
+ def excluded?(dependency_name)
57
+ @exclude.any? { |pattern| File.fnmatch?(pattern, dependency_name) }
58
+ end
59
+ end
60
+ end
61
+ end
@@ -9,6 +9,7 @@ require "json"
9
9
  require "open3"
10
10
  require "sorbet-runtime"
11
11
  require "tmpdir"
12
+ require "securerandom"
12
13
 
13
14
  require "dependabot/credential"
14
15
  require "dependabot/simple_instrumentor"
@@ -22,7 +23,6 @@ module Dependabot
22
23
  module SharedHelpers # rubocop:disable Metrics/ModuleLength
23
24
  extend T::Sig
24
25
 
25
- GIT_CONFIG_GLOBAL_PATH = T.let(File.expand_path(".gitconfig", Utils::BUMP_TMP_DIR_PATH), String)
26
26
  USER_AGENT = T.let(
27
27
  "dependabot-core/#{Dependabot::VERSION} " \
28
28
  "#{Excon::USER_AGENT} ruby/#{RUBY_VERSION} " \
@@ -290,12 +290,15 @@ module Dependabot
290
290
  FileUtils.mkdir_p(Utils::BUMP_TMP_DIR_PATH)
291
291
 
292
292
  previous_config = ENV.fetch("GIT_CONFIG_GLOBAL", nil)
293
+ # adding a random suffix to avoid conflicts when running in parallel
294
+ # some package managers like bundler will modify the global git config
295
+ git_config_global_path = File.expand_path("#{SecureRandom.hex(16)}.gitconfig", Utils::BUMP_TMP_DIR_PATH)
293
296
  previous_terminal_prompt = ENV.fetch("GIT_TERMINAL_PROMPT", nil)
294
297
 
295
298
  begin
296
- ENV["GIT_CONFIG_GLOBAL"] = GIT_CONFIG_GLOBAL_PATH
299
+ ENV["GIT_CONFIG_GLOBAL"] = git_config_global_path
297
300
  ENV["GIT_TERMINAL_PROMPT"] = "false"
298
- configure_git_to_use_https_with_credentials(credentials, safe_directories)
301
+ configure_git_to_use_https_with_credentials(credentials, safe_directories, git_config_global_path)
299
302
  yield
300
303
  ensure
301
304
  ENV["GIT_CONFIG_GLOBAL"] = previous_config
@@ -304,7 +307,7 @@ module Dependabot
304
307
  rescue Errno::ENOSPC => e
305
308
  raise Dependabot::OutOfDisk, e.message
306
309
  ensure
307
- FileUtils.rm_f(GIT_CONFIG_GLOBAL_PATH)
310
+ FileUtils.rm_f(T.must(git_config_global_path))
308
311
  end
309
312
 
310
313
  # Handle SCP-style git URIs
@@ -321,9 +324,12 @@ module Dependabot
321
324
  end
322
325
 
323
326
  # rubocop:disable Metrics/PerceivedComplexity
324
- sig { params(credentials: T::Array[Dependabot::Credential], safe_directories: T::Array[String]).void }
325
- def self.configure_git_to_use_https_with_credentials(credentials, safe_directories)
326
- File.open(GIT_CONFIG_GLOBAL_PATH, "w") do |file|
327
+ sig do
328
+ params(credentials: T::Array[Dependabot::Credential], safe_directories: T::Array[String],
329
+ git_config_global_path: String).void
330
+ end
331
+ def self.configure_git_to_use_https_with_credentials(credentials, safe_directories, git_config_global_path)
332
+ File.open(git_config_global_path, "w") do |file|
327
333
  file << "# Generated by dependabot/dependabot-core"
328
334
  end
329
335
 
@@ -7,6 +7,7 @@ require "sorbet-runtime"
7
7
  require "dependabot/requirements_update_strategy"
8
8
  require "dependabot/security_advisory"
9
9
  require "dependabot/utils"
10
+ require "dependabot/package/release_cooldown_options"
10
11
 
11
12
  module Dependabot
12
13
  module UpdateCheckers
@@ -41,6 +42,9 @@ module Dependabot
41
42
  sig { returns(T.nilable(Dependabot::DependencyGroup)) }
42
43
  attr_reader :dependency_group
43
44
 
45
+ sig { returns(T.nilable(Dependabot::Package::ReleaseCooldownOptions)) }
46
+ attr_reader :update_cooldown
47
+
44
48
  sig { returns(T::Hash[Symbol, T.untyped]) }
45
49
  attr_reader :options
46
50
 
@@ -55,6 +59,7 @@ module Dependabot
55
59
  security_advisories: T::Array[Dependabot::SecurityAdvisory],
56
60
  requirements_update_strategy: T.nilable(Dependabot::RequirementsUpdateStrategy),
57
61
  dependency_group: T.nilable(Dependabot::DependencyGroup),
62
+ update_cooldown: T.nilable(Dependabot::Package::ReleaseCooldownOptions),
58
63
  options: T::Hash[Symbol, T.untyped]
59
64
  )
60
65
  .void
@@ -63,7 +68,7 @@ module Dependabot
63
68
  repo_contents_path: nil, ignored_versions: [],
64
69
  raise_on_ignored: false, security_advisories: [],
65
70
  requirements_update_strategy: nil, dependency_group: nil,
66
- options: {})
71
+ update_cooldown: nil, options: {})
67
72
  @dependency = dependency
68
73
  @dependency_files = dependency_files
69
74
  @repo_contents_path = repo_contents_path
@@ -73,6 +78,7 @@ module Dependabot
73
78
  @raise_on_ignored = raise_on_ignored
74
79
  @security_advisories = security_advisories
75
80
  @dependency_group = dependency_group
81
+ @update_cooldown = update_cooldown
76
82
  @options = options
77
83
  end
78
84
 
@@ -73,5 +73,18 @@ module Dependabot
73
73
  def lowest_prerelease_suffix
74
74
  "a"
75
75
  end
76
+
77
+ sig { returns(T.nilable([Integer, Integer, Integer])) }
78
+ def semver_parts
79
+ # Extracts only the numeric major.minor.patch part of the version, ensuring it starts with a number
80
+ match = to_semver.match(/^\d+(?:\.\d+)?(?:\.\d+)?(?=[^\d]|$)/)
81
+ return nil unless match
82
+
83
+ first_match = match[0]
84
+ return nil unless first_match
85
+
86
+ major, minor, patch = first_match.split(".").map(&:to_i)
87
+ [major || 0, minor || 0, patch || 0]
88
+ end
76
89
  end
77
90
  end
data/lib/dependabot.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Dependabot
5
- VERSION = "0.299.1"
5
+ VERSION = "0.300.0"
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-common
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.299.1
4
+ version: 0.300.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-02-28 00:00:00.000000000 Z
11
+ date: 2025-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-codecommit
@@ -572,6 +572,7 @@ files:
572
572
  - lib/dependabot/package/package_language.rb
573
573
  - lib/dependabot/package/package_latest_version_finder.rb
574
574
  - lib/dependabot/package/package_release.rb
575
+ - lib/dependabot/package/release_cooldown_options.rb
575
576
  - lib/dependabot/pull_request_creator.rb
576
577
  - lib/dependabot/pull_request_creator/azure.rb
577
578
  - lib/dependabot/pull_request_creator/bitbucket.rb
@@ -619,7 +620,7 @@ licenses:
619
620
  - MIT
620
621
  metadata:
621
622
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
622
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.299.1
623
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.300.0
623
624
  post_install_message:
624
625
  rdoc_options: []
625
626
  require_paths: