dependabot-composer 0.89.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.
@@ -0,0 +1,214 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dependabot/shared_helpers"
4
+ require "dependabot/composer/update_checker"
5
+ require "dependabot/composer/version"
6
+ require "dependabot/composer/native_helpers"
7
+
8
+ module Dependabot
9
+ module Composer
10
+ class UpdateChecker
11
+ class VersionResolver
12
+ VERSION_REGEX = /[0-9]+(?:\.[A-Za-z0-9\-_]+)*/.freeze
13
+ SOURCE_TIMED_OUT_REGEX =
14
+ /The "(?<url>[^"]+packages\.json)".*timed out/.freeze
15
+
16
+ def initialize(credentials:, dependency:, dependency_files:,
17
+ requirements_to_unlock:, latest_allowable_version:)
18
+ @credentials = credentials
19
+ @dependency = dependency
20
+ @dependency_files = dependency_files
21
+ @requirements_to_unlock = requirements_to_unlock
22
+ @latest_allowable_version = latest_allowable_version
23
+ end
24
+
25
+ def latest_resolvable_version
26
+ @latest_resolvable_version ||= fetch_latest_resolvable_version
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :credentials, :dependency, :dependency_files,
32
+ :requirements_to_unlock, :latest_allowable_version
33
+
34
+ def fetch_latest_resolvable_version
35
+ version = fetch_latest_resolvable_version_string
36
+ return if version.nil?
37
+ return unless Composer::Version.correct?(version)
38
+
39
+ Composer::Version.new(version)
40
+ end
41
+
42
+ def fetch_latest_resolvable_version_string
43
+ base_directory = dependency_files.first.directory
44
+ SharedHelpers.in_a_temporary_directory(base_directory) do
45
+ File.write("composer.json", prepared_composer_json_content)
46
+ File.write("composer.lock", lockfile.content) if lockfile
47
+
48
+ run_update_checker
49
+ end
50
+ rescue SharedHelpers::HelperSubprocessFailed => error
51
+ retry_count ||= 0
52
+ retry_count += 1
53
+ retry if retry_count < 2 && error.message.include?("404 Not Found")
54
+ retry if retry_count < 2 && error.message.include?("timed out")
55
+ handle_composer_errors(error)
56
+ end
57
+
58
+ def run_update_checker
59
+ SharedHelpers.with_git_configured(credentials: credentials) do
60
+ SharedHelpers.run_helper_subprocess(
61
+ command: "php -d memory_limit=-1 #{php_helper_path}",
62
+ function: "get_latest_resolvable_version",
63
+ args: [
64
+ Dir.pwd,
65
+ dependency.name.downcase,
66
+ git_credentials,
67
+ registry_credentials
68
+ ]
69
+ )
70
+ end
71
+ end
72
+
73
+ def prepared_composer_json_content
74
+ content = composer_file.content
75
+
76
+ content.gsub(
77
+ /"#{Regexp.escape(dependency.name)}"\s*:\s*".*"/,
78
+ %("#{dependency.name}": "#{updated_version_requirement_string}")
79
+ )
80
+ end
81
+
82
+ def updated_version_requirement_string
83
+ lower_bound =
84
+ if requirements_to_unlock == :none
85
+ dependency.requirements.first&.fetch(:requirement) || ">= 0"
86
+ elsif dependency.version
87
+ ">= #{dependency.version}"
88
+ else
89
+ version_for_requirement =
90
+ dependency.requirements.map { |r| r[:requirement] }.compact.
91
+ reject { |req_string| req_string.start_with?("<") }.
92
+ select { |req_string| req_string.match?(VERSION_REGEX) }.
93
+ map { |req_string| req_string.match(VERSION_REGEX) }.
94
+ select { |version| Gem::Version.correct?(version) }.
95
+ max_by { |version| Gem::Version.new(version) }
96
+
97
+ ">= #{version_for_requirement || 0}"
98
+ end
99
+
100
+ # Add the latest_allowable_version as an upper bound. This means
101
+ # ignore conditions are considered when checking for the latest
102
+ # resolvable version.
103
+ #
104
+ # NOTE: This isn't perfect. If v2.x is ignored and v3 is out but
105
+ # unresolvable then the `latest_allowable_version` will be v3, and
106
+ # we won't be ignoring v2.x releases like we should be.
107
+ return lower_bound unless latest_allowable_version
108
+
109
+ lower_bound + ", <= #{latest_allowable_version}"
110
+ end
111
+
112
+ # rubocop:disable Metrics/PerceivedComplexity
113
+ # rubocop:disable Metrics/AbcSize
114
+ # rubocop:disable Metrics/CyclomaticComplexity
115
+ # rubocop:disable Metrics/MethodLength
116
+ def handle_composer_errors(error)
117
+ if error.message.start_with?("Failed to execute git clone")
118
+ dependency_url =
119
+ error.message.match(/--mirror '(?<url>.*?)'/).
120
+ named_captures.fetch("url")
121
+ raise Dependabot::GitDependenciesNotReachable, dependency_url
122
+ elsif error.message.start_with?("Failed to clone")
123
+ dependency_url =
124
+ error.message.match(/Failed to clone (?<url>.*?) via/).
125
+ named_captures.fetch("url")
126
+ raise Dependabot::GitDependenciesNotReachable, dependency_url
127
+ elsif error.message.start_with?("Could not parse version")
128
+ raise Dependabot::DependencyFileNotResolvable, error.message
129
+ elsif error.message.include?("requested PHP extension")
130
+ extensions = error.message.scan(/\sext\-.*?\s/).map(&:strip).uniq
131
+ msg = "Dependabot's installed extensions didn't match those "\
132
+ "required by your application.\n\n"\
133
+ "Please add the following extensions to the platform "\
134
+ "config in your composer.json to allow Dependabot to run: "\
135
+ "#{extensions.join(', ')}.\n\n"\
136
+ "The full error raised was:\n\n#{error.message}"
137
+ raise Dependabot::DependencyFileNotResolvable, msg
138
+ elsif error.message.include?("package requires php") ||
139
+ error.message.include?("cannot require itself")
140
+ raise Dependabot::DependencyFileNotResolvable, error.message
141
+ elsif error.message.include?("No driver found to handle VCS") &&
142
+ !error.message.include?("@") && !error.message.include?("://")
143
+ msg = "Dependabot detected a VCS requirement with a local path, "\
144
+ "rather than a URL. Dependabot does not support this "\
145
+ "setup.\n\nThe underlying error was:\n\n#{error.message}"
146
+ raise Dependabot::DependencyFileNotResolvable, msg
147
+ elsif error.message.include?("requirements could not be resolved")
148
+ # We should raise a Dependabot::DependencyFileNotResolvable error
149
+ # here, but can't confidently distinguish between cases where we
150
+ # can't install and cases where we can't update. For now, we
151
+ # therefore just ignore the dependency.
152
+ nil
153
+ elsif error.message.include?("URL required authentication") ||
154
+ error.message.include?("403 Forbidden")
155
+ source =
156
+ error.message.match(%r{https?://(?<source>[^/]+)/}).
157
+ named_captures.fetch("source")
158
+ raise Dependabot::PrivateSourceAuthenticationFailure, source
159
+ elsif error.message.match?(SOURCE_TIMED_OUT_REGEX)
160
+ url = error.message.match(SOURCE_TIMED_OUT_REGEX).
161
+ named_captures.fetch("url")
162
+ raise if url.include?("packagist.org")
163
+
164
+ source = url.gsub(%r{/packages.json$}, "")
165
+ raise Dependabot::PrivateSourceTimedOut, source
166
+ elsif error.message.start_with?("Allowed memory size")
167
+ raise Dependabot::OutOfMemory
168
+ elsif error.message.start_with?("Package not found in updated") &&
169
+ !dependency.top_level?
170
+ # If we can't find the dependency in the composer.lock after an
171
+ # update, but it was originally a sub-dependency, it's because the
172
+ # dependency is no longer required and is just cruft in the
173
+ # composer.json. In this case we just ignore the dependency.
174
+ nil
175
+ elsif error.message.include?("stefandoorn/sitemap-plugin-1.0.0.0")
176
+ # We get a recurring error when attempting to update this repo
177
+ # which doesn't recur locally and we can't figure out how to fix!
178
+ #
179
+ # Package is not installed: stefandoorn/sitemap-plugin-1.0.0.0
180
+ nil
181
+ else
182
+ raise error
183
+ end
184
+ end
185
+ # rubocop:enable Metrics/PerceivedComplexity
186
+ # rubocop:enable Metrics/AbcSize
187
+ # rubocop:enable Metrics/CyclomaticComplexity
188
+ # rubocop:enable Metrics/MethodLength
189
+
190
+ def php_helper_path
191
+ NativeHelpers.composer_helper_path
192
+ end
193
+
194
+ def composer_file
195
+ @composer_file ||=
196
+ dependency_files.find { |f| f.name == "composer.json" }
197
+ end
198
+
199
+ def lockfile
200
+ @lockfile ||=
201
+ dependency_files.find { |f| f.name == "composer.lock" }
202
+ end
203
+
204
+ def git_credentials
205
+ credentials.select { |cred| cred["type"] == "git_source" }
206
+ end
207
+
208
+ def registry_credentials
209
+ credentials.select { |cred| cred["type"] == "composer_repository" }
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dependabot/utils"
4
+ require "rubygems_version_patch"
5
+
6
+ # PHP pre-release versions use 1.0.1-rc1 syntax, which Gem::Version
7
+ # converts into 1.0.1.pre.rc1. We override the `to_s` method to stop that
8
+ # alteration.
9
+
10
+ module Dependabot
11
+ module Composer
12
+ class Version < Gem::Version
13
+ def initialize(version)
14
+ @version_string = version.to_s
15
+ super
16
+ end
17
+
18
+ def to_s
19
+ @version_string
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ Dependabot::Utils.
26
+ register_version_class("composer", Dependabot::Composer::Version)
metadata ADDED
@@ -0,0 +1,195 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dependabot-composer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.89.0
5
+ platform: ruby
6
+ authors:
7
+ - Dependabot
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-01-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dependabot-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.89.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.89.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: byebug
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '12'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '12'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.8'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.8'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-its
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec_junit_formatter
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.4'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.4'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.61'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.61'
111
+ - !ruby/object:Gem::Dependency
112
+ name: vcr
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '4.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '4.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: webmock
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.4'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.4'
139
+ description: Automated dependency management for Ruby, JavaScript, Python, PHP, Elixir,
140
+ Rust, Java, .NET, Elm and Go
141
+ email: support@dependabot.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - helpers/.php_cs
147
+ - helpers/bin/run.php
148
+ - helpers/build
149
+ - helpers/composer.json
150
+ - helpers/composer.lock
151
+ - helpers/php/.php_cs
152
+ - helpers/setup.sh
153
+ - helpers/src/DependabotInstallationManager.php
154
+ - helpers/src/DependabotPluginManager.php
155
+ - helpers/src/ExceptionIO.php
156
+ - helpers/src/Hasher.php
157
+ - helpers/src/UpdateChecker.php
158
+ - helpers/src/Updater.php
159
+ - lib/dependabot/composer.rb
160
+ - lib/dependabot/composer/file_fetcher.rb
161
+ - lib/dependabot/composer/file_parser.rb
162
+ - lib/dependabot/composer/file_updater.rb
163
+ - lib/dependabot/composer/file_updater/lockfile_updater.rb
164
+ - lib/dependabot/composer/file_updater/manifest_updater.rb
165
+ - lib/dependabot/composer/metadata_finder.rb
166
+ - lib/dependabot/composer/native_helpers.rb
167
+ - lib/dependabot/composer/requirement.rb
168
+ - lib/dependabot/composer/update_checker.rb
169
+ - lib/dependabot/composer/update_checker/requirements_updater.rb
170
+ - lib/dependabot/composer/update_checker/version_resolver.rb
171
+ - lib/dependabot/composer/version.rb
172
+ homepage: https://github.com/dependabot/dependabot-core
173
+ licenses:
174
+ - Nonstandard
175
+ metadata: {}
176
+ post_install_message:
177
+ rdoc_options: []
178
+ require_paths:
179
+ - lib
180
+ required_ruby_version: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - ">="
183
+ - !ruby/object:Gem::Version
184
+ version: 2.5.0
185
+ required_rubygems_version: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - ">="
188
+ - !ruby/object:Gem::Version
189
+ version: 2.5.0
190
+ requirements: []
191
+ rubygems_version: 3.0.2
192
+ signing_key:
193
+ specification_version: 4
194
+ summary: PHP (Composer) support for dependabot-core
195
+ test_files: []