dependabot-pre_commit 0.361.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 756b5487cc3c7be59843fde399c176c66d3716acca89a364b9a9b2309001a0eb
4
+ data.tar.gz: 11184797fefef083921b31eef2b74ca04a27e70ddf0e3f48cc7819554a8c2c56
5
+ SHA512:
6
+ metadata.gz: ee6ac4a1364fa3f9c7d897c80dd5d68edf73552b522b112175bcda3e1e76b0e35cabb4904c1fd22027709de68544b38e0b92473217cbad72cf5f12fdc7fb1c91
7
+ data.tar.gz: adcecfc80611486b0446a56cc6a95d011b1213e4266aff09b9bd0623fff26c1e87f513726449c8f4e7a34a3f1919cf1ba98a2e9f604696dc0f4cb5335b176e8b
@@ -0,0 +1,89 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Dependabot
7
+ module PreCommit
8
+ module AdditionalDependencyCheckers
9
+ # Abstract base class for language-specific additional_dependency update checkers.
10
+ # Each language implementation should inherit from this class and implement
11
+ # the abstract methods.
12
+ #
13
+ # The checker is responsible for:
14
+ # 1. Finding the latest available version from the language's registry (PyPI, npm, etc.)
15
+ # 2. Generating updated requirements that preserve the original version constraint operators
16
+ #
17
+ # Example implementation for a new language:
18
+ #
19
+ # class MyLanguage < Base
20
+ # def latest_version
21
+ # # Delegate to ecosystem's UpdateChecker
22
+ # ecosystem_checker = Dependabot::UpdateCheckers
23
+ # .for_package_manager("my_pm")
24
+ # .new(dependency: build_ecosystem_dependency, ...)
25
+ # ecosystem_checker.latest_version&.to_s
26
+ # end
27
+ #
28
+ # def updated_requirements(latest_version)
29
+ # # Build updated requirements preserving operators
30
+ # end
31
+ # end
32
+ #
33
+ # AdditionalDependencyCheckers.register("my_language", MyLanguage)
34
+ #
35
+ class Base
36
+ extend T::Sig
37
+ extend T::Helpers
38
+
39
+ abstract!
40
+
41
+ sig do
42
+ params(
43
+ source: T::Hash[Symbol, T.untyped],
44
+ credentials: T::Array[Dependabot::Credential],
45
+ requirements: T::Array[T::Hash[Symbol, T.untyped]],
46
+ current_version: T.nilable(String)
47
+ ).void
48
+ end
49
+ def initialize(source:, credentials:, requirements:, current_version:)
50
+ @source = source
51
+ @credentials = credentials
52
+ @requirements = requirements
53
+ @current_version = current_version
54
+ end
55
+
56
+ # Find the latest available version for this dependency
57
+ # Should delegate to the appropriate ecosystem UpdateChecker
58
+ # Returns nil if no update is available or if there's an error
59
+ sig { abstract.returns(T.nilable(String)) }
60
+ def latest_version; end
61
+
62
+ # Generate updated requirements for the new version
63
+ # Should preserve the original version constraint operator (>=, ~=, etc.)
64
+ # and update the source hash with the new original_string
65
+ sig { abstract.params(latest_version: String).returns(T::Array[T::Hash[Symbol, T.untyped]]) }
66
+ def updated_requirements(latest_version); end
67
+
68
+ private
69
+
70
+ sig { returns(T::Hash[Symbol, T.untyped]) }
71
+ attr_reader :source
72
+
73
+ sig { returns(T::Array[Dependabot::Credential]) }
74
+ attr_reader :credentials
75
+
76
+ sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
77
+ attr_reader :requirements
78
+
79
+ sig { returns(T.nilable(String)) }
80
+ attr_reader :current_version
81
+
82
+ sig { returns(T.nilable(String)) }
83
+ def package_name
84
+ source[:package_name]&.to_s
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,160 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+ require "dependabot/dependency"
6
+ require "dependabot/update_checkers"
7
+ require "dependabot/go_modules/version"
8
+ require "dependabot/pre_commit/additional_dependency_checkers"
9
+ require "dependabot/pre_commit/additional_dependency_checkers/base"
10
+
11
+ module Dependabot
12
+ module PreCommit
13
+ module AdditionalDependencyCheckers
14
+ class Go < Base
15
+ extend T::Sig
16
+
17
+ sig { override.returns(T.nilable(String)) }
18
+ def latest_version
19
+ return nil unless package_name
20
+
21
+ @latest_version ||= T.let(
22
+ fetch_latest_version_via_go_checker,
23
+ T.nilable(String)
24
+ )
25
+ end
26
+
27
+ sig { override.params(latest_version: String).returns(T::Array[T::Hash[Symbol, T.untyped]]) }
28
+ def updated_requirements(latest_version)
29
+ requirements.map do |original_req|
30
+ original_source = original_req[:source]
31
+ next original_req unless original_source.is_a?(Hash)
32
+ next original_req unless original_source[:type] == "additional_dependency"
33
+
34
+ new_requirement = "v#{latest_version}"
35
+
36
+ new_original_string = build_original_string(
37
+ original_name: original_source[:original_name] || original_source[:package_name],
38
+ requirement: new_requirement
39
+ )
40
+
41
+ new_source = original_source.merge(original_string: new_original_string)
42
+
43
+ original_req.merge(
44
+ requirement: new_requirement,
45
+ source: new_source
46
+ )
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ sig { returns(T.nilable(String)) }
53
+ def fetch_latest_version_via_go_checker
54
+ go_checker = go_update_checker
55
+ return nil unless go_checker
56
+
57
+ latest = go_checker.latest_version
58
+ Dependabot.logger.info("Go UpdateChecker found latest version: #{latest || 'none'}")
59
+
60
+ latest&.to_s
61
+ rescue Dependabot::PrivateSourceTimedOut,
62
+ Dependabot::PrivateSourceAuthenticationFailure,
63
+ Dependabot::DependencyFileNotResolvable,
64
+ Dependabot::DependencyNotFound,
65
+ Excon::Error::Timeout,
66
+ Excon::Error::Socket => e
67
+ Dependabot.logger.warn("Error checking Go module: #{e.message}")
68
+ nil
69
+ end
70
+
71
+ sig { returns(T.nilable(Dependabot::UpdateCheckers::Base)) }
72
+ def go_update_checker
73
+ @go_update_checker ||= T.let(
74
+ build_go_update_checker,
75
+ T.nilable(Dependabot::UpdateCheckers::Base)
76
+ )
77
+ end
78
+
79
+ sig { returns(T.nilable(Dependabot::UpdateCheckers::Base)) }
80
+ def build_go_update_checker
81
+ go_dependency = build_go_dependency
82
+ return nil unless go_dependency
83
+
84
+ Dependabot.logger.info("Delegating to Go UpdateChecker for module: #{go_dependency.name}")
85
+
86
+ Dependabot::UpdateCheckers.for_package_manager("go_modules").new(
87
+ dependency: go_dependency,
88
+ dependency_files: build_go_dependency_files,
89
+ credentials: credentials,
90
+ ignored_versions: [],
91
+ security_advisories: [],
92
+ raise_on_ignored: false
93
+ )
94
+ end
95
+
96
+ sig { returns(T.nilable(Dependabot::Dependency)) }
97
+ def build_go_dependency
98
+ return nil unless package_name
99
+
100
+ version = current_version || extract_version_from_requirement
101
+
102
+ Dependabot::Dependency.new(
103
+ name: T.must(package_name),
104
+ version: version,
105
+ requirements: [{
106
+ requirement: version ? "v#{version}" : nil,
107
+ groups: [],
108
+ file: "go.mod",
109
+ source: { type: "default", source: T.must(package_name) }
110
+ }],
111
+ package_manager: "go_modules"
112
+ )
113
+ end
114
+
115
+ sig { returns(T.nilable(String)) }
116
+ def extract_version_from_requirement
117
+ req_string = requirements.first&.dig(:requirement)
118
+ return nil unless req_string
119
+
120
+ # Go versions are like "v1.2.3" — strip the leading "v"
121
+ version = req_string.to_s.delete_prefix("v")
122
+ return nil unless Dependabot::GoModules::Version.correct?(version)
123
+
124
+ version
125
+ end
126
+
127
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
128
+ def build_go_dependency_files
129
+ version = current_version || extract_version_from_requirement
130
+ version_string = version ? "v#{version}" : ""
131
+ content = "module dependabot/pre-commit-dummy\n\ngo 1.21\n\nrequire #{package_name} #{version_string}\n"
132
+
133
+ [
134
+ Dependabot::DependencyFile.new(
135
+ name: "go.mod",
136
+ content: content
137
+ )
138
+ ]
139
+ end
140
+
141
+ sig do
142
+ params(
143
+ original_name: T.nilable(String),
144
+ requirement: T.nilable(String)
145
+ ).returns(String)
146
+ end
147
+ def build_original_string(original_name:, requirement:)
148
+ base = original_name.to_s
149
+ base = "#{base}@#{requirement}" if requirement
150
+ base
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ Dependabot::PreCommit::AdditionalDependencyCheckers.register(
158
+ "golang",
159
+ Dependabot::PreCommit::AdditionalDependencyCheckers::Go
160
+ )
@@ -0,0 +1,175 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "excon"
5
+ require "json"
6
+ require "sorbet-runtime"
7
+ require "dependabot/dependency"
8
+ require "dependabot/update_checkers"
9
+ require "dependabot/pre_commit/additional_dependency_checkers"
10
+ require "dependabot/pre_commit/additional_dependency_checkers/base"
11
+
12
+ module Dependabot
13
+ module PreCommit
14
+ module AdditionalDependencyCheckers
15
+ class Node < Base
16
+ extend T::Sig
17
+
18
+ sig { override.returns(T.nilable(String)) }
19
+ def latest_version
20
+ return nil unless package_name
21
+
22
+ @latest_version ||= T.let(
23
+ fetch_latest_version_via_npm_checker,
24
+ T.nilable(String)
25
+ )
26
+ end
27
+
28
+ sig { override.params(latest_version: String).returns(T::Array[T::Hash[Symbol, T.untyped]]) }
29
+ def updated_requirements(latest_version)
30
+ requirements.map do |original_req|
31
+ original_source = original_req[:source]
32
+ next original_req unless original_source.is_a?(Hash)
33
+ next original_req unless original_source[:type] == "additional_dependency"
34
+
35
+ original_requirement = original_req[:requirement]
36
+ new_requirement = build_updated_requirement(original_requirement, latest_version)
37
+
38
+ new_original_string = build_original_string(
39
+ package_name: original_source[:original_name] || original_source[:package_name],
40
+ requirement: new_requirement
41
+ )
42
+
43
+ new_source = original_source.merge(original_string: new_original_string)
44
+
45
+ original_req.merge(
46
+ requirement: new_requirement,
47
+ source: new_source
48
+ )
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ sig { returns(T.nilable(String)) }
55
+ def fetch_latest_version_via_npm_checker
56
+ npm_checker = npm_update_checker
57
+ return nil unless npm_checker
58
+
59
+ latest = npm_checker.latest_version
60
+ Dependabot.logger.info("Node UpdateChecker found latest version: #{latest || 'none'}")
61
+
62
+ latest&.to_s
63
+ rescue Dependabot::DependabotError, Excon::Error, JSON::ParserError => e
64
+ Dependabot.logger.debug("Error checking Node package #{package_name}: #{e.message}")
65
+ nil
66
+ end
67
+
68
+ sig { returns(T.nilable(Dependabot::UpdateCheckers::Base)) }
69
+ def npm_update_checker
70
+ @npm_update_checker ||= T.let(
71
+ build_npm_update_checker,
72
+ T.nilable(Dependabot::UpdateCheckers::Base)
73
+ )
74
+ end
75
+
76
+ sig { returns(T.nilable(Dependabot::UpdateCheckers::Base)) }
77
+ def build_npm_update_checker
78
+ npm_dependency = build_npm_dependency
79
+ return nil unless npm_dependency
80
+
81
+ Dependabot.logger.info("Delegating to npm_and_yarn UpdateChecker for package: #{npm_dependency.name}")
82
+
83
+ Dependabot::UpdateCheckers.for_package_manager("npm_and_yarn").new(
84
+ dependency: npm_dependency,
85
+ dependency_files: build_npm_dependency_files,
86
+ credentials: credentials,
87
+ ignored_versions: [],
88
+ security_advisories: [],
89
+ raise_on_ignored: false
90
+ )
91
+ end
92
+
93
+ sig { returns(T.nilable(Dependabot::Dependency)) }
94
+ def build_npm_dependency
95
+ return nil unless package_name
96
+
97
+ version = current_version || extract_version_from_requirement
98
+
99
+ Dependabot::Dependency.new(
100
+ name: T.must(package_name),
101
+ version: version,
102
+ requirements: [{
103
+ requirement: version || nil,
104
+ groups: ["dependencies"],
105
+ file: "package.json",
106
+ source: nil
107
+ }],
108
+ package_manager: "npm_and_yarn"
109
+ )
110
+ end
111
+
112
+ sig { returns(T.nilable(String)) }
113
+ def extract_version_from_requirement
114
+ req_string = requirements.first&.dig(:requirement)
115
+ return nil unless req_string
116
+
117
+ version_part = req_string.sub(/\A[~^]|[><=]+\s*/, "")
118
+ return version_part if version_part.match?(/\A\d+(?:\.\d+)*(?:-[\w.]+)?(?:\+[\w.]+)?\z/)
119
+
120
+ nil
121
+ end
122
+
123
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
124
+ def build_npm_dependency_files
125
+ version = current_version || extract_version_from_requirement
126
+ content = JSON.generate(
127
+ {
128
+ "name" => "dependabot-pre-commit-check",
129
+ "version" => "0.0.1",
130
+ "dependencies" => {
131
+ T.must(package_name) => version || "*"
132
+ }
133
+ }
134
+ )
135
+
136
+ [
137
+ Dependabot::DependencyFile.new(
138
+ name: "package.json",
139
+ content: content
140
+ )
141
+ ]
142
+ end
143
+
144
+ sig do
145
+ params(
146
+ package_name: T.nilable(String),
147
+ requirement: T.nilable(String)
148
+ ).returns(String)
149
+ end
150
+ def build_original_string(package_name:, requirement:)
151
+ base = package_name.to_s
152
+ base = "#{base}@#{requirement}" if requirement
153
+ base
154
+ end
155
+
156
+ sig { params(original_requirement: T.nilable(String), new_version: String).returns(String) }
157
+ def build_updated_requirement(original_requirement, new_version)
158
+ return new_version unless original_requirement
159
+
160
+ operator_match = original_requirement.match(/\A(?<op>[~^]|[><=]+)\s*/)
161
+ if operator_match
162
+ "#{operator_match[:op]}#{new_version}"
163
+ else
164
+ new_version
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ Dependabot::PreCommit::AdditionalDependencyCheckers.register(
173
+ "node",
174
+ Dependabot::PreCommit::AdditionalDependencyCheckers::Node
175
+ )
@@ -0,0 +1,213 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+ require "dependabot/dependency"
6
+ require "dependabot/update_checkers"
7
+ require "dependabot/requirements_update_strategy"
8
+ require "dependabot/python/update_checker/requirements_updater"
9
+ require "dependabot/pre_commit/additional_dependency_checkers"
10
+ require "dependabot/pre_commit/additional_dependency_checkers/base"
11
+
12
+ module Dependabot
13
+ module PreCommit
14
+ module AdditionalDependencyCheckers
15
+ class Python < Base
16
+ extend T::Sig
17
+
18
+ sig { override.returns(T.nilable(String)) }
19
+ def latest_version
20
+ return nil unless package_name
21
+
22
+ @latest_version ||= T.let(
23
+ fetch_latest_version_via_pip_checker,
24
+ T.nilable(String)
25
+ )
26
+ end
27
+
28
+ sig { override.params(latest_version: String).returns(T::Array[T::Hash[Symbol, T.untyped]]) }
29
+ def updated_requirements(latest_version)
30
+ requirements.map do |original_req|
31
+ original_source = original_req[:source]
32
+ next original_req unless original_source.is_a?(Hash)
33
+ next original_req unless original_source[:type] == "additional_dependency"
34
+
35
+ original_requirement = original_req[:requirement]
36
+ new_requirement = build_updated_requirement(original_requirement, latest_version)
37
+
38
+ new_original_string = build_original_string(
39
+ original_name: original_source[:original_name] || original_source[:package_name],
40
+ extras: original_source[:extras],
41
+ requirement: new_requirement
42
+ )
43
+
44
+ new_source = original_source.merge(original_string: new_original_string)
45
+
46
+ original_req.merge(
47
+ requirement: new_requirement,
48
+ source: new_source
49
+ )
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ sig { returns(T.nilable(String)) }
56
+ def fetch_latest_version_via_pip_checker
57
+ pip_checker = pip_update_checker
58
+ return nil unless pip_checker
59
+
60
+ latest = pip_checker.latest_version
61
+ Dependabot.logger.info("Python UpdateChecker found latest version: #{latest || 'none'}")
62
+
63
+ latest&.to_s
64
+ rescue Dependabot::PrivateSourceTimedOut,
65
+ Dependabot::PrivateSourceAuthenticationFailure,
66
+ Dependabot::DependencyFileNotResolvable,
67
+ Dependabot::DependencyNotFound,
68
+ Excon::Error::Timeout,
69
+ Excon::Error::Socket => e
70
+ Dependabot.logger.warn("Error checking Python package: #{e.message}")
71
+ nil
72
+ end
73
+
74
+ sig { returns(T.nilable(Dependabot::UpdateCheckers::Base)) }
75
+ def pip_update_checker
76
+ @pip_update_checker ||= T.let(
77
+ build_pip_update_checker,
78
+ T.nilable(Dependabot::UpdateCheckers::Base)
79
+ )
80
+ end
81
+
82
+ sig { returns(T.nilable(Dependabot::UpdateCheckers::Base)) }
83
+ def build_pip_update_checker
84
+ pip_dependency = build_pip_dependency
85
+ return nil unless pip_dependency
86
+
87
+ Dependabot.logger.info("Delegating to Python UpdateChecker for package: #{pip_dependency.name}")
88
+
89
+ Dependabot::UpdateCheckers.for_package_manager("pip").new(
90
+ dependency: pip_dependency,
91
+ dependency_files: build_pip_dependency_files,
92
+ credentials: credentials,
93
+ ignored_versions: [],
94
+ security_advisories: [],
95
+ raise_on_ignored: false
96
+ )
97
+ end
98
+
99
+ sig { returns(T.nilable(Dependabot::Dependency)) }
100
+ def build_pip_dependency
101
+ return nil unless package_name
102
+
103
+ # Extract version from requirement string if current_version is nil
104
+ # This prevents Python's UpdateChecker from treating it as a sub-dependency
105
+ version = current_version || extract_version_from_requirement
106
+
107
+ # Use an exact requirement (==version) to force Python's UpdateChecker
108
+ # to use the :requirements resolver instead of subdependency_resolver.
109
+ exact_requirement = version ? "==#{version}" : nil
110
+
111
+ # Build a dependency that Python's UpdateChecker understands
112
+ Dependabot::Dependency.new(
113
+ name: T.must(package_name),
114
+ version: version,
115
+ requirements: [{
116
+ requirement: exact_requirement,
117
+ groups: [],
118
+ file: "requirements.txt",
119
+ source: nil
120
+ }],
121
+ package_manager: "pip"
122
+ )
123
+ end
124
+
125
+ sig { returns(T.nilable(String)) }
126
+ def extract_version_from_requirement
127
+ req_string = requirements.first&.dig(:requirement)
128
+ return nil unless req_string
129
+
130
+ match = req_string.match(/[\d]+(?:\.[\d]+)*(?:\.?\w+)*/)
131
+ match&.[](0)
132
+ end
133
+
134
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
135
+ def build_pip_dependency_files
136
+ version = current_version || extract_version_from_requirement
137
+ exact_requirement = version ? "==#{version}" : ""
138
+ content = "#{package_name}#{exact_requirement}\n"
139
+
140
+ [
141
+ Dependabot::DependencyFile.new(
142
+ name: "requirements.txt",
143
+ content: content
144
+ )
145
+ ]
146
+ end
147
+
148
+ sig do
149
+ params(
150
+ original_name: T.nilable(String),
151
+ extras: T.nilable(String),
152
+ requirement: T.nilable(String)
153
+ ).returns(String)
154
+ end
155
+ def build_original_string(original_name:, extras:, requirement:)
156
+ base = original_name.to_s
157
+ base = "#{base}[#{extras}]" if extras
158
+ base = "#{base}#{requirement}" if requirement
159
+ base
160
+ end
161
+
162
+ sig { params(original_requirement: T.nilable(String), new_version: String).returns(T.nilable(String)) }
163
+ def build_updated_requirement(original_requirement, new_version)
164
+ return ">=#{new_version}" unless original_requirement
165
+
166
+ updater = Dependabot::Python::UpdateChecker::RequirementsUpdater.new(
167
+ requirements: [{
168
+ requirement: original_requirement,
169
+ file: "requirements.txt",
170
+ groups: [],
171
+ source: nil
172
+ }],
173
+ update_strategy: Dependabot::RequirementsUpdateStrategy::BumpVersions,
174
+ has_lockfile: false,
175
+ latest_resolvable_version: new_version
176
+ )
177
+
178
+ updated_reqs = updater.updated_requirements
179
+ updated_req = updated_reqs.first&.fetch(:requirement, nil)
180
+
181
+ return ">=#{new_version}" if updated_req == :unfixable
182
+
183
+ if updated_req == original_requirement
184
+ force_bump_lower_bounds(original_requirement, new_version)
185
+ else
186
+ updated_req || ">=#{new_version}"
187
+ end
188
+ end
189
+
190
+ sig { params(requirement: String, new_version: String).returns(String) }
191
+ def force_bump_lower_bounds(requirement, new_version)
192
+ constraints = requirement.split(",").map(&:strip)
193
+
194
+ updated = constraints.map do |constraint|
195
+ if constraint.match?(/\A(>=|>|~=)/)
196
+ operator = T.must(constraint.match(/\A(>=|>|~=)/))[1]
197
+ "#{operator}#{new_version}"
198
+ else
199
+ constraint
200
+ end
201
+ end
202
+
203
+ updated.join(",")
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+
210
+ Dependabot::PreCommit::AdditionalDependencyCheckers.register(
211
+ "python",
212
+ Dependabot::PreCommit::AdditionalDependencyCheckers::Python
213
+ )