dependabot-terraform 0.317.0 → 0.318.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: b7055fe970a2f595c719cd45b125f54ea2e264b9ef1b29f34366a323d2c39a41
4
- data.tar.gz: 526f1865cc6eb012a364740a4e6fa3784e5d0d066bb3bb0826ceb3807138e934
3
+ metadata.gz: 9aeadb67b3052b13cdaab12209c8be0e0c47aa7cc9077573fbe10396d2f63469
4
+ data.tar.gz: 340bfd127b2153d12aaa520abbae5d95bd86c5229aeaf73a316b4153af7fb6bb
5
5
  SHA512:
6
- metadata.gz: 4b627d2cb8fc9ddb8cce9bbd29b3eb67d33d8df747c9610c6ceb8789fa4d16cb85a136930e478a8f4b3705811fd6034e3102a7fc881c880477ab07cd17ba68fc
7
- data.tar.gz: 9bbc4238991c385ad673235de866d6f63cf03ed341ae40f094636db50b3076bd8f5bb0812ea96c631e9b08e7f825833275a99c1b1d65bc4c41e2a69af19ea6ba
6
+ metadata.gz: 94807295eb7c44635117a07a30d6073f744d40768d8f1ac45815aa1ffa421149c3c7e7dea7921e22cda1528a1959a6af000dd42e69ae2a305b3972c151a3565c
7
+ data.tar.gz: da3966cf9b5003da0d1ed7b2a08db979e83cc4d27cd717f070c627c78648bd6ad4b25dcd9a83e46b0af738f1098a2f666685a8844621a1b10158170896add941
@@ -0,0 +1,135 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "json"
5
+ require "time"
6
+ require "cgi"
7
+ require "excon"
8
+ require "sorbet-runtime"
9
+ require "dependabot/swift"
10
+
11
+ module Dependabot
12
+ module Terraform
13
+ module Package
14
+ class PackageDetailsFetcher
15
+ extend T::Sig
16
+
17
+ RELEASES_URL_GIT = "https://api.github.com/repos/"
18
+ RELEASE_URL_FOR_PROVIDER = "https://registry.terraform.io/v2/providers/"
19
+ RELEASE_URL_FOR_MODULE = "https://registry.terraform.io/v2/modules/"
20
+ APPLICATION_JSON = "JSON"
21
+ INCLUDE_FOR_PROVIDER = "?include=provider-versions"
22
+ INCLUDE_FOR_MODULE = "?include=module-versions"
23
+ # https://registry.terraform.io/v2/providers/hashicorp/aws?include=provider-versions
24
+ # https://registry.terraform.io/v2/modules/terraform-aws-modules/iam/aws?include=module-versions
25
+
26
+ ELIGIBLE_SOURCE_TYPES = T.let(
27
+ %w(git provider registry).freeze,
28
+ T::Array[String]
29
+ )
30
+
31
+ sig do
32
+ params(
33
+ dependency: Dependency,
34
+ credentials: T::Array[Dependabot::Credential],
35
+ git_commit_checker: Dependabot::GitCommitChecker
36
+ ).void
37
+ end
38
+ def initialize(dependency:, credentials:, git_commit_checker:)
39
+ @dependency = dependency
40
+ @credentials = credentials
41
+ @git_commit_checker = git_commit_checker
42
+ end
43
+
44
+ sig { returns(Dependabot::GitCommitChecker) }
45
+ attr_reader :git_commit_checker
46
+
47
+ sig { returns(T::Array[Dependabot::Credential]) }
48
+ attr_reader :credentials
49
+
50
+ sig { returns(T::Array[GitTagWithDetail]) }
51
+ def fetch_tag_and_release_date
52
+ truncate_github_url = @dependency.name.gsub("github.com/", "")
53
+ url = RELEASES_URL_GIT + "#{truncate_github_url}/releases"
54
+ result_lines = T.let([], T::Array[GitTagWithDetail])
55
+ # Fetch the releases from the GitHub API
56
+ response = Excon.get(url, headers: { "Accept" => "application/vnd.github.v3+json" })
57
+ Dependabot.logger.error("Failed call details: #{response.body}") unless response.status == 200
58
+ return result_lines unless response.status == 200
59
+
60
+ # Parse the JSON response
61
+ releases = JSON.parse(response.body)
62
+
63
+ # Extract version names and release dates into a hash
64
+ releases.map do |release|
65
+ result_lines << GitTagWithDetail.new(
66
+ tag: release["tag_name"],
67
+ release_date: release["published_at"]
68
+ )
69
+ end
70
+
71
+ # sort the result lines by tag in descending order
72
+ result_lines = result_lines.sort_by(&:tag).reverse
73
+ # Log the extracted details for debugging
74
+ Dependabot.logger.info("Extracted release details: #{result_lines}")
75
+ result_lines
76
+ end
77
+
78
+ sig { returns(T::Array[GitTagWithDetail]) }
79
+ def fetch_tag_and_release_date_from_provider
80
+ url = RELEASE_URL_FOR_PROVIDER + dependency_source_details&.fetch(:module_identifier) +
81
+ INCLUDE_FOR_PROVIDER
82
+ Dependabot.logger.info("Fetching provider release details from URL: #{url}")
83
+ result_lines = T.let([], T::Array[GitTagWithDetail])
84
+ # Fetch the releases from the provider API
85
+ response = Excon.get(url, headers: { "Accept" => "application/vnd.github.v3+json" })
86
+ Dependabot.logger.error("Failed call details: #{response.body}") unless response.status == 200
87
+ return result_lines unless response.status == 200
88
+
89
+ # Parse the JSON response
90
+ releases = JSON.parse(response.body).fetch("provider_versions", [])
91
+
92
+ # Extract version names and release dates into result_lines
93
+ releases.each do |release|
94
+ result_lines << GitTagWithDetail.new(
95
+ tag: release["version"],
96
+ release_date: release["published_at"]
97
+ )
98
+ end
99
+ # Sort the result lines by tag in descending order
100
+ result_lines.sort_by(&:tag).reverse
101
+ end
102
+
103
+ sig { returns(T::Array[GitTagWithDetail]) }
104
+ def fetch_tag_and_release_date_from_module
105
+ url = RELEASE_URL_FOR_MODULE + dependency_source_details&.fetch(:module_identifier) +
106
+ INCLUDE_FOR_MODULE
107
+ Dependabot.logger.info("Fetching provider release details from URL: #{url}")
108
+ result_lines = T.let([], T::Array[GitTagWithDetail])
109
+ # Fetch the releases from the provider API
110
+ response = Excon.get(url, headers: { "Accept" => "application/vnd.github.v3+json" })
111
+ Dependabot.logger.error("Failed call details: #{response.body}") unless response.status == 200
112
+ return result_lines unless response.status == 200
113
+
114
+ # Parse the JSON response
115
+ releases = JSON.parse(response.body).fetch("module-versions", [])
116
+
117
+ # Extract version names and release dates into result_lines
118
+ releases.each do |release|
119
+ result_lines << GitTagWithDetail.new(
120
+ tag: release["version"],
121
+ release_date: release["published_at"]
122
+ )
123
+ end
124
+ # Sort the result lines by tag in descending order
125
+ result_lines.sort_by(&:tag).reverse
126
+ end
127
+
128
+ sig { returns(T.nilable(T::Hash[T.any(String, Symbol), T.untyped])) }
129
+ def dependency_source_details
130
+ @dependency.source_details(allowed_types: ELIGIBLE_SOURCE_TYPES)
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,200 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "dependabot/update_checkers/base"
5
+ require "dependabot/terraform/package/package_details_fetcher"
6
+ require "sorbet-runtime"
7
+ require "dependabot/git_commit_checker"
8
+
9
+ module Dependabot
10
+ module Terraform
11
+ class UpdateChecker < Dependabot::UpdateCheckers::Base
12
+ class LatestVersionResolver
13
+ extend T::Sig
14
+
15
+ DAY_IN_SECONDS = T.let(24 * 60 * 60, Integer)
16
+
17
+ sig do
18
+ params(
19
+ dependency: Dependabot::Dependency,
20
+ credentials: T::Array[Dependabot::Credential],
21
+ cooldown_options: T.nilable(Dependabot::Package::ReleaseCooldownOptions),
22
+ git_commit_checker: Dependabot::GitCommitChecker
23
+ ).void
24
+ end
25
+ def initialize(dependency:, credentials:, cooldown_options:, git_commit_checker:)
26
+ @dependency = dependency
27
+ @credentials = credentials
28
+ @cooldown_options = cooldown_options
29
+ @git_commit_checker = T.let(
30
+ git_commit_checker,
31
+ Dependabot::GitCommitChecker
32
+ )
33
+ end
34
+
35
+ sig { returns(Dependabot::Dependency) }
36
+ attr_reader :dependency
37
+
38
+ # Return latest version tag for the dependency, it removes tags that are in cooldown period
39
+ # and returns the latest version tag that is not in cooldown period. If exception occurs
40
+ # it will return the latest version tag from the git_commit_checker. as it was before
41
+ sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
42
+ def latest_version_tag
43
+ # step one fetch allowed version tags and
44
+ allowed_version_tags = git_commit_checker.allowed_version_tags
45
+ begin
46
+ # sort the allowed version tags by name in descending order
47
+ select_version_tags_in_cooldown_period&.each do |tag_name|
48
+ # filter out if name is not in cooldown period
49
+ allowed_version_tags.reject! do |gitref_filtered|
50
+ true if gitref_filtered.name == tag_name
51
+ end
52
+ end
53
+ Dependabot.logger.info("Allowed version tags after filtering versions in cooldown:
54
+ #{allowed_version_tags.map(&:name).join(', ')}")
55
+ git_commit_checker.max_local_tag(allowed_version_tags)
56
+ rescue StandardError => e
57
+ Dependabot.logger.error("Error fetching latest version tag: #{e.message}")
58
+ git_commit_checker.local_tag_for_latest_version
59
+ end
60
+ end
61
+
62
+ # To filter versions in cooldown period based on version tags from registry call
63
+ sig { params(versions: T::Array[Dependabot::Version]).returns(T::Array[Dependabot::Version]) }
64
+ def filter_versions_in_cooldown_period_from_provider(versions)
65
+ # to make call for registry to get the versions
66
+ # step one fetch allowed version tags and
67
+
68
+ # sort the allowed version tags by name in descending order
69
+ select_tags_which_in_cooldown_from_provider&.each do |tag_name|
70
+ # Iterate through versions and filter out those matching the tag_name
71
+ versions.reject! do |version|
72
+ version.to_s == tag_name
73
+ end
74
+ end
75
+ Dependabot.logger.info("Allowed version tags after filtering versions in cooldown:
76
+ #{versions.map(&:to_s).join(', ')}")
77
+ versions
78
+ rescue StandardError => e
79
+ Dependabot.logger.error("Error filter_versions_in_cooldown_period_from_provider(versions): #{e.message}")
80
+ versions
81
+ end
82
+
83
+ # To filter versions in cooldown period based on version tags from registry call
84
+ sig { params(versions: T::Array[Dependabot::Version]).returns(T::Array[Dependabot::Version]) }
85
+ def filter_versions_in_cooldown_period_from_module(versions)
86
+ # to make call for registry to get the versions
87
+ # step one fetch allowed version tags and
88
+
89
+ # sort the allowed version tags by name in descending order
90
+ select_tags_which_in_cooldown_from_module&.each do |tag_name|
91
+ # Iterate through versions and filter out those matching the tag_name
92
+ versions.reject! do |version|
93
+ version.to_s == tag_name
94
+ end
95
+ end
96
+ Dependabot.logger.info("filter_versions_in_cooldown_period_from_module::
97
+ Allowed version tags after filtering versions in cooldown:#{versions.map(&:to_s).join(', ')}")
98
+ versions
99
+ rescue StandardError => e
100
+ Dependabot.logger.error("Error fetching latest version tag: #{e.message}")
101
+ versions
102
+ end
103
+
104
+ sig { returns(T.nilable(T::Array[String])) }
105
+ def select_version_tags_in_cooldown_period
106
+ version_tags_in_cooldown_period = T.let([], T::Array[String])
107
+
108
+ package_details_fetcher.fetch_tag_and_release_date.each do |git_tag_with_detail|
109
+ if check_if_version_in_cooldown_period?(T.must(git_tag_with_detail.release_date))
110
+ version_tags_in_cooldown_period << git_tag_with_detail.tag
111
+ end
112
+ end
113
+ version_tags_in_cooldown_period
114
+ rescue StandardError => e
115
+ Dependabot.logger.error("Error checking if version is in cooldown: #{e.message}")
116
+ version_tags_in_cooldown_period
117
+ end
118
+
119
+ sig { params(release_date: String).returns(T::Boolean) }
120
+ def check_if_version_in_cooldown_period?(release_date)
121
+ return false unless release_date.length.positive?
122
+
123
+ cooldown = @cooldown_options
124
+ return false unless cooldown
125
+
126
+ return false if cooldown.nil?
127
+
128
+ # Get maximum cooldown days based on semver parts
129
+ days = [cooldown.default_days, cooldown.semver_major_days].max
130
+ days = cooldown.semver_minor_days unless days > cooldown.semver_minor_days
131
+ days = cooldown.semver_patch_days unless days > cooldown.semver_patch_days
132
+ # Calculate the number of seconds passed since the release
133
+ passed_seconds = Time.now.to_i - release_date_to_seconds(release_date)
134
+ # Check if the release is within the cooldown period
135
+ passed_seconds < days * DAY_IN_SECONDS
136
+ end
137
+
138
+ sig { params(release_date: String).returns(Integer) }
139
+ def release_date_to_seconds(release_date)
140
+ Time.parse(release_date).to_i
141
+ rescue ArgumentError => e
142
+ Dependabot.logger.error("Invalid release date format: #{release_date} and error: #{e.message}")
143
+ 0 # Default to 360 days in seconds if parsing fails, so that it will not be in cooldown
144
+ end
145
+
146
+ sig { returns(T.nilable(T::Array[String])) }
147
+ def select_tags_which_in_cooldown_from_provider
148
+ version_tags_in_cooldown_from_provider = T.let([], T::Array[String])
149
+
150
+ package_details_fetcher.fetch_tag_and_release_date_from_provider.each do |git_tag_with_detail|
151
+ if check_if_version_in_cooldown_period?(T.must(git_tag_with_detail.release_date))
152
+ version_tags_in_cooldown_from_provider << git_tag_with_detail.tag
153
+ end
154
+ end
155
+ version_tags_in_cooldown_from_provider
156
+ rescue StandardError => e
157
+ Dependabot.logger.error("Error checking if version is in cooldown: #{e.message}")
158
+ version_tags_in_cooldown_from_provider
159
+ end
160
+
161
+ sig { returns(T.nilable(T::Array[String])) }
162
+ def select_tags_which_in_cooldown_from_module
163
+ version_tags_in_cooldown_from_module = T.let([], T::Array[String])
164
+
165
+ package_details_fetcher.fetch_tag_and_release_date_from_module.each do |git_tag_with_detail|
166
+ if check_if_version_in_cooldown_period?(T.must(git_tag_with_detail.release_date))
167
+ version_tags_in_cooldown_from_module << git_tag_with_detail.tag
168
+ end
169
+ end
170
+ version_tags_in_cooldown_from_module
171
+ rescue StandardError => e
172
+ Dependabot.logger.error("Error checking if version is in cooldown: #{e.message}")
173
+ version_tags_in_cooldown_from_module
174
+ end
175
+
176
+ sig { returns(Package::PackageDetailsFetcher) }
177
+ def package_details_fetcher
178
+ @package_details_fetcher ||= T.let(
179
+ Package::PackageDetailsFetcher.new(
180
+ dependency: dependency,
181
+ credentials: credentials,
182
+ git_commit_checker: git_commit_checker
183
+ ), T.nilable(Package::PackageDetailsFetcher)
184
+ )
185
+ end
186
+
187
+ sig { returns(T::Boolean) }
188
+ def cooldown_enabled?
189
+ Dependabot::Experiments.enabled?(:enable_cooldown_for_swift)
190
+ end
191
+
192
+ sig { returns(Dependabot::GitCommitChecker) }
193
+ attr_reader :git_commit_checker
194
+
195
+ sig { returns(T::Array[Dependabot::Credential]) }
196
+ attr_reader :credentials
197
+ end
198
+ end
199
+ end
200
+ end
@@ -16,6 +16,8 @@ module Dependabot
16
16
  class UpdateChecker < Dependabot::UpdateCheckers::Base
17
17
  extend T::Sig
18
18
 
19
+ require_relative "update_checker/latest_version_resolver"
20
+
19
21
  ELIGIBLE_SOURCE_TYPES = T.let(
20
22
  %w(git provider registry).freeze,
21
23
  T::Array[String]
@@ -79,9 +81,10 @@ module Dependabot
79
81
  return @latest_version_for_registry_dependency if @latest_version_for_registry_dependency
80
82
 
81
83
  versions = all_module_versions
84
+ # Filter versions which are in cooldown period
85
+ latest_version_resolver.filter_versions_in_cooldown_period_from_module(versions)
82
86
  versions.reject!(&:prerelease?) unless wants_prerelease?
83
87
  versions.reject! { |v| ignore_requirements.any? { |r| r.satisfied_by?(v) } }
84
-
85
88
  @latest_version_for_registry_dependency = T.let(
86
89
  versions.max,
87
90
  T.nilable(Dependabot::Terraform::Version)
@@ -118,6 +121,8 @@ module Dependabot
118
121
  return @latest_version_for_provider_dependency if @latest_version_for_provider_dependency
119
122
 
120
123
  versions = all_provider_versions
124
+ # Filter versions which are in cooldown period
125
+ latest_version_resolver.filter_versions_in_cooldown_period_from_provider(versions)
121
126
  versions.reject!(&:prerelease?) unless wants_prerelease?
122
127
  versions.reject! { |v| ignore_requirements.any? { |r| r.satisfied_by?(v) } }
123
128
 
@@ -153,8 +158,8 @@ module Dependabot
153
158
  # we want to update that tag. Because we don't have a lockfile, the
154
159
  # latest version is the tag itself.
155
160
  if git_commit_checker.pinned_ref_looks_like_version?
156
- latest_tag = git_commit_checker.local_tag_for_latest_version
157
- &.fetch(:tag)
161
+ # Filter version tags that are in cooldown period
162
+ latest_tag = latest_version_resolver.latest_version_tag&.fetch(:tag)
158
163
  version_rgx = GitCommitChecker::VERSION_REGEX
159
164
  return unless latest_tag.match(version_rgx)
160
165
 
@@ -214,6 +219,16 @@ module Dependabot
214
219
  git_commit_checker.git_dependency?
215
220
  end
216
221
 
222
+ sig { returns(LatestVersionResolver) }
223
+ def latest_version_resolver
224
+ LatestVersionResolver.new(
225
+ dependency: dependency,
226
+ credentials: credentials,
227
+ cooldown_options: update_cooldown,
228
+ git_commit_checker: git_commit_checker
229
+ )
230
+ end
231
+
217
232
  sig { returns(Dependabot::GitCommitChecker) }
218
233
  def git_commit_checker
219
234
  @git_commit_checker ||= T.let(
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-terraform
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.317.0
4
+ version: 0.318.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.317.0
18
+ version: 0.318.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 0.317.0
25
+ version: 0.318.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: debug
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -249,18 +249,20 @@ files:
249
249
  - lib/dependabot/terraform/file_selector.rb
250
250
  - lib/dependabot/terraform/file_updater.rb
251
251
  - lib/dependabot/terraform/metadata_finder.rb
252
+ - lib/dependabot/terraform/package/package_details_fetcher.rb
252
253
  - lib/dependabot/terraform/package_manager.rb
253
254
  - lib/dependabot/terraform/registry_client.rb
254
255
  - lib/dependabot/terraform/requirement.rb
255
256
  - lib/dependabot/terraform/requirements_updater.rb
256
257
  - lib/dependabot/terraform/update_checker.rb
258
+ - lib/dependabot/terraform/update_checker/latest_version_resolver.rb
257
259
  - lib/dependabot/terraform/version.rb
258
260
  homepage: https://github.com/dependabot/dependabot-core
259
261
  licenses:
260
262
  - MIT
261
263
  metadata:
262
264
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
263
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.317.0
265
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.318.0
264
266
  rdoc_options: []
265
267
  require_paths:
266
268
  - lib