danger 8.0.4

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.
Files changed (121) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +94 -0
  4. data/bin/danger +5 -0
  5. data/lib/assets/DangerfileTemplate +13 -0
  6. data/lib/danger.rb +44 -0
  7. data/lib/danger/ci_source/appcenter.rb +55 -0
  8. data/lib/danger/ci_source/appveyor.rb +60 -0
  9. data/lib/danger/ci_source/azure_pipelines.rb +44 -0
  10. data/lib/danger/ci_source/bamboo.rb +41 -0
  11. data/lib/danger/ci_source/bitbucket_pipelines.rb +37 -0
  12. data/lib/danger/ci_source/bitrise.rb +65 -0
  13. data/lib/danger/ci_source/buddybuild.rb +62 -0
  14. data/lib/danger/ci_source/buildkite.rb +51 -0
  15. data/lib/danger/ci_source/ci_source.rb +37 -0
  16. data/lib/danger/ci_source/circle.rb +94 -0
  17. data/lib/danger/ci_source/circle_api.rb +51 -0
  18. data/lib/danger/ci_source/cirrus.rb +31 -0
  19. data/lib/danger/ci_source/code_build.rb +57 -0
  20. data/lib/danger/ci_source/codefresh.rb +53 -0
  21. data/lib/danger/ci_source/codeship.rb +44 -0
  22. data/lib/danger/ci_source/dotci.rb +52 -0
  23. data/lib/danger/ci_source/drone.rb +71 -0
  24. data/lib/danger/ci_source/github_actions.rb +43 -0
  25. data/lib/danger/ci_source/gitlab_ci.rb +86 -0
  26. data/lib/danger/ci_source/jenkins.rb +149 -0
  27. data/lib/danger/ci_source/local_git_repo.rb +119 -0
  28. data/lib/danger/ci_source/local_only_git_repo.rb +47 -0
  29. data/lib/danger/ci_source/screwdriver.rb +47 -0
  30. data/lib/danger/ci_source/semaphore.rb +37 -0
  31. data/lib/danger/ci_source/support/commits.rb +17 -0
  32. data/lib/danger/ci_source/support/find_repo_info_from_logs.rb +35 -0
  33. data/lib/danger/ci_source/support/find_repo_info_from_url.rb +42 -0
  34. data/lib/danger/ci_source/support/local_pull_request.rb +14 -0
  35. data/lib/danger/ci_source/support/no_pull_request.rb +7 -0
  36. data/lib/danger/ci_source/support/no_repo_info.rb +5 -0
  37. data/lib/danger/ci_source/support/pull_request_finder.rb +179 -0
  38. data/lib/danger/ci_source/support/remote_pull_request.rb +15 -0
  39. data/lib/danger/ci_source/support/repo_info.rb +10 -0
  40. data/lib/danger/ci_source/surf.rb +37 -0
  41. data/lib/danger/ci_source/teamcity.rb +161 -0
  42. data/lib/danger/ci_source/travis.rb +51 -0
  43. data/lib/danger/ci_source/vsts.rb +73 -0
  44. data/lib/danger/ci_source/xcode_server.rb +48 -0
  45. data/lib/danger/clients/rubygems_client.rb +14 -0
  46. data/lib/danger/commands/dangerfile/gem.rb +43 -0
  47. data/lib/danger/commands/dangerfile/init.rb +30 -0
  48. data/lib/danger/commands/dry_run.rb +54 -0
  49. data/lib/danger/commands/init.rb +297 -0
  50. data/lib/danger/commands/init_helpers/interviewer.rb +92 -0
  51. data/lib/danger/commands/local.rb +83 -0
  52. data/lib/danger/commands/local_helpers/http_cache.rb +36 -0
  53. data/lib/danger/commands/local_helpers/local_setup.rb +46 -0
  54. data/lib/danger/commands/local_helpers/pry_setup.rb +31 -0
  55. data/lib/danger/commands/plugins/plugin_json.rb +46 -0
  56. data/lib/danger/commands/plugins/plugin_lint.rb +54 -0
  57. data/lib/danger/commands/plugins/plugin_readme.rb +45 -0
  58. data/lib/danger/commands/pr.rb +92 -0
  59. data/lib/danger/commands/runner.rb +94 -0
  60. data/lib/danger/commands/staging.rb +53 -0
  61. data/lib/danger/commands/systems.rb +43 -0
  62. data/lib/danger/comment_generators/bitbucket_server.md.erb +20 -0
  63. data/lib/danger/comment_generators/bitbucket_server_inline.md.erb +15 -0
  64. data/lib/danger/comment_generators/bitbucket_server_message_group.md.erb +12 -0
  65. data/lib/danger/comment_generators/github.md.erb +55 -0
  66. data/lib/danger/comment_generators/github_inline.md.erb +26 -0
  67. data/lib/danger/comment_generators/gitlab.md.erb +40 -0
  68. data/lib/danger/comment_generators/gitlab_inline.md.erb +26 -0
  69. data/lib/danger/comment_generators/vsts.md.erb +20 -0
  70. data/lib/danger/core_ext/file_list.rb +18 -0
  71. data/lib/danger/core_ext/string.rb +20 -0
  72. data/lib/danger/danger_core/dangerfile.rb +341 -0
  73. data/lib/danger/danger_core/dangerfile_dsl.rb +29 -0
  74. data/lib/danger/danger_core/dangerfile_generator.rb +11 -0
  75. data/lib/danger/danger_core/environment_manager.rb +123 -0
  76. data/lib/danger/danger_core/executor.rb +92 -0
  77. data/lib/danger/danger_core/message_aggregator.rb +49 -0
  78. data/lib/danger/danger_core/message_group.rb +68 -0
  79. data/lib/danger/danger_core/messages/base.rb +56 -0
  80. data/lib/danger/danger_core/messages/markdown.rb +42 -0
  81. data/lib/danger/danger_core/messages/violation.rb +54 -0
  82. data/lib/danger/danger_core/plugins/dangerfile_bitbucket_cloud_plugin.rb +144 -0
  83. data/lib/danger/danger_core/plugins/dangerfile_bitbucket_server_plugin.rb +211 -0
  84. data/lib/danger/danger_core/plugins/dangerfile_danger_plugin.rb +248 -0
  85. data/lib/danger/danger_core/plugins/dangerfile_git_plugin.rb +158 -0
  86. data/lib/danger/danger_core/plugins/dangerfile_github_plugin.rb +254 -0
  87. data/lib/danger/danger_core/plugins/dangerfile_gitlab_plugin.rb +240 -0
  88. data/lib/danger/danger_core/plugins/dangerfile_local_only_plugin.rb +42 -0
  89. data/lib/danger/danger_core/plugins/dangerfile_messaging_plugin.rb +218 -0
  90. data/lib/danger/danger_core/plugins/dangerfile_vsts_plugin.rb +191 -0
  91. data/lib/danger/danger_core/standard_error.rb +143 -0
  92. data/lib/danger/helpers/array_subclass.rb +61 -0
  93. data/lib/danger/helpers/comment.rb +32 -0
  94. data/lib/danger/helpers/comments_helper.rb +178 -0
  95. data/lib/danger/helpers/comments_parsing_helper.rb +70 -0
  96. data/lib/danger/helpers/emoji_mapper.rb +41 -0
  97. data/lib/danger/helpers/find_max_num_violations.rb +31 -0
  98. data/lib/danger/helpers/message_groups_array_helper.rb +31 -0
  99. data/lib/danger/plugin_support/gems_resolver.rb +77 -0
  100. data/lib/danger/plugin_support/plugin.rb +49 -0
  101. data/lib/danger/plugin_support/plugin_file_resolver.rb +30 -0
  102. data/lib/danger/plugin_support/plugin_linter.rb +161 -0
  103. data/lib/danger/plugin_support/plugin_parser.rb +199 -0
  104. data/lib/danger/plugin_support/templates/readme_table.html.erb +26 -0
  105. data/lib/danger/request_sources/bitbucket_cloud.rb +171 -0
  106. data/lib/danger/request_sources/bitbucket_cloud_api.rb +181 -0
  107. data/lib/danger/request_sources/bitbucket_server.rb +105 -0
  108. data/lib/danger/request_sources/bitbucket_server_api.rb +117 -0
  109. data/lib/danger/request_sources/github/github.rb +530 -0
  110. data/lib/danger/request_sources/github/github_review.rb +126 -0
  111. data/lib/danger/request_sources/github/github_review_resolver.rb +19 -0
  112. data/lib/danger/request_sources/github/github_review_unsupported.rb +25 -0
  113. data/lib/danger/request_sources/gitlab.rb +525 -0
  114. data/lib/danger/request_sources/local_only.rb +53 -0
  115. data/lib/danger/request_sources/request_source.rb +85 -0
  116. data/lib/danger/request_sources/support/get_ignored_violation.rb +17 -0
  117. data/lib/danger/request_sources/vsts.rb +118 -0
  118. data/lib/danger/request_sources/vsts_api.rb +138 -0
  119. data/lib/danger/scm_source/git_repo.rb +181 -0
  120. data/lib/danger/version.rb +4 -0
  121. metadata +339 -0
@@ -0,0 +1,42 @@
1
+ require "danger/plugin_support/plugin"
2
+
3
+ # Danger
4
+ module Danger
5
+ # Handles interacting with local only plugin inside a Dangerfile.
6
+ # It is support pluggin for dry_run command and does not expose any methods.
7
+ # But you can still use other plugins like git
8
+ #
9
+ # @example Check that added lines contains agreed form of words
10
+ #
11
+ # git.diff.each do |chunk|
12
+ # chunk.patch.lines.grep(/^\+/).each do |added_line|
13
+ # if added_line.gsub!(/(?<cancel>cancel)(?<rest>[^l[[:space:]][[:punct:]]]+)/i, '>>\k<cancel>-l-\k<rest><<')
14
+ # fail "Single 'L' for cancellation-alike words in '#{added_line}'"
15
+ # end
16
+ # end
17
+ # end
18
+ #
19
+ # @see danger/danger
20
+ # @tags core, local_only
21
+ #
22
+ class DangerfileLocalOnlyPlugin < Plugin
23
+ # So that this init can fail.
24
+ def self.new(dangerfile)
25
+ return nil if dangerfile.env.request_source.class != Danger::RequestSources::LocalOnly
26
+ super
27
+ end
28
+
29
+ def initialize(dangerfile)
30
+ super(dangerfile)
31
+
32
+ @local_repo = dangerfile.env.request_source
33
+ end
34
+
35
+ # The instance name used in the Dangerfile
36
+ # @return [String]
37
+ #
38
+ def self.instance_name
39
+ "local_repo"
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,218 @@
1
+ require "danger/danger_core/messages/violation"
2
+ require "danger/danger_core/messages/markdown"
3
+ require "danger/plugin_support/plugin"
4
+
5
+ module Danger
6
+ # Provides the feedback mechanism for Danger. Danger can keep track of
7
+ # messages, warnings, failure and post arbitrary markdown into a comment.
8
+ #
9
+ # The message within which Danger communicates back is amended on each run in a session.
10
+ #
11
+ # Each of `message`, `warn` and `fail` have a `sticky` flag, `false` by default, which
12
+ # when `true` means that the message will be crossed out instead of being removed.
13
+ # If it's not called again on subsequent runs.
14
+ #
15
+ # Each of `message`, `warn`, `fail` and `markdown` support multiple passed arguments
16
+ # @example
17
+ #
18
+ # message 'Hello', 'World', file: "Dangerfile", line: 1
19
+ # warn ['This', 'is', 'warning'], file: "Dangerfile", line: 1
20
+ # failure 'Ooops', 'bad bad error', sticky: false
21
+ # markdown '# And', '# Even', '# Markdown', file: "Dangerfile", line: 1
22
+ #
23
+ # By default, using `failure` would fail the corresponding build. Either via an API call, or
24
+ # via the return value for the danger command. Older code examples use `fail` which is an alias
25
+ # of `failure`, but the default Rubocop settings would have an issue with it.
26
+ #
27
+ # You can optionally add `file` and `line` to provide inline feedback on a PR in GitHub, note that
28
+ # only feedback inside the PR's diff will show up inline. Others will appear inside the main comment.
29
+ #
30
+ # It is possible to have Danger ignore specific warnings or errors by writing `Danger: Ignore "[warning/error text]"`.
31
+ #
32
+ # Sidenote: Messaging is the only plugin which adds functions to the root of the Dangerfile.
33
+ #
34
+ # @example Failing a build
35
+ #
36
+ # failure "This build didn't pass tests"
37
+ # failure "Ooops!", "Something bad happened"
38
+ # failure ["This is example", "with array"]
39
+ #
40
+ # @example Failing a build, and note that on subsequent runs
41
+ #
42
+ # failure("This build didn't pass tests", sticky: true)
43
+ #
44
+ # @example Passing a warning
45
+ #
46
+ # warn "This build didn't pass linting"
47
+ # warn "Hm...", "This is not really good"
48
+ # warn ["Multiple warnings", "via array"]
49
+ #
50
+ # @example Displaying a markdown table
51
+ #
52
+ # message = "### Proselint found issues\n\n"
53
+ # message << "Line | Message | Severity |\n"
54
+ # message << "| --- | ----- | ----- |\n"
55
+ # message << "20 | No documentation | Error \n"
56
+ # markdown message
57
+ #
58
+ # markdown "### First issue", "### Second issue"
59
+ # markdown ["### First issue", "### Second issue"]
60
+ #
61
+ # @example Adding an inline warning to a file
62
+ #
63
+ # warn("You shouldn't use puts in your Dangerfile", file: "Dangerfile", line: 10)
64
+ #
65
+ #
66
+ # @see danger/danger
67
+ # @tags core, messaging
68
+ #
69
+
70
+ class DangerfileMessagingPlugin < Plugin
71
+ def initialize(dangerfile)
72
+ super(dangerfile)
73
+
74
+ @warnings = []
75
+ @errors = []
76
+ @messages = []
77
+ @markdowns = []
78
+ end
79
+
80
+ # The instance name used in the Dangerfile
81
+ # @return [String]
82
+ #
83
+ def self.instance_name
84
+ "messaging"
85
+ end
86
+
87
+ # @!group Core
88
+ # Print markdown to below the table
89
+ #
90
+ # @param [String, Array<String>] message
91
+ # The markdown based message to be printed below the table
92
+ # @param [String] file
93
+ # Optional. Path to the file that the message is for.
94
+ # @param [String] line
95
+ # Optional. The line in the file to present the message in.
96
+ # @return [void]
97
+ #
98
+ def markdown(*markdowns, **options)
99
+ file = options.fetch(:file, nil)
100
+ line = options.fetch(:line, nil)
101
+
102
+ markdowns.flatten.each do |markdown|
103
+ @markdowns << Markdown.new(markdown, file, line)
104
+ end
105
+ end
106
+
107
+ # @!group Core
108
+ # Print out a generate message on the PR
109
+ #
110
+ # @param [String, Array<String>] message
111
+ # The message to present to the user
112
+ # @param [Boolean] sticky
113
+ # Whether the message should be kept after it was fixed,
114
+ # defaults to `false`.
115
+ # @param [String] file
116
+ # Optional. Path to the file that the message is for.
117
+ # @param [String] line
118
+ # Optional. The line in the file to present the message in.
119
+ # @return [void]
120
+ #
121
+ def message(*messages, **options)
122
+ sticky = options.fetch(:sticky, false)
123
+ file = options.fetch(:file, nil)
124
+ line = options.fetch(:line, nil)
125
+
126
+ messages.flatten.each do |message|
127
+ @messages << Violation.new(message, sticky, file, line, type: :message) if message
128
+ end
129
+ end
130
+
131
+ # @!group Core
132
+ # Specifies a problem, but not critical
133
+ #
134
+ # @param [String, Array<String>] message
135
+ # The message to present to the user
136
+ # @param [Boolean] sticky
137
+ # Whether the message should be kept after it was fixed,
138
+ # defaults to `false`.
139
+ # @param [String] file
140
+ # Optional. Path to the file that the message is for.
141
+ # @param [String] line
142
+ # Optional. The line in the file to present the message in.
143
+ # @return [void]
144
+ #
145
+ def warn(*warnings, **options)
146
+ sticky = options.fetch(:sticky, false)
147
+ file = options.fetch(:file, nil)
148
+ line = options.fetch(:line, nil)
149
+
150
+ warnings.flatten.each do |warning|
151
+ next if should_ignore_violation(warning)
152
+ @warnings << Violation.new(warning, sticky, file, line, type: :warning) if warning
153
+ end
154
+ end
155
+
156
+ # @!group Core
157
+ # Declares a CI blocking error
158
+ #
159
+ # @param [String, Array<String>] message
160
+ # The message to present to the user
161
+ # @param [Boolean] sticky
162
+ # Whether the message should be kept after it was fixed,
163
+ # defaults to `false`.
164
+ # @param [String] file
165
+ # Optional. Path to the file that the message is for.
166
+ # @param [String] line
167
+ # Optional. The line in the file to present the message in.
168
+ # @return [void]
169
+ #
170
+ def fail(*failures, **options)
171
+ sticky = options.fetch(:sticky, false)
172
+ file = options.fetch(:file, nil)
173
+ line = options.fetch(:line, nil)
174
+
175
+ failures.flatten.each do |failure|
176
+ next if should_ignore_violation(failure)
177
+ @errors << Violation.new(failure, sticky, file, line, type: :error) if failure
178
+ end
179
+ end
180
+
181
+ alias_method :failure, :fail
182
+
183
+ # @!group Reporting
184
+ # A list of all messages passed to Danger, including
185
+ # the markdowns.
186
+ #
187
+ # @visibility hidden
188
+ # @return [Hash]
189
+ def status_report
190
+ {
191
+ errors: @errors.map(&:message).clone.freeze,
192
+ warnings: @warnings.map(&:message).clone.freeze,
193
+ messages: @messages.map(&:message).clone.freeze,
194
+ markdowns: @markdowns.clone.freeze
195
+ }
196
+ end
197
+
198
+ # @!group Reporting
199
+ # A list of all violations passed to Danger, we don't
200
+ # anticipate users of Danger needing to use this.
201
+ #
202
+ # @visibility hidden
203
+ # @return [Hash]
204
+ def violation_report
205
+ {
206
+ errors: @errors.clone.freeze,
207
+ warnings: @warnings.clone.freeze,
208
+ messages: @messages.clone.freeze
209
+ }
210
+ end
211
+
212
+ private
213
+
214
+ def should_ignore_violation(message)
215
+ env.request_source.ignored_violations.include? message
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,191 @@
1
+ # coding: utf-8
2
+
3
+ require "danger/plugin_support/plugin"
4
+
5
+ module Danger
6
+ # Handles interacting with VSTS inside a Dangerfile. Provides a few functions which wrap `pr_json` and also
7
+ # through a few standard functions to simplify your code.
8
+ #
9
+ # @example Warn when a PR is classed as work in progress
10
+ #
11
+ # warn "PR is classed as Work in Progress" if vsts.pr_title.include? "[WIP]"
12
+ #
13
+ # @example Declare a PR to be simple to avoid specific Danger rules
14
+ #
15
+ # declared_trivial = (vsts.pr_title + vsts.pr_body).include?("#trivial")
16
+ #
17
+ # @example Ensure there is a summary for a PR
18
+ #
19
+ # failure "Please provide a summary in the Pull Request description" if vsts.pr_body.length < 5
20
+ #
21
+ # @example Only accept PRs to the develop branch
22
+ #
23
+ # failure "Please re-submit this PR to develop, we may have already fixed your issue." if vsts.branch_for_base != "develop"
24
+ #
25
+ # @example Highlight when a celebrity makes a pull request
26
+ #
27
+ # message "Welcome, Danger." if vsts.pr_author == "dangermcshane"
28
+ #
29
+ # @example Ensure that all PRs have an assignee
30
+ #
31
+ # warn "This PR does not have any assignees yet." unless vsts.pr_json["reviewers"].length == 0
32
+ #
33
+ # @example Send a message with links to a collection of specific files
34
+ #
35
+ # if git.modified_files.include? "config/*.js"
36
+ # config_files = git.modified_files.select { |path| path.include? "config/" }
37
+ # message "This PR changes #{ vsts.markdown_link(config_files) }"
38
+ # end
39
+ #
40
+ # @example Highlight with a clickable link if a Package.json is changed
41
+ #
42
+ # warn "#{vsts.markdown_link("Package.json")} was edited." if git.modified_files.include? "Package.json"
43
+ #
44
+ # @example Note an issue with a particular line on a file using the #L[num] syntax, e.g. `#L23`
45
+ #
46
+ # linter_json = `my_linter lint "file"`
47
+ # results = JSON.parse linter_json
48
+ # unless results.empty?
49
+ # file, line, warning = result.first
50
+ # warn "#{vsts.markdown_link("#{file}#L#{line}")} has linter issue: #{warning}."
51
+ # end
52
+ #
53
+ #
54
+ # @see danger/danger
55
+ # @tags core, vsts
56
+ #
57
+ class DangerfileVSTSPlugin < Plugin
58
+ # So that this init can fail.
59
+ def self.new(dangerfile)
60
+ return nil if dangerfile.env.request_source.class != Danger::RequestSources::VSTS
61
+ super
62
+ end
63
+
64
+ # The instance name used in the Dangerfile
65
+ # @return [String]
66
+ #
67
+ def self.instance_name
68
+ "vsts"
69
+ end
70
+
71
+ def initialize(dangerfile)
72
+ super(dangerfile)
73
+ @source = dangerfile.env.request_source
74
+ end
75
+
76
+ # @!group VSTS Misc
77
+ # The hash that represents the PR's JSON. For an example of what this looks like
78
+ # see the [Danger Fixture'd one](https://raw.githubusercontent.com/danger/danger/master/spec/fixtures/vsts_api/pr_response.json).
79
+ # @return [Hash]
80
+ def pr_json
81
+ @source.pr_json
82
+ end
83
+
84
+ # @!group PR Metadata
85
+ # The title of the Pull Request.
86
+ # @return [String]
87
+ #
88
+ def pr_title
89
+ @source.pr_json[:title].to_s
90
+ end
91
+
92
+ # @!group PR Metadata
93
+ # The body text of the Pull Request.
94
+ # @return [String]
95
+ #
96
+ def pr_description
97
+ @source.pr_json[:description].to_s
98
+ end
99
+ alias pr_body pr_description
100
+
101
+ # @!group PR Metadata
102
+ # The username of the author of the Pull Request.
103
+ # @return [String]
104
+ #
105
+ def pr_author
106
+ @source.pr_json[:createdBy][:displayName].to_s
107
+ end
108
+
109
+ # @!group PR Commit Metadata
110
+ # The branch to which the PR is going to be merged into.
111
+ # @return [String]
112
+ #
113
+ def branch_for_base
114
+ branch_name(:targetRefName)
115
+ end
116
+
117
+ # @!group PR Commit Metadata
118
+ # A href that represents the current PR
119
+ # @return [String]
120
+ #
121
+ def pr_link
122
+ repo_path = @source.pr_json[:repository][:remoteUrl].to_s
123
+ pull_request_id = @source.pr_json[:pullRequestId].to_s
124
+
125
+ "#{repo_path}/pullRequest/#{pull_request_id}"
126
+ end
127
+
128
+ # @!group PR Commit Metadata
129
+ # The branch to which the PR is going to be merged from.
130
+ # @return [String]
131
+ #
132
+ def branch_for_head
133
+ branch_name(:sourceRefName)
134
+ end
135
+
136
+ # @!group PR Commit Metadata
137
+ # The base commit to which the PR is going to be merged as a parent.
138
+ # @return [String]
139
+ #
140
+ def base_commit
141
+ @source.pr_json[:lastMergeTargetCommit][:commitId].to_s
142
+ end
143
+
144
+ # @!group PR Commit Metadata
145
+ # The head commit to which the PR is requesting to be merged from.
146
+ # @return [String]
147
+ #
148
+ def head_commit
149
+ @source.pr_json[:lastMergeSourceCommit][:commitId].to_s
150
+ end
151
+
152
+ # @!group VSTS Misc
153
+ # Returns a list of Markdown links for a file, or files in the head repository.
154
+ # It returns a string of multiple links if passed an array.
155
+ # @param [String or Array<String>] paths
156
+ # A list of strings to convert to Markdown links
157
+ # @param [Bool] full_path
158
+ # Shows the full path as the link's text, defaults to `true`.
159
+ #
160
+ # @return [String]
161
+ #
162
+ def markdown_link(paths, full_path: true)
163
+ paths = [paths] unless paths.kind_of?(Array)
164
+ commit = head_commit
165
+ repo = pr_json[:repository][:remoteUrl].to_s
166
+
167
+ paths = paths.map do |path|
168
+ path, line = path.split("#L")
169
+ url_path = path.start_with?("/") ? path : "/#{path}"
170
+ text = full_path ? path : File.basename(path)
171
+ url_path.gsub!(" ", "%20")
172
+ line_ref = line ? "&line=#{line}" : ""
173
+ create_markdown_link("#{repo}/commit/#{commit}?path=#{url_path}&_a=contents#{line_ref}", text)
174
+ end
175
+
176
+ return paths.first if paths.count < 2
177
+ paths.first(paths.count - 1).join(", ") + " & " + paths.last
178
+ end
179
+
180
+ private
181
+
182
+ def create_markdown_link(href, text)
183
+ "[#{text}](#{href})"
184
+ end
185
+
186
+ def branch_name(key)
187
+ repo_matches = @source.pr_json[key].to_s.match(%r{refs\/heads\/(.*)})
188
+ repo_matches[1] unless repo_matches.nil?
189
+ end
190
+ end
191
+ end