gitlab_reviewable 0.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 (54) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +37 -0
  4. data/app/controllers/gitlab_reviewable/reviews_controller.rb +58 -0
  5. data/app/helpers/gitlab_reviewable/reviews_helper.rb +377 -0
  6. data/app/views/gitlab_reviewable/reviews/diffs.html.haml +53 -0
  7. data/app/views/gitlab_reviewable/reviews/discussion.html.haml +55 -0
  8. data/app/views/layouts/review.haml +34 -0
  9. data/config/routes.rb +5 -0
  10. data/lib/gitlab_reviewable.rb +4 -0
  11. data/lib/gitlab_reviewable/engine.rb +5 -0
  12. data/lib/gitlab_reviewable/version.rb +3 -0
  13. data/lib/tasks/gitlab_reviewable_tasks.rake +4 -0
  14. data/test/dummy/README.rdoc +28 -0
  15. data/test/dummy/Rakefile +6 -0
  16. data/test/dummy/app/assets/javascripts/application.js +13 -0
  17. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  18. data/test/dummy/app/controllers/application_controller.rb +5 -0
  19. data/test/dummy/app/helpers/application_helper.rb +2 -0
  20. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  21. data/test/dummy/bin/bundle +3 -0
  22. data/test/dummy/bin/rails +4 -0
  23. data/test/dummy/bin/rake +4 -0
  24. data/test/dummy/bin/setup +29 -0
  25. data/test/dummy/config.ru +4 -0
  26. data/test/dummy/config/application.rb +26 -0
  27. data/test/dummy/config/boot.rb +5 -0
  28. data/test/dummy/config/database.yml +25 -0
  29. data/test/dummy/config/environment.rb +5 -0
  30. data/test/dummy/config/environments/development.rb +41 -0
  31. data/test/dummy/config/environments/production.rb +79 -0
  32. data/test/dummy/config/environments/test.rb +42 -0
  33. data/test/dummy/config/initializers/assets.rb +11 -0
  34. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  35. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  36. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  37. data/test/dummy/config/initializers/inflections.rb +16 -0
  38. data/test/dummy/config/initializers/mime_types.rb +4 -0
  39. data/test/dummy/config/initializers/session_store.rb +3 -0
  40. data/test/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
  41. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  42. data/test/dummy/config/locales/en.yml +23 -0
  43. data/test/dummy/config/routes.rb +4 -0
  44. data/test/dummy/config/secrets.yml +22 -0
  45. data/test/dummy/db/development.sqlite3 +0 -0
  46. data/test/dummy/log/development.log +423 -0
  47. data/test/dummy/public/404.html +67 -0
  48. data/test/dummy/public/422.html +67 -0
  49. data/test/dummy/public/500.html +66 -0
  50. data/test/dummy/public/favicon.ico +0 -0
  51. data/test/gitlab_reviewable_test.rb +7 -0
  52. data/test/integration/navigation_test.rb +8 -0
  53. data/test/test_helper.rb +21 -0
  54. metadata +164 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e106229e4eeb661a205c46cda1f073d0dad6ed40
4
+ data.tar.gz: eaf7dec42bf9a8e4422b81e40942983570c2c20b
5
+ SHA512:
6
+ metadata.gz: 2ed83457388686dd79b7075b4d8188462cee050032bfd6da476856b24df4670c00a7bcd13f21d162955e2f389f76b0d450084bd3790a92f2f814d515c00813a1
7
+ data.tar.gz: 5c380c55e79e638b3e493858a2e4de320c1047376b04bf48e664a34be9366000f7e716f909333a8d38e44c4ffd26ecba06294d7fe2539f768382de8d778c6f5d
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2017 lenghan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'GitlabReviewable'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task default: :test
@@ -0,0 +1,58 @@
1
+ module GitlabReviewable
2
+ class ReviewsController < ApplicationController
3
+ include DiffHelper
4
+
5
+ skip_before_action :authenticate_user!
6
+ before_action :merge_request
7
+ before_action :define_show_vars
8
+ layout 'review'
9
+
10
+ def diffs
11
+ puts 111111
12
+ @note_counts = Note.where(commit_id: @merge_request.commits.map(&:id)).
13
+ group(:commit_id).count
14
+
15
+ respond_to do |format|
16
+ format.html
17
+ end
18
+ end
19
+
20
+ def discussion
21
+ @note_counts = Note.where(commit_id: @merge_request.commits.map(&:id)).
22
+ group(:commit_id).count
23
+
24
+ respond_to do |format|
25
+ format.html
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def merge_request
32
+ @project = Project.find_by!(id: params[:project_id])
33
+ @merge_request ||= @project.merge_requests.find_by!(iid: params[:merge_request_id])
34
+ end
35
+
36
+ def define_show_vars
37
+ # Build a note object for comment form
38
+ @note = @project.notes.new(noteable: @merge_request)
39
+ @notes = @merge_request.mr_and_commit_notes.nonawards.inc_author.fresh
40
+ @discussions = @notes.discussions
41
+ @noteable = @merge_request
42
+
43
+ # Get commits from repository
44
+ # or from cache if already merged
45
+ @commits = @merge_request.commits
46
+
47
+ @merge_request_diff = @merge_request.merge_request_diff
48
+
49
+ @ci_commit = @merge_request.ci_commit
50
+ @statuses = @ci_commit.statuses if @ci_commit
51
+
52
+ if @merge_request.locked_long_ago?
53
+ @merge_request.unlock_mr
54
+ @merge_request.close
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,377 @@
1
+ module GitlabReviewable
2
+ module ReviewsHelper
3
+ def method_missing method, *args, &block
4
+ if method.to_s.end_with?('_path') or method.to_s.end_with?('_url')
5
+ if main_app.respond_to?(method)
6
+ main_app.send(method, *args)
7
+ else
8
+ super
9
+ end
10
+ else
11
+ super
12
+ end
13
+ end
14
+
15
+ def respond_to?(method)
16
+ if method.to_s.end_with?('_path') or method.to_s.end_with?('_url')
17
+ if main_app.respond_to?(method)
18
+ true
19
+ else
20
+ super
21
+ end
22
+ else
23
+ super
24
+ end
25
+ end
26
+
27
+ def remove_from_project_team_message(project, member)
28
+ if member.user
29
+ "You are going to remove #{member.user.name} from #{project.name} project team. Are you sure?"
30
+ else
31
+ "You are going to revoke the invitation for #{member.invite_email} to join #{project.name} project team. Are you sure?"
32
+ end
33
+ end
34
+
35
+ def link_to_project(project)
36
+ link_to [project.namespace.becomes(Namespace), project], title: h(project.name) do
37
+ title = content_tag(:span, project.name, class: 'project-name')
38
+
39
+ if project.namespace
40
+ namespace = content_tag(:span, "#{project.namespace.human_name} / ", class: 'namespace-name')
41
+ title = namespace + title
42
+ end
43
+
44
+ title
45
+ end
46
+ end
47
+
48
+ def link_to_member_avatar(author, opts = {})
49
+ default_opts = { avatar: true, name: true, size: 16, author_class: 'author', title: ":name" }
50
+ opts = default_opts.merge(opts)
51
+ image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar]
52
+ end
53
+
54
+ def link_to_member(project, author, opts = {}, &block)
55
+ default_opts = { avatar: true, name: true, size: 16, author_class: 'author', title: ":name" }
56
+ opts = default_opts.merge(opts)
57
+
58
+ return "(deleted)" unless author
59
+
60
+ author_html = ""
61
+
62
+ # Build avatar image tag
63
+ author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar]
64
+
65
+ # Build name span tag
66
+ if opts[:by_username]
67
+ author_html << content_tag(:span, sanitize("@#{author.username}"), class: opts[:author_class]) if opts[:name]
68
+ else
69
+ author_html << content_tag(:span, sanitize(author.name), class: opts[:author_class]) if opts[:name]
70
+ end
71
+
72
+ author_html << capture(&block) if block
73
+
74
+ author_html = author_html.html_safe
75
+
76
+ if opts[:name]
77
+ link_to(author_html, user_path(author), class: "author_link #{"#{opts[:mobile_classes]}" if opts[:mobile_classes]}").html_safe
78
+ else
79
+ title = opts[:title].sub(":name", sanitize(author.name))
80
+ link_to(author_html, user_path(author), class: "author_link has-tooltip", title: title, data: { container: 'body' } ).html_safe
81
+ end
82
+ end
83
+
84
+ def project_title(project, name = nil, url = nil)
85
+ namespace_link =
86
+ if project.group
87
+ link_to(simple_sanitize(project.group.name), group_path(project.group))
88
+ else
89
+ owner = project.namespace.owner
90
+ link_to(simple_sanitize(owner.name), user_path(owner))
91
+ end
92
+
93
+ project_link = link_to simple_sanitize(project.name), '#', { class: "project-item-select-holder" }
94
+
95
+ if current_user
96
+ project_link << icon("chevron-down", class: "dropdown-toggle-caret js-projects-dropdown-toggle", data: { target: ".js-dropdown-menu-projects", toggle: "dropdown" })
97
+ end
98
+
99
+ full_title = "#{namespace_link} / #{project_link}".html_safe
100
+ full_title << ' &middot; '.html_safe << link_to(simple_sanitize(name), url) if name
101
+
102
+ full_title
103
+ end
104
+
105
+ def remove_project_message(project)
106
+ "You are going to remove #{project.name_with_namespace}.\n Removed project CANNOT be restored!\n Are you ABSOLUTELY sure?"
107
+ end
108
+
109
+ def transfer_project_message(project)
110
+ "You are going to transfer #{project.name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
111
+ end
112
+
113
+ def remove_fork_project_message(project)
114
+ "You are going to remove the fork relationship to source project #{@project.forked_from_project.name_with_namespace}. Are you ABSOLUTELY sure?"
115
+ end
116
+
117
+ def project_nav_tabs
118
+ @nav_tabs ||= get_project_nav_tabs(@project, current_user)
119
+ end
120
+
121
+ def project_nav_tab?(name)
122
+ project_nav_tabs.include? name
123
+ end
124
+
125
+ def project_for_deploy_key(deploy_key)
126
+ if deploy_key.projects.include?(@project)
127
+ @project
128
+ else
129
+ deploy_key.projects.find { |project| can?(current_user, :read_project, project) }
130
+ end
131
+ end
132
+
133
+ def can_change_visibility_level?(project, current_user)
134
+ return false unless can?(current_user, :change_visibility_level, project)
135
+
136
+ if project.forked?
137
+ project.forked_from_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE
138
+ else
139
+ true
140
+ end
141
+ end
142
+
143
+ def user_max_access_in_project(user_id, project)
144
+ level = project.team.max_member_access(user_id)
145
+
146
+ if level
147
+ Gitlab::Access.options_with_owner.key(level)
148
+ end
149
+ end
150
+
151
+ def license_short_name(project)
152
+ return 'LICENSE' if project.repository.license_key.nil?
153
+
154
+ license = Licensee::License.new(project.repository.license_key)
155
+
156
+ license.nickname || license.name
157
+ end
158
+
159
+ private
160
+
161
+ def get_project_nav_tabs(project, current_user)
162
+ nav_tabs = [:home]
163
+
164
+ if !project.empty_repo? && can?(current_user, :download_code, project)
165
+ nav_tabs << [:files, :commits, :network, :graphs, :forks]
166
+ end
167
+
168
+ if project.repo_exists? && can?(current_user, :read_merge_request, project)
169
+ nav_tabs << :merge_requests
170
+ end
171
+
172
+ if can?(current_user, :read_pipeline, project)
173
+ nav_tabs << :pipelines
174
+ end
175
+
176
+ if can?(current_user, :read_build, project)
177
+ nav_tabs << :builds
178
+ end
179
+
180
+ if Gitlab.config.registry.enabled && can?(current_user, :read_container_image, project)
181
+ nav_tabs << :container_registry
182
+ end
183
+
184
+ if can?(current_user, :admin_project, project)
185
+ nav_tabs << :settings
186
+ end
187
+
188
+ if can?(current_user, :read_project_member, project)
189
+ nav_tabs << :team
190
+ end
191
+
192
+ if can?(current_user, :read_issue, project)
193
+ nav_tabs << :issues
194
+ end
195
+
196
+ if can?(current_user, :read_wiki, project)
197
+ nav_tabs << :wiki
198
+ end
199
+
200
+ if can?(current_user, :read_project_snippet, project)
201
+ nav_tabs << :snippets
202
+ end
203
+
204
+ if can?(current_user, :read_label, project)
205
+ nav_tabs << :labels
206
+ end
207
+
208
+ if can?(current_user, :read_milestone, project)
209
+ nav_tabs << :milestones
210
+ end
211
+
212
+ nav_tabs.flatten
213
+ end
214
+
215
+ def git_user_name
216
+ if current_user
217
+ current_user.name
218
+ else
219
+ "Your name"
220
+ end
221
+ end
222
+
223
+ def git_user_email
224
+ if current_user
225
+ current_user.email
226
+ else
227
+ "your@email.com"
228
+ end
229
+ end
230
+
231
+ def repository_size(project = @project)
232
+ size_in_bytes = project.repository_size * 1.megabyte
233
+ number_to_human_size(size_in_bytes, delimiter: ',', precision: 2)
234
+ end
235
+
236
+ def default_url_to_repo(project = @project)
237
+ case default_clone_protocol
238
+ when 'ssh'
239
+ project.ssh_url_to_repo
240
+ else
241
+ project.http_url_to_repo
242
+ end
243
+ end
244
+
245
+ def default_clone_protocol
246
+ if !current_user || current_user.require_ssh_key?
247
+ gitlab_config.protocol
248
+ else
249
+ "ssh"
250
+ end
251
+ end
252
+
253
+ def project_last_activity(project)
254
+ if project.last_activity_at
255
+ time_ago_with_tooltip(project.last_activity_at, placement: 'bottom', html_class: 'last_activity_time_ago')
256
+ else
257
+ "Never"
258
+ end
259
+ end
260
+
261
+ def add_special_file_path(project, file_name:, commit_message: nil)
262
+ namespace_project_new_blob_path(
263
+ project.namespace,
264
+ project,
265
+ project.default_branch || 'master',
266
+ file_name: file_name,
267
+ commit_message: commit_message || "Add #{file_name.downcase}"
268
+ )
269
+ end
270
+
271
+ def contribution_guide_path(project)
272
+ if project && contribution_guide = project.repository.contribution_guide
273
+ namespace_project_blob_path(
274
+ project.namespace,
275
+ project,
276
+ tree_join(project.default_branch,
277
+ contribution_guide.name)
278
+ )
279
+ end
280
+ end
281
+
282
+ def readme_path(project)
283
+ filename_path(project, :readme)
284
+ end
285
+
286
+ def changelog_path(project)
287
+ filename_path(project, :changelog)
288
+ end
289
+
290
+ def license_path(project)
291
+ filename_path(project, :license_blob)
292
+ end
293
+
294
+ def version_path(project)
295
+ filename_path(project, :version)
296
+ end
297
+
298
+ def project_wiki_path_with_version(proj, page, version, is_newest)
299
+ url_params = is_newest ? {} : { version_id: version }
300
+ namespace_project_wiki_path(proj.namespace, proj, page, url_params)
301
+ end
302
+
303
+ def project_status_css_class(status)
304
+ case status
305
+ when "started"
306
+ "active"
307
+ when "failed"
308
+ "danger"
309
+ when "finished"
310
+ "success"
311
+ end
312
+ end
313
+
314
+ def leave_project_message(project)
315
+ "Are you sure you want to leave \"#{project.name}\" project?"
316
+ end
317
+
318
+ def new_readme_path
319
+ ref = @repository.root_ref if @repository
320
+ ref ||= 'master'
321
+
322
+ namespace_project_new_blob_path(@project.namespace, @project, tree_join(ref), file_name: 'README.md')
323
+ end
324
+
325
+ def new_license_path
326
+ ref = @repository.root_ref if @repository
327
+ ref ||= 'master'
328
+
329
+ namespace_project_new_blob_path(@project.namespace, @project, tree_join(ref), file_name: 'LICENSE')
330
+ end
331
+
332
+ def last_push_event
333
+ if current_user
334
+ current_user.recent_push(@project.id)
335
+ end
336
+ end
337
+
338
+ def readme_cache_key
339
+ sha = @project.commit.try(:sha) || 'nil'
340
+ [@project.path_with_namespace, sha, "readme"].join('-')
341
+ end
342
+
343
+ def round_commit_count(project)
344
+ count = project.commit_count
345
+
346
+ if count > 10000
347
+ '10000+'
348
+ elsif count > 5000
349
+ '5000+'
350
+ elsif count > 1000
351
+ '1000+'
352
+ else
353
+ count
354
+ end
355
+ end
356
+
357
+ def current_ref
358
+ @ref || @repository.try(:root_ref)
359
+ end
360
+
361
+ def filename_path(project, filename)
362
+ if project && blob = project.repository.send(filename)
363
+ namespace_project_blob_path(
364
+ project.namespace,
365
+ project,
366
+ tree_join(project.default_branch, blob.name)
367
+ )
368
+ end
369
+ end
370
+
371
+ def sanitize_repo_path(message)
372
+ return '' unless message.present?
373
+
374
+ message.strip.gsub(Gitlab.config.gitlab_shell.repos_path.chomp('/'), "[REPOS PATH]")
375
+ end
376
+ end
377
+ end