dependabot-core 0.94.12 → 0.95.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. metadata +13 -337
  3. data/CHANGELOG.md +0 -7075
  4. data/LICENSE +0 -39
  5. data/README.md +0 -114
  6. data/helpers/test/run.rb +0 -18
  7. data/helpers/utils/git-credential-store-immutable +0 -10
  8. data/lib/dependabot/clients/bitbucket.rb +0 -105
  9. data/lib/dependabot/clients/github_with_retries.rb +0 -117
  10. data/lib/dependabot/clients/gitlab.rb +0 -72
  11. data/lib/dependabot/dependency.rb +0 -115
  12. data/lib/dependabot/dependency_file.rb +0 -60
  13. data/lib/dependabot/errors.rb +0 -179
  14. data/lib/dependabot/file_fetchers/README.md +0 -65
  15. data/lib/dependabot/file_fetchers/base.rb +0 -368
  16. data/lib/dependabot/file_fetchers.rb +0 -18
  17. data/lib/dependabot/file_parsers/README.md +0 -45
  18. data/lib/dependabot/file_parsers/base/dependency_set.rb +0 -77
  19. data/lib/dependabot/file_parsers/base.rb +0 -31
  20. data/lib/dependabot/file_parsers.rb +0 -18
  21. data/lib/dependabot/file_updaters/README.md +0 -58
  22. data/lib/dependabot/file_updaters/base.rb +0 -52
  23. data/lib/dependabot/file_updaters.rb +0 -18
  24. data/lib/dependabot/git_commit_checker.rb +0 -412
  25. data/lib/dependabot/metadata_finders/README.md +0 -53
  26. data/lib/dependabot/metadata_finders/base/changelog_finder.rb +0 -321
  27. data/lib/dependabot/metadata_finders/base/changelog_pruner.rb +0 -177
  28. data/lib/dependabot/metadata_finders/base/commits_finder.rb +0 -221
  29. data/lib/dependabot/metadata_finders/base/release_finder.rb +0 -255
  30. data/lib/dependabot/metadata_finders/base.rb +0 -117
  31. data/lib/dependabot/metadata_finders.rb +0 -18
  32. data/lib/dependabot/pull_request_creator/branch_namer.rb +0 -170
  33. data/lib/dependabot/pull_request_creator/commit_signer.rb +0 -63
  34. data/lib/dependabot/pull_request_creator/github.rb +0 -277
  35. data/lib/dependabot/pull_request_creator/gitlab.rb +0 -136
  36. data/lib/dependabot/pull_request_creator/labeler.rb +0 -373
  37. data/lib/dependabot/pull_request_creator/message_builder.rb +0 -906
  38. data/lib/dependabot/pull_request_creator.rb +0 -153
  39. data/lib/dependabot/pull_request_updater/github.rb +0 -165
  40. data/lib/dependabot/pull_request_updater.rb +0 -43
  41. data/lib/dependabot/shared_helpers.rb +0 -224
  42. data/lib/dependabot/source.rb +0 -120
  43. data/lib/dependabot/update_checkers/README.md +0 -67
  44. data/lib/dependabot/update_checkers/base.rb +0 -220
  45. data/lib/dependabot/update_checkers.rb +0 -18
  46. data/lib/dependabot/utils.rb +0 -33
  47. data/lib/dependabot/version.rb +0 -5
  48. data/lib/dependabot.rb +0 -4
  49. data/lib/rubygems_version_patch.rb +0 -14
@@ -1,153 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/metadata_finders"
4
-
5
- module Dependabot
6
- class PullRequestCreator
7
- require "dependabot/pull_request_creator/github"
8
- require "dependabot/pull_request_creator/gitlab"
9
- require "dependabot/pull_request_creator/message_builder"
10
- require "dependabot/pull_request_creator/branch_namer"
11
- require "dependabot/pull_request_creator/labeler"
12
-
13
- class RepoNotFound < StandardError; end
14
- class RepoArchived < StandardError; end
15
- class NoHistoryInCommon < StandardError; end
16
-
17
- attr_reader :source, :dependencies, :files, :base_commit,
18
- :credentials, :pr_message_footer, :custom_labels,
19
- :author_details, :signature_key, :vulnerabilities_fixed,
20
- :reviewers, :assignees, :milestone, :branch_name_separator
21
-
22
- def initialize(source:, base_commit:, dependencies:, files:, credentials:,
23
- pr_message_footer: nil, custom_labels: nil,
24
- author_details: nil, signature_key: nil,
25
- reviewers: nil, assignees: nil, milestone: nil,
26
- vulnerabilities_fixed: {}, branch_name_separator: "/",
27
- label_language: false)
28
- @dependencies = dependencies
29
- @source = source
30
- @base_commit = base_commit
31
- @files = files
32
- @credentials = credentials
33
- @pr_message_footer = pr_message_footer
34
- @author_details = author_details
35
- @signature_key = signature_key
36
- @custom_labels = custom_labels
37
- @reviewers = reviewers
38
- @assignees = assignees
39
- @milestone = milestone
40
- @vulnerabilities_fixed = vulnerabilities_fixed
41
- @branch_name_separator = branch_name_separator
42
- @label_language = label_language
43
-
44
- check_dependencies_have_previous_version
45
- end
46
-
47
- def check_dependencies_have_previous_version
48
- return if library? && dependencies.all? { |d| requirements_changed?(d) }
49
- return if dependencies.all?(&:previous_version)
50
-
51
- raise "Dependencies must have a previous version or changed " \
52
- "requirement to have a pull request created for them!"
53
- end
54
-
55
- def create
56
- case source.provider
57
- when "github" then github_creator.create
58
- when "gitlab" then gitlab_creator.create
59
- else raise "Unsupported provider #{source.provider}"
60
- end
61
- end
62
-
63
- private
64
-
65
- def label_language?
66
- @label_language
67
- end
68
-
69
- def github_creator
70
- Github.new(
71
- source: source,
72
- branch_name: branch_namer.new_branch_name,
73
- base_commit: base_commit,
74
- credentials: credentials,
75
- files: files,
76
- commit_message: message_builder.commit_message,
77
- pr_description: message_builder.pr_message,
78
- pr_name: message_builder.pr_name,
79
- author_details: author_details,
80
- signature_key: signature_key,
81
- labeler: labeler,
82
- reviewers: reviewers,
83
- assignees: assignees,
84
- milestone: milestone
85
- )
86
- end
87
-
88
- def gitlab_creator
89
- Gitlab.new(
90
- source: source,
91
- branch_name: branch_namer.new_branch_name,
92
- base_commit: base_commit,
93
- credentials: credentials,
94
- files: files,
95
- commit_message: message_builder.commit_message,
96
- pr_description: message_builder.pr_message,
97
- pr_name: message_builder.pr_name,
98
- author_details: author_details,
99
- labeler: labeler,
100
- assignee: assignees&.first
101
- )
102
- end
103
-
104
- def message_builder
105
- @message_builder ||
106
- MessageBuilder.new(
107
- source: source,
108
- dependencies: dependencies,
109
- files: files,
110
- credentials: credentials,
111
- author_details: author_details,
112
- pr_message_footer: pr_message_footer,
113
- vulnerabilities_fixed: vulnerabilities_fixed
114
- )
115
- end
116
-
117
- def branch_namer
118
- @branch_namer ||=
119
- BranchNamer.new(
120
- dependencies: dependencies,
121
- files: files,
122
- target_branch: source.branch,
123
- separator: branch_name_separator
124
- )
125
- end
126
-
127
- def labeler
128
- @labeler ||=
129
- Labeler.new(
130
- source: source,
131
- custom_labels: custom_labels,
132
- credentials: credentials,
133
- includes_security_fixes: includes_security_fixes?,
134
- dependencies: dependencies,
135
- label_language: label_language?
136
- )
137
- end
138
-
139
- def library?
140
- return true if files.any? { |file| file.name.end_with?(".gemspec") }
141
-
142
- dependencies.none?(&:appears_in_lockfile?)
143
- end
144
-
145
- def includes_security_fixes?
146
- vulnerabilities_fixed.values.flatten.any?
147
- end
148
-
149
- def requirements_changed?(dependency)
150
- (dependency.requirements - dependency.previous_requirements).any?
151
- end
152
- end
153
- end
@@ -1,165 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "octokit"
4
- require "dependabot/clients/github_with_retries"
5
- require "dependabot/pull_request_creator/commit_signer"
6
- require "dependabot/pull_request_updater"
7
-
8
- module Dependabot
9
- class PullRequestUpdater
10
- class Github
11
- attr_reader :source, :files, :base_commit, :credentials,
12
- :pull_request_number, :author_details, :signature_key
13
-
14
- def initialize(source:, base_commit:, files:, credentials:,
15
- pull_request_number:, author_details: nil,
16
- signature_key: nil)
17
- @source = source
18
- @base_commit = base_commit
19
- @files = files
20
- @credentials = credentials
21
- @pull_request_number = pull_request_number
22
- @author_details = author_details
23
- @signature_key = signature_key
24
- end
25
-
26
- def update
27
- return unless branch_exists?
28
-
29
- commit = create_commit
30
- branch = update_branch(commit)
31
- update_pull_request_target_branch
32
- branch
33
- end
34
-
35
- private
36
-
37
- def update_pull_request_target_branch
38
- target_branch = source.branch || pull_request.base.repo.default_branch
39
- return if target_branch == pull_request.base.ref
40
-
41
- github_client_for_source.update_pull_request(
42
- source.repo,
43
- pull_request_number,
44
- base: target_branch
45
- )
46
- end
47
-
48
- def github_client_for_source
49
- @github_client_for_source ||=
50
- Dependabot::Clients::GithubWithRetries.for_source(
51
- source: source,
52
- credentials: credentials
53
- )
54
- end
55
-
56
- def pull_request
57
- @pull_request ||=
58
- github_client_for_source.pull_request(
59
- source.repo,
60
- pull_request_number
61
- )
62
- end
63
-
64
- def branch_exists?
65
- github_client_for_source.branch(source.repo, pull_request.head.ref)
66
- rescue Octokit::NotFound
67
- false
68
- end
69
-
70
- def create_commit
71
- tree = create_tree
72
-
73
- options = author_details&.any? ? { author: author_details } : {}
74
-
75
- if options[:author]&.any? && signature_key
76
- options[:author][:date] = Time.now.utc.iso8601
77
- options[:signature] = commit_signature(tree, options[:author])
78
- end
79
-
80
- github_client_for_source.create_commit(
81
- source.repo,
82
- commit_message,
83
- tree.sha,
84
- base_commit,
85
- options
86
- )
87
- end
88
-
89
- def create_tree
90
- file_trees = files.map do |file|
91
- if file.type == "file"
92
- {
93
- path: file.path.sub(%r{^/}, ""),
94
- mode: "100644",
95
- type: "blob",
96
- content: file.content
97
- }
98
- elsif file.type == "submodule"
99
- {
100
- path: file.path.sub(%r{^/}, ""),
101
- mode: "160000",
102
- type: "commit",
103
- sha: file.content
104
- }
105
- else
106
- raise "Unknown file type #{file.type}"
107
- end
108
- end
109
-
110
- github_client_for_source.create_tree(
111
- source.repo,
112
- file_trees,
113
- base_tree: base_commit
114
- )
115
- end
116
-
117
- def update_branch(commit)
118
- github_client_for_source.update_ref(
119
- source.repo,
120
- "heads/" + pull_request.head.ref,
121
- commit.sha,
122
- true
123
- )
124
- rescue Octokit::UnprocessableEntity => error
125
- # Return quietly if the branch has been deleted
126
- return nil if error.message.match?(/Reference does not exist/i)
127
-
128
- # Return quietly if the branch has been merged
129
- return nil if error.message.match?(/Reference cannot be updated/i)
130
-
131
- raise
132
- end
133
-
134
- def commit_message
135
- @commit_message ||=
136
- if pull_request.commits == 1
137
- github_client_for_source.
138
- git_commit(source.repo, pull_request.head.sha).
139
- message
140
- else
141
- author_name = author_details&.fetch(:name, nil) || "dependabot[bot]"
142
- commits =
143
- github_client_for_source.
144
- pull_request_commits(source.repo, pull_request_number)
145
-
146
- commit =
147
- commits.find { |c| c.commit.author.name == author_name } ||
148
- commits.first
149
-
150
- commit.commit.message
151
- end
152
- end
153
-
154
- def commit_signature(tree, author_details_with_date)
155
- PullRequestCreator::CommitSigner.new(
156
- author_details: author_details_with_date,
157
- commit_message: commit_message,
158
- tree_sha: tree.sha,
159
- parent_sha: base_commit,
160
- signature_key: signature_key
161
- ).signature
162
- end
163
- end
164
- end
165
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/pull_request_updater/github"
4
-
5
- module Dependabot
6
- class PullRequestUpdater
7
- attr_reader :source, :files, :base_commit, :credentials,
8
- :pull_request_number, :author_details, :signature_key
9
-
10
- def initialize(source:, base_commit:, files:, credentials:,
11
- pull_request_number:, author_details: nil,
12
- signature_key: nil)
13
- @source = source
14
- @base_commit = base_commit
15
- @files = files
16
- @credentials = credentials
17
- @pull_request_number = pull_request_number
18
- @author_details = author_details
19
- @signature_key = signature_key
20
- end
21
-
22
- def update
23
- case source.provider
24
- when "github" then github_updater.update
25
- else raise "Unsupported provider #{source.provider}"
26
- end
27
- end
28
-
29
- private
30
-
31
- def github_updater
32
- Github.new(
33
- source: source,
34
- base_commit: base_commit,
35
- files: files,
36
- credentials: credentials,
37
- pull_request_number: pull_request_number,
38
- author_details: author_details,
39
- signature_key: signature_key
40
- )
41
- end
42
- end
43
- end
@@ -1,224 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "json"
4
- require "tmpdir"
5
- require "excon"
6
- require "English"
7
- require "digest"
8
- require "open3"
9
-
10
- module Dependabot
11
- module SharedHelpers
12
- BUMP_TMP_FILE_PREFIX = "dependabot_"
13
- BUMP_TMP_DIR_PATH = "tmp"
14
- GIT_CONFIG_GLOBAL_PATH = File.expand_path("~/.gitconfig")
15
-
16
- class ChildProcessFailed < StandardError
17
- attr_reader :error_class, :error_message, :error_backtrace
18
-
19
- def initialize(error_class:, error_message:, error_backtrace:)
20
- @error_class = error_class
21
- @error_message = error_message
22
- @error_backtrace = error_backtrace
23
-
24
- msg = "Child process raised #{error_class} with message: "\
25
- "#{error_message}"
26
- super(msg)
27
- set_backtrace(error_backtrace)
28
- end
29
- end
30
-
31
- def self.in_a_temporary_directory(directory = "/")
32
- Dir.mkdir(BUMP_TMP_DIR_PATH) unless Dir.exist?(BUMP_TMP_DIR_PATH)
33
- Dir.mktmpdir(BUMP_TMP_FILE_PREFIX, BUMP_TMP_DIR_PATH) do |dir|
34
- path = Pathname.new(File.join(dir, directory)).expand_path
35
- FileUtils.mkpath(path)
36
- Dir.chdir(path) { yield(path) }
37
- end
38
- end
39
-
40
- def self.in_a_forked_process
41
- read, write = IO.pipe
42
-
43
- pid = fork do
44
- read.close
45
- result = yield
46
- rescue Exception => error # rubocop:disable Lint/RescueException
47
- result = { _error_details: { error_class: error.class.to_s,
48
- error_message: error.message,
49
- error_backtrace: error.backtrace } }
50
- ensure
51
- Marshal.dump(result, write)
52
- exit!(0)
53
- end
54
-
55
- write.close
56
- result = read.read
57
- Process.wait(pid)
58
- result = Marshal.load(result) # rubocop:disable Security/MarshalLoad
59
-
60
- return result unless result.is_a?(Hash) && result[:_error_details]
61
-
62
- raise ChildProcessFailed, result[:_error_details]
63
- end
64
-
65
- class HelperSubprocessFailed < StandardError
66
- def initialize(message:, error_context:)
67
- super(message)
68
- @error_context = error_context
69
- @command = error_context[:command]
70
- end
71
-
72
- def raven_context
73
- { fingerprint: [@command], extra: @error_context }
74
- end
75
- end
76
-
77
- def self.run_helper_subprocess(command:, function:, args:, env: nil,
78
- stderr_to_stdout: false)
79
- start = Time.now
80
- stdin_data = JSON.dump(function: function, args: args)
81
- env_cmd = [env, command].compact
82
- stdout, stderr, process = Open3.capture3(*env_cmd, stdin_data: stdin_data)
83
- time_taken = Time.now - start
84
-
85
- # Some package managers output useful stuff to stderr instead of stdout so
86
- # we want to parse this, most package manager will output garbage here so
87
- # would mess up json response from stdout
88
- stdout = "#{stderr}\n#{stdout}" if stderr_to_stdout
89
-
90
- error_context = {
91
- command: command,
92
- function: function,
93
- args: args,
94
- time_taken: time_taken,
95
- stderr_output: stderr ? stderr[0..50_000] : "", # Truncate to ~100kb
96
- process_exit_value: process.to_s
97
- }
98
-
99
- response = JSON.parse(stdout)
100
- return response["result"] if process.success?
101
-
102
- raise HelperSubprocessFailed.new(
103
- message: response["error"],
104
- error_context: error_context
105
- )
106
- rescue JSON::ParserError
107
- raise HelperSubprocessFailed.new(
108
- message: stdout || "No output from command",
109
- error_context: error_context
110
- )
111
- end
112
-
113
- def self.excon_middleware
114
- Excon.defaults[:middlewares] + [Excon::Middleware::RedirectFollower]
115
- end
116
-
117
- def self.excon_defaults
118
- {
119
- connect_timeout: 5,
120
- write_timeout: 5,
121
- read_timeout: 5,
122
- omit_default_port: true,
123
- middlewares: excon_middleware
124
- }
125
- end
126
-
127
- def self.with_git_configured(credentials:)
128
- backup_git_config_path = stash_global_git_config
129
- configure_git_to_use_https_with_credentials(credentials)
130
- yield
131
- ensure
132
- reset_global_git_config(backup_git_config_path)
133
- end
134
-
135
- def self.configure_git_to_use_https_with_credentials(credentials)
136
- configure_git_to_use_https
137
- configure_git_credentials(credentials)
138
- end
139
-
140
- def self.configure_git_to_use_https
141
- # Note: we use --global here (rather than --system) so that Dependabot
142
- # can be run without privileged access
143
- run_shell_command(
144
- 'git config --global --replace-all url."https://github.com/".'\
145
- "insteadOf ssh://git@github.com/ && "\
146
- 'git config --global --add url."https://github.com/".'\
147
- "insteadOf ssh://git@github.com: && "\
148
- 'git config --global --add url."https://github.com/".'\
149
- "insteadOf git@github.com: && "\
150
- 'git config --global --add url."https://github.com/".'\
151
- "insteadOf git@github.com/ && "\
152
- 'git config --global --add url."https://github.com/".'\
153
- "insteadOf git://github.com/"
154
- )
155
- end
156
-
157
- def self.configure_git_credentials(credentials)
158
- # Then add a file-based credential store that loads a file in this repo.
159
- # Under the hood this uses git credential-store, but it's invoked through
160
- # an wrapper binary that only allows non-mutative commands. Without this,
161
- # whenever the credentials are deemed to be invalid, they're erased.
162
- credential_helper_path =
163
- File.join(__dir__, "../../helpers/utils/git-credential-store-immutable")
164
- run_shell_command(
165
- "git config --global credential.helper "\
166
- "'#{credential_helper_path} --file=#{Dir.pwd}/git.store'"
167
- )
168
-
169
- # Build the content for our credentials file
170
- git_store_content = ""
171
- credentials.each do |cred|
172
- next unless cred["type"] == "git_source"
173
-
174
- authenticated_url =
175
- "https://#{cred.fetch('username')}:#{cred.fetch('password')}"\
176
- "@#{cred.fetch('host')}"
177
-
178
- git_store_content += authenticated_url + "\n"
179
- end
180
-
181
- # Save the file
182
- File.write("git.store", git_store_content)
183
- end
184
-
185
- def self.stash_global_git_config
186
- return unless File.exist?(GIT_CONFIG_GLOBAL_PATH)
187
-
188
- contents = File.read(GIT_CONFIG_GLOBAL_PATH)
189
- digest = Digest::SHA2.hexdigest(contents)[0...10]
190
- backup_path = GIT_CONFIG_GLOBAL_PATH + ".backup-#{digest}"
191
-
192
- FileUtils.mv(GIT_CONFIG_GLOBAL_PATH, backup_path)
193
- backup_path
194
- end
195
-
196
- def self.reset_global_git_config(backup_path)
197
- return if backup_path.nil?
198
- return unless File.exist?(backup_path)
199
-
200
- FileUtils.mv(backup_path, GIT_CONFIG_GLOBAL_PATH)
201
- end
202
-
203
- def self.run_shell_command(command)
204
- start = Time.now
205
- stdout, process = Open3.capture2e(command)
206
- time_taken = start - Time.now
207
-
208
- # Raise an error with the output from the shell session if the
209
- # command returns a non-zero status
210
- return if process.success?
211
-
212
- error_context = {
213
- command: command,
214
- time_taken: time_taken,
215
- process_exit_value: process.to_s
216
- }
217
-
218
- raise SharedHelpers::HelperSubprocessFailed.new(
219
- message: stdout,
220
- error_context: error_context
221
- )
222
- end
223
- end
224
- end
@@ -1,120 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Dependabot
4
- class Source
5
- GITHUB_SOURCE = %r{
6
- (?<provider>github)
7
- (?:\.com)[/:]
8
- (?<repo>[\w.-]+/(?:(?!\.git|\.\s)[\w.-])+)
9
- (?:(?:/tree|/blob)/(?<branch>[^/]+)/(?<directory>.*)[\#|/])?
10
- }x.freeze
11
-
12
- GITLAB_SOURCE = %r{
13
- (?<provider>gitlab)
14
- (?:\.com)[/:]
15
- (?<repo>[^/\s]+/(?:(?!\.git|\.\s)[^/\s#"',])+)
16
- (?:(?:/tree|/blob)/(?<branch>[^/]+)/(?<directory>.*)[\#|/])?
17
- }x.freeze
18
-
19
- BITBUCKET_SOURCE = %r{
20
- (?<provider>bitbucket)
21
- (?:\.org)[/:]
22
- (?<repo>[^/\s]+/(?:(?!\.git|\.\s)[^/\s#"',])+)
23
- (?:(?:/src)/(?<branch>[^/]+)/(?<directory>.*)[\#|/])?
24
- }x.freeze
25
-
26
- AZURE_SOURCE = %r{
27
- (?<provider>azure)
28
- (?:\.com)[/:]
29
- (?<repo>[^/\s]+/([^/\s]+/)?(?:_git/)(?:(?!\.git|\.\s)[^/\s#?"',])+)
30
- }x.freeze
31
-
32
- SOURCE_REGEX = /
33
- (?:#{GITHUB_SOURCE})|
34
- (?:#{GITLAB_SOURCE})|
35
- (?:#{BITBUCKET_SOURCE})|
36
- (?:#{AZURE_SOURCE})
37
- /x.freeze
38
-
39
- attr_reader :provider, :repo, :directory, :branch, :hostname, :api_endpoint
40
-
41
- def self.from_url(url_string)
42
- return unless url_string&.match?(SOURCE_REGEX)
43
-
44
- captures = url_string.match(SOURCE_REGEX).named_captures
45
-
46
- new(
47
- provider: captures.fetch("provider"),
48
- repo: captures.fetch("repo"),
49
- directory: captures.fetch("directory"),
50
- branch: captures.fetch("branch")
51
- )
52
- end
53
-
54
- def initialize(provider:, repo:, directory: nil, branch: nil, hostname: nil,
55
- api_endpoint: nil)
56
- if hostname.nil? ^ api_endpoint.nil?
57
- msg = "Both hostname and api_endpoint must be specified if either "\
58
- "are. Alternatively, both may be left blank to use the "\
59
- "provider's defaults."
60
- raise msg
61
- end
62
-
63
- @provider = provider
64
- @repo = repo
65
- @directory = directory
66
- @branch = branch
67
- @hostname = hostname || default_hostname(provider)
68
- @api_endpoint = api_endpoint || default_api_endpoint(provider)
69
- end
70
-
71
- def url
72
- case provider
73
- when "github" then "https://github.com/" + repo
74
- when "bitbucket" then "https://bitbucket.org/" + repo
75
- when "gitlab" then "https://gitlab.com/" + repo
76
- when "azure" then "https://dev.azure.com/" + repo
77
- else raise "Unexpected repo provider '#{provider}'"
78
- end
79
- end
80
-
81
- def organization
82
- repo.split("/").first
83
- end
84
-
85
- def project
86
- raise "Project is an Azure DevOps concept only" unless provider == "azure"
87
-
88
- parts = repo.split("/_git/")
89
- return parts.first.split("/").last if parts.first.split("/").count == 2
90
-
91
- parts.last
92
- end
93
-
94
- def unscoped_repo
95
- repo.split("/").last
96
- end
97
-
98
- private
99
-
100
- def default_hostname(provider)
101
- case provider
102
- when "github" then "github.com"
103
- when "bitbucket" then "bitbucket.org"
104
- when "gitlab" then "gitlab.com"
105
- when "azure" then "dev.azure.com"
106
- else raise "Unexpected provider '#{provider}'"
107
- end
108
- end
109
-
110
- def default_api_endpoint(provider)
111
- case provider
112
- when "github" then "https://api.github.com/"
113
- when "bitbucket" then "https://api.bitbucket.org/2.0/"
114
- when "gitlab" then "https://gitlab.com/api/v4"
115
- when "azure" then "https://dev.azure.com/"
116
- else raise "Unexpected provider '#{provider}'"
117
- end
118
- end
119
- end
120
- end