Module: Dependabot::Maven::NativeHelpers
- Extended by:
- T::Sig
- Defined in:
- lib/dependabot/maven/native_helpers.rb
Constant Summary collapse
- TRANSFER_FAILURE_REGEX =
Matches Maven's "Could not transfer artifact" failures, capturing the repository URL and HTTP status so we can classify auth vs. other errors.
%r{Could not transfer artifact (?<artifact>[^ ]+) from/to (?<repository_name>[^ ]+) \((?<repository_url>[^ ]+)\): status code: (?<status_code>[0-9]+)}- WRAPPER_PLUGIN_UNRESOLVED_REGEX =
Matches Maven's "Plugin ... could not be resolved" failures, used to detect when the wrapper plugin itself is unavailable behind the proxy.
/Plugin org\.apache\.maven\.plugins:maven-wrapper-plugin[^ ]* .*could not be resolved/- MAX_ERROR_SUMMARY_LENGTH =
Upper bound on the length of the Maven error summary included in raised errors, to avoid oversized error payloads while retaining the relevant failure detail.
2_000- ANSI_ESCAPE_REGEX =
Matches ANSI/VT100 control sequences. Maven can be configured to emit colored output (e.g.
-Dstyle.color=always), wrapping markers like[ERROR]in escape codes; we strip these so classification and the surfaced summary see plain text. %r{\e\[[0-9;?]*[ -/]*[@-~]}- DEPENDENCY_PLUGIN_VERSION =
T.let(version, T.nilable(String))
Class Method Summary collapse
- .handle_tool_error(output) ⇒ Object
- .handle_wrapper_error(error) ⇒ Object
- .mvn_error_summary(output) ⇒ Object
- .run_mvn_dependency_tree_plugin(file_name) ⇒ Object
- .run_mvnw_wrapper(version:, wrapper_plugin_version:, env:, distribution_type:, extra_args: [], cwd: nil) ⇒ Object
Class Method Details
.handle_tool_error(output) ⇒ Object
65 66 67 68 69 70 71 72 |
# File 'lib/dependabot/maven/native_helpers.rb', line 65 def self.handle_tool_error(output) if (match = output.match(TRANSFER_FAILURE_REGEX)) && (match[:status_code] == "403" || match[:status_code] == "401") raise Dependabot::PrivateSourceAuthenticationFailure, match[:repository_url] end raise DependabotError, "mvn CLI failed with an unhandled error" end |
.handle_wrapper_error(error) ⇒ Object
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/dependabot/maven/native_helpers.rb', line 135 def self.handle_wrapper_error(error) # Strip ANSI color codes up front so classification and the surfaced summary see # plain text even when Maven is configured to emit colored output. output = error..gsub(ANSI_ESCAPE_REGEX, "") if (match = output.match(TRANSFER_FAILURE_REGEX)) && (match[:status_code] == "403" || match[:status_code] == "401") raise Dependabot::PrivateSourceAuthenticationFailure, match[:repository_url] end if output.match?(WRAPPER_PLUGIN_UNRESOLVED_REGEX) raise Dependabot::DependencyFileNotResolvable, "Could not resolve the Maven Wrapper plugin." end # Only reclassify when Maven emitted its own `[ERROR]` diagnostics. Otherwise the # failure is not a Maven misconfiguration (e.g. timeout or missing executable), so # re-raise the original error; its full output is already in the job log. summary = mvn_error_summary(output) raise error unless summary raise Dependabot::MisconfiguredTooling.new("Maven Wrapper", summary) end |
.mvn_error_summary(output) ⇒ Object
164 165 166 167 168 169 170 |
# File 'lib/dependabot/maven/native_helpers.rb', line 164 def self.mvn_error_summary(output) error_lines = output.lines.map(&:chomp).select { |line| line.include?("[ERROR]") } return nil if error_lines.empty? summary = error_lines.join("\n") summary.length > MAX_ERROR_SUMMARY_LENGTH ? "#{summary[0, MAX_ERROR_SUMMARY_LENGTH]}..." : summary end |
.run_mvn_dependency_tree_plugin(file_name) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/dependabot/maven/native_helpers.rb', line 48 def self.run_mvn_dependency_tree_plugin(file_name) raise DependabotError, "Could not resolve maven-dependency-plugin version" unless DEPENDENCY_PLUGIN_VERSION proxy_url = URI.parse(ENV.fetch("HTTPS_PROXY")) stdout, _, status = Open3.capture3( { "PROXY_HOST" => proxy_url.host }, "mvn", "dependency:#{DEPENDENCY_PLUGIN_VERSION}:tree", "-DoutputFile=#{file_name}", "-DoutputType=json", "-e" ) Dependabot.logger.info("mvn dependency:tree output: STDOUT:#{stdout}") handle_tool_error(stdout) unless status.success? end |
.run_mvnw_wrapper(version:, wrapper_plugin_version:, env:, distribution_type:, extra_args: [], cwd: nil) ⇒ Object
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/dependabot/maven/native_helpers.rb', line 93 def self.run_mvnw_wrapper(version:, wrapper_plugin_version:, env:, distribution_type:, extra_args: [], cwd: nil) # Use the fully-qualified plugin goal so the exact plugin version is # invoked regardless of the project's plugin group configuration. plugin_goal = "org.apache.maven.plugins:maven-wrapper-plugin:" \ "#{wrapper_plugin_version}:wrapper" standard_args = [ plugin_goal, "-Dmaven=#{version}", "-Dtype=#{distribution_type}", "--no-transfer-progress" ] + extra_args # Pass the argument vector directly instead of a pre-joined shell string. # `run_shell_command` shell-escapes string commands internally, so building # the command with `Shellwords.join` here would double-escape arguments # (e.g. `-Dmaven=3.6.3` becoming `-Dmaven\=3.6.3`), which Maven then fails # to parse. An argument vector is executed without an intermediate shell. cmd = ["mvn"] + standard_args run_cwd = cwd && cwd != "." ? cwd : nil output = SharedHelpers.run_shell_command(cmd, env: env, cwd: run_cwd) Dependabot.logger.info("mvn wrapper output: STDOUT:#{output}") output rescue SharedHelpers::HelperSubprocessFailed => e # `run_shell_command` raises HelperSubprocessFailed on a non-zero exit, and the # updater sanitizes that into an opaque `SubprocessFailed` that only reports the # command and hides the real Maven output. Log the full output and re-raise a # classified Dependabot error so operators get an actionable message, mirroring # the `run_mvn_dependency_tree_plugin` path. Dependabot.logger.warn("mvn wrapper command failed:\n#{e.}") handle_wrapper_error(e) end |