From f4e7a8893d71bcbc92a5ecd16c95593f17d1ddf5 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 24 Dec 2015 19:05:57 +0100 Subject: Add builds API (listing, showing trace) --- lib/api/api.rb | 2 ++ lib/api/builds.rb | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/api/entities.rb | 13 +++++++++ 3 files changed, 95 insertions(+) create mode 100644 lib/api/builds.rb diff --git a/lib/api/api.rb b/lib/api/api.rb index 7834262d612..266b5f48f8f 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -54,5 +54,7 @@ module API mount Keys mount Tags mount Triggers + + mount Builds end end diff --git a/lib/api/builds.rb b/lib/api/builds.rb new file mode 100644 index 00000000000..ce4892b5eeb --- /dev/null +++ b/lib/api/builds.rb @@ -0,0 +1,80 @@ +module API + # Projects builds API + class Builds < Grape::API + before { authenticate! } + + resource :projects do + # Get a project repository commits + # + # Parameters: + # id (required) - The ID of a project + # scope (optional) - The scope of builds to show (one of: all, finished, running) + # page (optional) - The page number for pagination (default: 1) + # per_page (ooptional) - The value of items per page to show (default 30) + # Example Request: + # GET /projects/:id/builds/all + get ':id/builds' do + all_builds = user_project.builds + builds = all_builds.order('created_at DESC') + builds = + case params[:scope] + when 'all' + builds + when 'finished' + builds.finished + when 'running' + builds.running + when 'pending' + builds.pending + when 'success' + builds.success + when 'failed' + builds.failed + else + builds.running_or_pending.reverse_order + end + + page = (params[:page] || 1).to_i + per_page = (params[:per_page] || 30).to_i + + present builds.page(page).per(per_page), with: Entities::Build + end + + # Get a specific build of a project + # + # Parameters: + # id (required) - The ID of a project + # build_id (required) - The ID of a build + # Example Request: + # GET /projects/:id/builds/:build_id + get ':id/builds/:build_id' do + present get_build(params[:build_id]), with: Entities::Build + end + + # Get a trace of a specific build of a project + # + # Parameters: + # id (required) - The ID of a project + # build_id (required) - The ID of a build + # Example Request: + # GET /projects/:id/build/:build_id/trace + get ':id/builds/:build_id/trace' do + trace = get_build(params[:build_id]).trace + trace = + unless trace.nil? + trace.split("\n") + else + [] + end + + present trace + end + end + + helpers do + def get_build(id) + user_project.builds.where(id: id).first + end + end + end +end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index f8511ac5f5c..0bf50490eac 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -366,5 +366,18 @@ module API class TriggerRequest < Grape::Entity expose :id, :variables end + + class Build < Grape::Entity + expose :id + expose :status + expose :stage + expose :name + expose :ref + expose :commit + expose :runner + expose :created_at + expose :started_at + expose :finished_at + end end end -- cgit v1.2.1 From b5fef34f1e3beb60e7184cfb3420976bfa367137 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 24 Dec 2015 19:18:01 +0100 Subject: Fix example request url --- lib/api/builds.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/builds.rb b/lib/api/builds.rb index ce4892b5eeb..0ddb9e98de6 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -12,7 +12,7 @@ module API # page (optional) - The page number for pagination (default: 1) # per_page (ooptional) - The value of items per page to show (default 30) # Example Request: - # GET /projects/:id/builds/all + # GET /projects/:id/builds get ':id/builds' do all_builds = user_project.builds builds = all_builds.order('created_at DESC') -- cgit v1.2.1 From f39959d00a1358ba7d73ebeaccb827738c8151ba Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Mon, 28 Dec 2015 13:09:51 +0100 Subject: Add some fixes to builds API --- lib/api/builds.rb | 27 +++++++++------------------ lib/api/entities.rb | 20 ++++++++++++++++++-- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/lib/api/builds.rb b/lib/api/builds.rb index 0ddb9e98de6..863be0d5e40 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -15,23 +15,15 @@ module API # GET /projects/:id/builds get ':id/builds' do all_builds = user_project.builds - builds = all_builds.order('created_at DESC') + builds = all_builds.order('id DESC') builds = case params[:scope] - when 'all' - builds when 'finished' builds.finished when 'running' builds.running - when 'pending' - builds.pending - when 'success' - builds.success - when 'failed' - builds.failed else - builds.running_or_pending.reverse_order + builds end page = (params[:page] || 1).to_i @@ -59,15 +51,14 @@ module API # Example Request: # GET /projects/:id/build/:build_id/trace get ':id/builds/:build_id/trace' do - trace = get_build(params[:build_id]).trace - trace = - unless trace.nil? - trace.split("\n") - else - [] - end + build = get_build(params[:build_id]) + + header 'Content-Disposition', "infile; filename=\"#{build.id}.log\"" + content_type 'text/plain' + env['api.format'] = :binary - present trace + trace = build.trace + body trace end end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 0bf50490eac..76b5d14f202 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -367,14 +367,30 @@ module API expose :id, :variables end + class CiCommit < Grape::Entity + expose :id + expose :ref + expose :sha + expose :committed_at + end + + class CiRunner < Grape::Entity + expose :id + expose :token + expose :description + expose :active + expose :is_shared + expose :name + end + class Build < Grape::Entity expose :id expose :status expose :stage expose :name expose :ref - expose :commit - expose :runner + expose :commit, with: CiCommit + expose :runner, with: CiRunner expose :created_at expose :started_at expose :finished_at -- cgit v1.2.1 From f4cff4dcd0b11d4597efe454731838fbf5803516 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Mon, 28 Dec 2015 13:33:03 +0100 Subject: Modify build pagination to use 'paginate' helper --- lib/api/builds.rb | 5 +---- lib/api/helpers.rb | 6 ++++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/api/builds.rb b/lib/api/builds.rb index 863be0d5e40..f219b0f5241 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -26,10 +26,7 @@ module API builds end - page = (params[:page] || 1).to_i - per_page = (params[:per_page] || 30).to_i - - present builds.page(page).per(per_page), with: Entities::Build + present paginate(builds), with: Entities::Build end # Get a specific build of a project diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index a4df810e755..8fb5cd6ab63 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -97,8 +97,10 @@ module API end def paginate(relation) - per_page = params[:per_page].to_i - paginated = relation.page(params[:page]).per(per_page) + page = (params[:page] || 1).to_i + per_page = (params[:per_page] || 30).to_i + + paginated = relation.page(page).per(per_page) add_pagination_headers(paginated, per_page) paginated -- cgit v1.2.1 From d398e78ea09c1f88800cd4c99f92dd8e5d1d0d39 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Mon, 28 Dec 2015 15:49:13 +0100 Subject: Add endpoint for getting builds for a specific commit --- lib/api/builds.rb | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/lib/api/builds.rb b/lib/api/builds.rb index f219b0f5241..7488863cdcf 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -4,7 +4,7 @@ module API before { authenticate! } resource :projects do - # Get a project repository commits + # Get a project builds # # Parameters: # id (required) - The ID of a project @@ -14,18 +14,21 @@ module API # Example Request: # GET /projects/:id/builds get ':id/builds' do - all_builds = user_project.builds - builds = all_builds.order('id DESC') - builds = - case params[:scope] - when 'finished' - builds.finished - when 'running' - builds.running - else - builds - end + builds = user_project.builds.order('id DESC') + builds = filter_builds(builds, params[:scope]) + present paginate(builds), with: Entities::Build + end + # GET builds for a specific commit of a project + # + # Parameters: + # id (required) - The ID of a project + # sha (required) - The SHA id of a commit + # Example Request: + # GET /projects/:id/builds/commit/:sha + get ':id/builds/commit/:sha' do + builds = user_project.ci_commits.find_by_sha(params[:sha]).builds.order('id DESC') + builds = filter_builds(builds, params[:scope]) present paginate(builds), with: Entities::Build end @@ -63,6 +66,17 @@ module API def get_build(id) user_project.builds.where(id: id).first end + + def filter_builds(builds, scope) + case scope + when 'finished' + builds.finished + when 'running' + builds.running + else + builds + end + end end end end -- cgit v1.2.1 From e7d0746d9319119c459581615ae4205139bee444 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Mon, 28 Dec 2015 16:38:02 +0100 Subject: Add 'not_found' notifications in build/trace details --- lib/api/builds.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/api/builds.rb b/lib/api/builds.rb index 7488863cdcf..5ac24d0367a 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -19,7 +19,7 @@ module API present paginate(builds), with: Entities::Build end - # GET builds for a specific commit of a project + # Get builds for a specific commit of a project # # Parameters: # id (required) - The ID of a project @@ -40,7 +40,10 @@ module API # Example Request: # GET /projects/:id/builds/:build_id get ':id/builds/:build_id' do - present get_build(params[:build_id]), with: Entities::Build + build = get_build(params[:build_id]) + return not_found!(build) unless build + + present build, with: Entities::Build end # Get a trace of a specific build of a project @@ -52,6 +55,7 @@ module API # GET /projects/:id/build/:build_id/trace get ':id/builds/:build_id/trace' do build = get_build(params[:build_id]) + return not_found!(build) unless build header 'Content-Disposition', "infile; filename=\"#{build.id}.log\"" content_type 'text/plain' -- cgit v1.2.1 From 8d4555037a844d21dbf56c2995cff30782af920b Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Mon, 28 Dec 2015 16:38:29 +0100 Subject: Add cancel/retry endpoints to build API --- lib/api/builds.rb | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/lib/api/builds.rb b/lib/api/builds.rb index 5ac24d0367a..16e4549d280 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -64,6 +64,42 @@ module API trace = build.trace body trace end + + # cancel a specific build of a project + # + # parameters: + # id (required) - the id of a project + # build_id (required) - the id of a build + # example request: + # post /projects/:id/build/:build_id/cancel + post ':id/builds/:build_id/cancel' do + authorize_manage_builds! + + build = get_build(params[:build_id]) + return not_found!(build) unless build + + build.cancel + + present build, with: Entities::Build + end + + # cancel a specific build of a project + # + # parameters: + # id (required) - the id of a project + # build_id (required) - the id of a build + # example request: + # post /projects/:id/build/:build_id/retry + post ':id/builds/:build_id/retry' do + authorize_manage_builds! + + build = get_build(params[:build_id]) + return not_found!(build) unless build && build.retryable? + + build = Ci::Build.retry(build) + + present build, with: Entities::Build + end end helpers do @@ -81,6 +117,10 @@ module API builds end end + + def authorize_manage_builds! + authorize! :manage_builds, user_project + end end end end -- cgit v1.2.1 From b2fbeb377d8ba17352d40817b0b444196cb97636 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Mon, 28 Dec 2015 17:01:02 +0100 Subject: Remove changes in 'paginate' helper --- lib/api/helpers.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 8fb5cd6ab63..a4df810e755 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -97,10 +97,8 @@ module API end def paginate(relation) - page = (params[:page] || 1).to_i - per_page = (params[:per_page] || 30).to_i - - paginated = relation.page(page).per(per_page) + per_page = params[:per_page].to_i + paginated = relation.page(params[:page]).per(per_page) add_pagination_headers(paginated, per_page) paginated -- cgit v1.2.1 From 34657b821ae597de76ffd5a70d2b0b298dc270ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Tue, 15 Dec 2015 18:09:09 -0500 Subject: Add syntax highlighting to diff view. #3945 --- app/helpers/application_helper.rb | 6 +++++ app/helpers/blob_helper.rb | 29 +++++++++++++++++++---- app/views/projects/diffs/_parallel_view.html.haml | 8 ++++--- app/views/projects/diffs/_text_file.html.haml | 6 +++-- lib/rouge/lexers/gitlab_diff.rb | 20 ++++++++++++++++ spec/helpers/blob_helper_spec.rb | 11 +++++++++ 6 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 lib/rouge/lexers/gitlab_diff.rb diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 0b00b9a0702..bc4b6ec0327 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -326,4 +326,10 @@ module ApplicationHelper def truncate_first_line(message, length = 50) truncate(message.each_line.first.chomp, length: length) if message end + + def unescape_html(content) + text = CGI.unescapeHTML(content) + text.gsub!(' ', ' ') + text + end end diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index d31d4cde08f..bf18673972c 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -1,11 +1,17 @@ module BlobHelper - def highlight(blob_name, blob_content, nowrap: false, continue: false) - @formatter ||= Rouge::Formatters::HTMLGitlab.new( - nowrap: nowrap, + def rouge_formatter(options = {}) + default_options = { + nowrap: false, cssclass: 'code highlight', lineanchors: true, lineanchorsid: 'LC' - ) + } + + Rouge::Formatters::HTMLGitlab.new(default_options.merge!(options)) + end + + def highlight(blob_name, blob_content, nowrap: false, continue: false) + @formatter ||= rouge_formatter(nowrap: nowrap) begin @lexer ||= Rouge::Lexer.guess(filename: blob_name, source: blob_content).new @@ -18,6 +24,21 @@ module BlobHelper result end + def highlight_line(blob_name, content, continue: false) + if @previous_blob_name != blob_name + @parent = Rouge::Lexer.guess(filename: blob_name, source: content).new rescue Rouge::Lexers::PlainText.new + @lexer = Rouge::Lexers::GitlabDiff.new(parent_lexer: @parent) + @options = Rouge::Lexers::PlainText === @parent ? {} : { continue: continue } + end + + @previous_blob_name = blob_name + @formatter ||= rouge_formatter(nowrap: true) + + content.sub!(/\A((?:\+|-)\s*)/, '') # Don't format '+' or '-' indicators. + + "#{$1}#{@formatter.format(@lexer.lex(content, @options))}".html_safe + end + def no_highlight_files %w(credits changelog news copying copyright license authors) end diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml index 37fd1b1ec8a..c6a9d71e789 100644 --- a/app/views/projects/diffs/_parallel_view.html.haml +++ b/app/views/projects/diffs/_parallel_view.html.haml @@ -1,5 +1,5 @@ / Side-by-side diff view -%div.text-file.diff-wrap-lines +%div.text-file.diff-wrap-lines.code.file-content.js-syntax-highlight{ class: user_color_scheme } %table - parallel_diff(diff_file, index).each do |line| - type_left = line[0] @@ -20,7 +20,8 @@ = link_to raw(line_number_left), "##{line_code_left}", id: line_code_left - if @comments_allowed && can?(current_user, :create_note, @project) = link_to_new_diff_note(line_code_left, 'old') - %td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }= raw line_content_left + %td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }< + = highlight_line(diff_file.new_path, unescape_html(line_content_left)) - if type_right == 'new' - new_line_class = 'new' @@ -33,7 +34,8 @@ = link_to raw(line_number_right), "##{new_line_code}", id: new_line_code - if @comments_allowed && can?(current_user, :create_note, @project) = link_to_new_diff_note(line_code_right, 'new') - %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}= raw line_content_right + %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}< + = highlight_line(diff_file.new_path, unescape_html(line_content_right)) - if @reply_allowed - comments_left, comments_right = organize_comments(type_left, type_right, line_code_left, line_code_right) diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml index 977ca423f75..78c66a6291e 100644 --- a/app/views/projects/diffs/_text_file.html.haml +++ b/app/views/projects/diffs/_text_file.html.haml @@ -3,7 +3,8 @@ .suppressed-container %a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show. -%table.text-file{class: "#{'hide' if too_big}"} +%table.text-file.code.js-syntax-highlight{ class: [user_color_scheme, too_big ? 'hide' : ''] } + - last_line = 0 - diff_file.diff_lines.each_with_index do |line, index| - type = line.type @@ -21,7 +22,8 @@ = link_to_new_diff_note(line_code) %td.new_line{data: {linenumber: line.new_pos}} = link_to raw(type == "old" ? " " : line.new_pos) , "##{line_code}", id: line_code - %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line.text) + %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}< + = highlight_line(diff_file.new_path, unescape_html(diff_line_content(line.text))) - if @reply_allowed - comments = @line_notes.select { |n| n.line_code == line_code && n.active? }.sort_by(&:created_at) diff --git a/lib/rouge/lexers/gitlab_diff.rb b/lib/rouge/lexers/gitlab_diff.rb new file mode 100644 index 00000000000..e136d47df00 --- /dev/null +++ b/lib/rouge/lexers/gitlab_diff.rb @@ -0,0 +1,20 @@ +Rouge::Token::Tokens.token(:InlineDiff, 'idiff') + +module Rouge + module Lexers + class GitlabDiff < RegexLexer + title "GitLab Diff" + tag 'gitlab_diff' + + state :root do + rule %r{(.*?)} do |match| + token InlineDiff, match[1] + end + + rule /(?:(?!puts 'Hello' world) + end + + it 'should respect the inline diff markup' do + result = highlight_line('demo.rb', "puts 'Hello' world") + expect(result).to eq(expected) + end + end end -- cgit v1.2.1 From c031b9d9cd1ea41ab68f46eb5e630efaf901933a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Wed, 23 Dec 2015 19:10:13 -0500 Subject: Set initial state on parent Lexer. #3945 --- lib/rouge/lexers/gitlab_diff.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/rouge/lexers/gitlab_diff.rb b/lib/rouge/lexers/gitlab_diff.rb index e136d47df00..c7aaeb92608 100644 --- a/lib/rouge/lexers/gitlab_diff.rb +++ b/lib/rouge/lexers/gitlab_diff.rb @@ -15,6 +15,10 @@ module Rouge delegate option(:parent_lexer) end end + + start do + option(:parent_lexer).reset! + end end end end -- cgit v1.2.1 From 8e74460534cdb0081ca1ac3e52892a4ebad05fe3 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Tue, 29 Dec 2015 12:53:21 -0500 Subject: adds ajax to bottom discussion buttons. Now submits issue and closes via ajax. --- app/assets/javascripts/issue.js.coffee | 12 +++++++++++- app/assets/javascripts/notes.js.coffee | 16 ++-------------- app/views/projects/issues/_discussion.html.haml | 6 ++---- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee index c256ec8f41b..0d26c58a81d 100644 --- a/app/assets/javascripts/issue.js.coffee +++ b/app/assets/javascripts/issue.js.coffee @@ -16,12 +16,16 @@ class @Issue $(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList initIssueBtnEventListeners: -> + _this = @ issueFailMessage = 'Unable to update this issue at this time.' $('a.btn-close, a.btn-reopen').on 'click', (e) -> e.preventDefault() e.stopImmediatePropagation() $this = $(this) isClose = $this.hasClass('btn-close') + shouldSubmit = $this.hasClass('btn-comment') + if shouldSubmit + _this.submitNoteForm($this.closest('form')) $this.prop('disabled', true) url = $this.attr('href') $.ajax @@ -32,12 +36,13 @@ class @Issue new Flash(issueFailMessage, 'alert') success: (data, textStatus, jqXHR) -> if data.saved - $this.addClass('hidden') if isClose + $('a.btn-close').addClass('hidden') $('a.btn-reopen').removeClass('hidden') $('div.status-box-closed').removeClass('hidden') $('div.status-box-open').addClass('hidden') else + $('a.btn-reopen').addClass('hidden') $('a.btn-close').removeClass('hidden') $('div.status-box-closed').addClass('hidden') $('div.status-box-open').removeClass('hidden') @@ -45,6 +50,11 @@ class @Issue new Flash(issueFailMessage, 'alert') $this.prop('disabled', false) + submitNoteForm: (form) => + noteText = form.find("textarea.js-note-text").val() + if noteText.trim().length > 0 + form.submit() + disableTaskList: -> $('.detail-page-description .js-task-list-container').taskList('disable') $(document).off 'tasklist:changed', '.detail-page-description .js-task-list-container' diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index 9e5204bfeeb..ba0de896201 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -19,6 +19,8 @@ class @Notes @cleanBinding() @addBinding() @initTaskList() + # for updating the comment disscussion buttons once that issue #5534 is approved. + # @updateTargetButtons({target:$("#note_note")}) addBinding: -> # add note to UI after creation @@ -33,8 +35,6 @@ class @Notes $(document).on "click", ".note-edit-cancel", @cancelEdit # Reopen and close actions for Issue/MR combined with note form submit - $(document).on "click", ".js-note-target-reopen", @targetReopen - $(document).on "click", ".js-note-target-close", @targetClose $(document).on "click", ".js-comment-button", @updateCloseButton $(document).on "keyup", ".js-note-text", @updateTargetButtons @@ -512,17 +512,6 @@ class @Notes visibilityChange: => @refresh() - targetReopen: (e) => - @submitNoteForm($(e.target).parents('form')) - - targetClose: (e) => - @submitNoteForm($(e.target).parents('form')) - - submitNoteForm: (form) => - noteText = form.find(".js-note-text").val() - if noteText.trim().length > 0 - form.submit() - updateCloseButton: (e) => textarea = $(e.target) form = textarea.parents('form') @@ -531,7 +520,6 @@ class @Notes updateTargetButtons: (e) => textarea = $(e.target) form = textarea.parents('form') - if textarea.val().trim().length > 0 form.find('.js-note-target-reopen').text('Comment & reopen') form.find('.js-note-target-close').text('Comment & close') diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml index dc434cf38c4..673020a4e30 100644 --- a/app/views/projects/issues/_discussion.html.haml +++ b/app/views/projects/issues/_discussion.html.haml @@ -1,9 +1,7 @@ - content_for :note_actions do - if can?(current_user, :update_issue, @issue) - - if @issue.closed? - = link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-reopen js-note-target-reopen', title: 'Reopen Issue' - - else - = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-close js-note-target-close', title: 'Close Issue' + = link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-reopen btn-comment js-note-target-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen Issue' + = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-close btn-comment js-note-target-close #{issue_button_visibility(@issue, true)}", title: 'Close Issue' #notes = render 'projects/notes/notes_with_form' -- cgit v1.2.1 From d2601211a0c7a44666501dea82a8488b08f8faa7 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Tue, 29 Dec 2015 23:12:36 +0100 Subject: Add specs for build listings in API --- lib/api/builds.rb | 9 ++++--- spec/requests/api/builds_spec.rb | 52 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 spec/requests/api/builds_spec.rb diff --git a/lib/api/builds.rb b/lib/api/builds.rb index 16e4549d280..a519224d2b8 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -27,7 +27,10 @@ module API # Example Request: # GET /projects/:id/builds/commit/:sha get ':id/builds/commit/:sha' do - builds = user_project.ci_commits.find_by_sha(params[:sha]).builds.order('id DESC') + commit = user_project.ci_commits.find_by_sha(params[:sha]) + return not_found! unless commit + + builds = commit.builds.order('id DESC') builds = filter_builds(builds, params[:scope]) present paginate(builds), with: Entities::Build end @@ -65,7 +68,7 @@ module API body trace end - # cancel a specific build of a project + # Cancel a specific build of a project # # parameters: # id (required) - the id of a project @@ -83,7 +86,7 @@ module API present build, with: Entities::Build end - # cancel a specific build of a project + # Retry a specific build of a project # # parameters: # id (required) - the id of a project diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb new file mode 100644 index 00000000000..81c176c9fb0 --- /dev/null +++ b/spec/requests/api/builds_spec.rb @@ -0,0 +1,52 @@ +require 'spec_helper' + +describe API::API, api: true do + include ApiHelpers + + let(:user) { create(:user) } + let(:user2) { create(:user) } + let!(:project) { create(:project, creator_id: user.id) } + let!(:master) { create(:project_member, user: user, project: project, access_level: ProjectMember::MASTER) } + let!(:guest) { create(:project_member, user: user2, project: project, access_level: ProjectMember::GUEST) } + + describe 'GET /projects/:id/builds ' do + context 'authorized user' do + it 'should return project builds' do + get api("/projects/#{project.id}/builds", user) + + puts json_response + expect(response.status).to eq(200) + expect(json_response).to be_an Array + end + end + + context 'unauthorized user' do + it 'should not return project builds' do + get api("/projects/#{project.id}/builds") + + expect(response.status).to eq(401) + end + end + end + + describe 'GET /projects/:id/builds/commit/:sha' do + context 'authorized user' do + it 'should return project builds for specific commit' do + project.ensure_ci_commit(project.repository.commit.sha) + get api("/projects/#{project.id}/builds/commit/#{project.ci_commits.first.sha}", user) + + expect(response.status).to eq(200) + expect(json_response).to be_an Array + end + end + + context 'unauthorized user' do + it 'should not return project builds' do + project.ensure_ci_commit(project.repository.commit.sha) + get api("/projects/#{project.id}/builds/commit/#{project.ci_commits.first.sha}") + + expect(response.status).to eq(401) + end + end + end +end -- cgit v1.2.1 From bb96d631537d3d8181f0d3b762603a012219c3e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Wed, 30 Dec 2015 00:52:50 -0500 Subject: New implementation for highlighting diff files. #3945 * It is more performant given now we process all the diff file instead of processing line by line. * Multiline comments are highlighted correctly. --- app/helpers/application_helper.rb | 6 --- app/helpers/blob_helper.rb | 15 ------- app/helpers/diff_helper.rb | 6 +-- app/views/projects/diffs/_parallel_view.html.haml | 6 +-- app/views/projects/diffs/_text_file.html.haml | 5 +-- lib/gitlab/diff/file.rb | 4 ++ lib/gitlab/diff/highlight.rb | 55 +++++++++++++++++++++++ lib/gitlab/diff/line.rb | 1 + lib/rouge/lexers/gitlab_diff.rb | 2 +- spec/helpers/blob_helper_spec.rb | 11 ----- 10 files changed, 68 insertions(+), 43 deletions(-) create mode 100644 lib/gitlab/diff/highlight.rb diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index bc4b6ec0327..0b00b9a0702 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -326,10 +326,4 @@ module ApplicationHelper def truncate_first_line(message, length = 50) truncate(message.each_line.first.chomp, length: length) if message end - - def unescape_html(content) - text = CGI.unescapeHTML(content) - text.gsub!(' ', ' ') - text - end end diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index bf18673972c..1230002e69c 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -24,21 +24,6 @@ module BlobHelper result end - def highlight_line(blob_name, content, continue: false) - if @previous_blob_name != blob_name - @parent = Rouge::Lexer.guess(filename: blob_name, source: content).new rescue Rouge::Lexers::PlainText.new - @lexer = Rouge::Lexers::GitlabDiff.new(parent_lexer: @parent) - @options = Rouge::Lexers::PlainText === @parent ? {} : { continue: continue } - end - - @previous_blob_name = blob_name - @formatter ||= rouge_formatter(nowrap: true) - - content.sub!(/\A((?:\+|-)\s*)/, '') # Don't format '+' or '-' indicators. - - "#{$1}#{@formatter.format(@lexer.lex(content, @options))}".html_safe - end - def no_highlight_files %w(credits changelog news copying copyright license authors) end diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 24134310fc5..2ff8c65e5ca 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -54,9 +54,9 @@ module DiffHelper # right_line_type, right_line_number, right_line_content, right_line_code # ] # - diff_file.diff_lines.each do |line| + diff_file.highlighted_diff_lines.each do |line| - full_line = line.text + full_line = line.highlighted_text type = line.type line_code = generate_line_code(diff_file.file_path, line) line_new = line.new_pos @@ -67,7 +67,7 @@ module DiffHelper if next_line next_line_code = generate_line_code(diff_file.file_path, next_line) next_type = next_line.type - next_line = next_line.text + next_line = next_line.highlighted_text end if type == 'match' || type.nil? diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml index c6a9d71e789..4ded4d2daad 100644 --- a/app/views/projects/diffs/_parallel_view.html.haml +++ b/app/views/projects/diffs/_parallel_view.html.haml @@ -20,8 +20,7 @@ = link_to raw(line_number_left), "##{line_code_left}", id: line_code_left - if @comments_allowed && can?(current_user, :create_note, @project) = link_to_new_diff_note(line_code_left, 'old') - %td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }< - = highlight_line(diff_file.new_path, unescape_html(line_content_left)) + %td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }= raw(line_content_left) - if type_right == 'new' - new_line_class = 'new' @@ -34,8 +33,7 @@ = link_to raw(line_number_right), "##{new_line_code}", id: new_line_code - if @comments_allowed && can?(current_user, :create_note, @project) = link_to_new_diff_note(line_code_right, 'new') - %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}< - = highlight_line(diff_file.new_path, unescape_html(line_content_right)) + %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}= raw(line_content_right) - if @reply_allowed - comments_left, comments_right = organize_comments(type_left, type_right, line_code_left, line_code_right) diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml index 78c66a6291e..641e9e5501a 100644 --- a/app/views/projects/diffs/_text_file.html.haml +++ b/app/views/projects/diffs/_text_file.html.haml @@ -6,7 +6,7 @@ %table.text-file.code.js-syntax-highlight{ class: [user_color_scheme, too_big ? 'hide' : ''] } - last_line = 0 - - diff_file.diff_lines.each_with_index do |line, index| + - diff_file.highlighted_diff_lines.each_with_index do |line, index| - type = line.type - last_line = line.new_pos - line_code = generate_line_code(diff_file.file_path, line) @@ -22,8 +22,7 @@ = link_to_new_diff_note(line_code) %td.new_line{data: {linenumber: line.new_pos}} = link_to raw(type == "old" ? " " : line.new_pos) , "##{line_code}", id: line_code - %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}< - = highlight_line(diff_file.new_path, unescape_html(diff_line_content(line.text))) + %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw(diff_line_content(line.highlighted_text)) - if @reply_allowed - comments = @line_notes.select { |n| n.line_code == line_code && n.active? }.sort_by(&:created_at) diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index 79061cd0141..ff8765b8e26 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -15,6 +15,10 @@ module Gitlab @lines ||= parser.parse(raw_diff.lines) end + def highlighted_diff_lines + Gitlab::Diff::Highlight.process_diff_lines(self) + end + def mode_changed? !!(diff.a_mode && diff.b_mode && diff.a_mode != diff.b_mode) end diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb new file mode 100644 index 00000000000..f10b55eb00b --- /dev/null +++ b/lib/gitlab/diff/highlight.rb @@ -0,0 +1,55 @@ +module Gitlab + module Diff + class Highlight + def self.process_diff_lines(diff_file) + processor = new(diff_file) + processor.highlight + end + + def initialize(diff_file) + text_lines = diff_file.diff_lines.map(&:text) + @diff_file = diff_file + @diff_lines = diff_file.diff_lines + @diff_line_prefixes = text_lines.map { |line| line.sub!(/\A((\+|\-)\s*)/, '');$1 } + @raw_lines = text_lines.join("\n") + end + + def highlight + @code = unescape_html(@raw_lines) + @highlighted_code = formatter.format(lexer.lex(@code)) + + update_diff_lines + end + + private + + def update_diff_lines + @highlighted_code.lines.each_with_index do |line, i| + @diff_lines[i].highlighted_text = "#{@diff_line_prefixes[i]}#{line}" + end + + @diff_lines + end + + def lexer + parent = Rouge::Lexer.guess(filename: @diff_file.new_path, source: @code).new rescue Rouge::Lexers::PlainText.new + Rouge::Lexers::GitlabDiff.new(parent_lexer: parent) + end + + def unescape_html(content) + text = CGI.unescapeHTML(content) + text.gsub!(' ', ' ') + text + end + + def formatter + @formatter ||= Rouge::Formatters::HTMLGitlab.new( + nowrap: true, + cssclass: 'code highlight', + lineanchors: true, + lineanchorsid: 'LC' + ) + end + end + end +end diff --git a/lib/gitlab/diff/line.rb b/lib/gitlab/diff/line.rb index 0072194606e..c48c69fb344 100644 --- a/lib/gitlab/diff/line.rb +++ b/lib/gitlab/diff/line.rb @@ -2,6 +2,7 @@ module Gitlab module Diff class Line attr_reader :type, :text, :index, :old_pos, :new_pos + attr_accessor :highlighted_text def initialize(text, type, index, old_pos, new_pos) @text, @type, @index = text, type, index diff --git a/lib/rouge/lexers/gitlab_diff.rb b/lib/rouge/lexers/gitlab_diff.rb index c7aaeb92608..d91dd6c4245 100644 --- a/lib/rouge/lexers/gitlab_diff.rb +++ b/lib/rouge/lexers/gitlab_diff.rb @@ -11,7 +11,7 @@ module Rouge token InlineDiff, match[1] end - rule /(?:(?!puts 'Hello' world) - end - - it 'should respect the inline diff markup' do - result = highlight_line('demo.rb', "puts 'Hello' world") - expect(result).to eq(expected) - end - end end -- cgit v1.2.1 From 5a997a02a2cd71877d2af7b72fb67e86722882b2 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Wed, 30 Dec 2015 06:29:56 -0500 Subject: removes commented out code. --- app/assets/javascripts/notes.js.coffee | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index ba0de896201..8ba00ecbbab 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -19,8 +19,6 @@ class @Notes @cleanBinding() @addBinding() @initTaskList() - # for updating the comment disscussion buttons once that issue #5534 is approved. - # @updateTargetButtons({target:$("#note_note")}) addBinding: -> # add note to UI after creation -- cgit v1.2.1 From 593d87ea54eec4d60cf7eeb404af82d9e015b066 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Wed, 30 Dec 2015 15:12:07 +0100 Subject: Add specs for build details/traces features in builds API --- spec/factories/ci/builds.rb | 6 ++++++ spec/requests/api/builds_spec.rb | 40 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index f76e826f138..4551ee57d78 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -30,6 +30,7 @@ FactoryGirl.define do name 'test' ref 'master' tag false + created_at 'Di 29. Okt 09:50:00 CET 2013' started_at 'Di 29. Okt 09:51:28 CET 2013' finished_at 'Di 29. Okt 09:53:28 CET 2013' commands 'ls -a' @@ -54,5 +55,10 @@ FactoryGirl.define do factory :ci_build_tag do tag true end + + factory :ci_build_with_trace do + id 999 + trace 'BUILD TRACE' + end end end diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb index 81c176c9fb0..c68ea0898b8 100644 --- a/spec/requests/api/builds_spec.rb +++ b/spec/requests/api/builds_spec.rb @@ -8,6 +8,9 @@ describe API::API, api: true do let!(:project) { create(:project, creator_id: user.id) } let!(:master) { create(:project_member, user: user, project: project, access_level: ProjectMember::MASTER) } let!(:guest) { create(:project_member, user: user2, project: project, access_level: ProjectMember::GUEST) } + let(:commit) { create(:ci_commit, project: project)} + let(:build) { create(:ci_build, commit: commit) } + let(:build_with_trace) { create(:ci_build_with_trace, commit: commit) } describe 'GET /projects/:id/builds ' do context 'authorized user' do @@ -32,7 +35,7 @@ describe API::API, api: true do describe 'GET /projects/:id/builds/commit/:sha' do context 'authorized user' do it 'should return project builds for specific commit' do - project.ensure_ci_commit(project.repository.commit.sha) + project.ensure_ci_commit(commit.sha) get api("/projects/#{project.id}/builds/commit/#{project.ci_commits.first.sha}", user) expect(response.status).to eq(200) @@ -42,11 +45,44 @@ describe API::API, api: true do context 'unauthorized user' do it 'should not return project builds' do - project.ensure_ci_commit(project.repository.commit.sha) + project.ensure_ci_commit(commit.sha) get api("/projects/#{project.id}/builds/commit/#{project.ci_commits.first.sha}") expect(response.status).to eq(401) end end end + + describe 'GET /projects/:id/builds/:build_id(/trace)?' do + context 'authorized user' do + it 'should return specific build data' do + get api("/projects/#{project.id}/builds/#{build.id}", user) + + expect(response.status).to eq(200) + expect(json_response['name']).to eq('test') + expect(json_response['commit']['sha']).to eq(commit.sha) + end + + it 'should return specific build trace' do + get api("/projects/#{project.id}/builds/#{build_with_trace.id}/trace", user) + + expect(response.status).to eq(200) + expect(response.body).to eq(build_with_trace.trace) + end + end + + context 'unauthorized user' do + it 'should not return specific build data' do + get api("/projects/#{project.id}/builds/#{build.id}") + + expect(response.status).to eq(401) + end + + it 'should not return specific build trace' do + get api("/projects/#{project.id}/builds/#{build_with_trace.id}/trace") + + expect(response.status).to eq(401) + end + end + end end -- cgit v1.2.1 From a17bf380cb4c90696349f268ca4a8c2fedc1f545 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Wed, 30 Dec 2015 16:37:47 +0100 Subject: Add cancel/retry features to builds API --- spec/factories/ci/builds.rb | 4 +++ spec/requests/api/builds_spec.rb | 62 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index 4551ee57d78..ce68457f86b 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -60,5 +60,9 @@ FactoryGirl.define do id 999 trace 'BUILD TRACE' end + + factory :ci_build_canceled do + status 'canceled' + end end end diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb index c68ea0898b8..d4af7639d4b 100644 --- a/spec/requests/api/builds_spec.rb +++ b/spec/requests/api/builds_spec.rb @@ -7,10 +7,11 @@ describe API::API, api: true do let(:user2) { create(:user) } let!(:project) { create(:project, creator_id: user.id) } let!(:master) { create(:project_member, user: user, project: project, access_level: ProjectMember::MASTER) } - let!(:guest) { create(:project_member, user: user2, project: project, access_level: ProjectMember::GUEST) } + let!(:reporter) { create(:project_member, user: user2, project: project, access_level: ProjectMember::REPORTER) } let(:commit) { create(:ci_commit, project: project)} let(:build) { create(:ci_build, commit: commit) } let(:build_with_trace) { create(:ci_build_with_trace, commit: commit) } + let(:build_canceled) { create(:ci_build_canceled, commit: commit) } describe 'GET /projects/:id/builds ' do context 'authorized user' do @@ -85,4 +86,63 @@ describe API::API, api: true do end end end + + describe 'GET /projects/:id/builds/:build_id/cancel' do + context 'authorized user' do + context 'user with :manage_builds persmission' do + it 'should cancel running or pending build' do + post api("/projects/#{project.id}/builds/#{build.id}/cancel", user) + + expect(response.status).to eq(201) + expect(project.builds.first.status).to eq('canceled') + end + end + + context 'user without :manage_builds permission' do + it 'should not cancel build' do + post api("/projects/#{project.id}/builds/#{build.id}/cancel", user2) + + expect(response.status).to eq(403) + end + end + end + + context 'unauthorized user' do + it 'should not cancel build' do + post api("/projects/#{project.id}/builds/#{build.id}/cancel") + + expect(response.status).to eq(401) + end + end + end + + describe 'GET /projects/:id/builds/:build_id/retry' do + context 'authorized user' do + context 'user with :manage_builds persmission' do + it 'should retry non-running build' do + post api("/projects/#{project.id}/builds/#{build_canceled.id}/retry", user) + + expect(response.status).to eq(201) + expect(project.builds.first.status).to eq('canceled') + expect(json_response['status']).to eq('pending') + end + end + + context 'user without :manage_builds permission' do + it 'should not retry build' do + post api("/projects/#{project.id}/builds/#{build_canceled.id}/retry", user2) + + expect(response.status).to eq(403) + end + end + end + + context 'unauthorized user' do + it 'should not retry build' do + post api("/projects/#{project.id}/builds/#{build_canceled.id}/retry") + + expect(response.status).to eq(401) + end + end + end end -- cgit v1.2.1 From b74f36c9caae38a1d62c18281d8240ec5905c5d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Wed, 30 Dec 2015 13:10:28 -0500 Subject: Fix Rubocop complain. #3945 --- lib/gitlab/diff/highlight.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb index f10b55eb00b..adb437abed2 100644 --- a/lib/gitlab/diff/highlight.rb +++ b/lib/gitlab/diff/highlight.rb @@ -44,11 +44,11 @@ module Gitlab def formatter @formatter ||= Rouge::Formatters::HTMLGitlab.new( - nowrap: true, - cssclass: 'code highlight', - lineanchors: true, - lineanchorsid: 'LC' - ) + nowrap: true, + cssclass: 'code highlight', + lineanchors: true, + lineanchorsid: 'LC' + ) end end end -- cgit v1.2.1 From 7de90f4b53f865dc417d022a9133372e57274549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Wed, 30 Dec 2015 18:42:11 -0500 Subject: Fix broken spec and small refactor. #3945 --- app/helpers/diff_helper.rb | 4 +- app/views/projects/diffs/_text_file.html.haml | 2 +- lib/gitlab/diff/highlight.rb | 2 +- lib/gitlab/diff/line.rb | 4 +- spec/fixtures/parallel_diff_result.yml | 274 ++++++++++++++++++++++++++ spec/helpers/diff_helper_spec.rb | 30 +-- 6 files changed, 281 insertions(+), 35 deletions(-) create mode 100644 spec/fixtures/parallel_diff_result.yml diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 2ff8c65e5ca..22deb69cec5 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -56,7 +56,7 @@ module DiffHelper # diff_file.highlighted_diff_lines.each do |line| - full_line = line.highlighted_text + full_line = line.text type = line.type line_code = generate_line_code(diff_file.file_path, line) line_new = line.new_pos @@ -67,7 +67,7 @@ module DiffHelper if next_line next_line_code = generate_line_code(diff_file.file_path, next_line) next_type = next_line.type - next_line = next_line.highlighted_text + next_line = next_line.text end if type == 'match' || type.nil? diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml index 641e9e5501a..059d0baf45e 100644 --- a/app/views/projects/diffs/_text_file.html.haml +++ b/app/views/projects/diffs/_text_file.html.haml @@ -22,7 +22,7 @@ = link_to_new_diff_note(line_code) %td.new_line{data: {linenumber: line.new_pos}} = link_to raw(type == "old" ? " " : line.new_pos) , "##{line_code}", id: line_code - %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw(diff_line_content(line.highlighted_text)) + %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw(diff_line_content(line.text)) - if @reply_allowed - comments = @line_notes.select { |n| n.line_code == line_code && n.active? }.sort_by(&:created_at) diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb index adb437abed2..d0c2e3670c6 100644 --- a/lib/gitlab/diff/highlight.rb +++ b/lib/gitlab/diff/highlight.rb @@ -25,7 +25,7 @@ module Gitlab def update_diff_lines @highlighted_code.lines.each_with_index do |line, i| - @diff_lines[i].highlighted_text = "#{@diff_line_prefixes[i]}#{line}" + @diff_lines[i].text = "#{@diff_line_prefixes[i]}#{line}" end @diff_lines diff --git a/lib/gitlab/diff/line.rb b/lib/gitlab/diff/line.rb index c48c69fb344..03730b435ad 100644 --- a/lib/gitlab/diff/line.rb +++ b/lib/gitlab/diff/line.rb @@ -1,8 +1,8 @@ module Gitlab module Diff class Line - attr_reader :type, :text, :index, :old_pos, :new_pos - attr_accessor :highlighted_text + attr_reader :type, :index, :old_pos, :new_pos + attr_accessor :text def initialize(text, type, index, old_pos, new_pos) @text, @type, @index = text, type, index diff --git a/spec/fixtures/parallel_diff_result.yml b/spec/fixtures/parallel_diff_result.yml new file mode 100644 index 00000000000..abbb364f61f --- /dev/null +++ b/spec/fixtures/parallel_diff_result.yml @@ -0,0 +1,274 @@ +--- +- - match + - 6 + - | + @@ -6,12 +6,18 @@ module Popen + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6 + - match + - 6 + - | + @@ -6,12 +6,18 @@ module Popen + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6 +- - + - 6 + - | + + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6 + - + - 6 + - | + + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6 +- - + - 7 + - | + def popen(cmd, path=nil) + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7 + - + - 7 + - | + def popen(cmd, path=nil) + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7 +- - + - 8 + - | + unless cmd.is_a?(Array) + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8 + - + - 8 + - | + unless cmd.is_a?(Array) + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8 +- - old + - 9 + - | + - raise "System commands must be given as an array of strings" + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9 + - new + - 9 + - | + + raise RuntimeError, "System commands must be given as an array of strings" + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9 +- - + - 10 + - | + end + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10 + - + - 10 + - | + end + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10 +- - + - 11 + - | + + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_11_11 + - + - 11 + - | + + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_11_11 +- - + - 12 + - | + path ||= Dir.pwd + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_12_12 + - + - 12 + - | + path ||= Dir.pwd + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_12_12 +- - old + - 13 + - | + - vars = { "PWD" => path } + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_13_13 + - old + - + - " " + - +- - old + - 14 + - | + - options = { chdir: path } + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_13 + - new + - 13 + - | + + + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_13 +- - + - + - " " + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14 + - new + - 14 + - | + + vars = { + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14 +- - + - + - " " + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15 + - new + - 15 + - | + + "PWD" => path + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15 +- - + - + - " " + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_16 + - new + - 16 + - | + + } + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_16 +- - + - + - " " + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_17 + - new + - 17 + - | + + + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_17 +- - + - + - " " + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_18 + - new + - 18 + - | + + options = { + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_18 +- - + - + - " " + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_19 + - new + - 19 + - | + + chdir: path + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_19 +- - + - + - " " + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_20 + - new + - 20 + - | + + } + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_20 +- - + - 15 + - | + + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_21 + - + - 21 + - | + + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_21 +- - + - 16 + - | + unless File.directory?(path) + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_16_22 + - + - 22 + - | + unless File.directory?(path) + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_16_22 +- - + - 17 + - | + FileUtils.mkdir_p(path) + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23 + - + - 23 + - | + FileUtils.mkdir_p(path) + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23 +- - match + - 19 + - | + @@ -19,6 +25,7 @@ module Popen + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25 + - match + - 25 + - | + @@ -19,6 +25,7 @@ module Popen + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25 +- - + - 19 + - | + + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25 + - + - 25 + - | + + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25 +- - + - 20 + - | + @cmd_output = "" + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26 + - + - 26 + - | + @cmd_output = "" + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26 +- - + - 21 + - | + @cmd_status = 0 + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_21_27 + - + - 27 + - | + @cmd_status = 0 + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_21_27 +- - + - + - " " + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_28 + - new + - 28 + - | + + + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_28 +- - + - 22 + - | + Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_29 + - + - 29 + - | + Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_29 +- - + - 23 + - | + @cmd_output << stdout.read + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_23_30 + - + - 30 + - | + @cmd_output << stdout.read + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_23_30 +- - + - 24 + - @cmd_output << stderr.read + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_24_31 + - + - 31 + - @cmd_output << stderr.read + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_24_31 diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb index 7c96a74e581..0501c2e8c29 100644 --- a/spec/helpers/diff_helper_spec.rb +++ b/spec/helpers/diff_helper_spec.rb @@ -131,34 +131,6 @@ describe DiffHelper do end def parallel_diff_result_array - [ - ["match", 6, "@@ -6,12 +6,18 @@ module Popen", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6", "match", 6, "@@ -6,12 +6,18 @@ module Popen", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6"], - [nil, 6, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6", nil, 6, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6"], [nil, 7, " def popen(cmd, path=nil)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7", nil, 7, " def popen(cmd, path=nil)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"], - [nil, 8, " unless cmd.is_a?(Array)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8", nil, 8, " unless cmd.is_a?(Array)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8"], - ["old", 9, "- raise "System commands must be given as an array of strings"", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9", "new", 9, "+ raise RuntimeError, "System commands must be given as an array of strings"", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"], - [nil, 10, " end", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10", nil, 10, " end", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10"], - [nil, 11, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_11_11", nil, 11, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_11_11"], - [nil, 12, " path ||= Dir.pwd", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_12_12", nil, 12, " path ||= Dir.pwd", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_12_12"], - ["old", 13, "- vars = { "PWD" => path }", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_13_13", "old", nil, " ", nil], - ["old", 14, "- options = { chdir: path }", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_13", "new", 13, "+", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_13"], - [nil, nil, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14", "new", 14, "+ vars = {", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14"], - [nil, nil, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15", "new", 15, "+ "PWD" => path", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15"], - [nil, nil, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_16", "new", 16, "+ }", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_16"], - [nil, nil, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_17", "new", 17, "+", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_17"], - [nil, nil, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_18", "new", 18, "+ options = {", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_18"], - [nil, nil, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_19", "new", 19, "+ chdir: path", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_19"], - [nil, nil, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_20", "new", 20, "+ }", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_20"], - [nil, 15, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_21", nil, 21, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_21"], - [nil, 16, " unless File.directory?(path)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_16_22", nil, 22, " unless File.directory?(path)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_16_22"], - [nil, 17, " FileUtils.mkdir_p(path)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23", nil, 23, " FileUtils.mkdir_p(path)", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23"], - ["match", 19, "@@ -19,6 +25,7 @@ module Popen", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25", "match", 25, "@@ -19,6 +25,7 @@ module Popen", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25"], - [nil, 19, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25", nil, 25, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25"], - [nil, 20, " @cmd_output = """, "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26", nil, 26, " @cmd_output = """, "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26"], - [nil, 21, " @cmd_status = 0", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_21_27", nil, 27, " @cmd_status = 0", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_21_27"], - [nil, nil, " ", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_28", "new", 28, "+", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_28"], - [nil, 22, " Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_29", nil, 29, " Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_29"], - [nil, 23, " @cmd_output << stdout.read", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_23_30", nil, 30, " @cmd_output << stdout.read", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_23_30"], - [nil, 24, " @cmd_output << stderr.read", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_24_31", nil, 31, " @cmd_output << stderr.read", "2f6fcd96b88b36ce98c38da085c795a27d92a3dd_24_31"] - ] + YAML.load_file("#{Rails.root}/spec/fixtures/parallel_diff_result.yml") end end -- cgit v1.2.1 From d83275620a0eeaf17a2958e59e2b4d6f217c6464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Wed, 30 Dec 2015 20:18:40 -0500 Subject: Add specs for Gitlab::Diff::Highlight. #3945 --- spec/lib/gitlab/diff/highlight_spec.rb | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 spec/lib/gitlab/diff/highlight_spec.rb diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb new file mode 100644 index 00000000000..2a827a08dba --- /dev/null +++ b/spec/lib/gitlab/diff/highlight_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe Gitlab::Diff::Highlight, lib: true do + include RepoHelpers + + let(:project) { create(:project) } + let(:commit) { project.commit(sample_commit.id) } + let(:diff) { commit.diffs.first } + let(:diff_file) { Gitlab::Diff::File.new(diff) } + + describe '.process_diff_lines' do + let(:diff_lines) { Gitlab::Diff::Highlight.process_diff_lines(diff_file) } + + it 'should return Gitlab::Diff::Line elements' do + expect(diff_lines.first).to be_an_instance_of(Gitlab::Diff::Line) + end + + it 'should highlight the code' do + code = %Q{ def popen(cmd, path=nil)\n} + + expect(diff_lines[2].text).to eq(code) + end + + it 'should keep the inline diff markup' do + expect(diff_lines[5].text).to match(Regexp.new(Regexp.escape('RuntimeError, '))) + end + end +end -- cgit v1.2.1 From 8b079315d98a8ccf852592148632c6f052d9cb55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Wed, 30 Dec 2015 21:23:50 -0500 Subject: A bit of refactoring. #3945 --- lib/gitlab/diff/file.rb | 2 +- lib/gitlab/diff/highlight.rb | 16 ++++++++-------- lib/rouge/lexers/gitlab_diff.rb | 2 ++ spec/lib/gitlab/diff/highlight_spec.rb | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index ff8765b8e26..69b38a32eeb 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -16,7 +16,7 @@ module Gitlab end def highlighted_diff_lines - Gitlab::Diff::Highlight.process_diff_lines(self) + Gitlab::Diff::Highlight.process_diff_lines(new_path, diff_lines) end def mode_changed? diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb index d0c2e3670c6..40a54ede2bb 100644 --- a/lib/gitlab/diff/highlight.rb +++ b/lib/gitlab/diff/highlight.rb @@ -1,15 +1,15 @@ module Gitlab module Diff class Highlight - def self.process_diff_lines(diff_file) - processor = new(diff_file) + def self.process_diff_lines(file_name, diff_lines) + processor = new(file_name, diff_lines) processor.highlight end - def initialize(diff_file) - text_lines = diff_file.diff_lines.map(&:text) - @diff_file = diff_file - @diff_lines = diff_file.diff_lines + def initialize(file_name, diff_lines) + text_lines = diff_lines.map(&:text) + @file_name = file_name + @diff_lines = diff_lines @diff_line_prefixes = text_lines.map { |line| line.sub!(/\A((\+|\-)\s*)/, '');$1 } @raw_lines = text_lines.join("\n") end @@ -32,7 +32,7 @@ module Gitlab end def lexer - parent = Rouge::Lexer.guess(filename: @diff_file.new_path, source: @code).new rescue Rouge::Lexers::PlainText.new + parent = Rouge::Lexer.guess(filename: @file_name, source: @code).new rescue Rouge::Lexers::PlainText.new Rouge::Lexers::GitlabDiff.new(parent_lexer: parent) end @@ -43,7 +43,7 @@ module Gitlab end def formatter - @formatter ||= Rouge::Formatters::HTMLGitlab.new( + Rouge::Formatters::HTMLGitlab.new( nowrap: true, cssclass: 'code highlight', lineanchors: true, diff --git a/lib/rouge/lexers/gitlab_diff.rb b/lib/rouge/lexers/gitlab_diff.rb index d91dd6c4245..cbf272ee1de 100644 --- a/lib/rouge/lexers/gitlab_diff.rb +++ b/lib/rouge/lexers/gitlab_diff.rb @@ -2,6 +2,8 @@ Rouge::Token::Tokens.token(:InlineDiff, 'idiff') module Rouge module Lexers + # This new Lexer is required in order to avoid the inline diff markup + # to be tokenized, it will be rendered as raw HTML code if that happens. class GitlabDiff < RegexLexer title "GitLab Diff" tag 'gitlab_diff' diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb index 2a827a08dba..80083c15cff 100644 --- a/spec/lib/gitlab/diff/highlight_spec.rb +++ b/spec/lib/gitlab/diff/highlight_spec.rb @@ -9,7 +9,7 @@ describe Gitlab::Diff::Highlight, lib: true do let(:diff_file) { Gitlab::Diff::File.new(diff) } describe '.process_diff_lines' do - let(:diff_lines) { Gitlab::Diff::Highlight.process_diff_lines(diff_file) } + let(:diff_lines) { Gitlab::Diff::Highlight.process_diff_lines(diff_file.new_path, diff_file.diff_lines) } it 'should return Gitlab::Diff::Line elements' do expect(diff_lines.first).to be_an_instance_of(Gitlab::Diff::Line) -- cgit v1.2.1 From fd100e1ef1726418c81ab8833cf8bcf86fab6eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Wed, 30 Dec 2015 21:44:12 -0500 Subject: Don't modify "match" diff lines. #3945 --- lib/gitlab/diff/highlight.rb | 7 ++++++- spec/lib/gitlab/diff/highlight_spec.rb | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb index 40a54ede2bb..c780ea21775 100644 --- a/lib/gitlab/diff/highlight.rb +++ b/lib/gitlab/diff/highlight.rb @@ -25,7 +25,12 @@ module Gitlab def update_diff_lines @highlighted_code.lines.each_with_index do |line, i| - @diff_lines[i].text = "#{@diff_line_prefixes[i]}#{line}" + diff_line = @diff_lines[i] + + # ignore highlighting for "match" lines + next if diff_line.type == 'match' + + diff_line.text = "#{@diff_line_prefixes[i]}#{line}" end @diff_lines diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb index 80083c15cff..54621f773d7 100644 --- a/spec/lib/gitlab/diff/highlight_spec.rb +++ b/spec/lib/gitlab/diff/highlight_spec.rb @@ -24,5 +24,10 @@ describe Gitlab::Diff::Highlight, lib: true do it 'should keep the inline diff markup' do expect(diff_lines[5].text).to match(Regexp.new(Regexp.escape('RuntimeError, '))) end + + it 'should not modify "match" lines' do + expect(diff_lines[0].text).to eq('@@ -6,12 +6,18 @@ module Popen') + expect(diff_lines[22].text).to eq('@@ -19,6 +25,7 @@ module Popen') + end end end -- cgit v1.2.1 From 3fbcf52ec8decc3a4e331d52b2f47d7b85d399cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Thu, 31 Dec 2015 01:05:52 -0500 Subject: Apply syntax highlighting when expanding diff plus some refactor. #3945 --- app/controllers/projects/blob_controller.rb | 2 +- app/views/projects/blob/diff.html.haml | 2 +- lib/gitlab/diff/highlight.rb | 55 ++++++++++++++++++++++------- spec/lib/gitlab/diff/highlight_spec.rb | 42 +++++++++++++++------- 4 files changed, 74 insertions(+), 27 deletions(-) diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index c56a3497bb2..d22c7b550b0 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -66,7 +66,7 @@ class Projects::BlobController < Projects::ApplicationController def diff @form = UnfoldForm.new(params) - @lines = @blob.data.lines[@form.since - 1..@form.to - 1] + @lines = Gitlab::Diff::Highlight.process_diff_lines(@blob.name, @blob.data.lines[@form.since - 1..@form.to - 1]) if @form.bottom? @match_line = '' diff --git a/app/views/projects/blob/diff.html.haml b/app/views/projects/blob/diff.html.haml index f3b01ff3288..9d8f6ecb3ac 100644 --- a/app/views/projects/blob/diff.html.haml +++ b/app/views/projects/blob/diff.html.haml @@ -11,7 +11,7 @@ %td.old_line.diff-line-num{data: {linenumber: line_old}} = link_to raw(line_old), "#" %td.new_line= link_to raw(line_new) , "#" - %td.line_content.noteable_line= ' ' * @form.indent + line + %td.line_content.noteable_line= raw("#{' ' * @form.indent}#{line}") - if @form.unfold? && @form.bottom? && @form.to < @blob.loc %tr.line_holder{ id: @form.to } diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb index c780ea21775..7f340de65cc 100644 --- a/lib/gitlab/diff/highlight.rb +++ b/lib/gitlab/diff/highlight.rb @@ -1,31 +1,62 @@ module Gitlab module Diff class Highlight - def self.process_diff_lines(file_name, diff_lines) - processor = new(file_name, diff_lines) + # Apply syntax highlight to provided source code + # + # file_name - The file name related to the code. + # lines - It can be an Array of Gitlab::Diff::Line objects or simple Strings. + # When passing Strings you need to provide the required 'end of lines' + # chars ("\n") for each String given that we don't append them automatically. + # + # Returns an Array with the processed items. + def self.process_diff_lines(file_name, lines) + processor = new(file_name, lines) processor.highlight end - def initialize(file_name, diff_lines) - text_lines = diff_lines.map(&:text) - @file_name = file_name - @diff_lines = diff_lines - @diff_line_prefixes = text_lines.map { |line| line.sub!(/\A((\+|\-)\s*)/, '');$1 } - @raw_lines = text_lines.join("\n") + def initialize(file_name, lines) + @file_name = file_name + @lines = lines end def highlight - @code = unescape_html(@raw_lines) + return [] if @lines.empty? + + extract_line_prefixes + + @code = unescape_html(raw_content) @highlighted_code = formatter.format(lexer.lex(@code)) - update_diff_lines + is_diff_line? ? update_diff_lines : @highlighted_code.lines end private + def is_diff_line? + @lines.first.is_a?(Gitlab::Diff::Line) + end + + def text_lines + @text_lines ||= (is_diff_line? ? @lines.map(&:text) : @lines) + end + + def raw_content + @raw_content ||= text_lines.join(is_diff_line? ? "\n" : nil) + end + + def extract_line_prefixes + @diff_line_prefixes ||= begin + if is_diff_line? + text_lines.map { |line| line.sub!(/\A((\+|\-)\s*)/, '');$1 } + else + [] + end + end + end + def update_diff_lines @highlighted_code.lines.each_with_index do |line, i| - diff_line = @diff_lines[i] + diff_line = @lines[i] # ignore highlighting for "match" lines next if diff_line.type == 'match' @@ -33,7 +64,7 @@ module Gitlab diff_line.text = "#{@diff_line_prefixes[i]}#{line}" end - @diff_lines + @lines end def lexer diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb index 54621f773d7..fc5cb894d2a 100644 --- a/spec/lib/gitlab/diff/highlight_spec.rb +++ b/spec/lib/gitlab/diff/highlight_spec.rb @@ -9,25 +9,41 @@ describe Gitlab::Diff::Highlight, lib: true do let(:diff_file) { Gitlab::Diff::File.new(diff) } describe '.process_diff_lines' do - let(:diff_lines) { Gitlab::Diff::Highlight.process_diff_lines(diff_file.new_path, diff_file.diff_lines) } + context 'when processing Gitlab::Diff::Line objects' do + let(:diff_lines) { Gitlab::Diff::Highlight.process_diff_lines(diff_file.new_path, diff_file.diff_lines) } - it 'should return Gitlab::Diff::Line elements' do - expect(diff_lines.first).to be_an_instance_of(Gitlab::Diff::Line) - end + it 'should return Gitlab::Diff::Line elements' do + expect(diff_lines.first).to be_an_instance_of(Gitlab::Diff::Line) + end - it 'should highlight the code' do - code = %Q{ def popen(cmd, path=nil)\n} + it 'should highlight the code' do + code = %Q{ def popen(cmd, path=nil)\n} - expect(diff_lines[2].text).to eq(code) - end + expect(diff_lines[2].text).to eq(code) + end + + it 'should keep the inline diff markup' do + expect(diff_lines[5].text).to match(Regexp.new(Regexp.escape('RuntimeError, '))) + end - it 'should keep the inline diff markup' do - expect(diff_lines[5].text).to match(Regexp.new(Regexp.escape('RuntimeError, '))) + it 'should not modify "match" lines' do + expect(diff_lines[0].text).to eq('@@ -6,12 +6,18 @@ module Popen') + expect(diff_lines[22].text).to eq('@@ -19,6 +25,7 @@ module Popen') + end end - it 'should not modify "match" lines' do - expect(diff_lines[0].text).to eq('@@ -6,12 +6,18 @@ module Popen') - expect(diff_lines[22].text).to eq('@@ -19,6 +25,7 @@ module Popen') + context 'when processing raw lines' do + let(:lines) { ["puts 'Hello'\n", "# A comment"] } + let(:highlighted_lines) { Gitlab::Diff::Highlight.process_diff_lines('demo.rb', lines) } + + it 'should highlight the code' do + line_1 = %Q{puts 'Hello'\n} + line_2 = %Q{# A comment} + + expect(highlighted_lines[0]).to eq(line_1) + expect(highlighted_lines[1]).to eq(line_2) + end end + end end -- cgit v1.2.1 From 795ecb498c74d7fbc2db461b3d37ff10b350a3c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Thu, 31 Dec 2015 01:46:52 -0500 Subject: Fix broken spec. #3945 --- spec/fixtures/parallel_diff_result.yml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/spec/fixtures/parallel_diff_result.yml b/spec/fixtures/parallel_diff_result.yml index abbb364f61f..16c4bac96df 100644 --- a/spec/fixtures/parallel_diff_result.yml +++ b/spec/fixtures/parallel_diff_result.yml @@ -1,13 +1,11 @@ --- - - match - 6 - - | - @@ -6,12 +6,18 @@ module Popen + - '@@ -6,12 +6,18 @@ module Popen' - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6 - match - 6 - - | - @@ -6,12 +6,18 @@ module Popen + - '@@ -6,12 +6,18 @@ module Popen' - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6 - - - 6 @@ -193,13 +191,11 @@ - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23 - - match - 19 - - | - @@ -19,6 +25,7 @@ module Popen + - '@@ -19,6 +25,7 @@ module Popen' - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25 - match - 25 - - | - @@ -19,6 +25,7 @@ module Popen + - '@@ -19,6 +25,7 @@ module Popen' - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25 - - - 19 -- cgit v1.2.1 From ea4777ff501e370a39ae30e76a955136afe3c1fa Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 31 Dec 2015 15:19:13 +0100 Subject: Add features for list and show details of variables in API --- app/models/ci/variable.rb | 1 + lib/api/api.rb | 2 + lib/api/entities.rb | 4 ++ lib/api/variables.rb | 43 +++++++++++++++++++++ spec/factories/ci/variables.rb | 25 +++++++++++++ spec/requests/api/variables_spec.rb | 75 +++++++++++++++++++++++++++++++++++++ 6 files changed, 150 insertions(+) create mode 100644 lib/api/variables.rb create mode 100644 spec/factories/ci/variables.rb create mode 100644 spec/requests/api/variables_spec.rb diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb index 56759d3e50f..0e2712086ca 100644 --- a/app/models/ci/variable.rb +++ b/app/models/ci/variable.rb @@ -9,6 +9,7 @@ # encrypted_value :text # encrypted_value_salt :string(255) # encrypted_value_iv :string(255) +# gl_project_id :integer # module Ci diff --git a/lib/api/api.rb b/lib/api/api.rb index 7834262d612..a9e1913f0f2 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -54,5 +54,7 @@ module API mount Keys mount Tags mount Triggers + + mount Variables end end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 26e7c956e8f..f71d072f269 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -365,5 +365,9 @@ module API class TriggerRequest < Grape::Entity expose :id, :variables end + + class Variable < Grape::Entity + expose :id, :key, :value + end end end diff --git a/lib/api/variables.rb b/lib/api/variables.rb new file mode 100644 index 00000000000..6517150f6f4 --- /dev/null +++ b/lib/api/variables.rb @@ -0,0 +1,43 @@ +module API + # Projects variables API + class Variables < Grape::API + before { authenticate! } + before { authorize_admin_project } + + resource :projects do + # Get project variables + # + # Parameters: + # id (required) - The ID of a project + # page (optional) - The page number for pagination + # per_page (optional) - The value of items per page to show + # Example Request: + # GET /projects/:id/variables + get ':id/variables' do + variables = user_project.variables + present paginate(variables), with: Entities::Variable + end + + # Get specifica bariable of a project + # + # Parameters: + # id (required) - The ID of a project + # variable_id (required) - The ID OR `key` of variable to show; if variable_id contains only digits it's treated + # as ID other ways it's treated as `key` + # Example Reuest: + # GET /projects/:id/variables/:variable_id + get ':id/variables/:variable_id' do + variable_id = params[:variable_id] + variables = user_project.variables + variables = + if variable_id.match(/^\d+$/) + variables.where(id: variable_id.to_i) + else + variables.where(key: variable_id) + end + + present variables.first, with: Entities::Variable + end + end + end +end diff --git a/spec/factories/ci/variables.rb b/spec/factories/ci/variables.rb new file mode 100644 index 00000000000..c3dcb678da7 --- /dev/null +++ b/spec/factories/ci/variables.rb @@ -0,0 +1,25 @@ +# == Schema Information +# +# Table name: ci_variables +# +# id :integer not null, primary key +# project_id :integer not null +# key :string(255) +# value :text +# encrypted_value :text +# encrypted_value_salt :string(255) +# encrypted_value_iv :string(255) +# gl_project_id :integer +# + +# Read about factories at https://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :ci_variable, class: Ci::Variable do + id 1 + key 'TEST_VARIABLE_1' + value 'VALUE_1' + + project factory: :empty_project + end +end diff --git a/spec/requests/api/variables_spec.rb b/spec/requests/api/variables_spec.rb new file mode 100644 index 00000000000..8f66f5432b6 --- /dev/null +++ b/spec/requests/api/variables_spec.rb @@ -0,0 +1,75 @@ +require 'spec_helper' + +describe API::API, api: true do + include ApiHelpers + + let(:user) { create(:user) } + let(:user2) { create(:user) } + let!(:project) { create(:project, creator_id: user.id) } + let!(:master) { create(:project_member, user: user, project: project, access_level: ProjectMember::MASTER) } + let!(:developer) { create(:project_member, user: user2, project: project, access_level: ProjectMember::DEVELOPER) } + let!(:variable) { create(:ci_variable, project: project) } + + describe 'GET /projects/:id/variables' do + context 'authorized user with proper permissions' do + it 'should return project variables' do + get api("/projects/#{project.id}/variables", user) + + expect(response.status).to eq(200) + expect(json_response).to be_a(Array) + end + end + + context 'authorized user with invalid permissions' do + it 'should not return project variables' do + get api("/projects/#{project.id}/variables", user2) + + expect(response.status).to eq(403) + end + end + + context 'unauthorized user' do + it 'should not return project variables' do + get api("/projects/#{project.id}/variables") + + expect(response.status).to eq(401) + end + end + end + + describe 'GET /projects/:id/variables/:variable_id' do + context 'authorized user with proper permissions' do + it 'should return project variable details when ID is used as :variable_id' do + get api("/projects/#{project.id}/variables/1", user) + + expect(response.status).to eq(200) + expect(json_response['key']).to eq('TEST_VARIABLE_1') + expect(json_response['value']).to eq('VALUE_1') + end + + it 'should return project variable details when `key` is used as :variable_id' do + get api("/projects/#{project.id}/variables/TEST_VARIABLE_1", user) + + expect(response.status).to eq(200) + expect(json_response['id']).to eq(1) + expect(json_response['value']).to eq('VALUE_1') + end + end + + context 'authorized user with invalid permissions' do + it 'should not return project variable details' do + get api("/projects/#{project.id}/variables/1", user2) + + expect(response.status).to eq(403) + end + end + + context 'unauthorized user' do + it 'should not return project variable details' do + get api("/projects/#{project.id}/variables/1") + + expect(response.status).to eq(401) + end + end + end +end -- cgit v1.2.1 From a692ce1c079703c4f3947e1d0a29547189e94d0f Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 31 Dec 2015 16:25:49 +0100 Subject: Add update feature for variables API --- lib/api/variables.rb | 21 ++++++++++++++- spec/requests/api/variables_spec.rb | 52 +++++++++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/lib/api/variables.rb b/lib/api/variables.rb index 6517150f6f4..6522ecba70c 100644 --- a/lib/api/variables.rb +++ b/lib/api/variables.rb @@ -24,7 +24,7 @@ module API # id (required) - The ID of a project # variable_id (required) - The ID OR `key` of variable to show; if variable_id contains only digits it's treated # as ID other ways it's treated as `key` - # Example Reuest: + # Example Request: # GET /projects/:id/variables/:variable_id get ':id/variables/:variable_id' do variable_id = params[:variable_id] @@ -38,6 +38,25 @@ module API present variables.first, with: Entities::Variable end + + # Update existing variable of a project + # + # Parameters: + # id (required) - The ID of a project + # variable_id (required) - The ID of a variable + # key (optional) - new value for `key` field of variable + # value (optional) - new value for `value` field of variable + # Example Request: + # PUT /projects/:id/variables/:variable_id + put ':id/variables/:variable_id' do + variable = user_project.variables.where(id: params[:variable_id].to_i).first + + variable.key = params[:key] + variable.value = params[:value] + variable.save! + + present variable, with: Entities::Variable + end end end end diff --git a/spec/requests/api/variables_spec.rb b/spec/requests/api/variables_spec.rb index 8f66f5432b6..3f58277c4ae 100644 --- a/spec/requests/api/variables_spec.rb +++ b/spec/requests/api/variables_spec.rb @@ -40,25 +40,25 @@ describe API::API, api: true do describe 'GET /projects/:id/variables/:variable_id' do context 'authorized user with proper permissions' do it 'should return project variable details when ID is used as :variable_id' do - get api("/projects/#{project.id}/variables/1", user) + get api("/projects/#{project.id}/variables/#{variable.id}", user) expect(response.status).to eq(200) - expect(json_response['key']).to eq('TEST_VARIABLE_1') - expect(json_response['value']).to eq('VALUE_1') + expect(json_response['key']).to eq(variable.key) + expect(json_response['value']).to eq(variable.value) end it 'should return project variable details when `key` is used as :variable_id' do - get api("/projects/#{project.id}/variables/TEST_VARIABLE_1", user) + get api("/projects/#{project.id}/variables/#{variable.key}", user) expect(response.status).to eq(200) - expect(json_response['id']).to eq(1) - expect(json_response['value']).to eq('VALUE_1') + expect(json_response['id']).to eq(variable.id) + expect(json_response['value']).to eq(variable.value) end end context 'authorized user with invalid permissions' do it 'should not return project variable details' do - get api("/projects/#{project.id}/variables/1", user2) + get api("/projects/#{project.id}/variables/#{variable.id}", user2) expect(response.status).to eq(403) end @@ -66,7 +66,43 @@ describe API::API, api: true do context 'unauthorized user' do it 'should not return project variable details' do - get api("/projects/#{project.id}/variables/1") + get api("/projects/#{project.id}/variables/#{variable.id}") + + expect(response.status).to eq(401) + end + end + end + + describe 'PUT /projects/:id/variables/:variable_id' do + context 'authorized user with proper permissions' do + it 'should update variable data' do + initial_variable = project.variables.first + key_before = initial_variable.key + value_before = initial_variable.value + + put api("/projects/#{project.id}/variables/#{variable.id}", user), key: 'TEST_VARIABLE_1_UP', value: 'VALUE_1_UP' + + updated_variable = project.variables.first + + expect(response.status).to eq(200) + expect(key_before).to eq(variable.key) + expect(value_before).to eq(variable.value) + expect(updated_variable.key).to eq('TEST_VARIABLE_1_UP') + expect(updated_variable.value).to eq('VALUE_1_UP') + end + end + + context 'authorized user with invalid permissions' do + it 'should not update variable' do + put api("/projects/#{project.id}/variables/#{variable.id}", user2) + + expect(response.status).to eq(403) + end + end + + context 'unauthorized user' do + it 'should not return project variable details' do + put api("/projects/#{project.id}/variables/#{variable.id}") expect(response.status).to eq(401) end -- cgit v1.2.1 From 0d014feb1d216e692882976f0d70c3227eaec4ca Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 31 Dec 2015 16:56:03 +0100 Subject: Add delete feature to variables API --- lib/api/variables.rb | 12 ++++++++++++ spec/requests/api/variables_spec.rb | 29 ++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/lib/api/variables.rb b/lib/api/variables.rb index 6522ecba70c..c70c7cd9d7b 100644 --- a/lib/api/variables.rb +++ b/lib/api/variables.rb @@ -57,6 +57,18 @@ module API present variable, with: Entities::Variable end + + # Delete existing variable of a project + # + # Parameters: + # id (required) - The ID of a project + # variable_id (required) - The ID of a variable + # Exanoke Reqyest: + # DELETE /projects/:id/variables/:variable_id + delete ':id/variables/:variable_id' do + variable = user_project.variables.where(id: params[:variable_id].to_i).first + variable.destroy + end end end end diff --git a/spec/requests/api/variables_spec.rb b/spec/requests/api/variables_spec.rb index 3f58277c4ae..385db2409bd 100644 --- a/spec/requests/api/variables_spec.rb +++ b/spec/requests/api/variables_spec.rb @@ -101,11 +101,38 @@ describe API::API, api: true do end context 'unauthorized user' do - it 'should not return project variable details' do + it 'should not update variable' do put api("/projects/#{project.id}/variables/#{variable.id}") expect(response.status).to eq(401) end end end + + describe 'DELETE /projects/:id/variables/:variable_id' do + context 'authorized user with proper permissions' do + it 'should delete variable' do + expect do + delete api("/projects/#{project.id}/variables/#{variable.id}", user) + end.to change{project.variables.count}.by(-1) + expect(response.status).to eq(200) + end + end + + context 'authorized user with invalid permissions' do + it 'should not delete variable' do + delete api("/projects/#{project.id}/variables/#{variable.id}", user2) + + expect(response.status).to eq(403) + end + end + + context 'unauthorized user' do + it 'should not delete variable' do + delete api("/projects/#{project.id}/variables/#{variable.id}") + + expect(response.status).to eq(401) + end + end + end end -- cgit v1.2.1 From c5177dd5e2171b047a695802c979cf779522ba8a Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 31 Dec 2015 17:03:11 +0100 Subject: Add missing 'not_found' checks in variables API --- lib/api/variables.rb | 7 +++++++ spec/requests/api/variables_spec.rb | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/lib/api/variables.rb b/lib/api/variables.rb index c70c7cd9d7b..dac2ba679c7 100644 --- a/lib/api/variables.rb +++ b/lib/api/variables.rb @@ -36,6 +36,8 @@ module API variables.where(key: variable_id) end + return not_found!('Variable') if variables.empty? + present variables.first, with: Entities::Variable end @@ -51,6 +53,8 @@ module API put ':id/variables/:variable_id' do variable = user_project.variables.where(id: params[:variable_id].to_i).first + return not_found!('Variable') unless variable + variable.key = params[:key] variable.value = params[:value] variable.save! @@ -67,6 +71,9 @@ module API # DELETE /projects/:id/variables/:variable_id delete ':id/variables/:variable_id' do variable = user_project.variables.where(id: params[:variable_id].to_i).first + + return not_found!('Variable') unless variable + variable.destroy end end diff --git a/spec/requests/api/variables_spec.rb b/spec/requests/api/variables_spec.rb index 385db2409bd..b35ee2d32d1 100644 --- a/spec/requests/api/variables_spec.rb +++ b/spec/requests/api/variables_spec.rb @@ -54,6 +54,12 @@ describe API::API, api: true do expect(json_response['id']).to eq(variable.id) expect(json_response['value']).to eq(variable.value) end + + it 'should responde with 404 Not Found if requesting non-existing variable' do + get api("/projects/#{project.id}/variables/9999", user) + + expect(response.status).to eq(404) + end end context 'authorized user with invalid permissions' do @@ -90,6 +96,12 @@ describe API::API, api: true do expect(updated_variable.key).to eq('TEST_VARIABLE_1_UP') expect(updated_variable.value).to eq('VALUE_1_UP') end + + it 'should responde with 404 Not Found if requesting non-existing variable' do + put api("/projects/#{project.id}/variables/9999", user) + + expect(response.status).to eq(404) + end end context 'authorized user with invalid permissions' do @@ -117,6 +129,12 @@ describe API::API, api: true do end.to change{project.variables.count}.by(-1) expect(response.status).to eq(200) end + + it 'should responde with 404 Not Found if requesting non-existing variable' do + delete api("/projects/#{project.id}/variables/9999", user) + + expect(response.status).to eq(404) + end end context 'authorized user with invalid permissions' do -- cgit v1.2.1 From 937567b767e6d7b34dcaa1d9c83fc75464638683 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 31 Dec 2015 22:30:07 +0100 Subject: Add create feature to variables API --- lib/api/variables.rb | 20 +++++++++++++++++++ spec/factories/ci/variables.rb | 2 +- spec/requests/api/variables_spec.rb | 38 +++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/lib/api/variables.rb b/lib/api/variables.rb index dac2ba679c7..fc63ac2f56a 100644 --- a/lib/api/variables.rb +++ b/lib/api/variables.rb @@ -41,6 +41,24 @@ module API present variables.first, with: Entities::Variable end + # Create a new variable in project + # + # Parameters: + # id (required) - The ID of a project + # key (required) - The key of variable being created + # value (required) - The value of variable being created + # Example Request: + # POST /projects/:id/variables + post ':id/variables' do + required_attributes! [:key, :value] + + variable = user_project.variables.create(key: params[:key], value: params[:value]) + return render_validation_error!(variable) unless variable.valid? + variable.save! + + present variable, with: Entities::Variable + end + # Update existing variable of a project # # Parameters: @@ -75,6 +93,8 @@ module API return not_found!('Variable') unless variable variable.destroy + + present variable, with: Entities::Variable end end end diff --git a/spec/factories/ci/variables.rb b/spec/factories/ci/variables.rb index c3dcb678da7..a19b9fc72f2 100644 --- a/spec/factories/ci/variables.rb +++ b/spec/factories/ci/variables.rb @@ -16,7 +16,7 @@ FactoryGirl.define do factory :ci_variable, class: Ci::Variable do - id 1 + id 10 key 'TEST_VARIABLE_1' value 'VALUE_1' diff --git a/spec/requests/api/variables_spec.rb b/spec/requests/api/variables_spec.rb index b35ee2d32d1..bf0dd77473a 100644 --- a/spec/requests/api/variables_spec.rb +++ b/spec/requests/api/variables_spec.rb @@ -79,6 +79,44 @@ describe API::API, api: true do end end + describe 'POST /projects/:id/variables' do + context 'authorized user with proper permissions' do + it 'should create variable' do + expect do + post api("/projects/#{project.id}/variables", user), key: 'TEST_VARIABLE_2', value: 'VALUE_2' + end.to change{project.variables.count}.by(1) + + expect(response.status).to eq(201) + expect(json_response['key']).to eq('TEST_VARIABLE_2') + expect(json_response['value']).to eq('VALUE_2') + end + + it 'should not allow to duplicate variable key' do + expect do + post api("/projects/#{project.id}/variables", user), key: 'TEST_VARIABLE_1', value: 'VALUE_2' + end.to change{project.variables.count}.by(0) + + expect(response.status).to eq(400) + end + end + + context 'authorized user with invalid permissions' do + it 'should not create variable' do + post api("/projects/#{project.id}/variables", user2) + + expect(response.status).to eq(403) + end + end + + context 'unauthorized user' do + it 'should not create variable' do + post api("/projects/#{project.id}/variables") + + expect(response.status).to eq(401) + end + end + end + describe 'PUT /projects/:id/variables/:variable_id' do context 'authorized user with proper permissions' do it 'should update variable data' do -- cgit v1.2.1 From 16bd4df083135e2e4a263b2e1bdd71b78a875ef7 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 31 Dec 2015 22:59:06 +0100 Subject: Fix a typo in method description --- lib/api/variables.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/variables.rb b/lib/api/variables.rb index fc63ac2f56a..b8bbcb6ce3b 100644 --- a/lib/api/variables.rb +++ b/lib/api/variables.rb @@ -18,7 +18,7 @@ module API present paginate(variables), with: Entities::Variable end - # Get specifica bariable of a project + # Get specifica variable of a project # # Parameters: # id (required) - The ID of a project -- cgit v1.2.1 From 628297fe5692fc241c93ff34cece71132bfb9aed Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 31 Dec 2015 23:01:28 +0100 Subject: Remove incorrect 'default' values from method description --- lib/api/builds.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/api/builds.rb b/lib/api/builds.rb index a519224d2b8..92bf849824c 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -9,8 +9,8 @@ module API # Parameters: # id (required) - The ID of a project # scope (optional) - The scope of builds to show (one of: all, finished, running) - # page (optional) - The page number for pagination (default: 1) - # per_page (ooptional) - The value of items per page to show (default 30) + # page (optional) - The page number for pagination + # per_page (ooptional) - The value of items per page to show # Example Request: # GET /projects/:id/builds get ':id/builds' do -- cgit v1.2.1 From 0134a85bee1e1f932d7c9d8752d8eb8e5148baf2 Mon Sep 17 00:00:00 2001 From: Christian Mehlmauer Date: Mon, 4 Jan 2016 00:29:30 +0100 Subject: added make command to docs --- doc/update/patch_versions.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/update/patch_versions.md b/doc/update/patch_versions.md index c19ee49f9e0..a10e62877ba 100644 --- a/doc/update/patch_versions.md +++ b/doc/update/patch_versions.md @@ -48,6 +48,7 @@ sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION` -b v`ca cd /home/git/gitlab-workhorse sudo -u git -H git fetch sudo -u git -H git checkout `cat /home/git/gitlab/GITLAB_WORKHORSE_VERSION` -b `cat /home/git/gitlab/GITLAB_WORKHORSE_VERSION` +sudo -u git -H make ``` ### 5. Install libs, migrations, etc. -- cgit v1.2.1 From d9da81f736b770bb44c4869aef5d5c455e74ab7a Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Mon, 4 Jan 2016 16:38:32 +0100 Subject: Add triggers feature to API --- lib/api/entities.rb | 10 ++++++++ lib/api/triggers.rb | 18 ++++++++++++++ spec/factories/ci/trigger_requests.rb | 2 ++ spec/requests/api/triggers_spec.rb | 45 +++++++++++++++++++++++++++++++---- 4 files changed, 71 insertions(+), 4 deletions(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 26e7c956e8f..bc0cd76a2b8 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -365,5 +365,15 @@ module API class TriggerRequest < Grape::Entity expose :id, :variables end + + class Trigger < Grape::Entity + expose :id, :token, :created_at, :updated_at, :deleted_at + expose :last_used do |repo_obj, _options| + if repo_obj.respond_to?(:last_trigger_request) + request = repo_obj.last_trigger_request + request.created_at if request + end + end + end end end diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb index 2781f1cf191..9a1e3fdc976 100644 --- a/lib/api/triggers.rb +++ b/lib/api/triggers.rb @@ -43,6 +43,24 @@ module API render_api_error!(errors, 400) end end + + # Get triggers list + # + # Parameters: + # id (required) - The ID of a project + # page (optional) - The page number for pagination + # per_page (optional) - The value of items per page to show + # Example Request: + # GET /projects/:id/triggers + get ':id/triggers' do + authenticate! + authorize_admin_project + + triggers = user_project.triggers.includes(:trigger_requests) + triggers = paginate(triggers) + + present triggers, with: Entities::Trigger + end end end end diff --git a/spec/factories/ci/trigger_requests.rb b/spec/factories/ci/trigger_requests.rb index db053c610cd..5298d9fa7c3 100644 --- a/spec/factories/ci/trigger_requests.rb +++ b/spec/factories/ci/trigger_requests.rb @@ -3,6 +3,8 @@ FactoryGirl.define do factory :ci_trigger_request, class: Ci::TriggerRequest do factory :ci_trigger_request_with_variables do + trigger :ci_trigger + variables do { TRIGGER_KEY: 'TRIGGER_VALUE' diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index 314bd7ddc59..4b356108c80 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -3,11 +3,19 @@ require 'spec_helper' describe API::API do include ApiHelpers + let(:user) { create(:user) } + let(:user2) { create(:user) } + let!(:trigger_token) { 'secure token' } + let!(:trigger_token_2) { 'secure token 2' } + let!(:project) { create(:project, creator_id: user.id) } + let!(:master) { create(:project_member, user: user, project: project, access_level: ProjectMember::MASTER) } + let!(:developer) { create(:project_member, user: user2, project: project, access_level: ProjectMember::DEVELOPER) } + let!(:trigger) { create(:ci_trigger, project: project, token: trigger_token) } + let!(:trigger2) { create(:ci_trigger, project: project, token: trigger_token_2) } + let!(:trigger_request) { create(:ci_trigger_request, trigger: trigger, created_at: '2015-01-01 12:13:14') } + describe 'POST /projects/:project_id/trigger' do - let!(:trigger_token) { 'secure token' } - let!(:project) { FactoryGirl.create(:project) } - let!(:project2) { FactoryGirl.create(:empty_project) } - let!(:trigger) { FactoryGirl.create(:ci_trigger, project: project, token: trigger_token) } + let!(:project2) { create(:empty_project) } let(:options) do { token: trigger_token @@ -77,4 +85,33 @@ describe API::API do end end end + + describe 'GET /projects/:id/triggets' do + context 'authenticated user with valid permissions' do + it 'should return list of triggers' do + get api("/projects/#{project.id}/triggers", user) + + expect(response.status).to eq(200) + expect(json_response).to be_a(Array) + expect(json_response[0]['token']).to eq(trigger_token) + expect(json_response[1]['token']).to eq(trigger_token_2) + end + end + + context 'authenticated user with invalid permissions' do + it 'should not return triggers list' do + get api("/projects/#{project.id}/triggers", user2) + + expect(response.status).to eq(403) + end + end + + context 'unauthentikated user' do + it 'should not return triggers list' do + get api("/projects/#{project.id}/triggers") + + expect(response.status).to eq(401) + end + end + end end -- cgit v1.2.1 From 3098500835aad26748d982fa81c84a2deed97931 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Tue, 5 Jan 2016 11:01:44 +0100 Subject: Fix ci_trigger_request factory --- spec/factories/ci/trigger_requests.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/factories/ci/trigger_requests.rb b/spec/factories/ci/trigger_requests.rb index 5298d9fa7c3..2c0d004d267 100644 --- a/spec/factories/ci/trigger_requests.rb +++ b/spec/factories/ci/trigger_requests.rb @@ -3,7 +3,7 @@ FactoryGirl.define do factory :ci_trigger_request, class: Ci::TriggerRequest do factory :ci_trigger_request_with_variables do - trigger :ci_trigger + trigger factory: :ci_trigger variables do { -- cgit v1.2.1 From f00607431cd13a952731e36701ebc3b39e64d09b Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Tue, 5 Jan 2016 11:27:38 +0100 Subject: Add delete feature to triggers API --- lib/api/triggers.rb | 19 +++++++++++++++++++ spec/requests/api/triggers_spec.rb | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb index 9a1e3fdc976..3cb7810241f 100644 --- a/lib/api/triggers.rb +++ b/lib/api/triggers.rb @@ -61,6 +61,25 @@ module API present triggers, with: Entities::Trigger end + + # Delete trigger + # + # Parameters: + # id (required) - The ID of a project + # trigger_id - The ID of trigger to delete + # Example Request: + # DELETE /projects/:id/triggers/:trigger_id + delete ':id/triggers/:trigger_id' do + authenticate! + authorize_admin_project + + trigger = user_project.triggers.where(id: params[:trigger_id].to_i).first + return not_found!('Trigger') unless trigger + + trigger.destroy + + present trigger, with: Entities::Trigger + end end end end diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index 4b356108c80..4e073a55d9c 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -114,4 +114,37 @@ describe API::API do end end end + + describe 'DELETE /projects/:id/triggets/:trigger_id' do + context 'authenticated user with valid permissions' do + it 'should delete trigger' do + expect do + delete api("/projects/#{project.id}/triggers/#{trigger.id}", user) + end.to change{project.triggers.count}.by(-1) + expect(response.status).to eq(200) + end + + it 'should responde with 404 Not Found if requesting non-existing trigger' do + delete api("/projects/#{project.id}/triggers/9999", user) + + expect(response.status).to eq(404) + end + end + + context 'authenticated user with invalid permissions' do + it 'should not delete trigger' do + delete api("/projects/#{project.id}/triggers/#{trigger.id}", user2) + + expect(response.status).to eq(403) + end + end + + context 'unauthentikated user' do + it 'should not delete trigger' do + delete api("/projects/#{project.id}/triggers/#{trigger.id}") + + expect(response.status).to eq(401) + end + end + end end -- cgit v1.2.1 From 49c8bf4e9b510be51859dcc301cb46b29b750cb0 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Tue, 5 Jan 2016 11:44:10 +0100 Subject: Add create feature to triggers API --- lib/api/triggers.rb | 16 ++++++++++++++++ spec/requests/api/triggers_spec.rb | 29 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb index 3cb7810241f..38cf1e9a2e0 100644 --- a/lib/api/triggers.rb +++ b/lib/api/triggers.rb @@ -62,6 +62,22 @@ module API present triggers, with: Entities::Trigger end + # Create trigger + # + # Parameters: + # id (required) - The ID of a project + # Example Request: + # POST /projects/:id/triggers + post ':id/triggers' do + authenticate! + authorize_admin_project + + trigger = user_project.triggers.new + trigger.save + + present trigger, with: Entities::Trigger + end + # Delete trigger # # Parameters: diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index 4e073a55d9c..316c2ae958d 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -115,6 +115,35 @@ describe API::API do end end + describe 'POST /projects/:id/triggets' do + context 'authenticated user with valid permissions' do + it 'should create trigger' do + expect do + post api("/projects/#{project.id}/triggers", user) + end.to change{project.triggers.count}.by(1) + + expect(response.status).to eq(201) + expect(json_response).to be_a(Hash) + end + end + + context 'authenticated user with invalid permissions' do + it 'should not create trigger' do + post api("/projects/#{project.id}/triggers", user2) + + expect(response.status).to eq(403) + end + end + + context 'unauthentikated user' do + it 'should not create trigger' do + post api("/projects/#{project.id}/triggers") + + expect(response.status).to eq(401) + end + end + end + describe 'DELETE /projects/:id/triggets/:trigger_id' do context 'authenticated user with valid permissions' do it 'should delete trigger' do -- cgit v1.2.1 From 8675664655c4e0f1e043afa88ff1fd75ae5a6a9e Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Tue, 5 Jan 2016 12:25:16 +0100 Subject: Get show details feature to triggers API --- lib/api/triggers.rb | 26 ++++++++++++++++++ spec/requests/api/triggers_spec.rb | 56 ++++++++++++++++++++++++++++++++++---- 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb index 38cf1e9a2e0..0e548b936cd 100644 --- a/lib/api/triggers.rb +++ b/lib/api/triggers.rb @@ -62,6 +62,32 @@ module API present triggers, with: Entities::Trigger end + # Get specific trigger of a project + # + # Parameters: + # id (required) - The ID of a project + # trigger_id (required) - The ID or `token` of a trigger to show; if trigger_id contains only digits it's + # treated as ID other ways it's reated as `key` + # Example Request: + # GET /projects/:id/triggers/:trigger_id + get ':id/triggers/:trigger_id' do + authenticate! + authorize_admin_project + + trigger_id = params[:trigger_id] + triggers = user_project.triggers + triggers = + if trigger_id.match(/^\d+$/) + triggers.where(id: trigger_id.to_i) + else + triggers.where(token: trigger_id) + end + + return not_found!('Trigger') if triggers.empty? + + present triggers.first, with: Entities::Trigger + end + # Create trigger # # Parameters: diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index 316c2ae958d..c1c2bb04b29 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -5,8 +5,8 @@ describe API::API do let(:user) { create(:user) } let(:user2) { create(:user) } - let!(:trigger_token) { 'secure token' } - let!(:trigger_token_2) { 'secure token 2' } + let!(:trigger_token) { 'secure_token' } + let!(:trigger_token_2) { 'secure_token_2' } let!(:project) { create(:project, creator_id: user.id) } let!(:master) { create(:project_member, user: user, project: project, access_level: ProjectMember::MASTER) } let!(:developer) { create(:project_member, user: user2, project: project, access_level: ProjectMember::DEVELOPER) } @@ -86,7 +86,7 @@ describe API::API do end end - describe 'GET /projects/:id/triggets' do + describe 'GET /projects/:id/triggers' do context 'authenticated user with valid permissions' do it 'should return list of triggers' do get api("/projects/#{project.id}/triggers", user) @@ -115,7 +115,53 @@ describe API::API do end end - describe 'POST /projects/:id/triggets' do + describe 'GET /projects/:id/triggers/:triggers_id' do + context 'authenticated user with valid permissions' do + context 'ID is used as :trigger_id' do + it 'should return trigger details' do + get api("/projects/#{project.id}/triggers/#{trigger.id}", user) + + expect(response.status).to eq(200) + expect(json_response).to be_a(Hash) + expect(json_response['token']).to eq(trigger_token) + end + end + + context '`token` is used as :trigger_id' do + it 'should return trigger details' do + get api("/projects/#{project.id}/triggers/#{trigger.token}", user) + + expect(response.status).to eq(200) + expect(json_response).to be_a(Hash) + expect(json_response['id']).to eq(trigger.id) + end + end + + it 'should responde with 404 Not Found if requesting non-existing trigger' do + get api("/projects/#{project.id}/triggers/9999", user) + + expect(response.status).to eq(404) + end + end + + context 'authenticated user with invalid permissions' do + it 'should not return triggers list' do + get api("/projects/#{project.id}/triggers/#{trigger.id}", user2) + + expect(response.status).to eq(403) + end + end + + context 'unauthentikated user' do + it 'should not return triggers list' do + get api("/projects/#{project.id}/triggers/#{trigger.id}") + + expect(response.status).to eq(401) + end + end + end + + describe 'POST /projects/:id/triggers' do context 'authenticated user with valid permissions' do it 'should create trigger' do expect do @@ -144,7 +190,7 @@ describe API::API do end end - describe 'DELETE /projects/:id/triggets/:trigger_id' do + describe 'DELETE /projects/:id/triggers/:trigger_id' do context 'authenticated user with valid permissions' do it 'should delete trigger' do expect do -- cgit v1.2.1 From f60bceb988bd629f9adecc070ef5579d264f27c6 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Tue, 5 Jan 2016 13:20:06 +0100 Subject: Add CI data to projcet entity --- lib/api/entities.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 26e7c956e8f..e8154e0f383 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -71,6 +71,9 @@ module API expose :avatar_url expose :star_count, :forks_count expose :open_issues_count, if: lambda { |project, options| project.issues_enabled? && project.default_issues_tracker? } + + expose :build_allow_git_fetch, :build_timeout, :build_coverage_regex + expose :runners_token end class ProjectMember < UserBasic -- cgit v1.2.1 From 0a21731e3bc400ceb9898c9efbc2a186f5348e09 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Tue, 5 Jan 2016 15:00:25 +0100 Subject: Add ci fields in project create/update feature API --- lib/api/helpers.rb | 2 +- lib/api/projects.rb | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index a4df810e755..563c12e4f74 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -157,7 +157,7 @@ module API def attributes_for_keys(keys, custom_params = nil) attrs = {} keys.each do |key| - if params[key].present? or (params.has_key?(key) and params[key] == false) + if params[key].present? or (params.has_key?(key) and (params[key].empty? or params[key] == false)) attrs[key] = params[key] end end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 0781236cf6d..7dd6b133f9b 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -114,7 +114,10 @@ module API :namespace_id, :public, :visibility_level, - :import_url] + :import_url, + :build_allow_git_fetch, + :build_timeout, + :build_coverage_regex] attrs = map_public_to_visibility_level(attrs) @project = ::Projects::CreateService.new(current_user, attrs).execute if @project.saved? @@ -159,7 +162,10 @@ module API :shared_runners_enabled, :public, :visibility_level, - :import_url] + :import_url, + :build_allow_git_fetch, + :build_timeout, + :build_coverage_regex] attrs = map_public_to_visibility_level(attrs) @project = ::Projects::CreateService.new(user, attrs).execute if @project.saved? @@ -215,7 +221,10 @@ module API :snippets_enabled, :shared_runners_enabled, :public, - :visibility_level] + :visibility_level, + :build_allow_git_fetch, + :build_timeout, + :build_coverage_regex] attrs = map_public_to_visibility_level(attrs) authorize_admin_project authorize! :rename_project, user_project if attrs[:name].present? -- cgit v1.2.1 From a862ade55bf68f56734538b40e02e56036f8a1bd Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Tue, 5 Jan 2016 16:36:14 +0100 Subject: Update ./doc/api/ --- doc/api/README.md | 1 + doc/api/builds.md | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/api/builds.rb | 3 +- 3 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 doc/api/builds.md diff --git a/doc/api/README.md b/doc/api/README.md index 25a31b235cc..43ee24ddb63 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -23,6 +23,7 @@ - [Namespaces](namespaces.md) - [Settings](settings.md) - [Keys](keys.md) +- [Builds](builds.md) ## Clients diff --git a/doc/api/builds.md b/doc/api/builds.md new file mode 100644 index 00000000000..b716499dd36 --- /dev/null +++ b/doc/api/builds.md @@ -0,0 +1,206 @@ +# Builds API + +## List project builds + +Get a list of builds in a project. + +``` +GET /projects/:id/builds +``` + +Parameters: + +- `id` (required) - The ID of a project +- `scope` (optional) - The scope of builds to show (one of: `all`, `finished`, `running`; default: `all`) + +```json +[ + { + "commit": { + "committed_at": "2015-12-28T14:34:03.814Z", + "id": 2, + "ref": null, + "sha": "6b053ad388c531c21907f022933e5e81598db388" + }, + "created_at": "2016-01-04T15:41:23.147Z", + "finished_at": null, + "id": 65, + "name": "brakeman", + "ref": "master", + "runner": null, + "stage": "test", + "started_at": null, + "status": "pending" + }, + { + "commit": { + "committed_at": "2015-12-28T14:34:03.814Z", + "id": 2, + "ref": null, + "sha": "6b053ad388c531c21907f022933e5e81598db388" + }, + "created_at": "2016-01-04T15:41:23.046Z", + "finished_at": null, + "id": 64, + "name": "rubocop", + "ref": "master", + "runner": null, + "stage": "test", + "started_at": null, + "status": "pending" + } +] +``` + +## List commit builds + +Get a list of builds for specific commit in a project. + +``` +GET /projects/:id/builds/commit/:sha +``` + +Parameters: + +- `id` (required) - The ID of a project +- `sha` (required) - The SHA id of a commit +- `scope` (optional) - The scope of builds to show (one of: `all`, `finished`, `running`; default: `all`) + + +```json +[ + { + "commit": { + "committed_at": "2015-12-28T14:34:03.814Z", + "id": 2, + "ref": null, + "sha": "6b053ad388c531c21907f022933e5e81598db388" + }, + "created_at": "2016-01-04T15:41:23.147Z", + "finished_at": null, + "id": 65, + "name": "brakeman", + "ref": "master", + "runner": null, + "stage": "test", + "started_at": null, + "status": "pending" + }, + { + "commit": { + "committed_at": "2015-12-28T14:34:03.814Z", + "id": 2, + "ref": null, + "sha": "6b053ad388c531c21907f022933e5e81598db388" + }, + "created_at": "2016-01-04T15:41:23.046Z", + "finished_at": null, + "id": 64, + "name": "rubocop", + "ref": "master", + "runner": null, + "stage": "test", + "started_at": null, + "status": "pending" + } +] +``` + +## Get a single build + +Get a single build of a project + +``` +GET /projects/:id/builds/:build_id +``` + +Parameters: + +- `id` (required) - The ID of a project +- `build_id` (required) - The ID of a build + +```json +{ + "commit": { + "committed_at": "2015-12-28T14:34:03.814Z", + "id": 2, + "ref": null, + "sha": "6b053ad388c531c21907f022933e5e81598db388" + }, + "created_at": "2016-01-04T15:41:23.046Z", + "finished_at": null, + "id": 64, + "name": "rubocop", + "ref": "master", + "runner": null, + "stage": "test", + "started_at": null, + "status": "pending" +} +``` + +## Cancel a build + +Cancel a single build of a project + +``` +POST /projects/:id/builds/:build_id/cancel +``` + +Parameters: + +- `id` (required) - The ID of a project +- `build_id` (required) - The ID of a build + +```json +{ + "commit": { + "committed_at": "2015-12-28T14:34:03.814Z", + "id": 2, + "ref": null, + "sha": "6b053ad388c531c21907f022933e5e81598db388" + }, + "created_at": "2016-01-05T15:33:25.936Z", + "finished_at": "2016-01-05T15:33:47.553Z", + "id": 66, + "name": "rubocop", + "ref": "master", + "runner": null, + "stage": "test", + "started_at": null, + "status": "canceled" +} +``` + +## Retry a build + +Retry a single build of a project + +``` +POST /projects/:id/builds/:build_id/retry +``` + +Parameters: + +- `id` (required) - The ID of a project +- `build_id` (required) - The ID of a build + +```json +{ + "commit": { + "committed_at": "2015-12-28T14:34:03.814Z", + "id": 2, + "ref": null, + "sha": "6b053ad388c531c21907f022933e5e81598db388" + }, + "created_at": "2016-01-05T15:33:25.936Z", + "finished_at": null, + "id": 66, + "name": "rubocop", + "ref": "master", + "runner": null, + "stage": "test", + "started_at": null, + "status": "pending" +} +``` diff --git a/lib/api/builds.rb b/lib/api/builds.rb index 92bf849824c..6b0edcff820 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -8,7 +8,7 @@ module API # # Parameters: # id (required) - The ID of a project - # scope (optional) - The scope of builds to show (one of: all, finished, running) + # scope (optional) - The scope of builds to show (one of: all, finished, running; default: all) # page (optional) - The page number for pagination # per_page (ooptional) - The value of items per page to show # Example Request: @@ -24,6 +24,7 @@ module API # Parameters: # id (required) - The ID of a project # sha (required) - The SHA id of a commit + # scope (optional) - The scope of builds to show (one of: all, finished, running; default: all) # Example Request: # GET /projects/:id/builds/commit/:sha get ':id/builds/commit/:sha' do -- cgit v1.2.1 From cbdc8dd46ff2b74e5817053f774cc8f17db55f77 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Tue, 5 Jan 2016 20:42:25 -0500 Subject: adds ajax open and close merges, with discussion/comments working as well --- app/assets/javascripts/merge_request.js.coffee | 43 ++++++++++++++++++++++ app/helpers/merge_requests_helper.rb | 4 ++ app/models/merge_request.rb | 10 ----- .../projects/merge_requests/_discussion.html.haml | 9 ++--- .../merge_requests/show/_mr_title.html.haml | 26 ++++++++----- 5 files changed, 67 insertions(+), 25 deletions(-) diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee index 9047587db81..8c321319b30 100644 --- a/app/assets/javascripts/merge_request.js.coffee +++ b/app/assets/javascripts/merge_request.js.coffee @@ -22,6 +22,7 @@ class @MergeRequest if $("a.btn-close").length @initTaskList() + @initMergeRequestBtnEventListeners() # Local jQuery finder $: (selector) -> @@ -35,6 +36,48 @@ class @MergeRequest # Show the first tab (Commits) $('.merge-request-tabs a[data-toggle="tab"]:first').tab('show') + initMergeRequestBtnEventListeners: -> + _this = @ + mergeRequestFailMessage = 'Unable to update this merge request at this time.' + $('a.btn-close, a.btn-reopen').on 'click', (e) -> + e.preventDefault() + e.stopImmediatePropagation() + $this = $(this) + isClose = $this.hasClass('btn-close') + shouldSubmit = $this.hasClass('btn-comment') + if shouldSubmit + _this.submitNoteForm($this.closest('form')) + $this.prop('disabled', true) + url = $this.attr('href') + $.ajax + type: 'PUT', + url: url, + error: (jqXHR, textStatus, errorThrown) -> + mergeRequestStatus = if isClose then 'close' else 'open' + new Flash(mergeRequestFailMessage, 'alert') + success: (data, textStatus, jqXHR) -> + if data.saved + if isClose + $('a.btn-close').addClass('hidden') + $('a.issuable-edit').addClass('hidden') + $('a.btn-reopen').removeClass('hidden') + $('div.status-box-closed').removeClass('hidden') + $('div.status-box-open').addClass('hidden') + else + $('a.btn-reopen').addClass('hidden') + $('a.issuable-edit').removeClass('hidden') + $('a.btn-close').removeClass('hidden') + $('div.status-box-closed').addClass('hidden') + $('div.status-box-open').removeClass('hidden') + else + new Flash(mergeRequestFailMessage, 'alert') + $this.prop('disabled', false) + + submitNoteForm: (form) => + noteText = form.find("textarea.js-note-text").val() + if noteText.trim().length > 0 + form.submit() + showAllCommits: -> this.$('.first-commits').remove() this.$('.all-commits').removeClass 'hide' diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index 1dd07a2a220..fafe2acd538 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -19,6 +19,10 @@ module MergeRequestsHelper } end + def merge_request_button_visibility(mr, closed) + return 'hidden' if mr.closed? == closed + end + def mr_css_classes(mr) classes = "merge-request" classes << " closed" if mr.closed? diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index ac25d38eb63..f013018ec08 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -456,16 +456,6 @@ class MergeRequest < ActiveRecord::Base ::Gitlab::GitAccess.new(user, project).can_push_to_branch?(target_branch) end - def state_human_name - if merged? - "Merged" - elsif closed? - "Closed" - else - "Open" - end - end - def target_sha @target_sha ||= target_project. repository.commit(target_branch).sha diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml index bff3c3b283d..ed3628a36a3 100644 --- a/app/views/projects/merge_requests/_discussion.html.haml +++ b/app/views/projects/merge_requests/_discussion.html.haml @@ -1,8 +1,7 @@ - content_for :note_actions do - if can?(current_user, :update_merge_request, @merge_request) - - if @merge_request.open? - = link_to 'Close', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-nr btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request" - - if @merge_request.closed? - = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-nr btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request" + = link_to 'Close', merge_request_path(@merge_request, merge_request: {state_event: :close}, format: 'json'), data: {no_turbolinks: true}, method: :put, class: "btn btn-nr btn-grouped btn-close close-mr-link btn-comment js-note-target-close #{merge_request_button_visibility(@merge_request, true)}", title: "Close merge request" + = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen}, format: 'json'), data: {no_turbolinks: true}, method: :put, class: "btn btn-nr btn-grouped btn-reopen reopen-mr-link btn-comment js-note-target-reopen #{merge_request_button_visibility(@merge_request, false)}", title: "Reopen merge request" -#notes= render "projects/notes/notes_with_form" +#notes + = render "projects/notes/notes_with_form" diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml index fc6fb2a0d42..7996d35c462 100644 --- a/app/views/projects/merge_requests/show/_mr_title.html.haml +++ b/app/views/projects/merge_requests/show/_mr_title.html.haml @@ -1,6 +1,12 @@ .detail-page-header - .status-box{ class: status_box_class(@merge_request) } - = @merge_request.state_human_name + - if @merge_request.merged? + .status-box{ class: "status-box-merged" } + Merged + - else + .status-box{ class: "status-box-closed #{merge_request_button_visibility(@merge_request, false)}"} + Closed + .status-box{ class: "status-box-open #{merge_request_button_visibility(@merge_request, true)}"} + Open %span.identifier Merge Request ##{@merge_request.iid} %span.creator @@ -15,11 +21,11 @@ = time_ago_with_tooltip(@merge_request.updated_at, placement: 'bottom') .issue-btn-group.pull-right - - if can?(current_user, :update_merge_request, @merge_request) - - if @merge_request.open? - = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: 'btn btn-nr btn-grouped btn-close', title: 'Close merge request' - = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'btn btn-nr btn-grouped issuable-edit', id: 'edit_merge_request' do - %i.fa.fa-pencil-square-o - Edit - - if @merge_request.closed? - = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'btn btn-nr btn-grouped btn-reopen reopen-mr-link', title: 'Reopen merge request' + - if can?(current_user, :update_merge_request, @merge_request) && !@merge_request.merged? + + = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }, format: 'json'), data: {no_turbolink: true}, method: :put, class: "btn btn-nr btn-grouped btn-reopen reopen-mr-link #{merge_request_button_visibility(@merge_request, false)}", title: 'Reopen merge request' + = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }, format: 'json'), data: {no_turbolink: true}, method: :put, class: "btn btn-nr btn-grouped btn-close #{merge_request_button_visibility(@merge_request, true)}", title: 'Close merge request' + + = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: "btn btn-nr btn-grouped issuable-edit #{merge_request_button_visibility(@merge_request, true)}", id: 'edit_merge_request' do + %i.fa.fa-pencil-square-o + Edit \ No newline at end of file -- cgit v1.2.1 From f71642017ebfd409e20735b621dd3a9fe09add12 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Wed, 6 Jan 2016 07:33:50 -0500 Subject: adds tests (and passes them) for ajax open and close merge requests. --- .../fixtures/merge_requests_show.html.haml | 12 ++- spec/javascripts/issue_spec.js.coffee | 2 +- spec/javascripts/merge_request_spec.js.coffee | 88 ++++++++++++++++++++++ 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/spec/javascripts/fixtures/merge_requests_show.html.haml b/spec/javascripts/fixtures/merge_requests_show.html.haml index 8447dfdda32..fdfa8a273e2 100644 --- a/spec/javascripts/fixtures/merge_requests_show.html.haml +++ b/spec/javascripts/fixtures/merge_requests_show.html.haml @@ -1,4 +1,14 @@ -%a.btn-close +:css + .hidden { display: none !important } + +.flash-container + .flash-alert + .flash-notice + +.status-box.status-box-open Open +.status-box.status-box-closed.hidden Closed +%a.btn-close{"href" => "http://gitlab.com/merge_requests/6/close"} Close +%a.btn-reopen.hidden{"href" => "http://gitlab.com/merge_requests/6/reopen"} Reopen .detail-page-description .description.js-task-list-container diff --git a/spec/javascripts/issue_spec.js.coffee b/spec/javascripts/issue_spec.js.coffee index 7e67c778861..e1c22860da7 100644 --- a/spec/javascripts/issue_spec.js.coffee +++ b/spec/javascripts/issue_spec.js.coffee @@ -44,7 +44,7 @@ describe 'reopen/close issue', -> expect($('div.status-box-closed')).toBeVisible() expect($('div.status-box-open')).toBeHidden() - it 'fails to closes an issue with success:false', -> + it 'fails to close an issue with success:false', -> $.ajax = (obj) -> expect(obj.type).toBe('PUT') diff --git a/spec/javascripts/merge_request_spec.js.coffee b/spec/javascripts/merge_request_spec.js.coffee index 22ebc7039d1..e21bfde38ad 100644 --- a/spec/javascripts/merge_request_spec.js.coffee +++ b/spec/javascripts/merge_request_spec.js.coffee @@ -21,3 +21,91 @@ describe 'MergeRequest', -> expect(req.data.merge_request.description).not.toBe(null) $('.js-task-list-field').trigger('tasklist:changed') + + describe 'reopen/close merge request', -> + fixture.preload('merge_requests_show.html') + beforeEach -> + fixture.load('merge_requests_show.html') + @merge_request = new MergeRequest({}) + it 'closes a merge request', -> + $.ajax = (obj) -> + expect(obj.type).toBe('PUT') + expect(obj.url).toBe('http://gitlab.com/merge_requests/6/close') + obj.success saved:true + + $btnClose = $('a.btn-close') + $btnReopen = $('a.btn-reopen') + expect($btnReopen).toBeHidden() + expect($btnClose.text()).toBe('Close') + expect(typeof $btnClose.prop('disabled')).toBe('undefined') + + $btnClose.trigger('click') + + expect($btnReopen).toBeVisible() + + expect($btnClose).toBeHidden() + expect($('div.status-box-closed')).toBeVisible() + expect($('div.status-box-open')).toBeHidden() + + it 'fails to close a merge request with success:false', -> + + $.ajax = (obj) -> + expect(obj.type).toBe('PUT') + expect(obj.url).toBe('http://goesnowhere.nothing/whereami') + obj.success saved:false + + $btnClose = $('a.btn-close') + $btnReopen = $('a.btn-reopen') + $btnClose.attr('href','http://goesnowhere.nothing/whereami') + expect($btnReopen).toBeHidden() + expect($btnClose.text()).toBe('Close') + expect(typeof $btnClose.prop('disabled')).toBe('undefined') + + $btnClose.trigger('click') + + expect($btnReopen).toBeHidden() + expect($btnClose).toBeVisible() + expect($('div.status-box-closed')).toBeHidden() + expect($('div.status-box-open')).toBeVisible() + expect($('div.flash-alert')).toBeVisible() + expect($('div.flash-alert').text()).toBe('Unable to update this merge request at this time.') + + it 'fails to closes an issue with HTTP error', -> + + $.ajax = (obj) -> + expect(obj.type).toBe('PUT') + expect(obj.url).toBe('http://goesnowhere.nothing/whereami') + obj.error() + + $btnClose = $('a.btn-close') + $btnReopen = $('a.btn-reopen') + $btnClose.attr('href','http://goesnowhere.nothing/whereami') + expect($btnReopen).toBeHidden() + expect($btnClose.text()).toBe('Close') + expect(typeof $btnClose.prop('disabled')).toBe('undefined') + + $btnClose.trigger('click') + + expect($btnReopen).toBeHidden() + expect($btnClose).toBeVisible() + expect($('div.status-box-closed')).toBeHidden() + expect($('div.status-box-open')).toBeVisible() + expect($('div.flash-alert')).toBeVisible() + expect($('div.flash-alert').text()).toBe('Unable to update this merge request at this time.') + + it 'reopens a merge request', -> + $.ajax = (obj) -> + expect(obj.type).toBe('PUT') + expect(obj.url).toBe('http://gitlab.com/merge_requests/6/reopen') + obj.success saved: true + + $btnClose = $('a.btn-close') + $btnReopen = $('a.btn-reopen') + expect($btnReopen.text()).toBe('Reopen') + + $btnReopen.trigger('click') + + expect($btnReopen).toBeHidden() + expect($btnClose).toBeVisible() + expect($('div.status-box-open')).toBeVisible() + expect($('div.status-box-closed')).toBeHidden() \ No newline at end of file -- cgit v1.2.1 From 4d41294d71f2a8910a3aa5d475f8eb3923ca3531 Mon Sep 17 00:00:00 2001 From: Tommy Beadle Date: Wed, 6 Jan 2016 11:42:31 -0500 Subject: Include the user_id in user_*_team system hooks. This fixes an issue where the user_id is not included in the data for user_add_to_team and user_remove_from_team system hooks. The documentation already states that the user_id should be included. --- app/services/system_hooks_service.rb | 1 + spec/services/system_hooks_service_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb index 6dc854ec33d..9f677444f1f 100644 --- a/app/services/system_hooks_service.rb +++ b/app/services/system_hooks_service.rb @@ -101,6 +101,7 @@ class SystemHooksService project_id: model.project.id, user_name: model.user.name, user_email: model.user.email, + user_id: model.user.id, access_level: model.human_access, project_visibility: Project.visibility_levels.key(model.project.visibility_level_field).downcase } diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb index 4455ae7b321..41df4951d16 100644 --- a/spec/services/system_hooks_service_spec.rb +++ b/spec/services/system_hooks_service_spec.rb @@ -13,8 +13,8 @@ describe SystemHooksService, services: true do it { expect(event_data(user, :destroy)).to include(:event_name, :name, :created_at, :updated_at, :email, :user_id) } it { expect(event_data(project, :create)).to include(:event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) } it { expect(event_data(project, :destroy)).to include(:event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) } - it { expect(event_data(project_member, :create)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_email, :access_level, :project_visibility) } - it { expect(event_data(project_member, :destroy)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_email, :access_level, :project_visibility) } + it { expect(event_data(project_member, :create)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_email, :user_id, :access_level, :project_visibility) } + it { expect(event_data(project_member, :destroy)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_email, :user_id, :access_level, :project_visibility) } it { expect(event_data(key, :create)).to include(:username, :key, :id) } it { expect(event_data(key, :destroy)).to include(:username, :key, :id) } -- cgit v1.2.1 From 776d70d11b822e5991d518e91b138853275ef42c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Wed, 6 Jan 2016 19:54:36 -0500 Subject: Use #html_safe instead of #raw in some diff views. #3945 --- app/views/projects/blob/diff.html.haml | 2 +- app/views/projects/diffs/_parallel_view.html.haml | 4 ++-- app/views/projects/diffs/_text_file.html.haml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/projects/blob/diff.html.haml b/app/views/projects/blob/diff.html.haml index 9d8f6ecb3ac..ef23876677a 100644 --- a/app/views/projects/blob/diff.html.haml +++ b/app/views/projects/blob/diff.html.haml @@ -11,7 +11,7 @@ %td.old_line.diff-line-num{data: {linenumber: line_old}} = link_to raw(line_old), "#" %td.new_line= link_to raw(line_new) , "#" - %td.line_content.noteable_line= raw("#{' ' * @form.indent}#{line}") + %td.line_content.noteable_line= "#{' ' * @form.indent}#{line}".html_safe - if @form.unfold? && @form.bottom? && @form.to < @blob.loc %tr.line_holder{ id: @form.to } diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml index 4ded4d2daad..6a7d4f2db20 100644 --- a/app/views/projects/diffs/_parallel_view.html.haml +++ b/app/views/projects/diffs/_parallel_view.html.haml @@ -20,7 +20,7 @@ = link_to raw(line_number_left), "##{line_code_left}", id: line_code_left - if @comments_allowed && can?(current_user, :create_note, @project) = link_to_new_diff_note(line_code_left, 'old') - %td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }= raw(line_content_left) + %td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }= line_content_left.html_safe - if type_right == 'new' - new_line_class = 'new' @@ -33,7 +33,7 @@ = link_to raw(line_number_right), "##{new_line_code}", id: new_line_code - if @comments_allowed && can?(current_user, :create_note, @project) = link_to_new_diff_note(line_code_right, 'new') - %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}= raw(line_content_right) + %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}= line_content_right.html_safe - if @reply_allowed - comments_left, comments_right = organize_comments(type_left, type_right, line_code_left, line_code_right) diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml index 059d0baf45e..5509d5403b0 100644 --- a/app/views/projects/diffs/_text_file.html.haml +++ b/app/views/projects/diffs/_text_file.html.haml @@ -21,8 +21,8 @@ - if @comments_allowed && can?(current_user, :create_note, @project) = link_to_new_diff_note(line_code) %td.new_line{data: {linenumber: line.new_pos}} - = link_to raw(type == "old" ? " " : line.new_pos) , "##{line_code}", id: line_code - %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw(diff_line_content(line.text)) + = link_to raw(type == "old" ? " " : line.new_pos), "##{line_code}", id: line_code + %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= diff_line_content(line.text).html_safe - if @reply_allowed - comments = @line_notes.select { |n| n.line_code == line_code && n.active? }.sort_by(&:created_at) -- cgit v1.2.1 From 1494bb3f253b2e37065080c27af22ec531966ab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Wed, 6 Jan 2016 21:01:44 -0500 Subject: Force white theme when viewing diffs. #3945 --- app/views/projects/diffs/_parallel_view.html.haml | 2 +- app/views/projects/diffs/_text_file.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml index 6a7d4f2db20..2a43bbd11f2 100644 --- a/app/views/projects/diffs/_parallel_view.html.haml +++ b/app/views/projects/diffs/_parallel_view.html.haml @@ -1,5 +1,5 @@ / Side-by-side diff view -%div.text-file.diff-wrap-lines.code.file-content.js-syntax-highlight{ class: user_color_scheme } +%div.text-file.diff-wrap-lines.code.file-content.js-syntax-highlight.white %table - parallel_diff(diff_file, index).each do |line| - type_left = line[0] diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml index 5509d5403b0..8e86219155f 100644 --- a/app/views/projects/diffs/_text_file.html.haml +++ b/app/views/projects/diffs/_text_file.html.haml @@ -3,7 +3,7 @@ .suppressed-container %a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show. -%table.text-file.code.js-syntax-highlight{ class: [user_color_scheme, too_big ? 'hide' : ''] } +%table.text-file.code.js-syntax-highlight.white{ class: too_big ? 'hide' : '' } - last_line = 0 - diff_file.highlighted_diff_lines.each_with_index do |line, index| -- cgit v1.2.1 From ba9799b42f5bc861df1fc5d41c149cf72e9daf04 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 7 Jan 2016 10:39:02 +0100 Subject: Update ./doc/api --- doc/api/projects.md | 36 +++++++++++++++++++++++++++++++++--- lib/api/projects.rb | 9 +++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 0ca81ffd49e..96a3f08490c 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -76,7 +76,14 @@ Parameters: "updated_at": "2013-09-30T13: 46: 02Z" }, "archived": false, - "avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png" + "avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png", + "shared_runners_enabled": true, + "forks_count": 0, + "star_count": 0, + "build_allow_git_fetch": true, + "build_coverage_regex": null, + "build_timeout": 3600, + "runners_token": "4f9e77be0eed5ef29548fccda3b371" }, { "id": 6, @@ -129,7 +136,14 @@ Parameters: } }, "archived": false, - "avatar_url": null + "avatar_url": null, + "shared_runners_enabled": true, + "forks_count": 0, + "star_count": 0, + "build_allow_git_fetch": true, + "build_coverage_regex": null, + "build_timeout": 3600, + "runners_token": "b8547b1dc37721d05889db52fa2f02" } ] ``` @@ -244,7 +258,14 @@ Parameters: } }, "archived": false, - "avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png" + "avatar_url": "http://example.com/uploads/project/avatar/3/uploads/avatar.png", + "shared_runners_enabled": true, + "forks_count": 0, + "star_count": 0, + "build_allow_git_fetch": true, + "build_coverage_regex": null, + "build_timeout": 3600, + "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b" } ``` @@ -409,6 +430,9 @@ Parameters: - `public` (optional) - if `true` same as setting visibility_level = 20 - `visibility_level` (optional) - `import_url` (optional) +- `build_allow_git_fetch` (optional) +- `build_timeout` (optional) +- `build_coverage_regex` (optional) ### Create project for user @@ -431,6 +455,9 @@ Parameters: - `public` (optional) - if `true` same as setting visibility_level = 20 - `visibility_level` (optional) - `import_url` (optional) +- `build_allow_git_fetch` (optional) +- `build_timeout` (optional) +- `build_coverage_regex` (optional) ### Edit project @@ -454,6 +481,9 @@ Parameters: - `snippets_enabled` (optional) - `public` (optional) - if `true` same as setting visibility_level = 20 - `visibility_level` (optional) +- `build_allow_git_fetch` (optional) +- `build_timeout` (optional) +- `build_coverage_regex` (optional) On success, method returns 200 with the updated project. If parameters are invalid, 400 is returned. diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 7dd6b133f9b..31b081266a8 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -98,6 +98,9 @@ module API # public (optional) - if true same as setting visibility_level = 20 # visibility_level (optional) - 0 by default # import_url (optional) + # build_allow_git_fetch (optional) + # build_timeout (optional) + # build_coverage_regex (optional) # Example Request # POST /projects post do @@ -146,6 +149,9 @@ module API # public (optional) - if true same as setting visibility_level = 20 # visibility_level (optional) # import_url (optional) + # build_allow_git_fetch (optional) + # build_timeout (optional) + # build_coverage_regex (optional) # Example Request # POST /projects/user/:user_id post "user/:user_id" do @@ -207,6 +213,9 @@ module API # shared_runners_enabled (optional) # public (optional) - if true same as setting visibility_level = 20 # visibility_level (optional) - visibility level of a project + # build_allow_git_fetch (optional) + # build_timeout (optional) + # build_coverage_regex (optional) # Example Request # PUT /projects/:id put ':id' do -- cgit v1.2.1 From b0a77a224857ed45afaf642b26ce3ba87d9828a7 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 7 Jan 2016 11:04:25 +0100 Subject: Update ./doc/api --- doc/api/README.md | 1 + doc/api/triggers.md | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 doc/api/triggers.md diff --git a/doc/api/README.md b/doc/api/README.md index 25a31b235cc..1838bcc0bb9 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -23,6 +23,7 @@ - [Namespaces](namespaces.md) - [Settings](settings.md) - [Keys](keys.md) +- [Triggers](triggers.md) ## Clients diff --git a/doc/api/triggers.md b/doc/api/triggers.md new file mode 100644 index 00000000000..6adcc8fe3b8 --- /dev/null +++ b/doc/api/triggers.md @@ -0,0 +1,94 @@ +# Triggers + +## List project triggers + +Get a list of project triggers + +``` +GET /projects/:id/triggers +``` + +Parameters: + +- `id` (required) - The ID of a project + +```json +[ + { + "created_at": "2015-12-23T16:24:34.716Z", + "deleted_at": null, + "id": 1, + "last_used": "2016-01-04T15:41:21.986Z", + "token": "fbdb730c2fbdb095a0862dbd8ab88b", + "updated_at": "2015-12-23T16:24:34.716Z" + }, + { + "created_at": "2015-12-23T16:25:56.760Z", + "deleted_at": null, + "id": 2, + "last_used": null, + "token": "7b9148c158980bbd9bcea92c17522d", + "updated_at": "2015-12-23T16:25:56.760Z" + } +] +``` + +## Get trigger details + +Get details of trigger of a project + +``` +GET /projects/:id/triggers/:trigger_id +``` + +Parameters: + +- `id` (required) - The ID of a project +- `trigger_id` (required) - The ID of a trigger + +```json +{ + "created_at": "2015-12-23T16:25:56.760Z", + "deleted_at": null, + "id": 2, + "last_used": null, + "token": "7b9148c158980bbd9bcea92c17522d", + "updated_at": "2015-12-23T16:25:56.760Z" +} +``` + +## Create a project trigger + +Create a trigger for a project + +``` +POST /projects/:id/triggers +``` + +Parameters: + +- `id` (required) - The ID of a project + +```json +{ + "created_at": "2016-01-07T09:53:58.235Z", + "deleted_at": null, + "id": 5, + "last_used": null, + "token": "6d056f63e50fe6f8c5f8f4aa10edb7", + "updated_at": "2016-01-07T09:53:58.235Z" +} +``` + +## Remove a project trigger + +Remove a trigger of a project + +``` +DELETE /projects/:id/triggers/:trigger_id +``` + +Parameters: + +- `id` (required) - The ID of a project +- `trigger_id` (required) - The ID of a trigger -- cgit v1.2.1 From b60c146267dfa8dc1c170426e1817c6b2a168d1a Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 7 Jan 2016 13:49:38 +0100 Subject: Change :variable_id to :key as resource ID in API --- app/models/ci/variable.rb | 6 +++++- lib/api/variables.rb | 41 ++++++++++++++---------------------- spec/requests/api/variables_spec.rb | 42 +++++++++++++------------------------ 3 files changed, 36 insertions(+), 53 deletions(-) diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb index 0e2712086ca..1d9ee91a31c 100644 --- a/app/models/ci/variable.rb +++ b/app/models/ci/variable.rb @@ -18,8 +18,12 @@ module Ci belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id - validates_presence_of :key validates_uniqueness_of :key, scope: :gl_project_id + validates :key, + presence: true, + length: { within: 0..255 }, + format: { with: /\A[a-zA-Z0-9_]+\z/, + message: "can contain only letters, digits and '_'." } attr_encrypted :value, mode: :per_attribute_iv_and_salt, key: Gitlab::Application.secrets.db_key_base end diff --git a/lib/api/variables.rb b/lib/api/variables.rb index b8bbcb6ce3b..cc038e5731d 100644 --- a/lib/api/variables.rb +++ b/lib/api/variables.rb @@ -22,19 +22,12 @@ module API # # Parameters: # id (required) - The ID of a project - # variable_id (required) - The ID OR `key` of variable to show; if variable_id contains only digits it's treated - # as ID other ways it's treated as `key` + # key (required) - The `key` of variable # Example Request: - # GET /projects/:id/variables/:variable_id - get ':id/variables/:variable_id' do - variable_id = params[:variable_id] - variables = user_project.variables - variables = - if variable_id.match(/^\d+$/) - variables.where(id: variable_id.to_i) - else - variables.where(key: variable_id) - end + # GET /projects/:id/variables/:key + get ':id/variables/:key' do + key = params[:key] + variables = user_project.variables.where(key: key) return not_found!('Variable') if variables.empty? @@ -45,8 +38,8 @@ module API # # Parameters: # id (required) - The ID of a project - # key (required) - The key of variable being created - # value (required) - The value of variable being created + # key (required) - The key of variable + # value (required) - The value of variable # Example Request: # POST /projects/:id/variables post ':id/variables' do @@ -63,17 +56,15 @@ module API # # Parameters: # id (required) - The ID of a project - # variable_id (required) - The ID of a variable - # key (optional) - new value for `key` field of variable - # value (optional) - new value for `value` field of variable + # key (optional) - The `key` of variable + # value (optional) - New value for `value` field of variable # Example Request: - # PUT /projects/:id/variables/:variable_id - put ':id/variables/:variable_id' do - variable = user_project.variables.where(id: params[:variable_id].to_i).first + # PUT /projects/:id/variables/:key + put ':id/variables/:key' do + variable = user_project.variables.where(key: params[:key]).first return not_found!('Variable') unless variable - variable.key = params[:key] variable.value = params[:value] variable.save! @@ -84,11 +75,11 @@ module API # # Parameters: # id (required) - The ID of a project - # variable_id (required) - The ID of a variable + # key (required) - The ID of a variable # Exanoke Reqyest: - # DELETE /projects/:id/variables/:variable_id - delete ':id/variables/:variable_id' do - variable = user_project.variables.where(id: params[:variable_id].to_i).first + # DELETE /projects/:id/variables/:key + delete ':id/variables/:key' do + variable = user_project.variables.where(key: params[:key]).first return not_found!('Variable') unless variable diff --git a/spec/requests/api/variables_spec.rb b/spec/requests/api/variables_spec.rb index bf0dd77473a..214d7d5a0cc 100644 --- a/spec/requests/api/variables_spec.rb +++ b/spec/requests/api/variables_spec.rb @@ -37,26 +37,17 @@ describe API::API, api: true do end end - describe 'GET /projects/:id/variables/:variable_id' do + describe 'GET /projects/:id/variables/:key' do context 'authorized user with proper permissions' do - it 'should return project variable details when ID is used as :variable_id' do - get api("/projects/#{project.id}/variables/#{variable.id}", user) - - expect(response.status).to eq(200) - expect(json_response['key']).to eq(variable.key) - expect(json_response['value']).to eq(variable.value) - end - - it 'should return project variable details when `key` is used as :variable_id' do + it 'should return project variable details' do get api("/projects/#{project.id}/variables/#{variable.key}", user) expect(response.status).to eq(200) - expect(json_response['id']).to eq(variable.id) expect(json_response['value']).to eq(variable.value) end it 'should responde with 404 Not Found if requesting non-existing variable' do - get api("/projects/#{project.id}/variables/9999", user) + get api("/projects/#{project.id}/variables/non_existing_variable", user) expect(response.status).to eq(404) end @@ -64,7 +55,7 @@ describe API::API, api: true do context 'authorized user with invalid permissions' do it 'should not return project variable details' do - get api("/projects/#{project.id}/variables/#{variable.id}", user2) + get api("/projects/#{project.id}/variables/#{variable.key}", user2) expect(response.status).to eq(403) end @@ -72,7 +63,7 @@ describe API::API, api: true do context 'unauthorized user' do it 'should not return project variable details' do - get api("/projects/#{project.id}/variables/#{variable.id}") + get api("/projects/#{project.id}/variables/#{variable.key}") expect(response.status).to eq(401) end @@ -117,26 +108,23 @@ describe API::API, api: true do end end - describe 'PUT /projects/:id/variables/:variable_id' do + describe 'PUT /projects/:id/variables/:key' do context 'authorized user with proper permissions' do it 'should update variable data' do initial_variable = project.variables.first - key_before = initial_variable.key value_before = initial_variable.value - put api("/projects/#{project.id}/variables/#{variable.id}", user), key: 'TEST_VARIABLE_1_UP', value: 'VALUE_1_UP' + put api("/projects/#{project.id}/variables/#{variable.key}", user), value: 'VALUE_1_UP' updated_variable = project.variables.first expect(response.status).to eq(200) - expect(key_before).to eq(variable.key) expect(value_before).to eq(variable.value) - expect(updated_variable.key).to eq('TEST_VARIABLE_1_UP') expect(updated_variable.value).to eq('VALUE_1_UP') end it 'should responde with 404 Not Found if requesting non-existing variable' do - put api("/projects/#{project.id}/variables/9999", user) + put api("/projects/#{project.id}/variables/non_existing_variable", user) expect(response.status).to eq(404) end @@ -144,7 +132,7 @@ describe API::API, api: true do context 'authorized user with invalid permissions' do it 'should not update variable' do - put api("/projects/#{project.id}/variables/#{variable.id}", user2) + put api("/projects/#{project.id}/variables/#{variable.key}", user2) expect(response.status).to eq(403) end @@ -152,24 +140,24 @@ describe API::API, api: true do context 'unauthorized user' do it 'should not update variable' do - put api("/projects/#{project.id}/variables/#{variable.id}") + put api("/projects/#{project.id}/variables/#{variable.key}") expect(response.status).to eq(401) end end end - describe 'DELETE /projects/:id/variables/:variable_id' do + describe 'DELETE /projects/:id/variables/:key' do context 'authorized user with proper permissions' do it 'should delete variable' do expect do - delete api("/projects/#{project.id}/variables/#{variable.id}", user) + delete api("/projects/#{project.id}/variables/#{variable.key}", user) end.to change{project.variables.count}.by(-1) expect(response.status).to eq(200) end it 'should responde with 404 Not Found if requesting non-existing variable' do - delete api("/projects/#{project.id}/variables/9999", user) + delete api("/projects/#{project.id}/variables/non_existing_variable", user) expect(response.status).to eq(404) end @@ -177,7 +165,7 @@ describe API::API, api: true do context 'authorized user with invalid permissions' do it 'should not delete variable' do - delete api("/projects/#{project.id}/variables/#{variable.id}", user2) + delete api("/projects/#{project.id}/variables/#{variable.key}", user2) expect(response.status).to eq(403) end @@ -185,7 +173,7 @@ describe API::API, api: true do context 'unauthorized user' do it 'should not delete variable' do - delete api("/projects/#{project.id}/variables/#{variable.id}") + delete api("/projects/#{project.id}/variables/#{variable.key}") expect(response.status).to eq(401) end -- cgit v1.2.1 From b60445906849e84ff52ac6a5d7d501bb5a21eb60 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 7 Jan 2016 14:10:49 +0100 Subject: Update ./doc/api --- doc/api/README.md | 1 + doc/api/variables.md | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/api/entities.rb | 2 +- 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 doc/api/variables.md diff --git a/doc/api/README.md b/doc/api/README.md index 25a31b235cc..198b4ddfee1 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -23,6 +23,7 @@ - [Namespaces](namespaces.md) - [Settings](settings.md) - [Keys](keys.md) +- [Variables](variables.md) ## Clients diff --git a/doc/api/variables.md b/doc/api/variables.md new file mode 100644 index 00000000000..cdc9ba42254 --- /dev/null +++ b/doc/api/variables.md @@ -0,0 +1,106 @@ +# Variables + +## Variables keys + +All variable keys must contains only letters, digits and '\_'. They must also be no longer than 255 characters. + +## List project variables + +Get list of variables of a project. + +``` +GET /projects/:id/variables +``` + +Parameters: + +- `id` (required) - The ID of a project + +```json +[ + { + "key": "TEST_VARIABLE_1", + "value": "TEST_1" + }, + { + "key": "TEST_VARIABLE_2", + "value": "TEST_2" + } +] +``` + +## Show variable details + +Get details of specifica variable of a project. + +``` +GET /projects/:id/variables/:key +``` + +Parameters: + +- `id` (required) - The ID of a project +- `key` (required) - The `key` of variable + +```json +{ + "key": "TEST_VARIABLE_1", + "value": "TEST_1" +} +``` + +## Create variable + +Create new variable in project. + +``` +POST /projects/:id/variables +``` + +Parameters: + +- `id` (required) - The ID of a project +- `key` (required) - The `key` for variable +- `value` (required) - The `value` for variable + +```json +{ + "key": "NEW_VARIABLE", + "value": "new value" +} +``` + +## Update variable + +Update variable. + +``` +PUT /projects/:id/variables/:key +``` + +Parameters: + +- `id` (required) - The ID of a project +- `key` (required) - The `key` for variable +- `value` (required) - The `value` for variable + +```json +{ + "key": "NEW_VARIABLE", + "value": "updated value" +} +``` + +## Remove variable + +Remove variable. + +``` +DELETE /projects/:id/variables/:key +``` + +Parameters: + +- `id` (required) - The ID of a project +- `key` (required) - The `key` for variable + diff --git a/lib/api/entities.rb b/lib/api/entities.rb index f71d072f269..db3164d9d9c 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -367,7 +367,7 @@ module API end class Variable < Grape::Entity - expose :id, :key, :value + expose :key, :value end end end -- cgit v1.2.1 From ab9612df8dd97d83a94a8290f1530760e5cc7d2e Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Thu, 7 Jan 2016 11:47:39 -0500 Subject: initial json requests instead of HTML --- app/assets/javascripts/merge_request.js.coffee | 6 ++++ .../javascripts/merge_request_widget.js.coffee | 5 +-- .../projects/merge_requests_controller.rb | 24 ++++++++++--- app/helpers/merge_requests_helper.rb | 9 +++++ .../merge_requests/widget/_closed.html.haml | 2 +- .../merge_requests/widget/_locked.html.haml | 2 +- .../merge_requests/widget/_merged.html.haml | 2 +- .../projects/merge_requests/widget/_open.html.haml | 39 +++++++++++----------- .../projects/merge_requests/widget/_show.html.haml | 14 +++----- .../merge_requests/widget/open/_archived.html.haml | 2 +- 10 files changed, 66 insertions(+), 39 deletions(-) diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee index 8c321319b30..c6c7f37707f 100644 --- a/app/assets/javascripts/merge_request.js.coffee +++ b/app/assets/javascripts/merge_request.js.coffee @@ -63,12 +63,18 @@ class @MergeRequest $('a.btn-reopen').removeClass('hidden') $('div.status-box-closed').removeClass('hidden') $('div.status-box-open').addClass('hidden') + + $('div.mr-state-widget-closed').removeClass('hidden') + $('div.mr-state-widget-opened').addClass('hidden') else $('a.btn-reopen').addClass('hidden') $('a.issuable-edit').removeClass('hidden') $('a.btn-close').removeClass('hidden') $('div.status-box-closed').addClass('hidden') $('div.status-box-open').removeClass('hidden') + + $('div.mr-state-widget-closed').addClass('hidden') + $('div.mr-state-widget-opened').removeClass('hidden') else new Flash(mergeRequestFailMessage, 'alert') $this.prop('disabled', false) diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee index 738ffc8343b..f0a687f79b1 100644 --- a/app/assets/javascripts/merge_request_widget.js.coffee +++ b/app/assets/javascripts/merge_request_widget.js.coffee @@ -28,8 +28,9 @@ class @MergeRequestWidget getMergeStatus: -> $.get @opts.url_to_automerge_check, (data) -> - $('.mr-state-widget').replaceWith(data) - + console.log("data",data); + # $('div.mr-state-widget.mr-state-widget-opened').replaceWith(data) + getCiStatus: -> if @opts.ci_enable $.get @opts.url_to_ci_check, (data) => diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index ab5c953189c..e3c4aa4873a 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -48,9 +48,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController @note_counts = Note.where(commit_id: @merge_request.commits.map(&:id)). group(:commit_id).count + json_merge_request = @merge_requests.as_json + respond_to do |format| format.html - format.json { render json: @merge_request } + format.json do + render json: { + hi: "yes" + } + end format.diff { render text: @merge_request.to_diff(current_user) } format.patch { render text: @merge_request.to_patch(current_user) } end @@ -143,7 +149,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController format.json do render json: { saved: @merge_request.valid?, - assignee_avatar_url: @merge_request.assignee.try(:avatar_url) + assignee_avatar_url: @merge_request.assignee.try(:avatar_url), + closed_event: @merge_request.closed_event } end end @@ -154,8 +161,17 @@ class Projects::MergeRequestsController < Projects::ApplicationController def merge_check @merge_request.check_if_can_be_merged if @merge_request.unchecked? - - render partial: "projects/merge_requests/widget/show.html.haml", layout: false + puts @merge_request.merge_status + respond_to do |format| + format.json do + render json: { + can_be_merged: @merge_request.merge_status == :can_be_merged + } + end + format.html do + render partial: "projects/merge_requests/widget/show.html.haml", layout: false + end + end end def cancel_merge_when_build_succeeds diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index fafe2acd538..6306450ca26 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -23,6 +23,15 @@ module MergeRequestsHelper return 'hidden' if mr.closed? == closed end + def merge_request_widget_visibility(mr, *states) + states.each do |state| + if mr.state == state + return + end + end + return 'hidden' + end + def mr_css_classes(mr) classes = "merge-request" classes << " closed" if mr.closed? diff --git a/app/views/projects/merge_requests/widget/_closed.html.haml b/app/views/projects/merge_requests/widget/_closed.html.haml index f3cc0e7e8a1..46ee22ec873 100644 --- a/app/views/projects/merge_requests/widget/_closed.html.haml +++ b/app/views/projects/merge_requests/widget/_closed.html.haml @@ -1,4 +1,4 @@ -.mr-state-widget +.mr-state-widget.mr-state-widget-closed{class: merge_request_widget_visibility(@merge_request, 'closed')} = render 'projects/merge_requests/widget/heading' .mr-widget-body %h4 diff --git a/app/views/projects/merge_requests/widget/_locked.html.haml b/app/views/projects/merge_requests/widget/_locked.html.haml index 78d0783cba0..55ecd69a6ce 100644 --- a/app/views/projects/merge_requests/widget/_locked.html.haml +++ b/app/views/projects/merge_requests/widget/_locked.html.haml @@ -1,4 +1,4 @@ -.mr-state-widget +.mr-state-widget.mr-state-widget-locked{class: merge_request_widget_visibility(@merge_request, 'locked')} = render 'projects/merge_requests/widget/heading' .mr-widget-body %h4 diff --git a/app/views/projects/merge_requests/widget/_merged.html.haml b/app/views/projects/merge_requests/widget/_merged.html.haml index d1d602eecdc..2bb50967023 100644 --- a/app/views/projects/merge_requests/widget/_merged.html.haml +++ b/app/views/projects/merge_requests/widget/_merged.html.haml @@ -1,4 +1,4 @@ -.mr-state-widget +.mr-state-widget.mr-state-widget-merged{class: merge_request_widget_visibility(@merge_request, 'merged')} = render 'projects/merge_requests/widget/heading' .mr-widget-body %h4 diff --git a/app/views/projects/merge_requests/widget/_open.html.haml b/app/views/projects/merge_requests/widget/_open.html.haml index 55dbae598d3..2257a166460 100644 --- a/app/views/projects/merge_requests/widget/_open.html.haml +++ b/app/views/projects/merge_requests/widget/_open.html.haml @@ -1,24 +1,23 @@ -.mr-state-widget +.mr-state-widget.mr-state-widget-opened{class: merge_request_widget_visibility(@merge_request, "opened","reopened")} = render 'projects/merge_requests/widget/heading' - .mr-widget-body - - if @project.archived? - = render 'projects/merge_requests/widget/open/archived' - - elsif @merge_request.commits.blank? - = render 'projects/merge_requests/widget/open/nothing' - - elsif @merge_request.branch_missing? - = render 'projects/merge_requests/widget/open/missing_branch' - - elsif @merge_request.unchecked? - = render 'projects/merge_requests/widget/open/check' - - elsif @merge_request.cannot_be_merged? - = render 'projects/merge_requests/widget/open/conflicts' - - elsif @merge_request.work_in_progress? - = render 'projects/merge_requests/widget/open/wip' - - elsif @merge_request.merge_when_build_succeeds? - = render 'projects/merge_requests/widget/open/merge_when_build_succeeds' - - elsif !@merge_request.can_be_merged_by?(current_user) - = render 'projects/merge_requests/widget/open/not_allowed' - - elsif @merge_request.can_be_merged? - = render 'projects/merge_requests/widget/open/accept' + .mr-widget-body.merge-request-archived{class: ("hidden" unless @project.archived?)} + = render 'projects/merge_requests/widget/open/archived' + .mr-widget-body.merge-request-blank{class: ("hidden" unless @merge_request.commits.blank?)} + = render 'projects/merge_requests/widget/open/nothing' + .mr-widget-body.merge-request-branch-missing{class: ("hidden" unless @merge_request.branch_missing?)} + = render 'projects/merge_requests/widget/open/missing_branch' + .mr-widget-body.merge-request-unchecked{class: ("hidden" unless @merge_request.unchecked?)} + = render 'projects/merge_requests/widget/open/check' + .mr-widget-body.merge-request-cannot-be-merged{class: ("hidden" unless @merge_request.cannot_be_merged?)} + = render 'projects/merge_requests/widget/open/conflicts' + .mr-widget-body.merge-request-work-in-progress{class: ("hidden" unless @merge_request.work_in_progress?)} + = render 'projects/merge_requests/widget/open/wip' + .mr-widget-body.merge-request-merge-when-build-succeeds{class: ("hidden" unless @merge_request.merge_when_build_succeeds?)} + = render 'projects/merge_requests/widget/open/merge_when_build_succeeds' + .mr-widget-body.not-allowed{class: ("hidden" if @merge_request.can_be_merged_by?(current_user))} + = render 'projects/merge_requests/widget/open/not_allowed' + .mr-widget-body.merge-request-archived.can-be-merged{class: ("hidden" unless @merge_request.can_be_merged?)} + = render 'projects/merge_requests/widget/open/accept' - if @closes_issues.present? .mr-widget-footer diff --git a/app/views/projects/merge_requests/widget/_show.html.haml b/app/views/projects/merge_requests/widget/_show.html.haml index a489d4f9b24..d8f81dab067 100644 --- a/app/views/projects/merge_requests/widget/_show.html.haml +++ b/app/views/projects/merge_requests/widget/_show.html.haml @@ -1,17 +1,13 @@ -- if @merge_request.open? - = render 'projects/merge_requests/widget/open' -- elsif @merge_request.merged? - = render 'projects/merge_requests/widget/merged' -- elsif @merge_request.closed? - = render 'projects/merge_requests/widget/closed' -- elsif @merge_request.locked? - = render 'projects/merge_requests/widget/locked' += render 'projects/merge_requests/widget/open' += render 'projects/merge_requests/widget/merged' += render 'projects/merge_requests/widget/closed' += render 'projects/merge_requests/widget/locked' :javascript var merge_request_widget; merge_request_widget = new MergeRequestWidget({ - url_to_automerge_check: "#{merge_check_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}", + url_to_automerge_check: "#{merge_check_namespace_project_merge_request_path(@project.namespace, @project, @merge_request, format: :json)}", check_enable: #{@merge_request.unchecked? ? "true" : "false"}, url_to_ci_check: "#{ci_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}", ci_enable: #{@project.ci_service ? "true" : "false"}, diff --git a/app/views/projects/merge_requests/widget/open/_archived.html.haml b/app/views/projects/merge_requests/widget/open/_archived.html.haml index ab30fa6b243..0d61e56d8fb 100644 --- a/app/views/projects/merge_requests/widget/open/_archived.html.haml +++ b/app/views/projects/merge_requests/widget/open/_archived.html.haml @@ -1,4 +1,4 @@ -%h4 +%h4 Project is archived %p This merge request cannot be merged because archived projects cannot be written to. -- cgit v1.2.1 From e0ec69d919cb44194e76034f2324ec0d4f5f1df6 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 7 Jan 2016 18:48:33 +0100 Subject: Change 'trigger_id' to 'token' as resource ID in triggers API --- doc/api/triggers.md | 12 ++++------- lib/api/entities.rb | 2 +- lib/api/triggers.rb | 25 ++++++++--------------- spec/requests/api/triggers_spec.rb | 42 +++++++++++++------------------------- 4 files changed, 27 insertions(+), 54 deletions(-) diff --git a/doc/api/triggers.md b/doc/api/triggers.md index 6adcc8fe3b8..4150d7b4c10 100644 --- a/doc/api/triggers.md +++ b/doc/api/triggers.md @@ -17,7 +17,6 @@ Parameters: { "created_at": "2015-12-23T16:24:34.716Z", "deleted_at": null, - "id": 1, "last_used": "2016-01-04T15:41:21.986Z", "token": "fbdb730c2fbdb095a0862dbd8ab88b", "updated_at": "2015-12-23T16:24:34.716Z" @@ -25,7 +24,6 @@ Parameters: { "created_at": "2015-12-23T16:25:56.760Z", "deleted_at": null, - "id": 2, "last_used": null, "token": "7b9148c158980bbd9bcea92c17522d", "updated_at": "2015-12-23T16:25:56.760Z" @@ -38,19 +36,18 @@ Parameters: Get details of trigger of a project ``` -GET /projects/:id/triggers/:trigger_id +GET /projects/:id/triggers/:token ``` Parameters: - `id` (required) - The ID of a project -- `trigger_id` (required) - The ID of a trigger +- `token` (required) - The `token` of a trigger ```json { "created_at": "2015-12-23T16:25:56.760Z", "deleted_at": null, - "id": 2, "last_used": null, "token": "7b9148c158980bbd9bcea92c17522d", "updated_at": "2015-12-23T16:25:56.760Z" @@ -73,7 +70,6 @@ Parameters: { "created_at": "2016-01-07T09:53:58.235Z", "deleted_at": null, - "id": 5, "last_used": null, "token": "6d056f63e50fe6f8c5f8f4aa10edb7", "updated_at": "2016-01-07T09:53:58.235Z" @@ -85,10 +81,10 @@ Parameters: Remove a trigger of a project ``` -DELETE /projects/:id/triggers/:trigger_id +DELETE /projects/:id/triggers/:token ``` Parameters: - `id` (required) - The ID of a project -- `trigger_id` (required) - The ID of a trigger +- `token` (required) - The `token` of a trigger diff --git a/lib/api/entities.rb b/lib/api/entities.rb index bc0cd76a2b8..37c483b45ec 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -367,7 +367,7 @@ module API end class Trigger < Grape::Entity - expose :id, :token, :created_at, :updated_at, :deleted_at + expose :token, :created_at, :updated_at, :deleted_at expose :last_used do |repo_obj, _options| if repo_obj.respond_to?(:last_trigger_request) request = repo_obj.last_trigger_request diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb index 0e548b936cd..25bb8aef20b 100644 --- a/lib/api/triggers.rb +++ b/lib/api/triggers.rb @@ -66,23 +66,14 @@ module API # # Parameters: # id (required) - The ID of a project - # trigger_id (required) - The ID or `token` of a trigger to show; if trigger_id contains only digits it's - # treated as ID other ways it's reated as `key` + # token (required) - The `token` of a trigger # Example Request: - # GET /projects/:id/triggers/:trigger_id - get ':id/triggers/:trigger_id' do + # GET /projects/:id/triggers/:token + get ':id/triggers/:token' do authenticate! authorize_admin_project - trigger_id = params[:trigger_id] - triggers = user_project.triggers - triggers = - if trigger_id.match(/^\d+$/) - triggers.where(id: trigger_id.to_i) - else - triggers.where(token: trigger_id) - end - + triggers = user_project.triggers.where(token: params[:token]) return not_found!('Trigger') if triggers.empty? present triggers.first, with: Entities::Trigger @@ -108,14 +99,14 @@ module API # # Parameters: # id (required) - The ID of a project - # trigger_id - The ID of trigger to delete + # token (required) - The `token` of a trigger # Example Request: - # DELETE /projects/:id/triggers/:trigger_id - delete ':id/triggers/:trigger_id' do + # DELETE /projects/:id/triggers/:token + delete ':id/triggers/:token' do authenticate! authorize_admin_project - trigger = user_project.triggers.where(id: params[:trigger_id].to_i).first + trigger = user_project.triggers.where(token: params[:token]).first return not_found!('Trigger') unless trigger trigger.destroy diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index c1c2bb04b29..e8d89426ec0 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -93,8 +93,7 @@ describe API::API do expect(response.status).to eq(200) expect(json_response).to be_a(Array) - expect(json_response[0]['token']).to eq(trigger_token) - expect(json_response[1]['token']).to eq(trigger_token_2) + expect(json_response[0]).to have_key('token') end end @@ -115,30 +114,17 @@ describe API::API do end end - describe 'GET /projects/:id/triggers/:triggers_id' do + describe 'GET /projects/:id/triggers/:token' do context 'authenticated user with valid permissions' do - context 'ID is used as :trigger_id' do - it 'should return trigger details' do - get api("/projects/#{project.id}/triggers/#{trigger.id}", user) + it 'should return trigger details' do + get api("/projects/#{project.id}/triggers/#{trigger.token}", user) - expect(response.status).to eq(200) - expect(json_response).to be_a(Hash) - expect(json_response['token']).to eq(trigger_token) - end - end - - context '`token` is used as :trigger_id' do - it 'should return trigger details' do - get api("/projects/#{project.id}/triggers/#{trigger.token}", user) - - expect(response.status).to eq(200) - expect(json_response).to be_a(Hash) - expect(json_response['id']).to eq(trigger.id) - end + expect(response.status).to eq(200) + expect(json_response).to be_a(Hash) end it 'should responde with 404 Not Found if requesting non-existing trigger' do - get api("/projects/#{project.id}/triggers/9999", user) + get api("/projects/#{project.id}/triggers/abcdef012345", user) expect(response.status).to eq(404) end @@ -146,7 +132,7 @@ describe API::API do context 'authenticated user with invalid permissions' do it 'should not return triggers list' do - get api("/projects/#{project.id}/triggers/#{trigger.id}", user2) + get api("/projects/#{project.id}/triggers/#{trigger.token}", user2) expect(response.status).to eq(403) end @@ -154,7 +140,7 @@ describe API::API do context 'unauthentikated user' do it 'should not return triggers list' do - get api("/projects/#{project.id}/triggers/#{trigger.id}") + get api("/projects/#{project.id}/triggers/#{trigger.token}") expect(response.status).to eq(401) end @@ -190,17 +176,17 @@ describe API::API do end end - describe 'DELETE /projects/:id/triggers/:trigger_id' do + describe 'DELETE /projects/:id/triggers/:token' do context 'authenticated user with valid permissions' do it 'should delete trigger' do expect do - delete api("/projects/#{project.id}/triggers/#{trigger.id}", user) + delete api("/projects/#{project.id}/triggers/#{trigger.token}", user) end.to change{project.triggers.count}.by(-1) expect(response.status).to eq(200) end it 'should responde with 404 Not Found if requesting non-existing trigger' do - delete api("/projects/#{project.id}/triggers/9999", user) + delete api("/projects/#{project.id}/triggers/abcdef012345", user) expect(response.status).to eq(404) end @@ -208,7 +194,7 @@ describe API::API do context 'authenticated user with invalid permissions' do it 'should not delete trigger' do - delete api("/projects/#{project.id}/triggers/#{trigger.id}", user2) + delete api("/projects/#{project.id}/triggers/#{trigger.token}", user2) expect(response.status).to eq(403) end @@ -216,7 +202,7 @@ describe API::API do context 'unauthentikated user' do it 'should not delete trigger' do - delete api("/projects/#{project.id}/triggers/#{trigger.id}") + delete api("/projects/#{project.id}/triggers/#{trigger.token}") expect(response.status).to eq(401) end -- cgit v1.2.1 From dada25d4472ec9ad601447fdd12da2301ac9ee79 Mon Sep 17 00:00:00 2001 From: Tommy Beadle Date: Thu, 7 Jan 2016 12:54:35 -0500 Subject: Include the username in user_create/destroy system hooks. --- app/services/system_hooks_service.rb | 3 ++- doc/system_hooks/system_hooks.md | 2 ++ spec/services/system_hooks_service_spec.rb | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb index 6dc854ec33d..2bd8223fbd8 100644 --- a/app/services/system_hooks_service.rb +++ b/app/services/system_hooks_service.rb @@ -47,7 +47,8 @@ class SystemHooksService data.merge!({ name: model.name, email: model.email, - user_id: model.id + user_id: model.id, + username: model.username }) when ProjectMember data.merge!(project_member_data(model)) diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md index 49f98ded046..0539f30e802 100644 --- a/doc/system_hooks/system_hooks.md +++ b/doc/system_hooks/system_hooks.md @@ -129,6 +129,7 @@ X-Gitlab-Event: System Hook "email": "js@gitlabhq.com", "event_name": "user_create", "name": "John Smith", + "username": "js", "user_id": 41 } ``` @@ -142,6 +143,7 @@ X-Gitlab-Event: System Hook "email": "js@gitlabhq.com", "event_name": "user_destroy", "name": "John Smith", + "username": "js", "user_id": 41 } ``` diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb index 4455ae7b321..1824e51ebfe 100644 --- a/spec/services/system_hooks_service_spec.rb +++ b/spec/services/system_hooks_service_spec.rb @@ -9,8 +9,8 @@ describe SystemHooksService, services: true do let(:group_member) { create(:group_member) } context 'event data' do - it { expect(event_data(user, :create)).to include(:event_name, :name, :created_at, :updated_at, :email, :user_id) } - it { expect(event_data(user, :destroy)).to include(:event_name, :name, :created_at, :updated_at, :email, :user_id) } + it { expect(event_data(user, :create)).to include(:event_name, :name, :created_at, :updated_at, :email, :user_id, :username) } + it { expect(event_data(user, :destroy)).to include(:event_name, :name, :created_at, :updated_at, :email, :user_id, :username) } it { expect(event_data(project, :create)).to include(:event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) } it { expect(event_data(project, :destroy)).to include(:event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) } it { expect(event_data(project_member, :create)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_email, :access_level, :project_visibility) } -- cgit v1.2.1 From 1f64332e11949a5954b1e4ac7c6667b03ea70a0b Mon Sep 17 00:00:00 2001 From: Tommy Beadle Date: Thu, 7 Jan 2016 12:54:54 -0500 Subject: Include user_username in user_(add_to/remove_from)_(project/group) system hooks. --- app/services/system_hooks_service.rb | 2 ++ doc/system_hooks/system_hooks.md | 4 ++++ spec/services/system_hooks_service_spec.rb | 8 ++++---- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb index 2bd8223fbd8..bc39ae9f2cb 100644 --- a/app/services/system_hooks_service.rb +++ b/app/services/system_hooks_service.rb @@ -100,6 +100,7 @@ class SystemHooksService project_path: model.project.path, project_path_with_namespace: model.project.path_with_namespace, project_id: model.project.id, + user_username: model.user.username, user_name: model.user.name, user_email: model.user.email, access_level: model.human_access, @@ -112,6 +113,7 @@ class SystemHooksService group_name: model.group.name, group_path: model.group.path, group_id: model.group.id, + user_username: model.user.username, user_name: model.user.name, user_email: model.user.email, user_id: model.user.id, diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md index 0539f30e802..612376e3a49 100644 --- a/doc/system_hooks/system_hooks.md +++ b/doc/system_hooks/system_hooks.md @@ -96,6 +96,7 @@ X-Gitlab-Event: System Hook "project_path_with_namespace": "jsmith/storecloud", "user_email": "johnsmith@gmail.com", "user_name": "John Smith", + "user_username": "johnsmith", "user_id": 41, "project_visibility": "private", } @@ -115,6 +116,7 @@ X-Gitlab-Event: System Hook "project_path_with_namespace": "jsmith/storecloud", "user_email": "johnsmith@gmail.com", "user_name": "John Smith", + "user_username": "johnsmith", "user_id": 41, "project_visibility": "private", } @@ -217,6 +219,7 @@ X-Gitlab-Event: System Hook "group_path": "storecloud", "user_email": "johnsmith@gmail.com", "user_name": "John Smith", + "user_username": "johnsmith", "user_id": 41 } ``` @@ -233,6 +236,7 @@ X-Gitlab-Event: System Hook "group_path": "storecloud", "user_email": "johnsmith@gmail.com", "user_name": "John Smith", + "user_username": "johnsmith", "user_id": 41 } ``` diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb index 1824e51ebfe..eb066fe97f3 100644 --- a/spec/services/system_hooks_service_spec.rb +++ b/spec/services/system_hooks_service_spec.rb @@ -13,8 +13,8 @@ describe SystemHooksService, services: true do it { expect(event_data(user, :destroy)).to include(:event_name, :name, :created_at, :updated_at, :email, :user_id, :username) } it { expect(event_data(project, :create)).to include(:event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) } it { expect(event_data(project, :destroy)).to include(:event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) } - it { expect(event_data(project_member, :create)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_email, :access_level, :project_visibility) } - it { expect(event_data(project_member, :destroy)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_email, :access_level, :project_visibility) } + it { expect(event_data(project_member, :create)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_username, :user_email, :access_level, :project_visibility) } + it { expect(event_data(project_member, :destroy)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_username, :user_email, :access_level, :project_visibility) } it { expect(event_data(key, :create)).to include(:username, :key, :id) } it { expect(event_data(key, :destroy)).to include(:username, :key, :id) } @@ -50,13 +50,13 @@ describe SystemHooksService, services: true do it do expect(event_data(group_member, :create)).to include( :event_name, :created_at, :updated_at, :group_name, :group_path, - :group_id, :user_id, :user_name, :user_email, :group_access + :group_id, :user_id, :user_username, :user_name, :user_email, :group_access ) end it do expect(event_data(group_member, :destroy)).to include( :event_name, :created_at, :updated_at, :group_name, :group_path, - :group_id, :user_id, :user_name, :user_email, :group_access + :group_id, :user_id, :user_username, :user_name, :user_email, :group_access ) end end -- cgit v1.2.1 From 21958a393955037318141d39fbe14b1c2e842cab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Thu, 7 Jan 2016 13:45:19 -0500 Subject: Add some styling for syntax highlighting themes. #3945 --- app/assets/stylesheets/highlight/dark.scss | 14 ++++++++++++++ app/assets/stylesheets/highlight/monokai.scss | 18 ++++++++++++++++++ app/assets/stylesheets/highlight/solarized_dark.scss | 14 ++++++++++++++ app/assets/stylesheets/highlight/solarized_light.scss | 15 +++++++++++++++ app/assets/stylesheets/pages/diff.scss | 15 +++++++++++++++ app/views/projects/diffs/_parallel_view.html.haml | 2 +- app/views/projects/diffs/_text_file.html.haml | 2 +- 7 files changed, 78 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss index 6a2b25ddc67..f7d1334705f 100644 --- a/app/assets/stylesheets/highlight/dark.scss +++ b/app/assets/stylesheets/highlight/dark.scss @@ -90,4 +90,18 @@ .vg { color: #cc6666 } /* Name.Variable.Global */ .vi { color: #cc6666 } /* Name.Variable.Instance */ .il { color: #de935f } /* Literal.Number.Integer.Long */ + + .line_holder { + &.new .old_line, + &.new .new_line, + &.new .line_content { + @include diff_background(255, 255, 255, #808080); + } + + &.old .old_line, + &.old .new_line, + &.old .line_content { + @include diff_background(255, 51, 51, #808080); + } + } } diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss index 8560c3c490f..cc03ed6ae45 100644 --- a/app/assets/stylesheets/highlight/monokai.scss +++ b/app/assets/stylesheets/highlight/monokai.scss @@ -90,4 +90,22 @@ .gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */ .gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */ .gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */ + + .line_holder { + &.parallel .new.new_line, + &.parallel .new.line_content, + &.new .old_line, + &.new .new_line, + &.new .line_content { + @include diff_background(156, 175, 183, #808080); + } + + &.parallel .old.old_line, + &.parallel .old.line_content, + &.old .old_line, + &.old .new_line, + &.old .line_content { + @include diff_background(254, 147, 140, #808080); + } + } } diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss index 7d489a9666b..2c3648274cf 100644 --- a/app/assets/stylesheets/highlight/solarized_dark.scss +++ b/app/assets/stylesheets/highlight/solarized_dark.scss @@ -111,4 +111,18 @@ .vg { color: #268bd2 } /* Name.Variable.Global */ .vi { color: #268bd2 } /* Name.Variable.Instance */ .il { color: #2aa198 } /* Literal.Number.Integer.Long */ + + .line_holder { + &.new .old_line, + &.new .new_line, + &.new .line_content { + @include diff_background(255, 255, 255, #808080); + } + + &.old .old_line, + &.old .new_line, + &.old .line_content { + @include diff_background(255, 51, 51, #808080); + } + } } diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss index 200ed346446..c16473ffe66 100644 --- a/app/assets/stylesheets/highlight/solarized_light.scss +++ b/app/assets/stylesheets/highlight/solarized_light.scss @@ -111,4 +111,19 @@ .vg { color: #268bd2 } /* Name.Variable.Global */ .vi { color: #268bd2 } /* Name.Variable.Instance */ .il { color: #2aa198 } /* Literal.Number.Integer.Long */ + + + .line_holder { + &.new .old_line, + &.new .new_line, + &.new .line_content { + @include diff_background(92, 164, 169, #FAF3DD); + } + + &.old .old_line, + &.old .new_line, + &.old .line_content { + @include diff_background(237, 106, 90, #FAF3DD); + } + } } diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index afd6fb73675..caaad1e31d3 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -402,3 +402,18 @@ right: 15px; } } + +@mixin diff_background($r, $g, $b, $custom-border) { + /* Fallback for web browsers that doesn't support RGBa */ + background: rgb($r, $g, $b); + /* RGBa with 0.3 opacity */ + background: rgba($r, $g, $b, 0.3); + + &.new_line, &.old_line { + border-right-color: $custom-border !important; + } + + &.line_content span.idiff { + background: rgb($r, $g, $b); + } +} diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml index 2a43bbd11f2..1ad54d1848b 100644 --- a/app/views/projects/diffs/_parallel_view.html.haml +++ b/app/views/projects/diffs/_parallel_view.html.haml @@ -1,5 +1,5 @@ / Side-by-side diff view -%div.text-file.diff-wrap-lines.code.file-content.js-syntax-highlight.white +%div.text-file.diff-wrap-lines.code.file-content.js-syntax-highlight %table - parallel_diff(diff_file, index).each do |line| - type_left = line[0] diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml index 8e86219155f..f1b8cba5e55 100644 --- a/app/views/projects/diffs/_text_file.html.haml +++ b/app/views/projects/diffs/_text_file.html.haml @@ -3,7 +3,7 @@ .suppressed-container %a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show. -%table.text-file.code.js-syntax-highlight.white{ class: too_big ? 'hide' : '' } +%table.text-file.code.js-syntax-highlight{ class: too_big ? 'hide' : '' } - last_line = 0 - diff_file.highlighted_diff_lines.each_with_index do |line, index| -- cgit v1.2.1 From f1f4fdf778245cab74ff9cda2a421315c21a99aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Thu, 7 Jan 2016 21:08:57 -0500 Subject: Don't process inline diffs on backend. #3945 --- lib/gitlab/diff/parser.rb | 5 +- lib/gitlab/inline_diff.rb | 104 ------------------------------------ spec/lib/gitlab/inline_diff_spec.rb | 39 -------------- 3 files changed, 1 insertion(+), 147 deletions(-) delete mode 100644 lib/gitlab/inline_diff.rb delete mode 100644 spec/lib/gitlab/inline_diff_spec.rb diff --git a/lib/gitlab/diff/parser.rb b/lib/gitlab/diff/parser.rb index 7015fe36c3d..177bad4b1cf 100644 --- a/lib/gitlab/diff/parser.rb +++ b/lib/gitlab/diff/parser.rb @@ -11,13 +11,10 @@ module Gitlab line_new = 1 type = nil - lines_arr = ::Gitlab::InlineDiff.processing lines - - lines_arr.each do |line| + @lines.each do |line| next if filename?(line) full_line = html_escape(line.gsub(/\n/, '')) - full_line = ::Gitlab::InlineDiff.replace_markers full_line if line.match(/^@@ -/) type = "match" diff --git a/lib/gitlab/inline_diff.rb b/lib/gitlab/inline_diff.rb deleted file mode 100644 index 44507bde25d..00000000000 --- a/lib/gitlab/inline_diff.rb +++ /dev/null @@ -1,104 +0,0 @@ -module Gitlab - class InlineDiff - class << self - - START = "#!idiff-start!#" - FINISH = "#!idiff-finish!#" - - def processing(diff_arr) - indexes = _indexes_of_changed_lines diff_arr - - indexes.each do |index| - first_line = diff_arr[index+1] - second_line = diff_arr[index+2] - - # Skip inline diff if empty line was replaced with content - next if first_line == "-\n" - - first_token = find_first_token(first_line, second_line) - apply_first_token(diff_arr, index, first_token) - - last_token = find_last_token(first_line, second_line, first_token) - apply_last_token(diff_arr, index, last_token) - end - - diff_arr - end - - def apply_first_token(diff_arr, index, first_token) - start = first_token + START - - if first_token.empty? - # In case if we remove string of spaces in commit - diff_arr[index+1].sub!("-", "-" => "-#{START}") - diff_arr[index+2].sub!("+", "+" => "+#{START}") - else - diff_arr[index+1].sub!(first_token, first_token => start) - diff_arr[index+2].sub!(first_token, first_token => start) - end - end - - def apply_last_token(diff_arr, index, last_token) - # This is tricky: escape backslashes so that `sub` doesn't interpret them - # as backreferences. Regexp.escape does NOT do the right thing. - replace_token = FINISH + last_token.gsub(/\\/, '\&\&') - diff_arr[index+1].sub!(/#{Regexp.escape(last_token)}$/, replace_token) - diff_arr[index+2].sub!(/#{Regexp.escape(last_token)}$/, replace_token) - end - - def find_first_token(first_line, second_line) - max_length = [first_line.size, second_line.size].max - first_the_same_symbols = 0 - - (0..max_length + 1).each do |i| - first_the_same_symbols = i - 1 - - if first_line[i] != second_line[i] && i > 0 - break - end - end - - first_line[0..first_the_same_symbols][1..-1] - end - - def find_last_token(first_line, second_line, first_token) - max_length = [first_line.size, second_line.size].max - last_the_same_symbols = 0 - - (1..max_length + 1).each do |i| - last_the_same_symbols = -i - shortest_line = second_line.size > first_line.size ? first_line : second_line - - if (first_line[-i] != second_line[-i]) || "#{first_token}#{START}".size == shortest_line[1..-i].size - break - end - end - - last_the_same_symbols += 1 - first_line[last_the_same_symbols..-1] - end - - def _indexes_of_changed_lines(diff_arr) - chain_of_first_symbols = "" - diff_arr.each_with_index do |line, i| - chain_of_first_symbols += line[0] - end - chain_of_first_symbols.gsub!(/[^\-\+]/, "#") - - offset = 0 - indexes = [] - while index = chain_of_first_symbols.index("#-+#", offset) - indexes << index - offset = index + 1 - end - indexes - end - - def replace_markers(line) - line.gsub!(START, "") - line.gsub!(FINISH, "") - line - end - end - end -end diff --git a/spec/lib/gitlab/inline_diff_spec.rb b/spec/lib/gitlab/inline_diff_spec.rb deleted file mode 100644 index c690c195112..00000000000 --- a/spec/lib/gitlab/inline_diff_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -require 'spec_helper' - -describe Gitlab::InlineDiff, lib: true do - describe '#processing' do - let(:diff) do - < Date: Thu, 7 Jan 2016 22:37:01 -0500 Subject: Change strategy to highlight diffs. #3945 Now we apply syntax highlighting to the whole old and new files. This basically help us to highlight adequately multiline content. --- app/controllers/application_controller.rb | 1 + app/controllers/projects/blob_controller.rb | 7 ++- app/controllers/projects/commit_controller.rb | 1 + app/controllers/projects/compare_controller.rb | 1 + .../projects/merge_requests_controller.rb | 2 + app/helpers/diff_helper.rb | 4 +- app/views/projects/commit/show.html.haml | 3 +- app/views/projects/compare/show.html.haml | 2 +- app/views/projects/diffs/_diffs.html.haml | 2 +- .../projects/merge_requests/_new_submit.html.haml | 2 +- .../projects/merge_requests/show/_diffs.html.haml | 2 +- lib/gitlab/diff/file.rb | 8 ++- lib/gitlab/diff/highlight.rb | 70 ++++++++++++++++------ 13 files changed, 76 insertions(+), 29 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d9a37a4d45f..d3c1ff035f5 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -24,6 +24,7 @@ class ApplicationController < ActionController::Base helper_method :abilities, :can?, :current_application_settings helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :gitorious_import_enabled?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled? + helper_method :repository rescue_from Encoding::CompatibilityError do |exception| log_exception(exception) diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index d22c7b550b0..6aa602321f4 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -65,8 +65,11 @@ class Projects::BlobController < Projects::ApplicationController end def diff - @form = UnfoldForm.new(params) - @lines = Gitlab::Diff::Highlight.process_diff_lines(@blob.name, @blob.data.lines[@form.since - 1..@form.to - 1]) + ref, file_name = params[:id].split('/', 2) + + @form = UnfoldForm.new(params) + @lines = Gitlab::Diff::Highlight.process_file(repository, ref, file_name) + @lines = @lines[@form.since - 1..@form.to - 1] if @form.bottom? @match_line = '' diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb index 0aaba3792bf..9bbf4581057 100644 --- a/app/controllers/projects/commit_controller.rb +++ b/app/controllers/projects/commit_controller.rb @@ -72,6 +72,7 @@ class Projects::CommitController < Projects::ApplicationController @diffs = commit.diffs end + @diff_refs = [commit.parent.id, commit.id] @notes_count = commit.notes.count @statuses = ci_commit.statuses if ci_commit diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb index 5200d609cc9..5b88aed7a64 100644 --- a/app/controllers/projects/compare_controller.rb +++ b/app/controllers/projects/compare_controller.rb @@ -20,6 +20,7 @@ class Projects::CompareController < Projects::ApplicationController if compare_result @commits = Commit.decorate(compare_result.commits, @project) @diffs = compare_result.diffs + @diff_refs = [base_ref, head_ref] @commit = @project.commit(head_ref) @first_commit = @project.commit(base_ref) @line_notes = [] diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index ab5c953189c..d25adbe952d 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -59,6 +59,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController def diffs @commit = @merge_request.last_commit @first_commit = @merge_request.first_commit + @diff_refs = [@merge_request.target_sha, @merge_request.source_sha] @comments_allowed = @reply_allowed = true @comments_target = { @@ -103,6 +104,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @commit = @merge_request.last_commit @first_commit = @merge_request.first_commit @diffs = @merge_request.compare_diffs + @diff_refs = [@merge_request.target_sha, @merge_request.source_branch] @ci_commit = @merge_request.ci_commit @statuses = @ci_commit.statuses if @ci_commit diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 22deb69cec5..668610364c5 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -19,13 +19,13 @@ module DiffHelper end end - def safe_diff_files(diffs) + def safe_diff_files(diffs, diff_refs, repository) lines = 0 safe_files = [] diffs.first(allowed_diff_size).each do |diff| lines += diff.diff.lines.count break if lines > allowed_diff_lines - safe_files << Gitlab::Diff::File.new(diff) + safe_files << Gitlab::Diff::File.new(diff, diff_refs, repository) end safe_files end diff --git a/app/views/projects/commit/show.html.haml b/app/views/projects/commit/show.html.haml index 069b8b1f169..16ebce2d771 100644 --- a/app/views/projects/commit/show.html.haml +++ b/app/views/projects/commit/show.html.haml @@ -5,5 +5,6 @@ = render "ci_menu" - else %div.block-connector -= render "projects/diffs/diffs", diffs: @diffs, project: @project += render "projects/diffs/diffs", diffs: @diffs, project: @project, + diff_refs: @diff_refs = render "projects/notes/notes_with_form" diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml index 51088a7dea8..da731f28bb6 100644 --- a/app/views/projects/compare/show.html.haml +++ b/app/views/projects/compare/show.html.haml @@ -9,7 +9,7 @@ - if @commits.present? .prepend-top-default = render "projects/commits/commit_list" - = render "projects/diffs/diffs", diffs: @diffs, project: @project + = render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @diff_refs - else .light-well.prepend-top-default .center diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index f9d661d59d2..58ad7d79af9 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -1,7 +1,7 @@ - if diff_view == 'parallel' - fluid_layout true -- diff_files = safe_diff_files(diffs) +- diff_files = safe_diff_files(diffs, diff_refs, repository) .gray-content-block.middle-block.oneline-block .inline-parallel-buttons diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml index a14943b15d3..0cb8b6daedb 100644 --- a/app/views/projects/merge_requests/_new_submit.html.haml +++ b/app/views/projects/merge_requests/_new_submit.html.haml @@ -38,7 +38,7 @@ = render "projects/merge_requests/show/commits" #diffs.diffs.tab-pane.active - if @diffs.present? - = render "projects/diffs/diffs", diffs: @diffs, project: @project + = render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @diff_refs - elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE .alert.alert-danger %h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits. diff --git a/app/views/projects/merge_requests/show/_diffs.html.haml b/app/views/projects/merge_requests/show/_diffs.html.haml index d9cfc3d7ae9..1d9af1e4160 100644 --- a/app/views/projects/merge_requests/show/_diffs.html.haml +++ b/app/views/projects/merge_requests/show/_diffs.html.haml @@ -1,5 +1,5 @@ - if @merge_request_diff.collected? - = render "projects/diffs/diffs", diffs: params[:w] == '1' ? @merge_request.diffs_no_whitespace : @merge_request.diffs, project: @merge_request.project + = render "projects/diffs/diffs", diffs: params[:w] == '1' ? @merge_request.diffs_no_whitespace : @merge_request.diffs, project: @merge_request.project, diff_refs: @diff_refs - elsif @merge_request_diff.empty? .nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch} - else diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index 69b38a32eeb..cb93c6a574a 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -1,13 +1,15 @@ module Gitlab module Diff class File - attr_reader :diff + attr_reader :diff, :repository, :new_ref, :old_ref delegate :new_file, :deleted_file, :renamed_file, :old_path, :new_path, to: :diff, prefix: false - def initialize(diff) + def initialize(diff, diff_refs, repository) @diff = diff + @repository = repository + @old_ref, @new_ref = diff_refs end # Array of Gitlab::DIff::Line objects @@ -16,7 +18,7 @@ module Gitlab end def highlighted_diff_lines - Gitlab::Diff::Highlight.process_diff_lines(new_path, diff_lines) + Gitlab::Diff::Highlight.process_diff_lines(self) end def mode_changed? diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb index 7f340de65cc..0d0a3268107 100644 --- a/lib/gitlab/diff/highlight.rb +++ b/lib/gitlab/diff/highlight.rb @@ -1,22 +1,43 @@ module Gitlab module Diff class Highlight + attr_reader :diff_file + + delegate :repository, :old_path, :new_path, :old_ref, :new_ref, + to: :diff_file, prefix: :diff + # Apply syntax highlight to provided source code # - # file_name - The file name related to the code. - # lines - It can be an Array of Gitlab::Diff::Line objects or simple Strings. - # When passing Strings you need to provide the required 'end of lines' - # chars ("\n") for each String given that we don't append them automatically. + # diff_file - an instance of Gitlab::Diff::File # # Returns an Array with the processed items. - def self.process_diff_lines(file_name, lines) - processor = new(file_name, lines) + def self.process_diff_lines(diff_file) + processor = new(diff_file) processor.highlight end - def initialize(file_name, lines) - @file_name = file_name - @lines = lines + def self.process_file(repository, ref, file_name) + blob = repository.blob_at(ref, file_name) + return [] unless blob + + content = blob.data + lexer = Rouge::Lexer.guess(filename: file_name, source: content).new rescue Rouge::Lexers::PlainText.new + formatter.format(lexer.lex(content)).lines + end + + def self.formatter + @formatter ||= Rouge::Formatters::HTMLGitlab.new( + nowrap: true, + cssclass: 'code highlight', + lineanchors: true, + lineanchorsid: 'LC' + ) + end + + def initialize(diff_file) + @diff_file = diff_file + @file_name = diff_file.new_path + @lines = diff_file.diff_lines end def highlight @@ -47,7 +68,7 @@ module Gitlab def extract_line_prefixes @diff_line_prefixes ||= begin if is_diff_line? - text_lines.map { |line| line.sub!(/\A((\+|\-)\s*)/, '');$1 } + text_lines.map { |line| line.sub!(/\A((\+|\-))/, '');$1 } else [] end @@ -57,11 +78,17 @@ module Gitlab def update_diff_lines @highlighted_code.lines.each_with_index do |line, i| diff_line = @lines[i] + line_prefix = @diff_line_prefixes[i] || ' ' # ignore highlighting for "match" lines next if diff_line.type == 'match' - diff_line.text = "#{@diff_line_prefixes[i]}#{line}" + case diff_line.type + when 'new', nil + diff_line.text = new_lines[diff_line.new_pos - 1].try(:gsub!, /\A\s/, line_prefix) + when 'old' + diff_line.text = old_lines[diff_line.old_pos - 1].try(:gsub!, /\A\s/, line_prefix) + end end @lines @@ -79,12 +106,21 @@ module Gitlab end def formatter - Rouge::Formatters::HTMLGitlab.new( - nowrap: true, - cssclass: 'code highlight', - lineanchors: true, - lineanchorsid: 'LC' - ) + self.class.formatter + end + + def old_lines + @old_lines ||= begin + lines = self.class.process_file(diff_repository, diff_old_ref, diff_old_path) + lines.map! { |line| " #{line}" } + end + end + + def new_lines + @new_lines ||= begin + lines = self.class.process_file(diff_repository, diff_new_ref, diff_new_path) + lines.map! { |line| " #{line}" } + end end end end -- cgit v1.2.1 From 549a2fa7873366b52e9ba3caa849073b7b958b73 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Fri, 8 Jan 2016 14:01:31 +0100 Subject: Modify builds scope filtering in builds API --- app/models/ci/build.rb | 4 ++++ doc/api/builds.md | 5 ++--- lib/api/builds.rb | 31 +++++++++++++++++++------------ spec/requests/api/builds_spec.rb | 15 ++++++++++++++- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 3e67b2771c1..8fb68743a9b 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -94,6 +94,10 @@ module Ci new_build.save new_build end + + def available_statuses + state_machines[:status].states.map &:value + end end state_machine :status, initial: :pending do diff --git a/doc/api/builds.md b/doc/api/builds.md index b716499dd36..c52266714d0 100644 --- a/doc/api/builds.md +++ b/doc/api/builds.md @@ -11,7 +11,7 @@ GET /projects/:id/builds Parameters: - `id` (required) - The ID of a project -- `scope` (optional) - The scope of builds to show (one of: `all`, `finished`, `running`; default: `all`) +- `scope` (optional) - The scope of builds to show (one or array of: pending, running, failed, success, canceled; if none provided showing all builds) ```json [ @@ -64,8 +64,7 @@ Parameters: - `id` (required) - The ID of a project - `sha` (required) - The SHA id of a commit -- `scope` (optional) - The scope of builds to show (one of: `all`, `finished`, `running`; default: `all`) - +- `scope` (optional) - The scope of builds to show (one or array of: pending, running, failed, success, canceled; if none provided showing all builds) ```json [ diff --git a/lib/api/builds.rb b/lib/api/builds.rb index 6b0edcff820..6aae1856953 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -8,9 +8,8 @@ module API # # Parameters: # id (required) - The ID of a project - # scope (optional) - The scope of builds to show (one of: all, finished, running; default: all) - # page (optional) - The page number for pagination - # per_page (ooptional) - The value of items per page to show + # scope (optional) - The scope of builds to show (one or array of: pending, running, failed, success, canceled; + # if none provided showing all builds) # Example Request: # GET /projects/:id/builds get ':id/builds' do @@ -24,7 +23,8 @@ module API # Parameters: # id (required) - The ID of a project # sha (required) - The SHA id of a commit - # scope (optional) - The scope of builds to show (one of: all, finished, running; default: all) + # scope (optional) - The scope of builds to show (one or array of: pending, running, failed, success, canceled; + # if none provided showing all builds) # Example Request: # GET /projects/:id/builds/commit/:sha get ':id/builds/commit/:sha' do @@ -112,14 +112,21 @@ module API end def filter_builds(builds, scope) - case scope - when 'finished' - builds.finished - when 'running' - builds.running - else - builds - end + available_scopes = Ci::Build.available_statuses + scope = + if scope.is_a?(String) || scope.is_a?(Symbol) + available_scopes & [scope.to_s] + elsif scope.is_a?(Array) + available_scopes & scope + elsif scope.respond_to?(:to_h) + available_scopes & scope.to_h.values + else + [] + end + + return builds if scope.empty? + + builds.where(status: scope) end def authorize_manage_builds! diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb index d4af7639d4b..a953eb2fac2 100644 --- a/spec/requests/api/builds_spec.rb +++ b/spec/requests/api/builds_spec.rb @@ -18,7 +18,20 @@ describe API::API, api: true do it 'should return project builds' do get api("/projects/#{project.id}/builds", user) - puts json_response + expect(response.status).to eq(200) + expect(json_response).to be_an Array + end + + it 'should filter project with one scope element' do + get api("/projects/#{project.id}/builds?scope=pending", user) + + expect(response.status).to eq(200) + expect(json_response).to be_an Array + end + + it 'should filter project with array of scope elements' do + get api("/projects/#{project.id}/builds?scope[0]=pending&scope[1]=running", user) + expect(response.status).to eq(200) expect(json_response).to be_an Array end -- cgit v1.2.1 From bc7ef8e5b7a002ca6bc2d7a5e6be11b4a59b6710 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Tue, 29 Dec 2015 17:53:55 -0200 Subject: Add ldap_blocked as new state to users state machine --- app/models/user.rb | 12 +++++++++++- spec/models/user_spec.rb | 44 ++++++++++++++++++++++++++++---------------- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 46b36c605b0..67b47b0f329 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -198,16 +198,26 @@ class User < ActiveRecord::Base transition active: :blocked end + event :ldap_block do + transition active: :ldap_blocked + end + event :activate do transition blocked: :active end + + state :blocked, :ldap_blocked do + def blocked? + true + end + end end mount_uploader :avatar, AvatarUploader # Scopes scope :admins, -> { where(admin: true) } - scope :blocked, -> { with_state(:blocked) } + scope :blocked, -> { with_states(:blocked, :ldap_blocked) } scope :active, -> { with_state(:active) } scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all } scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM members)') } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 3cd63b2b0e8..0bef68e2885 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -569,27 +569,39 @@ describe User, models: true do end end - describe :ldap_user? do - it "is true if provider name starts with ldap" do - user = create(:omniauth_user, provider: 'ldapmain') - expect( user.ldap_user? ).to be_truthy - end + context 'ldap synchronized user' do + describe :ldap_user? do + it 'is true if provider name starts with ldap' do + user = create(:omniauth_user, provider: 'ldapmain') + expect(user.ldap_user?).to be_truthy + end - it "is false for other providers" do - user = create(:omniauth_user, provider: 'other-provider') - expect( user.ldap_user? ).to be_falsey + it 'is false for other providers' do + user = create(:omniauth_user, provider: 'other-provider') + expect(user.ldap_user?).to be_falsey + end + + it 'is false if no extern_uid is provided' do + user = create(:omniauth_user, extern_uid: nil) + expect(user.ldap_user?).to be_falsey + end end - it "is false if no extern_uid is provided" do - user = create(:omniauth_user, extern_uid: nil) - expect( user.ldap_user? ).to be_falsey + describe :ldap_identity do + it 'returns ldap identity' do + user = create :omniauth_user + expect(user.ldap_identity.provider).not_to be_empty + end end - end - describe :ldap_identity do - it "returns ldap identity" do - user = create :omniauth_user - expect(user.ldap_identity.provider).not_to be_empty + describe '#ldap_block' do + let(:user) { create(:omniauth_user, provider: 'ldapmain', name: 'John Smith') } + + it 'blocks user flaging the action caming from ldap' do + user.ldap_block + expect(user.blocked?).to be_truthy + expect(user.ldap_blocked?).to be_truthy + end end end -- cgit v1.2.1 From ba9855d4877998e3574907cc542fcab15a9d1353 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Tue, 29 Dec 2015 18:58:38 -0200 Subject: Prevent ldap_blocked users from being unblocked by the Admin UI --- app/assets/stylesheets/framework/buttons.scss | 3 +++ app/controllers/admin/users_controller.rb | 4 ++- app/views/admin/users/index.html.haml | 7 ++++- spec/controllers/admin/users_controller_spec.rb | 35 ++++++++++++++++++------- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index 97a94638847..e2376363485 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -132,6 +132,9 @@ margin-right: 0px; } } + &.disabled { + pointer-events: auto !important; + } } .btn-block { diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index d7c927d444c..87f4fb455b8 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -40,7 +40,9 @@ class Admin::UsersController < Admin::ApplicationController end def unblock - if user.activate + if user.ldap_blocked? + redirect_back_or_admin_user(alert: "This user cannot be unlocked manually from GitLab") + elsif user.activate redirect_back_or_admin_user(notice: "Successfully unblocked") else redirect_back_or_admin_user(alert: "Error occurred. User was not unblocked") diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index a92c9c152b9..911c4d0cf12 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -90,7 +90,12 @@   = link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn btn-xs" - unless user == current_user - - if user.blocked? + - if user.ldap_blocked? + = link_to '#', title: 'Cannot unblock LDAP blocked users', data: {toggle: 'tooltip'}, class: 'btn btn-xs btn-success disabled' do + %i.fa.fa-lock + Unblock + = '' + - elsif user.blocked? = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn btn-xs btn-success" - else = link_to 'Block', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-xs btn-warning" diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index 8b7af4d3a0a..5b1f65d7aff 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -34,17 +34,34 @@ describe Admin::UsersController do end describe 'PUT unblock/:id' do - let(:user) { create(:user) } - - before do - user.block + context 'ldap blocked users' do + let(:user) { create(:omniauth_user, provider: 'ldapmain') } + + before do + user.ldap_block + end + + it 'will not unblock user' do + put :unblock, id: user.username + user.reload + expect(user.blocked?).to be_truthy + expect(flash[:alert]).to eq 'This user cannot be unlocked manually from GitLab' + end end - it 'unblocks user' do - put :unblock, id: user.username - user.reload - expect(user.blocked?).to be_falsey - expect(flash[:notice]).to eq 'Successfully unblocked' + context 'manually blocked users' do + let(:user) { create(:user) } + + before do + user.block + end + + it 'unblocks user' do + put :unblock, id: user.username + user.reload + expect(user.blocked?).to be_falsey + expect(flash[:notice]).to eq 'Successfully unblocked' + end end end -- cgit v1.2.1 From 6e7db8e23e169bcbf0847ece27b9e44e00ae572b Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Wed, 30 Dec 2015 16:52:02 -0200 Subject: Prevent ldap_blocked users from being blocked/unblocked by the API --- doc/api/users.md | 6 ++++-- lib/api/users.rb | 12 ++++++++---- spec/requests/api/users_spec.rb | 23 ++++++++++++++++++----- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/doc/api/users.md b/doc/api/users.md index 773fe36d277..b7fc903825e 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -558,7 +558,8 @@ Parameters: - `uid` (required) - id of specified user -Will return `200 OK` on success, or `404 User Not Found` is user cannot be found. +Will return `200 OK` on success, `404 User Not Found` is user cannot be found or +`403 Forbidden` when trying to block an already blocked user by LDAP synchronization. ## Unblock user @@ -572,4 +573,5 @@ Parameters: - `uid` (required) - id of specified user -Will return `200 OK` on success, or `404 User Not Found` is user cannot be found. +Will return `200 OK` on success, `404 User Not Found` is user cannot be found or +`403 Forbidden` when trying to unblock a user blocked by LDAP synchronization. diff --git a/lib/api/users.rb b/lib/api/users.rb index 0d7813428e2..01fd90139b0 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -284,10 +284,12 @@ module API authenticated_as_admin! user = User.find_by(id: params[:id]) - if user + if !user + not_found!('User') + elsif !user.ldap_blocked? user.block else - not_found!('User') + forbidden!('LDAP blocked users cannot be modified by the API') end end @@ -299,10 +301,12 @@ module API authenticated_as_admin! user = User.find_by(id: params[:id]) - if user + if !user + not_found!('User') + elsif !user.ldap_blocked? user.activate else - not_found!('User') + forbidden!('LDAP blocked users cannot be unblocked by the API') end end end diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 4f278551d07..b82c5c7685f 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -8,6 +8,8 @@ describe API::API, api: true do let(:key) { create(:key, user: user) } let(:email) { create(:email, user: user) } let(:omniauth_user) { create(:omniauth_user) } + let(:ldap_user) { create(:omniauth_user, provider: 'ldapmain') } + let(:ldap_blocked_user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') } describe "GET /users" do context "when unauthenticated" do @@ -783,6 +785,12 @@ describe API::API, api: true do expect(user.reload.state).to eq('blocked') end + it 'should not re-block ldap blocked users' do + put api("/users/#{ldap_blocked_user.id}/block", admin) + expect(response.status).to eq(403) + expect(ldap_blocked_user.reload.state).to eq('ldap_blocked') + end + it 'should not be available for non admin users' do put api("/users/#{user.id}/block", user) expect(response.status).to eq(403) @@ -797,7 +805,9 @@ describe API::API, api: true do end describe 'PUT /user/:id/unblock' do + let(:blocked_user) { create(:user, state: 'blocked') } before { admin } + it 'should unblock existing user' do put api("/users/#{user.id}/unblock", admin) expect(response.status).to eq(200) @@ -805,12 +815,15 @@ describe API::API, api: true do end it 'should unblock a blocked user' do - put api("/users/#{user.id}/block", admin) - expect(response.status).to eq(200) - expect(user.reload.state).to eq('blocked') - put api("/users/#{user.id}/unblock", admin) + put api("/users/#{blocked_user.id}/unblock", admin) expect(response.status).to eq(200) - expect(user.reload.state).to eq('active') + expect(blocked_user.reload.state).to eq('active') + end + + it 'should not unblock ldap blocked users' do + put api("/users/#{ldap_blocked_user.id}/unblock", admin) + expect(response.status).to eq(403) + expect(ldap_blocked_user.reload.state).to eq('ldap_blocked') end it 'should not be available for non admin users' do -- cgit v1.2.1 From d6dc088affeee4568e771e1d7894e0bcdb955af8 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Wed, 30 Dec 2015 20:56:26 -0200 Subject: LDAP synchronization block/unblock new states --- lib/gitlab/ldap/access.rb | 6 +++--- spec/lib/gitlab/ldap/access_spec.rb | 34 ++++++++++++++-------------------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/lib/gitlab/ldap/access.rb b/lib/gitlab/ldap/access.rb index c438a3d167b..76cb48d7aa6 100644 --- a/lib/gitlab/ldap/access.rb +++ b/lib/gitlab/ldap/access.rb @@ -37,15 +37,15 @@ module Gitlab # Block user in GitLab if he/she was blocked in AD if Gitlab::LDAP::Person.disabled_via_active_directory?(user.ldap_identity.extern_uid, adapter) - user.block + user.ldap_block false else - user.activate if user.blocked? && !ldap_config.block_auto_created_users + user.activate if (user.blocked? && !ldap_config.block_auto_created_users) || user.ldap_blocked? true end else # Block the user if they no longer exist in LDAP/AD - user.block + user.ldap_block false end rescue diff --git a/spec/lib/gitlab/ldap/access_spec.rb b/spec/lib/gitlab/ldap/access_spec.rb index a628d0c0157..f58d70e809c 100644 --- a/spec/lib/gitlab/ldap/access_spec.rb +++ b/spec/lib/gitlab/ldap/access_spec.rb @@ -13,64 +13,59 @@ describe Gitlab::LDAP::Access, lib: true do end it { is_expected.to be_falsey } - + it 'should block user in GitLab' do access.allowed? expect(user).to be_blocked + expect(user).to be_ldap_blocked end end context 'when the user is found' do before do - allow(Gitlab::LDAP::Person). - to receive(:find_by_dn).and_return(:ldap_user) + allow(Gitlab::LDAP::Person).to receive(:find_by_dn).and_return(:ldap_user) end context 'and the user is disabled via active directory' do before do - allow(Gitlab::LDAP::Person). - to receive(:disabled_via_active_directory?).and_return(true) + allow(Gitlab::LDAP::Person).to receive(:disabled_via_active_directory?).and_return(true) end it { is_expected.to be_falsey } - it "should block user in GitLab" do + it 'should block user in GitLab' do access.allowed? expect(user).to be_blocked + expect(user).to be_ldap_blocked end end context 'and has no disabled flag in active diretory' do before do user.block - - allow(Gitlab::LDAP::Person). - to receive(:disabled_via_active_directory?).and_return(false) + allow(Gitlab::LDAP::Person).to receive(:disabled_via_active_directory?).and_return(false) end it { is_expected.to be_truthy } context 'when auto-created users are blocked' do - before do - allow_any_instance_of(Gitlab::LDAP::Config). - to receive(:block_auto_created_users).and_return(true) + allow_any_instance_of(Gitlab::LDAP::Config).to receive(:block_auto_created_users).and_return(true) end - it "does not unblock user in GitLab" do + it 'does not unblock user in GitLab' do access.allowed? expect(user).to be_blocked + expect(user).not_to be_ldap_blocked # this block is handled by omniauth not by our internal logic end end - context "when auto-created users are not blocked" do - + context 'when auto-created users are not blocked' do before do - allow_any_instance_of(Gitlab::LDAP::Config). - to receive(:block_auto_created_users).and_return(false) + allow_any_instance_of(Gitlab::LDAP::Config).to receive(:block_auto_created_users).and_return(false) end - it "should unblock user in GitLab" do + it 'should unblock user in GitLab' do access.allowed? expect(user).not_to be_blocked end @@ -80,8 +75,7 @@ describe Gitlab::LDAP::Access, lib: true do context 'without ActiveDirectory enabled' do before do allow(Gitlab::LDAP::Config).to receive(:enabled?).and_return(true) - allow_any_instance_of(Gitlab::LDAP::Config). - to receive(:active_directory).and_return(false) + allow_any_instance_of(Gitlab::LDAP::Config).to receive(:active_directory).and_return(false) end it { is_expected.to be_truthy } -- cgit v1.2.1 From ec67e9be1d7486199b47e19c766202a8bfdefe93 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Wed, 6 Jan 2016 05:38:52 -0200 Subject: Repair ldap_blocked state when no ldap identity exist anymore --- app/controllers/admin/identities_controller.rb | 2 ++ app/models/identity.rb | 4 +++ app/models/user.rb | 1 + app/services/repair_ldap_blocked_user_service.rb | 15 +++++++++ .../admin/identities_controller_spec.rb | 26 +++++++++++++++ spec/models/identity_spec.rb | 38 ++++++++++++++++++++++ .../repair_ldap_blocked_user_service_spec.rb | 23 +++++++++++++ 7 files changed, 109 insertions(+) create mode 100644 app/services/repair_ldap_blocked_user_service.rb create mode 100644 spec/controllers/admin/identities_controller_spec.rb create mode 100644 spec/models/identity_spec.rb create mode 100644 spec/services/repair_ldap_blocked_user_service_spec.rb diff --git a/app/controllers/admin/identities_controller.rb b/app/controllers/admin/identities_controller.rb index e383fe38ea6..9ba10487512 100644 --- a/app/controllers/admin/identities_controller.rb +++ b/app/controllers/admin/identities_controller.rb @@ -26,6 +26,7 @@ class Admin::IdentitiesController < Admin::ApplicationController def update if @identity.update_attributes(identity_params) + RepairLdapBlockedUserService.new(@user, @identity).execute redirect_to admin_user_identities_path(@user), notice: 'User identity was successfully updated.' else render :edit @@ -34,6 +35,7 @@ class Admin::IdentitiesController < Admin::ApplicationController def destroy if @identity.destroy + RepairLdapBlockedUserService.new(@user, @identity).execute redirect_to admin_user_identities_path(@user), notice: 'User identity was successfully removed.' else redirect_to admin_user_identities_path(@user), alert: 'Failed to remove user identity.' diff --git a/app/models/identity.rb b/app/models/identity.rb index 8bcdc194953..830b99fa3f2 100644 --- a/app/models/identity.rb +++ b/app/models/identity.rb @@ -18,4 +18,8 @@ class Identity < ActiveRecord::Base validates :provider, presence: true validates :extern_uid, allow_blank: true, uniqueness: { scope: :provider } validates :user_id, uniqueness: { scope: :provider } + + def is_ldap? + provider.starts_with?('ldap') + end end diff --git a/app/models/user.rb b/app/models/user.rb index 67b47b0f329..5eed9cf91c7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -196,6 +196,7 @@ class User < ActiveRecord::Base state_machine :state, initial: :active do event :block do transition active: :blocked + transition ldap_blocked: :blocked end event :ldap_block do diff --git a/app/services/repair_ldap_blocked_user_service.rb b/app/services/repair_ldap_blocked_user_service.rb new file mode 100644 index 00000000000..ceca15414e0 --- /dev/null +++ b/app/services/repair_ldap_blocked_user_service.rb @@ -0,0 +1,15 @@ +class RepairLdapBlockedUserService + attr_accessor :user, :identity + + def initialize(user, identity) + @user, @identity = user, identity + end + + def execute + if identity.destroyed? + user.block if identity.is_ldap? && user.ldap_blocked? && !user.ldap_user? + else + user.block if !identity.is_ldap? && user.ldap_blocked? && !user.ldap_user? + end + end +end diff --git a/spec/controllers/admin/identities_controller_spec.rb b/spec/controllers/admin/identities_controller_spec.rb new file mode 100644 index 00000000000..c131d22a30a --- /dev/null +++ b/spec/controllers/admin/identities_controller_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe Admin::IdentitiesController do + let(:admin) { create(:admin) } + before { sign_in(admin) } + + describe 'UPDATE identity' do + let(:user) { create(:omniauth_user, provider: 'ldapmain', extern_uid: 'uid=myuser,ou=people,dc=example,dc=com') } + + it 'repairs ldap blocks' do + expect_any_instance_of(RepairLdapBlockedUserService).to receive(:execute) + + put :update, user_id: user.username, id: user.ldap_identity.id, identity: { provider: 'twitter' } + end + end + + describe 'DELETE identity' do + let(:user) { create(:omniauth_user, provider: 'ldapmain', extern_uid: 'uid=myuser,ou=people,dc=example,dc=com') } + + it 'repairs ldap blocks' do + expect_any_instance_of(RepairLdapBlockedUserService).to receive(:execute) + + delete :destroy, user_id: user.username, id: user.ldap_identity.id + end + end +end diff --git a/spec/models/identity_spec.rb b/spec/models/identity_spec.rb new file mode 100644 index 00000000000..107bfc17782 --- /dev/null +++ b/spec/models/identity_spec.rb @@ -0,0 +1,38 @@ +# == Schema Information +# +# Table name: identities +# +# id :integer not null, primary key +# extern_uid :string(255) +# provider :string(255) +# user_id :integer +# created_at :datetime +# updated_at :datetime +# + +require 'spec_helper' + +RSpec.describe Identity, models: true do + + describe 'relations' do + it { is_expected.to belong_to(:user) } + end + + describe 'fields' do + it { is_expected.to respond_to(:provider) } + it { is_expected.to respond_to(:extern_uid) } + end + + describe '#is_ldap?' do + let(:ldap_identity) { create(:identity, provider: 'ldapmain') } + let(:other_identity) { create(:identity, provider: 'twitter') } + + it 'returns true if it is a ldap identity' do + expect(ldap_identity.is_ldap?).to be_truthy + end + + it 'returns false if it is not a ldap identity' do + expect(other_identity.is_ldap?).to be_falsey + end + end +end diff --git a/spec/services/repair_ldap_blocked_user_service_spec.rb b/spec/services/repair_ldap_blocked_user_service_spec.rb new file mode 100644 index 00000000000..2a2114d038c --- /dev/null +++ b/spec/services/repair_ldap_blocked_user_service_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe RepairLdapBlockedUserService, services: true do + let(:user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') } + let(:identity) { user.ldap_identity } + subject(:service) { RepairLdapBlockedUserService.new(user, identity) } + + describe '#execute' do + it 'change to normal block after destroying last ldap identity' do + identity.destroy + service.execute + + expect(user.reload).not_to be_ldap_blocked + end + + it 'change to normal block after changing last ldap identity to another provider' do + identity.update_attribute(:provider, 'twitter') + service.execute + + expect(user.reload).not_to be_ldap_blocked + end + end +end -- cgit v1.2.1 From 47e4613f4adc2d6ef4b066a87ec772ef8044bdd5 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Thu, 7 Jan 2016 14:01:01 -0200 Subject: Code style fixes and some code simplified --- app/controllers/admin/identities_controller.rb | 4 ++-- app/services/repair_ldap_blocked_user_service.rb | 18 ++++++++++-------- lib/gitlab/ldap/access.rb | 4 +++- spec/services/repair_ldap_blocked_user_service_spec.rb | 2 +- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/app/controllers/admin/identities_controller.rb b/app/controllers/admin/identities_controller.rb index 9ba10487512..79a53556f0a 100644 --- a/app/controllers/admin/identities_controller.rb +++ b/app/controllers/admin/identities_controller.rb @@ -26,7 +26,7 @@ class Admin::IdentitiesController < Admin::ApplicationController def update if @identity.update_attributes(identity_params) - RepairLdapBlockedUserService.new(@user, @identity).execute + RepairLdapBlockedUserService.new(@user).execute redirect_to admin_user_identities_path(@user), notice: 'User identity was successfully updated.' else render :edit @@ -35,7 +35,7 @@ class Admin::IdentitiesController < Admin::ApplicationController def destroy if @identity.destroy - RepairLdapBlockedUserService.new(@user, @identity).execute + RepairLdapBlockedUserService.new(@user).execute redirect_to admin_user_identities_path(@user), notice: 'User identity was successfully removed.' else redirect_to admin_user_identities_path(@user), alert: 'Failed to remove user identity.' diff --git a/app/services/repair_ldap_blocked_user_service.rb b/app/services/repair_ldap_blocked_user_service.rb index ceca15414e0..863cef7ff61 100644 --- a/app/services/repair_ldap_blocked_user_service.rb +++ b/app/services/repair_ldap_blocked_user_service.rb @@ -1,15 +1,17 @@ class RepairLdapBlockedUserService - attr_accessor :user, :identity + attr_accessor :user - def initialize(user, identity) - @user, @identity = user, identity + def initialize(user) + @user = user end def execute - if identity.destroyed? - user.block if identity.is_ldap? && user.ldap_blocked? && !user.ldap_user? - else - user.block if !identity.is_ldap? && user.ldap_blocked? && !user.ldap_user? - end + user.block if ldap_hard_blocked? + end + + private + + def ldap_hard_blocked? + user.ldap_blocked? && !user.ldap_user? end end diff --git a/lib/gitlab/ldap/access.rb b/lib/gitlab/ldap/access.rb index 76cb48d7aa6..ebd9260ad5d 100644 --- a/lib/gitlab/ldap/access.rb +++ b/lib/gitlab/ldap/access.rb @@ -40,7 +40,9 @@ module Gitlab user.ldap_block false else - user.activate if (user.blocked? && !ldap_config.block_auto_created_users) || user.ldap_blocked? + if (user.blocked? && !ldap_config.block_auto_created_users) || user.ldap_blocked? + user.activate + end true end else diff --git a/spec/services/repair_ldap_blocked_user_service_spec.rb b/spec/services/repair_ldap_blocked_user_service_spec.rb index 2a2114d038c..ce7d1455975 100644 --- a/spec/services/repair_ldap_blocked_user_service_spec.rb +++ b/spec/services/repair_ldap_blocked_user_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe RepairLdapBlockedUserService, services: true do let(:user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') } let(:identity) { user.ldap_identity } - subject(:service) { RepairLdapBlockedUserService.new(user, identity) } + subject(:service) { RepairLdapBlockedUserService.new(user) } describe '#execute' do it 'change to normal block after destroying last ldap identity' do -- cgit v1.2.1 From 6282202ee84f80f2197698b6f132abdf588e94d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Fri, 8 Jan 2016 15:17:45 -0500 Subject: Remove custom Lexer. #3945 [ci skip] Inline diff is going to be generated client side now. #3945 --- lib/gitlab/diff/highlight.rb | 3 +-- lib/rouge/lexers/gitlab_diff.rb | 26 -------------------------- 2 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 lib/rouge/lexers/gitlab_diff.rb diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb index 0d0a3268107..7dd44b6004a 100644 --- a/lib/gitlab/diff/highlight.rb +++ b/lib/gitlab/diff/highlight.rb @@ -95,8 +95,7 @@ module Gitlab end def lexer - parent = Rouge::Lexer.guess(filename: @file_name, source: @code).new rescue Rouge::Lexers::PlainText.new - Rouge::Lexers::GitlabDiff.new(parent_lexer: parent) + Rouge::Lexer.guess(filename: @file_name, source: @code).new rescue Rouge::Lexers::PlainText.new end def unescape_html(content) diff --git a/lib/rouge/lexers/gitlab_diff.rb b/lib/rouge/lexers/gitlab_diff.rb deleted file mode 100644 index cbf272ee1de..00000000000 --- a/lib/rouge/lexers/gitlab_diff.rb +++ /dev/null @@ -1,26 +0,0 @@ -Rouge::Token::Tokens.token(:InlineDiff, 'idiff') - -module Rouge - module Lexers - # This new Lexer is required in order to avoid the inline diff markup - # to be tokenized, it will be rendered as raw HTML code if that happens. - class GitlabDiff < RegexLexer - title "GitLab Diff" - tag 'gitlab_diff' - - state :root do - rule %r{(.*?)} do |match| - token InlineDiff, match[1] - end - - rule /(?:(?! Date: Fri, 8 Jan 2016 14:16:58 -0600 Subject: Improve button styles --- app/helpers/notes_helper.rb | 2 +- app/views/projects/notes/_edit_form.html.haml | 4 ++-- app/views/projects/notes/_form.html.haml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 5f0c921413a..53c543c28c5 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -67,7 +67,7 @@ module NotesHelper line_type: line_type } - button_tag class: 'btn reply-btn js-discussion-reply-button', + button_tag class: 'btn btn-nr reply-btn js-discussion-reply-button', data: data, title: 'Add a reply' do link_text = icon('comment') link_text << ' Reply' diff --git a/app/views/projects/notes/_edit_form.html.haml b/app/views/projects/notes/_edit_form.html.haml index 3ccda1b381c..5d78652befa 100644 --- a/app/views/projects/notes/_edit_form.html.haml +++ b/app/views/projects/notes/_edit_form.html.haml @@ -6,5 +6,5 @@ = render 'projects/notes/hints' .note-form-actions - = f.submit 'Save Comment', class: 'btn btn-primary btn-save btn-grouped js-comment-button' - = link_to 'Cancel', '#', class: 'btn btn-cancel note-edit-cancel' + = f.submit 'Save Comment', class: 'btn btn-nr btn-save btn-grouped js-comment-button' + = link_to 'Cancel', '#', class: 'btn btn-nr btn-cancel note-edit-cancel' diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml index acb6dc52a8e..f10a4145d62 100644 --- a/app/views/projects/notes/_form.html.haml +++ b/app/views/projects/notes/_form.html.haml @@ -15,4 +15,4 @@ .note-form-actions.clearfix = f.submit 'Add Comment', class: "btn btn-nr btn-create comment-btn btn-grouped js-comment-button" = yield(:note_actions) - %a.btn.btn-cancel.js-close-discussion-note-form Cancel + %a.btn.btn-nr.btn-cancel.js-close-discussion-note-form Cancel -- cgit v1.2.1 From 1eb7b5ee8d5afeeea74ccbd5627e5a235dffe9fd Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Fri, 8 Jan 2016 22:57:42 +0100 Subject: Modify entities for builds API --- lib/api/builds.rb | 16 +++++++++++----- lib/api/entities.rb | 37 ++++++++++++++++++------------------- spec/requests/api/builds_spec.rb | 1 - 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/lib/api/builds.rb b/lib/api/builds.rb index 6aae1856953..33e6ed24101 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -15,7 +15,9 @@ module API get ':id/builds' do builds = user_project.builds.order('id DESC') builds = filter_builds(builds, params[:scope]) - present paginate(builds), with: Entities::Build + + present paginate(builds), with: Entities::Build, + user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project) end # Get builds for a specific commit of a project @@ -33,7 +35,8 @@ module API builds = commit.builds.order('id DESC') builds = filter_builds(builds, params[:scope]) - present paginate(builds), with: Entities::Build + present paginate(builds), with: Entities::Build, + user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project) end # Get a specific build of a project @@ -47,7 +50,8 @@ module API build = get_build(params[:build_id]) return not_found!(build) unless build - present build, with: Entities::Build + present build, with: Entities::Build, + user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project) end # Get a trace of a specific build of a project @@ -84,7 +88,8 @@ module API build.cancel - present build, with: Entities::Build + present build, with: Entities::Build, + user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project) end # Retry a specific build of a project @@ -102,7 +107,8 @@ module API build = Ci::Build.retry(build) - present build, with: Entities::Build + present build, with: Entities::Build, + user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project) end end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index f21da54b8fc..cb00b392db9 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -366,16 +366,8 @@ module API expose :id, :variables end - class CiCommit < Grape::Entity + class Runner < Grape::Entity expose :id - expose :ref - expose :sha - expose :committed_at - end - - class CiRunner < Grape::Entity - expose :id - expose :token expose :description expose :active expose :is_shared @@ -383,16 +375,23 @@ module API end class Build < Grape::Entity - expose :id - expose :status - expose :stage - expose :name - expose :ref - expose :commit, with: CiCommit - expose :runner, with: CiRunner - expose :created_at - expose :started_at - expose :finished_at + expose :id, :status, :stage, :name, :ref, :tag, :coverage, :user + expose :created_at, :started_at, :finished_at + expose :download_url do |repo_obj, options| + if options[:user_can_download_artifacts] + repo_obj.download_url + else + nil + end + end + expose :commit, with: RepoCommit do |repo_obj, _options| + if repo_obj.respond_to?(:commit) + repo_obj.commit.commit_data + else + nil + end + end + expose :runner, with: Runner end end end diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb index a953eb2fac2..1e58e18fad9 100644 --- a/spec/requests/api/builds_spec.rb +++ b/spec/requests/api/builds_spec.rb @@ -74,7 +74,6 @@ describe API::API, api: true do expect(response.status).to eq(200) expect(json_response['name']).to eq('test') - expect(json_response['commit']['sha']).to eq(commit.sha) end it 'should return specific build trace' do -- cgit v1.2.1 From d54bff2a770c1030056866a47097aee9937390ef Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Fri, 8 Jan 2016 23:04:44 +0100 Subject: Change test access level from MASTER to DEVELOPER This should help us detect potential regressions in the future. --- spec/requests/api/builds_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb index 1e58e18fad9..b6a1154cf76 100644 --- a/spec/requests/api/builds_spec.rb +++ b/spec/requests/api/builds_spec.rb @@ -6,7 +6,7 @@ describe API::API, api: true do let(:user) { create(:user) } let(:user2) { create(:user) } let!(:project) { create(:project, creator_id: user.id) } - let!(:master) { create(:project_member, user: user, project: project, access_level: ProjectMember::MASTER) } + let!(:developer) { create(:project_member, user: user, project: project, access_level: ProjectMember::DEVELOPER) } let!(:reporter) { create(:project_member, user: user2, project: project, access_level: ProjectMember::REPORTER) } let(:commit) { create(:ci_commit, project: project)} let(:build) { create(:ci_build, commit: commit) } -- cgit v1.2.1 From 4eb27d7c72d57015c7551a00e34a54cefc2d3db9 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Fri, 8 Jan 2016 23:33:45 +0100 Subject: Add some modifications to builds API and specs --- lib/api/builds.rb | 2 +- spec/requests/api/builds_spec.rb | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/api/builds.rb b/lib/api/builds.rb index 33e6ed24101..05d1b8d92ea 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -103,7 +103,7 @@ module API authorize_manage_builds! build = get_build(params[:build_id]) - return not_found!(build) unless build && build.retryable? + return forbidden!('Build is not retryable') unless build && build.retryable? build = Ci::Build.retry(build) diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb index b6a1154cf76..799558d1bdd 100644 --- a/spec/requests/api/builds_spec.rb +++ b/spec/requests/api/builds_spec.rb @@ -50,7 +50,7 @@ describe API::API, api: true do context 'authorized user' do it 'should return project builds for specific commit' do project.ensure_ci_commit(commit.sha) - get api("/projects/#{project.id}/builds/commit/#{project.ci_commits.first.sha}", user) + get api("/projects/#{project.id}/builds/commit/#{commit.sha}", user) expect(response.status).to eq(200) expect(json_response).to be_an Array @@ -60,7 +60,7 @@ describe API::API, api: true do context 'unauthorized user' do it 'should not return project builds' do project.ensure_ci_commit(commit.sha) - get api("/projects/#{project.id}/builds/commit/#{project.ci_commits.first.sha}") + get api("/projects/#{project.id}/builds/commit/#{commit.sha}") expect(response.status).to eq(401) end @@ -99,7 +99,7 @@ describe API::API, api: true do end end - describe 'GET /projects/:id/builds/:build_id/cancel' do + describe 'POST /projects/:id/builds/:build_id/cancel' do context 'authorized user' do context 'user with :manage_builds persmission' do it 'should cancel running or pending build' do @@ -128,7 +128,7 @@ describe API::API, api: true do end end - describe 'GET /projects/:id/builds/:build_id/retry' do + describe 'POST /projects/:id/builds/:build_id/retry' do context 'authorized user' do context 'user with :manage_builds persmission' do it 'should retry non-running build' do -- cgit v1.2.1 From 52f8286a02bab5af1ebbf0fb7bcccff56c74ab9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Fri, 8 Jan 2016 18:40:05 -0500 Subject: Update specs. #3945 --- spec/lib/gitlab/diff/highlight_spec.rb | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb index fc5cb894d2a..4ab509f47b9 100644 --- a/spec/lib/gitlab/diff/highlight_spec.rb +++ b/spec/lib/gitlab/diff/highlight_spec.rb @@ -6,24 +6,24 @@ describe Gitlab::Diff::Highlight, lib: true do let(:project) { create(:project) } let(:commit) { project.commit(sample_commit.id) } let(:diff) { commit.diffs.first } - let(:diff_file) { Gitlab::Diff::File.new(diff) } + let(:diff_file) { Gitlab::Diff::File.new(diff, [commit.parent.id, commit.id], project.repository) } describe '.process_diff_lines' do context 'when processing Gitlab::Diff::Line objects' do - let(:diff_lines) { Gitlab::Diff::Highlight.process_diff_lines(diff_file.new_path, diff_file.diff_lines) } + let(:diff_lines) { Gitlab::Diff::Highlight.process_diff_lines(diff_file) } it 'should return Gitlab::Diff::Line elements' do expect(diff_lines.first).to be_an_instance_of(Gitlab::Diff::Line) end it 'should highlight the code' do - code = %Q{ def popen(cmd, path=nil)\n} + code = %Q{ def popen(cmd, path=nil)\n} expect(diff_lines[2].text).to eq(code) end - it 'should keep the inline diff markup' do - expect(diff_lines[5].text).to match(Regexp.new(Regexp.escape('RuntimeError, '))) + it 'should not generate the inline diff markup' do + expect(diff_lines[5].text).not_to match(Regexp.new(Regexp.escape(''))) end it 'should not modify "match" lines' do @@ -31,19 +31,18 @@ describe Gitlab::Diff::Highlight, lib: true do expect(diff_lines[22].text).to eq('@@ -19,6 +25,7 @@ module Popen') end end + end - context 'when processing raw lines' do - let(:lines) { ["puts 'Hello'\n", "# A comment"] } - let(:highlighted_lines) { Gitlab::Diff::Highlight.process_diff_lines('demo.rb', lines) } - - it 'should highlight the code' do - line_1 = %Q{puts 'Hello'\n} - line_2 = %Q{# A comment} - - expect(highlighted_lines[0]).to eq(line_1) - expect(highlighted_lines[1]).to eq(line_2) - end + describe '.process_file' do + let(:lines) do + Gitlab::Diff::Highlight.process_file(project.repository, commit.id, 'files/ruby/popen.rb') end + it 'should properly highlight all the lines' do + expect(lines[4]).to eq(%Q{ extend self\n}) + expect(lines[21]).to eq(%Q{ unless File.directory?(path)\n}) + expect(lines[26]).to eq(%Q{ @cmd_status = 0\n}) + end end + end -- cgit v1.2.1 From 78d7c0e0d81c40e0d9541e4ef0dd15df30d457e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Fri, 8 Jan 2016 19:05:55 -0500 Subject: Fix broken specs. #3945 --- app/views/projects/diffs/_parallel_view.html.haml | 4 ++-- lib/gitlab/diff/highlight.rb | 10 +++++----- spec/helpers/diff_helper_spec.rb | 3 ++- spec/lib/gitlab/diff/file_spec.rb | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml index 1ad54d1848b..77069501d1c 100644 --- a/app/views/projects/diffs/_parallel_view.html.haml +++ b/app/views/projects/diffs/_parallel_view.html.haml @@ -20,7 +20,7 @@ = link_to raw(line_number_left), "##{line_code_left}", id: line_code_left - if @comments_allowed && can?(current_user, :create_note, @project) = link_to_new_diff_note(line_code_left, 'old') - %td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }= line_content_left.html_safe + %td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }= raw(line_content_left) - if type_right == 'new' - new_line_class = 'new' @@ -33,7 +33,7 @@ = link_to raw(line_number_right), "##{new_line_code}", id: new_line_code - if @comments_allowed && can?(current_user, :create_note, @project) = link_to_new_diff_note(line_code_right, 'new') - %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}= line_content_right.html_safe + %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}= raw(line_content_right) - if @reply_allowed - comments_left, comments_right = organize_comments(type_left, type_right, line_code_left, line_code_right) diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb index 7dd44b6004a..caeefe5bbdd 100644 --- a/lib/gitlab/diff/highlight.rb +++ b/lib/gitlab/diff/highlight.rb @@ -27,11 +27,11 @@ module Gitlab def self.formatter @formatter ||= Rouge::Formatters::HTMLGitlab.new( - nowrap: true, - cssclass: 'code highlight', - lineanchors: true, - lineanchorsid: 'LC' - ) + nowrap: true, + cssclass: 'code highlight', + lineanchors: true, + lineanchorsid: 'LC' + ) end def initialize(diff_file) diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb index 0501c2e8c29..84b8f4d1679 100644 --- a/spec/helpers/diff_helper_spec.rb +++ b/spec/helpers/diff_helper_spec.rb @@ -7,7 +7,8 @@ describe DiffHelper do let(:commit) { project.commit(sample_commit.id) } let(:diffs) { commit.diffs } let(:diff) { diffs.first } - let(:diff_file) { Gitlab::Diff::File.new(diff) } + let(:diff_refs) { [commit.parent.id, commit.id] } + let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs, project.repository) } describe 'diff_hard_limit_enabled?' do it 'should return true if param is provided' do diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb index c7cdf8691d6..97ba7f14eb1 100644 --- a/spec/lib/gitlab/diff/file_spec.rb +++ b/spec/lib/gitlab/diff/file_spec.rb @@ -6,7 +6,7 @@ describe Gitlab::Diff::File, lib: true do let(:project) { create(:project) } let(:commit) { project.commit(sample_commit.id) } let(:diff) { commit.diffs.first } - let(:diff_file) { Gitlab::Diff::File.new(diff) } + let(:diff_file) { Gitlab::Diff::File.new(diff, [commit.parent.id, commit.id], project.repository) } describe :diff_lines do let(:diff_lines) { diff_file.diff_lines } -- cgit v1.2.1 From 164c6374a708754086a1bca1033c46c01503056d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Fri, 8 Jan 2016 19:57:51 -0500 Subject: Fix broken specs. #3945 --- spec/fixtures/parallel_diff_result.yml | 156 ++++++++++++++++----------------- spec/helpers/diff_helper_spec.rb | 17 ++-- 2 files changed, 86 insertions(+), 87 deletions(-) diff --git a/spec/fixtures/parallel_diff_result.yml b/spec/fixtures/parallel_diff_result.yml index 16c4bac96df..020c1817226 100644 --- a/spec/fixtures/parallel_diff_result.yml +++ b/spec/fixtures/parallel_diff_result.yml @@ -1,86 +1,86 @@ --- - - match - 6 - - '@@ -6,12 +6,18 @@ module Popen' + - "@@ -6,12 +6,18 @@ module Popen" - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6 - match - 6 - - '@@ -6,12 +6,18 @@ module Popen' + - "@@ -6,12 +6,18 @@ module Popen" - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6 - - - 6 - - | - + - |2 + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6 - - 6 - - | - + - |2 + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6 - - - 7 - - | - def popen(cmd, path=nil) + - |2 + def popen(cmd, path=nil) - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7 - - 7 - - | - def popen(cmd, path=nil) + - |2 + def popen(cmd, path=nil) - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7 - - - 8 - - | - unless cmd.is_a?(Array) + - |2 + unless cmd.is_a?(Array) - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8 - - 8 - - | - unless cmd.is_a?(Array) + - |2 + unless cmd.is_a?(Array) - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8 - - old - 9 - | - - raise "System commands must be given as an array of strings" + - raise "System commands must be given as an array of strings" - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9 - new - 9 - | - + raise RuntimeError, "System commands must be given as an array of strings" + + raise RuntimeError, "System commands must be given as an array of strings" - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9 - - - 10 - - | - end + - |2 + end - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10 - - 10 - - | - end + - |2 + end - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10 - - - 11 - - | - + - |2 + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_11_11 - - 11 - - | - + - |2 + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_11_11 - - - 12 - - | - path ||= Dir.pwd + - |2 + path ||= Dir.pwd - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_12_12 - - 12 - - | - path ||= Dir.pwd + - |2 + path ||= Dir.pwd - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_12_12 - - old - 13 - | - - vars = { "PWD" => path } + - vars = { "PWD" => path } - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_13_13 - old - @@ -89,12 +89,12 @@ - - old - 14 - | - - options = { chdir: path } + - options = { chdir: path } - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_13 - new - 13 - | - + + + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_13 - - - @@ -103,7 +103,7 @@ - new - 14 - | - + vars = { + + vars = { - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14 - - - @@ -112,7 +112,7 @@ - new - 15 - | - + "PWD" => path + + "PWD" => path - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15 - - - @@ -121,7 +121,7 @@ - new - 16 - | - + } + + } - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_16 - - - @@ -130,7 +130,7 @@ - new - 17 - | - + + + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_17 - - - @@ -139,7 +139,7 @@ - new - 18 - | - + options = { + + options = { - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_18 - - - @@ -148,7 +148,7 @@ - new - 19 - | - + chdir: path + + chdir: path - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_19 - - - @@ -157,75 +157,75 @@ - new - 20 - | - + } + + } - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_20 - - - 15 - - | - + - |2 + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_21 - - 21 - - | - + - |2 + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_21 - - - 16 - - | - unless File.directory?(path) + - |2 + unless File.directory?(path) - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_16_22 - - 22 - - | - unless File.directory?(path) + - |2 + unless File.directory?(path) - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_16_22 - - - 17 - - | - FileUtils.mkdir_p(path) + - |2 + FileUtils.mkdir_p(path) - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23 - - 23 - - | - FileUtils.mkdir_p(path) + - |2 + FileUtils.mkdir_p(path) - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23 - - match - 19 - - '@@ -19,6 +25,7 @@ module Popen' + - "@@ -19,6 +25,7 @@ module Popen" - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25 - match - 25 - - '@@ -19,6 +25,7 @@ module Popen' + - "@@ -19,6 +25,7 @@ module Popen" - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25 - - - 19 - - | - + - |2 + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25 - - 25 - - | - + - |2 + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25 - - - 20 - - | - @cmd_output = "" + - |2 + @cmd_output = "" - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26 - - 26 - - | - @cmd_output = "" + - |2 + @cmd_output = "" - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26 - - - 21 - - | - @cmd_status = 0 + - |2 + @cmd_status = 0 - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_21_27 - - 27 - - | - @cmd_status = 0 + - |2 + @cmd_status = 0 - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_21_27 - - - @@ -234,37 +234,35 @@ - new - 28 - | - + + + - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_28 - - - 22 - - | - Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| + - |2 + Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_29 - - 29 - - | - Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| + - |2 + Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_29 - - - 23 - - | - @cmd_output << stdout.read + - |2 + @cmd_output << stdout.read - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_23_30 - - 30 - - | - @cmd_output << stdout.read + - |2 + @cmd_output << stdout.read - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_23_30 - - - 24 - - @cmd_output << stderr.read + - |2 + @cmd_output << stderr.read - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_24_31 - - 31 - - @cmd_output << stderr.read + - |2 + @cmd_output << stderr.read - 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_24_31 diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb index 84b8f4d1679..4b10ee3d33c 100644 --- a/spec/helpers/diff_helper_spec.rb +++ b/spec/helpers/diff_helper_spec.rb @@ -4,11 +4,12 @@ describe DiffHelper do include RepoHelpers let(:project) { create(:project) } + let(:repository) { project.repository } let(:commit) { project.commit(sample_commit.id) } let(:diffs) { commit.diffs } let(:diff) { diffs.first } let(:diff_refs) { [commit.parent.id, commit.id] } - let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs, project.repository) } + let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs, repository) } describe 'diff_hard_limit_enabled?' do it 'should return true if param is provided' do @@ -45,41 +46,41 @@ describe DiffHelper do describe 'safe_diff_files' do it 'should return all files from a commit that is smaller than safe limits' do - expect(safe_diff_files(diffs).length).to eq(2) + expect(safe_diff_files(diffs, diff_refs, repository).length).to eq(2) end it 'should return only the first file if the diff line count in the 2nd file takes the total beyond safe limits' do allow(diffs[1].diff).to receive(:lines).and_return([""] * 4999) #simulate 4999 lines - expect(safe_diff_files(diffs).length).to eq(1) + expect(safe_diff_files(diffs, diff_refs, repository).length).to eq(1) end it 'should return all files from a commit that is beyond safe limit for numbers of lines if force diff is true' do allow(controller).to receive(:params) { { force_show_diff: true } } allow(diffs[1].diff).to receive(:lines).and_return([""] * 4999) #simulate 4999 lines - expect(safe_diff_files(diffs).length).to eq(2) + expect(safe_diff_files(diffs, diff_refs, repository).length).to eq(2) end it 'should return only the first file if the diff line count in the 2nd file takes the total beyond hard limits' do allow(controller).to receive(:params) { { force_show_diff: true } } allow(diffs[1].diff).to receive(:lines).and_return([""] * 49999) #simulate 49999 lines - expect(safe_diff_files(diffs).length).to eq(1) + expect(safe_diff_files(diffs, diff_refs, repository).length).to eq(1) end it 'should return only a safe number of file diffs if a commit touches more files than the safe limits' do large_diffs = diffs * 100 #simulate 200 diffs - expect(safe_diff_files(large_diffs).length).to eq(100) + expect(safe_diff_files(large_diffs, diff_refs, repository).length).to eq(100) end it 'should return all file diffs if a commit touches more files than the safe limits but force diff is true' do allow(controller).to receive(:params) { { force_show_diff: true } } large_diffs = diffs * 100 #simulate 200 diffs - expect(safe_diff_files(large_diffs).length).to eq(200) + expect(safe_diff_files(large_diffs, diff_refs, repository).length).to eq(200) end it 'should return a limited file diffs if a commit touches more files than the hard limits and force diff is true' do allow(controller).to receive(:params) { { force_show_diff: true } } very_large_diffs = diffs * 1000 #simulate 2000 diffs - expect(safe_diff_files(very_large_diffs).length).to eq(1000) + expect(safe_diff_files(very_large_diffs, diff_refs, repository).length).to eq(1000) end end -- cgit v1.2.1 From fed10766e533fcef2a6840deeb8d7ea1747f0c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Sat, 9 Jan 2016 01:55:31 -0500 Subject: Fix broken spec for submodule commit. #3945 --- lib/gitlab/diff/highlight.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb index caeefe5bbdd..3c44abff3fb 100644 --- a/lib/gitlab/diff/highlight.rb +++ b/lib/gitlab/diff/highlight.rb @@ -85,10 +85,14 @@ module Gitlab case diff_line.type when 'new', nil - diff_line.text = new_lines[diff_line.new_pos - 1].try(:gsub!, /\A\s/, line_prefix) + line = new_lines[diff_line.new_pos - 1] when 'old' - diff_line.text = old_lines[diff_line.old_pos - 1].try(:gsub!, /\A\s/, line_prefix) + line = old_lines[diff_line.old_pos - 1] end + + # Only update text if line is found. This will prevent + # issues with submodules given the line only exists in diff content. + diff_line.text = line.gsub!(/\A\s/, line_prefix) if line end @lines @@ -121,6 +125,10 @@ module Gitlab lines.map! { |line| " #{line}" } end end + + def submodules + @submodules ||= diff_repository.raw_repository.submodules(diff_new_ref).keys + end end end end -- cgit v1.2.1 From 58867eff46dc6886b85bfe5a787341f224d09421 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Wed, 9 Dec 2015 11:59:25 +0100 Subject: Unsubscribe from thread through link in email footer --- CHANGELOG | 1 + app/controllers/sent_notifications_controller.rb | 25 ++++++++++ app/mailers/emails/issues.rb | 38 +++++++-------- app/mailers/emails/merge_requests.rb | 55 +++++++++------------- app/mailers/emails/notes.rb | 42 ++++++++--------- app/mailers/notify.rb | 5 +- app/models/concerns/issuable.rb | 6 +++ app/models/sent_notification.rb | 8 ++-- app/views/layouts/notify.html.haml | 8 +++- config/routes.rb | 6 +++ .../sent_notification_controller_spec.rb | 26 ++++++++++ spec/factories.rb | 7 +++ spec/mailers/notify_spec.rb | 34 ++++++++++++- 13 files changed, 176 insertions(+), 85 deletions(-) create mode 100644 app/controllers/sent_notifications_controller.rb create mode 100644 spec/controllers/sent_notification_controller_spec.rb diff --git a/CHANGELOG b/CHANGELOG index 921dac01264..38c0dbf0934 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -59,6 +59,7 @@ v 8.3.0 - Add open_issues_count to project API (Stan Hu) - Expand character set of usernames created by Omniauth (Corey Hinshaw) - Add button to automatically merge a merge request when the build succeeds (Zeger-Jan van de Weg) + - Add unsubscribe link in the email footer (Zeger-Jan van de Weg) - Provide better diagnostic message upon project creation errors (Stan Hu) - Bump devise to 3.5.3 to fix reset token expiring after account creation (Stan Hu) - Remove api credentials from link to build_page diff --git a/app/controllers/sent_notifications_controller.rb b/app/controllers/sent_notifications_controller.rb new file mode 100644 index 00000000000..93dcc16094f --- /dev/null +++ b/app/controllers/sent_notifications_controller.rb @@ -0,0 +1,25 @@ +class SentNotificationsController < ApplicationController + skip_before_action :authenticate_user! + + def unsubscribe + @sent_notification = SentNotification.for(params[:id]) + return render_404 unless @sent_notification && !@sent_notification.for_commit? + + noteable = @sent_notification.noteable + noteable.unsubscribe(@sent_notification.recipient) + + flash[:notice] = "You have been unsubscribed from this thread." + if current_user + case @sent_notification.noteable + when Issue + redirect_to issue_path(noteable) + when MergeRequest + redirect_to merge_request_path(noteable) + else + redirect_to root_path + end + else + redirect_to new_user_session_path + end + end +end diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb index abdeefed5ef..4a88cb61132 100644 --- a/app/mailers/emails/issues.rb +++ b/app/mailers/emails/issues.rb @@ -1,31 +1,31 @@ module Emails module Issues def new_issue_email(recipient_id, issue_id) - issue_mail_with_notification(issue_id, recipient_id) do - mail_new_thread(@issue, issue_thread_options(@issue.author_id, recipient_id)) - end + setup_issue_mail(issue_id, recipient_id) + + mail_new_thread(@issue, issue_thread_options(@issue.author_id, recipient_id)) end def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id, updated_by_user_id) - issue_mail_with_notification(issue_id, recipient_id) do - @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id - mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) - end + setup_issue_mail(issue_id, recipient_id) + + @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id + mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) end def closed_issue_email(recipient_id, issue_id, updated_by_user_id) - issue_mail_with_notification(issue_id, recipient_id) do - @updated_by = User.find updated_by_user_id - mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) - end + setup_issue_mail(issue_id, recipient_id) + + @updated_by = User.find updated_by_user_id + mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) end def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id) - issue_mail_with_notification(issue_id, recipient_id) do - @issue_status = status - @updated_by = User.find updated_by_user_id - mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) - end + setup_issue_mail(issue_id, recipient_id) + + @issue_status = status + @updated_by = User.find updated_by_user_id + mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id)) end private @@ -38,14 +38,12 @@ module Emails } end - def issue_mail_with_notification(issue_id, recipient_id) + def setup_issue_mail(issue_id, recipient_id) @issue = Issue.find(issue_id) @project = @issue.project @target_url = namespace_project_issue_url(@project.namespace, @project, @issue) - yield - - SentNotification.record(@issue, recipient_id, reply_key) + @sent_notification = SentNotification.record(@issue, recipient_id, reply_key) end end end diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb index 7923fb770d0..325996e2e16 100644 --- a/app/mailers/emails/merge_requests.rb +++ b/app/mailers/emails/merge_requests.rb @@ -1,77 +1,64 @@ module Emails module MergeRequests def new_merge_request_email(recipient_id, merge_request_id) - @merge_request = MergeRequest.find(merge_request_id) - @project = @merge_request.project - @target_url = namespace_project_merge_request_url(@project.namespace, - @project, - @merge_request) + setup_merge_request_mail(merge_request_id, recipient_id) + mail_new_thread(@merge_request, from: sender(@merge_request.author_id), to: recipient(recipient_id), subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) - - SentNotification.record(@merge_request, recipient_id, reply_key) end def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id, updated_by_user_id) - @merge_request = MergeRequest.find(merge_request_id) + setup_merge_request_mail(merge_request_id, recipient_id) + @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id - @project = @merge_request.project - @target_url = namespace_project_merge_request_url(@project.namespace, - @project, - @merge_request) mail_answer_thread(@merge_request, from: sender(updated_by_user_id), to: recipient(recipient_id), subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) - - SentNotification.record(@merge_request, recipient_id, reply_key) end def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id) - @merge_request = MergeRequest.find(merge_request_id) + setup_merge_request_mail(merge_request_id, recipient_id) + @updated_by = User.find updated_by_user_id - @project = @merge_request.project - @target_url = namespace_project_merge_request_url(@project.namespace, - @project, - @merge_request) mail_answer_thread(@merge_request, from: sender(updated_by_user_id), to: recipient(recipient_id), subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) - - SentNotification.record(@merge_request, recipient_id, reply_key) end def merged_merge_request_email(recipient_id, merge_request_id, updated_by_user_id) - @merge_request = MergeRequest.find(merge_request_id) - @project = @merge_request.project - @target_url = namespace_project_merge_request_url(@project.namespace, - @project, - @merge_request) + setup_merge_request_mail(merge_request_id, recipient_id) + mail_answer_thread(@merge_request, from: sender(updated_by_user_id), to: recipient(recipient_id), subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) - - SentNotification.record(@merge_request, recipient_id, reply_key) end def merge_request_status_email(recipient_id, merge_request_id, status, updated_by_user_id) - @merge_request = MergeRequest.find(merge_request_id) + setup_merge_request_mail(merge_request_id, recipient_id) + @mr_status = status - @project = @merge_request.project @updated_by = User.find updated_by_user_id - @target_url = namespace_project_merge_request_url(@project.namespace, - @project, - @merge_request) mail_answer_thread(@merge_request, from: sender(updated_by_user_id), to: recipient(recipient_id), subject: subject("#{@merge_request.title} (##{@merge_request.iid})")) + end + + private + + def setup_merge_request_mail(merge_request_id, recipient_id) + @merge_request = MergeRequest.find(merge_request_id) + @project = @merge_request.project + @target_url = namespace_project_merge_request_url(@project.namespace, + @project, + @merge_request) - SentNotification.record(@merge_request, recipient_id, reply_key) + @sent_notification = SentNotification.record(@merge_request, recipient_id, reply_key) end end end diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb index e1382d2da12..ccd33b880f7 100644 --- a/app/mailers/emails/notes.rb +++ b/app/mailers/emails/notes.rb @@ -1,31 +1,31 @@ module Emails module Notes def note_commit_email(recipient_id, note_id) - note_mail_with_notification(note_id, recipient_id) do - @commit = @note.noteable - @target_url = namespace_project_commit_url(*note_target_url_options) - - mail_answer_thread(@commit, - from: sender(@note.author_id), - to: recipient(recipient_id), - subject: subject("#{@commit.title} (#{@commit.short_id})")) - end + note_mail_with_notification(note_id, recipient_id) + + @commit = @note.noteable + @target_url = namespace_project_commit_url(*note_target_url_options) + + mail_answer_thread(@commit, + from: sender(@note.author_id), + to: recipient(recipient_id), + subject: subject("#{@commit.title} (#{@commit.short_id})")) end def note_issue_email(recipient_id, note_id) - note_mail_with_notification(note_id, recipient_id) do - @issue = @note.noteable - @target_url = namespace_project_issue_url(*note_target_url_options) - mail_answer_thread(@issue, note_thread_options(recipient_id)) - end + note_mail_with_notification(note_id, recipient_id) + + @issue = @note.noteable + @target_url = namespace_project_issue_url(*note_target_url_options) + mail_answer_thread(@issue, note_thread_options(recipient_id)) end def note_merge_request_email(recipient_id, note_id) - note_mail_with_notification(note_id, recipient_id) do - @merge_request = @note.noteable - @target_url = namespace_project_merge_request_url(*note_target_url_options) - mail_answer_thread(@merge_request, note_thread_options(recipient_id)) - end + note_mail_with_notification(note_id, recipient_id) + + @merge_request = @note.noteable + @target_url = namespace_project_merge_request_url(*note_target_url_options) + mail_answer_thread(@merge_request, note_thread_options(recipient_id)) end private @@ -46,9 +46,7 @@ module Emails @note = Note.find(note_id) @project = @note.project - yield - - SentNotification.record_note(@note, recipient_id, reply_key) + @sent_notification = SentNotification.record_note(@note, recipient_id, reply_key) end end end diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index 3bbdd9cee76..e1cd075a978 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -107,10 +107,9 @@ class Notify < BaseMailer end headers["X-GitLab-#{model.class.name}-ID"] = model.id + headers['X-GitLab-Reply-Key'] = reply_key - if reply_key - headers['X-GitLab-Reply-Key'] = reply_key - + if Gitlab::IncomingEmail.enabled? address = Mail::Address.new(Gitlab::IncomingEmail.reply_address(reply_key)) address.display_name = @project.name_with_namespace diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 18a00f95b48..04650a9e67a 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -119,6 +119,12 @@ module Issuable update(subscribed: !subscribed?(user)) end + def unsubscribe(user) + subscriptions. + find_or_initialize_by(user_id: user.id). + update(subscribed: false) + end + def to_hook_data(user) { object_kind: self.class.name.underscore, diff --git a/app/models/sent_notification.rb b/app/models/sent_notification.rb index f36eda1531b..fd12615717b 100644 --- a/app/models/sent_notification.rb +++ b/app/models/sent_notification.rb @@ -25,8 +25,6 @@ class SentNotification < ActiveRecord::Base class << self def reply_key - return nil unless Gitlab::IncomingEmail.enabled? - SecureRandom.hex(16) end @@ -59,7 +57,7 @@ class SentNotification < ActiveRecord::Base def record_note(note, recipient_id, reply_key, params = {}) params[:line_code] = note.line_code - + record(note.noteable, recipient_id, reply_key, params) end end @@ -75,4 +73,8 @@ class SentNotification < ActiveRecord::Base super end end + + def to_param + self.reply_key + end end diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml index 3ca4c340406..da7de41abad 100644 --- a/app/views/layouts/notify.html.haml +++ b/app/views/layouts/notify.html.haml @@ -44,6 +44,10 @@ %br -# Don't link the host is the line below, one link in the email is easier to quickly click than two. You're receiving this email because of your account on #{Gitlab.config.gitlab.host}. - If you'd like to receive fewer emails, you can adjust your notification settings. + If you'd like to receive fewer emails, you can + - if @sent_notification && !@sent_notification.for_commit? + = link_to "unsubscribe", unsubscribe_sent_notification_url(@sent_notification) + from this thread or + adjust your notification settings. - = email_action @target_url \ No newline at end of file + = email_action @target_url diff --git a/config/routes.rb b/config/routes.rb index 4fcea1185c0..2739e4961f7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -88,6 +88,12 @@ Rails.application.routes.draw do end end + resources :sent_notifications, only: [], constraints: { id: /[0-9a-f]{32}/ } do + member do + get :unsubscribe + end + end + # Spam reports resources :abuse_reports, only: [:new, :create] diff --git a/spec/controllers/sent_notification_controller_spec.rb b/spec/controllers/sent_notification_controller_spec.rb new file mode 100644 index 00000000000..9ced397bd4a --- /dev/null +++ b/spec/controllers/sent_notification_controller_spec.rb @@ -0,0 +1,26 @@ +require 'rails_helper' + +describe SentNotificationsController, type: :controller do + let(:user) { create(:user) } + let(:issue) { create(:issue, author: user) } + let(:sent_notification) { create(:sent_notification, noteable: issue) } + + describe 'GET #unsubscribe' do + it 'returns a 404 when calling without existing id' do + get(:unsubscribe, id: '0' * 32) + + expect(response.status).to be 404 + end + + context 'calling with id' do + it 'shows a flash message to the user' do + get(:unsubscribe, id: sent_notification.reply_key) + + expect(response.status).to be 302 + + expect(response).to redirect_to new_user_session_path + expect(controller).to set_flash[:notice].to(/unsubscribed/).now + end + end + end +end diff --git a/spec/factories.rb b/spec/factories.rb index d6b4efa9a03..2a81684dfcf 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -212,4 +212,11 @@ FactoryGirl.define do provider 'ldapmain' extern_uid 'my-ldap-id' end + + factory :sent_notification do + project + recipient factory: :user + noteable factory: :issue + reply_key "0123456789abcdef" * 2 + end end diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 154901a2fbc..08ade644643 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -104,6 +104,14 @@ describe Notify do it { is_expected.to have_body_text /View Commit/ } end + shared_examples 'an unsubscribeable thread' do + it { is_expected.to have_body_text /unsubscribe/ } + end + + shared_examples "a user can not unsubscribe through footer link" do + it { is_expected.not_to have_body_text /unsubscribe/ } + end + describe 'for new users, the email' do let(:example_site_path) { root_path } let(:new_user) { create(:user, email: new_user_address, created_by_id: 1) } @@ -115,6 +123,7 @@ describe Notify do it_behaves_like 'an email sent from GitLab' it_behaves_like 'a new user email', new_user_address it_behaves_like 'it should not have Gmail Actions links' + it_behaves_like 'a user can not unsubscribe through footer link' it 'contains the password text' do is_expected.to have_body_text /Click here to set your password/ @@ -134,7 +143,6 @@ describe Notify do end end - describe 'for users that signed up, the email' do let(:example_site_path) { root_path } let(:new_user) { create(:user, email: new_user_address, password: "securePassword") } @@ -144,6 +152,7 @@ describe Notify do it_behaves_like 'an email sent from GitLab' it_behaves_like 'a new user email', new_user_address it_behaves_like 'it should not have Gmail Actions links' + it_behaves_like 'a user can not unsubscribe through footer link' it 'should not contain the new user\'s password' do is_expected.not_to have_body_text /password/ @@ -157,6 +166,7 @@ describe Notify do it_behaves_like 'an email sent from GitLab' it_behaves_like 'it should not have Gmail Actions links' + it_behaves_like 'a user can not unsubscribe through footer link' it 'is sent to the new user' do is_expected.to deliver_to key.user.email @@ -181,6 +191,7 @@ describe Notify do subject { Notify.new_email_email(email.id) } it_behaves_like 'it should not have Gmail Actions links' + it_behaves_like 'a user can not unsubscribe through footer link' it 'is sent to the new user' do is_expected.to deliver_to email.user.email @@ -227,6 +238,7 @@ describe Notify do it_behaves_like 'an assignee email' it_behaves_like 'an email starting a new thread', 'issue' it_behaves_like 'it should show Gmail Actions View Issue link' + it_behaves_like 'an unsubscribeable thread' it 'has the correct subject' do is_expected.to have_subject /#{project.name} \| #{issue.title} \(##{issue.iid}\)/ @@ -253,6 +265,7 @@ describe Notify do it_behaves_like 'a multiple recipients email' it_behaves_like 'an answer to an existing thread', 'issue' it_behaves_like 'it should show Gmail Actions View Issue link' + it_behaves_like "an unsubscribeable thread" it 'is sent as the author' do sender = subject.header[:from].addrs[0] @@ -283,6 +296,7 @@ describe Notify do it_behaves_like 'an answer to an existing thread', 'issue' it_behaves_like 'it should show Gmail Actions View Issue link' + it_behaves_like 'an unsubscribeable thread' it 'is sent as the author' do sender = subject.header[:from].addrs[0] @@ -319,6 +333,7 @@ describe Notify do it_behaves_like 'an assignee email' it_behaves_like 'an email starting a new thread', 'merge_request' it_behaves_like 'it should show Gmail Actions View Merge request link' + it_behaves_like "an unsubscribeable thread" it 'has the correct subject' do is_expected.to have_subject /#{merge_request.title} \(##{merge_request.iid}\)/ @@ -345,6 +360,7 @@ describe Notify do subject { Notify.new_merge_request_email(merge_request_with_description.assignee_id, merge_request_with_description.id) } it_behaves_like 'it should show Gmail Actions View Merge request link' + it_behaves_like "an unsubscribeable thread" it 'contains the description' do is_expected.to have_body_text /#{merge_request_with_description.description}/ @@ -357,6 +373,7 @@ describe Notify do it_behaves_like 'a multiple recipients email' it_behaves_like 'an answer to an existing thread', 'merge_request' it_behaves_like 'it should show Gmail Actions View Merge request link' + it_behaves_like "an unsubscribeable thread" it 'is sent as the author' do sender = subject.header[:from].addrs[0] @@ -387,6 +404,7 @@ describe Notify do it_behaves_like 'an answer to an existing thread', 'merge_request' it_behaves_like 'it should show Gmail Actions View Merge request link' + it_behaves_like "an unsubscribeable thread" it 'is sent as the author' do sender = subject.header[:from].addrs[0] @@ -417,6 +435,7 @@ describe Notify do it_behaves_like 'a multiple recipients email' it_behaves_like 'an answer to an existing thread', 'merge_request' it_behaves_like 'it should show Gmail Actions View Merge request link' + it_behaves_like "an unsubscribeable thread" it 'is sent as the merge author' do sender = subject.header[:from].addrs[0] @@ -446,6 +465,7 @@ describe Notify do it_behaves_like 'an email sent from GitLab' it_behaves_like 'it should not have Gmail Actions links' + it_behaves_like "a user can not unsubscribe through footer link" it 'has the correct subject' do is_expected.to have_subject /Project was moved/ @@ -468,6 +488,7 @@ describe Notify do it_behaves_like 'an email sent from GitLab' it_behaves_like 'it should not have Gmail Actions links' + it_behaves_like "a user can not unsubscribe through footer link" it 'has the correct subject' do is_expected.to have_subject /Access to project was granted/ @@ -518,6 +539,7 @@ describe Notify do it_behaves_like 'a note email' it_behaves_like 'an answer to an existing thread', 'commit' it_behaves_like 'it should show Gmail Actions View Commit link' + it_behaves_like "a user can not unsubscribe through footer link" it 'has the correct subject' do is_expected.to have_subject /#{commit.title} \(#{commit.short_id}\)/ @@ -538,6 +560,7 @@ describe Notify do it_behaves_like 'a note email' it_behaves_like 'an answer to an existing thread', 'merge_request' it_behaves_like 'it should show Gmail Actions View Merge request link' + it_behaves_like 'an unsubscribeable thread' it 'has the correct subject' do is_expected.to have_subject /#{merge_request.title} \(##{merge_request.iid}\)/ @@ -558,6 +581,7 @@ describe Notify do it_behaves_like 'a note email' it_behaves_like 'an answer to an existing thread', 'issue' it_behaves_like 'it should show Gmail Actions View Issue link' + it_behaves_like 'an unsubscribeable thread' it 'has the correct subject' do is_expected.to have_subject /#{issue.title} \(##{issue.iid}\)/ @@ -579,6 +603,7 @@ describe Notify do it_behaves_like 'an email sent from GitLab' it_behaves_like 'it should not have Gmail Actions links' + it_behaves_like "a user can not unsubscribe through footer link" it 'has the correct subject' do is_expected.to have_subject /Access to group was granted/ @@ -607,6 +632,7 @@ describe Notify do subject { ActionMailer::Base.deliveries.last } it_behaves_like 'an email sent from GitLab' + it_behaves_like "a user can not unsubscribe through footer link" it 'is sent to the new user' do is_expected.to deliver_to 'new-email@mail.com' @@ -629,6 +655,7 @@ describe Notify do subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :create) } it_behaves_like 'it should not have Gmail Actions links' + it_behaves_like "a user can not unsubscribe through footer link" it 'is sent as the author' do sender = subject.header[:from].addrs[0] @@ -657,6 +684,7 @@ describe Notify do subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/tags/v1.0', action: :create) } it_behaves_like 'it should not have Gmail Actions links' + it_behaves_like "a user can not unsubscribe through footer link" it 'is sent as the author' do sender = subject.header[:from].addrs[0] @@ -684,6 +712,7 @@ describe Notify do subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :delete) } it_behaves_like 'it should not have Gmail Actions links' + it_behaves_like "a user can not unsubscribe through footer link" it 'is sent as the author' do sender = subject.header[:from].addrs[0] @@ -707,6 +736,7 @@ describe Notify do subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/tags/v1.0', action: :delete) } it_behaves_like 'it should not have Gmail Actions links' + it_behaves_like "a user can not unsubscribe through footer link" it 'is sent as the author' do sender = subject.header[:from].addrs[0] @@ -734,6 +764,7 @@ describe Notify do subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare, reverse_compare: false, send_from_committer_email: send_from_committer_email) } it_behaves_like 'it should not have Gmail Actions links' + it_behaves_like "a user can not unsubscribe through footer link" it 'is sent as the author' do sender = subject.header[:from].addrs[0] @@ -839,6 +870,7 @@ describe Notify do subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare) } it_behaves_like 'it should show Gmail Actions View Commit link' + it_behaves_like "a user can not unsubscribe through footer link" it 'is sent as the author' do sender = subject.header[:from].addrs[0] -- cgit v1.2.1 From 36d858bcf98868426256ce51a28e7029b38e0c2d Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Sat, 9 Jan 2016 12:47:31 +0100 Subject: Add #can_unsubscribe? to SentNotification --- app/models/sent_notification.rb | 4 ++++ app/views/layouts/notify.html.haml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/sent_notification.rb b/app/models/sent_notification.rb index fd12615717b..03108da17be 100644 --- a/app/models/sent_notification.rb +++ b/app/models/sent_notification.rb @@ -62,6 +62,10 @@ class SentNotification < ActiveRecord::Base end end + def can_unsubscribe? + !for_commit? + end + def for_commit? noteable_type == "Commit" end diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml index da7de41abad..07f9be12f99 100644 --- a/app/views/layouts/notify.html.haml +++ b/app/views/layouts/notify.html.haml @@ -45,7 +45,7 @@ -# Don't link the host is the line below, one link in the email is easier to quickly click than two. You're receiving this email because of your account on #{Gitlab.config.gitlab.host}. If you'd like to receive fewer emails, you can - - if @sent_notification && !@sent_notification.for_commit? + - if @sent_notification && @sent_notification.can_unsubscribe? = link_to "unsubscribe", unsubscribe_sent_notification_url(@sent_notification) from this thread or adjust your notification settings. -- cgit v1.2.1 From ee2230c3291354035f52cc4d87e3340982367fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Sat, 9 Jan 2016 02:24:30 -0500 Subject: Fix css for other highlighting themes. #3945 --- app/assets/stylesheets/highlight/dark.scss | 4 ++++ app/assets/stylesheets/highlight/solarized_dark.scss | 4 ++++ app/assets/stylesheets/highlight/solarized_light.scss | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss index f7d1334705f..8201735beb5 100644 --- a/app/assets/stylesheets/highlight/dark.scss +++ b/app/assets/stylesheets/highlight/dark.scss @@ -92,12 +92,16 @@ .il { color: #de935f } /* Literal.Number.Integer.Long */ .line_holder { + &.parallel .new.new_line, + &.parallel .new.line_content, &.new .old_line, &.new .new_line, &.new .line_content { @include diff_background(255, 255, 255, #808080); } + &.parallel .old.old_line, + &.parallel .old.line_content, &.old .old_line, &.old .new_line, &.old .line_content { diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss index 2c3648274cf..fdfac6cd249 100644 --- a/app/assets/stylesheets/highlight/solarized_dark.scss +++ b/app/assets/stylesheets/highlight/solarized_dark.scss @@ -113,12 +113,16 @@ .il { color: #2aa198 } /* Literal.Number.Integer.Long */ .line_holder { + &.parallel .new.new_line, + &.parallel .new.line_content, &.new .old_line, &.new .new_line, &.new .line_content { @include diff_background(255, 255, 255, #808080); } + &.parallel .old.old_line, + &.parallel .old.line_content, &.old .old_line, &.old .new_line, &.old .line_content { diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss index c16473ffe66..f9788951aa8 100644 --- a/app/assets/stylesheets/highlight/solarized_light.scss +++ b/app/assets/stylesheets/highlight/solarized_light.scss @@ -114,12 +114,16 @@ .line_holder { + &.parallel .new.new_line, + &.parallel .new.line_content, &.new .old_line, &.new .new_line, &.new .line_content { @include diff_background(92, 164, 169, #FAF3DD); } + &.parallel .old.old_line, + &.parallel .old.line_content, &.old .old_line, &.old .new_line, &.old .line_content { -- cgit v1.2.1 From 26cedc7e0bd83fc488da3a4dc5265d395639215f Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Sat, 9 Jan 2016 19:32:03 +0100 Subject: Minor improvements, unsubscribe from email footer --- app/controllers/sent_notifications_controller.rb | 4 +-- app/mailers/emails/notes.rb | 8 +++--- config/routes.rb | 2 +- spec/mailers/notify_spec.rb | 32 ++++++++++++------------ 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/app/controllers/sent_notifications_controller.rb b/app/controllers/sent_notifications_controller.rb index 93dcc16094f..b7008c82bf2 100644 --- a/app/controllers/sent_notifications_controller.rb +++ b/app/controllers/sent_notifications_controller.rb @@ -3,14 +3,14 @@ class SentNotificationsController < ApplicationController def unsubscribe @sent_notification = SentNotification.for(params[:id]) - return render_404 unless @sent_notification && !@sent_notification.for_commit? + return render_404 unless @sent_notification && @sent_notification.can_unsubscribe? noteable = @sent_notification.noteable noteable.unsubscribe(@sent_notification.recipient) flash[:notice] = "You have been unsubscribed from this thread." if current_user - case @sent_notification.noteable + case noteable when Issue redirect_to issue_path(noteable) when MergeRequest diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb index ccd33b880f7..f9650df9a74 100644 --- a/app/mailers/emails/notes.rb +++ b/app/mailers/emails/notes.rb @@ -1,7 +1,7 @@ module Emails module Notes def note_commit_email(recipient_id, note_id) - note_mail_with_notification(note_id, recipient_id) + setup_note_mail(note_id, recipient_id) @commit = @note.noteable @target_url = namespace_project_commit_url(*note_target_url_options) @@ -13,7 +13,7 @@ module Emails end def note_issue_email(recipient_id, note_id) - note_mail_with_notification(note_id, recipient_id) + setup_note_mail(note_id, recipient_id) @issue = @note.noteable @target_url = namespace_project_issue_url(*note_target_url_options) @@ -21,7 +21,7 @@ module Emails end def note_merge_request_email(recipient_id, note_id) - note_mail_with_notification(note_id, recipient_id) + setup_note_mail(note_id, recipient_id) @merge_request = @note.noteable @target_url = namespace_project_merge_request_url(*note_target_url_options) @@ -42,7 +42,7 @@ module Emails } end - def note_mail_with_notification(note_id, recipient_id) + def setup_note_mail(note_id, recipient_id) @note = Note.find(note_id) @project = @note.project diff --git a/config/routes.rb b/config/routes.rb index 2739e4961f7..0fd72ae78eb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -88,7 +88,7 @@ Rails.application.routes.draw do end end - resources :sent_notifications, only: [], constraints: { id: /[0-9a-f]{32}/ } do + resources :sent_notifications, only: [], constraints: { id: /\h{32}/ } do member do get :unsubscribe end diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 08ade644643..8f86c491d3f 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -108,7 +108,7 @@ describe Notify do it { is_expected.to have_body_text /unsubscribe/ } end - shared_examples "a user can not unsubscribe through footer link" do + shared_examples "a user cannot unsubscribe through footer link" do it { is_expected.not_to have_body_text /unsubscribe/ } end @@ -123,7 +123,7 @@ describe Notify do it_behaves_like 'an email sent from GitLab' it_behaves_like 'a new user email', new_user_address it_behaves_like 'it should not have Gmail Actions links' - it_behaves_like 'a user can not unsubscribe through footer link' + it_behaves_like 'a user cannot unsubscribe through footer link' it 'contains the password text' do is_expected.to have_body_text /Click here to set your password/ @@ -152,7 +152,7 @@ describe Notify do it_behaves_like 'an email sent from GitLab' it_behaves_like 'a new user email', new_user_address it_behaves_like 'it should not have Gmail Actions links' - it_behaves_like 'a user can not unsubscribe through footer link' + it_behaves_like 'a user cannot unsubscribe through footer link' it 'should not contain the new user\'s password' do is_expected.not_to have_body_text /password/ @@ -166,7 +166,7 @@ describe Notify do it_behaves_like 'an email sent from GitLab' it_behaves_like 'it should not have Gmail Actions links' - it_behaves_like 'a user can not unsubscribe through footer link' + it_behaves_like 'a user cannot unsubscribe through footer link' it 'is sent to the new user' do is_expected.to deliver_to key.user.email @@ -191,7 +191,7 @@ describe Notify do subject { Notify.new_email_email(email.id) } it_behaves_like 'it should not have Gmail Actions links' - it_behaves_like 'a user can not unsubscribe through footer link' + it_behaves_like 'a user cannot unsubscribe through footer link' it 'is sent to the new user' do is_expected.to deliver_to email.user.email @@ -465,7 +465,7 @@ describe Notify do it_behaves_like 'an email sent from GitLab' it_behaves_like 'it should not have Gmail Actions links' - it_behaves_like "a user can not unsubscribe through footer link" + it_behaves_like "a user cannot unsubscribe through footer link" it 'has the correct subject' do is_expected.to have_subject /Project was moved/ @@ -488,7 +488,7 @@ describe Notify do it_behaves_like 'an email sent from GitLab' it_behaves_like 'it should not have Gmail Actions links' - it_behaves_like "a user can not unsubscribe through footer link" + it_behaves_like "a user cannot unsubscribe through footer link" it 'has the correct subject' do is_expected.to have_subject /Access to project was granted/ @@ -539,7 +539,7 @@ describe Notify do it_behaves_like 'a note email' it_behaves_like 'an answer to an existing thread', 'commit' it_behaves_like 'it should show Gmail Actions View Commit link' - it_behaves_like "a user can not unsubscribe through footer link" + it_behaves_like "a user cannot unsubscribe through footer link" it 'has the correct subject' do is_expected.to have_subject /#{commit.title} \(#{commit.short_id}\)/ @@ -603,7 +603,7 @@ describe Notify do it_behaves_like 'an email sent from GitLab' it_behaves_like 'it should not have Gmail Actions links' - it_behaves_like "a user can not unsubscribe through footer link" + it_behaves_like "a user cannot unsubscribe through footer link" it 'has the correct subject' do is_expected.to have_subject /Access to group was granted/ @@ -632,7 +632,7 @@ describe Notify do subject { ActionMailer::Base.deliveries.last } it_behaves_like 'an email sent from GitLab' - it_behaves_like "a user can not unsubscribe through footer link" + it_behaves_like "a user cannot unsubscribe through footer link" it 'is sent to the new user' do is_expected.to deliver_to 'new-email@mail.com' @@ -655,7 +655,7 @@ describe Notify do subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :create) } it_behaves_like 'it should not have Gmail Actions links' - it_behaves_like "a user can not unsubscribe through footer link" + it_behaves_like "a user cannot unsubscribe through footer link" it 'is sent as the author' do sender = subject.header[:from].addrs[0] @@ -684,7 +684,7 @@ describe Notify do subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/tags/v1.0', action: :create) } it_behaves_like 'it should not have Gmail Actions links' - it_behaves_like "a user can not unsubscribe through footer link" + it_behaves_like "a user cannot unsubscribe through footer link" it 'is sent as the author' do sender = subject.header[:from].addrs[0] @@ -712,7 +712,7 @@ describe Notify do subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :delete) } it_behaves_like 'it should not have Gmail Actions links' - it_behaves_like "a user can not unsubscribe through footer link" + it_behaves_like "a user cannot unsubscribe through footer link" it 'is sent as the author' do sender = subject.header[:from].addrs[0] @@ -736,7 +736,7 @@ describe Notify do subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/tags/v1.0', action: :delete) } it_behaves_like 'it should not have Gmail Actions links' - it_behaves_like "a user can not unsubscribe through footer link" + it_behaves_like "a user cannot unsubscribe through footer link" it 'is sent as the author' do sender = subject.header[:from].addrs[0] @@ -764,7 +764,7 @@ describe Notify do subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare, reverse_compare: false, send_from_committer_email: send_from_committer_email) } it_behaves_like 'it should not have Gmail Actions links' - it_behaves_like "a user can not unsubscribe through footer link" + it_behaves_like "a user cannot unsubscribe through footer link" it 'is sent as the author' do sender = subject.header[:from].addrs[0] @@ -870,7 +870,7 @@ describe Notify do subject { Notify.repository_push_email(project.id, 'devs@company.name', author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare) } it_behaves_like 'it should show Gmail Actions View Commit link' - it_behaves_like "a user can not unsubscribe through footer link" + it_behaves_like "a user cannot unsubscribe through footer link" it 'is sent as the author' do sender = subject.header[:from].addrs[0] -- cgit v1.2.1 From 96bbc145f31ad029e080ad8903445d81d6c31968 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Mon, 11 Jan 2016 10:20:45 +0100 Subject: Change commit builds URL in builds API --- lib/api/builds.rb | 4 ++-- spec/requests/api/builds_spec.rb | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/api/builds.rb b/lib/api/builds.rb index 05d1b8d92ea..8c21754596b 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -28,8 +28,8 @@ module API # scope (optional) - The scope of builds to show (one or array of: pending, running, failed, success, canceled; # if none provided showing all builds) # Example Request: - # GET /projects/:id/builds/commit/:sha - get ':id/builds/commit/:sha' do + # GET /projects/:id/repository/commits/:sha/builds + get ':id/repository/commits/:sha/builds' do commit = user_project.ci_commits.find_by_sha(params[:sha]) return not_found! unless commit diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb index 799558d1bdd..587fb74750d 100644 --- a/spec/requests/api/builds_spec.rb +++ b/spec/requests/api/builds_spec.rb @@ -46,11 +46,11 @@ describe API::API, api: true do end end - describe 'GET /projects/:id/builds/commit/:sha' do + describe 'GET /projects/:id/repository/commits/:sha/builds' do context 'authorized user' do it 'should return project builds for specific commit' do project.ensure_ci_commit(commit.sha) - get api("/projects/#{project.id}/builds/commit/#{commit.sha}", user) + get api("/projects/#{project.id}/repository/commits/#{commit.sha}/builds", user) expect(response.status).to eq(200) expect(json_response).to be_an Array @@ -60,7 +60,7 @@ describe API::API, api: true do context 'unauthorized user' do it 'should not return project builds' do project.ensure_ci_commit(commit.sha) - get api("/projects/#{project.id}/builds/commit/#{commit.sha}") + get api("/projects/#{project.id}/repository/commits/#{commit.sha}/builds") expect(response.status).to eq(401) end -- cgit v1.2.1 From 4e70f2519bba83d5f9d6fd0bed80e9837e8b5fc5 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Mon, 11 Jan 2016 11:15:04 +0100 Subject: Update ./doc/api/builds.md --- doc/api/builds.md | 301 ++++++++++++++++++++++++++++++++++++++++------------ lib/api/entities.rb | 3 +- 2 files changed, 234 insertions(+), 70 deletions(-) diff --git a/doc/api/builds.md b/doc/api/builds.md index c52266714d0..64efe6bb3b1 100644 --- a/doc/api/builds.md +++ b/doc/api/builds.md @@ -17,37 +17,97 @@ Parameters: [ { "commit": { - "committed_at": "2015-12-28T14:34:03.814Z", - "id": 2, - "ref": null, - "sha": "6b053ad388c531c21907f022933e5e81598db388" + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." }, - "created_at": "2016-01-04T15:41:23.147Z", - "finished_at": null, - "id": 65, - "name": "brakeman", + "coverage": null, + "created_at": "2015-12-24T15:51:21.802Z", + "download_url": null, + "finished_at": "2015-12-24T17:54:27.895Z", + "id": 7, + "name": "teaspoon", "ref": "master", "runner": null, "stage": "test", - "started_at": null, - "status": "pending" + "started_at": "2015-12-24T17:54:27.722Z", + "status": "failed", + "tag": false, + "user": { + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "bio": null, + "can_create_group": true, + "can_create_project": true, + "color_scheme_id": 2, + "created_at": "2015-12-21T13:14:24.077Z", + "current_sign_in_at": "2016-01-11T09:31:40.472Z", + "email": "admin@example.com", + "id": 1, + "identities": [], + "is_admin": true, + "linkedin": "", + "name": "Administrator", + "projects_limit": 100, + "skype": "", + "state": "active", + "theme_id": 3, + "twitter": "", + "two_factor_enabled": false, + "username": "root", + "web_url": "http://gitlab.dev/u/root", + "website_url": "" + } }, { "commit": { - "committed_at": "2015-12-28T14:34:03.814Z", - "id": 2, - "ref": null, - "sha": "6b053ad388c531c21907f022933e5e81598db388" + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." }, - "created_at": "2016-01-04T15:41:23.046Z", - "finished_at": null, - "id": 64, - "name": "rubocop", + "coverage": null, + "created_at": "2015-12-24T15:51:21.727Z", + "download_url": null, + "finished_at": "2015-12-24T17:54:24.921Z", + "id": 6, + "name": "spinach:other", "ref": "master", "runner": null, "stage": "test", - "started_at": null, - "status": "pending" + "started_at": "2015-12-24T17:54:24.729Z", + "status": "failed", + "tag": false, + "user": { + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "bio": null, + "can_create_group": true, + "can_create_project": true, + "color_scheme_id": 2, + "created_at": "2015-12-21T13:14:24.077Z", + "current_sign_in_at": "2016-01-11T09:31:40.472Z", + "email": "admin@example.com", + "id": 1, + "identities": [], + "is_admin": true, + "linkedin": "", + "name": "Administrator", + "projects_limit": 100, + "skype": "", + "state": "active", + "theme_id": 3, + "twitter": "", + "two_factor_enabled": false, + "username": "root", + "web_url": "http://gitlab.dev/u/root", + "website_url": "" + } } ] ``` @@ -57,7 +117,7 @@ Parameters: Get a list of builds for specific commit in a project. ``` -GET /projects/:id/builds/commit/:sha +GET /projects/:id/repository/commits/:sha/builds ``` Parameters: @@ -67,45 +127,104 @@ Parameters: - `scope` (optional) - The scope of builds to show (one or array of: pending, running, failed, success, canceled; if none provided showing all builds) ```json -[ - { - "commit": { - "committed_at": "2015-12-28T14:34:03.814Z", - "id": 2, - "ref": null, - "sha": "6b053ad388c531c21907f022933e5e81598db388" + +``` + +## Get a single build +mmit": { + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." }, - "created_at": "2016-01-04T15:41:23.147Z", - "finished_at": null, - "id": 65, + "coverage": null, + "created_at": "2015-12-24T15:51:21.957Z", + "download_url": null, + "finished_at": "2015-12-24T17:54:33.913Z", + "id": 9, "name": "brakeman", "ref": "master", "runner": null, "stage": "test", - "started_at": null, - "status": "pending" + "started_at": "2015-12-24T17:54:33.727Z", + "status": "failed", + "tag": false, + "user": { + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "bio": null, + "can_create_group": true, + "can_create_project": true, + "color_scheme_id": 2, + "created_at": "2015-12-21T13:14:24.077Z", + "current_sign_in_at": "2016-01-11T09:31:40.472Z", + "email": "admin@example.com", + "id": 1, + "identities": [], + "is_admin": true, + "linkedin": "", + "name": "Administrator", + "projects_limit": 100, + "skype": "", + "state": "active", + "theme_id": 3, + "twitter": "", + "two_factor_enabled": false, + "username": "root", + "web_url": "http://gitlab.dev/u/root", + "website_url": "" + } }, { "commit": { - "committed_at": "2015-12-28T14:34:03.814Z", - "id": 2, - "ref": null, - "sha": "6b053ad388c531c21907f022933e5e81598db388" + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." }, - "created_at": "2016-01-04T15:41:23.046Z", - "finished_at": null, - "id": 64, + "coverage": null, + "created_at": "2015-12-24T15:51:21.880Z", + "download_url": null, + "finished_at": "2015-12-24T17:54:31.198Z", + "id": 8, "name": "rubocop", "ref": "master", "runner": null, "stage": "test", - "started_at": null, - "status": "pending" + "started_at": "2015-12-24T17:54:30.733Z", + "status": "failed", + "tag": false, + "user": { + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "bio": null, + "can_create_group": true, + "can_create_project": true, + "color_scheme_id": 2, + "created_at": "2015-12-21T13:14:24.077Z", + "current_sign_in_at": "2016-01-11T09:31:40.472Z", + "email": "admin@example.com", + "id": 1, + "identities": [], + "is_admin": true, + "linkedin": "", + "name": "Administrator", + "projects_limit": 100, + "skype": "", + "state": "active", + "theme_id": 3, + "twitter": "", + "two_factor_enabled": false, + "username": "root", + "web_url": "http://gitlab.dev/u/root", + "website_url": "" + } } ] -``` - -## Get a single build Get a single build of a project @@ -121,20 +240,50 @@ Parameters: ```json { "commit": { - "committed_at": "2015-12-28T14:34:03.814Z", - "id": 2, - "ref": null, - "sha": "6b053ad388c531c21907f022933e5e81598db388" + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." }, - "created_at": "2016-01-04T15:41:23.046Z", - "finished_at": null, - "id": 64, + "coverage": null, + "created_at": "2015-12-24T15:51:21.880Z", + "download_url": null, + "finished_at": "2015-12-24T17:54:31.198Z", + "id": 8, "name": "rubocop", "ref": "master", "runner": null, "stage": "test", - "started_at": null, - "status": "pending" + "started_at": "2015-12-24T17:54:30.733Z", + "status": "failed", + "tag": false, + "user": { + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "bio": null, + "can_create_group": true, + "can_create_project": true, + "color_scheme_id": 2, + "created_at": "2015-12-21T13:14:24.077Z", + "current_sign_in_at": "2016-01-11T09:31:40.472Z", + "email": "admin@example.com", + "id": 1, + "identities": [], + "is_admin": true, + "linkedin": "", + "name": "Administrator", + "projects_limit": 100, + "skype": "", + "state": "active", + "theme_id": 3, + "twitter": "", + "two_factor_enabled": false, + "username": "root", + "web_url": "http://gitlab.dev/u/root", + "website_url": "" + } } ``` @@ -154,20 +303,27 @@ Parameters: ```json { "commit": { - "committed_at": "2015-12-28T14:34:03.814Z", - "id": 2, - "ref": null, - "sha": "6b053ad388c531c21907f022933e5e81598db388" + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." }, - "created_at": "2016-01-05T15:33:25.936Z", - "finished_at": "2016-01-05T15:33:47.553Z", - "id": 66, + "coverage": null, + "created_at": "2016-01-11T10:13:33.506Z", + "download_url": null, + "finished_at": "2016-01-11T10:14:09.526Z", + "id": 69, "name": "rubocop", "ref": "master", "runner": null, "stage": "test", "started_at": null, - "status": "canceled" + "status": "canceled", + "tag": false, + "user": null } ``` @@ -187,19 +343,26 @@ Parameters: ```json { "commit": { - "committed_at": "2015-12-28T14:34:03.814Z", - "id": 2, - "ref": null, - "sha": "6b053ad388c531c21907f022933e5e81598db388" + "author_email": "admin@example.com", + "author_name": "Administrator", + "created_at": "2015-12-24T16:51:14.000+01:00", + "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd", + "message": "Test the CI integration.", + "short_id": "0ff3ae19", + "title": "Test the CI integration." }, - "created_at": "2016-01-05T15:33:25.936Z", + "coverage": null, + "created_at": "2016-01-11T10:13:33.506Z", + "download_url": null, "finished_at": null, - "id": 66, + "id": 69, "name": "rubocop", "ref": "master", "runner": null, "stage": "test", "started_at": null, - "status": "pending" + "status": "pending", + "tag": false, + "user": null } ``` diff --git a/lib/api/entities.rb b/lib/api/entities.rb index cb00b392db9..a1a886d6fea 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -375,8 +375,9 @@ module API end class Build < Grape::Entity - expose :id, :status, :stage, :name, :ref, :tag, :coverage, :user + expose :id, :status, :stage, :name, :ref, :tag, :coverage expose :created_at, :started_at, :finished_at + expose :user, with: UserFull expose :download_url do |repo_obj, options| if options[:user_can_download_artifacts] repo_obj.download_url -- cgit v1.2.1 From 31b66aa75ea1294d64f3da9731cb7a145f6fd127 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 11 Jan 2016 12:34:58 +0100 Subject: Generate builds when creating tag using web interface --- CHANGELOG | 1 + app/services/create_tag_service.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index efb261f6573..c337ba9fb61 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -42,6 +42,7 @@ v 8.3.3 (unreleased) - Enable "Add key" button when user fills in a proper key (Stan Hu) - Fix error in processing reply-by-email messages (Jason Lee) - Fix Error 500 when visiting build page of project with nil runners_token (Stan Hu) + - Fix regression when builds were not generated for tags created through web/api interface v 8.3.2 - Change single user API endpoint to return more detailed data (Michael Potthoff) diff --git a/app/services/create_tag_service.rb b/app/services/create_tag_service.rb index 2452999382a..55985380d31 100644 --- a/app/services/create_tag_service.rb +++ b/app/services/create_tag_service.rb @@ -23,6 +23,7 @@ class CreateTagService < BaseService EventCreateService.new.push(project, current_user, push_data) project.execute_hooks(push_data.dup, :tag_push_hooks) project.execute_services(push_data.dup, :tag_push_hooks) + CreateCommitBuildsService.new.execute(project, current_user, push_data) if release_description CreateReleaseService.new(@project, @current_user). -- cgit v1.2.1 From 13c3562217bef7d17e7c1bcc0c98c847a5e82189 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 11 Jan 2016 13:05:32 +0100 Subject: Use gitlab-workhorse 0.5.3 --- GITLAB_WORKHORSE_VERSION | 2 +- doc/install/installation.md | 2 +- doc/update/8.2-to-8.3.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index 4b9fcbec101..be14282b7ff 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -0.5.1 +0.5.3 diff --git a/doc/install/installation.md b/doc/install/installation.md index dd59733cf4d..8c4e092c636 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -348,7 +348,7 @@ GitLab Shell is an SSH access and repository management software developed speci cd /home/git sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git cd gitlab-workhorse - sudo -u git -H git checkout 0.5.1 + sudo -u git -H git checkout 0.5.3 sudo -u git -H make ### Initialize Database and Activate Advanced Features diff --git a/doc/update/8.2-to-8.3.md b/doc/update/8.2-to-8.3.md index 3748941b781..a3950df5fef 100644 --- a/doc/update/8.2-to-8.3.md +++ b/doc/update/8.2-to-8.3.md @@ -78,7 +78,7 @@ which should already be on your system from GitLab 8.1. ```bash cd /home/git/gitlab-workhorse sudo -u git -H git fetch --all -sudo -u git -H git checkout 0.5.1 +sudo -u git -H git checkout 0.5.3 sudo -u git -H make ``` -- cgit v1.2.1 From cdd3a806825db480b9cc9dfd36f3cf58c84e0f61 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 11 Jan 2016 13:34:12 +0100 Subject: Allow subsequent validations in CI Linter Closes #5851 --- CHANGELOG | 1 + app/controllers/ci/lints_controller.rb | 6 ++++-- app/views/ci/lints/show.html.haml | 6 +++--- spec/features/ci_lint_spec.rb | 8 ++++++++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9ff4820c12c..c2e44936a0e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -33,6 +33,7 @@ v 8.4.0 (unreleased) - Add file finder feature in tree view (Kyungchul Shin) - Ajax filter by message for commits page - API: Add support for deleting a tag via the API (Robert Schilling) + - Allow subsequent validations in CI Linter v 8.3.3 (unreleased) - Preserve CE behavior with JIRA integration by only calling API if URL is set diff --git a/app/controllers/ci/lints_controller.rb b/app/controllers/ci/lints_controller.rb index e782a51e7eb..a7af3cb8345 100644 --- a/app/controllers/ci/lints_controller.rb +++ b/app/controllers/ci/lints_controller.rb @@ -6,11 +6,13 @@ module Ci end def create - if params[:content].blank? + @content = params[:content] + + if @content.blank? @status = false @error = "Please provide content of .gitlab-ci.yml" else - @config_processor = Ci::GitlabCiYamlProcessor.new params[:content] + @config_processor = Ci::GitlabCiYamlProcessor.new(@content) @stages = @config_processor.stages @builds = @config_processor.builds @status = true diff --git a/app/views/ci/lints/show.html.haml b/app/views/ci/lints/show.html.haml index a144c43be47..0044d779c31 100644 --- a/app/views/ci/lints/show.html.haml +++ b/app/views/ci/lints/show.html.haml @@ -4,12 +4,12 @@ .row = form_tag ci_lint_path, method: :post do .form-group - = label_tag :content, 'Content of .gitlab-ci.yml', class: 'control-label text-nowrap' + = label_tag(:content, 'Content of .gitlab-ci.yml', class: 'control-label text-nowrap') .col-sm-12 - = text_area_tag :content, nil, class: 'form-control span1', rows: 7, require: true + = text_area_tag(:content, @content, class: 'form-control span1', rows: 7, require: true) .col-sm-12 .pull-left.prepend-top-10 - = submit_tag 'Validate', class: 'btn btn-success submit-yml' + = submit_tag('Validate', class: 'btn btn-success submit-yml') .row.prepend-top-20 .col-sm-12 diff --git a/spec/features/ci_lint_spec.rb b/spec/features/ci_lint_spec.rb index e6e73e5e67c..30e29d9d552 100644 --- a/spec/features/ci_lint_spec.rb +++ b/spec/features/ci_lint_spec.rb @@ -35,5 +35,13 @@ describe 'CI Lint' do expect(page).to have_content('Error: Please provide content of .gitlab-ci.yml') end end + + describe 'YAML revalidate' do + let(:yaml_content) { 'my yaml content' } + + it 'loads previous YAML content after validation' do + expect(page).to have_field('content', with: 'my yaml content', type: 'textarea') + end + end end end -- cgit v1.2.1 From be08490863b76026b8f3ffbc422cb7f5d8b4a6a4 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Mon, 11 Jan 2016 14:23:45 +0100 Subject: #can_unsubscribe? -> #?unsubscribable? --- app/controllers/sent_notifications_controller.rb | 2 +- app/models/sent_notification.rb | 2 +- app/views/layouts/notify.html.haml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/sent_notifications_controller.rb b/app/controllers/sent_notifications_controller.rb index b7008c82bf2..7271c933b9b 100644 --- a/app/controllers/sent_notifications_controller.rb +++ b/app/controllers/sent_notifications_controller.rb @@ -3,7 +3,7 @@ class SentNotificationsController < ApplicationController def unsubscribe @sent_notification = SentNotification.for(params[:id]) - return render_404 unless @sent_notification && @sent_notification.can_unsubscribe? + return render_404 unless @sent_notification && @sent_notification.unsubscribable? noteable = @sent_notification.noteable noteable.unsubscribe(@sent_notification.recipient) diff --git a/app/models/sent_notification.rb b/app/models/sent_notification.rb index 03108da17be..77115597d71 100644 --- a/app/models/sent_notification.rb +++ b/app/models/sent_notification.rb @@ -62,7 +62,7 @@ class SentNotification < ActiveRecord::Base end end - def can_unsubscribe? + def unsubscribable? !for_commit? end diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml index 07f9be12f99..325c68c69dc 100644 --- a/app/views/layouts/notify.html.haml +++ b/app/views/layouts/notify.html.haml @@ -45,7 +45,7 @@ -# Don't link the host is the line below, one link in the email is easier to quickly click than two. You're receiving this email because of your account on #{Gitlab.config.gitlab.host}. If you'd like to receive fewer emails, you can - - if @sent_notification && @sent_notification.can_unsubscribe? + - if @sent_notification && @sent_notification.unsubscribable? = link_to "unsubscribe", unsubscribe_sent_notification_url(@sent_notification) from this thread or adjust your notification settings. -- cgit v1.2.1 From 67aa0b8c4cbf762211ad178efb537f1649d91776 Mon Sep 17 00:00:00 2001 From: Drew Blessing Date: Thu, 31 Dec 2015 13:22:51 -0600 Subject: Optimize LDAP and add a search timeout --- CHANGELOG | 1 + config/gitlab.yml.example | 5 +++++ config/initializers/1_settings.rb | 1 + doc/integration/ldap.md | 5 +++++ lib/gitlab/ldap/access.rb | 8 ++++++-- lib/gitlab/ldap/adapter.rb | 24 +++++++++++++++--------- lib/gitlab/ldap/config.rb | 4 ++++ 7 files changed, 37 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9ff4820c12c..ea05231937e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -37,6 +37,7 @@ v 8.4.0 (unreleased) v 8.3.3 (unreleased) - Preserve CE behavior with JIRA integration by only calling API if URL is set - Fix duplicated branch creation/deletion events when using Web UI (Stan Hu) + - Add configurable LDAP server query timeout - Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running - Suppress e-mails on failed builds if allow_failure is set (Stan Hu) - Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 2d9f730c183..d6e2c9380a5 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -204,6 +204,11 @@ production: &base bind_dn: '_the_full_dn_of_the_user_you_will_bind_with' password: '_the_password_of_the_bind_user' + # Set a timeout, in seconds, for LDAP queries. This helps avoid blocking + # a request if the LDAP server becomes unresponsive. + # A value of 0 means there is no timeout. + timeout: 10 + # This setting specifies if LDAP server is Active Directory LDAP server. # For non AD servers it skips the AD specific queries. # If your LDAP server is not AD, set this to false. diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 4fbd84ee890..a9c5b2caf0a 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -108,6 +108,7 @@ if Settings.ldap['enabled'] || Rails.env.test? Settings.ldap['servers'].each do |key, server| server['label'] ||= 'LDAP' + server['timeout'] ||= 10.seconds server['block_auto_created_users'] = false if server['block_auto_created_users'].nil? server['allow_username_or_email_login'] = false if server['allow_username_or_email_login'].nil? server['active_directory'] = true if server['active_directory'].nil? diff --git a/doc/integration/ldap.md b/doc/integration/ldap.md index 845f588f913..f256477196b 100644 --- a/doc/integration/ldap.md +++ b/doc/integration/ldap.md @@ -48,6 +48,11 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server bind_dn: '_the_full_dn_of_the_user_you_will_bind_with' password: '_the_password_of_the_bind_user' + # Set a timeout, in seconds, for LDAP queries. This helps avoid blocking + # a request if the LDAP server becomes unresponsive. + # A value of 0 means there is no timeout. + timeout: 10 + # This setting specifies if LDAP server is Active Directory LDAP server. # For non AD servers it skips the AD specific queries. # If your LDAP server is not AD, set this to false. diff --git a/lib/gitlab/ldap/access.rb b/lib/gitlab/ldap/access.rb index c438a3d167b..b2bdbc10d7f 100644 --- a/lib/gitlab/ldap/access.rb +++ b/lib/gitlab/ldap/access.rb @@ -5,7 +5,7 @@ module Gitlab module LDAP class Access - attr_reader :adapter, :provider, :user + attr_reader :provider, :user def self.open(user, &block) Gitlab::LDAP::Adapter.open(user.ldap_identity.provider) do |adapter| @@ -32,7 +32,7 @@ module Gitlab end def allowed? - if Gitlab::LDAP::Person.find_by_dn(user.ldap_identity.extern_uid, adapter) + if ldap_user return true unless ldap_config.active_directory # Block user in GitLab if he/she was blocked in AD @@ -59,6 +59,10 @@ module Gitlab def ldap_config Gitlab::LDAP::Config.new(provider) end + + def ldap_user + @ldap_user ||= Gitlab::LDAP::Person.find_by_dn(user.ldap_identity.extern_uid, adapter) + end end end end diff --git a/lib/gitlab/ldap/adapter.rb b/lib/gitlab/ldap/adapter.rb index 577a890a7d9..df65179bfea 100644 --- a/lib/gitlab/ldap/adapter.rb +++ b/lib/gitlab/ldap/adapter.rb @@ -70,19 +70,25 @@ module Gitlab end def ldap_search(*args) - results = ldap.search(*args) + # Net::LDAP's `time` argument doesn't work. Use Ruby `Timeout` instead. + Timeout.timeout(config.timeout) do + results = ldap.search(*args) - if results.nil? - response = ldap.get_operation_result + if results.nil? + response = ldap.get_operation_result - unless response.code.zero? - Rails.logger.warn("LDAP search error: #{response.message}") - end + unless response.code.zero? + Rails.logger.warn("LDAP search error: #{response.message}") + end - [] - else - results + [] + else + results + end end + rescue Timeout::Error + Rails.logger.warn("LDAP search timed out after #{config.timeout} seconds") + [] end end end diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb index 101a3285f4b..aff7ccb157f 100644 --- a/lib/gitlab/ldap/config.rb +++ b/lib/gitlab/ldap/config.rb @@ -88,6 +88,10 @@ module Gitlab options['attributes'] end + def timeout + options['timeout'].to_i + end + protected def base_config Gitlab.config.ldap -- cgit v1.2.1 From fc4108b38b5d0a7fc755c1977663f516b5dea0bd Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Mon, 11 Jan 2016 15:27:20 +0100 Subject: Modify CI features in projects API --- doc/api/projects.md | 21 +-------------------- lib/api/entities.rb | 4 +--- lib/api/helpers.rb | 2 +- lib/api/projects.rb | 41 ++++++++++++++--------------------------- 4 files changed, 17 insertions(+), 51 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 96a3f08490c..4632554bf86 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -79,11 +79,7 @@ Parameters: "avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png", "shared_runners_enabled": true, "forks_count": 0, - "star_count": 0, - "build_allow_git_fetch": true, - "build_coverage_regex": null, - "build_timeout": 3600, - "runners_token": "4f9e77be0eed5ef29548fccda3b371" + "star_count": 0 }, { "id": 6, @@ -140,9 +136,6 @@ Parameters: "shared_runners_enabled": true, "forks_count": 0, "star_count": 0, - "build_allow_git_fetch": true, - "build_coverage_regex": null, - "build_timeout": 3600, "runners_token": "b8547b1dc37721d05889db52fa2f02" } ] @@ -262,9 +255,6 @@ Parameters: "shared_runners_enabled": true, "forks_count": 0, "star_count": 0, - "build_allow_git_fetch": true, - "build_coverage_regex": null, - "build_timeout": 3600, "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b" } ``` @@ -430,9 +420,6 @@ Parameters: - `public` (optional) - if `true` same as setting visibility_level = 20 - `visibility_level` (optional) - `import_url` (optional) -- `build_allow_git_fetch` (optional) -- `build_timeout` (optional) -- `build_coverage_regex` (optional) ### Create project for user @@ -455,9 +442,6 @@ Parameters: - `public` (optional) - if `true` same as setting visibility_level = 20 - `visibility_level` (optional) - `import_url` (optional) -- `build_allow_git_fetch` (optional) -- `build_timeout` (optional) -- `build_coverage_regex` (optional) ### Edit project @@ -481,9 +465,6 @@ Parameters: - `snippets_enabled` (optional) - `public` (optional) - if `true` same as setting visibility_level = 20 - `visibility_level` (optional) -- `build_allow_git_fetch` (optional) -- `build_timeout` (optional) -- `build_coverage_regex` (optional) On success, method returns 200 with the updated project. If parameters are invalid, 400 is returned. diff --git a/lib/api/entities.rb b/lib/api/entities.rb index e8154e0f383..e3bc3316ce5 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -71,9 +71,7 @@ module API expose :avatar_url expose :star_count, :forks_count expose :open_issues_count, if: lambda { |project, options| project.issues_enabled? && project.default_issues_tracker? } - - expose :build_allow_git_fetch, :build_timeout, :build_coverage_regex - expose :runners_token + expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] } end class ProjectMember < UserBasic diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 563c12e4f74..a4df810e755 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -157,7 +157,7 @@ module API def attributes_for_keys(keys, custom_params = nil) attrs = {} keys.each do |key| - if params[key].present? or (params.has_key?(key) and (params[key].empty? or params[key] == false)) + if params[key].present? or (params.has_key?(key) and params[key] == false) attrs[key] = params[key] end end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 31b081266a8..28c3583f351 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -69,7 +69,8 @@ module API # Example Request: # GET /projects/:id get ":id" do - present user_project, with: Entities::ProjectWithAccess, user: current_user + present user_project, with: Entities::ProjectWithAccess, user: current_user, + user_can_admin_project: can?(current_user, :admin_project, user_project) end # Get events for a single project @@ -98,9 +99,6 @@ module API # public (optional) - if true same as setting visibility_level = 20 # visibility_level (optional) - 0 by default # import_url (optional) - # build_allow_git_fetch (optional) - # build_timeout (optional) - # build_coverage_regex (optional) # Example Request # POST /projects post do @@ -117,14 +115,12 @@ module API :namespace_id, :public, :visibility_level, - :import_url, - :build_allow_git_fetch, - :build_timeout, - :build_coverage_regex] + :import_url] attrs = map_public_to_visibility_level(attrs) @project = ::Projects::CreateService.new(current_user, attrs).execute if @project.saved? - present @project, with: Entities::Project + present @project, with: Entities::Project, + user_can_admin_project: can?(current_user, :admin_project, @project) else if @project.errors[:limit_reached].present? error!(@project.errors[:limit_reached], 403) @@ -149,9 +145,6 @@ module API # public (optional) - if true same as setting visibility_level = 20 # visibility_level (optional) # import_url (optional) - # build_allow_git_fetch (optional) - # build_timeout (optional) - # build_coverage_regex (optional) # Example Request # POST /projects/user/:user_id post "user/:user_id" do @@ -168,14 +161,12 @@ module API :shared_runners_enabled, :public, :visibility_level, - :import_url, - :build_allow_git_fetch, - :build_timeout, - :build_coverage_regex] + :import_url] attrs = map_public_to_visibility_level(attrs) @project = ::Projects::CreateService.new(user, attrs).execute if @project.saved? - present @project, with: Entities::Project + present @project, with: Entities::Project, + user_can_admin_project: can?(current_user, :admin_project, @project) else render_validation_error!(@project) end @@ -194,8 +185,9 @@ module API if @forked_project.errors.any? conflict!(@forked_project.errors.messages) else - present @forked_project, with: Entities::Project - end + present @forked_project, with: Entities::Project, + user_can_admin_project: can?(current_user, :admin_project, @forked_project) + end end # Update an existing project @@ -213,9 +205,6 @@ module API # shared_runners_enabled (optional) # public (optional) - if true same as setting visibility_level = 20 # visibility_level (optional) - visibility level of a project - # build_allow_git_fetch (optional) - # build_timeout (optional) - # build_coverage_regex (optional) # Example Request # PUT /projects/:id put ':id' do @@ -230,10 +219,7 @@ module API :snippets_enabled, :shared_runners_enabled, :public, - :visibility_level, - :build_allow_git_fetch, - :build_timeout, - :build_coverage_regex] + :visibility_level] attrs = map_public_to_visibility_level(attrs) authorize_admin_project authorize! :rename_project, user_project if attrs[:name].present? @@ -247,7 +233,8 @@ module API if user_project.errors.any? render_validation_error!(user_project) else - present user_project, with: Entities::Project + present user_project, with: Entities::Project, + user_can_admin_project: can?(current_user, :admin_project, user_project) end end -- cgit v1.2.1 From 5dcfd7d06754fecb245475cc005c112677693801 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Mon, 11 Jan 2016 15:49:25 +0100 Subject: Add TODO notice to build trace feature in CI API --- lib/api/builds.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/api/builds.rb b/lib/api/builds.rb index 8c21754596b..d3f4e33ebbf 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -61,6 +61,10 @@ module API # build_id (required) - The ID of a build # Example Request: # GET /projects/:id/build/:build_id/trace + # + # TODO: We should use `present_file!` and leave this implementation for backward compatibility (when build trace + # is saved in the DB instead of file). But before that, we need to consider how to replace the value of + # `runners_token` with some mask (like `xxxxxx`) when sending trace file directly by workhorse. get ':id/builds/:build_id/trace' do build = get_build(params[:build_id]) return not_found!(build) unless build -- cgit v1.2.1 From 97022c414ed61ede8e3270ec23d1b91392b2b689 Mon Sep 17 00:00:00 2001 From: Drew Blessing Date: Fri, 8 Jan 2016 14:40:25 -0600 Subject: Improve admin area button style --- app/views/admin/labels/index.html.haml | 2 +- app/views/admin/projects/show.html.haml | 2 +- app/views/admin/users/_head.html.haml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/admin/labels/index.html.haml b/app/views/admin/labels/index.html.haml index d67454c03e7..3c57e3dc174 100644 --- a/app/views/admin/labels/index.html.haml +++ b/app/views/admin/labels/index.html.haml @@ -1,5 +1,5 @@ - page_title "Labels" -= link_to new_admin_label_path, class: "pull-right btn btn-new" do += link_to new_admin_label_path, class: "pull-right btn btn-nr btn-new" do New label %h3.page-title Labels diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 0c986af4a95..d734e60682a 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -1,7 +1,7 @@ - page_title @project.name_with_namespace, "Projects" %h3.page-title Project: #{@project.name_with_namespace} - = link_to edit_project_path(@project), class: "btn pull-right" do + = link_to edit_project_path(@project), class: "btn btn-nr pull-right" do %i.fa.fa-pencil-square-o Edit %hr diff --git a/app/views/admin/users/_head.html.haml b/app/views/admin/users/_head.html.haml index 5e17b018163..bc44b1b1d8e 100644 --- a/app/views/admin/users/_head.html.haml +++ b/app/views/admin/users/_head.html.haml @@ -7,8 +7,8 @@ .pull-right - unless @user == current_user || @user.blocked? - = link_to 'Impersonate', impersonate_admin_user_path(@user), method: :post, class: "btn btn-grouped btn-info" - = link_to edit_admin_user_path(@user), class: "btn btn-grouped" do + = link_to 'Impersonate', impersonate_admin_user_path(@user), method: :post, class: "btn btn-nr btn-grouped btn-info" + = link_to edit_admin_user_path(@user), class: "btn btn-nr btn-grouped" do %i.fa.fa-pencil-square-o Edit %hr -- cgit v1.2.1 From 35b501f30ae9e121151ad6a2140d036e5ef3b0f5 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 11 Jan 2016 16:51:01 +0100 Subject: Tag all transaction metrics with an "action" tag Without this it's impossible to find out what methods/views/queries are executed by a certain controller or Sidekiq worker. While this will increase the total number of series it should stay within reasonable limits due to the amount of "actions" being small enough. --- lib/gitlab/metrics/rack_middleware.rb | 6 ++---- lib/gitlab/metrics/sidekiq_middleware.rb | 7 +------ lib/gitlab/metrics/transaction.rb | 17 +++++++++++++++-- spec/lib/gitlab/metrics/rack_middleware_spec.rb | 2 +- spec/lib/gitlab/metrics/sidekiq_middleware_spec.rb | 17 +++++------------ spec/lib/gitlab/metrics/transaction_spec.rb | 17 +++++++++++++++++ 6 files changed, 41 insertions(+), 25 deletions(-) diff --git a/lib/gitlab/metrics/rack_middleware.rb b/lib/gitlab/metrics/rack_middleware.rb index e7a2f26d48b..6f179789d3e 100644 --- a/lib/gitlab/metrics/rack_middleware.rb +++ b/lib/gitlab/metrics/rack_middleware.rb @@ -39,10 +39,8 @@ module Gitlab end def tag_controller(trans, env) - controller = env[CONTROLLER_KEY] - label = "#{controller.class.name}##{controller.action_name}" - - trans.add_tag(:action, label) + controller = env[CONTROLLER_KEY] + trans.action = "#{controller.class.name}##{controller.action_name}" end end end diff --git a/lib/gitlab/metrics/sidekiq_middleware.rb b/lib/gitlab/metrics/sidekiq_middleware.rb index ad441decfa2..fd98aa3412e 100644 --- a/lib/gitlab/metrics/sidekiq_middleware.rb +++ b/lib/gitlab/metrics/sidekiq_middleware.rb @@ -5,19 +5,14 @@ module Gitlab # This middleware is intended to be used as a server-side middleware. class SidekiqMiddleware def call(worker, message, queue) - trans = Transaction.new + trans = Transaction.new("#{worker.class.name}#perform") begin trans.run { yield } ensure - tag_worker(trans, worker) trans.finish end end - - def tag_worker(trans, worker) - trans.add_tag(:action, "#{worker.class.name}#perform") - end end end end diff --git a/lib/gitlab/metrics/transaction.rb b/lib/gitlab/metrics/transaction.rb index 73131cc6ef2..86606b1c6d6 100644 --- a/lib/gitlab/metrics/transaction.rb +++ b/lib/gitlab/metrics/transaction.rb @@ -6,11 +6,15 @@ module Gitlab attr_reader :tags, :values + attr_accessor :action + def self.current Thread.current[THREAD_KEY] end - def initialize + # action - A String describing the action performed, usually the class + # plus method name. + def initialize(action = nil) @metrics = [] @started_at = nil @@ -18,6 +22,7 @@ module Gitlab @values = Hash.new(0) @tags = {} + @action = action end def duration @@ -70,7 +75,15 @@ module Gitlab end def submit - Metrics.submit_metrics(@metrics.map(&:to_hash)) + metrics = @metrics.map do |metric| + hash = metric.to_hash + + hash[:tags][:action] ||= @action if @action + + hash + end + + Metrics.submit_metrics(metrics) end def sidekiq? diff --git a/spec/lib/gitlab/metrics/rack_middleware_spec.rb b/spec/lib/gitlab/metrics/rack_middleware_spec.rb index 4e6dfc73df2..b99be4e1060 100644 --- a/spec/lib/gitlab/metrics/rack_middleware_spec.rb +++ b/spec/lib/gitlab/metrics/rack_middleware_spec.rb @@ -57,7 +57,7 @@ describe Gitlab::Metrics::RackMiddleware do middleware.tag_controller(transaction, env) - expect(transaction.tags[:action]).to eq('TestController#show') + expect(transaction.action).to eq('TestController#show') end end end diff --git a/spec/lib/gitlab/metrics/sidekiq_middleware_spec.rb b/spec/lib/gitlab/metrics/sidekiq_middleware_spec.rb index 5882e7d81c7..e520a968999 100644 --- a/spec/lib/gitlab/metrics/sidekiq_middleware_spec.rb +++ b/spec/lib/gitlab/metrics/sidekiq_middleware_spec.rb @@ -5,22 +5,15 @@ describe Gitlab::Metrics::SidekiqMiddleware do describe '#call' do it 'tracks the transaction' do - worker = Class.new.new + worker = double(:worker, class: double(:class, name: 'TestWorker')) + + expect(Gitlab::Metrics::Transaction).to receive(:new). + with('TestWorker#perform'). + and_call_original expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:finish) middleware.call(worker, 'test', :test) { nil } end end - - describe '#tag_worker' do - it 'adds the worker class and action to the transaction' do - trans = Gitlab::Metrics::Transaction.new - worker = double(:worker, class: double(:class, name: 'TestWorker')) - - expect(trans).to receive(:add_tag).with(:action, 'TestWorker#perform') - - middleware.tag_worker(trans, worker) - end - end end diff --git a/spec/lib/gitlab/metrics/transaction_spec.rb b/spec/lib/gitlab/metrics/transaction_spec.rb index 3a27f897735..6bdeb719491 100644 --- a/spec/lib/gitlab/metrics/transaction_spec.rb +++ b/spec/lib/gitlab/metrics/transaction_spec.rb @@ -96,5 +96,22 @@ describe Gitlab::Metrics::Transaction do transaction.submit end + + it 'adds the action as a tag for every metric' do + transaction.action = 'Foo#bar' + transaction.track_self + + hash = { + series: 'rails_transactions', + tags: { action: 'Foo#bar' }, + values: { duration: 0.0 }, + timestamp: an_instance_of(Fixnum) + } + + expect(Gitlab::Metrics).to receive(:submit_metrics). + with([hash]) + + transaction.submit + end end end -- cgit v1.2.1 From 5ba0232f7905a0c2a55ff80cbb97ddf2404fa22c Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Mon, 11 Jan 2016 16:30:01 +0100 Subject: Fix :ci_build_with_trace factory --- spec/factories/ci/builds.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index ce68457f86b..558598d4d5c 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -58,7 +58,9 @@ FactoryGirl.define do factory :ci_build_with_trace do id 999 - trace 'BUILD TRACE' + after(:build) do |build, evaluator| + build.trace = 'BUILD TRACE' + end end factory :ci_build_canceled do -- cgit v1.2.1 From 75180eae1c0dc98a6668f70e5cc4923d8e651e09 Mon Sep 17 00:00:00 2001 From: Josh Frye Date: Mon, 11 Jan 2016 09:06:39 -0500 Subject: Change milestone close notice copy. Closes #6051 --- app/views/dashboard/milestones/show.html.haml | 2 +- app/views/groups/milestones/show.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/dashboard/milestones/show.html.haml b/app/views/dashboard/milestones/show.html.haml index 4316c358dcb..49a558e8ac9 100644 --- a/app/views/dashboard/milestones/show.html.haml +++ b/app/views/dashboard/milestones/show.html.haml @@ -16,7 +16,7 @@ - if @milestone.complete? && @milestone.active? .alert.alert-success.prepend-top-default - %span All issues for this milestone are closed. You may close the milestone now. + %span All issues for this milestone are closed. Navigate to the project to close the milestone. .table-holder %table.table diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml index d063b257b5e..044a9a7aafb 100644 --- a/app/views/groups/milestones/show.html.haml +++ b/app/views/groups/milestones/show.html.haml @@ -22,7 +22,7 @@ - if @milestone.complete? && @milestone.active? .alert.alert-success.prepend-top-default - %span All issues for this milestone are closed. You may close the milestone now. + %span All issues for this milestone are closed. Navigate to the project to close the milestone. .table-holder %table.table -- cgit v1.2.1 From e34c621ea1c26549f8b06e0e74f24538c0dac8ba Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 11 Jan 2016 08:41:11 -0800 Subject: Bump fog to 1.36.0 Closes #4231 --- CHANGELOG | 1 + Gemfile | 2 +- Gemfile.lock | 80 +++++++++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 65 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 9ff4820c12c..1cae1cc40ff 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.4.0 (unreleased) + - Bump fog to 1.36.0 (Stan Hu) - Add housekeeping function to project settings page - The default GitLab logo now acts as a loading indicator - Fix caching issue where build status was not updating in project dashboard (Stan Hu) diff --git a/Gemfile b/Gemfile index e9361f73e6e..9a5253924ea 100644 --- a/Gemfile +++ b/Gemfile @@ -80,7 +80,7 @@ gem "carrierwave", '~> 0.9.0' gem 'dropzonejs-rails', '~> 0.7.1' # for aws storage -gem "fog", "~> 1.25.0" +gem "fog", "~> 1.36.0" gem "unf", '~> 0.1.4' # Authorization diff --git a/Gemfile.lock b/Gemfile.lock index db0104eee84..f1bba7f437e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -219,21 +219,45 @@ GEM flowdock (0.7.1) httparty (~> 0.7) multi_json - fog (1.25.0) + fog (1.36.0) + fog-aliyun (>= 0.1.0) + fog-atmos + fog-aws (>= 0.6.0) fog-brightbox (~> 0.4) - fog-core (~> 1.25) + fog-core (~> 1.32) + fog-dynect (~> 0.0.2) + fog-ecloud (~> 0.1) + fog-google (<= 0.1.0) fog-json + fog-local + fog-powerdns (>= 0.1.1) fog-profitbricks fog-radosgw (>= 0.0.2) + fog-riakcs fog-sakuracloud (>= 0.0.4) + fog-serverlove fog-softlayer + fog-storm_on_demand fog-terremark fog-vmfusion fog-voxel + fog-xenserver fog-xml (~> 0.1.1) ipaddress (~> 0.5) nokogiri (~> 1.5, >= 1.5.11) - opennebula + fog-aliyun (0.1.0) + fog-core (~> 1.27) + fog-json (~> 1.0) + ipaddress (~> 0.8) + xml-simple (~> 1.1) + fog-atmos (0.1.0) + fog-core + fog-xml + fog-aws (0.8.1) + fog-core (~> 1.27) + fog-json (~> 1.0) + fog-xml (~> 0.1) + ipaddress (~> 0.8) fog-brightbox (0.10.1) fog-core (~> 1.22) fog-json @@ -242,21 +266,48 @@ GEM builder excon (~> 0.45) formatador (~> 0.2) + fog-dynect (0.0.2) + fog-core + fog-json + fog-xml + fog-ecloud (0.3.0) + fog-core + fog-xml + fog-google (0.1.0) + fog-core + fog-json + fog-xml fog-json (1.0.2) fog-core (~> 1.0) multi_json (~> 1.10) + fog-local (0.2.1) + fog-core (~> 1.27) + fog-powerdns (0.1.1) + fog-core (~> 1.27) + fog-json (~> 1.0) + fog-xml (~> 0.1) fog-profitbricks (0.0.5) fog-core fog-xml nokogiri - fog-radosgw (0.0.4) + fog-radosgw (0.0.5) fog-core (>= 1.21.0) fog-json fog-xml (>= 0.0.1) - fog-sakuracloud (1.5.0) + fog-riakcs (0.1.0) + fog-core + fog-json + fog-xml + fog-sakuracloud (1.7.5) + fog-core + fog-json + fog-serverlove (0.1.2) + fog-core + fog-json + fog-softlayer (1.0.3) fog-core fog-json - fog-softlayer (1.0.2) + fog-storm_on_demand (0.1.1) fog-core fog-json fog-terremark (0.1.0) @@ -268,6 +319,9 @@ GEM fog-voxel (0.1.0) fog-core fog-xml + fog-xenserver (0.2.2) + fog-core + fog-xml fog-xml (0.1.2) fog-core nokogiri (~> 1.5, >= 1.5.11) @@ -377,7 +431,7 @@ GEM influxdb (0.2.3) cause json - ipaddress (0.8.0) + ipaddress (0.8.2) jquery-atwho-rails (1.3.2) jquery-rails (4.0.5) rails-dom-testing (~> 1.0) @@ -492,10 +546,6 @@ GEM activesupport nokogiri (>= 1.4.4) omniauth (~> 1.0) - opennebula (4.14.2) - json - nokogiri - rbvmomi org-ruby (0.9.12) rubypants (~> 0.2) orm_adapter (0.5.0) @@ -571,10 +621,6 @@ GEM ffi (>= 0.5.0) rblineprof (0.3.6) debugger-ruby_core_source (~> 1.3) - rbvmomi (1.8.2) - builder - nokogiri (>= 1.4.1) - trollop rdoc (3.12.2) json (~> 1.4) recaptcha (1.0.2) @@ -773,7 +819,6 @@ GEM multi_json (~> 1.7) twitter-stream (~> 0.1) tins (1.6.0) - trollop (2.1.2) turbolinks (2.5.3) coffee-rails twitter-stream (0.1.16) @@ -822,6 +867,7 @@ GEM builder expression_parser rinku + xml-simple (1.1.5) xpath (2.0.0) nokogiri (~> 1.3) @@ -877,7 +923,7 @@ DEPENDENCIES ffaker (~> 2.0.0) flay flog - fog (~> 1.25.0) + fog (~> 1.36.0) font-awesome-rails (~> 4.2) foreman fuubar (~> 2.0.0) -- cgit v1.2.1 From 0f113828faf12cfe2de89326e1619d4eb5cd8828 Mon Sep 17 00:00:00 2001 From: John Galt Date: Mon, 11 Jan 2016 10:02:39 -0700 Subject: [ci skip] Fixed minor typo in docker documentation --- doc/ci/docker/using_docker_images.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md index 31458d61674..63fe840b369 100644 --- a/doc/ci/docker/using_docker_images.md +++ b/doc/ci/docker/using_docker_images.md @@ -174,7 +174,7 @@ The alias hostname for the service is made from the image name following these rules: 1. Everything after `:` is stripped -2. Backslash (`/`) is replaced with double underscores (`__`) +2. Slash (`/`) is replaced with double underscores (`__`) ## Configuring services -- cgit v1.2.1 From b3431a8ce85c7f6f7c1f862338a6135fca550a94 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Mon, 11 Jan 2016 12:50:01 -0500 Subject: adds hover titles to merge request and issue pages --- app/views/shared/issuable/_filter.html.haml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml index be06738eac9..0e3e9275fc1 100644 --- a/app/views/shared/issuable/_filter.html.haml +++ b/app/views/shared/issuable/_filter.html.haml @@ -1,25 +1,29 @@ .issues-filters .issues-state-filters %ul.center-top-menu + - if defined?(type) && type == :merge_requests + - page_context_word = 'merge requests' + - else + - page_context_word = 'issues' %li{class: ("active" if params[:state] == 'opened')} - = link_to page_filter_path(state: 'opened') do + = link_to page_filter_path(state: 'opened'), title: "Filter by #{page_context_word} that are currently opened." do #{state_filters_text_for(:opened, @project)} - if defined?(type) && type == :merge_requests %li{class: ("active" if params[:state] == 'merged')} - = link_to page_filter_path(state: 'merged') do + = link_to page_filter_path(state: 'merged'), title: 'Filter by merge requests that are currently merged.' do #{state_filters_text_for(:merged, @project)} %li{class: ("active" if params[:state] == 'closed')} - = link_to page_filter_path(state: 'closed') do + = link_to page_filter_path(state: 'closed'), title: 'Filter by merge requests that are currently closed and unmerged.' do #{state_filters_text_for(:closed, @project)} - else %li{class: ("active" if params[:state] == 'closed')} - = link_to page_filter_path(state: 'closed') do + = link_to page_filter_path(state: 'closed'), title: 'Filter by issues that are currently closed.' do #{state_filters_text_for(:closed, @project)} %li{class: ("active" if params[:state] == 'all')} - = link_to page_filter_path(state: 'all') do + = link_to page_filter_path(state: 'all'), title: "Show all #{page_context_word}." do #{state_filters_text_for(:all, @project)} .issues-details-filters.gray-content-block -- cgit v1.2.1 From f2fab27a562dbb0e1522e388b5719d226ce66e4b Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 11 Jan 2016 15:18:07 -0500 Subject: Update CHANGELOG [ci skip] --- CHANGELOG | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d2668490a46..0f89093d223 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -26,6 +26,9 @@ v 8.4.0 (unreleased) - Show 'All' tab by default in the builds page - Add Open Graph and Twitter Card data to all pages - Fix API project lookups when querying with a namespace with dots (Stan Hu) + - Enable forcing Two-Factor authentication sitewide, with optional grace period + - Import GitHub Pull Requests into GitLab + - Change single user API endpoint to return more detailed data (Michael Potthoff) - Update version check images to use SVG - Validate README format before displaying - Enable Microsoft Azure OAuth2 support (Janis Meybohm) @@ -35,22 +38,21 @@ v 8.4.0 (unreleased) - API: Add support for deleting a tag via the API (Robert Schilling) - Allow subsequent validations in CI Linter -v 8.3.3 (unreleased) +v 8.3.3 - Preserve CE behavior with JIRA integration by only calling API if URL is set - Fix duplicated branch creation/deletion events when using Web UI (Stan Hu) - Add configurable LDAP server query timeout - Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running - Suppress e-mails on failed builds if allow_failure is set (Stan Hu) - Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu) + - Better support for referencing and closing issues in Asana service (Mike Wyatt) - Enable "Add key" button when user fills in a proper key (Stan Hu) - Fix error in processing reply-by-email messages (Jason Lee) - Fix Error 500 when visiting build page of project with nil runners_token (Stan Hu) + - Use WOFF versions of SourceSansPro fonts - Fix regression when builds were not generated for tags created through web/api interface v 8.3.2 - - Change single user API endpoint to return more detailed data (Michael Potthoff) - -v 8.3.2 (unreleased) - Disable --follow in `git log` to avoid loading duplicate commit data in infinite scroll (Stan Hu) - Add support for Google reCAPTCHA in user registration @@ -59,8 +61,6 @@ v 8.3.1 - Fix Error 500 when doing a search in dashboard before visiting any project (Stan Hu) - Fix LDAP identity and user retrieval when special characters are used - Move Sidekiq-cron configuration to gitlab.yml - - Enable forcing Two-Factor authentication sitewide, with optional grace period - - Import GitHub Pull Requests into GitLab v 8.3.0 - Bump rack-attack to 4.3.1 for security fix (Stan Hu) -- cgit v1.2.1 From 9bea7efb73eeb195820072782e9aefdac6fb86ac Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Mon, 11 Jan 2016 16:04:31 -0500 Subject: changes bolded on active for dropdowns, sitewide. --- app/assets/stylesheets/pages/projects.scss | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index d32509b7d49..f24b71963a8 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -295,10 +295,9 @@ border: 1px solid #c6cacf !important; background-color: #e4e7ed !important; - text-transform: uppercase; + text-transform: none; color: #313236 !important; - font-size: 13px; - font-weight: 600; + font-size: 15px; } .dropdown-menu { -- cgit v1.2.1 From 21a46236e07af5c0e16d700a4b87d565e1b46671 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 11 Jan 2016 18:15:38 -0500 Subject: Add title attribute to Emojis in award picker --- app/helpers/issues_helper.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index a7080ddfefb..43262d579e9 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -103,9 +103,12 @@ module IssuesHelper content_tag :div, "", class: "icon emoji-icon emoji-#{unicode}", - "data-emoji" => name, - "data-aliases" => aliases.join(" "), - "data-unicode-name" => unicode + title: name, + data: { + aliases: aliases.join(' '), + emoji: name, + unicode_name: unicode + } end def emoji_author_list(notes, current_user) -- cgit v1.2.1 From d4ffe705ebebba49ebaf0652b4430bb459e83eb4 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 11 Jan 2016 18:37:20 -0500 Subject: Call clearInterval for the currentTimer if one exists Prevents a double-click from causing the logo to sweep forever after a load completes. --- app/assets/javascripts/logo.js.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/logo.js.coffee b/app/assets/javascripts/logo.js.coffee index e864a674cdd..a5879c8b793 100644 --- a/app/assets/javascripts/logo.js.coffee +++ b/app/assets/javascripts/logo.js.coffee @@ -21,6 +21,7 @@ start = -> clearHighlights() pieceIndex = 0 pieces.reverse() unless pieces[0] == firstPiece + clearInterval(currentTimer) if currentTimer currentTimer = setInterval(work, delay) stop = -> -- cgit v1.2.1 From ae7de2f8510d6d4b69120f168122e26d69dda256 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 11 Jan 2016 21:48:20 -0500 Subject: Remove the `:coffee` and `:coffeescript` Haml filters See https://git.io/vztMu and http://stackoverflow.com/a/17571242/223897 --- config/initializers/haml.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/initializers/haml.rb b/config/initializers/haml.rb index 7e8ddb3716b..1516476815a 100644 --- a/config/initializers/haml.rb +++ b/config/initializers/haml.rb @@ -1 +1,7 @@ Haml::Template.options[:ugly] = true + +# Remove the `:coffee` and `:coffeescript` filters +# +# See https://git.io/vztMu and http://stackoverflow.com/a/17571242/223897 +Haml::Filters.remove_filter('coffee') +Haml::Filters.remove_filter('coffeescript') -- cgit v1.2.1 From 75123458eecbc34d01844538b9ffc04c71f550d6 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 12 Jan 2016 00:57:05 -0800 Subject: Add user's last used IP addresses to admin page This would help admins figure out from where spam is originating. --- CHANGELOG | 1 + app/views/admin/users/show.html.haml | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index ab34661ce05..51ea9896219 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.4.0 (unreleased) - Bump fog to 1.36.0 (Stan Hu) + - Add user's last used IP addresses to admin page (Stan Hu) - Add housekeeping function to project settings page - The default GitLab logo now acts as a loading indicator - Fix caching issue where build status was not updating in project dashboard (Stan Hu) diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index 2c2450d4117..2bdbae19588 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -70,6 +70,14 @@ %strong.cred No + %li + %span.light Current sign-in IP: + %strong + - if @user.current_sign_in_ip + = @user.current_sign_in_ip + - else + never + %li %span.light Current sign-in at: %strong @@ -78,6 +86,14 @@ - else never + %li + %span.light Last sign-in IP: + %strong + - if @user.last_sign_in_ip + = @user.last_sign_in_ip + - else + never + %li %span.light Last sign-in at: %strong -- cgit v1.2.1 From 41bcab118ae8be1baee0d750d99f46f584bd2fd4 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Tue, 12 Jan 2016 17:05:43 +0800 Subject: Fix #9963 reference_filter "Encoding::CompatibilityError" bug with some complex URL; --- lib/banzai/filter/reference_filter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/banzai/filter/reference_filter.rb b/lib/banzai/filter/reference_filter.rb index 7198a8b03e2..5dd6d2fe3c7 100644 --- a/lib/banzai/filter/reference_filter.rb +++ b/lib/banzai/filter/reference_filter.rb @@ -133,7 +133,7 @@ module Banzai next unless link && text - link = URI.decode(link) + link = CGI.unescape(link) # Ignore ending punctionation like periods or commas next unless link == text && text =~ /\A#{pattern}/ @@ -170,7 +170,7 @@ module Banzai text = node.text next unless link && text - link = URI.decode(link) + link = CGI.unescape(link) next unless link && link =~ /\A#{pattern}\z/ html = yield link, text -- cgit v1.2.1 From 932a247f5fb4a14b3e096ec88a73f8fce481eebb Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Tue, 12 Jan 2016 17:32:25 +0800 Subject: Use CGI.escape instead of URI.escape, because URI is obsoleted. ref: https://github.com/ruby/ruby/commit/238b979f1789f95262a267d8df6239806f2859cc --- app/models/hooks/web_hook.rb | 4 ++-- app/models/project_services/hipchat_service.rb | 8 ++++---- config/initializers/1_settings.rb | 2 +- lib/gitlab/gitlab_import/importer.rb | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb index d0aadfc330a..3bb50c63cac 100644 --- a/app/models/hooks/web_hook.rb +++ b/app/models/hooks/web_hook.rb @@ -48,8 +48,8 @@ class WebHook < ActiveRecord::Base else post_url = url.gsub("#{parsed_url.userinfo}@", "") auth = { - username: URI.decode(parsed_url.user), - password: URI.decode(parsed_url.password), + username: CGI.unescape(parsed_url.user), + password: CGI.unescape(parsed_url.password), } response = WebHook.post(post_url, body: data.to_json, diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 32a81808930..0e3fa4a40fe 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -120,13 +120,13 @@ class HipchatService < Service message << "#{push[:user_name]} " if Gitlab::Git.blank_ref?(before) message << "pushed new #{ref_type} #{ref}"\ + "#{project_url}/commits/#{CGI.escape(ref)}\">#{ref}"\ " to #{project_link}\n" elsif Gitlab::Git.blank_ref?(after) message << "removed #{ref_type} #{ref} from #{project_name} \n" else message << "pushed to #{ref_type} #{ref} " + "#{project.web_url}/commits/#{CGI.escape(ref)}\">#{ref} " message << "of #{project.name_with_namespace.gsub!(/\s/,'')} " message << "(Compare changes)" @@ -255,8 +255,8 @@ class HipchatService < Service status = data[:commit][:status] duration = data[:commit][:duration] - branch_link = "#{ref}" - commit_link = "#{Commit.truncate_sha(sha)}" + branch_link = "#{ref}" + commit_link = "#{Commit.truncate_sha(sha)}" "#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status(status)} in #{duration} second(s)" end diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index a9c5b2caf0a..d625a909bf1 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -11,7 +11,7 @@ class Settings < Settingslogic # get host without www, thanks to http://stackoverflow.com/a/6674363/1233435 def get_host_without_www(url) - url = URI.encode(url) + url = CGI.escape(url) uri = URI.parse(url) uri = URI.parse("http://#{url}") if uri.scheme.nil? host = uri.host.downcase diff --git a/lib/gitlab/gitlab_import/importer.rb b/lib/gitlab/gitlab_import/importer.rb index e24b94d6159..59926084d07 100644 --- a/lib/gitlab/gitlab_import/importer.rb +++ b/lib/gitlab/gitlab_import/importer.rb @@ -12,7 +12,7 @@ module Gitlab end def execute - project_identifier = URI.encode(project.import_source, '/') + project_identifier = CGI.escape(project.import_source, '/') #Issues && Comments issues = client.issues(project_identifier) -- cgit v1.2.1 From 9f8510b329e123c70c912b87bd6186d2b78302ca Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 12 Jan 2016 11:36:40 +0100 Subject: Updated CHANGELOG with changes I made I forgot to add these in the respective MRs. [ci skip] --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index ab34661ce05..175399fe1fa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,9 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.4.0 (unreleased) + - Autocomplete data is now always loaded, instead of when focusing a comment text area (Yorick Peterse) + - Improved performance of finding issues for an entire group (Yorick Peterse) + - Added custom application performance measuring system powered by InfluxDB (Yorick Peterse) - Bump fog to 1.36.0 (Stan Hu) - Add housekeeping function to project settings page - The default GitLab logo now acts as a loading indicator -- cgit v1.2.1 From 470b3a482a06c733665abcf2d92ad4d898b2efe0 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Tue, 12 Jan 2016 11:50:14 +0100 Subject: Fix doc/api/builds.md --- doc/api/builds.md | 60 ++++++++++++++++++------------------------------------- 1 file changed, 19 insertions(+), 41 deletions(-) diff --git a/doc/api/builds.md b/doc/api/builds.md index 64efe6bb3b1..99ef0882c16 100644 --- a/doc/api/builds.md +++ b/doc/api/builds.md @@ -127,11 +127,9 @@ Parameters: - `scope` (optional) - The scope of builds to show (one or array of: pending, running, failed, success, canceled; if none provided showing all builds) ```json - -``` - -## Get a single build -mmit": { +[ + { + "commit": { "author_email": "admin@example.com", "author_name": "Administrator", "created_at": "2015-12-24T16:51:14.000+01:00", @@ -141,41 +139,18 @@ mmit": { "title": "Test the CI integration." }, "coverage": null, - "created_at": "2015-12-24T15:51:21.957Z", + "created_at": "2016-01-11T10:13:33.506Z", "download_url": null, - "finished_at": "2015-12-24T17:54:33.913Z", - "id": 9, - "name": "brakeman", + "finished_at": "2016-01-11T10:14:09.526Z", + "id": 69, + "name": "rubocop", "ref": "master", "runner": null, "stage": "test", - "started_at": "2015-12-24T17:54:33.727Z", - "status": "failed", + "started_at": null, + "status": "canceled", "tag": false, - "user": { - "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", - "bio": null, - "can_create_group": true, - "can_create_project": true, - "color_scheme_id": 2, - "created_at": "2015-12-21T13:14:24.077Z", - "current_sign_in_at": "2016-01-11T09:31:40.472Z", - "email": "admin@example.com", - "id": 1, - "identities": [], - "is_admin": true, - "linkedin": "", - "name": "Administrator", - "projects_limit": 100, - "skype": "", - "state": "active", - "theme_id": 3, - "twitter": "", - "two_factor_enabled": false, - "username": "root", - "web_url": "http://gitlab.dev/u/root", - "website_url": "" - } + "user": null }, { "commit": { @@ -188,15 +163,15 @@ mmit": { "title": "Test the CI integration." }, "coverage": null, - "created_at": "2015-12-24T15:51:21.880Z", + "created_at": "2015-12-24T15:51:21.957Z", "download_url": null, - "finished_at": "2015-12-24T17:54:31.198Z", - "id": 8, - "name": "rubocop", + "finished_at": "2015-12-24T17:54:33.913Z", + "id": 9, + "name": "brakeman", "ref": "master", "runner": null, "stage": "test", - "started_at": "2015-12-24T17:54:30.733Z", + "started_at": "2015-12-24T17:54:33.727Z", "status": "failed", "tag": false, "user": { @@ -206,7 +181,7 @@ mmit": { "can_create_project": true, "color_scheme_id": 2, "created_at": "2015-12-21T13:14:24.077Z", - "current_sign_in_at": "2016-01-11T09:31:40.472Z", + "current_sign_in_at": "2016-01-12T10:30:48.315Z", "email": "admin@example.com", "id": 1, "identities": [], @@ -225,6 +200,9 @@ mmit": { } } ] +``` + +## Get a single build Get a single build of a project -- cgit v1.2.1 From d0b2d278f4fc7c929bd19ce9f29eb689783f58ed Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 12 Jan 2016 11:47:08 +0100 Subject: Move doc_styleguide in the development directory [ci skip] --- doc/README.md | 2 + doc/development/doc_styleguide.md | 224 ++++++++++++++++++++++++++++++++++++++ doc_styleguide.md | 25 +---- 3 files changed, 227 insertions(+), 24 deletions(-) create mode 100644 doc/development/doc_styleguide.md diff --git a/doc/README.md b/doc/README.md index 25fe3abcb9a..7d4f84857e0 100644 --- a/doc/README.md +++ b/doc/README.md @@ -70,6 +70,8 @@ ## Contributor documentation +- [Documentation styleguide](development/doc_styleguide.md) Use this styleguide if you are + contributing to documentation. - [Development](development/README.md) Explains the architecture and the guidelines for shell commands. - [Legal](legal/README.md) Contributor license agreements. - [Release](release/README.md) How to make the monthly and security releases. diff --git a/doc/development/doc_styleguide.md b/doc/development/doc_styleguide.md new file mode 100644 index 00000000000..df2507a34d0 --- /dev/null +++ b/doc/development/doc_styleguide.md @@ -0,0 +1,224 @@ +# Documentation styleguide + +This styleguide recommends best practices to improve documentation and to keep +it organized and easy to find. + +## Naming + +- Use underscores for all names, including new documentation and images + +## Text + +- Split up long lines, this makes it much easier to review and edit. Only + double line breaks are shown as a full line break in GitLab markdown. + 80-100 characters is a good line length +- Make sure that the documentation is added in the correct directory and that + there's a link to it somewhere useful +- Do not duplicate information +- Be brief and clear +- Whenever it applies, add documents in alphabetical order +- Write in US English +- Use [single spaces][] instead of double spaces + +## Formatting + +- Use dashes (`-`) for unordered lists instead of asterisks (`*`) +- Use the number one (`1`) for ordered lists +- Use underscores (`_`) to mark a word or text in italics +- Use double asterisks (`**`) to mark a word or text in bold +- When using lists, prefer not to end each item with a period. You can use + them if there are multiple sentences, just keep the last sentence without + a period + +## Headings + +- Add only one H1 title in each document, by adding `#` at the beginning of + it (when using markdown). For subheadings, use `##`, `###` and so on +- For subtitles, make sure to start with the largest and go down, meaning: + `#` for the title, `##` for subtitles and `###` for subtitles of the subtitles, etc. +- Avoid putting numbers in Markdown headings. Numbers shift hence documentation + anchor links shift too which eventually leads to dead links. +- When introducing a new doc, be careful for the headings to be grammatically + and syntactically correct. It is advised to mention one or all of the + following GitLab members for a review: `@axil`, `@rspeicher`, `@dblessing`, + `@ashleys`, `@nearlythere`. This is to ensure that no document with + wrong heading is going live without an audit, thus preventing dead links and + redirection issues when corrected. +- Leave exactly one newline after a heading + +## Links + +- If the link sets the paragraph spanning across multiple lines, do not use + the regular Markdown approach: `[Text](https://example.com)`. Instead use + `[Text][identifier]` and at the very bottom of the document add: + `[identifier]: https://example.com`. This is another way to make Markdown + links which keeps the document clear and concise. Extra points if you also + add an alternative text: `[identifier]: https://example.com "Alternative text"` + that appears when hovering your mouse on a link. + +## Images + +- Place images in a separate directory named `img/` in the same directory where + the `.md` document that you're working on is located. Always prepend their + names with the name of the document that they will be included in. For + example, if there is a document called `twitter.md`, then a valid image name + could be `twitter_login_screen.png`. +- Images should have a specific, non-generic name that will differentiate them. +- Keep all file names in lower case. +- Consider using PNG images instead of JPEG. + +Inside the document: + +- The Markdown way of using an image inside a document is: + `![Proper description what the image is about](img/document_image_title.png)` +- Always use a proper description what the image is about. That way, when a + browser fails to show the image, this text will be used as an alternative + description +- If there are consecutive images with little text between them, always add + three dashes (`---`) between the image and the text to create a horizontal + line for better clarity +- If a heading is placed right after an image, always add three dashes (`---`) + between the image and the heading + +## Notes + +- Notes should be in italics with the word `Note:` being bold. Use this form: + `_**Note:** This is something to note._`. If the note spans across multiple + lines it's OK to split the line. + +## New features + +- Every piece of documentation that comes with a new feature should declare the + GitLab version that feature got introduced. Right below the heading add a + note: `_**Note:** This feature was introduced in GitLab CE 8.3_` +- If possible every feature should have a link to the MR that introduced it. + The above note would be transformed to: + `_**Note:** This feature was [introduced][ce-1242] in GitLab CE 8.3_`, where + the link is named after the repository (CE) and the MR number, and the + [link identifier](#links) is used. + +## API + +Here is a list of must have items. Use them in this exact order that appears +on this document. Further explanation is given below. + +- Every method must have the REST API request. For example: + + ``` + GET /projects/:id/repository/branches + ``` + +- Every method must have a detailed + [description of the parameters](#method-description). +- Every method must have a cURL example. +- Every method must have a response body (in JSON format). + +### Method description + +Use the following table headers to describe the methods. Attributes should +always be in code blocks using backticks (`). + +``` +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +``` + +Rendered example: + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `user` | string | yes | The GitLab username | + +### cURL commands + +- Use `https://gitlab.example.com/api/v3/` as an endpoint. +- Wherever needed use this private token: `9koXpg98eAheJpvBs5tK`. +- Always put the request first. `GET` is the default so you don't have to + include it. +- Use double quotes to the URL when it includes additional parameters. +- Prefer to use examples using the private token and don't pass data of + username and password. + +| Methods | Description | +| ------- | ----------- | +| `-H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"` | Use this method as is, whenever authentication needed | +| `-X POST` | Use this method when creating new objects | +| `-X PUT` | Use this method when updating existing objects | +| `-X DELETE` | Use this method when removing existing objects | + +### cURL Examples + +Below is a set of [cURL][] examples that you can use in the API documentation. + +#### Simple cURL command + +Get the details of a group: + +```bash +curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/groups/gitlab-org +``` + +#### cURL example with parameters passed in the URL + +Create a new project under the authenticated user's namespace: + +```bash +curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects?name=foo" +``` + +#### Post data using cURL's --data + +Instead of using `-X POST` and appending the parameters to the URI, you can use +cURL's `--data` option. The example below will create a new project `foo` under +the authenticated user's namespace. + +```bash +curl --data "name=foo" -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects" +``` + +#### Post data using JSON content + +_**Note:** In this example we create a new group. Watch carefully the single +and double quotes._ + +```bash +curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" -H "Content-Type: application/json" --data '{"path": "my-group", "name": "My group"}' https://gitlab.example.com/api/v3/groups +``` + +#### Post data using form-data + +Instead of using JSON or urlencode you can use multipart/form-data which +properly handles data encoding: + +```bash +curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" -F "title=ssh-key" -F "key=ssh-rsa AAAAB3NzaC1yc2EA..." https://gitlab.example.com/api/v3/users/25/keys +``` + +The above example is run by and administrator and will add an SSH public key +titled ssh-key to user's account which has an id of 25. + +#### Escape special characters + +Spaces or slashes (`/`) may sometimes result to errors, thus it is recommended +to escape them when possible. In the example below we create a new issue which +contains spaces in its title. Watch how spaces are escaped using the `%20` +ASCII code. + +```bash +curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/42/issues?title=Hello%20Dude" +``` + +Use `%2F` for slashes (`/`). + +#### Pass arrays to API calls + +The GitLab API sometimes accepts arrays of strings or integers. For example, to +restrict the sign-up e-mail domains of a GitLab instance to `*.example.com` and +`example.net`, you would do something like this: + +```bash +curl -X PUT -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" -d "restricted_signup_domains[]=*.example.com" -d "restricted_signup_domains[]=example.net" https://gitlab.example.com/api/v3/application/settings +``` + +[cURL]: http://curl.haxx.se/ "cURL website" +[single spaces]: http://www.slate.com/articles/technology/technology/2011/01/space_invaders.html diff --git a/doc_styleguide.md b/doc_styleguide.md index cceb449a854..05ff46323ac 100644 --- a/doc_styleguide.md +++ b/doc_styleguide.md @@ -1,26 +1,3 @@ # Documentation styleguide -This styleguide recommends best practices to improve documentation and to keep it organized and easy to find. - -## Text - -- Split up long lines, this makes it much easier to review and edit. Only -double line breaks are shown as a full line break in markdown. 80 characters -is a good line length. -- For subtitles, make sure to start with the largest and go down, meaning: -`#` for the title, `##` for subtitles and `###` for subtitles of the subtitles, etc. -- Make sure that the documentation is added in the correct directory and that there's a link to it somewhere useful. -- Add only one H1 or title in each document, by adding '#' at the begining of it (when using markdown). -For subtitles, use '##', '###' and so on. -- Do not duplicate information. -- Be brief and clear. -- Whenever it applies, add documents in alphabetical order. -- Write in US English -- Use [single spaces](http://www.slate.com/articles/technology/technology/2011/01/space_invaders.html) instead of double spaces. - -## Images - -- Create a directory to store the images with the specific name of the document where the images belong. -It could be in the same directory where the .md document that you're working on is located. -- Images should have a specific, non-generic name that will differentiate them. -- Keep all file names in lower case. \ No newline at end of file +Moved to [development/doc_styleguide](doc/development/doc_styleguide.md). -- cgit v1.2.1 From 5a757a63899fba66e08bf65870a288d7be207b09 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 12 Jan 2016 12:32:11 +0100 Subject: Add new location of doc_styleguide in CONTRIBUTING.md [ci skip] --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b9c2b3d2f8e..1eabbdc5cad 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -334,9 +334,9 @@ merge request: 1. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style/coffeescript) 1. [Shell commands](doc/development/shell_commands.md) created by GitLab contributors to enhance security -1. [Markdown](http://www.cirosantilli.com/markdown-styleguide) 1. [Database Migrations](doc/development/migration_style_guide.md) -1. [Documentation styleguide](doc_styleguide.md) +1. [Markdown](http://www.cirosantilli.com/markdown-styleguide) +1. [Documentation styleguide](doc/development/doc_styleguide.md) 1. Interface text should be written subjectively instead of objectively. It should be the GitLab core team addressing a person. It should be written in present time and never use past tense (has been/was). For example instead -- cgit v1.2.1 From 0c598004d72d197748bec0ec70e5a7fae4958713 Mon Sep 17 00:00:00 2001 From: Josh Frye Date: Tue, 12 Jan 2016 08:28:44 -0500 Subject: Revert group milestone copy --- app/views/groups/milestones/show.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml index 044a9a7aafb..d063b257b5e 100644 --- a/app/views/groups/milestones/show.html.haml +++ b/app/views/groups/milestones/show.html.haml @@ -22,7 +22,7 @@ - if @milestone.complete? && @milestone.active? .alert.alert-success.prepend-top-default - %span All issues for this milestone are closed. Navigate to the project to close the milestone. + %span All issues for this milestone are closed. You may close the milestone now. .table-holder %table.table -- cgit v1.2.1 From eb3e7bdfd87f97e28f9a0d4cf0ac8b913e0055bf Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Tue, 12 Jan 2016 08:40:02 -0500 Subject: merge request close message moved and merge request now refered by `!`. --- app/assets/stylesheets/framework/variables.scss | 1 + app/assets/stylesheets/pages/issues.scss | 5 +++++ app/views/projects/issues/_closed_by_box.html.haml | 4 ++-- app/views/projects/issues/_merge_requests.html.haml | 4 +++- app/views/projects/issues/show.html.haml | 3 --- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index af75123b0af..4c307d705e9 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -24,6 +24,7 @@ $gl-gray: #5a5a5a; $gl-padding: 16px; $gl-padding-top:10px; $gl-avatar-size: 46px; +$quote-gray: #7f8fa4; /* * Color schema diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index a02a3a72e79..30dfc0b3904 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -144,3 +144,8 @@ form.edit-issue { .issue-form .select2-container { width: 250px !important; } + +.issue-closed-by-widget { + color: $quote-gray; + margin-left: 52px; +} \ No newline at end of file diff --git a/app/views/projects/issues/_closed_by_box.html.haml b/app/views/projects/issues/_closed_by_box.html.haml index de415ae51a4..c434ad41f89 100644 --- a/app/views/projects/issues/_closed_by_box.html.haml +++ b/app/views/projects/issues/_closed_by_box.html.haml @@ -1,2 +1,2 @@ -.issue-closed-by-widget.gray-content-block.second-block.white - This issue will be closed automatically when merge request #{markdown(merge_requests_sentence(@closed_by_merge_requests), pipeline: :gfm)} is accepted. +.issue-closed-by-widget.second-block + When this merge request is accepted, this issue will be closed automatically. diff --git a/app/views/projects/issues/_merge_requests.html.haml b/app/views/projects/issues/_merge_requests.html.haml index 254968e4f67..e3b41bca815 100644 --- a/app/views/projects/issues/_merge_requests.html.haml +++ b/app/views/projects/issues/_merge_requests.html.haml @@ -11,7 +11,7 @@ - elsif has_any_ci = icon('blank fw') %span.merge-request-id - \##{merge_request.iid} + \!#{merge_request.iid} %span.merge-request-info %strong = link_to_gfm merge_request.title, merge_request_path(merge_request), class: "row_title" @@ -24,3 +24,5 @@ MERGED - elsif merge_request.closed? CLOSED + - if @closed_by_merge_requests.present? + = render 'projects/issues/closed_by_box' diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml index f931a0d3b92..7ed898ce72f 100644 --- a/app/views/projects/issues/show.html.haml +++ b/app/views/projects/issues/show.html.haml @@ -53,9 +53,6 @@ .gray-content-block.second-block.oneline-block = render 'votes/votes_block', votable: @issue - - if @closed_by_merge_requests.present? - = render 'projects/issues/closed_by_box' - .row %section.col-md-9 .issuable-discussion -- cgit v1.2.1 From fac252c9a2230b58b0de7b16fb7318fc048f32a0 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 12 Jan 2016 14:47:55 +0100 Subject: Never heard of gitlab-omnibus --- doc/integration/shibboleth.md | 4 ++-- doc/release/patch.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/integration/shibboleth.md b/doc/integration/shibboleth.md index 6258e5f1030..a0be3dd4e5c 100644 --- a/doc/integration/shibboleth.md +++ b/doc/integration/shibboleth.md @@ -1,8 +1,8 @@ # Shibboleth OmniAuth Provider -This documentation is for enabling shibboleth with gitlab-omnibus package. +This documentation is for enabling shibboleth with omnibus-gitlab package. -In order to enable Shibboleth support in gitlab we need to use Apache instead of Nginx (It may be possible to use Nginx, however I did not found way to easily configure Nginx that is bundled in gitlab-omnibus package). Apache uses mod_shib2 module for shibboleth authentication and can pass attributes as headers to omniauth-shibboleth provider. +In order to enable Shibboleth support in gitlab we need to use Apache instead of Nginx (It may be possible to use Nginx, however I did not found way to easily configure Nginx that is bundled in omnibus-gitlab package). Apache uses mod_shib2 module for shibboleth authentication and can pass attributes as headers to omniauth-shibboleth provider. To enable the Shibboleth OmniAuth provider you must: diff --git a/doc/release/patch.md b/doc/release/patch.md index 3022e375aca..1c921439156 100644 --- a/doc/release/patch.md +++ b/doc/release/patch.md @@ -24,7 +24,7 @@ Use the following template: - Picked into respective `stable` branches: - [ ] Merge `x-y-stable` into `x-y-stable-ee` - [ ] release-tools: `x.y.z` -- gitlab-omnibus +- omnibus-gitlab - [ ] `x.y.z+ee.0` - [ ] `x.y.z+ce.0` - [ ] Deploy -- cgit v1.2.1 From 5679ee0120ab45829b847d55d3a2253735856b3f Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 12 Jan 2016 14:59:30 +0100 Subject: Track memory allocated during a transaction This gives a very rough estimate of how much memory is allocated during a transaction. This only works reliably when using a single-threaded application server and a Ruby implementation with a GIL as otherwise memory allocated by other threads might skew the statistics. Sadly there's no way around this as Ruby doesn't provide a reliable way of gathering accurate object sizes upon allocation on a per-thread basis. --- lib/gitlab/metrics/transaction.rb | 15 ++++++++++++--- spec/lib/gitlab/metrics/transaction_spec.rb | 29 +++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/lib/gitlab/metrics/transaction.rb b/lib/gitlab/metrics/transaction.rb index 86606b1c6d6..2578ddc49f4 100644 --- a/lib/gitlab/metrics/transaction.rb +++ b/lib/gitlab/metrics/transaction.rb @@ -23,20 +23,29 @@ module Gitlab @values = Hash.new(0) @tags = {} @action = action + + @memory_before = 0 + @memory_after = 0 end def duration @finished_at ? (@finished_at - @started_at) * 1000.0 : 0.0 end + def allocated_memory + @memory_after - @memory_before + end + def run Thread.current[THREAD_KEY] = self - @started_at = Time.now + @memory_before = System.memory_usage + @started_at = Time.now yield ensure - @finished_at = Time.now + @memory_after = System.memory_usage + @finished_at = Time.now Thread.current[THREAD_KEY] = nil end @@ -65,7 +74,7 @@ module Gitlab end def track_self - values = { duration: duration } + values = { duration: duration, allocated_memory: allocated_memory } @values.each do |name, value| values[name] = value diff --git a/spec/lib/gitlab/metrics/transaction_spec.rb b/spec/lib/gitlab/metrics/transaction_spec.rb index 6bdeb719491..1d5a51a157e 100644 --- a/spec/lib/gitlab/metrics/transaction_spec.rb +++ b/spec/lib/gitlab/metrics/transaction_spec.rb @@ -11,6 +11,14 @@ describe Gitlab::Metrics::Transaction do end end + describe '#allocated_memory' do + it 'returns the allocated memory in bytes' do + transaction.run { 'a' * 32 } + + expect(transaction.allocated_memory).to be_a_kind_of(Numeric) + end + end + describe '#run' do it 'yields the supplied block' do expect { |b| transaction.run(&b) }.to yield_control @@ -43,8 +51,10 @@ describe Gitlab::Metrics::Transaction do transaction.increment(:time, 1) transaction.increment(:time, 2) + values = { duration: 0.0, time: 3, allocated_memory: a_kind_of(Numeric) } + expect(transaction).to receive(:add_metric). - with('transactions', { duration: 0.0, time: 3 }, {}) + with('transactions', values, {}) transaction.track_self end @@ -54,8 +64,14 @@ describe Gitlab::Metrics::Transaction do it 'sets a value' do transaction.set(:number, 10) + values = { + duration: 0.0, + number: 10, + allocated_memory: a_kind_of(Numeric) + } + expect(transaction).to receive(:add_metric). - with('transactions', { duration: 0.0, number: 10 }, {}) + with('transactions', values, {}) transaction.track_self end @@ -80,8 +96,13 @@ describe Gitlab::Metrics::Transaction do describe '#track_self' do it 'adds a metric for the transaction itself' do + values = { + duration: transaction.duration, + allocated_memory: a_kind_of(Numeric) + } + expect(transaction).to receive(:add_metric). - with('transactions', { duration: transaction.duration }, {}) + with('transactions', values, {}) transaction.track_self end @@ -104,7 +125,7 @@ describe Gitlab::Metrics::Transaction do hash = { series: 'rails_transactions', tags: { action: 'Foo#bar' }, - values: { duration: 0.0 }, + values: { duration: 0.0, allocated_memory: a_kind_of(Numeric) }, timestamp: an_instance_of(Fixnum) } -- cgit v1.2.1 From 81cd903de9e009c3f57e3ff2671cc0fdd5d39646 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 12 Jan 2016 15:15:54 +0100 Subject: Refactor GitHub importer documentation [ci skip] --- .../importing/github_importer/importer.png | Bin 39335 -> 0 bytes .../importing/github_importer/new_project_page.png | Bin 46276 -> 0 bytes .../img/import_projects_from_github_importer.png | Bin 0 -> 28033 bytes ...mport_projects_from_github_new_project_page.png | Bin 0 -> 17225 bytes .../importing/import_projects_from_github.md | 46 ++++++++++++++++----- 5 files changed, 36 insertions(+), 10 deletions(-) delete mode 100644 doc/workflow/importing/github_importer/importer.png delete mode 100644 doc/workflow/importing/github_importer/new_project_page.png create mode 100644 doc/workflow/importing/img/import_projects_from_github_importer.png create mode 100644 doc/workflow/importing/img/import_projects_from_github_new_project_page.png diff --git a/doc/workflow/importing/github_importer/importer.png b/doc/workflow/importing/github_importer/importer.png deleted file mode 100644 index 57636717571..00000000000 Binary files a/doc/workflow/importing/github_importer/importer.png and /dev/null differ diff --git a/doc/workflow/importing/github_importer/new_project_page.png b/doc/workflow/importing/github_importer/new_project_page.png deleted file mode 100644 index 002f22d81d7..00000000000 Binary files a/doc/workflow/importing/github_importer/new_project_page.png and /dev/null differ diff --git a/doc/workflow/importing/img/import_projects_from_github_importer.png b/doc/workflow/importing/img/import_projects_from_github_importer.png new file mode 100644 index 00000000000..f744dc06f81 Binary files /dev/null and b/doc/workflow/importing/img/import_projects_from_github_importer.png differ diff --git a/doc/workflow/importing/img/import_projects_from_github_new_project_page.png b/doc/workflow/importing/img/import_projects_from_github_new_project_page.png new file mode 100644 index 00000000000..86be35acb37 Binary files /dev/null and b/doc/workflow/importing/img/import_projects_from_github_new_project_page.png differ diff --git a/doc/workflow/importing/import_projects_from_github.md b/doc/workflow/importing/import_projects_from_github.md index 2027a055c37..77fb7ea7cd6 100644 --- a/doc/workflow/importing/import_projects_from_github.md +++ b/doc/workflow/importing/import_projects_from_github.md @@ -1,20 +1,46 @@ # Import your project from GitHub to GitLab -It takes just a couple of steps to import your existing GitHub projects to GitLab. Keep in mind that it is possible only if -GitHub support is enabled on your GitLab instance. You can read more about GitHub support [here](http://doc.gitlab.com/ce/integration/github.html) +_**Note:** In order to enable the GitHub import setting, you should first +enable the [GitHub integration][gh-import] in your GitLab instance._ -If you want to import from a GitHub Enterprise instance, you need to use GitLab Enterprise; please see the [EE docs for the GitHub integration](http://doc.gitlab.com/ee/integration/github.html). +At its current state, GitHub importer can import: -* Sign in to GitLab.com and go to your dashboard. -* To get to the importer page, you need to go to the "New project" page. +- the repository description +- the git repository data +- the issues +- the pull requests +- the wiki pages -![New project page](github_importer/new_project_page.png) +The importer page is visible when you [create a new project][new-project]. +Click on the **GitHub** link and you will be redirected to GitHub for +permission to access your projects. After accepting, you'll be automatically +redirected to the importer. -* Click on the "Import project from GitHub" link and you will be redirected to GitHub for permission to access your projects. After accepting, you'll be automatically redirected to the importer. +![New project page on GitLab](img/import_projects_from_github_new_project_page.png) -![Importer page](github_importer/importer.png) +--- -* To import a project, you can simple click "Add". The importer will import your repository, issues, and pull requests. Once the importer is done, a new GitLab project will be created with your imported data. +While at the GitHub importer page, you can see the import statuses of your +GitHub projects. Those that are being imported will show a _started_ status, +those already imported will be green, whereas those that are not yet imported +have an **Import** button on the right side of the table. If you want, you can +import all your GitHub projects in one go by hitting **Import all projects** +in the upper left corner. + +![GitHub importer page](img/import_projects_from_github_importer.png) + +--- + +The importer will create any new namespaces if they don't exist or in the +case the namespace is taken, the project will be imported on the user's +namespace. ### Note -When you import your projects from GitHub, it is not possible to keep your labels, milestones, and cross-repository pull requests. We are working on improving this in the near future. + +When you import your projects from GitHub, it is not possible to keep your +labels, milestones, and cross-repository pull requests. We are working on +improving this in the near future. + +[gh-import]: ../../integration/github.md "GitHub integration" +[ee-gh]: http://doc.gitlab.com/ee/integration/github.html "GitHub integration for GitLab EE" +[new-project]: ../../gitlab-basics/create-project.md "How to create a new project in GitLab" -- cgit v1.2.1 From 0e769d2a48032815a8a2a32caae9025f01f92ff4 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 12 Jan 2016 15:18:17 +0100 Subject: Use gitlab-workhorse 0.5.4 Fixes routing errors for /api/v3/projects/ --- GITLAB_WORKHORSE_VERSION | 2 +- doc/install/installation.md | 2 +- doc/update/8.2-to-8.3.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index be14282b7ff..7d8568351b4 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -0.5.3 +0.5.4 diff --git a/doc/install/installation.md b/doc/install/installation.md index 8c4e092c636..50ccaabd839 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -348,7 +348,7 @@ GitLab Shell is an SSH access and repository management software developed speci cd /home/git sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git cd gitlab-workhorse - sudo -u git -H git checkout 0.5.3 + sudo -u git -H git checkout 0.5.4 sudo -u git -H make ### Initialize Database and Activate Advanced Features diff --git a/doc/update/8.2-to-8.3.md b/doc/update/8.2-to-8.3.md index a3950df5fef..2ca4e1f3770 100644 --- a/doc/update/8.2-to-8.3.md +++ b/doc/update/8.2-to-8.3.md @@ -78,7 +78,7 @@ which should already be on your system from GitLab 8.1. ```bash cd /home/git/gitlab-workhorse sudo -u git -H git fetch --all -sudo -u git -H git checkout 0.5.3 +sudo -u git -H git checkout 0.5.4 sudo -u git -H make ``` -- cgit v1.2.1 From ac6a10f3e88c5d2081b8638df63016089517a844 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Tue, 12 Jan 2016 12:29:10 -0200 Subject: Codestyle changes --- app/models/identity.rb | 2 +- lib/api/users.rb | 6 +++--- spec/models/identity_spec.rb | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/models/identity.rb b/app/models/identity.rb index 830b99fa3f2..e1915b079d4 100644 --- a/app/models/identity.rb +++ b/app/models/identity.rb @@ -19,7 +19,7 @@ class Identity < ActiveRecord::Base validates :extern_uid, allow_blank: true, uniqueness: { scope: :provider } validates :user_id, uniqueness: { scope: :provider } - def is_ldap? + def ldap? provider.starts_with?('ldap') end end diff --git a/lib/api/users.rb b/lib/api/users.rb index 01fd90139b0..fd2128bd179 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -303,10 +303,10 @@ module API if !user not_found!('User') - elsif !user.ldap_blocked? - user.activate - else + elsif user.ldap_blocked? forbidden!('LDAP blocked users cannot be unblocked by the API') + else + user.activate end end end diff --git a/spec/models/identity_spec.rb b/spec/models/identity_spec.rb index 107bfc17782..5afe042e154 100644 --- a/spec/models/identity_spec.rb +++ b/spec/models/identity_spec.rb @@ -28,11 +28,11 @@ RSpec.describe Identity, models: true do let(:other_identity) { create(:identity, provider: 'twitter') } it 'returns true if it is a ldap identity' do - expect(ldap_identity.is_ldap?).to be_truthy + expect(ldap_identity.ldap?).to be_truthy end it 'returns false if it is not a ldap identity' do - expect(other_identity.is_ldap?).to be_falsey + expect(other_identity.ldap?).to be_falsey end end end -- cgit v1.2.1 From 355c341fe7c6b7c503386cf0b0e39cc02dbc8902 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 12 Jan 2016 15:41:22 +0100 Subject: Stop tracking call stacks for instrumented views Where a vew is called from doesn't matter as much. We already know what action they belong to and this is more than enough information. By removing the file/line number from the list of tags we should also be able to reduce the number of series stored in InfluxDB. --- lib/gitlab/metrics.rb | 14 -------------- lib/gitlab/metrics/subscribers/action_view.rb | 10 +--------- spec/lib/gitlab/metrics/subscribers/action_view_spec.rb | 9 +-------- spec/lib/gitlab/metrics_spec.rb | 9 --------- 4 files changed, 2 insertions(+), 40 deletions(-) diff --git a/lib/gitlab/metrics.rb b/lib/gitlab/metrics.rb index 44356a0e42c..cdf7c168ff2 100644 --- a/lib/gitlab/metrics.rb +++ b/lib/gitlab/metrics.rb @@ -36,20 +36,6 @@ module Gitlab @pool end - # Returns a relative path and line number based on the last application call - # frame. - def self.last_relative_application_frame - frame = caller_locations.find do |l| - l.path.start_with?(RAILS_ROOT) && !l.path.start_with?(METRICS_ROOT) - end - - if frame - return frame.path.sub(PATH_REGEX, ''), frame.lineno - else - return nil, nil - end - end - def self.submit_metrics(metrics) prepared = prepare_metrics(metrics) diff --git a/lib/gitlab/metrics/subscribers/action_view.rb b/lib/gitlab/metrics/subscribers/action_view.rb index 7c0105d543a..2e9dd4645e3 100644 --- a/lib/gitlab/metrics/subscribers/action_view.rb +++ b/lib/gitlab/metrics/subscribers/action_view.rb @@ -33,16 +33,8 @@ module Gitlab def tags_for(event) path = relative_path(event.payload[:identifier]) - tags = { view: path } - file, line = Metrics.last_relative_application_frame - - if file and line - tags[:file] = file - tags[:line] = line - end - - tags + { view: path } end def current_transaction diff --git a/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb b/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb index 05e4fbbeb51..0695c5ce096 100644 --- a/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb +++ b/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb @@ -14,19 +14,12 @@ describe Gitlab::Metrics::Subscribers::ActionView do before do allow(subscriber).to receive(:current_transaction).and_return(transaction) - - allow(Gitlab::Metrics).to receive(:last_relative_application_frame). - and_return(['app/views/x.html.haml', 4]) end describe '#render_template' do it 'tracks rendering of a template' do values = { duration: 2.1 } - tags = { - view: 'app/views/x.html.haml', - file: 'app/views/x.html.haml', - line: 4 - } + tags = { view: 'app/views/x.html.haml' } expect(transaction).to receive(:increment). with(:view_duration, 2.1) diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb index c2782f95c8e..0ec8a6dc5cb 100644 --- a/spec/lib/gitlab/metrics_spec.rb +++ b/spec/lib/gitlab/metrics_spec.rb @@ -13,15 +13,6 @@ describe Gitlab::Metrics do end end - describe '.last_relative_application_frame' do - it 'returns an Array containing a file path and line number' do - file, line = described_class.last_relative_application_frame - - expect(line).to eq(__LINE__ - 2) - expect(file).to eq('spec/lib/gitlab/metrics_spec.rb') - end - end - describe '#submit_metrics' do it 'prepares and writes the metrics to InfluxDB' do connection = double(:connection) -- cgit v1.2.1 From 20c327fcfde414bbc3011ba076538bfb3d557e94 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 12 Jan 2016 16:16:29 +0100 Subject: Clarify the naming guideline [ci skip] --- doc/development/doc_styleguide.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/development/doc_styleguide.md b/doc/development/doc_styleguide.md index df2507a34d0..17c6b9d4c92 100644 --- a/doc/development/doc_styleguide.md +++ b/doc/development/doc_styleguide.md @@ -5,7 +5,10 @@ it organized and easy to find. ## Naming -- Use underscores for all names, including new documentation and images +- When creating a new document and it has more than one word in its name, + make sure to use underscores instead of spaces or dashes (`-`). For example, + a proper naming would be `import_projects_from_github.md`. The same rule + applies to images. ## Text -- cgit v1.2.1 From 80a4c808b1e5d331833f7b2ed531cb4fc81c7ef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Tue, 12 Jan 2016 11:02:16 -0500 Subject: Make diff_line_content helper return a safe String. #3945 --- app/helpers/diff_helper.rb | 4 ++-- app/views/projects/blob/preview.html.haml | 2 +- app/views/projects/diffs/_text_file.html.haml | 2 +- app/views/projects/notes/discussions/_diff.html.haml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 668610364c5..28c8e58b2ad 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -111,9 +111,9 @@ module DiffHelper def diff_line_content(line) if line.blank? - "  " + "  ".html_safe else - line + line.try(:html_safe) end end diff --git a/app/views/projects/blob/preview.html.haml b/app/views/projects/blob/preview.html.haml index e7c3460ad78..fed483d6788 100644 --- a/app/views/projects/blob/preview.html.haml +++ b/app/views/projects/blob/preview.html.haml @@ -20,6 +20,6 @@ - else %td.old_line %td.new_line - %td.line_content{class: "#{line.type}"}= raw diff_line_content(line.text) + %td.line_content{class: "#{line.type}"}= diff_line_content(line.text) - else .nothing-here-block No changes. diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml index f1b8cba5e55..521f2ac1e8d 100644 --- a/app/views/projects/diffs/_text_file.html.haml +++ b/app/views/projects/diffs/_text_file.html.haml @@ -22,7 +22,7 @@ = link_to_new_diff_note(line_code) %td.new_line{data: {linenumber: line.new_pos}} = link_to raw(type == "old" ? " " : line.new_pos), "##{line_code}", id: line_code - %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= diff_line_content(line.text).html_safe + %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= diff_line_content(line.text) - if @reply_allowed - comments = @line_notes.select { |n| n.line_code == line_code && n.active? }.sort_by(&:created_at) diff --git a/app/views/projects/notes/discussions/_diff.html.haml b/app/views/projects/notes/discussions/_diff.html.haml index 0301445b5b2..97347a9f67f 100644 --- a/app/views/projects/notes/discussions/_diff.html.haml +++ b/app/views/projects/notes/discussions/_diff.html.haml @@ -24,7 +24,7 @@ = raw(type == "new" ? " " : line.old_pos) %td.new_line = raw(type == "old" ? " " : line.new_pos) - %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line.text) + %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= diff_line_content(line.text) - if line_code == note.line_code = render "projects/notes/diff_notes_with_reply", notes: discussion_notes -- cgit v1.2.1 From 1c46ab040d470b29b7175d9a9e2d53a3e6b1f371 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 12 Jan 2016 17:10:07 +0100 Subject: Add CHANGELOG entry for 8.3.4 --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index d672d408318..7dd17251663 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -43,6 +43,9 @@ v 8.4.0 (unreleased) - API: Add support for deleting a tag via the API (Robert Schilling) - Allow subsequent validations in CI Linter +v 8.3.4 + - Use gitlab-workhorse 0.5.4 (fixes API routing bug) + v 8.3.3 - Preserve CE behavior with JIRA integration by only calling API if URL is set - Fix duplicated branch creation/deletion events when using Web UI (Stan Hu) -- cgit v1.2.1 From c476395b4d8b78cfc7431153a144ffccbd414c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Tue, 12 Jan 2016 11:14:41 -0500 Subject: Reuse existent vars with ref and path. #3945 --- app/controllers/projects/blob_controller.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index 6aa602321f4..6ca3a636359 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -65,10 +65,8 @@ class Projects::BlobController < Projects::ApplicationController end def diff - ref, file_name = params[:id].split('/', 2) - @form = UnfoldForm.new(params) - @lines = Gitlab::Diff::Highlight.process_file(repository, ref, file_name) + @lines = Gitlab::Diff::Highlight.process_file(repository, @ref, @path) @lines = @lines[@form.since - 1..@form.to - 1] if @form.bottom? -- cgit v1.2.1 From ab2c6cc01ff26e07db15110e037e72159c48dc53 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Tue, 12 Jan 2016 18:32:18 +0100 Subject: Add some fixes --- lib/api/api.rb | 1 - lib/api/entities.rb | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/api/api.rb b/lib/api/api.rb index 266b5f48f8f..1a1340c428c 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -54,7 +54,6 @@ module API mount Keys mount Tags mount Triggers - mount Builds end end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index a1a886d6fea..e19f9f8d75a 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -377,7 +377,7 @@ module API class Build < Grape::Entity expose :id, :status, :stage, :name, :ref, :tag, :coverage expose :created_at, :started_at, :finished_at - expose :user, with: UserFull + expose :user, with: User expose :download_url do |repo_obj, options| if options[:user_can_download_artifacts] repo_obj.download_url -- cgit v1.2.1 From f1f9b5f7d388c6d7a0938229c9211beddb2fd6a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Tue, 12 Jan 2016 12:53:54 -0500 Subject: Small fixes from code review. #3945 --- app/controllers/projects/merge_requests_controller.rb | 2 +- app/helpers/blob_helper.rb | 6 +++--- lib/gitlab/diff/highlight.rb | 4 ---- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index d25adbe952d..b70533ef7be 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -104,7 +104,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @commit = @merge_request.last_commit @first_commit = @merge_request.first_commit @diffs = @merge_request.compare_diffs - @diff_refs = [@merge_request.target_sha, @merge_request.source_branch] + @diff_refs = [@merge_request.target_sha, @merge_request.source_sha] @ci_commit = @merge_request.ci_commit @statuses = @ci_commit.statuses if @ci_commit diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index 1230002e69c..a80162a3e33 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -11,14 +11,14 @@ module BlobHelper end def highlight(blob_name, blob_content, nowrap: false, continue: false) - @formatter ||= rouge_formatter(nowrap: nowrap) + formatter = rouge_formatter(nowrap: nowrap) begin @lexer ||= Rouge::Lexer.guess(filename: blob_name, source: blob_content).new - result = @formatter.format(@lexer.lex(blob_content, continue: continue)).html_safe + result = formatter.format(@lexer.lex(blob_content, continue: continue)).html_safe rescue @lexer = Rouge::Lexers::PlainText - result = @formatter.format(@lexer.lex(blob_content)).html_safe + result = formatter.format(@lexer.lex(blob_content)).html_safe end result diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb index 3c44abff3fb..d0137ab5f08 100644 --- a/lib/gitlab/diff/highlight.rb +++ b/lib/gitlab/diff/highlight.rb @@ -125,10 +125,6 @@ module Gitlab lines.map! { |line| " #{line}" } end end - - def submodules - @submodules ||= diff_repository.raw_repository.submodules(diff_new_ref).keys - end end end end -- cgit v1.2.1 From 100cdce21e6dafa1b5d32313436fc610e8c88648 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 12 Jan 2016 13:13:16 -0500 Subject: Make sure time_ago_with_tooltip is using a Time object Somehow this test existed on EE but not in CE, so it started failing after a bad CE-to-EE merge. --- app/helpers/application_helper.rb | 2 +- spec/helpers/application_helper_spec.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 2b9bad9c9ea..f35b8ead1f7 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -205,7 +205,7 @@ module ApplicationHelper def time_ago_with_tooltip(time, placement: 'top', html_class: 'time_ago', skip_js: false) element = content_tag :time, time.to_s, class: "#{html_class} js-timeago js-timeago-pending", - datetime: time.getutc.iso8601, + datetime: time.to_time.getutc.iso8601, title: time.in_time_zone.to_s(:medium), data: { toggle: 'tooltip', placement: placement, container: 'body' } diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index efc850eb705..30e353148a8 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -285,6 +285,10 @@ describe ApplicationHelper do it 'allows the script tag to be excluded' do expect(element(skip_js: true)).not_to include 'script' end + + it 'converts to Time' do + expect { helper.time_ago_with_tooltip(Date.today) }.not_to raise_error + end end describe 'render_markup' do -- cgit v1.2.1 From efb3395b4fc0425ebbc2437ad03f0cd5fc851863 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Tue, 12 Jan 2016 19:32:44 +0100 Subject: Remove blank line --- lib/api/api.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/api/api.rb b/lib/api/api.rb index a9e1913f0f2..098dd975840 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -54,7 +54,6 @@ module API mount Keys mount Tags mount Triggers - mount Variables end end -- cgit v1.2.1 From 906de20f82f43dd81a82f56a689b1973a0c23080 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Tue, 12 Jan 2016 13:52:36 -0500 Subject: reverting _disscusion --- app/views/projects/merge_requests/_discussion.html.haml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml index ed3628a36a3..bff3c3b283d 100644 --- a/app/views/projects/merge_requests/_discussion.html.haml +++ b/app/views/projects/merge_requests/_discussion.html.haml @@ -1,7 +1,8 @@ - content_for :note_actions do - if can?(current_user, :update_merge_request, @merge_request) - = link_to 'Close', merge_request_path(@merge_request, merge_request: {state_event: :close}, format: 'json'), data: {no_turbolinks: true}, method: :put, class: "btn btn-nr btn-grouped btn-close close-mr-link btn-comment js-note-target-close #{merge_request_button_visibility(@merge_request, true)}", title: "Close merge request" - = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen}, format: 'json'), data: {no_turbolinks: true}, method: :put, class: "btn btn-nr btn-grouped btn-reopen reopen-mr-link btn-comment js-note-target-reopen #{merge_request_button_visibility(@merge_request, false)}", title: "Reopen merge request" + - if @merge_request.open? + = link_to 'Close', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-nr btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request" + - if @merge_request.closed? + = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-nr btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request" -#notes - = render "projects/notes/notes_with_form" +#notes= render "projects/notes/notes_with_form" -- cgit v1.2.1 From fa8b228f9dc391367e9cde8e90bff83dc6396434 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Tue, 12 Jan 2016 13:58:10 -0500 Subject: restores merge request coffee file --- app/assets/javascripts/merge_request.js.coffee | 49 -------------------------- 1 file changed, 49 deletions(-) diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee index c6c7f37707f..9047587db81 100644 --- a/app/assets/javascripts/merge_request.js.coffee +++ b/app/assets/javascripts/merge_request.js.coffee @@ -22,7 +22,6 @@ class @MergeRequest if $("a.btn-close").length @initTaskList() - @initMergeRequestBtnEventListeners() # Local jQuery finder $: (selector) -> @@ -36,54 +35,6 @@ class @MergeRequest # Show the first tab (Commits) $('.merge-request-tabs a[data-toggle="tab"]:first').tab('show') - initMergeRequestBtnEventListeners: -> - _this = @ - mergeRequestFailMessage = 'Unable to update this merge request at this time.' - $('a.btn-close, a.btn-reopen').on 'click', (e) -> - e.preventDefault() - e.stopImmediatePropagation() - $this = $(this) - isClose = $this.hasClass('btn-close') - shouldSubmit = $this.hasClass('btn-comment') - if shouldSubmit - _this.submitNoteForm($this.closest('form')) - $this.prop('disabled', true) - url = $this.attr('href') - $.ajax - type: 'PUT', - url: url, - error: (jqXHR, textStatus, errorThrown) -> - mergeRequestStatus = if isClose then 'close' else 'open' - new Flash(mergeRequestFailMessage, 'alert') - success: (data, textStatus, jqXHR) -> - if data.saved - if isClose - $('a.btn-close').addClass('hidden') - $('a.issuable-edit').addClass('hidden') - $('a.btn-reopen').removeClass('hidden') - $('div.status-box-closed').removeClass('hidden') - $('div.status-box-open').addClass('hidden') - - $('div.mr-state-widget-closed').removeClass('hidden') - $('div.mr-state-widget-opened').addClass('hidden') - else - $('a.btn-reopen').addClass('hidden') - $('a.issuable-edit').removeClass('hidden') - $('a.btn-close').removeClass('hidden') - $('div.status-box-closed').addClass('hidden') - $('div.status-box-open').removeClass('hidden') - - $('div.mr-state-widget-closed').addClass('hidden') - $('div.mr-state-widget-opened').removeClass('hidden') - else - new Flash(mergeRequestFailMessage, 'alert') - $this.prop('disabled', false) - - submitNoteForm: (form) => - noteText = form.find("textarea.js-note-text").val() - if noteText.trim().length > 0 - form.submit() - showAllCommits: -> this.$('.first-commits').remove() this.$('.all-commits').removeClass 'hide' -- cgit v1.2.1 From c73d55e1be79b9a78dd5279f906eb62e055709bd Mon Sep 17 00:00:00 2001 From: Greg Smethells Date: Tue, 29 Dec 2015 13:50:32 -0600 Subject: enable milestone filter to stick --- CHANGELOG | 1 + app/helpers/application_helper.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 7dd17251663..945ad02c9e6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -59,6 +59,7 @@ v 8.3.3 - Fix Error 500 when visiting build page of project with nil runners_token (Stan Hu) - Use WOFF versions of SourceSansPro fonts - Fix regression when builds were not generated for tags created through web/api interface + - Fix: maintain milestone filter between Open and Closed tabs (Greg Smethells) v 8.3.2 - Disable --follow in `git log` to avoid loading duplicate commit data in infinite scroll (Stan Hu) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 2b9bad9c9ea..b01805c92dd 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -266,7 +266,7 @@ module ApplicationHelper state: params[:state], scope: params[:scope], label_name: params[:label_name], - milestone_id: params[:milestone_id], + milestone_title: params[:milestone_title], assignee_id: params[:assignee_id], author_id: params[:author_id], sort: params[:sort], -- cgit v1.2.1 From 7abfe14ee1d8fc81be102c35e449829586cec9f8 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Tue, 12 Jan 2016 14:35:55 -0500 Subject: reverting merge_request_controller --- app/controllers/projects/merge_requests_controller.rb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index d85ef229254..de948d271c8 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -48,15 +48,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController @note_counts = Note.where(commit_id: @merge_request.commits.map(&:id)). group(:commit_id).count - json_merge_request = @merge_requests.as_json - respond_to do |format| format.html - format.json do - render json: { - hi: "yes" - } - end + format.json { render json: @merge_request } format.diff { render text: @merge_request.to_diff(current_user) } format.patch { render text: @merge_request.to_patch(current_user) } end @@ -149,8 +143,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController format.json do render json: { saved: @merge_request.valid?, - assignee_avatar_url: @merge_request.assignee.try(:avatar_url), - closed_event: @merge_request.closed_event + assignee_avatar_url: @merge_request.assignee.try(:avatar_url) } end end -- cgit v1.2.1 From aaf184bfa643d748cce42a4cf524642c6e77dc6e Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Tue, 12 Jan 2016 14:38:37 -0500 Subject: reverting _mr_title.html.haml --- .../merge_requests/show/_mr_title.html.haml | 26 +++++++++------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml index 7996d35c462..fc6fb2a0d42 100644 --- a/app/views/projects/merge_requests/show/_mr_title.html.haml +++ b/app/views/projects/merge_requests/show/_mr_title.html.haml @@ -1,12 +1,6 @@ .detail-page-header - - if @merge_request.merged? - .status-box{ class: "status-box-merged" } - Merged - - else - .status-box{ class: "status-box-closed #{merge_request_button_visibility(@merge_request, false)}"} - Closed - .status-box{ class: "status-box-open #{merge_request_button_visibility(@merge_request, true)}"} - Open + .status-box{ class: status_box_class(@merge_request) } + = @merge_request.state_human_name %span.identifier Merge Request ##{@merge_request.iid} %span.creator @@ -21,11 +15,11 @@ = time_ago_with_tooltip(@merge_request.updated_at, placement: 'bottom') .issue-btn-group.pull-right - - if can?(current_user, :update_merge_request, @merge_request) && !@merge_request.merged? - - = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }, format: 'json'), data: {no_turbolink: true}, method: :put, class: "btn btn-nr btn-grouped btn-reopen reopen-mr-link #{merge_request_button_visibility(@merge_request, false)}", title: 'Reopen merge request' - = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }, format: 'json'), data: {no_turbolink: true}, method: :put, class: "btn btn-nr btn-grouped btn-close #{merge_request_button_visibility(@merge_request, true)}", title: 'Close merge request' - - = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: "btn btn-nr btn-grouped issuable-edit #{merge_request_button_visibility(@merge_request, true)}", id: 'edit_merge_request' do - %i.fa.fa-pencil-square-o - Edit \ No newline at end of file + - if can?(current_user, :update_merge_request, @merge_request) + - if @merge_request.open? + = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: 'btn btn-nr btn-grouped btn-close', title: 'Close merge request' + = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'btn btn-nr btn-grouped issuable-edit', id: 'edit_merge_request' do + %i.fa.fa-pencil-square-o + Edit + - if @merge_request.closed? + = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'btn btn-nr btn-grouped btn-reopen reopen-mr-link', title: 'Reopen merge request' -- cgit v1.2.1 From e6f34237bc85f6347a895526179498c56c866970 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Tue, 12 Jan 2016 14:44:07 -0500 Subject: reverting MR ajax changes, which will be in a different MR --- app/assets/javascripts/merge_request_widget.js.coffee | 5 ++--- app/helpers/merge_requests_helper.rb | 13 ------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee index f0a687f79b1..738ffc8343b 100644 --- a/app/assets/javascripts/merge_request_widget.js.coffee +++ b/app/assets/javascripts/merge_request_widget.js.coffee @@ -28,9 +28,8 @@ class @MergeRequestWidget getMergeStatus: -> $.get @opts.url_to_automerge_check, (data) -> - console.log("data",data); - # $('div.mr-state-widget.mr-state-widget-opened').replaceWith(data) - + $('.mr-state-widget').replaceWith(data) + getCiStatus: -> if @opts.ci_enable $.get @opts.url_to_ci_check, (data) => diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index 6306450ca26..1dd07a2a220 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -19,19 +19,6 @@ module MergeRequestsHelper } end - def merge_request_button_visibility(mr, closed) - return 'hidden' if mr.closed? == closed - end - - def merge_request_widget_visibility(mr, *states) - states.each do |state| - if mr.state == state - return - end - end - return 'hidden' - end - def mr_css_classes(mr) classes = "merge-request" classes << " closed" if mr.closed? -- cgit v1.2.1 From 63363e47f4228e15585b0908d91c8749b1067d37 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Tue, 12 Jan 2016 14:55:54 -0500 Subject: reverting more MR ajax files, will appear in different commit --- .../projects/merge_requests/widget/_open.html.haml | 39 +++++----- .../projects/merge_requests/widget/_show.html.haml | 14 ++-- .../merge_requests/widget/open/_archived.html.haml | 2 +- .../fixtures/merge_requests_show.html.haml | 12 +-- spec/javascripts/merge_request_spec.js.coffee | 88 ---------------------- 5 files changed, 31 insertions(+), 124 deletions(-) diff --git a/app/views/projects/merge_requests/widget/_open.html.haml b/app/views/projects/merge_requests/widget/_open.html.haml index 2257a166460..55dbae598d3 100644 --- a/app/views/projects/merge_requests/widget/_open.html.haml +++ b/app/views/projects/merge_requests/widget/_open.html.haml @@ -1,23 +1,24 @@ -.mr-state-widget.mr-state-widget-opened{class: merge_request_widget_visibility(@merge_request, "opened","reopened")} +.mr-state-widget = render 'projects/merge_requests/widget/heading' - .mr-widget-body.merge-request-archived{class: ("hidden" unless @project.archived?)} - = render 'projects/merge_requests/widget/open/archived' - .mr-widget-body.merge-request-blank{class: ("hidden" unless @merge_request.commits.blank?)} - = render 'projects/merge_requests/widget/open/nothing' - .mr-widget-body.merge-request-branch-missing{class: ("hidden" unless @merge_request.branch_missing?)} - = render 'projects/merge_requests/widget/open/missing_branch' - .mr-widget-body.merge-request-unchecked{class: ("hidden" unless @merge_request.unchecked?)} - = render 'projects/merge_requests/widget/open/check' - .mr-widget-body.merge-request-cannot-be-merged{class: ("hidden" unless @merge_request.cannot_be_merged?)} - = render 'projects/merge_requests/widget/open/conflicts' - .mr-widget-body.merge-request-work-in-progress{class: ("hidden" unless @merge_request.work_in_progress?)} - = render 'projects/merge_requests/widget/open/wip' - .mr-widget-body.merge-request-merge-when-build-succeeds{class: ("hidden" unless @merge_request.merge_when_build_succeeds?)} - = render 'projects/merge_requests/widget/open/merge_when_build_succeeds' - .mr-widget-body.not-allowed{class: ("hidden" if @merge_request.can_be_merged_by?(current_user))} - = render 'projects/merge_requests/widget/open/not_allowed' - .mr-widget-body.merge-request-archived.can-be-merged{class: ("hidden" unless @merge_request.can_be_merged?)} - = render 'projects/merge_requests/widget/open/accept' + .mr-widget-body + - if @project.archived? + = render 'projects/merge_requests/widget/open/archived' + - elsif @merge_request.commits.blank? + = render 'projects/merge_requests/widget/open/nothing' + - elsif @merge_request.branch_missing? + = render 'projects/merge_requests/widget/open/missing_branch' + - elsif @merge_request.unchecked? + = render 'projects/merge_requests/widget/open/check' + - elsif @merge_request.cannot_be_merged? + = render 'projects/merge_requests/widget/open/conflicts' + - elsif @merge_request.work_in_progress? + = render 'projects/merge_requests/widget/open/wip' + - elsif @merge_request.merge_when_build_succeeds? + = render 'projects/merge_requests/widget/open/merge_when_build_succeeds' + - elsif !@merge_request.can_be_merged_by?(current_user) + = render 'projects/merge_requests/widget/open/not_allowed' + - elsif @merge_request.can_be_merged? + = render 'projects/merge_requests/widget/open/accept' - if @closes_issues.present? .mr-widget-footer diff --git a/app/views/projects/merge_requests/widget/_show.html.haml b/app/views/projects/merge_requests/widget/_show.html.haml index d8f81dab067..a489d4f9b24 100644 --- a/app/views/projects/merge_requests/widget/_show.html.haml +++ b/app/views/projects/merge_requests/widget/_show.html.haml @@ -1,13 +1,17 @@ -= render 'projects/merge_requests/widget/open' -= render 'projects/merge_requests/widget/merged' -= render 'projects/merge_requests/widget/closed' -= render 'projects/merge_requests/widget/locked' +- if @merge_request.open? + = render 'projects/merge_requests/widget/open' +- elsif @merge_request.merged? + = render 'projects/merge_requests/widget/merged' +- elsif @merge_request.closed? + = render 'projects/merge_requests/widget/closed' +- elsif @merge_request.locked? + = render 'projects/merge_requests/widget/locked' :javascript var merge_request_widget; merge_request_widget = new MergeRequestWidget({ - url_to_automerge_check: "#{merge_check_namespace_project_merge_request_path(@project.namespace, @project, @merge_request, format: :json)}", + url_to_automerge_check: "#{merge_check_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}", check_enable: #{@merge_request.unchecked? ? "true" : "false"}, url_to_ci_check: "#{ci_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}", ci_enable: #{@project.ci_service ? "true" : "false"}, diff --git a/app/views/projects/merge_requests/widget/open/_archived.html.haml b/app/views/projects/merge_requests/widget/open/_archived.html.haml index 0d61e56d8fb..ab30fa6b243 100644 --- a/app/views/projects/merge_requests/widget/open/_archived.html.haml +++ b/app/views/projects/merge_requests/widget/open/_archived.html.haml @@ -1,4 +1,4 @@ -%h4 +%h4 Project is archived %p This merge request cannot be merged because archived projects cannot be written to. diff --git a/spec/javascripts/fixtures/merge_requests_show.html.haml b/spec/javascripts/fixtures/merge_requests_show.html.haml index fdfa8a273e2..8447dfdda32 100644 --- a/spec/javascripts/fixtures/merge_requests_show.html.haml +++ b/spec/javascripts/fixtures/merge_requests_show.html.haml @@ -1,14 +1,4 @@ -:css - .hidden { display: none !important } - -.flash-container - .flash-alert - .flash-notice - -.status-box.status-box-open Open -.status-box.status-box-closed.hidden Closed -%a.btn-close{"href" => "http://gitlab.com/merge_requests/6/close"} Close -%a.btn-reopen.hidden{"href" => "http://gitlab.com/merge_requests/6/reopen"} Reopen +%a.btn-close .detail-page-description .description.js-task-list-container diff --git a/spec/javascripts/merge_request_spec.js.coffee b/spec/javascripts/merge_request_spec.js.coffee index e21bfde38ad..22ebc7039d1 100644 --- a/spec/javascripts/merge_request_spec.js.coffee +++ b/spec/javascripts/merge_request_spec.js.coffee @@ -21,91 +21,3 @@ describe 'MergeRequest', -> expect(req.data.merge_request.description).not.toBe(null) $('.js-task-list-field').trigger('tasklist:changed') - - describe 'reopen/close merge request', -> - fixture.preload('merge_requests_show.html') - beforeEach -> - fixture.load('merge_requests_show.html') - @merge_request = new MergeRequest({}) - it 'closes a merge request', -> - $.ajax = (obj) -> - expect(obj.type).toBe('PUT') - expect(obj.url).toBe('http://gitlab.com/merge_requests/6/close') - obj.success saved:true - - $btnClose = $('a.btn-close') - $btnReopen = $('a.btn-reopen') - expect($btnReopen).toBeHidden() - expect($btnClose.text()).toBe('Close') - expect(typeof $btnClose.prop('disabled')).toBe('undefined') - - $btnClose.trigger('click') - - expect($btnReopen).toBeVisible() - - expect($btnClose).toBeHidden() - expect($('div.status-box-closed')).toBeVisible() - expect($('div.status-box-open')).toBeHidden() - - it 'fails to close a merge request with success:false', -> - - $.ajax = (obj) -> - expect(obj.type).toBe('PUT') - expect(obj.url).toBe('http://goesnowhere.nothing/whereami') - obj.success saved:false - - $btnClose = $('a.btn-close') - $btnReopen = $('a.btn-reopen') - $btnClose.attr('href','http://goesnowhere.nothing/whereami') - expect($btnReopen).toBeHidden() - expect($btnClose.text()).toBe('Close') - expect(typeof $btnClose.prop('disabled')).toBe('undefined') - - $btnClose.trigger('click') - - expect($btnReopen).toBeHidden() - expect($btnClose).toBeVisible() - expect($('div.status-box-closed')).toBeHidden() - expect($('div.status-box-open')).toBeVisible() - expect($('div.flash-alert')).toBeVisible() - expect($('div.flash-alert').text()).toBe('Unable to update this merge request at this time.') - - it 'fails to closes an issue with HTTP error', -> - - $.ajax = (obj) -> - expect(obj.type).toBe('PUT') - expect(obj.url).toBe('http://goesnowhere.nothing/whereami') - obj.error() - - $btnClose = $('a.btn-close') - $btnReopen = $('a.btn-reopen') - $btnClose.attr('href','http://goesnowhere.nothing/whereami') - expect($btnReopen).toBeHidden() - expect($btnClose.text()).toBe('Close') - expect(typeof $btnClose.prop('disabled')).toBe('undefined') - - $btnClose.trigger('click') - - expect($btnReopen).toBeHidden() - expect($btnClose).toBeVisible() - expect($('div.status-box-closed')).toBeHidden() - expect($('div.status-box-open')).toBeVisible() - expect($('div.flash-alert')).toBeVisible() - expect($('div.flash-alert').text()).toBe('Unable to update this merge request at this time.') - - it 'reopens a merge request', -> - $.ajax = (obj) -> - expect(obj.type).toBe('PUT') - expect(obj.url).toBe('http://gitlab.com/merge_requests/6/reopen') - obj.success saved: true - - $btnClose = $('a.btn-close') - $btnReopen = $('a.btn-reopen') - expect($btnReopen.text()).toBe('Reopen') - - $btnReopen.trigger('click') - - expect($btnReopen).toBeHidden() - expect($btnClose).toBeVisible() - expect($('div.status-box-open')).toBeVisible() - expect($('div.status-box-closed')).toBeHidden() \ No newline at end of file -- cgit v1.2.1 From c0385488fbfaf1285122793cea417e607c8e771e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Tue, 12 Jan 2016 15:12:30 -0500 Subject: Fix broken spec. #3945 --- app/helpers/diff_helper.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 28c8e58b2ad..0ec532a9a90 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -113,7 +113,8 @@ module DiffHelper if line.blank? "  ".html_safe else - line.try(:html_safe) + # Return line if it isn't a String, it helps when it's Numeric + line.is_a?(String) ? line.html_safe : line end end -- cgit v1.2.1 From c0220198d1fc880a092134a07901c52be4b3595b Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Tue, 12 Jan 2016 15:16:26 -0500 Subject: removing last chunk of MR ajax changes, rest will be in another MR --- app/models/merge_request.rb | 10 ++++++++++ app/views/projects/issues/_discussion.html.haml | 6 ++++-- app/views/projects/merge_requests/widget/_closed.html.haml | 2 +- app/views/projects/merge_requests/widget/_locked.html.haml | 2 +- app/views/projects/merge_requests/widget/_merged.html.haml | 2 +- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index b2cb86dc1e5..c63d0c01653 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -466,6 +466,16 @@ class MergeRequest < ActiveRecord::Base ::Gitlab::GitAccess.new(user, project).can_push_to_branch?(target_branch) end + def state_human_name + if merged? + "Merged" + elsif closed? + "Closed" + else + "Open" + end + end + def target_sha @target_sha ||= target_project. repository.commit(target_branch).sha diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml index 673020a4e30..dc434cf38c4 100644 --- a/app/views/projects/issues/_discussion.html.haml +++ b/app/views/projects/issues/_discussion.html.haml @@ -1,7 +1,9 @@ - content_for :note_actions do - if can?(current_user, :update_issue, @issue) - = link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-reopen btn-comment js-note-target-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen Issue' - = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-close btn-comment js-note-target-close #{issue_button_visibility(@issue, true)}", title: 'Close Issue' + - if @issue.closed? + = link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-reopen js-note-target-reopen', title: 'Reopen Issue' + - else + = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-close js-note-target-close', title: 'Close Issue' #notes = render 'projects/notes/notes_with_form' diff --git a/app/views/projects/merge_requests/widget/_closed.html.haml b/app/views/projects/merge_requests/widget/_closed.html.haml index 46ee22ec873..f3cc0e7e8a1 100644 --- a/app/views/projects/merge_requests/widget/_closed.html.haml +++ b/app/views/projects/merge_requests/widget/_closed.html.haml @@ -1,4 +1,4 @@ -.mr-state-widget.mr-state-widget-closed{class: merge_request_widget_visibility(@merge_request, 'closed')} +.mr-state-widget = render 'projects/merge_requests/widget/heading' .mr-widget-body %h4 diff --git a/app/views/projects/merge_requests/widget/_locked.html.haml b/app/views/projects/merge_requests/widget/_locked.html.haml index 55ecd69a6ce..78d0783cba0 100644 --- a/app/views/projects/merge_requests/widget/_locked.html.haml +++ b/app/views/projects/merge_requests/widget/_locked.html.haml @@ -1,4 +1,4 @@ -.mr-state-widget.mr-state-widget-locked{class: merge_request_widget_visibility(@merge_request, 'locked')} +.mr-state-widget = render 'projects/merge_requests/widget/heading' .mr-widget-body %h4 diff --git a/app/views/projects/merge_requests/widget/_merged.html.haml b/app/views/projects/merge_requests/widget/_merged.html.haml index 2bb50967023..d1d602eecdc 100644 --- a/app/views/projects/merge_requests/widget/_merged.html.haml +++ b/app/views/projects/merge_requests/widget/_merged.html.haml @@ -1,4 +1,4 @@ -.mr-state-widget.mr-state-widget-merged{class: merge_request_widget_visibility(@merge_request, 'merged')} +.mr-state-widget = render 'projects/merge_requests/widget/heading' .mr-widget-body %h4 -- cgit v1.2.1 From d82d3ecd488a04eacaf7bb0de6d3091cdceaf0a7 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Tue, 12 Jan 2016 15:45:48 -0500 Subject: adds back in discussion.haml.html for issues commenting and closing/reopening properly. --- app/assets/javascripts/issue.js.coffee | 2 ++ app/views/projects/issues/_discussion.html.haml | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee index 0d26c58a81d..8ecd0f36339 100644 --- a/app/assets/javascripts/issue.js.coffee +++ b/app/assets/javascripts/issue.js.coffee @@ -33,6 +33,7 @@ class @Issue url: url, error: (jqXHR, textStatus, errorThrown) -> issueStatus = if isClose then 'close' else 'open' + console.log('failed here') new Flash(issueFailMessage, 'alert') success: (data, textStatus, jqXHR) -> if data.saved @@ -47,6 +48,7 @@ class @Issue $('div.status-box-closed').addClass('hidden') $('div.status-box-open').removeClass('hidden') else + console.log('failed there') new Flash(issueFailMessage, 'alert') $this.prop('disabled', false) diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml index dc434cf38c4..673020a4e30 100644 --- a/app/views/projects/issues/_discussion.html.haml +++ b/app/views/projects/issues/_discussion.html.haml @@ -1,9 +1,7 @@ - content_for :note_actions do - if can?(current_user, :update_issue, @issue) - - if @issue.closed? - = link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-reopen js-note-target-reopen', title: 'Reopen Issue' - - else - = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-close js-note-target-close', title: 'Close Issue' + = link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-reopen btn-comment js-note-target-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen Issue' + = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-close btn-comment js-note-target-close #{issue_button_visibility(@issue, true)}", title: 'Close Issue' #notes = render 'projects/notes/notes_with_form' -- cgit v1.2.1 From f01d0520713a2b5cb58511cdda10d459941ac8e9 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Tue, 12 Jan 2016 16:29:14 -0500 Subject: gets merge request discussion working again --- app/assets/javascripts/issue.js.coffee | 2 -- app/assets/javascripts/merge_request.js.coffee | 22 ++++++++++++++++++++++ .../projects/merge_requests/_discussion.html.haml | 4 ++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee index 8ecd0f36339..0d26c58a81d 100644 --- a/app/assets/javascripts/issue.js.coffee +++ b/app/assets/javascripts/issue.js.coffee @@ -33,7 +33,6 @@ class @Issue url: url, error: (jqXHR, textStatus, errorThrown) -> issueStatus = if isClose then 'close' else 'open' - console.log('failed here') new Flash(issueFailMessage, 'alert') success: (data, textStatus, jqXHR) -> if data.saved @@ -48,7 +47,6 @@ class @Issue $('div.status-box-closed').addClass('hidden') $('div.status-box-open').removeClass('hidden') else - console.log('failed there') new Flash(issueFailMessage, 'alert') $this.prop('disabled', false) diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee index 9047587db81..ed0bf2b3f48 100644 --- a/app/assets/javascripts/merge_request.js.coffee +++ b/app/assets/javascripts/merge_request.js.coffee @@ -19,6 +19,7 @@ class @MergeRequest # Prevent duplicate event bindings @disableTaskList() + @initMRBtnListeners() if $("a.btn-close").length @initTaskList() @@ -43,6 +44,27 @@ class @MergeRequest $('.detail-page-description .js-task-list-container').taskList('enable') $(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList + initMRBtnListeners: -> + _this = @ + $('a.btn-close, a.btn-reopen').on 'click', (e) -> + $this = $(this) + if $this.data('submitted') + return + e.preventDefault() + e.stopImmediatePropagation() + shouldSubmit = $this.hasClass('btn-comment') + console.log("shouldSubmit") + if shouldSubmit + _this.submitNoteForm($this.closest('form'),$this) + + submitNoteForm: (form, $button) => + noteText = form.find("textarea.js-note-text").val() + if noteText.trim().length > 0 + form.submit() + $button.data('submitted',true) + $button.trigger('click') + + disableTaskList: -> $('.detail-page-description .js-task-list-container').taskList('disable') $(document).off 'tasklist:changed', '.detail-page-description .js-task-list-container' diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml index bff3c3b283d..1c7de94acfd 100644 --- a/app/views/projects/merge_requests/_discussion.html.haml +++ b/app/views/projects/merge_requests/_discussion.html.haml @@ -1,8 +1,8 @@ - content_for :note_actions do - if can?(current_user, :update_merge_request, @merge_request) - if @merge_request.open? - = link_to 'Close', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-nr btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request" + = link_to 'Close', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-nr btn-comment btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request" - if @merge_request.closed? - = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-nr btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request" + = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-nr btn-comment btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request" #notes= render "projects/notes/notes_with_form" -- cgit v1.2.1 From b0145d765b94d2cef86b10b6dd22895779cfef33 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 12 Jan 2016 16:30:38 -0500 Subject: Revert "Remove the `:coffee` and `:coffeescript` Haml filters" This reverts commit ae7de2f8510d6d4b69120f168122e26d69dda256. --- config/initializers/haml.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/config/initializers/haml.rb b/config/initializers/haml.rb index 1516476815a..7e8ddb3716b 100644 --- a/config/initializers/haml.rb +++ b/config/initializers/haml.rb @@ -1,7 +1 @@ Haml::Template.options[:ugly] = true - -# Remove the `:coffee` and `:coffeescript` filters -# -# See https://git.io/vztMu and http://stackoverflow.com/a/17571242/223897 -Haml::Filters.remove_filter('coffee') -Haml::Filters.remove_filter('coffeescript') -- cgit v1.2.1 From 6e3358a5077f5c6052e733722cd6baa63e43c081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Tue, 12 Jan 2016 17:36:08 -0500 Subject: Remove no longer required code. #3945 --- lib/gitlab/diff/highlight.rb | 51 ++++++++------------------------------------ 1 file changed, 9 insertions(+), 42 deletions(-) diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb index d0137ab5f08..14cf98e24a2 100644 --- a/lib/gitlab/diff/highlight.rb +++ b/lib/gitlab/diff/highlight.rb @@ -44,74 +44,41 @@ module Gitlab return [] if @lines.empty? extract_line_prefixes - - @code = unescape_html(raw_content) - @highlighted_code = formatter.format(lexer.lex(@code)) - - is_diff_line? ? update_diff_lines : @highlighted_code.lines + update_diff_lines end private - def is_diff_line? - @lines.first.is_a?(Gitlab::Diff::Line) - end - def text_lines - @text_lines ||= (is_diff_line? ? @lines.map(&:text) : @lines) - end - - def raw_content - @raw_content ||= text_lines.join(is_diff_line? ? "\n" : nil) + @text_lines ||= @lines.map(&:text) end def extract_line_prefixes - @diff_line_prefixes ||= begin - if is_diff_line? - text_lines.map { |line| line.sub!(/\A((\+|\-))/, '');$1 } - else - [] - end - end + @diff_line_prefixes ||= text_lines.map { |line| line.sub!(/\A((\+|\-))/, '');$1 } end def update_diff_lines - @highlighted_code.lines.each_with_index do |line, i| - diff_line = @lines[i] + @lines.each_with_index do |line, i| line_prefix = @diff_line_prefixes[i] || ' ' # ignore highlighting for "match" lines - next if diff_line.type == 'match' + next if line.type == 'match' - case diff_line.type + case line.type when 'new', nil - line = new_lines[diff_line.new_pos - 1] + highlighted_line = new_lines[line.new_pos - 1] when 'old' - line = old_lines[diff_line.old_pos - 1] + highlighted_line = old_lines[line.old_pos - 1] end # Only update text if line is found. This will prevent # issues with submodules given the line only exists in diff content. - diff_line.text = line.gsub!(/\A\s/, line_prefix) if line + line.text = highlighted_line.gsub!(/\A\s/, line_prefix) if line end @lines end - def lexer - Rouge::Lexer.guess(filename: @file_name, source: @code).new rescue Rouge::Lexers::PlainText.new - end - - def unescape_html(content) - text = CGI.unescapeHTML(content) - text.gsub!(' ', ' ') - text - end - - def formatter - self.class.formatter - end - def old_lines @old_lines ||= begin lines = self.class.process_file(diff_repository, diff_old_ref, diff_old_path) -- cgit v1.2.1 From f547e733d1f8acf2c8ae82835b91ae166cf95b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Tue, 12 Jan 2016 17:49:11 -0500 Subject: Add more specs. #3945 --- spec/lib/gitlab/diff/highlight_spec.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb index 4ab509f47b9..cdeed603e23 100644 --- a/spec/lib/gitlab/diff/highlight_spec.rb +++ b/spec/lib/gitlab/diff/highlight_spec.rb @@ -30,6 +30,24 @@ describe Gitlab::Diff::Highlight, lib: true do expect(diff_lines[0].text).to eq('@@ -6,12 +6,18 @@ module Popen') expect(diff_lines[22].text).to eq('@@ -19,6 +25,7 @@ module Popen') end + + it 'should highlight unchanged lines' do + code = %Q{ def popen(cmd, path=nil)\n} + + expect(diff_lines[2].text).to eq(code) + end + + it 'should highlight added lines' do + code = %Q{+ raise RuntimeError, "System commands must be given as an array of strings"\n} + + expect(diff_lines[5].text).to eq(code) + end + + it 'should highlight removed lines' do + code = %Q{- raise "System commands must be given as an array of strings"\n} + + expect(diff_lines[4].text).to eq(code) + end end end -- cgit v1.2.1 From 4819de1e7026849e10a0a05939152dfa01b5ba85 Mon Sep 17 00:00:00 2001 From: Landon Date: Tue, 12 Jan 2016 15:54:09 -0700 Subject: Mention channel/key bug in irkerd docs Per this issue: https://gitlab.com/esr/irker/issues/2 A documentation update was added to irkerd (https://gitlab.com/esr/irker/commit/190808c37d4ab5f0f16fe35352ff36863c2732d5) but the bug is still there. Making a note of it here could save someone a lot of hassle. This could probably be worded better if someone else wants to take a stab at it. --- app/models/project_services/irker_service.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/models/project_services/irker_service.rb b/app/models/project_services/irker_service.rb index bd9b580038f..04c714bfaad 100644 --- a/app/models/project_services/irker_service.rb +++ b/app/models/project_services/irker_service.rb @@ -73,9 +73,10 @@ class IrkerService < Service 'irc[s]://irc.network.net[:port]/#channel. Special cases: if '\ 'you want the channel to be a nickname instead, append ",isnick" to ' \ 'the channel name; if the channel is protected by a secret password, ' \ - ' append "?key=secretpassword" to the URI. Note that if you specify a ' \ - ' default IRC URI to prepend before each recipient, you can just give ' \ - ' a channel name.' }, + ' append "?key=secretpassword" to the URI (Note that due to a bug, if you ' \ + ' want to use a password, you have to omit the "#" on the channel). If you ' \ + ' specify a default IRC URI to prepend before each recipient, you can just ' \ + ' give a channel name.' }, { type: 'checkbox', name: 'colorize_messages' }, ] end -- cgit v1.2.1 From 3dfb69a59f94754320d25b115031766ffc67fcdf Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 12 Jan 2016 18:04:02 -0500 Subject: Prepare Installation and Update docs for 8.4 RC1 [ci skip] --- doc/install/installation.md | 4 +- doc/update/8.3-to-8.4.md | 148 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 doc/update/8.3-to-8.4.md diff --git a/doc/install/installation.md b/doc/install/installation.md index 50ccaabd839..e645445df2a 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -231,9 +231,9 @@ sudo usermod -aG redis git ### Clone the Source # Clone GitLab repository - sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-3-stable gitlab + sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-4-stable gitlab -**Note:** You can change `8-3-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server! +**Note:** You can change `8-4-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server! ### Configure It diff --git a/doc/update/8.3-to-8.4.md b/doc/update/8.3-to-8.4.md new file mode 100644 index 00000000000..1cbeab3eca3 --- /dev/null +++ b/doc/update/8.3-to-8.4.md @@ -0,0 +1,148 @@ +# From 8.3 to 8.4 + +### 1. Stop server + + sudo service gitlab stop + +### 2. Backup + +```bash +cd /home/git/gitlab +sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production +``` + +### 3. Get latest code + +```bash +sudo -u git -H git fetch --all +sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically +``` + +For GitLab Community Edition: + +```bash +sudo -u git -H git checkout 8-4-stable +``` + +OR + +For GitLab Enterprise Edition: + +```bash +sudo -u git -H git checkout 8-4-stable-ee +``` + +### 4. Update gitlab-shell + +```bash +cd /home/git/gitlab-shell +sudo -u git -H git fetch --all +sudo -u git -H git checkout v2.6.9 +``` + +### 5. Update gitlab-workhorse + +Install and compile gitlab-workhorse. This requires [Go 1.5](https://golang.org/dl) +which should already be on your system from GitLab 8.1. + +```bash +cd /home/git/gitlab-workhorse +sudo -u git -H git fetch --all +sudo -u git -H git checkout 0.5.4 +sudo -u git -H make +``` + +### 6. Install libs, migrations, etc. + +```bash +cd /home/git/gitlab + +# MySQL installations (note: the line below states '--without postgres') +sudo -u git -H bundle install --without postgres development test --deployment + +# PostgreSQL installations (note: the line below states '--without mysql') +sudo -u git -H bundle install --without mysql development test --deployment + +# Run database migrations +sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production + +# Clean up assets and cache +sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production + +``` + +### 7. Update configuration files + +#### New configuration options for `gitlab.yml` + +There are new configuration options available for [`gitlab.yml`](config/gitlab.yml.example). View them with the command below and apply them manually to your current `gitlab.yml`: + +```sh +git diff origin/8-3-stable:config/gitlab.yml.example origin/8-4-stable:config/gitlab.yml.example +``` + +#### Nginx configuration + +GitLab 8.3 introduced major changes in the NGINX configuration. Ensure you're +still up-to-date with the latest changes: + +```sh +# For HTTPS configurations +git diff origin/8-3-stable:lib/support/nginx/gitlab-ssl origin/8-4-stable:lib/support/nginx/gitlab-ssl + +# For HTTP configurations +git diff origin/8-3-stable:lib/support/nginx/gitlab origin/8-4-stable:lib/support/nginx/gitlab +``` + +If you are using Apache instead of NGINX please see the updated [Apache templates]. +Also note that because Apache does not support upstreams behind Unix sockets you +will need to let gitlab-workhorse listen on a TCP port. You can do this +via [/etc/default/gitlab]. + +[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache +[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-4-stable/lib/support/init.d/gitlab.default.example#L34 + +#### Init script + +We updated the init script for GitLab in order to pass new +configuration options to gitlab-workhorse. We let gitlab-workhorse +connect to the Rails application via a Unix domain socket and we tell +it where the 'public' directory of GitLab is. + +``` +cd /home/git/gitlab +sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab +``` + +### 8. Start application + + sudo service gitlab start + sudo service nginx restart + +### 9. Check application status + +Check if GitLab and its environment are configured correctly: + + sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production + +To make sure you didn't miss anything run a more thorough check: + + sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production + +If all items are green, then congratulations, the upgrade is complete! + +## Things went south? Revert to previous version (8.3) + +### 1. Revert the code to the previous version + +Follow the [upgrade guide from 8.2 to 8.3](8.2-to-8.3.md), except for the +database migration (the backup is already migrated to the previous version). + +### 2. Restore from the backup + +```bash +cd /home/git/gitlab +sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production +``` + +If you have more than one backup `*.tar` file(s) please add `BACKUP=timestamp_of_backup` to the command above. -- cgit v1.2.1 From 7307fa48e70a9fb42902c8a84479d4cf669640aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Tue, 12 Jan 2016 19:28:31 -0500 Subject: Fix broken specs. #3945 --- app/controllers/projects/merge_requests_controller.rb | 3 ++- lib/gitlab/diff/highlight.rb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index b70533ef7be..95fd62b8ace 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -104,7 +104,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController @commit = @merge_request.last_commit @first_commit = @merge_request.first_commit @diffs = @merge_request.compare_diffs - @diff_refs = [@merge_request.target_sha, @merge_request.source_sha] + # We need to use #source_branch because #source_sha requires an existent MergeRequestDiff object. + @diff_refs = [@merge_request.target_sha, @merge_request.source_branch] @ci_commit = @merge_request.ci_commit @statuses = @ci_commit.statuses if @ci_commit diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb index 14cf98e24a2..0b6a348acbc 100644 --- a/lib/gitlab/diff/highlight.rb +++ b/lib/gitlab/diff/highlight.rb @@ -73,7 +73,7 @@ module Gitlab # Only update text if line is found. This will prevent # issues with submodules given the line only exists in diff content. - line.text = highlighted_line.gsub!(/\A\s/, line_prefix) if line + line.text = highlighted_line.gsub!(/\A\s/, line_prefix) if highlighted_line end @lines -- cgit v1.2.1 From 0bb37c1ff21302c139061e133f8683013b33b155 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Tue, 12 Jan 2016 20:49:43 -0500 Subject: makes message plural for multiple MRs and removes from loop. Duh. --- app/assets/stylesheets/framework/lists.scss | 6 +++++- app/views/projects/issues/_closed_by_box.html.haml | 4 +++- app/views/projects/issues/_merge_requests.html.haml | 6 +++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index 1c74e525a60..bbdb1c038c5 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -74,7 +74,7 @@ /** light list with border-bottom between li **/ -ul.bordered-list { +ul.bordered-list, ul.unstyled-list { @include basic-list; &.top-list { @@ -88,6 +88,10 @@ ul.bordered-list { } } +ul.unstyled-list > li { + border-bottom: none; +} + ul.task-list { li.task-list-item { list-style-type: none; diff --git a/app/views/projects/issues/_closed_by_box.html.haml b/app/views/projects/issues/_closed_by_box.html.haml index c434ad41f89..38469ed4774 100644 --- a/app/views/projects/issues/_closed_by_box.html.haml +++ b/app/views/projects/issues/_closed_by_box.html.haml @@ -1,2 +1,4 @@ .issue-closed-by-widget.second-block - When this merge request is accepted, this issue will be closed automatically. + - pluralized_mr_this = merge_request_count > 1 ? "these" : "this" + - pluralized_mr_is = merge_request_count > 1 ? "are" : "is" + When #{pluralized_mr_this} merge #{"request".pluralize(merge_request_count)} #{pluralized_mr_is} accepted, this issue will be closed automatically. diff --git a/app/views/projects/issues/_merge_requests.html.haml b/app/views/projects/issues/_merge_requests.html.haml index e3b41bca815..640a1962ffc 100644 --- a/app/views/projects/issues/_merge_requests.html.haml +++ b/app/views/projects/issues/_merge_requests.html.haml @@ -1,7 +1,7 @@ -if @merge_requests.any? %h2.merge-requests-title = pluralize(@merge_requests.count, 'Related Merge Request') - %ul.bordered-list + %ul.unstyled-list - has_any_ci = @merge_requests.any?(&:ci_commit) - @merge_requests.each do |merge_request| %li @@ -24,5 +24,5 @@ MERGED - elsif merge_request.closed? CLOSED - - if @closed_by_merge_requests.present? - = render 'projects/issues/closed_by_box' + - if @closed_by_merge_requests.present? + = render partial: 'projects/issues/closed_by_box', locals: {merge_request_count: @merge_requests.count} -- cgit v1.2.1 From e74e03fa66d9cfc05ab70a5fef42bdb8f297ed1b Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Tue, 12 Jan 2016 20:51:13 -0500 Subject: changes `$quote-gray` to `$secondary-text` --- app/assets/stylesheets/framework/variables.scss | 2 +- app/assets/stylesheets/pages/issues.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 4c307d705e9..d0ff3248ce1 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -24,7 +24,7 @@ $gl-gray: #5a5a5a; $gl-padding: 16px; $gl-padding-top:10px; $gl-avatar-size: 46px; -$quote-gray: #7f8fa4; +$secondary-text: #7f8fa4; /* * Color schema diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index 30dfc0b3904..1e1af662850 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -146,6 +146,6 @@ form.edit-issue { } .issue-closed-by-widget { - color: $quote-gray; + color: $secondary-text; margin-left: 52px; } \ No newline at end of file -- cgit v1.2.1 From da40274fdc60fe17f928b80eb71c211e27523d5e Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 12 Jan 2016 20:48:16 -0500 Subject: Block the reported user before destroying the record This is intended to prevent the user from creating new objects while the transaction that removes them is being run, resulting in objects with nil authors which can then not be edited. See https://gitlab.com/gitlab-org/gitlab-ce/issues/7117 --- app/controllers/admin/abuse_reports_controller.rb | 6 ++---- app/models/abuse_report.rb | 5 +++++ spec/models/abuse_report_spec.rb | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/app/controllers/admin/abuse_reports_controller.rb b/app/controllers/admin/abuse_reports_controller.rb index 38a5a9fca08..2463cfa87be 100644 --- a/app/controllers/admin/abuse_reports_controller.rb +++ b/app/controllers/admin/abuse_reports_controller.rb @@ -6,11 +6,9 @@ class Admin::AbuseReportsController < Admin::ApplicationController def destroy abuse_report = AbuseReport.find(params[:id]) - if params[:remove_user] - abuse_report.user.destroy - end - + abuse_report.remove_user if params[:remove_user] abuse_report.destroy + render nothing: true end end diff --git a/app/models/abuse_report.rb b/app/models/abuse_report.rb index 55864236b2f..2bc15c60d57 100644 --- a/app/models/abuse_report.rb +++ b/app/models/abuse_report.rb @@ -19,6 +19,11 @@ class AbuseReport < ActiveRecord::Base validates :message, presence: true validates :user_id, uniqueness: true + def remove_user + user.block + user.destroy + end + def notify return unless self.persisted? diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb index 46cab1644c7..f9be8fcbcfe 100644 --- a/spec/models/abuse_report_spec.rb +++ b/spec/models/abuse_report_spec.rb @@ -29,6 +29,22 @@ RSpec.describe AbuseReport, type: :model do it { is_expected.to validate_uniqueness_of(:user_id) } end + describe '#remove_user' do + it 'blocks the user' do + report = build(:abuse_report) + + allow(report.user).to receive(:destroy) + + expect { report.remove_user }.to change { report.user.blocked? }.to(true) + end + + it 'removes the user' do + report = build(:abuse_report) + + expect { report.remove_user }.to change { User.count }.by(-1) + end + end + describe '#notify' do it 'delivers' do expect(AbuseReportMailer).to receive(:notify).with(subject.id). -- cgit v1.2.1 From a43fd5ce6d369c35b3ea421f045721d20f1c8ada Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 12 Jan 2016 21:34:23 -0500 Subject: Disable colorization if STDOUT is not a tty --- lib/tasks/gitlab/task_helpers.rake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/tasks/gitlab/task_helpers.rake b/lib/tasks/gitlab/task_helpers.rake index ebe516ec879..8c63877e51c 100644 --- a/lib/tasks/gitlab/task_helpers.rake +++ b/lib/tasks/gitlab/task_helpers.rake @@ -2,6 +2,8 @@ module Gitlab class TaskAbortedByUserError < StandardError; end end +String.disable_colorization = true unless STDOUT.isatty + namespace :gitlab do # Ask if the user wants to continue -- cgit v1.2.1 From 6d68ba287092428b49c9c9caa7b2cae03b7658b2 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 12 Jan 2016 21:34:47 -0500 Subject: Don't automatically require awesome_print It patches core classes (such as String) to add colorization methods like `red` which we can't disable the same way we can with the Colorization gem. --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 9a5253924ea..a9a8bed1064 100644 --- a/Gemfile +++ b/Gemfile @@ -247,7 +247,7 @@ group :development, :test do gem 'byebug', platform: :mri gem 'pry-rails' - gem 'awesome_print', '~> 1.2.0' + gem 'awesome_print', '~> 1.2.0', require: false gem 'fuubar', '~> 2.0.0' gem 'database_cleaner', '~> 1.4.0' -- cgit v1.2.1 From 9d7f88c12258e27a189e8229090920db0627e88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 12 Jan 2016 18:10:06 +0100 Subject: Show referenced MRs & Issues only when the current viewer can access them --- CHANGELOG | 1 + app/controllers/projects/issues_controller.rb | 2 +- app/models/issue.rb | 4 +- app/views/projects/notes/_notes.html.haml | 1 + features/project/issues/references.feature | 31 ++++++++ features/steps/project/issues/references.rb | 106 ++++++++++++++++++++++++++ features/steps/shared/note.rb | 6 ++ features/steps/shared/project.rb | 7 ++ 8 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 features/project/issues/references.feature create mode 100644 features/steps/project/issues/references.rb diff --git a/CHANGELOG b/CHANGELOG index ab34661ce05..f765899b42d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -38,6 +38,7 @@ v 8.4.0 (unreleased) - Ajax filter by message for commits page - API: Add support for deleting a tag via the API (Robert Schilling) - Allow subsequent validations in CI Linter + - Show referenced MRs & Issues only when the current viewer can access them v 8.3.3 - Preserve CE behavior with JIRA integration by only calling API if URL is set diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index b59b52291fb..f476afb2d92 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -61,7 +61,7 @@ class Projects::IssuesController < Projects::ApplicationController @note = @project.notes.new(noteable: @issue) @notes = @issue.notes.nonawards.with_associations.fresh @noteable = @issue - @merge_requests = @issue.referenced_merge_requests + @merge_requests = @issue.referenced_merge_requests(current_user) respond_with(@issue) end diff --git a/app/models/issue.rb b/app/models/issue.rb index f52e47f3e62..7beba984608 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -85,10 +85,10 @@ class Issue < ActiveRecord::Base reference end - def referenced_merge_requests + def referenced_merge_requests(current_user = nil) Gitlab::ReferenceExtractor.lazily do [self, *notes].flat_map do |note| - note.all_references.merge_requests + note.all_references(current_user).merge_requests end end.sort_by(&:iid) end diff --git a/app/views/projects/notes/_notes.html.haml b/app/views/projects/notes/_notes.html.haml index ca60dd239b2..a4ff947c656 100644 --- a/app/views/projects/notes/_notes.html.haml +++ b/app/views/projects/notes/_notes.html.haml @@ -8,4 +8,5 @@ - else - @notes.each do |note| - next unless note.author + - next if note.cross_reference? && note.referenced_mentionables(current_user).empty? = render note diff --git a/features/project/issues/references.feature b/features/project/issues/references.feature new file mode 100644 index 00000000000..bf7a4c6cb91 --- /dev/null +++ b/features/project/issues/references.feature @@ -0,0 +1,31 @@ +@project_issues +Feature: Project Issues References + Background: + Given I sign in as "John Doe" + And "John Doe" owns public project "Community" + And project "Community" has "Public Issue 01" open issue + And I logout + And I sign in as "Mary Jane" + And "Mary Jane" owns private project "Private Library" + And project "Private Library" has "Fix NS-01" open merge request + And project "Private Library" has "Private Issue 01" open issue + And I visit merge request page "Fix NS-01" + And I leave a comment referencing issue "Public Issue 01" from "Fix NS-01" merge request + And I visit issue page "Private Issue 01" + And I leave a comment referencing issue "Public Issue 01" from "Private Issue 01" issue + And I logout + + @javascript + Scenario: Viewing the public issue as a "John Doe" + Given I sign in as "John Doe" + When I visit issue page "Public Issue 01" + Then I should not see any related merge requests + And I should see no notes at all + + @javascript + Scenario: Viewing the public issue as "Mary Jane" + Given I sign in as "Mary Jane" + When I visit issue page "Public Issue 01" + Then I should see the "Fix NS-01" related merge request + And I should see a note linking to "Fix NS-01" merge request + And I should see a note linking to "Private Issue 01" issue diff --git a/features/steps/project/issues/references.rb b/features/steps/project/issues/references.rb new file mode 100644 index 00000000000..9c7725e8c14 --- /dev/null +++ b/features/steps/project/issues/references.rb @@ -0,0 +1,106 @@ +class Spinach::Features::ProjectIssuesReferences < Spinach::FeatureSteps + include SharedAuthentication + include SharedNote + include SharedProject + include SharedUser + + step 'project "Community" has "Public Issue 01" open issue' do + project = Project.find_by(name: 'Community') + create(:issue, + title: 'Public Issue 01', + project: project, + author: project.users.first, + description: '# Description header' + ) + end + + step 'project "Private Library" has "Fix NS-01" open merge request' do + project = Project.find_by(name: 'Private Library') + create(:merge_request, + title: 'Fix NS-01', + source_project: project, + target_project: project, + source_branch: 'fix', + target_branch: 'master', + author: project.users.first, + description: '# Description header' + ) + end + + step 'project "Private Library" has "Private Issue 01" open issue' do + project = Project.find_by(name: 'Private Library') + create(:issue, + title: 'Private Issue 01', + project: project, + author: project.users.first, + description: '# Description header' + ) + end + + step 'I leave a comment referencing issue "Public Issue 01" from "Fix NS-01" merge request' do + project = Project.find_by(name: 'Private Library') + issue = Issue.find_by!(title: 'Public Issue 01') + + page.within(".js-main-target-form") do + fill_in "note[note]", with: "##{issue.to_reference(project)}" + click_button "Add Comment" + end + end + + step 'I leave a comment referencing issue "Public Issue 01" from "Private Issue 01" issue' do + project = Project.find_by(name: 'Private Library') + issue = Issue.find_by!(title: 'Public Issue 01') + + page.within(".js-main-target-form") do + fill_in "note[note]", with: "##{issue.to_reference(project)}" + click_button "Add Comment" + end + end + + step 'I visit merge request page "Fix NS-01"' do + mr = MergeRequest.find_by(title: "Fix NS-01") + visit namespace_project_merge_request_path(mr.target_project.namespace, mr.target_project, mr) + end + + step 'I visit issue page "Private Issue 01"' do + issue = Issue.find_by(title: "Private Issue 01") + visit namespace_project_issue_path(issue.project.namespace, issue.project, issue) + end + + step 'I visit issue page "Public Issue 01"' do + issue = Issue.find_by(title: "Public Issue 01") + visit namespace_project_issue_path(issue.project.namespace, issue.project, issue) + end + + step 'I should not see any related merge requests' do + page.within '.issue-details' do + expect(page).not_to have_content('.merge-requests') + end + end + + step 'I should see the "Fix NS-01" related merge request' do + page.within '.merge-requests' do + expect(page).to have_content("1 Related Merge Request") + expect(page).to have_content('Fix NS-01') + end + end + + step 'I should see a note linking to "Fix NS-01" merge request' do + project = Project.find_by(name: 'Community') + mr = MergeRequest.find_by(title: 'Fix NS-01') + page.within('.notes') do + expect(page).to have_content('Mary Jane') + expect(page).to have_content("mentioned in merge request #{mr.to_reference(project)}") + end + end + + step 'I should see a note linking to "Private Issue 01" issue' do + project = Project.find_by(name: 'Community') + issue = Issue.find_by(title: 'Private Issue 01') + page.within('.notes') do + expect(page).to have_content('Mary Jane') + expect(page).to have_content("mentioned in issue #{issue.to_reference(project)}") + end + end + +end diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb index f6aabfefeff..6de58c6e2b1 100644 --- a/features/steps/shared/note.rb +++ b/features/steps/shared/note.rb @@ -106,6 +106,12 @@ module SharedNote end end + step 'I should see no notes at all' do + page.within('.notes') do + expect(page).to_not have_css('.note') + end + end + # Markdown step 'I leave a comment with a header containing "Comment with a header"' do diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb index da643bf3ba9..43a15f43470 100644 --- a/features/steps/shared/project.rb +++ b/features/steps/shared/project.rb @@ -181,6 +181,13 @@ module SharedProject project.team << [user, :master] end + step '"Mary Jane" owns private project "Private Library"' do + user = user_exists('Mary Jane', username: 'mary_jane') + project = Project.find_by(name: 'Private Library') + project ||= create(:project, name: 'Private Library', namespace: user.namespace) + project.team << [user, :master] + end + step 'public empty project "Empty Public Project"' do create :project_empty_repo, :public, name: "Empty Public Project" end -- cgit v1.2.1 From d44653da1f74c2c15fe7ec3f8aa9b16563ffebd6 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Wed, 13 Jan 2016 12:16:27 +0100 Subject: Add some fixes after review --- app/models/ci/trigger.rb | 4 ++++ lib/api/entities.rb | 8 +------- lib/api/triggers.rb | 11 +++++------ spec/requests/api/triggers_spec.rb | 12 ++++++------ 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/app/models/ci/trigger.rb b/app/models/ci/trigger.rb index 23516709a41..3328459c4c5 100644 --- a/app/models/ci/trigger.rb +++ b/app/models/ci/trigger.rb @@ -32,6 +32,10 @@ module Ci trigger_requests.last end + def last_used + last_trigger_request.try(:created_at) + end + def short_token token[0...10] end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 37c483b45ec..1108277aabf 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -367,13 +367,7 @@ module API end class Trigger < Grape::Entity - expose :token, :created_at, :updated_at, :deleted_at - expose :last_used do |repo_obj, _options| - if repo_obj.respond_to?(:last_trigger_request) - request = repo_obj.last_trigger_request - request.created_at if request - end - end + expose :token, :created_at, :updated_at, :deleted_at, :last_used end end end diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb index 25bb8aef20b..5e4964f446c 100644 --- a/lib/api/triggers.rb +++ b/lib/api/triggers.rb @@ -73,10 +73,10 @@ module API authenticate! authorize_admin_project - triggers = user_project.triggers.where(token: params[:token]) - return not_found!('Trigger') if triggers.empty? + trigger = user_project.triggers.find_by(token: params[:token].to_s) + return not_found!('Trigger') unless trigger - present triggers.first, with: Entities::Trigger + present trigger, with: Entities::Trigger end # Create trigger @@ -89,8 +89,7 @@ module API authenticate! authorize_admin_project - trigger = user_project.triggers.new - trigger.save + trigger = user_project.triggers.create present trigger, with: Entities::Trigger end @@ -106,7 +105,7 @@ module API authenticate! authorize_admin_project - trigger = user_project.triggers.where(token: params[:token]).first + trigger = user_project.triggers.find_by(token: params[:token].to_s) return not_found!('Trigger') unless trigger trigger.destroy diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index e8d89426ec0..2a86b60bc4d 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -105,7 +105,7 @@ describe API::API do end end - context 'unauthentikated user' do + context 'unauthenticated user' do it 'should not return triggers list' do get api("/projects/#{project.id}/triggers") @@ -123,7 +123,7 @@ describe API::API do expect(json_response).to be_a(Hash) end - it 'should responde with 404 Not Found if requesting non-existing trigger' do + it 'should respond with 404 Not Found if requesting non-existing trigger' do get api("/projects/#{project.id}/triggers/abcdef012345", user) expect(response.status).to eq(404) @@ -138,7 +138,7 @@ describe API::API do end end - context 'unauthentikated user' do + context 'unauthenticated user' do it 'should not return triggers list' do get api("/projects/#{project.id}/triggers/#{trigger.token}") @@ -167,7 +167,7 @@ describe API::API do end end - context 'unauthentikated user' do + context 'unauthenticated user' do it 'should not create trigger' do post api("/projects/#{project.id}/triggers") @@ -185,7 +185,7 @@ describe API::API do expect(response.status).to eq(200) end - it 'should responde with 404 Not Found if requesting non-existing trigger' do + it 'should respond with 404 Not Found if requesting non-existing trigger' do delete api("/projects/#{project.id}/triggers/abcdef012345", user) expect(response.status).to eq(404) @@ -200,7 +200,7 @@ describe API::API do end end - context 'unauthentikated user' do + context 'unauthenticated user' do it 'should not delete trigger' do delete api("/projects/#{project.id}/triggers/#{trigger.token}") -- cgit v1.2.1 From 23671600150cb022a09a77b8ea56a9465f19a013 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 13 Jan 2016 12:29:48 +0100 Subject: Make the metrics sampler interval configurable --- .../admin/application_settings_controller.rb | 1 + .../admin/application_settings/_form.html.haml | 7 + .../20160113111034_add_metrics_sample_interval.rb | 6 + db/schema.rb | 508 +++++++++++---------- lib/gitlab/metrics.rb | 3 +- lib/gitlab/metrics/sampler.rb | 2 +- 6 files changed, 272 insertions(+), 255 deletions(-) create mode 100644 db/migrate/20160113111034_add_metrics_sample_interval.rb diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 44d06b6a647..91f7d78bd73 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -73,6 +73,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :metrics_pool_size, :metrics_timeout, :metrics_method_call_threshold, + :metrics_sample_interval, :recaptcha_enabled, :recaptcha_site_key, :recaptcha_private_key, diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 81337432ab7..83f6814d822 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -202,6 +202,13 @@ .help-block A method call is only tracked when it takes longer to complete than the given amount of milliseconds. + .form-group + = f.label :metrics_sample_interval, 'Sampler Interval (sec)', class: 'control-label col-sm-2' + .col-sm-10 + = f.number_field :metrics_sample_interval, class: 'form-control' + .help-block + The sampling interval in seconds. Sampled data includes memory usage, + retained Ruby objects, file descriptors and so on. %fieldset %legend Spam and Anti-bot Protection diff --git a/db/migrate/20160113111034_add_metrics_sample_interval.rb b/db/migrate/20160113111034_add_metrics_sample_interval.rb new file mode 100644 index 00000000000..b741f5d2c75 --- /dev/null +++ b/db/migrate/20160113111034_add_metrics_sample_interval.rb @@ -0,0 +1,6 @@ +class AddMetricsSampleInterval < ActiveRecord::Migration + def change + add_column :application_settings, :metrics_sample_interval, :integer, + default: 15 + end +end diff --git a/db/schema.rb b/db/schema.rb index 2ded8a45e18..ecbe575bf83 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160106164438) do +ActiveRecord::Schema.define(version: 20160113111034) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -32,23 +32,23 @@ ActiveRecord::Schema.define(version: 20160106164438) do t.text "sign_in_text" t.datetime "created_at" t.datetime "updated_at" - t.string "home_page_url", limit: 255 - t.integer "default_branch_protection", default: 2 - t.boolean "twitter_sharing_enabled", default: true + t.string "home_page_url" + t.integer "default_branch_protection", default: 2 + t.boolean "twitter_sharing_enabled", default: true t.text "restricted_visibility_levels" - t.boolean "version_check_enabled", default: true - t.integer "max_attachment_size", default: 10, null: false + t.boolean "version_check_enabled", default: true + t.integer "max_attachment_size", default: 10, null: false t.integer "default_project_visibility" t.integer "default_snippet_visibility" t.text "restricted_signup_domains" - t.boolean "user_oauth_applications", default: true - t.string "after_sign_out_path", limit: 255 - t.integer "session_expire_delay", default: 10080, null: false + t.boolean "user_oauth_applications", default: true + t.string "after_sign_out_path" + t.integer "session_expire_delay", default: 10080, null: false t.text "import_sources" t.text "help_page_text" - t.string "admin_notification_email", limit: 255 - t.boolean "shared_runners_enabled", default: true, null: false - t.integer "max_artifacts_size", default: 100, null: false + t.string "admin_notification_email" + t.boolean "shared_runners_enabled", default: true, null: false + t.integer "max_artifacts_size", default: 100, null: false t.string "runners_registration_token" t.boolean "require_two_factor_authentication", default: false t.integer "two_factor_grace_period", default: 48 @@ -60,14 +60,15 @@ ActiveRecord::Schema.define(version: 20160106164438) do t.boolean "recaptcha_enabled", default: false t.string "recaptcha_site_key" t.string "recaptcha_private_key" - t.integer "metrics_port", default: 8089 + t.integer "metrics_port", default: 8089 + t.integer "metrics_sample_interval", default: 15 end create_table "audit_events", force: :cascade do |t| - t.integer "author_id", null: false - t.string "type", limit: 255, null: false - t.integer "entity_id", null: false - t.string "entity_type", limit: 255, null: false + t.integer "author_id", null: false + t.string "type", null: false + t.integer "entity_id", null: false + t.string "entity_type", null: false t.text "details" t.datetime "created_at" t.datetime "updated_at" @@ -78,14 +79,14 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "audit_events", ["type"], name: "index_audit_events_on_type", using: :btree create_table "broadcast_messages", force: :cascade do |t| - t.text "message", null: false + t.text "message", null: false t.datetime "starts_at" t.datetime "ends_at" t.integer "alert_type" t.datetime "created_at" t.datetime "updated_at" - t.string "color", limit: 255 - t.string "font", limit: 255 + t.string "color" + t.string "font" end create_table "ci_application_settings", force: :cascade do |t| @@ -97,7 +98,7 @@ ActiveRecord::Schema.define(version: 20160106164438) do create_table "ci_builds", force: :cascade do |t| t.integer "project_id" - t.string "status", limit: 255 + t.string "status" t.datetime "finished_at" t.text "trace" t.datetime "created_at" @@ -108,19 +109,19 @@ ActiveRecord::Schema.define(version: 20160106164438) do t.integer "commit_id" t.text "commands" t.integer "job_id" - t.string "name", limit: 255 - t.boolean "deploy", default: false + t.string "name" + t.boolean "deploy", default: false t.text "options" - t.boolean "allow_failure", default: false, null: false - t.string "stage", limit: 255 + t.boolean "allow_failure", default: false, null: false + t.string "stage" t.integer "trigger_request_id" t.integer "stage_idx" t.boolean "tag" - t.string "ref", limit: 255 + t.string "ref" t.integer "user_id" - t.string "type", limit: 255 - t.string "target_url", limit: 255 - t.string "description", limit: 255 + t.string "type" + t.string "target_url" + t.string "description" t.text "artifacts_file" t.integer "gl_project_id" end @@ -139,13 +140,13 @@ ActiveRecord::Schema.define(version: 20160106164438) do create_table "ci_commits", force: :cascade do |t| t.integer "project_id" - t.string "ref", limit: 255 - t.string "sha", limit: 255 - t.string "before_sha", limit: 255 + t.string "ref" + t.string "sha" + t.string "before_sha" t.text "push_data" t.datetime "created_at" t.datetime "updated_at" - t.boolean "tag", default: false + t.boolean "tag", default: false t.text "yaml_errors" t.datetime "committed_at" t.integer "gl_project_id" @@ -172,16 +173,16 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "ci_events", ["project_id"], name: "index_ci_events_on_project_id", using: :btree create_table "ci_jobs", force: :cascade do |t| - t.integer "project_id", null: false + t.integer "project_id", null: false t.text "commands" - t.boolean "active", default: true, null: false + t.boolean "active", default: true, null: false t.datetime "created_at" t.datetime "updated_at" - t.string "name", limit: 255 - t.boolean "build_branches", default: true, null: false - t.boolean "build_tags", default: false, null: false - t.string "job_type", limit: 255, default: "parallel" - t.string "refs", limit: 255 + t.string "name" + t.boolean "build_branches", default: true, null: false + t.boolean "build_tags", default: false, null: false + t.string "job_type", default: "parallel" + t.string "refs" t.datetime "deleted_at" end @@ -189,25 +190,25 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "ci_jobs", ["project_id"], name: "index_ci_jobs_on_project_id", using: :btree create_table "ci_projects", force: :cascade do |t| - t.string "name", limit: 255 - t.integer "timeout", default: 3600, null: false + t.string "name" + t.integer "timeout", default: 3600, null: false t.datetime "created_at" t.datetime "updated_at" - t.string "token", limit: 255 - t.string "default_ref", limit: 255 - t.string "path", limit: 255 - t.boolean "always_build", default: false, null: false + t.string "token" + t.string "default_ref" + t.string "path" + t.boolean "always_build", default: false, null: false t.integer "polling_interval" - t.boolean "public", default: false, null: false - t.string "ssh_url_to_repo", limit: 255 + t.boolean "public", default: false, null: false + t.string "ssh_url_to_repo" t.integer "gitlab_id" - t.boolean "allow_git_fetch", default: true, null: false - t.string "email_recipients", limit: 255, default: "", null: false - t.boolean "email_add_pusher", default: true, null: false - t.boolean "email_only_broken_builds", default: true, null: false - t.string "skip_refs", limit: 255 - t.string "coverage_regex", limit: 255 - t.boolean "shared_runners_enabled", default: false + t.boolean "allow_git_fetch", default: true, null: false + t.string "email_recipients", default: "", null: false + t.boolean "email_add_pusher", default: true, null: false + t.boolean "email_only_broken_builds", default: true, null: false + t.string "skip_refs" + t.string "coverage_regex" + t.boolean "shared_runners_enabled", default: false t.text "generated_yaml_config" end @@ -226,34 +227,34 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "ci_runner_projects", ["runner_id"], name: "index_ci_runner_projects_on_runner_id", using: :btree create_table "ci_runners", force: :cascade do |t| - t.string "token", limit: 255 + t.string "token" t.datetime "created_at" t.datetime "updated_at" - t.string "description", limit: 255 + t.string "description" t.datetime "contacted_at" - t.boolean "active", default: true, null: false - t.boolean "is_shared", default: false - t.string "name", limit: 255 - t.string "version", limit: 255 - t.string "revision", limit: 255 - t.string "platform", limit: 255 - t.string "architecture", limit: 255 + t.boolean "active", default: true, null: false + t.boolean "is_shared", default: false + t.string "name" + t.string "version" + t.string "revision" + t.string "platform" + t.string "architecture" end create_table "ci_services", force: :cascade do |t| - t.string "type", limit: 255 - t.string "title", limit: 255 - t.integer "project_id", null: false + t.string "type" + t.string "title" + t.integer "project_id", null: false t.datetime "created_at" t.datetime "updated_at" - t.boolean "active", default: false, null: false + t.boolean "active", default: false, null: false t.text "properties" end add_index "ci_services", ["project_id"], name: "index_ci_services_on_project_id", using: :btree create_table "ci_sessions", force: :cascade do |t| - t.string "session_id", limit: 255, null: false + t.string "session_id", null: false t.text "data" t.datetime "created_at" t.datetime "updated_at" @@ -265,9 +266,9 @@ ActiveRecord::Schema.define(version: 20160106164438) do create_table "ci_taggings", force: :cascade do |t| t.integer "tag_id" t.integer "taggable_id" - t.string "taggable_type", limit: 255 + t.string "taggable_type" t.integer "tagger_id" - t.string "tagger_type", limit: 255 + t.string "tagger_type" t.string "context", limit: 128 t.datetime "created_at" end @@ -276,8 +277,8 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "ci_taggings", ["taggable_id", "taggable_type", "context"], name: "index_ci_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree create_table "ci_tags", force: :cascade do |t| - t.string "name", limit: 255 - t.integer "taggings_count", default: 0 + t.string "name" + t.integer "taggings_count", default: 0 end add_index "ci_tags", ["name"], name: "index_ci_tags_on_name", unique: true, using: :btree @@ -291,7 +292,7 @@ ActiveRecord::Schema.define(version: 20160106164438) do end create_table "ci_triggers", force: :cascade do |t| - t.string "token", limit: 255 + t.string "token" t.integer "project_id" t.datetime "deleted_at" t.datetime "created_at" @@ -304,19 +305,19 @@ ActiveRecord::Schema.define(version: 20160106164438) do create_table "ci_variables", force: :cascade do |t| t.integer "project_id" - t.string "key", limit: 255 + t.string "key" t.text "value" t.text "encrypted_value" - t.string "encrypted_value_salt", limit: 255 - t.string "encrypted_value_iv", limit: 255 + t.string "encrypted_value_salt" + t.string "encrypted_value_iv" t.integer "gl_project_id" end add_index "ci_variables", ["gl_project_id"], name: "index_ci_variables_on_gl_project_id", using: :btree create_table "ci_web_hooks", force: :cascade do |t| - t.string "url", limit: 255, null: false - t.integer "project_id", null: false + t.string "url", null: false + t.integer "project_id", null: false t.datetime "created_at" t.datetime "updated_at" end @@ -331,8 +332,8 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "deploy_keys_projects", ["project_id"], name: "index_deploy_keys_projects_on_project_id", using: :btree create_table "emails", force: :cascade do |t| - t.integer "user_id", null: false - t.string "email", limit: 255, null: false + t.integer "user_id", null: false + t.string "email", null: false t.datetime "created_at" t.datetime "updated_at" end @@ -341,9 +342,9 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "emails", ["user_id"], name: "index_emails_on_user_id", using: :btree create_table "events", force: :cascade do |t| - t.string "target_type", limit: 255 + t.string "target_type" t.integer "target_id" - t.string "title", limit: 255 + t.string "title" t.text "data" t.integer "project_id" t.datetime "created_at" @@ -369,8 +370,8 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "forked_project_links", ["forked_to_project_id"], name: "index_forked_project_links_on_forked_to_project_id", unique: true, using: :btree create_table "identities", force: :cascade do |t| - t.string "extern_uid", limit: 255 - t.string "provider", limit: 255 + t.string "extern_uid" + t.string "provider" t.integer "user_id" t.datetime "created_at" t.datetime "updated_at" @@ -380,17 +381,17 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "identities", ["user_id"], name: "index_identities_on_user_id", using: :btree create_table "issues", force: :cascade do |t| - t.string "title", limit: 255 + t.string "title" t.integer "assignee_id" t.integer "author_id" t.integer "project_id" t.datetime "created_at" t.datetime "updated_at" - t.integer "position", default: 0 - t.string "branch_name", limit: 255 + t.integer "position", default: 0 + t.string "branch_name" t.text "description" t.integer "milestone_id" - t.string "state", limit: 255 + t.string "state" t.integer "iid" t.integer "updated_by_id" end @@ -410,10 +411,10 @@ ActiveRecord::Schema.define(version: 20160106164438) do t.datetime "created_at" t.datetime "updated_at" t.text "key" - t.string "title", limit: 255 - t.string "type", limit: 255 - t.string "fingerprint", limit: 255 - t.boolean "public", default: false, null: false + t.string "title" + t.string "type" + t.string "fingerprint" + t.boolean "public", default: false, null: false end add_index "keys", ["created_at", "id"], name: "index_keys_on_created_at_and_id", using: :btree @@ -422,7 +423,7 @@ ActiveRecord::Schema.define(version: 20160106164438) do create_table "label_links", force: :cascade do |t| t.integer "label_id" t.integer "target_id" - t.string "target_type", limit: 255 + t.string "target_type" t.datetime "created_at" t.datetime "updated_at" end @@ -431,22 +432,22 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "label_links", ["target_id", "target_type"], name: "index_label_links_on_target_id_and_target_type", using: :btree create_table "labels", force: :cascade do |t| - t.string "title", limit: 255 - t.string "color", limit: 255 + t.string "title" + t.string "color" t.integer "project_id" t.datetime "created_at" t.datetime "updated_at" - t.boolean "template", default: false + t.boolean "template", default: false end add_index "labels", ["project_id"], name: "index_labels_on_project_id", using: :btree create_table "lfs_objects", force: :cascade do |t| - t.string "oid", limit: 255, null: false - t.integer "size", null: false + t.string "oid", null: false + t.integer "size", null: false t.datetime "created_at" t.datetime "updated_at" - t.string "file", limit: 255 + t.string "file" end add_index "lfs_objects", ["oid"], name: "index_lfs_objects_on_oid", unique: true, using: :btree @@ -461,17 +462,17 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "lfs_objects_projects", ["project_id"], name: "index_lfs_objects_projects_on_project_id", using: :btree create_table "members", force: :cascade do |t| - t.integer "access_level", null: false - t.integer "source_id", null: false - t.string "source_type", limit: 255, null: false + t.integer "access_level", null: false + t.integer "source_id", null: false + t.string "source_type", null: false t.integer "user_id" - t.integer "notification_level", null: false - t.string "type", limit: 255 + t.integer "notification_level", null: false + t.string "type" t.datetime "created_at" t.datetime "updated_at" t.integer "created_by_id" - t.string "invite_email", limit: 255 - t.string "invite_token", limit: 255 + t.string "invite_email" + t.string "invite_token" t.datetime "invite_accepted_at" end @@ -483,10 +484,10 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "members", ["user_id"], name: "index_members_on_user_id", using: :btree create_table "merge_request_diffs", force: :cascade do |t| - t.string "state", limit: 255 + t.string "state" t.text "st_commits" t.text "st_diffs" - t.integer "merge_request_id", null: false + t.integer "merge_request_id", null: false t.datetime "created_at" t.datetime "updated_at" end @@ -494,26 +495,26 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "merge_request_diffs", ["merge_request_id"], name: "index_merge_request_diffs_on_merge_request_id", unique: true, using: :btree create_table "merge_requests", force: :cascade do |t| - t.string "target_branch", limit: 255, null: false - t.string "source_branch", limit: 255, null: false - t.integer "source_project_id", null: false + t.string "target_branch", null: false + t.string "source_branch", null: false + t.integer "source_project_id", null: false t.integer "author_id" t.integer "assignee_id" - t.string "title", limit: 255 + t.string "title" t.datetime "created_at" t.datetime "updated_at" t.integer "milestone_id" - t.string "state", limit: 255 - t.string "merge_status", limit: 255 - t.integer "target_project_id", null: false + t.string "state" + t.string "merge_status" + t.integer "target_project_id", null: false t.integer "iid" t.text "description" - t.integer "position", default: 0 + t.integer "position", default: 0 t.datetime "locked_at" t.integer "updated_by_id" - t.string "merge_error", limit: 255 + t.string "merge_error" t.text "merge_params" - t.boolean "merge_when_build_succeeds", default: false, null: false + t.boolean "merge_when_build_succeeds", default: false, null: false t.integer "merge_user_id" end @@ -529,13 +530,13 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "merge_requests", ["title"], name: "index_merge_requests_on_title", using: :btree create_table "milestones", force: :cascade do |t| - t.string "title", limit: 255, null: false - t.integer "project_id", null: false + t.string "title", null: false + t.integer "project_id", null: false t.text "description" t.date "due_date" t.datetime "created_at" t.datetime "updated_at" - t.string "state", limit: 255 + t.string "state" t.integer "iid" end @@ -543,16 +544,17 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "milestones", ["due_date"], name: "index_milestones_on_due_date", using: :btree add_index "milestones", ["project_id", "iid"], name: "index_milestones_on_project_id_and_iid", unique: true, using: :btree add_index "milestones", ["project_id"], name: "index_milestones_on_project_id", using: :btree + add_index "milestones", ["title"], name: "index_milestones_on_title", using: :btree create_table "namespaces", force: :cascade do |t| - t.string "name", limit: 255, null: false - t.string "path", limit: 255, null: false + t.string "name", null: false + t.string "path", null: false t.integer "owner_id" t.datetime "created_at" t.datetime "updated_at" - t.string "type", limit: 255 - t.string "description", limit: 255, default: "", null: false - t.string "avatar", limit: 255 + t.string "type" + t.string "description", default: "", null: false + t.string "avatar" end add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree @@ -563,19 +565,19 @@ ActiveRecord::Schema.define(version: 20160106164438) do create_table "notes", force: :cascade do |t| t.text "note" - t.string "noteable_type", limit: 255 + t.string "noteable_type" t.integer "author_id" t.datetime "created_at" t.datetime "updated_at" t.integer "project_id" - t.string "attachment", limit: 255 - t.string "line_code", limit: 255 - t.string "commit_id", limit: 255 + t.string "attachment" + t.string "line_code" + t.string "commit_id" t.integer "noteable_id" - t.boolean "system", default: false, null: false + t.boolean "system", default: false, null: false t.text "st_diff" t.integer "updated_by_id" - t.boolean "is_award", default: false, null: false + t.boolean "is_award", default: false, null: false end add_index "notes", ["author_id"], name: "index_notes_on_author_id", using: :btree @@ -591,14 +593,14 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "notes", ["updated_at"], name: "index_notes_on_updated_at", using: :btree create_table "oauth_access_grants", force: :cascade do |t| - t.integer "resource_owner_id", null: false - t.integer "application_id", null: false - t.string "token", limit: 255, null: false - t.integer "expires_in", null: false - t.text "redirect_uri", null: false - t.datetime "created_at", null: false + t.integer "resource_owner_id", null: false + t.integer "application_id", null: false + t.string "token", null: false + t.integer "expires_in", null: false + t.text "redirect_uri", null: false + t.datetime "created_at", null: false t.datetime "revoked_at" - t.string "scopes", limit: 255 + t.string "scopes" end add_index "oauth_access_grants", ["token"], name: "index_oauth_access_grants_on_token", unique: true, using: :btree @@ -606,12 +608,12 @@ ActiveRecord::Schema.define(version: 20160106164438) do create_table "oauth_access_tokens", force: :cascade do |t| t.integer "resource_owner_id" t.integer "application_id" - t.string "token", limit: 255, null: false - t.string "refresh_token", limit: 255 + t.string "token", null: false + t.string "refresh_token" t.integer "expires_in" t.datetime "revoked_at" - t.datetime "created_at", null: false - t.string "scopes", limit: 255 + t.datetime "created_at", null: false + t.string "scopes" end add_index "oauth_access_tokens", ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true, using: :btree @@ -619,15 +621,15 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "oauth_access_tokens", ["token"], name: "index_oauth_access_tokens_on_token", unique: true, using: :btree create_table "oauth_applications", force: :cascade do |t| - t.string "name", limit: 255, null: false - t.string "uid", limit: 255, null: false - t.string "secret", limit: 255, null: false - t.text "redirect_uri", null: false - t.string "scopes", limit: 255, default: "", null: false + t.string "name", null: false + t.string "uid", null: false + t.string "secret", null: false + t.text "redirect_uri", null: false + t.string "scopes", default: "", null: false t.datetime "created_at" t.datetime "updated_at" t.integer "owner_id" - t.string "owner_type", limit: 255 + t.string "owner_type" end add_index "oauth_applications", ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type", using: :btree @@ -639,39 +641,39 @@ ActiveRecord::Schema.define(version: 20160106164438) do end create_table "projects", force: :cascade do |t| - t.string "name", limit: 255 - t.string "path", limit: 255 + t.string "name" + t.string "path" t.text "description" t.datetime "created_at" t.datetime "updated_at" t.integer "creator_id" - t.boolean "issues_enabled", default: true, null: false - t.boolean "wall_enabled", default: true, null: false - t.boolean "merge_requests_enabled", default: true, null: false - t.boolean "wiki_enabled", default: true, null: false + t.boolean "issues_enabled", default: true, null: false + t.boolean "wall_enabled", default: true, null: false + t.boolean "merge_requests_enabled", default: true, null: false + t.boolean "wiki_enabled", default: true, null: false t.integer "namespace_id" - t.string "issues_tracker", limit: 255, default: "gitlab", null: false - t.string "issues_tracker_id", limit: 255 - t.boolean "snippets_enabled", default: true, null: false + t.string "issues_tracker", default: "gitlab", null: false + t.string "issues_tracker_id" + t.boolean "snippets_enabled", default: true, null: false t.datetime "last_activity_at" - t.string "import_url", limit: 255 - t.integer "visibility_level", default: 0, null: false - t.boolean "archived", default: false, null: false - t.string "avatar", limit: 255 - t.string "import_status", limit: 255 - t.float "repository_size", default: 0.0 - t.integer "star_count", default: 0, null: false - t.string "import_type", limit: 255 - t.string "import_source", limit: 255 - t.integer "commit_count", default: 0 + t.string "import_url" + t.integer "visibility_level", default: 0, null: false + t.boolean "archived", default: false, null: false + t.string "avatar" + t.string "import_status" + t.float "repository_size", default: 0.0 + t.integer "star_count", default: 0, null: false + t.string "import_type" + t.string "import_source" + t.integer "commit_count", default: 0 t.text "import_error" t.integer "ci_id" - t.boolean "builds_enabled", default: true, null: false - t.boolean "shared_runners_enabled", default: true, null: false + t.boolean "builds_enabled", default: true, null: false + t.boolean "shared_runners_enabled", default: true, null: false t.string "runners_token" t.string "build_coverage_regex" - t.boolean "build_allow_git_fetch", default: true, null: false - t.integer "build_timeout", default: 3600, null: false + t.boolean "build_allow_git_fetch", default: true, null: false + t.integer "build_timeout", default: 3600, null: false end add_index "projects", ["builds_enabled", "shared_runners_enabled"], name: "index_projects_on_builds_enabled_and_shared_runners_enabled", using: :btree @@ -687,17 +689,17 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "projects", ["visibility_level"], name: "index_projects_on_visibility_level", using: :btree create_table "protected_branches", force: :cascade do |t| - t.integer "project_id", null: false - t.string "name", limit: 255, null: false + t.integer "project_id", null: false + t.string "name", null: false t.datetime "created_at" t.datetime "updated_at" - t.boolean "developers_can_push", default: false, null: false + t.boolean "developers_can_push", default: false, null: false end add_index "protected_branches", ["project_id"], name: "index_protected_branches_on_project_id", using: :btree create_table "releases", force: :cascade do |t| - t.string "tag", limit: 255 + t.string "tag" t.text "description" t.integer "project_id" t.datetime "created_at" @@ -710,30 +712,30 @@ ActiveRecord::Schema.define(version: 20160106164438) do create_table "sent_notifications", force: :cascade do |t| t.integer "project_id" t.integer "noteable_id" - t.string "noteable_type", limit: 255 + t.string "noteable_type" t.integer "recipient_id" - t.string "commit_id", limit: 255 - t.string "reply_key", limit: 255, null: false - t.string "line_code", limit: 255 + t.string "commit_id" + t.string "reply_key", null: false + t.string "line_code" end add_index "sent_notifications", ["reply_key"], name: "index_sent_notifications_on_reply_key", unique: true, using: :btree create_table "services", force: :cascade do |t| - t.string "type", limit: 255 - t.string "title", limit: 255 + t.string "type" + t.string "title" t.integer "project_id" t.datetime "created_at" t.datetime "updated_at" - t.boolean "active", default: false, null: false + t.boolean "active", default: false, null: false t.text "properties" - t.boolean "template", default: false - t.boolean "push_events", default: true - t.boolean "issues_events", default: true - t.boolean "merge_requests_events", default: true - t.boolean "tag_push_events", default: true - t.boolean "note_events", default: true, null: false - t.boolean "build_events", default: false, null: false + t.boolean "template", default: false + t.boolean "push_events", default: true + t.boolean "issues_events", default: true + t.boolean "merge_requests_events", default: true + t.boolean "tag_push_events", default: true + t.boolean "note_events", default: true, null: false + t.boolean "build_events", default: false, null: false end add_index "services", ["created_at", "id"], name: "index_services_on_created_at_and_id", using: :btree @@ -741,16 +743,16 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "services", ["template"], name: "index_services_on_template", using: :btree create_table "snippets", force: :cascade do |t| - t.string "title", limit: 255 + t.string "title" t.text "content" - t.integer "author_id", null: false + t.integer "author_id", null: false t.integer "project_id" t.datetime "created_at" t.datetime "updated_at" - t.string "file_name", limit: 255 + t.string "file_name" t.datetime "expires_at" - t.string "type", limit: 255 - t.integer "visibility_level", default: 0, null: false + t.string "type" + t.integer "visibility_level", default: 0, null: false end add_index "snippets", ["author_id"], name: "index_snippets_on_author_id", using: :btree @@ -763,7 +765,7 @@ ActiveRecord::Schema.define(version: 20160106164438) do create_table "subscriptions", force: :cascade do |t| t.integer "user_id" t.integer "subscribable_id" - t.string "subscribable_type", limit: 255 + t.string "subscribable_type" t.boolean "subscribed" t.datetime "created_at" t.datetime "updated_at" @@ -774,10 +776,10 @@ ActiveRecord::Schema.define(version: 20160106164438) do create_table "taggings", force: :cascade do |t| t.integer "tag_id" t.integer "taggable_id" - t.string "taggable_type", limit: 255 + t.string "taggable_type" t.integer "tagger_id" - t.string "tagger_type", limit: 255 - t.string "context", limit: 255 + t.string "tagger_type" + t.string "context" t.datetime "created_at" end @@ -785,67 +787,67 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree create_table "tags", force: :cascade do |t| - t.string "name", limit: 255 - t.integer "taggings_count", default: 0 + t.string "name" + t.integer "taggings_count", default: 0 end add_index "tags", ["name"], name: "index_tags_on_name", unique: true, using: :btree create_table "users", force: :cascade do |t| - t.string "email", limit: 255, default: "", null: false - t.string "encrypted_password", limit: 255, default: "", null: false - t.string "reset_password_token", limit: 255 + t.string "email", default: "", null: false + t.string "encrypted_password", default: "", null: false + t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" - t.integer "sign_in_count", default: 0 + t.integer "sign_in_count", default: 0 t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" - t.string "current_sign_in_ip", limit: 255 - t.string "last_sign_in_ip", limit: 255 - t.datetime "created_at" - t.datetime "updated_at" - t.string "name", limit: 255 - t.boolean "admin", default: false, null: false - t.integer "projects_limit", default: 10 - t.string "skype", limit: 255, default: "", null: false - t.string "linkedin", limit: 255, default: "", null: false - t.string "twitter", limit: 255, default: "", null: false - t.string "authentication_token", limit: 255 - t.integer "theme_id", default: 1, null: false - t.string "bio", limit: 255 - t.integer "failed_attempts", default: 0 + t.string "current_sign_in_ip" + t.string "last_sign_in_ip" + t.datetime "created_at" + t.datetime "updated_at" + t.string "name" + t.boolean "admin", default: false, null: false + t.integer "projects_limit", default: 10 + t.string "skype", default: "", null: false + t.string "linkedin", default: "", null: false + t.string "twitter", default: "", null: false + t.string "authentication_token" + t.integer "theme_id", default: 1, null: false + t.string "bio" + t.integer "failed_attempts", default: 0 t.datetime "locked_at" - t.string "username", limit: 255 - t.boolean "can_create_group", default: true, null: false - t.boolean "can_create_team", default: true, null: false - t.string "state", limit: 255 - t.integer "color_scheme_id", default: 1, null: false - t.integer "notification_level", default: 1, null: false + t.string "username" + t.boolean "can_create_group", default: true, null: false + t.boolean "can_create_team", default: true, null: false + t.string "state" + t.integer "color_scheme_id", default: 1, null: false + t.integer "notification_level", default: 1, null: false t.datetime "password_expires_at" t.integer "created_by_id" t.datetime "last_credential_check_at" - t.string "avatar", limit: 255 - t.string "confirmation_token", limit: 255 + t.string "avatar" + t.string "confirmation_token" t.datetime "confirmed_at" t.datetime "confirmation_sent_at" - t.string "unconfirmed_email", limit: 255 - t.boolean "hide_no_ssh_key", default: false - t.string "website_url", limit: 255, default: "", null: false - t.string "notification_email", limit: 255 - t.boolean "hide_no_password", default: false - t.boolean "password_automatically_set", default: false - t.string "location", limit: 255 - t.string "encrypted_otp_secret", limit: 255 - t.string "encrypted_otp_secret_iv", limit: 255 - t.string "encrypted_otp_secret_salt", limit: 255 - t.boolean "otp_required_for_login", default: false, null: false + t.string "unconfirmed_email" + t.boolean "hide_no_ssh_key", default: false + t.string "website_url", default: "", null: false + t.string "notification_email" + t.boolean "hide_no_password", default: false + t.boolean "password_automatically_set", default: false + t.string "location" + t.string "encrypted_otp_secret" + t.string "encrypted_otp_secret_iv" + t.string "encrypted_otp_secret_salt" + t.boolean "otp_required_for_login", default: false, null: false t.text "otp_backup_codes" - t.string "public_email", limit: 255, default: "", null: false - t.integer "dashboard", default: 0 - t.integer "project_view", default: 0 + t.string "public_email", default: "", null: false + t.integer "dashboard", default: 0 + t.integer "project_view", default: 0 t.integer "consumed_timestep" - t.integer "layout", default: 0 - t.boolean "hide_project_limit", default: false + t.integer "layout", default: 0 + t.boolean "hide_project_limit", default: false t.string "unlock_token" t.datetime "otp_grace_period_started_at" end @@ -872,19 +874,19 @@ ActiveRecord::Schema.define(version: 20160106164438) do add_index "users_star_projects", ["user_id"], name: "index_users_star_projects_on_user_id", using: :btree create_table "web_hooks", force: :cascade do |t| - t.string "url", limit: 255 + t.string "url" t.integer "project_id" t.datetime "created_at" t.datetime "updated_at" - t.string "type", limit: 255, default: "ProjectHook" + t.string "type", default: "ProjectHook" t.integer "service_id" - t.boolean "push_events", default: true, null: false - t.boolean "issues_events", default: false, null: false - t.boolean "merge_requests_events", default: false, null: false - t.boolean "tag_push_events", default: false - t.boolean "note_events", default: false, null: false - t.boolean "enable_ssl_verification", default: true - t.boolean "build_events", default: false, null: false + t.boolean "push_events", default: true, null: false + t.boolean "issues_events", default: false, null: false + t.boolean "merge_requests_events", default: false, null: false + t.boolean "tag_push_events", default: false + t.boolean "note_events", default: false, null: false + t.boolean "enable_ssl_verification", default: true + t.boolean "build_events", default: false, null: false end add_index "web_hooks", ["created_at", "id"], name: "index_web_hooks_on_created_at_and_id", using: :btree diff --git a/lib/gitlab/metrics.rb b/lib/gitlab/metrics.rb index cdf7c168ff2..88a265c6af2 100644 --- a/lib/gitlab/metrics.rb +++ b/lib/gitlab/metrics.rb @@ -13,7 +13,8 @@ module Gitlab timeout: current_application_settings[:metrics_timeout], method_call_threshold: current_application_settings[:metrics_method_call_threshold], host: current_application_settings[:metrics_host], - port: current_application_settings[:metrics_port] + port: current_application_settings[:metrics_port], + sample_interval: current_application_settings[:metrics_sample_interval] || 15 } end diff --git a/lib/gitlab/metrics/sampler.rb b/lib/gitlab/metrics/sampler.rb index 1ea425bc904..c2913841de3 100644 --- a/lib/gitlab/metrics/sampler.rb +++ b/lib/gitlab/metrics/sampler.rb @@ -7,7 +7,7 @@ module Gitlab # statistics, etc. class Sampler # interval - The sampling interval in seconds. - def initialize(interval = 15) + def initialize(interval = Metrics.settings[:sample_interval]) @interval = interval @metrics = [] -- cgit v1.2.1 From df548285804fdc40ac7c4f36601e87a534792a4a Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Wed, 13 Jan 2016 12:47:11 +0100 Subject: Add some fixes after review --- lib/api/variables.rb | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/lib/api/variables.rb b/lib/api/variables.rb index cc038e5731d..0c3fb5c8a77 100644 --- a/lib/api/variables.rb +++ b/lib/api/variables.rb @@ -27,11 +27,11 @@ module API # GET /projects/:id/variables/:key get ':id/variables/:key' do key = params[:key] - variables = user_project.variables.where(key: key) + variable = user_project.variables.find_by(key: key.to_s) - return not_found!('Variable') if variables.empty? + return not_found!('Variable') unless variable - present variables.first, with: Entities::Variable + present variable, with: Entities::Variable end # Create a new variable in project @@ -46,10 +46,12 @@ module API required_attributes! [:key, :value] variable = user_project.variables.create(key: params[:key], value: params[:value]) - return render_validation_error!(variable) unless variable.valid? - variable.save! - present variable, with: Entities::Variable + if variable.valid? + present variable, with: Entities::Variable + else + render_validation_error!(variable) + end end # Update existing variable of a project @@ -61,14 +63,16 @@ module API # Example Request: # PUT /projects/:id/variables/:key put ':id/variables/:key' do - variable = user_project.variables.where(key: params[:key]).first + variable = user_project.variables.find_by(key: params[:key].to_s) return not_found!('Variable') unless variable - variable.value = params[:value] - variable.save! - - present variable, with: Entities::Variable + attrs = attributes_for_keys [:value] + if variable.update(attrs) + present variable, with: Entities::Variable + else + render_validation_error!(variable) + end end # Delete existing variable of a project @@ -79,10 +83,9 @@ module API # Exanoke Reqyest: # DELETE /projects/:id/variables/:key delete ':id/variables/:key' do - variable = user_project.variables.where(key: params[:key]).first + variable = user_project.variables.find_by(key: params[:key].to_s) return not_found!('Variable') unless variable - variable.destroy present variable, with: Entities::Variable -- cgit v1.2.1 From 057eb824b5d7f38547506303dc80da6164715420 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 13 Jan 2016 12:57:46 +0100 Subject: Randomize metrics sample intervals Sampling data at a fixed interval means we can potentially miss data from events occurring between sampling intervals. For example, say we sample data every 15 seconds but Unicorn workers get killed after 10 seconds. In this particular case it's possible to miss interesting data as the sampler will never get to actually submitting data. To work around this (at least for the most part) the sampling interval is randomized as following: 1. Take the user specified sampling interval (15 seconds by default) 2. Divide it by 2 (referred to as "half" below) 3. Generate a range (using a step of 0.1) from -"half" to "half" 4. Every time the sampler goes to sleep we'll grab the user provided interval and add a randomly chosen "adjustment" to it while making sure we don't pick the same value twice in a row. For a specified timeout of 15 this means the actual intervals can be anywhere between 7.5 and 22.5, but never can the same interval be used twice in a row. The rationale behind this change is that on dev.gitlab.org I'm sometimes seeing certain Gitlab::Git/Rugged objects being retained, but only for a few minutes every 24 hours. Knowing the code of Gitlab and how much memory it uses/leaks I suspect we're missing data due to workers getting terminated before the sampler can write its data to InfluxDB. --- lib/gitlab/metrics/sampler.rb | 28 +++++++++++++++++++++++++--- spec/lib/gitlab/metrics/sampler_spec.rb | 22 +++++++++++++++++++++- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/lib/gitlab/metrics/sampler.rb b/lib/gitlab/metrics/sampler.rb index c2913841de3..fc709222a9b 100644 --- a/lib/gitlab/metrics/sampler.rb +++ b/lib/gitlab/metrics/sampler.rb @@ -8,8 +8,13 @@ module Gitlab class Sampler # interval - The sampling interval in seconds. def initialize(interval = Metrics.settings[:sample_interval]) - @interval = interval - @metrics = [] + interval_half = interval.to_f / 2 + + @interval = interval + @interval_steps = (-interval_half..interval_half).step(0.1).to_a + @last_step = nil + + @metrics = [] @last_minor_gc = Delta.new(GC.stat[:minor_gc_count]) @last_major_gc = Delta.new(GC.stat[:major_gc_count]) @@ -26,7 +31,7 @@ module Gitlab Thread.current.abort_on_exception = true loop do - sleep(@interval) + sleep(sleep_interval) sample end @@ -102,6 +107,23 @@ module Gitlab def sidekiq? Sidekiq.server? end + + # Returns the sleep interval with a random adjustment. + # + # The random adjustment is put in place to ensure we: + # + # 1. Don't generate samples at the exact same interval every time (thus + # potentially missing anything that happens in between samples). + # 2. Don't sample data at the same interval two times in a row. + def sleep_interval + while step = @interval_steps.sample + if step != @last_step + @last_step = step + + return @interval + @last_step + end + end + end end end end diff --git a/spec/lib/gitlab/metrics/sampler_spec.rb b/spec/lib/gitlab/metrics/sampler_spec.rb index 27211350fbe..38da77adc9f 100644 --- a/spec/lib/gitlab/metrics/sampler_spec.rb +++ b/spec/lib/gitlab/metrics/sampler_spec.rb @@ -9,7 +9,7 @@ describe Gitlab::Metrics::Sampler do describe '#start' do it 'gathers a sample at a given interval' do - expect(sampler).to receive(:sleep).with(5) + expect(sampler).to receive(:sleep).with(a_kind_of(Numeric)) expect(sampler).to receive(:sample) expect(sampler).to receive(:loop).and_yield @@ -116,4 +116,24 @@ describe Gitlab::Metrics::Sampler do sampler.add_metric('cats', value: 10) end end + + describe '#sleep_interval' do + it 'returns a Numeric' do + expect(sampler.sleep_interval).to be_a_kind_of(Numeric) + end + + # Testing random behaviour is very hard, so treat this test as a basic smoke + # test instead of a very accurate behaviour/unit test. + it 'does not return the same interval twice in a row' do + last = nil + + 100.times do + interval = sampler.sleep_interval + + expect(interval).to_not eq(last) + + last = interval + end + end + end end -- cgit v1.2.1 From 99393cde942841e1bee656cebf8e16a25d1300cb Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Wed, 13 Jan 2016 13:49:10 +0100 Subject: Version 8.4.0.rc1 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index ce669730119..408340137f0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.4.0.pre +8.4.0.rc1 \ No newline at end of file -- cgit v1.2.1 From b433efcf70dbafd5f76ce7140a4e6eb36008eee5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Jan 2016 14:27:36 +0100 Subject: Add suport for layout without container Signed-off-by: Dmitriy Zaporozhets --- app/views/layouts/_page.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml index ec7cd79bc54..26159989777 100644 --- a/app/views/layouts/_page.html.haml +++ b/app/views/layouts/_page.html.haml @@ -24,7 +24,7 @@ .content-wrapper = render "layouts/flash" = yield :flash_message - %div{ class: container_class } + %div{ class: (container_class unless @no_container) } .content .clearfix = yield -- cgit v1.2.1 From 6f1a59b8ed6bbe8d2c0b25bdbb82102e7b29cafd Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 13 Jan 2016 13:27:05 +0000 Subject: Removes white line when hiding diff comments in MR Fixes #6071 --- app/assets/stylesheets/pages/diff.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index afd6fb73675..e5366427f76 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -76,6 +76,7 @@ width: 100%; font-family: $monospace_font; border: none; + border-collapse: separate; margin: 0px; padding: 0px; .line_holder td { -- cgit v1.2.1 From 3b3f755b5bfa5348375fffe22ec56fe0f01ac1f5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Jan 2016 14:37:25 +0100 Subject: New layout without background color Signed-off-by: Dmitriy Zaporozhets --- app/assets/javascripts/activities.js.coffee | 4 ++-- app/assets/stylesheets/framework/blocks.scss | 12 ++++++----- app/assets/stylesheets/framework/files.scss | 2 -- app/assets/stylesheets/framework/flash.scss | 2 ++ app/assets/stylesheets/framework/header.scss | 1 + app/assets/stylesheets/framework/layout.scss | 2 -- app/assets/stylesheets/framework/lists.scss | 6 ++---- app/assets/stylesheets/framework/sidebar.scss | 1 - app/assets/stylesheets/framework/tables.scss | 6 ++---- app/assets/stylesheets/framework/timeline.scss | 4 +--- app/assets/stylesheets/pages/detail_page.scss | 5 +++-- app/assets/stylesheets/pages/events.scss | 4 +--- app/assets/stylesheets/pages/projects.scss | 8 +++---- app/helpers/events_helper.rb | 8 ++++--- app/views/groups/show.html.haml | 30 +++++++++++++++----------- app/views/projects/_activity.html.haml | 2 +- app/views/projects/show.html.haml | 24 ++++++++++++--------- app/views/shared/_event_filter.html.haml | 2 +- 18 files changed, 63 insertions(+), 60 deletions(-) diff --git a/app/assets/javascripts/activities.js.coffee b/app/assets/javascripts/activities.js.coffee index 63803747413..8b8e5d48aa0 100644 --- a/app/assets/javascripts/activities.js.coffee +++ b/app/assets/javascripts/activities.js.coffee @@ -1,7 +1,7 @@ class @Activities constructor: -> Pager.init 20, true - $(".event-filter .btn").bind "click", (event) => + $(".event-filter a").bind "click", (event) => event.preventDefault() @toggleFilter($(event.currentTarget)) @reloadActivities() @@ -12,7 +12,7 @@ class @Activities toggleFilter: (sender) -> - sender.toggleClass "active" + sender.parent().toggleClass "active" event_filters = $.cookie("event_filter") filter = sender.attr("id").split("_")[0] if event_filters diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index fa0e70847f3..11df5a377ae 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -20,7 +20,8 @@ .content-block, .gray-content-block { - margin: -$gl-padding; + margin-top: -$gl-padding; + margin-bottom: -$gl-padding; background-color: $background-color; padding: $gl-padding; margin-bottom: 0px; @@ -86,10 +87,7 @@ .cover-block { text-align: center; background: $background-color; - margin: -$gl-padding; - margin-bottom: 0; - padding: 44px $gl-padding; - border-bottom: 1px solid $border-color; + padding-top: 44px; position: relative; .avatar-holder { @@ -131,6 +129,10 @@ right: auto; } } + + .cover-menu { + margin: 0; + } } .block-connector { diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index cbfd4bc29b6..f9058c8c309 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -3,8 +3,6 @@ * */ .file-holder { - margin-left: -$gl-padding; - margin-right: -$gl-padding; border: none; border-top: 1px solid #E7E9EE; border-bottom: 1px solid #E7E9EE; diff --git a/app/assets/stylesheets/framework/flash.scss b/app/assets/stylesheets/framework/flash.scss index 82eb50ad4be..1bfd0213995 100644 --- a/app/assets/stylesheets/framework/flash.scss +++ b/app/assets/stylesheets/framework/flash.scss @@ -8,10 +8,12 @@ .flash-notice { @extend .alert; @extend .alert-info; + margin: 0; } .flash-alert { @extend .alert; @extend .alert-danger; + margin: 0; } } diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index 4dbbb56104b..ba5e72c8c5a 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -28,6 +28,7 @@ header { min-height: $header-height; background-color: #fff; border: none; + border-bottom: 1px solid #EEE; .container-fluid { width: 100% !important; diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss index a1a9990241d..e901c78d02f 100644 --- a/app/assets/stylesheets/framework/layout.scss +++ b/app/assets/stylesheets/framework/layout.scss @@ -5,8 +5,6 @@ html { } body { - background-color: #F3F3F3 !important; - &.navless { background-color: white !important; } diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index bbdb1c038c5..a5e1afd6022 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -109,10 +109,8 @@ ul.content-list { padding: 0; > li { - padding: $gl-padding; + padding: $gl-padding 0; border-color: $table-border-color; - margin-left: -$gl-padding; - margin-right: -$gl-padding; color: $gl-gray; .avatar { @@ -148,7 +146,7 @@ ul.controls { > li { float: left; margin-right: 10px; - + &:last-child { margin-right: 0; } diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 83243dd2457..06ce52e26dc 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -21,7 +21,6 @@ .content-wrapper { width: 100%; - padding: 20px; .container-fluid { background: #FFF; diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss index 793ab3d9bb9..8ae235520da 100644 --- a/app/assets/stylesheets/framework/tables.scss +++ b/app/assets/stylesheets/framework/tables.scss @@ -1,13 +1,11 @@ .table-holder { - margin: -$gl-padding; - margin-top: 0; - margin-bottom: 0; + margin: 0; } table { &.table { margin-bottom: $gl-padding; - + .dropdown-menu a { text-decoration: none; } diff --git a/app/assets/stylesheets/framework/timeline.scss b/app/assets/stylesheets/framework/timeline.scss index ff41e26ed8a..47b843e5e3d 100644 --- a/app/assets/stylesheets/framework/timeline.scss +++ b/app/assets/stylesheets/framework/timeline.scss @@ -5,10 +5,8 @@ padding: 0; .timeline-entry { - padding: $gl-padding; + padding: $gl-padding 0; border-color: $table-border-color; - margin-left: -$gl-padding; - margin-right: -$gl-padding; color: $gl-gray; border-bottom: 1px solid $border-white-light; diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss index deab805dbc2..6844d5b421d 100644 --- a/app/assets/stylesheets/pages/detail_page.scss +++ b/app/assets/stylesheets/pages/detail_page.scss @@ -1,6 +1,7 @@ .detail-page-header { - margin: -$gl-padding; - padding: 7px $gl-padding; + margin-top: -$gl-padding; + margin-bottom: -$gl-padding; + padding: 7px 0; margin-bottom: 0px; border-bottom: 1px solid $border-color; color: #5c5d5e; diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss index 984b4b91216..8fa15b35748 100644 --- a/app/assets/stylesheets/pages/events.scss +++ b/app/assets/stylesheets/pages/events.scss @@ -4,9 +4,7 @@ */ .event-item { font-size: $gl-font-size; - padding: $gl-padding $gl-padding $gl-padding ($gl-padding + $gl-avatar-size + 15px); - margin-left: -$gl-padding; - margin-right: -$gl-padding; + padding: $gl-padding 0 $gl-padding ($gl-avatar-size + 15px); border-bottom: 1px solid $table-border-color; color: #7f8fa4; diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index f24b71963a8..a8bf63539bf 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -26,6 +26,8 @@ } .project-home-panel { + padding-bottom: 40px; + border-bottom: 1px solid $border-color; .cover-controls { .project-settings-dropdown { @@ -416,8 +418,6 @@ ul.nav.nav-projects-tabs { .top-area { border-bottom: 1px solid #EEE; - margin: 0 -16px; - padding: 0 $gl-padding; height: 42px; ul.left-top-menu { @@ -574,10 +574,8 @@ pre.light-well { @include basic-list; .project-row { - padding: $gl-padding; + padding: $gl-padding 0; border-color: $table-border-color; - margin-left: -$gl-padding; - margin-right: -$gl-padding; &.no-description { .project { diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index dde83ff36b5..31bf45baeb7 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -27,13 +27,15 @@ module EventsHelper key = key.to_s active = 'active' if @event_filter.active?(key) link_opts = { - class: "event-filter-link btn btn-default #{active}", + class: "event-filter-link", id: "#{key}_event_filter", title: "Filter by #{tooltip.downcase}", } - link_to request.path, link_opts do - content_tag(:span, ' ' + tooltip) + content_tag :li, class: active do + link_to request.path, link_opts do + content_tag(:span, ' ' + tooltip) + end end end diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 48a544fc834..34719481984 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -5,6 +5,9 @@ - if current_user = auto_discovery_link_tag(:atom, group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} activity") +- @no_container = true +- @blank_container = true + .cover-block .cover-controls - if @group && can?(current_user, :admin_group, @group) @@ -25,8 +28,8 @@ .cover-desc.description = markdown(@group.description, pipeline: :description) -- if can?(current_user, :read_group, @group) - %ul.center-top-menu.no-top + + %ul.center-top-menu.cover-menu %li.active = link_to "#activity", 'data-toggle' => 'tab' do Activity @@ -35,19 +38,22 @@ = link_to "#projects", 'data-toggle' => 'tab' do Projects - .tab-content - .tab-pane.active#activity - .gray-content-block.activity-filter-block - - if current_user - = render "events/event_last_push", event: @last_push +- if can?(current_user, :read_group, @group) + + %div{ class: container_class } + .tab-content + .tab-pane.active#activity + .activity-filter-block + - if current_user + = render "events/event_last_push", event: @last_push - = render 'shared/event_filter' + = render 'shared/event_filter' - .content_list - = spinner + .content_list + = spinner - .tab-pane#projects - = render "projects", projects: @projects + .tab-pane#projects + = render "projects", projects: @projects - else %p.center-top-menu.no-top diff --git a/app/views/projects/_activity.html.haml b/app/views/projects/_activity.html.haml index 101880bd105..6edc94e7a98 100644 --- a/app/views/projects/_activity.html.haml +++ b/app/views/projects/_activity.html.haml @@ -1,4 +1,4 @@ -.gray-content-block.activity-filter-block +.activity-filter-block - if current_user .pull-right = link_to namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), title: "Feed", class: 'btn rss-btn' do diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 8436be433b1..25dcedf2b0b 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -7,8 +7,10 @@ = render 'shared/no_ssh' = render 'shared/no_password' -= render 'projects/last_push' +- @no_container = true +- @blank_container = true += render 'projects/last_push' = render "home_panel" .project-stats.gray-content-block.second-block @@ -57,15 +59,17 @@ = link_to add_contribution_guide_path(@project) do Add Contribution guide -- if @project.archived? - .text-warning.center.prepend-top-20 - %p - = icon("exclamation-triangle fw") - Archived project! Repository is read-only - - if @repository.commit .content-block.second-block.white - = render 'projects/last_commit', commit: @repository.commit, project: @project + %div{ class: container_class } + = render 'projects/last_commit', commit: @repository.commit, project: @project + +%div{ class: container_class } + - if @project.archived? + .text-warning.center.prepend-top-20 + %p + = icon("exclamation-triangle fw") + Archived project! Repository is read-only -%div{class: "project-show-#{default_project_view}"} - = render default_project_view + %div{class: "project-show-#{default_project_view}"} + = render default_project_view diff --git a/app/views/shared/_event_filter.html.haml b/app/views/shared/_event_filter.html.haml index 8495774accc..4426096f742 100644 --- a/app/views/shared/_event_filter.html.haml +++ b/app/views/shared/_event_filter.html.haml @@ -1,4 +1,4 @@ -.btn-group.btn-group-next.event-filter +%ul.left-top-menu.event-filter.no-top = event_filter_link EventFilter.push, 'Push events' = event_filter_link EventFilter.merged, 'Merge events' = event_filter_link EventFilter.comments, 'Comments' -- cgit v1.2.1 From 8c3debb18aae2cda444d25468315bdf340cb3e9e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Jan 2016 15:03:32 +0100 Subject: Start moving all navigation to one class Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework.scss | 1 + app/assets/stylesheets/framework/blocks.scss | 4 -- app/assets/stylesheets/framework/buttons.scss | 27 ----------- app/assets/stylesheets/framework/common.scss | 69 --------------------------- app/assets/stylesheets/framework/mixins.scss | 35 -------------- app/assets/stylesheets/framework/nav.scss | 38 +++++++++++++++ app/views/groups/show.html.haml | 2 +- app/views/shared/_event_filter.html.haml | 2 +- 8 files changed, 41 insertions(+), 137 deletions(-) create mode 100644 app/assets/stylesheets/framework/nav.scss diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss index 48a4971c8fc..fa7641b1676 100644 --- a/app/assets/stylesheets/framework.scss +++ b/app/assets/stylesheets/framework.scss @@ -24,6 +24,7 @@ @import "framework/lists.scss"; @import "framework/markdown_area.scss"; @import "framework/mobile.scss"; +@import "framework/nav.scss"; @import "framework/pagination.scss"; @import "framework/panels.scss"; @import "framework/selects.scss"; diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index 11df5a377ae..7abc5955fbd 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -129,10 +129,6 @@ right: auto; } } - - .cover-menu { - margin: 0; - } } .block-connector { diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index 97a94638847..8ee2a9c9886 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -153,33 +153,6 @@ } } -.btn-group-next { - .btn { - padding: 9px 0px; - font-size: 15px; - color: #7f8fa4; - border-color: #e7e9ed; - width: 140px; - - .badge { - font-weight: normal; - background-color: #eee; - color: #78a; - } - - &.active { - border-color: $gl-info; - background: $gl-info; - color: #fff; - - .badge { - color: $gl-info; - background-color: white; - } - } - } -} - .btn-clipboard { border: none; } diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 11730000f85..05645116268 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -374,75 +374,6 @@ table { } } -.center-top-menu, .left-top-menu { - @include nav-menu; - text-align: center; - margin-top: 5px; - margin-bottom: $gl-padding; - height: auto; - margin-top: -$gl-padding; - - &.no-bottom { - margin-bottom: 0; - } - - &.no-top { - margin-top: 0; - } - - li a { - display: inline-block; - padding-top: $gl-padding; - padding-bottom: 11px; - margin-bottom: -1px; - } - - &.bottom-border { - border-bottom: 1px solid $border-color; - height: 57px; - } - - &.wide { - margin-left: -$gl-padding; - margin-right: -$gl-padding; - } -} - -.left-top-menu { - text-align: left; - border-bottom: 1px solid #EEE; -} - -.center-middle-menu { - @include nav-menu; - padding: 0; - text-align: center; - margin: -$gl-padding; - margin-top: 0; - margin-bottom: 0; - height: 58px; - border-bottom: 1px solid $border-color; - - li { - &:after { - content: "|"; - color: $border-gray-light; - } - - &:last-child { - &:after { - content: none; - } - } - - > a { - display: inline-block; - text-transform: uppercase; - font-size: 13px; - } - } -} - .dropzone .dz-preview .dz-progress { border-color: $border-color !important; } diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss index 41fd890f14f..1d5000fe388 100644 --- a/app/assets/stylesheets/framework/mixins.scss +++ b/app/assets/stylesheets/framework/mixins.scss @@ -118,38 +118,3 @@ font-size: 16px; line-height: 24px; } - -@mixin nav-menu { - padding: 0; - margin: 0; - list-style: none; - height: 56px; - - li { - display: inline-block; - - a { - padding: 14px; - font-size: 15px; - line-height: 28px; - color: #959494; - border-bottom: 2px solid transparent; - - &:hover, &:active, &:focus { - text-decoration: none; - outline: none; - } - } - - &.active a { - color: #616060; - border-bottom: 2px solid #4688f1; - } - - .badge { - font-weight: normal; - background-color: #eee; - color: #78a; - } - } -} diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss new file mode 100644 index 00000000000..ffa91278982 --- /dev/null +++ b/app/assets/stylesheets/framework/nav.scss @@ -0,0 +1,38 @@ +.nav-links { + padding: 0; + margin: 0; + list-style: none; + height: 56px; + border-bottom: 1px solid $border-color; + + li { + display: inline-block; + + a { + display: inline-block; + padding-top: $gl-padding; + padding-bottom: 11px; + margin-bottom: -1px; + font-size: 15px; + line-height: 28px; + color: #959494; + border-bottom: 2px solid transparent; + + &:hover, &:active, &:focus { + text-decoration: none; + outline: none; + } + } + + &.active a { + color: #616060; + border-bottom: 2px solid #4688f1; + } + + .badge { + font-weight: normal; + background-color: #eee; + color: #78a; + } + } +} diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 34719481984..24d2f000b40 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -29,7 +29,7 @@ = markdown(@group.description, pipeline: :description) - %ul.center-top-menu.cover-menu + %ul.nav-links %li.active = link_to "#activity", 'data-toggle' => 'tab' do Activity diff --git a/app/views/shared/_event_filter.html.haml b/app/views/shared/_event_filter.html.haml index 4426096f742..c38d9313dba 100644 --- a/app/views/shared/_event_filter.html.haml +++ b/app/views/shared/_event_filter.html.haml @@ -1,4 +1,4 @@ -%ul.left-top-menu.event-filter.no-top +%ul.nav-links.event-filter = event_filter_link EventFilter.push, 'Push events' = event_filter_link EventFilter.merged, 'Merge events' = event_filter_link EventFilter.comments, 'Comments' -- cgit v1.2.1 From 710659fc1fe73e4feffdb3fbb14f4098bb58046c Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Wed, 13 Jan 2016 22:08:59 +0800 Subject: Add changelog --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index ab34661ce05..57d612dc7e2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -38,6 +38,7 @@ v 8.4.0 (unreleased) - Ajax filter by message for commits page - API: Add support for deleting a tag via the API (Robert Schilling) - Allow subsequent validations in CI Linter + - Fix Encoding::CompatibilityError bug when markdown content has some complex URL (Jason Lee) v 8.3.3 - Preserve CE behavior with JIRA integration by only calling API if URL is set -- cgit v1.2.1 From 97338496188add9ec8d192c7e78f6a6040befffa Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Wed, 13 Jan 2016 15:17:59 +0100 Subject: Add some fixes after review --- doc/api/builds.md | 36 ------------------------------------ lib/api/builds.rb | 24 +++++++++++++----------- lib/api/entities.rb | 6 ++---- spec/requests/api/builds_spec.rb | 6 ++++++ 4 files changed, 21 insertions(+), 51 deletions(-) diff --git a/doc/api/builds.md b/doc/api/builds.md index 99ef0882c16..06ff89bea00 100644 --- a/doc/api/builds.md +++ b/doc/api/builds.md @@ -40,23 +40,14 @@ Parameters: "user": { "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", "bio": null, - "can_create_group": true, - "can_create_project": true, - "color_scheme_id": 2, "created_at": "2015-12-21T13:14:24.077Z", - "current_sign_in_at": "2016-01-11T09:31:40.472Z", - "email": "admin@example.com", "id": 1, - "identities": [], "is_admin": true, "linkedin": "", "name": "Administrator", - "projects_limit": 100, "skype": "", "state": "active", - "theme_id": 3, "twitter": "", - "two_factor_enabled": false, "username": "root", "web_url": "http://gitlab.dev/u/root", "website_url": "" @@ -87,23 +78,14 @@ Parameters: "user": { "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", "bio": null, - "can_create_group": true, - "can_create_project": true, - "color_scheme_id": 2, "created_at": "2015-12-21T13:14:24.077Z", - "current_sign_in_at": "2016-01-11T09:31:40.472Z", - "email": "admin@example.com", "id": 1, - "identities": [], "is_admin": true, "linkedin": "", "name": "Administrator", - "projects_limit": 100, "skype": "", "state": "active", - "theme_id": 3, "twitter": "", - "two_factor_enabled": false, "username": "root", "web_url": "http://gitlab.dev/u/root", "website_url": "" @@ -177,23 +159,14 @@ Parameters: "user": { "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", "bio": null, - "can_create_group": true, - "can_create_project": true, - "color_scheme_id": 2, "created_at": "2015-12-21T13:14:24.077Z", - "current_sign_in_at": "2016-01-12T10:30:48.315Z", - "email": "admin@example.com", "id": 1, - "identities": [], "is_admin": true, "linkedin": "", "name": "Administrator", - "projects_limit": 100, "skype": "", "state": "active", - "theme_id": 3, "twitter": "", - "two_factor_enabled": false, "username": "root", "web_url": "http://gitlab.dev/u/root", "website_url": "" @@ -241,23 +214,14 @@ Parameters: "user": { "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", "bio": null, - "can_create_group": true, - "can_create_project": true, - "color_scheme_id": 2, "created_at": "2015-12-21T13:14:24.077Z", - "current_sign_in_at": "2016-01-11T09:31:40.472Z", - "email": "admin@example.com", "id": 1, - "identities": [], "is_admin": true, "linkedin": "", "name": "Administrator", - "projects_limit": 100, "skype": "", "state": "active", - "theme_id": 3, "twitter": "", - "two_factor_enabled": false, "username": "root", "web_url": "http://gitlab.dev/u/root", "website_url": "" diff --git a/lib/api/builds.rb b/lib/api/builds.rb index d3f4e33ebbf..1337e1bb452 100644 --- a/lib/api/builds.rb +++ b/lib/api/builds.rb @@ -35,6 +35,7 @@ module API builds = commit.builds.order('id DESC') builds = filter_builds(builds, params[:scope]) + present paginate(builds), with: Entities::Build, user_can_download_artifacts: can?(current_user, :download_build_artifacts, user_project) end @@ -118,25 +119,26 @@ module API helpers do def get_build(id) - user_project.builds.where(id: id).first + user_project.builds.find_by(id: id.to_i) end def filter_builds(builds, scope) - available_scopes = Ci::Build.available_statuses + return builds if scope.nil? || scope.empty? + + available_statuses = Ci::Build.available_statuses scope = - if scope.is_a?(String) || scope.is_a?(Symbol) - available_scopes & [scope.to_s] - elsif scope.is_a?(Array) - available_scopes & scope - elsif scope.respond_to?(:to_h) - available_scopes & scope.to_h.values + if scope.is_a?(String) + [scope] + elsif scope.is_a?(Hashie::Mash) + scope.values else - [] + ['unknown'] end - return builds if scope.empty? + unknown = scope - available_statuses + render_api_error!('Scope contains invalid value(s)', 400) unless unknown.empty? - builds.where(status: scope) + builds.where(status: available_statuses && scope) end def authorize_manage_builds! diff --git a/lib/api/entities.rb b/lib/api/entities.rb index e19f9f8d75a..f0816a46529 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -378,18 +378,16 @@ module API expose :id, :status, :stage, :name, :ref, :tag, :coverage expose :created_at, :started_at, :finished_at expose :user, with: User + # TODO: download_url in Ci:Build model is an GitLab Web Interface URL, not API URL. We should think on some API + # for downloading of artifacts (see: https://gitlab.com/gitlab-org/gitlab-ce/issues/4255) expose :download_url do |repo_obj, options| if options[:user_can_download_artifacts] repo_obj.download_url - else - nil end end expose :commit, with: RepoCommit do |repo_obj, _options| if repo_obj.respond_to?(:commit) repo_obj.commit.commit_data - else - nil end end expose :runner, with: Runner diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb index 587fb74750d..4bf3d2681dc 100644 --- a/spec/requests/api/builds_spec.rb +++ b/spec/requests/api/builds_spec.rb @@ -35,6 +35,12 @@ describe API::API, api: true do expect(response.status).to eq(200) expect(json_response).to be_an Array end + + it 'should respond 400 when scope contains invalid state' do + get api("/projects/#{project.id}/builds?scope[0]=pending&scope[1]=unknown_status", user) + + expect(response.status).to eq(400) + end end context 'unauthorized user' do -- cgit v1.2.1 From 03090a88d80cbc8c4333053081882915beb721da Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Jan 2016 15:58:04 +0100 Subject: Replace all navigation menu with nav-links class Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/blocks.scss | 12 +++++- app/assets/stylesheets/framework/mobile.scss | 2 +- app/assets/stylesheets/framework/nav.scss | 5 ++- app/assets/stylesheets/framework/sidebar.scss | 2 +- app/assets/stylesheets/pages/detail_page.scss | 3 -- app/assets/stylesheets/pages/diff.scss | 2 - app/assets/stylesheets/pages/issuable.scss | 2 +- app/assets/stylesheets/pages/merge_requests.scss | 4 +- app/assets/stylesheets/pages/projects.scss | 9 +--- app/views/admin/builds/index.html.haml | 2 +- app/views/dashboard/_activities.html.haml | 4 +- app/views/dashboard/_activity_head.html.haml | 2 +- app/views/dashboard/_groups_head.html.haml | 2 +- app/views/dashboard/_projects_head.html.haml | 2 +- app/views/dashboard/_snippets_head.html.haml | 2 +- app/views/dashboard/milestones/show.html.haml | 2 +- app/views/dashboard/snippets/index.html.haml | 48 ++++++++++++---------- app/views/groups/milestones/show.html.haml | 2 +- app/views/groups/show.html.haml | 2 +- app/views/help/ui.html.haml | 4 +- app/views/projects/_activity.html.haml | 4 +- app/views/projects/_md_preview.html.haml | 2 +- app/views/projects/blob/edit.html.haml | 2 +- app/views/projects/builds/index.html.haml | 2 +- app/views/projects/builds/show.html.haml | 2 +- app/views/projects/commit/_ci_menu.html.haml | 2 +- app/views/projects/commit/show.html.haml | 4 +- app/views/projects/commits/_head.html.haml | 2 +- app/views/projects/graphs/_head.html.haml | 2 +- .../projects/merge_requests/_new_submit.html.haml | 2 +- app/views/projects/merge_requests/_show.html.haml | 2 +- app/views/projects/milestones/show.html.haml | 2 +- app/views/projects/wikis/_nav.html.haml | 2 +- app/views/shared/_milestones_filter.html.haml | 2 +- app/views/shared/issuable/_filter.html.haml | 2 +- app/views/sherlock/queries/show.html.haml | 2 +- app/views/sherlock/transactions/show.html.haml | 2 +- app/views/users/show.html.haml | 2 +- 38 files changed, 80 insertions(+), 73 deletions(-) diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index 7abc5955fbd..7c139d980de 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -20,7 +20,7 @@ .content-block, .gray-content-block { - margin-top: -$gl-padding; + margin-top: 0; margin-bottom: -$gl-padding; background-color: $background-color; padding: $gl-padding; @@ -134,3 +134,13 @@ .block-connector { margin-top: -1px; } + +.nav-block { + .controls { + float: right; + + .btn { + margin-top: 7px; + } + } +} diff --git a/app/assets/stylesheets/framework/mobile.scss b/app/assets/stylesheets/framework/mobile.scss index c00709fb6bb..fdb4b42fe8e 100644 --- a/app/assets/stylesheets/framework/mobile.scss +++ b/app/assets/stylesheets/framework/mobile.scss @@ -81,7 +81,7 @@ display: none; } - .center-top-menu, .left-top-menu { + .nav-links, .nav-links { li a { font-size: 14px; padding: 19px 10px; diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss index ffa91278982..c537d97fb24 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -2,7 +2,7 @@ padding: 0; margin: 0; list-style: none; - height: 56px; + height: auto; border-bottom: 1px solid $border-color; li { @@ -10,6 +10,7 @@ a { display: inline-block; + padding: 14px; padding-top: $gl-padding; padding-bottom: 11px; margin-bottom: -1px; @@ -25,7 +26,7 @@ } &.active a { - color: #616060; + color: #000000; border-bottom: 2px solid #4688f1; } diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 06ce52e26dc..540d0b03163 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -24,7 +24,7 @@ .container-fluid { background: #FFF; - padding: $gl-padding; + padding: 0 $gl-padding; &.container-blank { background: none; diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss index 6844d5b421d..a9605804fb3 100644 --- a/app/assets/stylesheets/pages/detail_page.scss +++ b/app/assets/stylesheets/pages/detail_page.scss @@ -1,8 +1,5 @@ .detail-page-header { - margin-top: -$gl-padding; - margin-bottom: -$gl-padding; padding: 7px 0; - margin-bottom: 0px; border-bottom: 1px solid $border-color; color: #5c5d5e; font-size: 16px; diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index afd6fb73675..c5515bc418c 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -1,7 +1,5 @@ // Common .diff-file { - margin-left: -$gl-padding; - margin-right: -$gl-padding; border: none; border-bottom: 1px solid #E7E9EE; diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index d4b44004f4f..7ab77550496 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -30,7 +30,7 @@ margin-top: 7px; } - .center-top-menu { + .nav-links { text-align: left; } } diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 82effde0bf3..0e95aaff65a 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -3,9 +3,9 @@ * */ .mr-state-widget { - background: #F7F8FA; + background: $background-color; color: $gl-gray; - border: 1px solid #dce0e6; + border: 1px solid $border-color; @include border-radius(2px); form { diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index a8bf63539bf..48fdfb1de66 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -228,7 +228,6 @@ } .projects-search-form { - .input-group .form-control { height: 42px; } @@ -418,9 +417,8 @@ ul.nav.nav-projects-tabs { .top-area { border-bottom: 1px solid #EEE; - height: 42px; - ul.left-top-menu { + ul.nav-links { display: inline-block; width: 50%; margin-bottom: 0px; @@ -523,8 +521,7 @@ pre.light-well { } .projects-search-form { - margin: -$gl-padding; - padding: $gl-padding; + padding: $gl-padding 0; padding-bottom: 0; margin-bottom: 0px; @@ -660,8 +657,6 @@ pre.light-well { } .project-show-readme .readme-holder { - margin-left: -$gl-padding; - margin-right: -$gl-padding; padding: ($gl-padding + 7px); border-top: 0; diff --git a/app/views/admin/builds/index.html.haml b/app/views/admin/builds/index.html.haml index ddd4e1481eb..ebf2b7b60e7 100644 --- a/app/views/admin/builds/index.html.haml +++ b/app/views/admin/builds/index.html.haml @@ -4,7 +4,7 @@ - if @all_builds.running_or_pending.any? = link_to 'Cancel all', cancel_all_admin_builds_path, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post - %ul.center-top-menu + %ul.nav-links %li{class: ('active' if @scope.nil?)} = link_to admin_builds_path do All diff --git a/app/views/dashboard/_activities.html.haml b/app/views/dashboard/_activities.html.haml index f98fd9f06ba..dc76599b776 100644 --- a/app/views/dashboard/_activities.html.haml +++ b/app/views/dashboard/_activities.html.haml @@ -1,9 +1,9 @@ .hidden-xs = render "events/event_last_push", event: @last_push -.gray-content-block +.nav-block - if current_user - .pull-right + .controls = link_to dashboard_projects_path(:atom, { private_token: current_user.private_token }), class: 'btn rss-btn' do %i.fa.fa-rss = render 'shared/event_filter' diff --git a/app/views/dashboard/_activity_head.html.haml b/app/views/dashboard/_activity_head.html.haml index 9f4be025bf2..b78e70ebc1e 100644 --- a/app/views/dashboard/_activity_head.html.haml +++ b/app/views/dashboard/_activity_head.html.haml @@ -1,4 +1,4 @@ -%ul.center-top-menu +%ul.nav-links %li{ class: ("active" unless params[:filter]) } = link_to activity_dashboard_path, class: 'shortcuts-activity', data: {placement: 'right'} do Your Projects diff --git a/app/views/dashboard/_groups_head.html.haml b/app/views/dashboard/_groups_head.html.haml index 64bd356f546..6ca97a692b4 100644 --- a/app/views/dashboard/_groups_head.html.haml +++ b/app/views/dashboard/_groups_head.html.haml @@ -1,4 +1,4 @@ -%ul.center-top-menu +%ul.nav-links = nav_link(page: dashboard_groups_path) do = link_to dashboard_groups_path, title: 'Your groups', data: {placement: 'right'} do Your Groups diff --git a/app/views/dashboard/_projects_head.html.haml b/app/views/dashboard/_projects_head.html.haml index f4a3e3162bf..5c4b58cd688 100644 --- a/app/views/dashboard/_projects_head.html.haml +++ b/app/views/dashboard/_projects_head.html.haml @@ -1,7 +1,7 @@ = content_for :flash_message do = render 'shared/project_limit' .top-area - %ul.left-top-menu + %ul.nav-links = nav_link(page: [dashboard_projects_path, root_path]) do = link_to dashboard_projects_path, title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do Your Projects diff --git a/app/views/dashboard/_snippets_head.html.haml b/app/views/dashboard/_snippets_head.html.haml index 0ae62d6f1b6..b25e8ea1f0c 100644 --- a/app/views/dashboard/_snippets_head.html.haml +++ b/app/views/dashboard/_snippets_head.html.haml @@ -1,4 +1,4 @@ -%ul.center-top-menu +%ul.nav-links = nav_link(page: dashboard_snippets_path, html_options: {class: 'home'}) do = link_to dashboard_snippets_path, title: 'Your snippets', data: {placement: 'right'} do Your Snippets diff --git a/app/views/dashboard/milestones/show.html.haml b/app/views/dashboard/milestones/show.html.haml index 49a558e8ac9..3810267577c 100644 --- a/app/views/dashboard/milestones/show.html.haml +++ b/app/views/dashboard/milestones/show.html.haml @@ -48,7 +48,7 @@ #{@milestone.open_items_count} open = milestone_progress_bar(@milestone) -%ul.center-top-menu.no-top.no-bottom +%ul.nav-links.no-top.no-bottom %li.active = link_to '#tab-issues', 'data-toggle' => 'tab' do Issues diff --git a/app/views/dashboard/snippets/index.html.haml b/app/views/dashboard/snippets/index.html.haml index 07b6d57932e..d4e7862981c 100644 --- a/app/views/dashboard/snippets/index.html.haml +++ b/app/views/dashboard/snippets/index.html.haml @@ -3,32 +3,36 @@ = render 'dashboard/snippets_head' -.gray-content-block - .pull-right +.nav-block + .controls = link_to new_snippet_path, class: "btn btn-new", title: "New Snippet" do = icon('plus') New Snippet - .btn-group.btn-group-next.snippet-scope-menu - = link_to dashboard_snippets_path, class: "btn btn-default #{"active" unless params[:scope]}" do - All - %span.badge - = current_user.snippets.count - - = link_to dashboard_snippets_path(scope: 'are_private'), class: "btn btn-default #{"active" if params[:scope] == "are_private"}" do - Private - %span.badge - = current_user.snippets.are_private.count - - = link_to dashboard_snippets_path(scope: 'are_internal'), class: "btn btn-default #{"active" if params[:scope] == "are_internal"}" do - Internal - %span.badge - = current_user.snippets.are_internal.count - - = link_to dashboard_snippets_path(scope: 'are_public'), class: "btn btn-default #{"active" if params[:scope] == "are_public"}" do - Public - %span.badge - = current_user.snippets.are_public.count + .nav-links.snippet-scope-menu + %li{ class: ("active" unless params[:scope]) } + = link_to dashboard_snippets_path do + All + %span.badge + = current_user.snippets.count + + %li{ class: ("active" if params[:scope] == "are_private") } + = link_to dashboard_snippets_path(scope: 'are_private') do + Private + %span.badge + = current_user.snippets.are_private.count + + %li{ class: ("active" if params[:scope] == "are_internal") } + = link_to dashboard_snippets_path(scope: 'are_internal') do + Internal + %span.badge + = current_user.snippets.are_internal.count + + %li{ class: ("active" if params[:scope] == "are_public") } + = link_to dashboard_snippets_path(scope: 'are_public') do + Public + %span.badge + = current_user.snippets.are_public.count = render 'snippets/snippets' diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml index d063b257b5e..1233da85524 100644 --- a/app/views/groups/milestones/show.html.haml +++ b/app/views/groups/milestones/show.html.haml @@ -54,7 +54,7 @@ #{@milestone.open_items_count} open = milestone_progress_bar(@milestone) -%ul.center-top-menu.no-top.no-bottom +%ul.nav-links.no-top.no-bottom %li.active = link_to '#tab-issues', 'data-toggle' => 'tab' do Issues diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 24d2f000b40..4da70358766 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -56,5 +56,5 @@ = render "projects", projects: @projects - else - %p.center-top-menu.no-top + %p.nav-links.no-top No projects to show diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml index d9ffda884c8..65335c708fa 100644 --- a/app/views/help/ui.html.haml +++ b/app/views/help/ui.html.haml @@ -139,9 +139,9 @@ %h2#navs Navigation %h4 - %code .center-top-menu + %code .nav-links .example - %ul.center-top-menu + %ul.nav-links %li.active %a Open %li diff --git a/app/views/projects/_activity.html.haml b/app/views/projects/_activity.html.haml index 6edc94e7a98..961b61d2e76 100644 --- a/app/views/projects/_activity.html.haml +++ b/app/views/projects/_activity.html.haml @@ -1,6 +1,6 @@ -.activity-filter-block +.nav-block.activity-filter-block - if current_user - .pull-right + .controls = link_to namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), title: "Feed", class: 'btn rss-btn' do %i.fa.fa-rss diff --git a/app/views/projects/_md_preview.html.haml b/app/views/projects/_md_preview.html.haml index 54c818baaf4..1fb37ef6621 100644 --- a/app/views/projects/_md_preview.html.haml +++ b/app/views/projects/_md_preview.html.haml @@ -1,6 +1,6 @@ .md-area .md-header.clearfix - %ul.center-top-menu + %ul.nav-links %li.active %a.js-md-write-button(href="#md-write-holder" tabindex="-1") Write diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml index 09fa148b129..a279e6eda55 100644 --- a/app/views/projects/blob/edit.html.haml +++ b/app/views/projects/blob/edit.html.haml @@ -2,7 +2,7 @@ = render "header_title" .file-editor - %ul.center-top-menu.no-bottom.js-edit-mode + %ul.nav-links.no-bottom.js-edit-mode %li.active = link_to '#editor' do = icon('edit') diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml index 3bbfdb1e3b0..5d18c0d803a 100644 --- a/app/views/projects/builds/index.html.haml +++ b/app/views/projects/builds/index.html.haml @@ -8,7 +8,7 @@ - if @all_builds.running_or_pending.any? = link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post - %ul.center-top-menu + %ul.nav-links %li{class: ('active' if @scope.nil?)} = link_to project_builds_path(@project) do All diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml index 5b7ecce86ab..08a59d465c0 100644 --- a/app/views/projects/builds/show.html.haml +++ b/app/views/projects/builds/show.html.haml @@ -14,7 +14,7 @@ #up-build-trace - if @commit.matrix_for_ref?(@build.ref) - %ul.center-top-menu.no-top.no-bottom + %ul.nav-links.no-top.no-bottom - @commit.latest_builds_for_ref(@build.ref).each do |build| %li{class: ('active' if build == @build) } = link_to namespace_project_build_path(@project.namespace, @project, build) do diff --git a/app/views/projects/commit/_ci_menu.html.haml b/app/views/projects/commit/_ci_menu.html.haml index f74f8b427ec..ea33aa472a6 100644 --- a/app/views/projects/commit/_ci_menu.html.haml +++ b/app/views/projects/commit/_ci_menu.html.haml @@ -1,4 +1,4 @@ -%ul.center-top-menu.no-top.no-bottom.commit-ci-menu +%ul.nav-links.no-top.no-bottom.commit-ci-menu = nav_link(path: 'commit#show') do = link_to namespace_project_commit_path(@project.namespace, @project, @commit.id) do Changes diff --git a/app/views/projects/commit/show.html.haml b/app/views/projects/commit/show.html.haml index 58aa45e8d2c..02297158dec 100644 --- a/app/views/projects/commit/show.html.haml +++ b/app/views/projects/commit/show.html.haml @@ -2,7 +2,9 @@ - page_description @commit.description = render "projects/commits/header_title" -= render "commit_box" + +.prepend-top-default + = render "commit_box" - if @ci_commit = render "ci_menu" - else diff --git a/app/views/projects/commits/_head.html.haml b/app/views/projects/commits/_head.html.haml index fcccb002d7e..498c5e05b32 100644 --- a/app/views/projects/commits/_head.html.haml +++ b/app/views/projects/commits/_head.html.haml @@ -1,4 +1,4 @@ -%ul.center-top-menu +%ul.nav-links = nav_link(controller: [:commit, :commits]) do = link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do Commits diff --git a/app/views/projects/graphs/_head.html.haml b/app/views/projects/graphs/_head.html.haml index a47643bd09c..79a56647c53 100644 --- a/app/views/projects/graphs/_head.html.haml +++ b/app/views/projects/graphs/_head.html.haml @@ -1,4 +1,4 @@ -%ul.center-top-menu +%ul.nav-links = nav_link(action: :show) do = link_to 'Contributors', namespace_project_graph_path = nav_link(action: :commits) do diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml index a14943b15d3..dd2c59e112a 100644 --- a/app/views/projects/merge_requests/_new_submit.html.haml +++ b/app/views/projects/merge_requests/_new_submit.html.haml @@ -18,7 +18,7 @@ = f.hidden_field :target_branch .mr-compare.merge-request - %ul.merge-request-tabs.center-top-menu.no-top.no-bottom + %ul.merge-request-tabs.nav-links.no-top.no-bottom %li.commits-tab = link_to url_for(params), data: {target: 'div#commits', action: 'commits', toggle: 'tab'} do Commits diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 095876450a0..200bfa5ac4f 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -45,7 +45,7 @@ = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal" - if @commits.present? - %ul.merge-request-tabs.center-top-menu.no-top.no-bottom + %ul.merge-request-tabs.nav-links.no-top.no-bottom %li.notes-tab = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#notes', action: 'notes', toggle: 'tab'} do Discussion diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml index 1670ea8741a..f258b75e01c 100644 --- a/app/views/projects/milestones/show.html.haml +++ b/app/views/projects/milestones/show.html.haml @@ -57,7 +57,7 @@ %span.pull-right= @milestone.expires_at = milestone_progress_bar(@milestone) -%ul.center-top-menu.no-top.no-bottom +%ul.nav-links.no-top.no-bottom %li.active = link_to '#tab-issues', 'data-toggle' => 'tab' do Issues diff --git a/app/views/projects/wikis/_nav.html.haml b/app/views/projects/wikis/_nav.html.haml index e6e6ad5bc4b..69ba301e231 100644 --- a/app/views/projects/wikis/_nav.html.haml +++ b/app/views/projects/wikis/_nav.html.haml @@ -7,7 +7,7 @@ = render 'projects/wikis/new' - %ul.center-top-menu + %ul.nav-links = nav_link(html_options: {class: params[:id] == 'home' ? 'active' : '' }) do = link_to 'Home', namespace_project_wiki_path(@project.namespace, @project, :home) diff --git a/app/views/shared/_milestones_filter.html.haml b/app/views/shared/_milestones_filter.html.haml index cbdecda4fff..f77feeb79cd 100644 --- a/app/views/shared/_milestones_filter.html.haml +++ b/app/views/shared/_milestones_filter.html.haml @@ -1,5 +1,5 @@ .milestones-filters - %ul.center-top-menu + %ul.nav-links %li{class: ("active" if params[:state].blank? || params[:state] == 'opened')} = link_to milestones_filter_path(state: 'opened') do Open diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml index 0e3e9275fc1..8d6f47b38ef 100644 --- a/app/views/shared/issuable/_filter.html.haml +++ b/app/views/shared/issuable/_filter.html.haml @@ -1,6 +1,6 @@ .issues-filters .issues-state-filters - %ul.center-top-menu + %ul.nav-links - if defined?(type) && type == :merge_requests - page_context_word = 'merge requests' - else diff --git a/app/views/sherlock/queries/show.html.haml b/app/views/sherlock/queries/show.html.haml index 4a84348ac82..83f61ce4b07 100644 --- a/app/views/sherlock/queries/show.html.haml +++ b/app/views/sherlock/queries/show.html.haml @@ -1,7 +1,7 @@ - page_title t('sherlock.title'), t('sherlock.transaction'), t('sherlock.query') - header_title t('sherlock.title'), sherlock_transactions_path -%ul.center-top-menu +%ul.nav-links %li.active %a(href="#tab-general" data-toggle="tab") = t('sherlock.general') diff --git a/app/views/sherlock/transactions/show.html.haml b/app/views/sherlock/transactions/show.html.haml index 3c8ffb06648..9d4b0b2724c 100644 --- a/app/views/sherlock/transactions/show.html.haml +++ b/app/views/sherlock/transactions/show.html.haml @@ -1,7 +1,7 @@ - page_title t('sherlock.title'), t('sherlock.transaction') - header_title t('sherlock.title'), sherlock_transactions_path -%ul.center-top-menu +%ul.nav-links %li.active %a(href="#tab-general" data-toggle="tab") = t('sherlock.general') diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index ce17fc7bca1..e7848bf1333 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -74,7 +74,7 @@ .user-calendar-activities -%ul.center-top-menu.no-top.no-bottom.bottom-border.wide +%ul.nav-links.no-top.no-bottom.bottom-border.wide %li.active = link_to "#activity", 'data-toggle' => 'tab' do Activity -- cgit v1.2.1 From 96dda5f6ecba417118d80a0bdfa5c0a14e15a04c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Jan 2016 16:00:08 +0100 Subject: Update UI help page with only one nav-link example Signed-off-by: Dmitriy Zaporozhets --- app/views/help/ui.html.haml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml index 65335c708fa..7b45bd09050 100644 --- a/app/views/help/ui.html.haml +++ b/app/views/help/ui.html.haml @@ -147,23 +147,6 @@ %li %a Closed - %h4 - %code .btn-group.btn-group-next - .example - %div.btn-group.btn-group-next - %a.btn.active Open - %a.btn Closed - - - %h4 - %code .nav.nav-tabs - .example - %ul.nav.nav-tabs - %li.active - %a Open - %li - %a Closed - %h2#buttons Buttons -- cgit v1.2.1 From 990bd06c04bebe6319968aa619990bf4cb60483c Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Wed, 13 Jan 2016 16:05:49 +0100 Subject: Change :ci_build_canceled factory to :canceled trait --- spec/factories/ci/builds.rb | 8 ++++---- spec/requests/api/builds_spec.rb | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index 558598d4d5c..636cdbba1b8 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -43,6 +43,10 @@ FactoryGirl.define do commit factory: :ci_commit + trait :canceled do + status 'canceled' + end + after(:build) do |build, evaluator| build.project = build.commit.project end @@ -62,9 +66,5 @@ FactoryGirl.define do build.trace = 'BUILD TRACE' end end - - factory :ci_build_canceled do - status 'canceled' - end end end diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb index 4bf3d2681dc..e5567d42500 100644 --- a/spec/requests/api/builds_spec.rb +++ b/spec/requests/api/builds_spec.rb @@ -11,7 +11,7 @@ describe API::API, api: true do let(:commit) { create(:ci_commit, project: project)} let(:build) { create(:ci_build, commit: commit) } let(:build_with_trace) { create(:ci_build_with_trace, commit: commit) } - let(:build_canceled) { create(:ci_build_canceled, commit: commit) } + let(:build_canceled) { create(:ci_build, :canceled, commit: commit) } describe 'GET /projects/:id/builds ' do context 'authorized user' do -- cgit v1.2.1 From 132ab484d46044c4c7a88b7df02e67a29255e032 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Jan 2016 16:06:59 +0100 Subject: Increase detail-page-header padding to match height with nav-link Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/pages/detail_page.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss index a9605804fb3..529a43548c8 100644 --- a/app/assets/stylesheets/pages/detail_page.scss +++ b/app/assets/stylesheets/pages/detail_page.scss @@ -1,5 +1,5 @@ .detail-page-header { - padding: 7px 0; + padding: 11px 0; border-bottom: 1px solid $border-color; color: #5c5d5e; font-size: 16px; -- cgit v1.2.1 From c44b927bc00ed75b41f3951a15794c5cc6bdc60e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Jan 2016 16:10:06 +0100 Subject: Allign md header components Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/markdown_area.scss | 7 ------- app/assets/stylesheets/framework/zen.scss | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss index 4a00a197d9a..f0674205c17 100644 --- a/app/assets/stylesheets/framework/markdown_area.scss +++ b/app/assets/stylesheets/framework/markdown_area.scss @@ -65,13 +65,6 @@ position: relative; } -.md-header { - ul { - float: left; - margin-bottom: 1px; - } -} - .referenced-users { color: #4c4e54; padding-top: 10px; diff --git a/app/assets/stylesheets/framework/zen.scss b/app/assets/stylesheets/framework/zen.scss index 002bd7e8ca5..c3f27333fad 100644 --- a/app/assets/stylesheets/framework/zen.scss +++ b/app/assets/stylesheets/framework/zen.scss @@ -4,7 +4,7 @@ position: absolute; top: 0px; right: 4px; - line-height: 40px; + line-height: 56px; } a.js-zen-leave { -- cgit v1.2.1 From 0673fad893e2cd457424bc730b1faa146e1f6f5f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Jan 2016 16:26:40 +0100 Subject: Apply new layout to user page Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/lists.scss | 1 + app/views/groups/show.html.haml | 7 +- app/views/projects/show.html.haml | 6 +- app/views/users/show.html.haml | 127 ++++++++++++++-------------- 4 files changed, 72 insertions(+), 69 deletions(-) diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index a5e1afd6022..c6bc6fb324d 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -131,6 +131,7 @@ ul.content-list { .panel > .content-list { li { margin: 0; + padding: $gl-padding; } } diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 4da70358766..5e39d3ab601 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -1,3 +1,6 @@ +- @no_container = true +- @blank_container = true + - unless can?(current_user, :read_group, @group) - @disable_search_panel = true @@ -5,9 +8,6 @@ - if current_user = auto_discovery_link_tag(:atom, group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} activity") -- @no_container = true -- @blank_container = true - .cover-block .cover-controls - if @group && can?(current_user, :admin_group, @group) @@ -39,7 +39,6 @@ Projects - if can?(current_user, :read_group, @group) - %div{ class: container_class } .tab-content .tab-pane.active#activity diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 25dcedf2b0b..65444e7e334 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -1,3 +1,6 @@ +- @no_container = true +- @blank_container = true + = content_for :meta_tags do - if current_user = auto_discovery_link_tag(:atom, namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), title: "#{@project.name} activity") @@ -7,9 +10,6 @@ = render 'shared/no_ssh' = render 'shared/no_password' -- @no_container = true -- @blank_container = true - = render 'projects/last_push' = render "home_panel" diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index e7848bf1333..284a62e6f47 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -1,6 +1,8 @@ - page_title @user.name - page_description @user.bio - header_title @user.name, user_path(@user) +- @no_container = true +- @blank_container = true = content_for :meta_tags do = auto_discovery_link_tag(:atom, user_url(@user, format: :atom), title: "#{@user.name} activity") @@ -8,6 +10,25 @@ = render 'shared/show_aside' .cover-block + .cover-controls + - if @user == current_user + = link_to profile_path, class: 'btn btn-gray' do + = icon('pencil') + - elsif current_user + %span.report-abuse + - if @user.abuse_report + %button.btn.btn-danger{ title: 'Already reported for abuse', + data: { toggle: 'tooltip', placement: 'left', container: 'body' }} + = icon('exclamation-circle') + - else + = link_to new_abuse_report_path(user_id: @user.id), class: 'btn btn-gray', + title: 'Report abuse', data: {toggle: 'tooltip', placement: 'left', container: 'body'} do + = icon('exclamation-circle') + - if current_user +   + = link_to user_path(@user, :atom, { private_token: current_user.private_token }), class: 'btn btn-gray' do + = icon('rss') + .avatar-holder = link_to avatar_icon(@user, 400), target: '_blank' do = image_tag avatar_icon(@user, 90), class: "avatar s90", alt: '' @@ -47,74 +68,56 @@ = icon('map-marker') = @user.location + %ul.nav-links.center + %li.active + = link_to "#activity", 'data-toggle' => 'tab' do + Activity + - if @groups.any? + %li + = link_to "#groups", 'data-toggle' => 'tab' do + Groups + - if @contributed_projects.present? + %li + = link_to "#contributed", 'data-toggle' => 'tab' do + Contributed projects + - if @projects.present? + %li + = link_to "#personal", 'data-toggle' => 'tab' do + Personal projects - .cover-controls - - if @user == current_user - = link_to profile_path, class: 'btn btn-gray' do - = icon('pencil') - - elsif current_user - %span.report-abuse - - if @user.abuse_report - %button.btn.btn-danger{ title: 'Already reported for abuse', - data: { toggle: 'tooltip', placement: 'left', container: 'body' }} - = icon('exclamation-circle') - - else - = link_to new_abuse_report_path(user_id: @user.id), class: 'btn btn-gray', - title: 'Report abuse', data: {toggle: 'tooltip', placement: 'left', container: 'body'} do - = icon('exclamation-circle') - - if current_user -   - = link_to user_path(@user, :atom, { private_token: current_user.private_token }), class: 'btn btn-gray' do - = icon('rss') - -.gray-content-block.second-block - .user-calendar - %h4.center.light - %i.fa.fa-spinner.fa-spin - .user-calendar-activities - +%div{ class: container_class } + .tab-content + .tab-pane.active#activity + .gray-content-block.white.second-block + %div{ class: container_class } + .user-calendar + %h4.center.light + %i.fa.fa-spinner.fa-spin + .user-calendar-activities -%ul.nav-links.no-top.no-bottom.bottom-border.wide - %li.active - = link_to "#activity", 'data-toggle' => 'tab' do - Activity - - if @groups.any? - %li - = link_to "#groups", 'data-toggle' => 'tab' do - Groups - - if @contributed_projects.present? - %li - = link_to "#contributed", 'data-toggle' => 'tab' do - Contributed projects - - if @projects.present? - %li - = link_to "#personal", 'data-toggle' => 'tab' do - Personal projects -.tab-content - .tab-pane.active#activity - .content_list - = spinner + .content_list + = spinner - - if @groups.any? - .tab-pane#groups - %ul.content-list - - @groups.each do |group| - = render 'shared/groups/group', group: group + - if @groups.any? + .tab-pane#groups + %ul.content-list + - @groups.each do |group| + = render 'shared/groups/group', group: group - - if @contributed_projects.present? - .tab-pane#contributed - .contributed-projects - = render 'shared/projects/list', - projects: @contributed_projects.sort_by(&:star_count).reverse, - projects_limit: 5, stars: true, avatar: true + - if @contributed_projects.present? + .tab-pane#contributed + .contributed-projects + = render 'shared/projects/list', + projects: @contributed_projects.sort_by(&:star_count).reverse, + projects_limit: 10, stars: true, avatar: true - - if @projects.present? - .tab-pane#personal - .personal-projects - = render 'shared/projects/list', - projects: @projects.sort_by(&:star_count).reverse, - projects_limit: 10, stars: true, avatar: true + - if @projects.present? + .tab-pane#personal + .personal-projects + = render 'shared/projects/list', + projects: @projects.sort_by(&:star_count).reverse, + projects_limit: 10, stars: true, avatar: true :javascript $(".user-calendar").load("#{user_calendar_path}"); -- cgit v1.2.1 From 5efbfa14d4666655edd6d79a3a352a134382b664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Wed, 13 Jan 2016 16:37:17 +0100 Subject: Move complex view condition to a model method This is moved to a model method rather than an helper method because the API will need it too. --- app/models/note.rb | 4 ++++ app/views/projects/notes/_notes.html.haml | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/models/note.rb b/app/models/note.rb index 3d5b663c99f..3e1375e5ad6 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -358,6 +358,10 @@ class Note < ActiveRecord::Base !system? && !is_award end + def cross_reference_not_visible_for?(user) + cross_reference? && referenced_mentionables(user).empty? + end + # Checks if note is an award added as a comment # # If note is an award, this method sets is_award to true diff --git a/app/views/projects/notes/_notes.html.haml b/app/views/projects/notes/_notes.html.haml index a4ff947c656..62db86fb181 100644 --- a/app/views/projects/notes/_notes.html.haml +++ b/app/views/projects/notes/_notes.html.haml @@ -2,11 +2,14 @@ - @discussions.each do |discussion_notes| - note = discussion_notes.first - if note_for_main_target?(note) + - next if note.cross_reference_not_visible_for?(current_user) + = render discussion_notes - else = render 'projects/notes/discussion', discussion_notes: discussion_notes - else - @notes.each do |note| - next unless note.author - - next if note.cross_reference? && note.referenced_mentionables(current_user).empty? + - next if note.cross_reference_not_visible_for?(current_user) + = render note -- cgit v1.2.1 From 48c45ba9a8a9a5536a3d501e40536cc5b73062a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Wed, 13 Jan 2016 10:58:19 -0500 Subject: Use html_safe instead of raw. #3945 --- app/views/projects/diffs/_parallel_view.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml index 77069501d1c..1ad54d1848b 100644 --- a/app/views/projects/diffs/_parallel_view.html.haml +++ b/app/views/projects/diffs/_parallel_view.html.haml @@ -20,7 +20,7 @@ = link_to raw(line_number_left), "##{line_code_left}", id: line_code_left - if @comments_allowed && can?(current_user, :create_note, @project) = link_to_new_diff_note(line_code_left, 'old') - %td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }= raw(line_content_left) + %td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }= line_content_left.html_safe - if type_right == 'new' - new_line_class = 'new' @@ -33,7 +33,7 @@ = link_to raw(line_number_right), "##{new_line_code}", id: new_line_code - if @comments_allowed && can?(current_user, :create_note, @project) = link_to_new_diff_note(line_code_right, 'new') - %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}= raw(line_content_right) + %td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}= line_content_right.html_safe - if @reply_allowed - comments_left, comments_right = organize_comments(type_left, type_right, line_code_left, line_code_right) -- cgit v1.2.1 From cf1a62e236bd74ce31eda3b07505664bed445a96 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Jan 2016 17:01:11 +0100 Subject: Add top margin for page title Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/typography.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index 714369d9f15..ab4f71af039 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -177,7 +177,7 @@ body { } .page-title { - margin-top: 0px; + margin-top: $gl-padding; line-height: 1.3; font-size: 1.25em; font-weight: 600; -- cgit v1.2.1 From 5e452d3794ffa4996611ecf53c6098f4a3913d4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Wed, 13 Jan 2016 16:38:42 +0100 Subject: Improve & adds specs for Issue/MR references - Improve specs for private Issue/MR referenced in public Issue - Add specs for private Issue/MR referenced in public MR --- features/project/issues/references.feature | 28 +++-- features/project/merge_requests/references.feature | 31 +++++ features/steps/project/issues/references.rb | 101 +--------------- .../steps/project/merge_requests/references.rb | 7 ++ features/steps/shared/issuable.rb | 134 +++++++++++++++++++++ features/steps/shared/note.rb | 4 +- features/steps/shared/project.rb | 48 +++++--- 7 files changed, 218 insertions(+), 135 deletions(-) create mode 100644 features/project/merge_requests/references.feature create mode 100644 features/steps/project/merge_requests/references.rb diff --git a/features/project/issues/references.feature b/features/project/issues/references.feature index bf7a4c6cb91..4ae2d653337 100644 --- a/features/project/issues/references.feature +++ b/features/project/issues/references.feature @@ -2,30 +2,32 @@ Feature: Project Issues References Background: Given I sign in as "John Doe" + And public project "Community" And "John Doe" owns public project "Community" - And project "Community" has "Public Issue 01" open issue + And project "Community" has "Community issue" open issue And I logout And I sign in as "Mary Jane" - And "Mary Jane" owns private project "Private Library" - And project "Private Library" has "Fix NS-01" open merge request - And project "Private Library" has "Private Issue 01" open issue - And I visit merge request page "Fix NS-01" - And I leave a comment referencing issue "Public Issue 01" from "Fix NS-01" merge request - And I visit issue page "Private Issue 01" - And I leave a comment referencing issue "Public Issue 01" from "Private Issue 01" issue + And private project "Enterprise" + And "Mary Jane" owns private project "Enterprise" + And project "Enterprise" has "Enterprise issue" open issue + And project "Enterprise" has "Enterprise fix" open merge request + And I visit issue page "Enterprise issue" + And I leave a comment referencing issue "Community issue" + And I visit merge request page "Enterprise fix" + And I leave a comment referencing issue "Community issue" And I logout @javascript Scenario: Viewing the public issue as a "John Doe" Given I sign in as "John Doe" - When I visit issue page "Public Issue 01" + When I visit issue page "Community issue" Then I should not see any related merge requests And I should see no notes at all @javascript Scenario: Viewing the public issue as "Mary Jane" Given I sign in as "Mary Jane" - When I visit issue page "Public Issue 01" - Then I should see the "Fix NS-01" related merge request - And I should see a note linking to "Fix NS-01" merge request - And I should see a note linking to "Private Issue 01" issue + When I visit issue page "Community issue" + Then I should see the "Enterprise fix" related merge request + And I should see a note linking to "Enterprise fix" merge request + And I should see a note linking to "Enterprise issue" issue diff --git a/features/project/merge_requests/references.feature b/features/project/merge_requests/references.feature new file mode 100644 index 00000000000..571612261a9 --- /dev/null +++ b/features/project/merge_requests/references.feature @@ -0,0 +1,31 @@ +@project_merge_requests +Feature: Project Merge Requests References + Background: + Given I sign in as "John Doe" + And public project "Community" + And "John Doe" owns public project "Community" + And project "Community" has "Community fix" open merge request + And I logout + And I sign in as "Mary Jane" + And private project "Enterprise" + And "Mary Jane" owns private project "Enterprise" + And project "Enterprise" has "Enterprise issue" open issue + And project "Enterprise" has "Enterprise fix" open merge request + And I visit issue page "Enterprise issue" + And I leave a comment referencing issue "Community fix" + And I visit merge request page "Enterprise fix" + And I leave a comment referencing issue "Community fix" + And I logout + + @javascript + Scenario: Viewing the public issue as a "John Doe" + Given I sign in as "John Doe" + When I visit issue page "Community fix" + Then I should see no notes at all + + @javascript + Scenario: Viewing the public issue as "Mary Jane" + Given I sign in as "Mary Jane" + When I visit issue page "Community fix" + And I should see a note linking to "Enterprise fix" merge request + And I should see a note linking to "Enterprise issue" issue diff --git a/features/steps/project/issues/references.rb b/features/steps/project/issues/references.rb index 9c7725e8c14..69e8b5cbde5 100644 --- a/features/steps/project/issues/references.rb +++ b/features/steps/project/issues/references.rb @@ -1,106 +1,7 @@ class Spinach::Features::ProjectIssuesReferences < Spinach::FeatureSteps include SharedAuthentication + include SharedIssuable include SharedNote include SharedProject include SharedUser - - step 'project "Community" has "Public Issue 01" open issue' do - project = Project.find_by(name: 'Community') - create(:issue, - title: 'Public Issue 01', - project: project, - author: project.users.first, - description: '# Description header' - ) - end - - step 'project "Private Library" has "Fix NS-01" open merge request' do - project = Project.find_by(name: 'Private Library') - create(:merge_request, - title: 'Fix NS-01', - source_project: project, - target_project: project, - source_branch: 'fix', - target_branch: 'master', - author: project.users.first, - description: '# Description header' - ) - end - - step 'project "Private Library" has "Private Issue 01" open issue' do - project = Project.find_by(name: 'Private Library') - create(:issue, - title: 'Private Issue 01', - project: project, - author: project.users.first, - description: '# Description header' - ) - end - - step 'I leave a comment referencing issue "Public Issue 01" from "Fix NS-01" merge request' do - project = Project.find_by(name: 'Private Library') - issue = Issue.find_by!(title: 'Public Issue 01') - - page.within(".js-main-target-form") do - fill_in "note[note]", with: "##{issue.to_reference(project)}" - click_button "Add Comment" - end - end - - step 'I leave a comment referencing issue "Public Issue 01" from "Private Issue 01" issue' do - project = Project.find_by(name: 'Private Library') - issue = Issue.find_by!(title: 'Public Issue 01') - - page.within(".js-main-target-form") do - fill_in "note[note]", with: "##{issue.to_reference(project)}" - click_button "Add Comment" - end - end - - step 'I visit merge request page "Fix NS-01"' do - mr = MergeRequest.find_by(title: "Fix NS-01") - visit namespace_project_merge_request_path(mr.target_project.namespace, mr.target_project, mr) - end - - step 'I visit issue page "Private Issue 01"' do - issue = Issue.find_by(title: "Private Issue 01") - visit namespace_project_issue_path(issue.project.namespace, issue.project, issue) - end - - step 'I visit issue page "Public Issue 01"' do - issue = Issue.find_by(title: "Public Issue 01") - visit namespace_project_issue_path(issue.project.namespace, issue.project, issue) - end - - step 'I should not see any related merge requests' do - page.within '.issue-details' do - expect(page).not_to have_content('.merge-requests') - end - end - - step 'I should see the "Fix NS-01" related merge request' do - page.within '.merge-requests' do - expect(page).to have_content("1 Related Merge Request") - expect(page).to have_content('Fix NS-01') - end - end - - step 'I should see a note linking to "Fix NS-01" merge request' do - project = Project.find_by(name: 'Community') - mr = MergeRequest.find_by(title: 'Fix NS-01') - page.within('.notes') do - expect(page).to have_content('Mary Jane') - expect(page).to have_content("mentioned in merge request #{mr.to_reference(project)}") - end - end - - step 'I should see a note linking to "Private Issue 01" issue' do - project = Project.find_by(name: 'Community') - issue = Issue.find_by(title: 'Private Issue 01') - page.within('.notes') do - expect(page).to have_content('Mary Jane') - expect(page).to have_content("mentioned in issue #{issue.to_reference(project)}") - end - end - end diff --git a/features/steps/project/merge_requests/references.rb b/features/steps/project/merge_requests/references.rb new file mode 100644 index 00000000000..ab2ae6847a2 --- /dev/null +++ b/features/steps/project/merge_requests/references.rb @@ -0,0 +1,7 @@ +class Spinach::Features::ProjectMergeRequestsReferences < Spinach::FeatureSteps + include SharedAuthentication + include SharedIssuable + include SharedNote + include SharedProject + include SharedUser +end diff --git a/features/steps/shared/issuable.rb b/features/steps/shared/issuable.rb index e6d1b8b8efc..4c5f7488efb 100644 --- a/features/steps/shared/issuable.rb +++ b/features/steps/shared/issuable.rb @@ -5,6 +5,99 @@ module SharedIssuable find(:css, '.issuable-edit').click end + step 'project "Community" has "Community issue" open issue' do + create_issuable_for_project( + project_name: 'Community', + title: 'Community issue' + ) + end + + step 'project "Community" has "Community fix" open merge request' do + create_issuable_for_project( + project_name: 'Community', + type: :merge_request, + title: 'Community fix' + ) + end + + step 'project "Enterprise" has "Enterprise issue" open issue' do + create_issuable_for_project( + project_name: 'Enterprise', + title: 'Enterprise issue' + ) + end + + step 'project "Enterprise" has "Enterprise fix" open merge request' do + create_issuable_for_project( + project_name: 'Enterprise', + type: :merge_request, + title: 'Enterprise fix' + ) + end + + step 'I leave a comment referencing issue "Community issue"' do + leave_reference_comment( + issuable: Issue.find_by(title: 'Community issue'), + from_project_name: 'Enterprise' + ) + end + + step 'I leave a comment referencing issue "Community fix"' do + leave_reference_comment( + issuable: MergeRequest.find_by(title: 'Community fix'), + from_project_name: 'Enterprise' + ) + end + + step 'I visit issue page "Enterprise issue"' do + issue = Issue.find_by(title: 'Enterprise issue') + visit namespace_project_issue_path(issue.project.namespace, issue.project, issue) + end + + step 'I visit merge request page "Enterprise fix"' do + mr = MergeRequest.find_by(title: 'Enterprise fix') + visit namespace_project_merge_request_path(mr.target_project.namespace, mr.target_project, mr) + end + + step 'I visit issue page "Community issue"' do + issue = Issue.find_by(title: 'Community issue') + visit namespace_project_issue_path(issue.project.namespace, issue.project, issue) + end + + step 'I visit issue page "Community fix"' do + mr = MergeRequest.find_by(title: 'Community fix') + visit namespace_project_merge_request_path(mr.target_project.namespace, mr.target_project, mr) + end + + step 'I should not see any related merge requests' do + page.within '.issue-details' do + expect(page).not_to have_content('.merge-requests') + end + end + + step 'I should see the "Enterprise fix" related merge request' do + page.within '.merge-requests' do + expect(page).to have_content('1 Related Merge Request') + expect(page).to have_content('Enterprise fix') + end + end + + step 'I should see a note linking to "Enterprise fix" merge request' do + visible_note( + issuable: MergeRequest.find_by(title: 'Enterprise fix'), + from_project_name: 'Community', + user_name: 'Mary Jane' + ) + end + + step 'I should see a note linking to "Enterprise issue" issue' do + visible_note( + issuable: Issue.find_by(title: 'Enterprise issue'), + from_project_name: 'Community', + user_name: 'Mary Jane' + ) + end + step 'I click link "Edit" for the merge request' do edit_issuable end @@ -12,4 +105,45 @@ module SharedIssuable step 'I click link "Edit" for the issue' do edit_issuable end + + def create_issuable_for_project(project_name:, title:, type: :issue) + project = Project.find_by(name: project_name) + + attrs = { + title: title, + author: project.users.first, + description: '# Description header' + } + + case type + when :issue + attrs.merge!(project: project) + when :merge_request + attrs.merge!( + source_project: project, + target_project: project, + source_branch: 'fix', + target_branch: 'master' + ) + end + + create(type, attrs) + end + + def leave_reference_comment(issuable:, from_project_name:) + project = Project.find_by(name: from_project_name) + + page.within('.js-main-target-form') do + fill_in 'note[note]', with: "##{issuable.to_reference(project)}" + click_button 'Add Comment' + end + end + + def visible_note(issuable:, from_project_name:, user_name:) + project = Project.find_by(name: from_project_name) + + expect(page).to have_content(user_name) + expect(page).to have_content("mentioned in #{issuable.class.to_s.titleize.downcase} #{issuable.to_reference(project)}") + end + end diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb index 6de58c6e2b1..444d6726f99 100644 --- a/features/steps/shared/note.rb +++ b/features/steps/shared/note.rb @@ -107,9 +107,7 @@ module SharedNote end step 'I should see no notes at all' do - page.within('.notes') do - expect(page).to_not have_css('.note') - end + expect(page).to_not have_css('.note') end # Markdown diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb index 43a15f43470..5420c451519 100644 --- a/features/steps/shared/project.rb +++ b/features/steps/shared/project.rb @@ -161,31 +161,33 @@ module SharedProject end step '"John Doe" owns private project "Enterprise"' do - user = user_exists("John Doe", username: "john_doe") - project = Project.find_by(name: "Enterprise") - project ||= create(:empty_project, name: "Enterprise", namespace: user.namespace) - project.team << [user, :master] + user_owns_project( + user_name: 'John Doe', + project_name: 'Enterprise' + ) end - step '"John Doe" owns internal project "Internal"' do - user = user_exists("John Doe", username: "john_doe") - project = Project.find_by(name: "Internal") - project ||= create :empty_project, :internal, name: 'Internal', namespace: user.namespace - project.team << [user, :master] + step '"Mary Jane" owns private project "Enterprise"' do + user_owns_project( + user_name: 'Mary Jane', + project_name: 'Enterprise' + ) end - step '"John Doe" owns public project "Community"' do - user = user_exists("John Doe", username: "john_doe") - project = Project.find_by(name: "Community") - project ||= create :empty_project, :public, name: 'Community', namespace: user.namespace - project.team << [user, :master] + step '"John Doe" owns internal project "Internal"' do + user_owns_project( + user_name: 'John Doe', + project_name: 'Internal', + visibility: :internal + ) end - step '"Mary Jane" owns private project "Private Library"' do - user = user_exists('Mary Jane', username: 'mary_jane') - project = Project.find_by(name: 'Private Library') - project ||= create(:project, name: 'Private Library', namespace: user.namespace) - project.team << [user, :master] + step '"John Doe" owns public project "Community"' do + user_owns_project( + user_name: 'John Doe', + project_name: 'Community', + visibility: :public + ) end step 'public empty project "Empty Public Project"' do @@ -220,4 +222,12 @@ module SharedProject expect(page).to have_content("skipped") end end + + def user_owns_project(user_name:, project_name:, visibility: :private) + user = user_exists(user_name, username: user_name.underscore) + project = Project.find_by(name: project_name) + project ||= create(:empty_project, visibility, name: project_name, namespace: user.namespace) + project.team << [user, :master] + end + end -- cgit v1.2.1 From 76b3ca72053633a17bba2f8a21f1672a88af3765 Mon Sep 17 00:00:00 2001 From: Patricio Cano Date: Wed, 13 Jan 2016 11:06:33 -0500 Subject: Added hint that you can search users by name, username, or email. --- app/views/groups/group_members/_new_group_member.html.haml | 2 +- app/views/projects/project_members/_new_project_member.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/groups/group_members/_new_group_member.html.haml b/app/views/groups/group_members/_new_group_member.html.haml index 3361d7e2a8d..e7ab4f2409b 100644 --- a/app/views/groups/group_members/_new_group_member.html.haml +++ b/app/views/groups/group_members/_new_group_member.html.haml @@ -4,7 +4,7 @@ .col-sm-10 = users_select_tag(:user_ids, multiple: true, class: 'input-large', scope: :all, email_user: true) .help-block - Search for existing users or invite new ones using their email address. + Search for users by name, username, or email, or invite new ones using their email address. .form-group = f.label :access_level, "Group Access", class: 'control-label' diff --git a/app/views/projects/project_members/_new_project_member.html.haml b/app/views/projects/project_members/_new_project_member.html.haml index d708b01a114..f0f3bb3c177 100644 --- a/app/views/projects/project_members/_new_project_member.html.haml +++ b/app/views/projects/project_members/_new_project_member.html.haml @@ -4,7 +4,7 @@ .col-sm-10 = users_select_tag(:user_ids, multiple: true, class: 'input-large', scope: :all, email_user: true) .help-block - Search for existing users or invite new ones using their email address. + Search for users by name, username, or email, or invite new ones using their email address. .form-group = f.label :access_level, "Project Access", class: 'control-label' -- cgit v1.2.1 From 3238b0bc9fddd1a00d4926a7679c454db03d6fed Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 13 Jan 2016 17:13:36 +0100 Subject: Replace nav-tabs with nav-links Signed-off-by: Dmitriy Zaporozhets --- .../javascripts/merge_request_tabs.js.coffee | 2 +- .../stylesheets/framework/markdown_area.scss | 17 ------------ app/assets/stylesheets/framework/mobile.scss | 2 +- app/assets/stylesheets/framework/tw_bootstrap.scss | 31 ---------------------- app/assets/stylesheets/pages/projects.scss | 22 --------------- app/views/admin/logs/show.html.haml | 5 ++-- app/views/admin/users/_head.html.haml | 3 ++- app/views/devise/shared/_signin_box.html.haml | 2 +- app/views/search/_category.html.haml | 2 +- app/views/search/_results.html.haml | 2 +- app/views/search/show.html.haml | 4 ++- 11 files changed, 13 insertions(+), 79 deletions(-) diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee index 9e2dc1250c9..b10e1db7f3f 100644 --- a/app/assets/javascripts/merge_request_tabs.js.coffee +++ b/app/assets/javascripts/merge_request_tabs.js.coffee @@ -5,7 +5,7 @@ # # ### Example Markup # -#