From 1898cb03d0c31534d8d82ef389e6858e1e6c6185 Mon Sep 17 00:00:00 2001 From: Fatih Acet Date: Tue, 21 Jun 2016 00:05:33 +0300 Subject: [PATCH 01/98] Added global ajax error handler to show a flash notification for failed requests. --- CHANGELOG | 1 + app/assets/javascripts/application.js.coffee | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 118dd79dda..a4709f7fa8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -145,6 +145,7 @@ v 8.9.0 (unreleased) - Filter parameters for request_uri value on instrumented transactions. - Remove duplicated keys add UNIQUE index to keys fingerprint column - ExtractsPath get ref_names from repository cache, if not there access git. + - Show a flash warning about the error detail of XHR requests which failed with status code 404 and 500 - Cache user todo counts from TodoService - Ensure Todos counters doesn't count Todos for projects pending delete - Add left/right arrows horizontal navigation diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee index 0206db461d..0b68612430 100644 --- a/app/assets/javascripts/application.js.coffee +++ b/app/assets/javascripts/application.js.coffee @@ -185,6 +185,15 @@ $ -> else buttons.enable() + $(document).ajaxError (e, xhrObj, xhrSetting, xhrErrorText) -> + + if xhrObj.status is 401 + new Flash 'You need to be logged in.', 'alert' + + else if xhrObj.status in [ 404, 500 ] + new Flash 'Something went wrong on our end.', 'alert' + + # Show/Hide the profile menu when hovering the account box $('.account-box').hover -> $(@).toggleClass('hover') From a6045538909ac9171bbeb5bf664f63ae9e71c3ff Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Wed, 22 Jun 2016 16:02:44 -0600 Subject: [PATCH 02/98] Adds focus state style to markdown area buttons. --- app/assets/stylesheets/framework/markdown_area.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss index fd8eaa8a69..5d3273ea64 100644 --- a/app/assets/stylesheets/framework/markdown_area.scss +++ b/app/assets/stylesheets/framework/markdown_area.scss @@ -125,7 +125,8 @@ border: 0; outline: 0; - &:hover { + &:hover, + &:focus { color: $gl-link-color; } } From d334f8d4fa434f92cac99e5cecba62f8822acae9 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 24 Jun 2016 11:31:36 +0100 Subject: [PATCH 03/98] Fixed URL on label button when filtering Closes #19005 --- app/helpers/labels_helper.rb | 12 ++++++++---- app/views/shared/_labels_row.html.haml | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb index 5074e64576..5e9f583710 100644 --- a/app/helpers/labels_helper.rb +++ b/app/helpers/labels_helper.rb @@ -34,10 +34,7 @@ module LabelsHelper # Returns a String def link_to_label(label, project: nil, type: :issue, tooltip: true, css_class: nil, &block) project ||= @project || label.project - link = send("namespace_project_#{type.to_s.pluralize}_path", - project.namespace, - project, - label_name: [label.name]) + link = label_filter_path(project, label, type: type) if block_given? link_to link, class: css_class, &block @@ -46,6 +43,13 @@ module LabelsHelper end end + def label_filter_path(project, label, type: issue) + send("namespace_project_#{type.to_s.pluralize}_path", + project.namespace, + project, + label_name: [label.name]) + end + def project_label_names @project.labels.pluck(:title) end diff --git a/app/views/shared/_labels_row.html.haml b/app/views/shared/_labels_row.html.haml index 87028ececd..5507a05f6c 100644 --- a/app/views/shared/_labels_row.html.haml +++ b/app/views/shared/_labels_row.html.haml @@ -1,6 +1,6 @@ - labels.each do |label| %span.label-row.btn-group{ role: "group", aria: { label: escape_once(label.name) }, style: "color: #{text_color_for_bg(label.color)}" } - = link_to namespace_project_label_path(@project.namespace, @project, label), + = link_to label_filter_path(@project, label, type: controller.controller_name), class: "btn btn-transparent has-tooltip", style: "background-color: #{label.color};", title: escape_once(label.description), From 0bba8adf8f197cd4a0e6eb0f18346c379aa0d85f Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 27 Jun 2016 10:59:56 +0100 Subject: [PATCH 04/98] Fixed comit avatar alignment --- app/assets/stylesheets/pages/commits.scss | 10 ++-------- app/assets/stylesheets/pages/tree.scss | 3 ++- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index de534d2842..85bbf70e18 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -83,11 +83,7 @@ position: relative; @media (min-width: $screen-sm-min) { - padding-left: 20px; - - .commit-info-block { - padding-left: 44px; - } + padding-left: 46px; } &:not(:last-child) { @@ -102,9 +98,7 @@ .avatar { - position: absolute; - top: 10px; - left: 16px; + margin-left: -46px; } .item-title { diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index 99c9e81ddb..5b61270daa 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -101,7 +101,8 @@ margin: 0; .commit { - padding: 0 0 0 55px; + padding-top: 0; + padding-bottom: 0; .commit-row-title { .commit-row-message { From d3d0e3dd5de9d00cbb6c8f2ec3c82bfdbb146ff3 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 13 Jun 2016 17:43:29 -0400 Subject: [PATCH 05/98] Update `Gitlab.com?` to support staging --- lib/gitlab.rb | 7 ++++++- spec/lib/gitlab_spec.rb | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/gitlab.rb b/lib/gitlab.rb index 37f4c34054..c3064163e0 100644 --- a/lib/gitlab.rb +++ b/lib/gitlab.rb @@ -2,6 +2,11 @@ require_dependency 'gitlab/git' module Gitlab def self.com? - Gitlab.config.gitlab.url == 'https://gitlab.com' + # Check `staging?` as well to keep parity with gitlab.com + Gitlab.config.gitlab.url == 'https://gitlab.com' || staging? + end + + def self.staging? + Gitlab.config.gitlab.url == 'https://staging.gitlab.com' end end diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb index c59dfea5c5..c4c107c9ee 100644 --- a/spec/lib/gitlab_spec.rb +++ b/spec/lib/gitlab_spec.rb @@ -8,6 +8,12 @@ describe Gitlab, lib: true do expect(described_class.com?).to eq true end + it 'is true when on staging' do + stub_config_setting(url: 'https://staging.gitlab.com') + + expect(described_class.com?).to eq true + end + it 'is false when not on GitLab.com' do stub_config_setting(url: 'http://example.com') From 95c99cd4fd0f768394d582ac49dc83ac93d9c1e5 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 28 Jun 2016 13:46:47 +0800 Subject: [PATCH 06/98] Admin should be able to turn shared runners into specific ones: The regression was introduced by: https://gitlab.com/gitlab-org/gitlab-ce/commit/1b8f52d9206bdf19c0dde04505c4c0b1cf46cfbe I did that because there's a test specifying that a shared runner cannot be enabled, in the API. So I assume that is the case for non-admin, but admins should be able to do so anyway. Also added a test to make sure this won't regress again. Closes #19039 --- .../admin/runner_projects_controller.rb | 2 +- spec/features/admin/admin_runners_spec.rb | 32 ++++++++++++++----- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/app/controllers/admin/runner_projects_controller.rb b/app/controllers/admin/runner_projects_controller.rb index bf20c5305a..5de06b4ad1 100644 --- a/app/controllers/admin/runner_projects_controller.rb +++ b/app/controllers/admin/runner_projects_controller.rb @@ -4,7 +4,7 @@ class Admin::RunnerProjectsController < Admin::ApplicationController def create @runner = Ci::Runner.find(params[:runner_project][:runner_id]) - return head(403) if @runner.is_shared? || @runner.locked? + return head(403) if @runner.locked? runner_project = @runner.assign_to(@project, current_user) diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb index 2d297776cb..f2814c6038 100644 --- a/spec/features/admin/admin_runners_spec.rb +++ b/spec/features/admin/admin_runners_spec.rb @@ -62,19 +62,35 @@ describe "Admin Runners" do end describe 'enable/create' do - before do - @project1.runners << runner - visit admin_runner_path(runner) + shared_examples 'enable runners' do + it 'enables a runner for a project' do + within '.unassigned-projects' do + click_on 'Enable' + end + + assigned_project = page.find('.assigned-projects') + + expect(assigned_project).to have_content(@project2.path) + end end - it 'enables specific runner for project' do - within '.unassigned-projects' do - click_on 'Enable' + context 'with specific runner' do + before do + @project1.runners << runner + visit admin_runner_path(runner) end - assigned_project = page.find('.assigned-projects') + it_behaves_like 'enable runners' + end - expect(assigned_project).to have_content(@project2.path) + context 'with shared runner' do + before do + @project1.destroy + runner.update(is_shared: true) + visit admin_runner_path(runner) + end + + it_behaves_like 'enable runners' end end From d08777b1a4ead4cc15089e9d0d333d91de56ee1e Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 28 Jun 2016 18:33:25 +0800 Subject: [PATCH 07/98] Rename to assignable runner for shared examples: Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4961#note_12738607 --- spec/features/admin/admin_runners_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb index f2814c6038..05b3b700b8 100644 --- a/spec/features/admin/admin_runners_spec.rb +++ b/spec/features/admin/admin_runners_spec.rb @@ -62,7 +62,7 @@ describe "Admin Runners" do end describe 'enable/create' do - shared_examples 'enable runners' do + shared_examples 'assignable runner' do it 'enables a runner for a project' do within '.unassigned-projects' do click_on 'Enable' @@ -80,7 +80,7 @@ describe "Admin Runners" do visit admin_runner_path(runner) end - it_behaves_like 'enable runners' + it_behaves_like 'assignable runner' end context 'with shared runner' do @@ -90,7 +90,7 @@ describe "Admin Runners" do visit admin_runner_path(runner) end - it_behaves_like 'enable runners' + it_behaves_like 'assignable runner' end end From 0d6d8376e6038d2a0fb30f3f9916c9e3788fa275 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 27 Jun 2016 11:02:54 +0100 Subject: [PATCH 08/98] Build path sends JSON file path --- app/views/projects/builds/show.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml index 4e2702c2e4..d1c468c469 100644 --- a/app/views/projects/builds/show.html.haml +++ b/app/views/projects/builds/show.html.haml @@ -67,4 +67,4 @@ = render "sidebar" :javascript - new CiBuild("#{namespace_project_build_url(@project.namespace, @project, @build)}", "#{@build.status}", "#{trace_with_state[:state]}") + new CiBuild("#{namespace_project_build_url(@project.namespace, @project, @build, :json)}", "#{@build.status}", "#{trace_with_state[:state]}") From b5c8d58afb7840acd9c26129b2ff0c0fe3f2586e Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 28 Jun 2016 19:54:18 +0800 Subject: [PATCH 09/98] Use 409 to indicate that interface might be outdated Because invalid actions shouldn't be shown on the page. --- app/controllers/projects/runner_projects_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/projects/runner_projects_controller.rb b/app/controllers/projects/runner_projects_controller.rb index dc1a18f8d4..dc82555792 100644 --- a/app/controllers/projects/runner_projects_controller.rb +++ b/app/controllers/projects/runner_projects_controller.rb @@ -6,8 +6,8 @@ class Projects::RunnerProjectsController < Projects::ApplicationController def create @runner = Ci::Runner.find(params[:runner_project][:runner_id]) - return head(403) if @runner.is_shared? || @runner.locked? - return head(403) unless current_user.ci_authorized_runners.include?(@runner) + return head(409) if @runner.is_shared? || @runner.locked? + return head(409) unless current_user.ci_authorized_runners.include?(@runner) path = runners_path(project) runner_project = @runner.assign_to(project, current_user) From 397a69f834ad8854301df4c09035e16d35ac5158 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 28 Jun 2016 19:55:12 +0800 Subject: [PATCH 10/98] Allow admins to assign locked runners: And show information about locked status. Help! This looks bad :o --- app/controllers/admin/runner_projects_controller.rb | 2 -- app/views/admin/runners/_runner.html.haml | 2 ++ app/views/admin/runners/index.html.haml | 3 +++ app/views/admin/runners/show.html.haml | 3 +++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/controllers/admin/runner_projects_controller.rb b/app/controllers/admin/runner_projects_controller.rb index 5de06b4ad1..bc65dcc33d 100644 --- a/app/controllers/admin/runner_projects_controller.rb +++ b/app/controllers/admin/runner_projects_controller.rb @@ -4,8 +4,6 @@ class Admin::RunnerProjectsController < Admin::ApplicationController def create @runner = Ci::Runner.find(params[:runner_project][:runner_id]) - return head(403) if @runner.locked? - runner_project = @runner.assign_to(@project, current_user) if runner_project.persisted? diff --git a/app/views/admin/runners/_runner.html.haml b/app/views/admin/runners/_runner.html.haml index 36b21eefde..875fa086db 100644 --- a/app/views/admin/runners/_runner.html.haml +++ b/app/views/admin/runners/_runner.html.haml @@ -4,6 +4,8 @@ %span.label.label-success shared - else %span.label.label-info specific + - if runner.locked? + %span.label.label-danger locked - unless runner.active? %span.label.label-danger paused diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml index 5eff77aff2..24b2312d20 100644 --- a/app/views/admin/runners/index.html.haml +++ b/app/views/admin/runners/index.html.haml @@ -39,6 +39,9 @@ %li %span.label.label-info specific \- run builds from assigned projects + %li + %span.label.label-danger locked + \- runner cannot be assigned to other projects %li %span.label.label-danger paused \- runner will not receive any new builds diff --git a/app/views/admin/runners/show.html.haml b/app/views/admin/runners/show.html.haml index 61abfc6ecb..6b3aa122c8 100644 --- a/app/views/admin/runners/show.html.haml +++ b/app/views/admin/runners/show.html.haml @@ -64,6 +64,9 @@ = project.name_with_namespace %td .pull-right + - if @runner.locked? + = icon('lock', class: 'has-tooltip', title: 'Locked to current projects') + = form_for [:admin, project.namespace.becomes(Namespace), project, project.runner_projects.new] do |f| = f.hidden_field :runner_id, value: @runner.id = f.submit 'Enable', class: 'btn btn-xs' From 2b5211833342fb31201030d84a9e0caf2c8cceb8 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 28 Jun 2016 20:10:42 +0800 Subject: [PATCH 11/98] They're projects, so we shouldn't show lock icon --- app/views/admin/runners/show.html.haml | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/views/admin/runners/show.html.haml b/app/views/admin/runners/show.html.haml index 6b3aa122c8..61abfc6ecb 100644 --- a/app/views/admin/runners/show.html.haml +++ b/app/views/admin/runners/show.html.haml @@ -64,9 +64,6 @@ = project.name_with_namespace %td .pull-right - - if @runner.locked? - = icon('lock', class: 'has-tooltip', title: 'Locked to current projects') - = form_for [:admin, project.namespace.becomes(Namespace), project, project.runner_projects.new] do |f| = f.hidden_field :runner_id, value: @runner.id = f.submit 'Enable', class: 'btn btn-xs' From deb5509f7bc3eec8fa47939144a52cda7d408625 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 28 Jun 2016 20:15:50 +0800 Subject: [PATCH 12/98] Admins should be able to assign locked runners as well --- spec/features/admin/admin_runners_spec.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb index 05b3b700b8..2f82fafc13 100644 --- a/spec/features/admin/admin_runners_spec.rb +++ b/spec/features/admin/admin_runners_spec.rb @@ -83,6 +83,16 @@ describe "Admin Runners" do it_behaves_like 'assignable runner' end + context 'with locked runner' do + before do + runner.update(locked: true) + @project1.runners << runner + visit admin_runner_path(runner) + end + + it_behaves_like 'assignable runner' + end + context 'with shared runner' do before do @project1.destroy From 8a27e8bb047ed45081a79f0a1429597c8f494299 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Tue, 28 Jun 2016 17:19:59 +0100 Subject: [PATCH 13/98] Disabled native autocomplete for dropdown filter inputs --- app/helpers/dropdowns_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/dropdowns_helper.rb b/app/helpers/dropdowns_helper.rb index 6b617e1730..7c14053801 100644 --- a/app/helpers/dropdowns_helper.rb +++ b/app/helpers/dropdowns_helper.rb @@ -69,7 +69,7 @@ module DropdownsHelper def dropdown_filter(placeholder, search_id: nil) content_tag :div, class: "dropdown-input" do - filter_output = search_field_tag search_id, nil, class: "dropdown-input-field", placeholder: placeholder + filter_output = search_field_tag search_id, nil, class: "dropdown-input-field", placeholder: placeholder, autocomplete: 'off' filter_output << icon('search', class: "dropdown-input-search") filter_output << icon('times', class: "dropdown-input-clear js-dropdown-input-clear", role: "button") From 3ce174c370cf45098bd592ac071e095b9f877363 Mon Sep 17 00:00:00 2001 From: Drew Blessing Date: Tue, 28 Jun 2016 15:51:50 -0500 Subject: [PATCH 14/98] Fix restore warning message --- CHANGELOG | 1 + lib/tasks/gitlab/backup.rake | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 047debbcd2..b5f8f42302 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -20,6 +20,7 @@ v 8.10.0 (unreleased) v 8.9.3 (unreleased) - Decreased min width of screen to 1280px for pinned sidebar + - Fix restore Rake task warning message output !4980 - Fix encrypted data backwards compatibility after upgrading attr_encrypted gem - Update mobile button icons to be more inline with typical UI paradigms diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake index 9ee72fde92..b43ee5b338 100644 --- a/lib/tasks/gitlab/backup.rake +++ b/lib/tasks/gitlab/backup.rake @@ -33,12 +33,13 @@ namespace :gitlab do unless backup.skipped?('db') unless ENV['force'] == 'yes' - warning = warning = <<-MSG.strip_heredoc + warning = <<-MSG.strip_heredoc Before restoring the database we recommend removing all existing tables to avoid future upgrade problems. Be aware that if you have custom tables in the GitLab database these tables and all data will be removed. MSG + puts warning.color(:red) ask_to_continue puts 'Removing all tables. Press `Ctrl-C` within 5 seconds to abort'.color(:yellow) sleep(5) From 3d2a73667983aefda9464d8651d5d59d617a4b95 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 29 Jun 2016 10:35:26 +0200 Subject: [PATCH 15/98] fixing events for import/export --- app/models/concerns/eventable.rb | 15 +++++++++++++++ app/models/issue.rb | 1 + app/models/merge_request.rb | 1 + app/models/milestone.rb | 1 + app/models/note.rb | 1 + lib/gitlab/import_export/import_export.yml | 15 ++++++++++----- .../import_export/project_tree_saver_spec.rb | 7 +++++-- 7 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 app/models/concerns/eventable.rb diff --git a/app/models/concerns/eventable.rb b/app/models/concerns/eventable.rb new file mode 100644 index 0000000000..fa6a4bfa8d --- /dev/null +++ b/app/models/concerns/eventable.rb @@ -0,0 +1,15 @@ +module Eventable + extend ActiveSupport::Concern + + def events + Event.where(target_id: id, target_type: self.class.to_s) + end + + def events=(events) + events.each do |event| + event.target_id = id + event.data.deep_symbolize_keys! + event.save! + end + end +end \ No newline at end of file diff --git a/app/models/issue.rb b/app/models/issue.rb index 3c5859194b..ae177c041e 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -6,6 +6,7 @@ class Issue < ActiveRecord::Base include Referable include Sortable include Taskable + include Eventable DueDateStruct = Struct.new(:title, :name).freeze NoDueDate = DueDateStruct.new('No Due Date', '0').freeze diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 53d9aa588a..326a0430eb 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -5,6 +5,7 @@ class MergeRequest < ActiveRecord::Base include Sortable include Taskable include Importable + include Eventable belongs_to :target_project, foreign_key: :target_project_id, class_name: "Project" belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project" diff --git a/app/models/milestone.rb b/app/models/milestone.rb index e0c8454a99..2283376c8a 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -11,6 +11,7 @@ class Milestone < ActiveRecord::Base include Referable include StripAttribute include Milestoneish + include Eventable belongs_to :project has_many :issues diff --git a/app/models/note.rb b/app/models/note.rb index 8db500a521..ed26fb2d88 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -5,6 +5,7 @@ class Note < ActiveRecord::Base include Mentionable include Awardable include Importable + include Eventable # Attribute containing rendered and redacted Markdown as generated by # Banzai::ObjectRenderer. diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml index 164ab6238c..05f4ad527a 100644 --- a/lib/gitlab/import_export/import_export.yml +++ b/lib/gitlab/import_export/import_export.yml @@ -1,24 +1,29 @@ # Model relationships to be included in the project import/export project_tree: - issues: + - :events - notes: - :author + - :author + - :events - :labels - - :milestones + - milestones: + - :events - snippets: - notes: :author - :releases - - :events - project_members: - :user - merge_requests: - notes: - :author + - :author + - :events - :merge_request_diff + - :events - pipelines: - notes: - :author + - :author + - :events - :statuses - :variables - :triggers diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb index 8d29b2f8fd..3b98045a2f 100644 --- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb @@ -34,7 +34,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do end it 'has events' do - expect(saved_project_json['events']).not_to be_empty + expect(saved_project_json['milestones'].first['events']).not_to be_empty end it 'has milestones' do @@ -132,7 +132,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do statuses: [commit_status]) create(:ci_build, pipeline: ci_pipeline, project: project) - create(:milestone, project: project) + milestone = create(:milestone, project: project) create(:note, noteable: issue, project: project) create(:note, noteable: merge_request, project: project) create(:note, noteable: snippet, project: project) @@ -140,6 +140,9 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do author: user, project: project, commit_id: ci_pipeline.sha) + + create(:event, target: milestone, project: project, action: Event::CREATED, author: user) + project end From 5cd3d7c40a19f85e977e6c9080170ef6ce679209 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 29 Jun 2016 10:49:31 +0200 Subject: [PATCH 16/98] bump version - as old exports wont be compatible --- lib/gitlab/import_export.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gitlab/import_export.rb b/lib/gitlab/import_export.rb index 99cf85d9a3..588647e5ad 100644 --- a/lib/gitlab/import_export.rb +++ b/lib/gitlab/import_export.rb @@ -2,7 +2,7 @@ module Gitlab module ImportExport extend self - VERSION = '0.1.0' + VERSION = '0.1.1' def export_path(relative_path:) File.join(storage_path, relative_path) From 23a3ce946ad0f7ef1c63036bf313cd549d18f0ab Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 29 Jun 2016 19:04:06 +0800 Subject: [PATCH 17/98] Use Ability to check pre-requisite. Change back to 403 because: If we're using `can?` it would look weird to use 409 --- .../projects/runner_projects_controller.rb | 3 +-- app/models/ability.rb | 13 +++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/controllers/projects/runner_projects_controller.rb b/app/controllers/projects/runner_projects_controller.rb index dc82555792..8267b14941 100644 --- a/app/controllers/projects/runner_projects_controller.rb +++ b/app/controllers/projects/runner_projects_controller.rb @@ -6,8 +6,7 @@ class Projects::RunnerProjectsController < Projects::ApplicationController def create @runner = Ci::Runner.find(params[:runner_project][:runner_id]) - return head(409) if @runner.is_shared? || @runner.locked? - return head(409) unless current_user.ci_authorized_runners.include?(@runner) + return head(403) unless can?(current_user, :assign_runner, @runner) path = runners_path(project) runner_project = @runner.assign_to(project, current_user) diff --git a/app/models/ability.rb b/app/models/ability.rb index f5950879cc..0add2f5a34 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -19,6 +19,7 @@ class Ability when ProjectMember then project_member_abilities(user, subject) when User then user_abilities when ExternalIssue, Deployment, Environment then project_abilities(user, subject.project) + when Ci::Runner then runner_abilities(user, subject) else [] end.concat(global_abilities(user)) end @@ -512,6 +513,18 @@ class Ability rules end + def runner_abilities(user, runner) + if user.is_admin? + [:assign_runner] + elsif runner.is_shared? || runner.locked? + [] + elsif user.ci_authorized_runners.include?(runner) + [:assign_runner] + else + [] + end + end + def user_abilities [:read_user] end From a65cf77ed9912202412c17701562693e06c033c4 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 29 Jun 2016 13:11:26 +0200 Subject: [PATCH 18/98] fixes and refactored JSON spec --- app/models/concerns/eventable.rb | 2 +- spec/lib/gitlab/import_export/project.json | 9262 ++++++++++++-------- 2 files changed, 5641 insertions(+), 3623 deletions(-) diff --git a/app/models/concerns/eventable.rb b/app/models/concerns/eventable.rb index fa6a4bfa8d..56aa7176de 100644 --- a/app/models/concerns/eventable.rb +++ b/app/models/concerns/eventable.rb @@ -8,7 +8,7 @@ module Eventable def events=(events) events.each do |event| event.target_id = id - event.data.deep_symbolize_keys! + event.data.deep_symbolize_keys! if event.data event.save! end end diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json index 403bd582ef..0b30e8c9b0 100644 --- a/spec/lib/gitlab/import_export/project.json +++ b/spec/lib/gitlab/import_export/project.json @@ -1,209 +1,39 @@ { - "name": "Gitlab Test", - "path": "gitlab-test", - "description": "Aut saepe in eos dolorem aliquam hic.", + "description": "Nisi et repellendus ut enim quo accusamus vel magnam.", "issues_enabled": true, "merge_requests_enabled": true, "wiki_enabled": true, "snippets_enabled": false, - "visibility_level": 20, + "visibility_level": 10, "archived": false, "issues": [ { "id": 40, - "title": "Voluptatem modi rerum ipsum vero voluptas repudiandae veniam quibusdam.", + "title": "Voluptatem amet doloribus deleniti eos maxime repudiandae molestias.", "assignee_id": 1, - "author_id": 4, + "author_id": 22, "project_id": 5, - "created_at": "2016-03-22T15:13:28.411Z", - "updated_at": "2016-04-12T13:08:26.029Z", + "created_at": "2016-06-14T15:02:08.340Z", + "updated_at": "2016-06-14T15:02:47.967Z", "position": 0, "branch_name": null, - "description": "Aut minima non sit qui nulla rerum laborum.", - "milestone_id": 10, + "description": "Aliquam enim illo et possimus.", + "milestone_id": 18, "state": "opened", "iid": 10, "updated_by_id": null, "confidential": false, "deleted_at": null, - "moved_to_id": null, "due_date": null, + "moved_to_id": null, "notes": [ { - "id": 1357, - "note": "test", - "noteable_type": "Issue", - "author_id": 1, - "created_at": "2016-04-12T13:08:26.006Z", - "updated_at": "2016-04-12T13:08:26.006Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": "", - "noteable_id": 40, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 338, - "note": "Fugit in aliquid voluptas dolor.", - "noteable_type": "Issue", - "author_id": 1, - "created_at": "2016-03-22T15:19:59.213Z", - "updated_at": "2016-03-22T15:19:59.213Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 40, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 337, - "note": "Occaecati consequatur facilis doloribus omnis hic placeat nihil.", - "noteable_type": "Issue", - "author_id": 3, - "created_at": "2016-03-22T15:19:59.186Z", - "updated_at": "2016-03-22T15:19:59.186Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 40, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 336, - "note": "Nostrum et et est repudiandae non dolores voluptatem.", - "noteable_type": "Issue", - "author_id": 4, - "created_at": "2016-03-22T15:19:59.156Z", - "updated_at": "2016-03-22T15:19:59.156Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 40, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 335, - "note": "Nihil et aut dolorum aut sit maxime.", - "noteable_type": "Issue", - "author_id": 10, - "created_at": "2016-03-22T15:19:59.130Z", - "updated_at": "2016-03-22T15:19:59.130Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 40, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 334, - "note": "Non blanditiis voluptatem sit earum accusantium distinctio voluptas officiis.", - "noteable_type": "Issue", - "author_id": 12, - "created_at": "2016-03-22T15:19:59.101Z", - "updated_at": "2016-03-22T15:19:59.101Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 40, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 333, - "note": "Nesciunt non dolorem similique nam ipsa et.", - "noteable_type": "Issue", - "author_id": 22, - "created_at": "2016-03-22T15:19:59.075Z", - "updated_at": "2016-03-22T15:19:59.075Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 40, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 332, - "note": "Sed aut fugit et officiis dolor.", - "noteable_type": "Issue", - "author_id": 24, - "created_at": "2016-03-22T15:19:59.047Z", - "updated_at": "2016-03-22T15:19:59.047Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 40, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 331, - "note": "Officiis iste eum recusandae suscipit consequatur consequatur.", + "id": 351, + "note": "Quo reprehenderit aliquam qui dicta impedit cupiditate eligendi.", "noteable_type": "Issue", "author_id": 26, - "created_at": "2016-03-22T15:19:59.015Z", - "updated_at": "2016-03-22T15:19:59.015Z", + "created_at": "2016-06-14T15:02:47.770Z", + "updated_at": "2016-06-14T15:02:47.770Z", "project_id": 5, "attachment": { "url": null @@ -214,186 +44,210 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] + }, + { + "id": 352, + "note": "Est reprehenderit quas aut aspernatur autem recusandae voluptatem.", + "noteable_type": "Issue", + "author_id": 25, + "created_at": "2016-06-14T15:02:47.795Z", + "updated_at": "2016-06-14T15:02:47.795Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 40, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 353, + "note": "Perspiciatis suscipit voluptates in eius nihil.", + "noteable_type": "Issue", + "author_id": 22, + "created_at": "2016-06-14T15:02:47.823Z", + "updated_at": "2016-06-14T15:02:47.823Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 40, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 354, + "note": "Aut vel voluptas corrupti nisi provident laboriosam magnam aut.", + "noteable_type": "Issue", + "author_id": 20, + "created_at": "2016-06-14T15:02:47.850Z", + "updated_at": "2016-06-14T15:02:47.850Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 40, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 355, + "note": "Officia dolore consequatur in saepe cum magni.", + "noteable_type": "Issue", + "author_id": 16, + "created_at": "2016-06-14T15:02:47.876Z", + "updated_at": "2016-06-14T15:02:47.876Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 40, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 356, + "note": "Cum ipsum rem voluptas eaque et ea.", + "noteable_type": "Issue", + "author_id": 15, + "created_at": "2016-06-14T15:02:47.908Z", + "updated_at": "2016-06-14T15:02:47.908Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 40, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 357, + "note": "Recusandae excepturi asperiores suscipit autem nostrum.", + "noteable_type": "Issue", + "author_id": 6, + "created_at": "2016-06-14T15:02:47.937Z", + "updated_at": "2016-06-14T15:02:47.937Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 40, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 358, + "note": "Et hic est id similique et non nesciunt voluptate.", + "noteable_type": "Issue", + "author_id": 1, + "created_at": "2016-06-14T15:02:47.965Z", + "updated_at": "2016-06-14T15:02:47.965Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 40, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] } ] }, { "id": 39, - "title": "Sit ut adipisci sint temporibus velit quis.", - "assignee_id": 1, - "author_id": 12, + "title": "Delectus veniam ratione in eos culpa et natus molestiae earum aut.", + "assignee_id": 20, + "author_id": 22, "project_id": 5, - "created_at": "2016-03-22T15:13:28.278Z", - "updated_at": "2016-03-22T15:19:59.473Z", + "created_at": "2016-06-14T15:02:08.233Z", + "updated_at": "2016-06-14T15:02:48.194Z", "position": 0, "branch_name": null, - "description": "Ab sint nostrum aliquam laudantium magni recusandae qui.", - "milestone_id": 10, - "state": "closed", + "description": "Voluptate vel reprehenderit facilis omnis voluptas magnam tenetur.", + "milestone_id": 16, + "state": "opened", "iid": 9, "updated_by_id": null, "confidential": false, "deleted_at": null, - "moved_to_id": null, "due_date": null, + "moved_to_id": null, "notes": [ { - "id": 346, - "note": "Natus rerum qui dolorem dolorum voluptas.", - "noteable_type": "Issue", - "author_id": 1, - "created_at": "2016-03-22T15:19:59.469Z", - "updated_at": "2016-03-22T15:19:59.469Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 39, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 345, - "note": "Voluptatibus et qui quis id sed necessitatibus quos.", - "noteable_type": "Issue", - "author_id": 3, - "created_at": "2016-03-22T15:19:59.438Z", - "updated_at": "2016-03-22T15:19:59.438Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 39, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 344, - "note": "Aperiam possimus ipsam quibusdam in.", - "noteable_type": "Issue", - "author_id": 4, - "created_at": "2016-03-22T15:19:59.410Z", - "updated_at": "2016-03-22T15:19:59.410Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 39, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 343, - "note": "Ad vel hic molestiae tempora.", - "noteable_type": "Issue", - "author_id": 10, - "created_at": "2016-03-22T15:19:59.379Z", - "updated_at": "2016-03-22T15:19:59.379Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 39, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 342, - "note": "Vel magnam sed quidem aut molestiae facilis alias.", - "noteable_type": "Issue", - "author_id": 12, - "created_at": "2016-03-22T15:19:59.348Z", - "updated_at": "2016-03-22T15:19:59.348Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 39, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 341, - "note": "Veritatis dolorum aut qui quod.", - "noteable_type": "Issue", - "author_id": 22, - "created_at": "2016-03-22T15:19:59.319Z", - "updated_at": "2016-03-22T15:19:59.319Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 39, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 340, - "note": "Illum at cumque dolorum et quia.", - "noteable_type": "Issue", - "author_id": 24, - "created_at": "2016-03-22T15:19:59.289Z", - "updated_at": "2016-03-22T15:19:59.289Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 39, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 339, - "note": "Fugiat et error molestiae cumque quos aperiam.", + "id": 359, + "note": "Quo eius velit quia et id quam.", "noteable_type": "Issue", "author_id": 26, - "created_at": "2016-03-22T15:19:59.255Z", - "updated_at": "2016-03-22T15:19:59.255Z", + "created_at": "2016-06-14T15:02:48.009Z", + "updated_at": "2016-06-14T15:02:48.009Z", "project_id": 5, "attachment": { "url": null @@ -404,186 +258,210 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] + }, + { + "id": 360, + "note": "Nulla commodi ratione cumque id autem.", + "noteable_type": "Issue", + "author_id": 25, + "created_at": "2016-06-14T15:02:48.032Z", + "updated_at": "2016-06-14T15:02:48.032Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 39, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 361, + "note": "Illum non ea sed dolores corrupti.", + "noteable_type": "Issue", + "author_id": 22, + "created_at": "2016-06-14T15:02:48.056Z", + "updated_at": "2016-06-14T15:02:48.056Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 39, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 362, + "note": "Facere dolores ipsum dolorum maiores omnis occaecati ab.", + "noteable_type": "Issue", + "author_id": 20, + "created_at": "2016-06-14T15:02:48.082Z", + "updated_at": "2016-06-14T15:02:48.082Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 39, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 363, + "note": "Quod laudantium similique sint aut est ducimus.", + "noteable_type": "Issue", + "author_id": 16, + "created_at": "2016-06-14T15:02:48.113Z", + "updated_at": "2016-06-14T15:02:48.113Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 39, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 364, + "note": "Aut omnis eos esse incidunt vero reiciendis.", + "noteable_type": "Issue", + "author_id": 15, + "created_at": "2016-06-14T15:02:48.139Z", + "updated_at": "2016-06-14T15:02:48.139Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 39, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 365, + "note": "Beatae dolore et doloremque asperiores sunt.", + "noteable_type": "Issue", + "author_id": 6, + "created_at": "2016-06-14T15:02:48.162Z", + "updated_at": "2016-06-14T15:02:48.162Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 39, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 366, + "note": "Doloribus ipsam ex delectus rerum libero recusandae modi repellendus.", + "noteable_type": "Issue", + "author_id": 1, + "created_at": "2016-06-14T15:02:48.192Z", + "updated_at": "2016-06-14T15:02:48.192Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 39, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] } ] }, { "id": 38, - "title": "Quod quo est quis vel natus nulla eos reiciendis.", - "assignee_id": 12, - "author_id": 3, + "title": "Quasi adipisci non cupiditate dolorem quo qui earum sed.", + "assignee_id": 1, + "author_id": 6, "project_id": 5, - "created_at": "2016-03-22T15:13:28.137Z", - "updated_at": "2016-03-22T15:19:59.712Z", + "created_at": "2016-06-14T15:02:08.154Z", + "updated_at": "2016-06-14T15:02:48.614Z", "position": 0, "branch_name": null, - "description": "Fugit dolor accusantium suscipit facere voluptate.", - "milestone_id": 10, - "state": "opened", + "description": "Ea recusandae neque autem tempora.", + "milestone_id": 16, + "state": "closed", "iid": 8, "updated_by_id": null, "confidential": false, "deleted_at": null, - "moved_to_id": null, "due_date": null, + "moved_to_id": null, "notes": [ { - "id": 354, - "note": "Id commodi natus vel corrupti ea placeat cum nihil.", - "noteable_type": "Issue", - "author_id": 1, - "created_at": "2016-03-22T15:19:59.708Z", - "updated_at": "2016-03-22T15:19:59.708Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 38, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 353, - "note": "Quia hic sed ratione eos voluptate dolor occaecati dolorem.", - "noteable_type": "Issue", - "author_id": 3, - "created_at": "2016-03-22T15:19:59.680Z", - "updated_at": "2016-03-22T15:19:59.680Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 38, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 352, - "note": "Commodi sint voluptatem est aut.", - "noteable_type": "Issue", - "author_id": 4, - "created_at": "2016-03-22T15:19:59.650Z", - "updated_at": "2016-03-22T15:19:59.650Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 38, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 351, - "note": "Et quibusdam voluptatibus dolores aut quam architecto optio.", - "noteable_type": "Issue", - "author_id": 10, - "created_at": "2016-03-22T15:19:59.622Z", - "updated_at": "2016-03-22T15:19:59.622Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 38, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 350, - "note": "Fugit natus explicabo sed pariatur et quasi autem.", - "noteable_type": "Issue", - "author_id": 12, - "created_at": "2016-03-22T15:19:59.590Z", - "updated_at": "2016-03-22T15:19:59.590Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 38, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 349, - "note": "Corporis commodi eos quia optio sunt corrupti.", - "noteable_type": "Issue", - "author_id": 22, - "created_at": "2016-03-22T15:19:59.562Z", - "updated_at": "2016-03-22T15:19:59.562Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 38, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 348, - "note": "Occaecati nostrum hic dolor tenetur aliquid maxime animi.", - "noteable_type": "Issue", - "author_id": 24, - "created_at": "2016-03-22T15:19:59.536Z", - "updated_at": "2016-03-22T15:19:59.536Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 38, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 347, - "note": "Inventore ullam sed repellendus laudantium itaque et quia.", + "id": 367, + "note": "Accusantium fugiat et eaque quisquam esse corporis.", "noteable_type": "Issue", "author_id": 26, - "created_at": "2016-03-22T15:19:59.506Z", - "updated_at": "2016-03-22T15:19:59.506Z", + "created_at": "2016-06-14T15:02:48.235Z", + "updated_at": "2016-06-14T15:02:48.235Z", "project_id": 5, "attachment": { "url": null @@ -594,186 +472,210 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] + }, + { + "id": 368, + "note": "Ea labore eum nam qui laboriosam.", + "noteable_type": "Issue", + "author_id": 25, + "created_at": "2016-06-14T15:02:48.261Z", + "updated_at": "2016-06-14T15:02:48.261Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 38, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 369, + "note": "Accusantium quis sed molestiae et.", + "noteable_type": "Issue", + "author_id": 22, + "created_at": "2016-06-14T15:02:48.294Z", + "updated_at": "2016-06-14T15:02:48.294Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 38, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 370, + "note": "Corporis numquam a voluptatem pariatur asperiores dolorem delectus autem.", + "noteable_type": "Issue", + "author_id": 20, + "created_at": "2016-06-14T15:02:48.523Z", + "updated_at": "2016-06-14T15:02:48.523Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 38, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 371, + "note": "Ea accusantium maxime voluptas rerum.", + "noteable_type": "Issue", + "author_id": 16, + "created_at": "2016-06-14T15:02:48.546Z", + "updated_at": "2016-06-14T15:02:48.546Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 38, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 372, + "note": "Pariatur iusto et et excepturi similique ipsam eum.", + "noteable_type": "Issue", + "author_id": 15, + "created_at": "2016-06-14T15:02:48.569Z", + "updated_at": "2016-06-14T15:02:48.569Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 38, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 373, + "note": "Aliquam et culpa officia iste eius.", + "noteable_type": "Issue", + "author_id": 6, + "created_at": "2016-06-14T15:02:48.591Z", + "updated_at": "2016-06-14T15:02:48.591Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 38, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 374, + "note": "Ab id velit id unde laborum.", + "noteable_type": "Issue", + "author_id": 1, + "created_at": "2016-06-14T15:02:48.613Z", + "updated_at": "2016-06-14T15:02:48.613Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 38, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] } ] }, { "id": 37, - "title": "Animi suscipit quia ut hic asperiores perferendis nisi ut.", - "assignee_id": 22, - "author_id": 10, + "title": "Cupiditate quo aut ducimus minima molestiae vero numquam possimus.", + "assignee_id": 15, + "author_id": 20, "project_id": 5, - "created_at": "2016-03-22T15:13:27.994Z", - "updated_at": "2016-03-22T15:19:59.972Z", + "created_at": "2016-06-14T15:02:08.051Z", + "updated_at": "2016-06-14T15:02:48.854Z", "position": 0, "branch_name": null, - "description": "Non quibusdam in maxime earum eveniet itaque culpa.", - "milestone_id": 11, - "state": "closed", + "description": "Maiores architecto quos in dolorem.", + "milestone_id": 17, + "state": "opened", "iid": 7, "updated_by_id": null, "confidential": false, "deleted_at": null, - "moved_to_id": null, "due_date": null, + "moved_to_id": null, "notes": [ { - "id": 362, - "note": "Quia qui quis molestiae in praesentium.", - "noteable_type": "Issue", - "author_id": 1, - "created_at": "2016-03-22T15:19:59.966Z", - "updated_at": "2016-03-22T15:19:59.966Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 37, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 361, - "note": "Maxime sed eius qui consequatur beatae.", - "noteable_type": "Issue", - "author_id": 3, - "created_at": "2016-03-22T15:19:59.924Z", - "updated_at": "2016-03-22T15:19:59.924Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 37, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 360, - "note": "Voluptatum quasi corrupti eveniet sed ut quis quibusdam.", - "noteable_type": "Issue", - "author_id": 4, - "created_at": "2016-03-22T15:19:59.897Z", - "updated_at": "2016-03-22T15:19:59.897Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 37, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 359, - "note": "Molestias quia eius ipsum non.", - "noteable_type": "Issue", - "author_id": 10, - "created_at": "2016-03-22T15:19:59.866Z", - "updated_at": "2016-03-22T15:19:59.866Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 37, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 358, - "note": "Aut non est accusantium aliquam.", - "noteable_type": "Issue", - "author_id": 12, - "created_at": "2016-03-22T15:19:59.834Z", - "updated_at": "2016-03-22T15:19:59.834Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 37, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 357, - "note": "Aspernatur voluptas id voluptas vel cum ipsam.", - "noteable_type": "Issue", - "author_id": 22, - "created_at": "2016-03-22T15:19:59.805Z", - "updated_at": "2016-03-22T15:19:59.805Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 37, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 356, - "note": "Harum dignissimos provident tempora sit numquam est qui.", - "noteable_type": "Issue", - "author_id": 24, - "created_at": "2016-03-22T15:19:59.773Z", - "updated_at": "2016-03-22T15:19:59.773Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 37, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 355, - "note": "Sint dignissimos molestiae recusandae delectus.", + "id": 375, + "note": "Quasi fugit qui sed eligendi aut quia.", "noteable_type": "Issue", "author_id": 26, - "created_at": "2016-03-22T15:19:59.746Z", - "updated_at": "2016-03-22T15:19:59.746Z", + "created_at": "2016-06-14T15:02:48.647Z", + "updated_at": "2016-06-14T15:02:48.647Z", "project_id": 5, "attachment": { "url": null @@ -784,186 +686,210 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] + }, + { + "id": 376, + "note": "Esse nesciunt voluptatem ex vero est consequatur.", + "noteable_type": "Issue", + "author_id": 25, + "created_at": "2016-06-14T15:02:48.674Z", + "updated_at": "2016-06-14T15:02:48.674Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 37, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 377, + "note": "Similique qui quas non aut et velit sequi in.", + "noteable_type": "Issue", + "author_id": 22, + "created_at": "2016-06-14T15:02:48.696Z", + "updated_at": "2016-06-14T15:02:48.696Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 37, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 378, + "note": "Eveniet ut cupiditate repellendus numquam in esse eius.", + "noteable_type": "Issue", + "author_id": 20, + "created_at": "2016-06-14T15:02:48.720Z", + "updated_at": "2016-06-14T15:02:48.720Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 37, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 379, + "note": "Velit est dolorem adipisci rerum sed iure.", + "noteable_type": "Issue", + "author_id": 16, + "created_at": "2016-06-14T15:02:48.755Z", + "updated_at": "2016-06-14T15:02:48.755Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 37, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 380, + "note": "Voluptatem ullam ab ut illo ut quo.", + "noteable_type": "Issue", + "author_id": 15, + "created_at": "2016-06-14T15:02:48.793Z", + "updated_at": "2016-06-14T15:02:48.793Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 37, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 381, + "note": "Voluptatem impedit beatae quasi ipsa earum consectetur.", + "noteable_type": "Issue", + "author_id": 6, + "created_at": "2016-06-14T15:02:48.823Z", + "updated_at": "2016-06-14T15:02:48.823Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 37, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 382, + "note": "Nihil officiis eaque incidunt sunt voluptatum excepturi.", + "noteable_type": "Issue", + "author_id": 1, + "created_at": "2016-06-14T15:02:48.852Z", + "updated_at": "2016-06-14T15:02:48.852Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 37, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] } ] }, { "id": 36, - "title": "Quia dolores commodi eligendi ut nemo totam.", - "assignee_id": 3, - "author_id": 4, + "title": "Necessitatibus dolor est enim quia rem suscipit quidem voluptas ullam.", + "assignee_id": 20, + "author_id": 16, "project_id": 5, - "created_at": "2016-03-22T15:13:27.814Z", - "updated_at": "2016-03-22T15:20:00.371Z", + "created_at": "2016-06-14T15:02:07.958Z", + "updated_at": "2016-06-14T15:02:49.044Z", "position": 0, "branch_name": null, - "description": "Molestiae veniam laudantium autem et natus.", - "milestone_id": 11, + "description": "Ut aut ut et tenetur velit aut id modi.", + "milestone_id": 16, "state": "opened", "iid": 6, "updated_by_id": null, "confidential": false, "deleted_at": null, - "moved_to_id": null, "due_date": null, + "moved_to_id": null, "notes": [ { - "id": 370, - "note": "Occaecati temporibus tempore harum vero incidunt veniam iste.", - "noteable_type": "Issue", - "author_id": 1, - "created_at": "2016-03-22T15:20:00.365Z", - "updated_at": "2016-03-22T15:20:00.365Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 36, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 369, - "note": "Modi architecto officiis quia iste voluptas libero nihil quo.", - "noteable_type": "Issue", - "author_id": 3, - "created_at": "2016-03-22T15:20:00.331Z", - "updated_at": "2016-03-22T15:20:00.331Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 36, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 368, - "note": "Eaque est tenetur ex est molestiae nobis.", - "noteable_type": "Issue", - "author_id": 4, - "created_at": "2016-03-22T15:20:00.296Z", - "updated_at": "2016-03-22T15:20:00.296Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 36, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 367, - "note": "Odit enim ut a quo qui.", - "noteable_type": "Issue", - "author_id": 10, - "created_at": "2016-03-22T15:20:00.261Z", - "updated_at": "2016-03-22T15:20:00.261Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 36, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 366, - "note": "Omnis unde cum officiis est.", - "noteable_type": "Issue", - "author_id": 12, - "created_at": "2016-03-22T15:20:00.223Z", - "updated_at": "2016-03-22T15:20:00.223Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 36, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 365, - "note": "Ab consequuntur aliquam illo voluptatum.", - "noteable_type": "Issue", - "author_id": 22, - "created_at": "2016-03-22T15:20:00.178Z", - "updated_at": "2016-03-22T15:20:00.178Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 36, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 364, - "note": "Molestiae dolorem est eos dolores aut.", - "noteable_type": "Issue", - "author_id": 24, - "created_at": "2016-03-22T15:20:00.127Z", - "updated_at": "2016-03-22T15:20:00.127Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 36, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 363, - "note": "Nemo velit nam quod veniam.", + "id": 383, + "note": "Excepturi deleniti sunt rerum nesciunt vero fugiat possimus.", "noteable_type": "Issue", "author_id": 26, - "created_at": "2016-03-22T15:20:00.083Z", - "updated_at": "2016-03-22T15:20:00.083Z", + "created_at": "2016-06-14T15:02:48.885Z", + "updated_at": "2016-06-14T15:02:48.885Z", "project_id": 5, "attachment": { "url": null @@ -974,186 +900,210 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] + }, + { + "id": 384, + "note": "Et est nemo sed nam sed.", + "noteable_type": "Issue", + "author_id": 25, + "created_at": "2016-06-14T15:02:48.910Z", + "updated_at": "2016-06-14T15:02:48.910Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 36, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 385, + "note": "Animi mollitia nulla facere amet aut quaerat.", + "noteable_type": "Issue", + "author_id": 22, + "created_at": "2016-06-14T15:02:48.934Z", + "updated_at": "2016-06-14T15:02:48.934Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 36, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 386, + "note": "Excepturi id voluptas ut odio officiis omnis.", + "noteable_type": "Issue", + "author_id": 20, + "created_at": "2016-06-14T15:02:48.955Z", + "updated_at": "2016-06-14T15:02:48.955Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 36, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 387, + "note": "Molestiae labore officiis magni et eligendi quasi maxime.", + "noteable_type": "Issue", + "author_id": 16, + "created_at": "2016-06-14T15:02:48.978Z", + "updated_at": "2016-06-14T15:02:48.978Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 36, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 388, + "note": "Officia tenetur praesentium rem nam non.", + "noteable_type": "Issue", + "author_id": 15, + "created_at": "2016-06-14T15:02:49.001Z", + "updated_at": "2016-06-14T15:02:49.001Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 36, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 389, + "note": "Et et et molestiae reprehenderit.", + "noteable_type": "Issue", + "author_id": 6, + "created_at": "2016-06-14T15:02:49.022Z", + "updated_at": "2016-06-14T15:02:49.022Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 36, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 390, + "note": "Aperiam in consequatur est sunt cum quia.", + "noteable_type": "Issue", + "author_id": 1, + "created_at": "2016-06-14T15:02:49.043Z", + "updated_at": "2016-06-14T15:02:49.043Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 36, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] } ] }, { "id": 35, - "title": "Rerum tenetur harum molestiae quam aut praesentium quaerat doloremque.", - "assignee_id": 4, - "author_id": 1, + "title": "Repellat praesentium deserunt maxime incidunt harum porro qui.", + "assignee_id": 6, + "author_id": 20, "project_id": 5, - "created_at": "2016-03-22T15:13:27.660Z", - "updated_at": "2016-03-22T15:20:00.665Z", + "created_at": "2016-06-14T15:02:07.832Z", + "updated_at": "2016-06-14T15:02:49.226Z", "position": 0, "branch_name": null, - "description": "Omnis et voluptatibus expedita qui et explicabo rem ut.", - "milestone_id": 11, - "state": "opened", + "description": "Dicta nisi nihil non ipsa velit.", + "milestone_id": 20, + "state": "closed", "iid": 5, "updated_by_id": null, "confidential": false, "deleted_at": null, - "moved_to_id": null, "due_date": null, + "moved_to_id": null, "notes": [ { - "id": 378, - "note": "Molestiae atque exercitationem culpa harum nemo.", - "noteable_type": "Issue", - "author_id": 1, - "created_at": "2016-03-22T15:20:00.660Z", - "updated_at": "2016-03-22T15:20:00.660Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 35, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 377, - "note": "Porro sed nobis neque amet velit velit.", - "noteable_type": "Issue", - "author_id": 3, - "created_at": "2016-03-22T15:20:00.625Z", - "updated_at": "2016-03-22T15:20:00.625Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 35, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 376, - "note": "Dicta officiis doloremque voluptatum qui omnis.", - "noteable_type": "Issue", - "author_id": 4, - "created_at": "2016-03-22T15:20:00.589Z", - "updated_at": "2016-03-22T15:20:00.589Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 35, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 375, - "note": "Incidunt rerum omnis cum laudantium aut impedit.", - "noteable_type": "Issue", - "author_id": 10, - "created_at": "2016-03-22T15:20:00.553Z", - "updated_at": "2016-03-22T15:20:00.553Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 35, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 374, - "note": "Et suscipit omnis dolorum officia vero.", - "noteable_type": "Issue", - "author_id": 12, - "created_at": "2016-03-22T15:20:00.517Z", - "updated_at": "2016-03-22T15:20:00.517Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 35, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 373, - "note": "Doloremque adipisci et cumque inventore beatae consectetur.", - "noteable_type": "Issue", - "author_id": 22, - "created_at": "2016-03-22T15:20:00.485Z", - "updated_at": "2016-03-22T15:20:00.485Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 35, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 372, - "note": "Dolores sapiente ea dolorum et quae adipisci id.", - "noteable_type": "Issue", - "author_id": 24, - "created_at": "2016-03-22T15:20:00.455Z", - "updated_at": "2016-03-22T15:20:00.455Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 35, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 371, - "note": "Accusantium repellat tenetur natus dicta ullam saepe facere.", + "id": 391, + "note": "Qui magnam et assumenda quod id dicta necessitatibus.", "noteable_type": "Issue", "author_id": 26, - "created_at": "2016-03-22T15:20:00.420Z", - "updated_at": "2016-03-22T15:20:00.420Z", + "created_at": "2016-06-14T15:02:49.075Z", + "updated_at": "2016-06-14T15:02:49.075Z", "project_id": 5, "attachment": { "url": null @@ -1164,39 +1114,210 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] + }, + { + "id": 392, + "note": "Consectetur deserunt possimus dolor est odio.", + "noteable_type": "Issue", + "author_id": 25, + "created_at": "2016-06-14T15:02:49.095Z", + "updated_at": "2016-06-14T15:02:49.095Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 35, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 393, + "note": "Labore nisi quo cumque voluptas consequatur aut qui.", + "noteable_type": "Issue", + "author_id": 22, + "created_at": "2016-06-14T15:02:49.117Z", + "updated_at": "2016-06-14T15:02:49.117Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 35, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 394, + "note": "Et totam facilis voluptas et enim.", + "noteable_type": "Issue", + "author_id": 20, + "created_at": "2016-06-14T15:02:49.138Z", + "updated_at": "2016-06-14T15:02:49.138Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 35, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 395, + "note": "Ratione sint pariatur sed omnis eligendi quo libero exercitationem.", + "noteable_type": "Issue", + "author_id": 16, + "created_at": "2016-06-14T15:02:49.160Z", + "updated_at": "2016-06-14T15:02:49.160Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 35, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 396, + "note": "Iure hic autem id voluptatem.", + "noteable_type": "Issue", + "author_id": 15, + "created_at": "2016-06-14T15:02:49.182Z", + "updated_at": "2016-06-14T15:02:49.182Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 35, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 397, + "note": "Excepturi eum laboriosam delectus repellendus odio nisi et voluptatem.", + "noteable_type": "Issue", + "author_id": 6, + "created_at": "2016-06-14T15:02:49.205Z", + "updated_at": "2016-06-14T15:02:49.205Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 35, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 398, + "note": "Ut quis ex soluta consequatur et blanditiis.", + "noteable_type": "Issue", + "author_id": 1, + "created_at": "2016-06-14T15:02:49.225Z", + "updated_at": "2016-06-14T15:02:49.225Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 35, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] } ] }, { "id": 34, - "title": "Enim occaecati aut sed quia mollitia eligendi atque dolores voluptatem.", - "assignee_id": 24, + "title": "Ullam expedita deserunt libero consequatur quia dolor harum perferendis facere quidem.", + "assignee_id": 20, "author_id": 1, "project_id": 5, - "created_at": "2016-03-22T15:13:27.506Z", - "updated_at": "2016-03-22T15:20:00.961Z", + "created_at": "2016-06-14T15:02:07.717Z", + "updated_at": "2016-06-14T15:02:49.416Z", "position": 0, "branch_name": null, - "description": "Voluptatem totam magnam fugit assumenda consequatur illo qui.", - "milestone_id": 10, - "state": "opened", + "description": "Ut et explicabo vel voluptatem consequuntur ut sed.", + "milestone_id": 19, + "state": "closed", "iid": 4, "updated_by_id": null, "confidential": false, "deleted_at": null, - "moved_to_id": null, "due_date": null, + "moved_to_id": null, "notes": [ { - "id": 379, - "note": "Praesentium odio quia fugit consequuntur repudiandae ducimus.", + "id": 399, + "note": "Dolor iste tempora tenetur non vitae maiores voluptatibus.", "noteable_type": "Issue", "author_id": 26, - "created_at": "2016-03-22T15:20:00.717Z", - "updated_at": "2016-03-22T15:20:00.717Z", + "created_at": "2016-06-14T15:02:49.256Z", + "updated_at": "2016-06-14T15:02:49.256Z", "project_id": 5, "attachment": { "url": null @@ -1207,17 +1328,20 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] }, { - "id": 380, - "note": "Dolores aut dolorem quia soluta incidunt commodi quia.", + "id": 400, + "note": "Aut sit quidem qui adipisci maxime excepturi iusto.", "noteable_type": "Issue", - "author_id": 24, - "created_at": "2016-03-22T15:20:00.754Z", - "updated_at": "2016-03-22T15:20:00.754Z", + "author_id": 25, + "created_at": "2016-06-14T15:02:49.284Z", + "updated_at": "2016-06-14T15:02:49.284Z", "project_id": 5, "attachment": { "url": null @@ -1228,17 +1352,20 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { - "name": "User 2" - } + "author": { + "name": "User 3" + }, + "events": [ + + ] }, { - "id": 381, - "note": "Enim et velit iure ad.", + "id": 401, + "note": "Et a necessitatibus autem quidem animi sunt voluptatum rerum.", "noteable_type": "Issue", "author_id": 22, - "created_at": "2016-03-22T15:20:00.787Z", - "updated_at": "2016-03-22T15:20:00.787Z", + "created_at": "2016-06-14T15:02:49.305Z", + "updated_at": "2016-06-14T15:02:49.305Z", "project_id": 5, "attachment": { "url": null @@ -1249,17 +1376,20 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 0" - } + }, + "events": [ + + ] }, { - "id": 382, - "note": "Impedit nobis quis laudantium ad assumenda.", + "id": 402, + "note": "Esse laboriosam quo voluptatem quis molestiae.", "noteable_type": "Issue", - "author_id": 12, - "created_at": "2016-03-22T15:20:00.822Z", - "updated_at": "2016-03-22T15:20:00.822Z", + "author_id": 20, + "created_at": "2016-06-14T15:02:49.328Z", + "updated_at": "2016-06-14T15:02:49.328Z", "project_id": 5, "attachment": { "url": null @@ -1270,17 +1400,20 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] }, { - "id": 383, - "note": "Facere sed numquam quos quas.", + "id": 403, + "note": "Nemo magnam distinctio est ut voluptate ea.", "noteable_type": "Issue", - "author_id": 10, - "created_at": "2016-03-22T15:20:00.855Z", - "updated_at": "2016-03-22T15:20:00.855Z", + "author_id": 16, + "created_at": "2016-06-14T15:02:49.350Z", + "updated_at": "2016-06-14T15:02:49.350Z", "project_id": 5, "attachment": { "url": null @@ -1291,17 +1424,20 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] }, { - "id": 384, - "note": "Ex voluptatem sit provident error.", + "id": 404, + "note": "Omnis sed rerum neque rerum quae quam nulla officiis.", "noteable_type": "Issue", - "author_id": 4, - "created_at": "2016-03-22T15:20:00.889Z", - "updated_at": "2016-03-22T15:20:00.889Z", + "author_id": 15, + "created_at": "2016-06-14T15:02:49.372Z", + "updated_at": "2016-06-14T15:02:49.372Z", "project_id": 5, "attachment": { "url": null @@ -1312,17 +1448,20 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { - "name": "Julius Moore" - } + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] }, { - "id": 385, - "note": "Soluta laboriosam recusandae est cupiditate.", + "id": 405, + "note": "Quo soluta dolorem vitae ad consequatur qui aut dicta.", "noteable_type": "Issue", - "author_id": 3, - "created_at": "2016-03-22T15:20:00.925Z", - "updated_at": "2016-03-22T15:20:00.925Z", + "author_id": 6, + "created_at": "2016-06-14T15:02:49.394Z", + "updated_at": "2016-06-14T15:02:49.394Z", "project_id": 5, "attachment": { "url": null @@ -1333,17 +1472,20 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] }, { - "id": 386, - "note": "Similique dolorem rerum iusto animi perferendis aut inventore.", + "id": 406, + "note": "Magni minus est aut aut totam ut.", "noteable_type": "Issue", "author_id": 1, - "created_at": "2016-03-22T15:20:00.957Z", - "updated_at": "2016-03-22T15:20:00.957Z", + "created_at": "2016-06-14T15:02:49.414Z", + "updated_at": "2016-06-14T15:02:49.414Z", "project_id": 5, "attachment": { "url": null @@ -1354,186 +1496,42 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "Administrator" - } + }, + "events": [ + + ] } ] }, { "id": 33, - "title": "Rem fugiat fugit occaecati quibusdam enim consectetur numquam.", - "assignee_id": 22, - "author_id": 22, + "title": "Numquam accusamus eos iste exercitationem magni non inventore.", + "assignee_id": 15, + "author_id": 26, "project_id": 5, - "created_at": "2016-03-22T15:13:27.364Z", - "updated_at": "2016-03-22T15:20:01.227Z", + "created_at": "2016-06-14T15:02:07.611Z", + "updated_at": "2016-06-14T15:02:49.661Z", "position": 0, "branch_name": null, - "description": "Provident nulla architecto neque beatae fuga alias repudiandae.", - "milestone_id": 10, + "description": "Non asperiores velit accusantium voluptate.", + "milestone_id": 18, "state": "closed", "iid": 3, "updated_by_id": null, "confidential": false, "deleted_at": null, - "moved_to_id": null, "due_date": null, + "moved_to_id": null, "notes": [ { - "id": 394, - "note": "Suscipit numquam voluptatibus ipsam libero dolorum dolore totam.", - "noteable_type": "Issue", - "author_id": 1, - "created_at": "2016-03-22T15:20:01.223Z", - "updated_at": "2016-03-22T15:20:01.223Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 33, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 393, - "note": "Et et sed sit sint.", - "noteable_type": "Issue", - "author_id": 3, - "created_at": "2016-03-22T15:20:01.194Z", - "updated_at": "2016-03-22T15:20:01.194Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 33, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 392, - "note": "Corrupti perferendis voluptas et iure omnis officia.", - "noteable_type": "Issue", - "author_id": 4, - "created_at": "2016-03-22T15:20:01.160Z", - "updated_at": "2016-03-22T15:20:01.160Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 33, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 391, - "note": "Autem quo fugit in iste nesciunt tempora.", - "noteable_type": "Issue", - "author_id": 10, - "created_at": "2016-03-22T15:20:01.131Z", - "updated_at": "2016-03-22T15:20:01.131Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 33, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 390, - "note": "Magni porro ut soluta quis et eveniet maiores.", - "noteable_type": "Issue", - "author_id": 12, - "created_at": "2016-03-22T15:20:01.101Z", - "updated_at": "2016-03-22T15:20:01.101Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 33, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 389, - "note": "Sed consequuntur debitis nisi veniam exercitationem recusandae a quisquam.", - "noteable_type": "Issue", - "author_id": 22, - "created_at": "2016-03-22T15:20:01.070Z", - "updated_at": "2016-03-22T15:20:01.070Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 33, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 388, - "note": "Aut impedit qui consectetur dicta temporibus.", - "noteable_type": "Issue", - "author_id": 24, - "created_at": "2016-03-22T15:20:01.042Z", - "updated_at": "2016-03-22T15:20:01.042Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 33, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 387, - "note": "Officia repudiandae ut culpa ipsa reiciendis.", + "id": 407, + "note": "Quod ea et possimus architecto.", "noteable_type": "Issue", "author_id": 26, - "created_at": "2016-03-22T15:20:01.005Z", - "updated_at": "2016-03-22T15:20:01.005Z", + "created_at": "2016-06-14T15:02:49.450Z", + "updated_at": "2016-06-14T15:02:49.450Z", "project_id": 5, "attachment": { "url": null @@ -1544,186 +1542,210 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] + }, + { + "id": 408, + "note": "Reiciendis est et unde perferendis dicta ut praesentium quasi.", + "noteable_type": "Issue", + "author_id": 25, + "created_at": "2016-06-14T15:02:49.503Z", + "updated_at": "2016-06-14T15:02:49.503Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 33, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 409, + "note": "Magni quia odio blanditiis pariatur voluptas.", + "noteable_type": "Issue", + "author_id": 22, + "created_at": "2016-06-14T15:02:49.527Z", + "updated_at": "2016-06-14T15:02:49.527Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 33, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 410, + "note": "Enim quam ut et et et.", + "noteable_type": "Issue", + "author_id": 20, + "created_at": "2016-06-14T15:02:49.551Z", + "updated_at": "2016-06-14T15:02:49.551Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 33, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 411, + "note": "Fugit voluptatem ratione maxime expedita.", + "noteable_type": "Issue", + "author_id": 16, + "created_at": "2016-06-14T15:02:49.578Z", + "updated_at": "2016-06-14T15:02:49.578Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 33, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 412, + "note": "Voluptatem enim aut ipsa et et ducimus.", + "noteable_type": "Issue", + "author_id": 15, + "created_at": "2016-06-14T15:02:49.604Z", + "updated_at": "2016-06-14T15:02:49.604Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 33, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 413, + "note": "Quia repellat fugiat consectetur quidem.", + "noteable_type": "Issue", + "author_id": 6, + "created_at": "2016-06-14T15:02:49.631Z", + "updated_at": "2016-06-14T15:02:49.631Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 33, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 414, + "note": "Corporis ipsum et ea necessitatibus quod assumenda repudiandae quam.", + "noteable_type": "Issue", + "author_id": 1, + "created_at": "2016-06-14T15:02:49.659Z", + "updated_at": "2016-06-14T15:02:49.659Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 33, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] } ] }, { "id": 32, - "title": "Velit nihil est alias blanditiis eius earum autem hic.", + "title": "Necessitatibus magnam qui at velit consequatur perspiciatis.", "assignee_id": 22, - "author_id": 26, + "author_id": 15, "project_id": 5, - "created_at": "2016-03-22T15:13:27.225Z", - "updated_at": "2016-03-22T15:20:01.495Z", + "created_at": "2016-06-14T15:02:07.431Z", + "updated_at": "2016-06-14T15:02:49.884Z", "position": 0, "branch_name": null, - "description": "Id voluptas ut sint aut laborum nobis commodi.", - "milestone_id": 11, - "state": "opened", + "description": "Molestiae corporis magnam et fugit aliquid nulla quia.", + "milestone_id": 17, + "state": "closed", "iid": 2, "updated_by_id": null, "confidential": false, "deleted_at": null, - "moved_to_id": null, "due_date": null, + "moved_to_id": null, "notes": [ { - "id": 402, - "note": "Magni ut eligendi sit sint recusandae voluptas tempore necessitatibus.", - "noteable_type": "Issue", - "author_id": 1, - "created_at": "2016-03-22T15:20:01.489Z", - "updated_at": "2016-03-22T15:20:01.489Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 32, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 401, - "note": "Est repellat commodi incidunt tempore earum optio unde sint.", - "noteable_type": "Issue", - "author_id": 3, - "created_at": "2016-03-22T15:20:01.455Z", - "updated_at": "2016-03-22T15:20:01.455Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 32, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 400, - "note": "Vero unde debitis tempore est laboriosam ut esse.", - "noteable_type": "Issue", - "author_id": 4, - "created_at": "2016-03-22T15:20:01.421Z", - "updated_at": "2016-03-22T15:20:01.421Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 32, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 399, - "note": "Omnis qui asperiores expedita harum voluptatem eius.", - "noteable_type": "Issue", - "author_id": 10, - "created_at": "2016-03-22T15:20:01.391Z", - "updated_at": "2016-03-22T15:20:01.391Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 32, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 398, - "note": "Dolorem doloribus delectus quo ratione esse veritatis.", - "noteable_type": "Issue", - "author_id": 12, - "created_at": "2016-03-22T15:20:01.358Z", - "updated_at": "2016-03-22T15:20:01.358Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 32, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 397, - "note": "Quia esse et odit id est omnis dolorum quia.", - "noteable_type": "Issue", - "author_id": 22, - "created_at": "2016-03-22T15:20:01.329Z", - "updated_at": "2016-03-22T15:20:01.329Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 32, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 396, - "note": "Exercitationem suscipit non rerum tempore sit.", - "noteable_type": "Issue", - "author_id": 24, - "created_at": "2016-03-22T15:20:01.297Z", - "updated_at": "2016-03-22T15:20:01.297Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 32, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 395, - "note": "Nihil veniam magni sit officiis.", + "id": 415, + "note": "Nemo consequatur sed blanditiis qui id iure dolores.", "noteable_type": "Issue", "author_id": 26, - "created_at": "2016-03-22T15:20:01.268Z", - "updated_at": "2016-03-22T15:20:01.268Z", + "created_at": "2016-06-14T15:02:49.694Z", + "updated_at": "2016-06-14T15:02:49.694Z", "project_id": 5, "attachment": { "url": null @@ -1734,186 +1756,210 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] + }, + { + "id": 416, + "note": "Voluptas ab accusantium dicta in.", + "noteable_type": "Issue", + "author_id": 25, + "created_at": "2016-06-14T15:02:49.718Z", + "updated_at": "2016-06-14T15:02:49.718Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 32, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 417, + "note": "Esse odit qui a et eum ducimus.", + "noteable_type": "Issue", + "author_id": 22, + "created_at": "2016-06-14T15:02:49.741Z", + "updated_at": "2016-06-14T15:02:49.741Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 32, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 418, + "note": "Sequi dolor doloribus ratione placeat repellendus.", + "noteable_type": "Issue", + "author_id": 20, + "created_at": "2016-06-14T15:02:49.767Z", + "updated_at": "2016-06-14T15:02:49.767Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 32, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 419, + "note": "Quae aspernatur rem est similique.", + "noteable_type": "Issue", + "author_id": 16, + "created_at": "2016-06-14T15:02:49.796Z", + "updated_at": "2016-06-14T15:02:49.796Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 32, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 420, + "note": "Voluptate omnis et id rerum non nesciunt laudantium assumenda.", + "noteable_type": "Issue", + "author_id": 15, + "created_at": "2016-06-14T15:02:49.825Z", + "updated_at": "2016-06-14T15:02:49.825Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 32, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 421, + "note": "Quia enim ab et eligendi.", + "noteable_type": "Issue", + "author_id": 6, + "created_at": "2016-06-14T15:02:49.853Z", + "updated_at": "2016-06-14T15:02:49.853Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 32, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 422, + "note": "In fugiat rerum voluptas quas officia.", + "noteable_type": "Issue", + "author_id": 1, + "created_at": "2016-06-14T15:02:49.881Z", + "updated_at": "2016-06-14T15:02:49.881Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 32, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] } ] }, { "id": 31, - "title": "Asperiores recusandae praesentium voluptas pariatur provident qui exercitationem quis.", - "assignee_id": 26, - "author_id": 24, + "title": "Libero nam magnam incidunt eaque placeat error et.", + "assignee_id": 1, + "author_id": 16, "project_id": 5, - "created_at": "2016-03-22T15:13:26.889Z", - "updated_at": "2016-03-22T15:20:01.834Z", + "created_at": "2016-06-14T15:02:07.280Z", + "updated_at": "2016-06-14T15:02:50.134Z", "position": 0, "branch_name": null, - "description": "Ex voluptates qui excepturi cupiditate.", - "milestone_id": 11, + "description": "Quod ad architecto qui est sed quia.", + "milestone_id": 20, "state": "closed", "iid": 1, "updated_by_id": null, "confidential": false, "deleted_at": null, - "moved_to_id": null, "due_date": null, + "moved_to_id": null, "notes": [ { - "id": 410, - "note": "Sit itaque non nihil nisi qui voluptatem dolorem error.", - "noteable_type": "Issue", - "author_id": 1, - "created_at": "2016-03-22T15:20:01.828Z", - "updated_at": "2016-03-22T15:20:01.828Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 31, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 409, - "note": "Omnis rem nihil molestiae enim laudantium doloremque.", - "noteable_type": "Issue", - "author_id": 3, - "created_at": "2016-03-22T15:20:01.783Z", - "updated_at": "2016-03-22T15:20:01.783Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 31, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 408, - "note": "Ullam harum sit et optio incidunt.", - "noteable_type": "Issue", - "author_id": 4, - "created_at": "2016-03-22T15:20:01.746Z", - "updated_at": "2016-03-22T15:20:01.746Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 31, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 407, - "note": "Fugit distinctio ab quo ipsam.", - "noteable_type": "Issue", - "author_id": 10, - "created_at": "2016-03-22T15:20:01.716Z", - "updated_at": "2016-03-22T15:20:01.716Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 31, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 406, - "note": "Impedit iste possimus ad ea.", - "noteable_type": "Issue", - "author_id": 12, - "created_at": "2016-03-22T15:20:01.676Z", - "updated_at": "2016-03-22T15:20:01.676Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 31, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 405, - "note": "Nemo recusandae dolore distinctio quam consequuntur ut et aut.", - "noteable_type": "Issue", - "author_id": 22, - "created_at": "2016-03-22T15:20:01.641Z", - "updated_at": "2016-03-22T15:20:01.641Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 31, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 404, - "note": "Nisi repudiandae repellat nulla culpa quasi expedita quod velit.", - "noteable_type": "Issue", - "author_id": 24, - "created_at": "2016-03-22T15:20:01.601Z", - "updated_at": "2016-03-22T15:20:01.601Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 31, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 403, - "note": "Quibusdam odio temporibus nemo voluptatibus accusamus.", + "id": 423, + "note": "A mollitia qui iste consequatur eaque iure omnis sunt.", "noteable_type": "Issue", "author_id": 26, - "created_at": "2016-03-22T15:20:01.552Z", - "updated_at": "2016-03-22T15:20:01.552Z", + "created_at": "2016-06-14T15:02:49.933Z", + "updated_at": "2016-06-14T15:02:49.933Z", "project_id": 5, "attachment": { "url": null @@ -1924,47 +1970,405 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] + }, + { + "id": 424, + "note": "Eveniet est et blanditiis sequi alias.", + "noteable_type": "Issue", + "author_id": 25, + "created_at": "2016-06-14T15:02:49.965Z", + "updated_at": "2016-06-14T15:02:49.965Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 31, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 425, + "note": "Commodi tempore voluptas doloremque est.", + "noteable_type": "Issue", + "author_id": 22, + "created_at": "2016-06-14T15:02:49.996Z", + "updated_at": "2016-06-14T15:02:49.996Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 31, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 426, + "note": "Quo libero impedit odio debitis rerum aspernatur.", + "noteable_type": "Issue", + "author_id": 20, + "created_at": "2016-06-14T15:02:50.024Z", + "updated_at": "2016-06-14T15:02:50.024Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 31, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 427, + "note": "Dolorem voluptatem qui labore deserunt.", + "noteable_type": "Issue", + "author_id": 16, + "created_at": "2016-06-14T15:02:50.049Z", + "updated_at": "2016-06-14T15:02:50.049Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 31, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 428, + "note": "Est blanditiis laboriosam enim ipsam.", + "noteable_type": "Issue", + "author_id": 15, + "created_at": "2016-06-14T15:02:50.077Z", + "updated_at": "2016-06-14T15:02:50.077Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 31, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 429, + "note": "Et in voluptatem animi dolorem eos.", + "noteable_type": "Issue", + "author_id": 6, + "created_at": "2016-06-14T15:02:50.107Z", + "updated_at": "2016-06-14T15:02:50.107Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 31, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 430, + "note": "Unde culpa voluptate qui sint quos.", + "noteable_type": "Issue", + "author_id": 1, + "created_at": "2016-06-14T15:02:50.132Z", + "updated_at": "2016-06-14T15:02:50.132Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 31, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] } ] } ], "labels": [ - { - "id": 12, - "title": "test", - "color": "#428bca", - "project_id": 5, - "created_at": "2016-05-10T10:53:14.214Z", - "updated_at": "2016-05-10T10:53:14.214Z", - "template": false, - "description": "test label" - } + ], "milestones": [ { - "id": 11, - "title": "v2.0", + "id": 20, + "title": "v4.0", "project_id": 5, - "description": "Sapiente facilis architecto reprehenderit aut sed enim.", + "description": "Totam quam laborum id magnam natus eaque aspernatur.", "due_date": null, - "created_at": "2016-03-22T15:13:21.631Z", - "updated_at": "2016-03-22T15:13:21.631Z", - "state": "closed", - "iid": 2 + "created_at": "2016-06-14T15:02:04.590Z", + "updated_at": "2016-06-14T15:02:04.590Z", + "state": "active", + "iid": 5, + "events": [ + { + "id": 240, + "target_type": "Milestone", + "target_id": 20, + "title": null, + "data": null, + "project_id": 36, + "created_at": "2016-06-14T15:02:04.593Z", + "updated_at": "2016-06-14T15:02:04.593Z", + "action": 1, + "author_id": 1 + }, + { + "id": 60, + "target_type": "Milestone", + "target_id": 20, + "title": null, + "data": null, + "project_id": 5, + "created_at": "2016-06-14T15:02:04.593Z", + "updated_at": "2016-06-14T15:02:04.593Z", + "action": 1, + "author_id": 20 + } + ] }, { - "id": 10, + "id": 19, + "title": "v3.0", + "project_id": 5, + "description": "Rerum at autem exercitationem ea voluptates harum quam placeat.", + "due_date": null, + "created_at": "2016-06-14T15:02:04.583Z", + "updated_at": "2016-06-14T15:02:04.583Z", + "state": "active", + "iid": 4, + "events": [ + { + "id": 241, + "target_type": "Milestone", + "target_id": 19, + "title": null, + "data": null, + "project_id": 36, + "created_at": "2016-06-14T15:02:04.585Z", + "updated_at": "2016-06-14T15:02:04.585Z", + "action": 1, + "author_id": 1 + }, + { + "id": 59, + "target_type": "Milestone", + "target_id": 19, + "title": null, + "data": { + "object_kind": "push", + "before": "0000000000000000000000000000000000000000", + "after": "de990aa15829d0ab182ad5a55b4c527846c0d39c", + "ref": "refs/heads/removable-group-owner", + "checkout_sha": "de990aa15829d0ab182ad5a55b4c527846c0d39c", + "message": null, + "user_id": 273486, + "user_name": "James Lopez", + "user_email": "james@jameslopez.es", + "project_id": 562317, + "repository": { + "name": "GitLab Community Edition", + "url": "git@gitlab.com:james11/gitlab-ce.git", + "description": "Version Control on your Server. See http://gitlab.org/gitlab-ce/ and the README for more information", + "homepage": "https://gitlab.com/james11/gitlab-ce", + "git_http_url": "https://gitlab.com/james11/gitlab-ce.git", + "git_ssh_url": "git@gitlab.com:james11/gitlab-ce.git", + "visibility_level": 20 + }, + "commits": [ + { + "id": "de990aa15829d0ab182ad5a55b4c527846c0d39c", + "message": "fixed last group owner issue and added test\\n", + "timestamp": "2015-10-29T16:10:27+00:00", + "url": "https://gitlab.com/james11/gitlab-ce/commit/de990aa15829d0ab182ad5a55b4c527846c0d39c", + "author": { + "name": "James Lopez", + "email": "james.lopez@vodafone.com" + } + } + ], + "total_commits_count": 1 + }, + "project_id": 5, + "created_at": "2016-06-14T15:02:04.585Z", + "updated_at": "2016-06-14T15:02:04.585Z", + "action": 1, + "author_id": 25 + } + ] + }, + { + "id": 18, + "title": "v2.0", + "project_id": 5, + "description": "Error dolorem rerum aut nulla.", + "due_date": null, + "created_at": "2016-06-14T15:02:04.576Z", + "updated_at": "2016-06-14T15:02:04.576Z", + "state": "active", + "iid": 3, + "events": [ + { + "id": 242, + "target_type": "Milestone", + "target_id": 18, + "title": null, + "data": null, + "project_id": 36, + "created_at": "2016-06-14T15:02:04.579Z", + "updated_at": "2016-06-14T15:02:04.579Z", + "action": 1, + "author_id": 1 + }, + { + "id": 58, + "target_type": "Milestone", + "target_id": 18, + "title": null, + "data": null, + "project_id": 5, + "created_at": "2016-06-14T15:02:04.579Z", + "updated_at": "2016-06-14T15:02:04.579Z", + "action": 1, + "author_id": 22 + } + ] + }, + { + "id": 17, "title": "v1.0", "project_id": 5, - "description": "Est sed eos minima veniam culpa aut non.", + "description": "Molestiae perspiciatis voluptates doloremque commodi veniam consequatur.", "due_date": null, - "created_at": "2016-03-22T15:13:21.622Z", - "updated_at": "2016-03-22T15:13:21.622Z", + "created_at": "2016-06-14T15:02:04.569Z", + "updated_at": "2016-06-14T15:02:04.569Z", + "state": "active", + "iid": 2, + "events": [ + { + "id": 243, + "target_type": "Milestone", + "target_id": 17, + "title": null, + "data": null, + "project_id": 36, + "created_at": "2016-06-14T15:02:04.570Z", + "updated_at": "2016-06-14T15:02:04.570Z", + "action": 1, + "author_id": 1 + }, + { + "id": 57, + "target_type": "Milestone", + "target_id": 17, + "title": null, + "data": null, + "project_id": 5, + "created_at": "2016-06-14T15:02:04.570Z", + "updated_at": "2016-06-14T15:02:04.570Z", + "action": 1, + "author_id": 20 + } + ] + }, + { + "id": 16, + "title": "v0.0", + "project_id": 5, + "description": "Velit numquam et sed sit.", + "due_date": null, + "created_at": "2016-06-14T15:02:04.561Z", + "updated_at": "2016-06-14T15:02:04.561Z", "state": "closed", - "iid": 1 + "iid": 1, + "events": [ + { + "id": 244, + "target_type": "Milestone", + "target_id": 16, + "title": null, + "data": null, + "project_id": 36, + "created_at": "2016-06-14T15:02:04.563Z", + "updated_at": "2016-06-14T15:02:04.563Z", + "action": 1, + "author_id": 26 + }, + { + "id": 56, + "target_type": "Milestone", + "target_id": 16, + "title": null, + "data": null, + "project_id": 5, + "created_at": "2016-06-14T15:02:04.563Z", + "updated_at": "2016-06-14T15:02:04.563Z", + "action": 1, + "author_id": 26 + } + ] } ], "snippets": [ @@ -1972,422 +2376,100 @@ ], "releases": [ - ], - "events": [ - { - "id": 301, - "target_type": "Note", - "target_id": 1357, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-04-12T13:08:30.886Z", - "updated_at": "2016-04-12T13:08:30.886Z", - "action": 6, - "author_id": 1 - }, - { - "id": 227, - "target_type": "MergeRequest", - "target_id": 85, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:19:44.957Z", - "updated_at": "2016-03-22T15:19:44.957Z", - "action": 1, - "author_id": 1 - }, - { - "id": 226, - "target_type": "MergeRequest", - "target_id": 84, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:19:44.600Z", - "updated_at": "2016-03-22T15:19:44.600Z", - "action": 1, - "author_id": 1 - }, - { - "id": 157, - "target_type": "MergeRequest", - "target_id": 15, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:45.936Z", - "updated_at": "2016-03-22T15:13:45.936Z", - "action": 1, - "author_id": 3 - }, - { - "id": 156, - "target_type": "MergeRequest", - "target_id": 14, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:45.500Z", - "updated_at": "2016-03-22T15:13:45.500Z", - "action": 1, - "author_id": 10 - }, - { - "id": 155, - "target_type": "MergeRequest", - "target_id": 13, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:45.242Z", - "updated_at": "2016-03-22T15:13:45.242Z", - "action": 1, - "author_id": 1 - }, - { - "id": 154, - "target_type": "MergeRequest", - "target_id": 12, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:44.940Z", - "updated_at": "2016-03-22T15:13:44.940Z", - "action": 1, - "author_id": 24 - }, - { - "id": 153, - "target_type": "MergeRequest", - "target_id": 11, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:44.568Z", - "updated_at": "2016-03-22T15:13:44.568Z", - "action": 1, - "author_id": 26 - }, - { - "id": 152, - "target_type": "MergeRequest", - "target_id": 10, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:44.225Z", - "updated_at": "2016-03-22T15:13:44.225Z", - "action": 1, - "author_id": 22 - }, - { - "id": 151, - "target_type": "MergeRequest", - "target_id": 9, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:43.868Z", - "updated_at": "2016-03-22T15:13:43.868Z", - "action": 1, - "author_id": 24 - }, - { - "id": 102, - "target_type": "Issue", - "target_id": 40, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:28.474Z", - "updated_at": "2016-03-22T15:13:28.474Z", - "action": 1, - "author_id": 4 - }, - { - "id": 101, - "target_type": "Issue", - "target_id": 39, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:28.328Z", - "updated_at": "2016-03-22T15:13:28.328Z", - "action": 1, - "author_id": 12 - }, - { - "id": 100, - "target_type": "Issue", - "target_id": 38, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:28.204Z", - "updated_at": "2016-03-22T15:13:28.204Z", - "action": 1, - "author_id": 3 - }, - { - "id": 99, - "target_type": "Issue", - "target_id": 37, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:28.055Z", - "updated_at": "2016-03-22T15:13:28.055Z", - "action": 1, - "author_id": 10 - }, - { - "id": 98, - "target_type": "Issue", - "target_id": 36, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:27.913Z", - "updated_at": "2016-03-22T15:13:27.913Z", - "action": 1, - "author_id": 4 - }, - { - "id": 97, - "target_type": "Issue", - "target_id": 35, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:27.731Z", - "updated_at": "2016-03-22T15:13:27.731Z", - "action": 1, - "author_id": 1 - }, - { - "id": 96, - "target_type": "Issue", - "target_id": 34, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:27.564Z", - "updated_at": "2016-03-22T15:13:27.564Z", - "action": 1, - "author_id": 1 - }, - { - "id": 95, - "target_type": "Issue", - "target_id": 33, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:27.429Z", - "updated_at": "2016-03-22T15:13:27.429Z", - "action": 1, - "author_id": 22 - }, - { - "id": 94, - "target_type": "Issue", - "target_id": 32, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:27.287Z", - "updated_at": "2016-03-22T15:13:27.287Z", - "action": 1, - "author_id": 26 - }, - { - "id": 93, - "target_type": "Issue", - "target_id": 31, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:26.997Z", - "updated_at": "2016-03-22T15:13:26.997Z", - "action": 1, - "author_id": 24 - }, - { - "id": 51, - "target_type": "Milestone", - "target_id": 11, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:21.634Z", - "updated_at": "2016-03-22T15:13:21.634Z", - "action": 1, - "author_id": 26 - }, - { - "id": 50, - "target_type": "Milestone", - "target_id": 10, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:21.625Z", - "updated_at": "2016-03-22T15:13:21.625Z", - "action": 1, - "author_id": 22 - }, - { - "id": 24, - "target_type": null, - "target_id": null, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:20.750Z", - "updated_at": "2016-03-22T15:13:20.750Z", - "action": 8, - "author_id": 12 - }, - { - "id": 23, - "target_type": null, - "target_id": null, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:20.711Z", - "updated_at": "2016-03-22T15:13:20.711Z", - "action": 8, - "author_id": 22 - }, - { - "id": 22, - "target_type": null, - "target_id": null, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:20.667Z", - "updated_at": "2016-03-22T15:13:20.667Z", - "action": 8, - "author_id": 26 - }, - { - "id": 21, - "target_type": null, - "target_id": null, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:20.646Z", - "updated_at": "2016-03-22T15:13:20.646Z", - "action": 8, - "author_id": 1 - }, - { - "id": 5, - "target_type": null, - "target_id": null, - "title": null, - "data": null, - "project_id": 5, - "created_at": "2016-03-22T15:13:10.369Z", - "updated_at": "2016-03-22T15:13:10.369Z", - "action": 1, - "author_id": 1 - } ], "project_members": [ { - "id": 35, + "id": 36, "access_level": 40, "source_id": 5, "source_type": "Project", - "user_id": 12, + "user_id": 16, "notification_level": 3, - "created_at": "2016-03-22T15:13:20.743Z", - "updated_at": "2016-03-22T15:13:20.743Z", + "created_at": "2016-06-14T15:02:03.834Z", + "updated_at": "2016-06-14T15:02:03.834Z", "created_by_id": null, "invite_email": null, "invite_token": null, "invite_accepted_at": null, + "requested_at": null, "user": { - "id": 12, - "email": "maureen.bogisich@russelkessler.com", - "username": "evans" + "id": 16, + "email": "maritza_schoen@block.ca", + "username": "bernard_willms" + } + }, + { + "id": 35, + "access_level": 10, + "source_id": 5, + "source_type": "Project", + "user_id": 6, + "notification_level": 3, + "created_at": "2016-06-14T15:02:03.811Z", + "updated_at": "2016-06-14T15:02:03.811Z", + "created_by_id": null, + "invite_email": null, + "invite_token": null, + "invite_accepted_at": null, + "requested_at": null, + "user": { + "id": 6, + "email": "shaina@koelpindenesik.com", + "username": "saul_will" } }, { "id": 34, - "access_level": 40, + "access_level": 20, "source_id": 5, "source_type": "Project", - "user_id": 22, + "user_id": 15, "notification_level": 3, - "created_at": "2016-03-22T15:13:20.708Z", - "updated_at": "2016-03-22T15:13:20.708Z", + "created_at": "2016-06-14T15:02:03.776Z", + "updated_at": "2016-06-14T15:02:03.776Z", "created_by_id": null, "invite_email": null, "invite_token": null, "invite_accepted_at": null, + "requested_at": null, "user": { - "id": 22, - "email": "user0@example.com", - "username": "user0" + "id": 15, + "email": "breanna_sanford@wolf.com", + "username": "emmet.schamberger" } }, { "id": 33, - "access_level": 40, + "access_level": 20, "source_id": 5, "source_type": "Project", "user_id": 26, "notification_level": 3, - "created_at": "2016-03-22T15:13:20.664Z", - "updated_at": "2016-03-22T15:13:20.664Z", + "created_at": "2016-06-14T15:02:03.742Z", + "updated_at": "2016-06-14T15:02:03.742Z", "created_by_id": null, "invite_email": null, "invite_token": null, "invite_accepted_at": null, + "requested_at": null, "user": { "id": 26, "email": "user4@example.com", "username": "user4" } - }, - { - "id": 32, - "access_level": 20, - "source_id": 5, - "source_type": "Project", - "user_id": 1, - "notification_level": 3, - "created_at": "2016-03-22T15:13:20.643Z", - "updated_at": "2016-03-22T15:13:20.643Z", - "created_by_id": null, - "invite_email": null, - "invite_token": null, - "invite_accepted_at": null, - "user": { - "id": 1, - "email": "nospam@bluegod.net", - "username": "root" - } } ], "merge_requests": [ { - "id": 85, + "id": 27, "target_branch": "feature", "source_branch": "feature_conflict", "source_project_id": 5, "author_id": 1, "assignee_id": null, "title": "Cannot be automatically merged", - "created_at": "2016-03-22T15:19:44.807Z", - "updated_at": "2016-03-22T15:20:09.557Z", + "created_at": "2016-06-14T15:02:36.568Z", + "updated_at": "2016-06-14T15:02:56.815Z", "milestone_id": null, "state": "opened", "merge_status": "unchecked", @@ -2399,7 +2481,7 @@ "updated_by_id": null, "merge_error": null, "merge_params": { - + "force_remove_source_branch": null }, "merge_when_build_succeeds": false, "merge_user_id": null, @@ -2407,176 +2489,200 @@ "deleted_at": null, "notes": [ { - "id": 638, - "note": "Ab velit ducimus totam sunt ut.", - "noteable_type": "MergeRequest", - "author_id": 1, - "created_at": "2016-03-22T15:20:09.553Z", - "updated_at": "2016-03-22T15:20:09.553Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 85, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 637, - "note": "Ipsum aliquam est in unde similique nihil illo ea.", - "noteable_type": "MergeRequest", - "author_id": 3, - "created_at": "2016-03-22T15:20:09.528Z", - "updated_at": "2016-03-22T15:20:09.528Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 85, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 636, - "note": "Soluta inventore adipisci et consequatur expedita aliquid earum modi.", - "noteable_type": "MergeRequest", - "author_id": 4, - "created_at": "2016-03-22T15:20:09.496Z", - "updated_at": "2016-03-22T15:20:09.496Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 85, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 635, - "note": "Corporis incidunt tempore est deleniti.", - "noteable_type": "MergeRequest", - "author_id": 10, - "created_at": "2016-03-22T15:20:09.469Z", - "updated_at": "2016-03-22T15:20:09.469Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 85, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 634, - "note": "Hic dolores voluptatibus qui necessitatibus.", - "noteable_type": "MergeRequest", - "author_id": 12, - "created_at": "2016-03-22T15:20:09.440Z", - "updated_at": "2016-03-22T15:20:09.440Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 85, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 633, - "note": "Rerum architecto placeat doloribus voluptates consequuntur quo.", - "noteable_type": "MergeRequest", - "author_id": 22, - "created_at": "2016-03-22T15:20:09.412Z", - "updated_at": "2016-03-22T15:20:09.412Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 85, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 632, - "note": "Vel earum aut ut occaecati aut ut rerum qui.", - "noteable_type": "MergeRequest", - "author_id": 24, - "created_at": "2016-03-22T15:20:09.389Z", - "updated_at": "2016-03-22T15:20:09.389Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 85, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 631, - "note": "Est voluptatibus dolores animi numquam.", + "id": 671, + "note": "Sit voluptatibus eveniet architecto quidem.", "noteable_type": "MergeRequest", "author_id": 26, - "created_at": "2016-03-22T15:20:09.361Z", - "updated_at": "2016-03-22T15:20:09.361Z", + "created_at": "2016-06-14T15:02:56.632Z", + "updated_at": "2016-06-14T15:02:56.632Z", "project_id": 5, "attachment": { "url": null }, "line_code": null, "commit_id": null, - "noteable_id": 85, + "noteable_id": 27, "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] + }, + { + "id": 672, + "note": "Odio maxime ratione voluptatibus sed.", + "noteable_type": "MergeRequest", + "author_id": 25, + "created_at": "2016-06-14T15:02:56.656Z", + "updated_at": "2016-06-14T15:02:56.656Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 27, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 673, + "note": "Et deserunt et omnis nihil excepturi accusantium.", + "noteable_type": "MergeRequest", + "author_id": 22, + "created_at": "2016-06-14T15:02:56.679Z", + "updated_at": "2016-06-14T15:02:56.679Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 27, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 674, + "note": "Saepe asperiores exercitationem non dignissimos laborum reiciendis et ipsum.", + "noteable_type": "MergeRequest", + "author_id": 20, + "created_at": "2016-06-14T15:02:56.700Z", + "updated_at": "2016-06-14T15:02:56.700Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 27, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 675, + "note": "Numquam est at dolor quo et sed eligendi similique.", + "noteable_type": "MergeRequest", + "author_id": 16, + "created_at": "2016-06-14T15:02:56.720Z", + "updated_at": "2016-06-14T15:02:56.720Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 27, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 676, + "note": "Et perferendis aliquam sunt nisi labore delectus.", + "noteable_type": "MergeRequest", + "author_id": 15, + "created_at": "2016-06-14T15:02:56.742Z", + "updated_at": "2016-06-14T15:02:56.742Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 27, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 677, + "note": "Aut ex rerum et in.", + "noteable_type": "MergeRequest", + "author_id": 6, + "created_at": "2016-06-14T15:02:56.791Z", + "updated_at": "2016-06-14T15:02:56.791Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 27, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 678, + "note": "Dolor laborum earum ut exercitationem.", + "noteable_type": "MergeRequest", + "author_id": 1, + "created_at": "2016-06-14T15:02:56.814Z", + "updated_at": "2016-06-14T15:02:56.814Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 27, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] } ], "merge_request_diff": { - "id": 85, + "id": 27, "state": "collected", "st_commits": [ { @@ -2759,23 +2865,49 @@ "too_large": false } ], - "merge_request_id": 85, - "created_at": "2016-03-22T15:19:44.810Z", - "updated_at": "2016-03-22T15:19:44.901Z", + "merge_request_id": 27, + "created_at": "2016-06-14T15:02:36.572Z", + "updated_at": "2016-06-14T15:02:36.658Z", "base_commit_sha": "ae73cb07c9eeaf35924a10f713b364d32b2dd34f", "real_size": "9" - } + }, + "events": [ + { + "id": 221, + "target_type": "MergeRequest", + "target_id": 27, + "title": null, + "data": null, + "project_id": 36, + "created_at": "2016-06-14T15:02:36.703Z", + "updated_at": "2016-06-14T15:02:36.703Z", + "action": 1, + "author_id": 1 + }, + { + "id": 187, + "target_type": "MergeRequest", + "target_id": 27, + "title": null, + "data": null, + "project_id": 5, + "created_at": "2016-06-14T15:02:36.703Z", + "updated_at": "2016-06-14T15:02:36.703Z", + "action": 1, + "author_id": 1 + } + ] }, { - "id": 84, + "id": 26, "target_branch": "master", "source_branch": "feature", "source_project_id": 5, "author_id": 1, "assignee_id": null, "title": "Can be automatically merged", - "created_at": "2016-03-22T15:19:44.482Z", - "updated_at": "2016-03-22T15:20:09.773Z", + "created_at": "2016-06-14T15:02:36.418Z", + "updated_at": "2016-06-14T15:02:57.013Z", "milestone_id": null, "state": "opened", "merge_status": "unchecked", @@ -2787,7 +2919,7 @@ "updated_by_id": null, "merge_error": null, "merge_params": { - + "force_remove_source_branch": null }, "merge_when_build_succeeds": false, "merge_user_id": null, @@ -2795,176 +2927,200 @@ "deleted_at": null, "notes": [ { - "id": 646, - "note": "Temporibus debitis veniam est ut sit nihil.", - "noteable_type": "MergeRequest", - "author_id": 1, - "created_at": "2016-03-22T15:20:09.770Z", - "updated_at": "2016-03-22T15:20:09.770Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 84, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 645, - "note": "Ut assumenda dignissimos quibusdam veritatis sequi dolores.", - "noteable_type": "MergeRequest", - "author_id": 3, - "created_at": "2016-03-22T15:20:09.740Z", - "updated_at": "2016-03-22T15:20:09.740Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 84, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 644, - "note": "Velit quae quidem cupiditate laudantium nihil ut eveniet.", - "noteable_type": "MergeRequest", - "author_id": 4, - "created_at": "2016-03-22T15:20:09.717Z", - "updated_at": "2016-03-22T15:20:09.717Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 84, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 643, - "note": "Repellat quas porro sed mollitia laborum ut fugiat.", - "noteable_type": "MergeRequest", - "author_id": 10, - "created_at": "2016-03-22T15:20:09.690Z", - "updated_at": "2016-03-22T15:20:09.690Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 84, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 642, - "note": "Qui aut debitis perspiciatis et voluptatem.", - "noteable_type": "MergeRequest", - "author_id": 12, - "created_at": "2016-03-22T15:20:09.665Z", - "updated_at": "2016-03-22T15:20:09.665Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 84, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 641, - "note": "Quia id quia velit et.", - "noteable_type": "MergeRequest", - "author_id": 22, - "created_at": "2016-03-22T15:20:09.639Z", - "updated_at": "2016-03-22T15:20:09.639Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 84, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 640, - "note": "Corporis commodi doloremque itaque non animi.", - "noteable_type": "MergeRequest", - "author_id": 24, - "created_at": "2016-03-22T15:20:09.617Z", - "updated_at": "2016-03-22T15:20:09.617Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 84, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 639, - "note": "Possimus dignissimos voluptatum in tenetur.", + "id": 679, + "note": "Qui rerum totam nisi est.", "noteable_type": "MergeRequest", "author_id": 26, - "created_at": "2016-03-22T15:20:09.589Z", - "updated_at": "2016-03-22T15:20:09.589Z", + "created_at": "2016-06-14T15:02:56.848Z", + "updated_at": "2016-06-14T15:02:56.848Z", "project_id": 5, "attachment": { "url": null }, "line_code": null, "commit_id": null, - "noteable_id": 84, + "noteable_id": 26, "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] + }, + { + "id": 680, + "note": "Pariatur magni corrupti consequatur debitis minima error beatae voluptatem.", + "noteable_type": "MergeRequest", + "author_id": 25, + "created_at": "2016-06-14T15:02:56.871Z", + "updated_at": "2016-06-14T15:02:56.871Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 26, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 681, + "note": "Qui quis ut modi eos rerum ratione.", + "noteable_type": "MergeRequest", + "author_id": 22, + "created_at": "2016-06-14T15:02:56.895Z", + "updated_at": "2016-06-14T15:02:56.895Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 26, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 682, + "note": "Illum quidem expedita mollitia fugit.", + "noteable_type": "MergeRequest", + "author_id": 20, + "created_at": "2016-06-14T15:02:56.918Z", + "updated_at": "2016-06-14T15:02:56.918Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 26, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 683, + "note": "Consectetur voluptate sit sint possimus veritatis quod.", + "noteable_type": "MergeRequest", + "author_id": 16, + "created_at": "2016-06-14T15:02:56.942Z", + "updated_at": "2016-06-14T15:02:56.942Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 26, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 684, + "note": "Natus libero quibusdam rem assumenda deleniti accusamus sed earum.", + "noteable_type": "MergeRequest", + "author_id": 15, + "created_at": "2016-06-14T15:02:56.966Z", + "updated_at": "2016-06-14T15:02:56.966Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 26, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 685, + "note": "Tenetur autem nihil rerum odit.", + "noteable_type": "MergeRequest", + "author_id": 6, + "created_at": "2016-06-14T15:02:56.989Z", + "updated_at": "2016-06-14T15:02:56.989Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 26, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 686, + "note": "Quia maiores et odio sed.", + "noteable_type": "MergeRequest", + "author_id": 1, + "created_at": "2016-06-14T15:02:57.012Z", + "updated_at": "2016-06-14T15:02:57.012Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 26, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] } ], "merge_request_diff": { - "id": 84, + "id": 26, "state": "collected", "st_commits": [ { @@ -2994,35 +3150,61 @@ "too_large": false } ], - "merge_request_id": 84, - "created_at": "2016-03-22T15:19:44.485Z", - "updated_at": "2016-03-22T15:19:44.577Z", + "merge_request_id": 26, + "created_at": "2016-06-14T15:02:36.421Z", + "updated_at": "2016-06-14T15:02:36.474Z", "base_commit_sha": "ae73cb07c9eeaf35924a10f713b364d32b2dd34f", "real_size": "1" - } + }, + "events": [ + { + "id": 222, + "target_type": "MergeRequest", + "target_id": 26, + "title": null, + "data": null, + "project_id": 36, + "created_at": "2016-06-14T15:02:36.496Z", + "updated_at": "2016-06-14T15:02:36.496Z", + "action": 1, + "author_id": 1 + }, + { + "id": 186, + "target_type": "MergeRequest", + "target_id": 26, + "title": null, + "data": null, + "project_id": 5, + "created_at": "2016-06-14T15:02:36.496Z", + "updated_at": "2016-06-14T15:02:36.496Z", + "action": 1, + "author_id": 1 + } + ] }, { "id": 15, - "target_branch": "markdown", - "source_branch": "master", + "target_branch": "test-7", + "source_branch": "test-1", "source_project_id": 5, - "author_id": 3, - "assignee_id": 3, - "title": "Nulla explicabo iure voluptas perferendis autem autem unde nemo totam optio.", - "created_at": "2016-03-22T15:13:45.689Z", - "updated_at": "2016-03-22T15:20:30.476Z", - "milestone_id": 10, + "author_id": 22, + "assignee_id": 16, + "title": "Qui accusantium et inventore facilis doloribus occaecati officiis.", + "created_at": "2016-06-14T15:02:25.168Z", + "updated_at": "2016-06-14T15:02:59.521Z", + "milestone_id": 17, "state": "opened", "merge_status": "unchecked", "target_project_id": 5, "iid": 7, - "description": "Doloribus dignissimos impedit qui et provident exercitationem. Veniam quis magni qui fugiat. Et quia voluptate et vel consequatur pariatur ea est.", + "description": "Et commodi deserunt aspernatur vero rerum. Ut non dolorum alias in odit est libero. Voluptatibus eos in et vitae repudiandae facilis ex mollitia.", "position": 0, "locked_at": null, "updated_by_id": null, "merge_error": null, "merge_params": { - + "force_remove_source_branch": null }, "merge_when_build_succeeds": false, "merge_user_id": null, @@ -3030,159 +3212,12 @@ "deleted_at": null, "notes": [ { - "id": 1231, - "note": "Rerum optio quibusdam provident possimus quis cum.", - "noteable_type": "MergeRequest", - "author_id": 1, - "created_at": "2016-03-22T15:20:30.472Z", - "updated_at": "2016-03-22T15:20:30.472Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 15, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 1230, - "note": "Quasi odit repudiandae ut officiis ut nihil illo.", - "noteable_type": "MergeRequest", - "author_id": 3, - "created_at": "2016-03-22T15:20:30.444Z", - "updated_at": "2016-03-22T15:20:30.444Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 15, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 1229, - "note": "Aut vero dolores facere sed.", - "noteable_type": "MergeRequest", - "author_id": 4, - "created_at": "2016-03-22T15:20:30.412Z", - "updated_at": "2016-03-22T15:20:30.412Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 15, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 1228, - "note": "Autem voluptatem et blanditiis accusantium deserunt et et.", - "noteable_type": "MergeRequest", - "author_id": 10, - "created_at": "2016-03-22T15:20:30.383Z", - "updated_at": "2016-03-22T15:20:30.383Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 15, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 1227, - "note": "Voluptatem aliquam voluptatem molestiae est.", - "noteable_type": "MergeRequest", - "author_id": 12, - "created_at": "2016-03-22T15:20:30.352Z", - "updated_at": "2016-03-22T15:20:30.352Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 15, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 1226, - "note": "Ea aut cupiditate est consequatur animi error qui et.", - "noteable_type": "MergeRequest", - "author_id": 22, - "created_at": "2016-03-22T15:20:30.319Z", - "updated_at": "2016-03-22T15:20:30.319Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 15, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 1225, - "note": "Voluptates est voluptas et nostrum modi beatae inventore et.", - "noteable_type": "MergeRequest", - "author_id": 24, - "created_at": "2016-03-22T15:20:30.289Z", - "updated_at": "2016-03-22T15:20:30.289Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 15, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 1224, - "note": "Quia est rerum adipisci cupiditate.", + "id": 777, + "note": "Pariatur voluptas placeat aspernatur culpa suscipit soluta.", "noteable_type": "MergeRequest", "author_id": 26, - "created_at": "2016-03-22T15:20:30.260Z", - "updated_at": "2016-03-22T15:20:30.260Z", + "created_at": "2016-06-14T15:02:59.348Z", + "updated_at": "2016-06-14T15:02:59.348Z", "project_id": 5, "attachment": { "url": null @@ -3193,15 +3228,1175 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] + }, + { + "id": 778, + "note": "Alias et iure mollitia suscipit molestiae voluptatum nostrum asperiores.", + "noteable_type": "MergeRequest", + "author_id": 25, + "created_at": "2016-06-14T15:02:59.372Z", + "updated_at": "2016-06-14T15:02:59.372Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 15, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 779, + "note": "Laudantium qui eum qui sunt.", + "noteable_type": "MergeRequest", + "author_id": 22, + "created_at": "2016-06-14T15:02:59.395Z", + "updated_at": "2016-06-14T15:02:59.395Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 15, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 780, + "note": "Quas rem est iusto ut delectus fugiat recusandae mollitia.", + "noteable_type": "MergeRequest", + "author_id": 20, + "created_at": "2016-06-14T15:02:59.418Z", + "updated_at": "2016-06-14T15:02:59.418Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 15, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 781, + "note": "Repellendus ab et qui nesciunt.", + "noteable_type": "MergeRequest", + "author_id": 16, + "created_at": "2016-06-14T15:02:59.444Z", + "updated_at": "2016-06-14T15:02:59.444Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 15, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 782, + "note": "Non possimus voluptatum odio qui ut.", + "noteable_type": "MergeRequest", + "author_id": 15, + "created_at": "2016-06-14T15:02:59.469Z", + "updated_at": "2016-06-14T15:02:59.469Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 15, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 783, + "note": "Dolores repellendus eum ducimus quam ab dolorem quia.", + "noteable_type": "MergeRequest", + "author_id": 6, + "created_at": "2016-06-14T15:02:59.494Z", + "updated_at": "2016-06-14T15:02:59.494Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 15, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 784, + "note": "Facilis dolorem aut corrupti id ratione occaecati.", + "noteable_type": "MergeRequest", + "author_id": 1, + "created_at": "2016-06-14T15:02:59.520Z", + "updated_at": "2016-06-14T15:02:59.520Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 15, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] } ], "merge_request_diff": { "id": 15, "state": "collected", "st_commits": [ + { + "id": "94b8d581c48d894b86661718582fecbc5e3ed2eb", + "message": "fixes #10\n", + "parent_ids": [ + "be93687618e4b132087f430a4d8fc3a609c9b77c" + ], + "authored_date": "2016-01-19T13:22:56.000+01:00", + "author_name": "James Lopez", + "author_email": "james@jameslopez.es", + "committed_date": "2016-01-19T13:22:56.000+01:00", + "committer_name": "James Lopez", + "committer_email": "james@jameslopez.es" + } + ], + "st_diffs": [ + { + "diff": "--- /dev/null\n+++ b/test\n", + "new_path": "test", + "old_path": "test", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + } + ], + "merge_request_id": 15, + "created_at": "2016-06-14T15:02:25.171Z", + "updated_at": "2016-06-14T15:02:25.230Z", + "base_commit_sha": "be93687618e4b132087f430a4d8fc3a609c9b77c", + "real_size": "1" + }, + "events": [ + { + "id": 223, + "target_type": "MergeRequest", + "target_id": 15, + "title": null, + "data": null, + "project_id": 36, + "created_at": "2016-06-14T15:02:25.262Z", + "updated_at": "2016-06-14T15:02:25.262Z", + "action": 1, + "author_id": 1 + }, + { + "id": 175, + "target_type": "MergeRequest", + "target_id": 15, + "title": null, + "data": null, + "project_id": 5, + "created_at": "2016-06-14T15:02:25.262Z", + "updated_at": "2016-06-14T15:02:25.262Z", + "action": 1, + "author_id": 22 + } + ] + }, + { + "id": 14, + "target_branch": "fix", + "source_branch": "test-3", + "source_project_id": 5, + "author_id": 20, + "assignee_id": 20, + "title": "In voluptas aut sequi voluptatem ullam vel corporis illum consequatur.", + "created_at": "2016-06-14T15:02:24.760Z", + "updated_at": "2016-06-14T15:02:59.749Z", + "milestone_id": 20, + "state": "opened", + "merge_status": "unchecked", + "target_project_id": 5, + "iid": 6, + "description": "Dicta magnam non voluptates nam dignissimos nostrum deserunt. Dolorum et suscipit iure quae doloremque. Necessitatibus saepe aut labore sed.", + "position": 0, + "locked_at": null, + "updated_by_id": null, + "merge_error": null, + "merge_params": { + "force_remove_source_branch": null + }, + "merge_when_build_succeeds": false, + "merge_user_id": null, + "merge_commit_sha": null, + "deleted_at": null, + "notes": [ + { + "id": 785, + "note": "Atque cupiditate necessitatibus deserunt minus natus odit.", + "noteable_type": "MergeRequest", + "author_id": 26, + "created_at": "2016-06-14T15:02:59.559Z", + "updated_at": "2016-06-14T15:02:59.559Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 14, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 4" + }, + "events": [ + + ] + }, + { + "id": 786, + "note": "Non dolorem provident mollitia nesciunt optio ex eveniet.", + "noteable_type": "MergeRequest", + "author_id": 25, + "created_at": "2016-06-14T15:02:59.587Z", + "updated_at": "2016-06-14T15:02:59.587Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 14, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 787, + "note": "Similique officia nemo quasi commodi accusantium quae qui.", + "noteable_type": "MergeRequest", + "author_id": 22, + "created_at": "2016-06-14T15:02:59.621Z", + "updated_at": "2016-06-14T15:02:59.621Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 14, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 788, + "note": "Et est et alias ad dolor qui.", + "noteable_type": "MergeRequest", + "author_id": 20, + "created_at": "2016-06-14T15:02:59.650Z", + "updated_at": "2016-06-14T15:02:59.650Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 14, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 789, + "note": "Numquam temporibus ratione voluptatibus aliquid.", + "noteable_type": "MergeRequest", + "author_id": 16, + "created_at": "2016-06-14T15:02:59.675Z", + "updated_at": "2016-06-14T15:02:59.675Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 14, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 790, + "note": "Ut ex aliquam consectetur perferendis est hic aut quia.", + "noteable_type": "MergeRequest", + "author_id": 15, + "created_at": "2016-06-14T15:02:59.703Z", + "updated_at": "2016-06-14T15:02:59.703Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 14, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 791, + "note": "Esse eos quam quaerat aut ut asperiores officiis.", + "noteable_type": "MergeRequest", + "author_id": 6, + "created_at": "2016-06-14T15:02:59.726Z", + "updated_at": "2016-06-14T15:02:59.726Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 14, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 792, + "note": "Sint facilis accusantium iure blanditiis.", + "noteable_type": "MergeRequest", + "author_id": 1, + "created_at": "2016-06-14T15:02:59.748Z", + "updated_at": "2016-06-14T15:02:59.748Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 14, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] + } + ], + "merge_request_diff": { + "id": 14, + "state": "collected", + "st_commits": [ + { + "id": "ddd4ff416a931589c695eb4f5b23f844426f6928", + "message": "fixes #10\n", + "parent_ids": [ + "be93687618e4b132087f430a4d8fc3a609c9b77c" + ], + "authored_date": "2016-01-19T14:14:43.000+01:00", + "author_name": "James Lopez", + "author_email": "james@jameslopez.es", + "committed_date": "2016-01-19T14:14:43.000+01:00", + "committer_name": "James Lopez", + "committer_email": "james@jameslopez.es" + }, + { + "id": "be93687618e4b132087f430a4d8fc3a609c9b77c", + "message": "Merge branch 'master' into 'master'\r\n\r\nLFS object pointer.\r\n\r\n\r\n\r\nSee merge request !6", + "parent_ids": [ + "5f923865dde3436854e9ceb9cdb7815618d4e849", + "048721d90c449b244b7b4c53a9186b04330174ec" + ], + "authored_date": "2015-12-07T12:52:12.000+01:00", + "author_name": "Marin Jankovski", + "author_email": "marin@gitlab.com", + "committed_date": "2015-12-07T12:52:12.000+01:00", + "committer_name": "Marin Jankovski", + "committer_email": "marin@gitlab.com" + }, + { + "id": "048721d90c449b244b7b4c53a9186b04330174ec", + "message": "LFS object pointer.\n", + "parent_ids": [ + "5f923865dde3436854e9ceb9cdb7815618d4e849" + ], + "authored_date": "2015-12-07T11:54:28.000+01:00", + "author_name": "Marin Jankovski", + "author_email": "maxlazio@gmail.com", + "committed_date": "2015-12-07T11:54:28.000+01:00", + "committer_name": "Marin Jankovski", + "committer_email": "maxlazio@gmail.com" + }, + { + "id": "5f923865dde3436854e9ceb9cdb7815618d4e849", + "message": "GitLab currently doesn't support patches that involve a merge commit: add a commit here\n", + "parent_ids": [ + "d2d430676773caa88cdaf7c55944073b2fd5561a" + ], + "authored_date": "2015-11-13T16:27:12.000+01:00", + "author_name": "Stan Hu", + "author_email": "stanhu@gmail.com", + "committed_date": "2015-11-13T16:27:12.000+01:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@gmail.com" + }, + { + "id": "d2d430676773caa88cdaf7c55944073b2fd5561a", + "message": "Merge branch 'add-svg' into 'master'\r\n\r\nAdd GitLab SVG\r\n\r\nAdded to test preview of sanitized SVG images\r\n\r\nSee merge request !5", + "parent_ids": [ + "59e29889be61e6e0e5e223bfa9ac2721d31605b8", + "2ea1f3dec713d940208fb5ce4a38765ecb5d3f73" + ], + "authored_date": "2015-11-13T08:50:17.000+01:00", + "author_name": "Stan Hu", + "author_email": "stanhu@gmail.com", + "committed_date": "2015-11-13T08:50:17.000+01:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@gmail.com" + }, + { + "id": "2ea1f3dec713d940208fb5ce4a38765ecb5d3f73", + "message": "Add GitLab SVG\n", + "parent_ids": [ + "59e29889be61e6e0e5e223bfa9ac2721d31605b8" + ], + "authored_date": "2015-11-13T08:39:43.000+01:00", + "author_name": "Stan Hu", + "author_email": "stanhu@gmail.com", + "committed_date": "2015-11-13T08:39:43.000+01:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@gmail.com" + }, + { + "id": "59e29889be61e6e0e5e223bfa9ac2721d31605b8", + "message": "Merge branch 'whitespace' into 'master'\r\n\r\nadd whitespace test file\r\n\r\nSorry, I did a mistake.\r\nGit ignore empty files.\r\nSo I add a new whitespace test file.\r\n\r\nSee merge request !4", + "parent_ids": [ + "19e2e9b4ef76b422ce1154af39a91323ccc57434", + "66eceea0db202bb39c4e445e8ca28689645366c5" + ], + "authored_date": "2015-11-13T07:21:40.000+01:00", + "author_name": "Stan Hu", + "author_email": "stanhu@gmail.com", + "committed_date": "2015-11-13T07:21:40.000+01:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@gmail.com" + }, + { + "id": "66eceea0db202bb39c4e445e8ca28689645366c5", + "message": "add spaces in whitespace file\n", + "parent_ids": [ + "08f22f255f082689c0d7d39d19205085311542bc" + ], + "authored_date": "2015-11-13T06:01:27.000+01:00", + "author_name": "윤민식", + "author_email": "minsik.yoon@samsung.com", + "committed_date": "2015-11-13T06:01:27.000+01:00", + "committer_name": "윤민식", + "committer_email": "minsik.yoon@samsung.com" + }, + { + "id": "08f22f255f082689c0d7d39d19205085311542bc", + "message": "remove emtpy file.(beacase git ignore empty file)\nadd whitespace test file.\n", + "parent_ids": [ + "c642fe9b8b9f28f9225d7ea953fe14e74748d53b" + ], + "authored_date": "2015-11-13T06:00:16.000+01:00", + "author_name": "윤민식", + "author_email": "minsik.yoon@samsung.com", + "committed_date": "2015-11-13T06:00:16.000+01:00", + "committer_name": "윤민식", + "committer_email": "minsik.yoon@samsung.com" + }, + { + "id": "19e2e9b4ef76b422ce1154af39a91323ccc57434", + "message": "Merge branch 'whitespace' into 'master'\r\n\r\nadd spaces\r\n\r\nTo test this pull request.(https://github.com/gitlabhq/gitlabhq/pull/9757)\r\nJust add whitespaces.\r\n\r\nSee merge request !3", + "parent_ids": [ + "c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd", + "c642fe9b8b9f28f9225d7ea953fe14e74748d53b" + ], + "authored_date": "2015-11-13T05:23:14.000+01:00", + "author_name": "Stan Hu", + "author_email": "stanhu@gmail.com", + "committed_date": "2015-11-13T05:23:14.000+01:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@gmail.com" + }, + { + "id": "c642fe9b8b9f28f9225d7ea953fe14e74748d53b", + "message": "add whitespace in empty\n", + "parent_ids": [ + "9a944d90955aaf45f6d0c88f30e27f8d2c41cec0" + ], + "authored_date": "2015-11-13T05:08:45.000+01:00", + "author_name": "윤민식", + "author_email": "minsik.yoon@samsung.com", + "committed_date": "2015-11-13T05:08:45.000+01:00", + "committer_name": "윤민식", + "committer_email": "minsik.yoon@samsung.com" + }, + { + "id": "9a944d90955aaf45f6d0c88f30e27f8d2c41cec0", + "message": "add empty file\n", + "parent_ids": [ + "c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd" + ], + "authored_date": "2015-11-13T05:08:04.000+01:00", + "author_name": "윤민식", + "author_email": "minsik.yoon@samsung.com", + "committed_date": "2015-11-13T05:08:04.000+01:00", + "committer_name": "윤민식", + "committer_email": "minsik.yoon@samsung.com" + }, + { + "id": "c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd", + "message": "Add ISO-8859 test file\n", + "parent_ids": [ + "e56497bb5f03a90a51293fc6d516788730953899" + ], + "authored_date": "2015-08-25T17:53:12.000+02:00", + "author_name": "Stan Hu", + "author_email": "stanhu@packetzoom.com", + "committed_date": "2015-08-25T17:53:12.000+02:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@packetzoom.com" + }, + { + "id": "e56497bb5f03a90a51293fc6d516788730953899", + "message": "Merge branch 'tree_helper_spec' into 'master'\n\nAdd directory structure for tree_helper spec\n\nThis directory structure is needed for a testing the method flatten_tree(tree) in the TreeHelper module\n\nSee [merge request #275](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/275#note_732774)\n\nSee merge request !2\n", + "parent_ids": [ + "5937ac0a7beb003549fc5fd26fc247adbce4a52e", + "4cd80ccab63c82b4bad16faa5193fbd2aa06df40" + ], + "authored_date": "2015-01-10T22:23:29.000+01:00", + "author_name": "Sytse Sijbrandij", + "author_email": "sytse@gitlab.com", + "committed_date": "2015-01-10T22:23:29.000+01:00", + "committer_name": "Sytse Sijbrandij", + "committer_email": "sytse@gitlab.com" + }, + { + "id": "4cd80ccab63c82b4bad16faa5193fbd2aa06df40", + "message": "add directory structure for tree_helper spec\n", + "parent_ids": [ + "5937ac0a7beb003549fc5fd26fc247adbce4a52e" + ], + "authored_date": "2015-01-10T21:28:18.000+01:00", + "author_name": "marmis85", + "author_email": "marmis85@gmail.com", + "committed_date": "2015-01-10T21:28:18.000+01:00", + "committer_name": "marmis85", + "committer_email": "marmis85@gmail.com" + }, + { + "id": "5937ac0a7beb003549fc5fd26fc247adbce4a52e", + "message": "Add submodule from gitlab.com\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", + "parent_ids": [ + "570e7b2abdd848b95f2f578043fc23bd6f6fd24d" + ], + "authored_date": "2014-02-27T10:01:38.000+01:00", + "author_name": "Dmitriy Zaporozhets", + "author_email": "dmitriy.zaporozhets@gmail.com", + "committed_date": "2014-02-27T10:01:38.000+01:00", + "committer_name": "Dmitriy Zaporozhets", + "committer_email": "dmitriy.zaporozhets@gmail.com" + }, + { + "id": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d", + "message": "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", + "parent_ids": [ + "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9" + ], + "authored_date": "2014-02-27T09:57:31.000+01:00", + "author_name": "Dmitriy Zaporozhets", + "author_email": "dmitriy.zaporozhets@gmail.com", + "committed_date": "2014-02-27T09:57:31.000+01:00", + "committer_name": "Dmitriy Zaporozhets", + "committer_email": "dmitriy.zaporozhets@gmail.com" + }, + { + "id": "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9", + "message": "More submodules\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", + "parent_ids": [ + "d14d6c0abdd253381df51a723d58691b2ee1ab08" + ], + "authored_date": "2014-02-27T09:54:21.000+01:00", + "author_name": "Dmitriy Zaporozhets", + "author_email": "dmitriy.zaporozhets@gmail.com", + "committed_date": "2014-02-27T09:54:21.000+01:00", + "committer_name": "Dmitriy Zaporozhets", + "committer_email": "dmitriy.zaporozhets@gmail.com" + }, + { + "id": "d14d6c0abdd253381df51a723d58691b2ee1ab08", + "message": "Remove ds_store files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", + "parent_ids": [ + "c1acaa58bbcbc3eafe538cb8274ba387047b69f8" + ], + "authored_date": "2014-02-27T09:49:50.000+01:00", + "author_name": "Dmitriy Zaporozhets", + "author_email": "dmitriy.zaporozhets@gmail.com", + "committed_date": "2014-02-27T09:49:50.000+01:00", + "committer_name": "Dmitriy Zaporozhets", + "committer_email": "dmitriy.zaporozhets@gmail.com" + }, + { + "id": "c1acaa58bbcbc3eafe538cb8274ba387047b69f8", + "message": "Ignore DS files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", + "parent_ids": [ + "ae73cb07c9eeaf35924a10f713b364d32b2dd34f" + ], + "authored_date": "2014-02-27T09:48:32.000+01:00", + "author_name": "Dmitriy Zaporozhets", + "author_email": "dmitriy.zaporozhets@gmail.com", + "committed_date": "2014-02-27T09:48:32.000+01:00", + "committer_name": "Dmitriy Zaporozhets", + "committer_email": "dmitriy.zaporozhets@gmail.com" + } + ], + "st_diffs": [ + { + "diff": "Binary files a/.DS_Store and /dev/null differ\n", + "new_path": ".DS_Store", + "old_path": ".DS_Store", + "a_mode": "100644", + "b_mode": "0", + "new_file": false, + "renamed_file": false, + "deleted_file": true, + "too_large": false + }, + { + "diff": "--- a/.gitignore\n+++ b/.gitignore\n@@ -17,3 +17,4 @@ rerun.txt\n pickle-email-*.html\n .project\n config/initializers/secret_token.rb\n+.DS_Store\n", + "new_path": ".gitignore", + "old_path": ".gitignore", + "a_mode": "100644", + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- a/.gitmodules\n+++ b/.gitmodules\n@@ -1,3 +1,9 @@\n [submodule \"six\"]\n \tpath = six\n \turl = git://github.com/randx/six.git\n+[submodule \"gitlab-shell\"]\n+\tpath = gitlab-shell\n+\turl = https://github.com/gitlabhq/gitlab-shell.git\n+[submodule \"gitlab-grack\"]\n+\tpath = gitlab-grack\n+\turl = https://gitlab.com/gitlab-org/gitlab-grack.git\n", + "new_path": ".gitmodules", + "old_path": ".gitmodules", + "a_mode": "100644", + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- a/CHANGELOG\n+++ b/CHANGELOG\n@@ -1,4 +1,6 @@\n-v 6.7.0\n+v6.8.0\n+\n+v6.7.0\n - Add support for Gemnasium as a Project Service (Olivier Gonzalez)\n - Add edit file button to MergeRequest diff\n - Public groups (Jason Hollingsworth)\n", + "new_path": "CHANGELOG", + "old_path": "CHANGELOG", + "a_mode": "100644", + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/encoding/iso8859.txt\n@@ -0,0 +1 @@\n+Äü\n", + "new_path": "encoding/iso8859.txt", + "old_path": "encoding/iso8859.txt", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "Binary files a/files/.DS_Store and /dev/null differ\n", + "new_path": "files/.DS_Store", + "old_path": "files/.DS_Store", + "a_mode": "100644", + "b_mode": "0", + "new_file": false, + "renamed_file": false, + "deleted_file": true, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/files/images/wm.svg\n@@ -0,0 +1,78 @@\n+\u003c?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?\u003e\n+\u003csvg width=\"1300px\" height=\"680px\" viewBox=\"0 0 1300 680\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\"\u003e\n+ \u003c!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch --\u003e\n+ \u003ctitle\u003ewm\u003c/title\u003e\n+ \u003cdesc\u003eCreated with Sketch.\u003c/desc\u003e\n+ \u003cdefs\u003e\n+ \u003cpath id=\"path-1\" d=\"M-69.8,1023.54607 L1675.19996,1023.54607 L1675.19996,0 L-69.8,0 L-69.8,1023.54607 L-69.8,1023.54607 Z\"\u003e\u003c/path\u003e\n+ \u003c/defs\u003e\n+ \u003cg id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\"\u003e\n+ \u003cpath d=\"M1300,680 L0,680 L0,0 L1300,0 L1300,680 L1300,680 Z\" id=\"bg\" fill=\"#30353E\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cg id=\"gitlab_logo\" sketch:type=\"MSLayerGroup\" transform=\"translate(-262.000000, -172.000000)\"\u003e\n+ \u003cg id=\"g10\" transform=\"translate(872.500000, 512.354581) scale(1, -1) translate(-872.500000, -512.354581) translate(0.000000, 0.290751)\"\u003e\n+ \u003cg id=\"g12\" transform=\"translate(1218.022652, 440.744871)\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\n+ \u003cpath d=\"M-50.0233338,141.900706 L-69.07059,141.900706 L-69.0100967,0.155858152 L8.04444805,0.155858152 L8.04444805,17.6840847 L-49.9628405,17.6840847 L-50.0233338,141.900706 L-50.0233338,141.900706 Z\" id=\"path14\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g16\"\u003e\n+ \u003cg id=\"g18-Clipped\"\u003e\n+ \u003cmask id=\"mask-2\" sketch:name=\"path22\" fill=\"white\"\u003e\n+ \u003cuse xlink:href=\"#path-1\"\u003e\u003c/use\u003e\n+ \u003c/mask\u003e\n+ \u003cg id=\"path22\"\u003e\u003c/g\u003e\n+ \u003cg id=\"g18\" mask=\"url(#mask-2)\"\u003e\n+ \u003cg transform=\"translate(382.736659, 312.879425)\"\u003e\n+ \u003cg id=\"g24\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(852.718192, 124.992771)\"\u003e\n+ \u003cpath d=\"M63.9833317,27.9148929 C59.2218085,22.9379001 51.2134221,17.9597442 40.3909323,17.9597442 C25.8888194,17.9597442 20.0453962,25.1013043 20.0453962,34.4074318 C20.0453962,48.4730484 29.7848226,55.1819277 50.5642821,55.1819277 C54.4602853,55.1819277 60.7364685,54.7492469 63.9833317,54.1002256 L63.9833317,27.9148929 L63.9833317,27.9148929 Z M44.2869356,113.827628 C28.9053426,113.827628 14.7975996,108.376082 3.78897657,99.301416 L10.5211864,87.6422957 C18.3131929,92.1866076 27.8374026,96.7320827 41.4728323,96.7320827 C57.0568452,96.7320827 63.9833317,88.7239978 63.9833317,75.3074024 L63.9833317,68.3821827 C60.9528485,69.0312039 54.6766653,69.4650479 50.7806621,69.4650479 C17.4476729,69.4650479 0.565379986,57.7791759 0.565379986,33.3245665 C0.565379986,11.4683685 13.9844297,0.43151772 34.3299658,0.43151772 C48.0351955,0.43151772 61.1692285,6.70771614 65.7143717,16.8780421 L69.1776149,3.02876588 L82.5978279,3.02876588 L82.5978279,75.5237428 C82.5978279,98.462806 72.6408582,113.827628 44.2869356,113.827628 L44.2869356,113.827628 Z\" id=\"path26\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g28\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(959.546624, 124.857151)\"\u003e\n+ \u003cpath d=\"M37.2266657,17.4468081 C30.0837992,17.4468081 23.8064527,18.3121698 19.0449295,20.4767371 L19.0449295,79.2306079 L19.0449295,86.0464943 C25.538656,91.457331 33.5470425,95.3526217 43.7203922,95.3526217 C62.1173451,95.3526217 69.2602116,82.3687072 69.2602116,61.3767077 C69.2602116,31.5135879 57.7885819,17.4468081 37.2266657,17.4468081 M45.2315622,113.963713 C28.208506,113.963713 19.0449295,102.384849 19.0449295,102.384849 L19.0449295,120.67143 L18.9844362,144.908535 L10.3967097,144.908535 L0.371103324,144.908535 L0.431596656,6.62629771 C9.73826309,2.73100702 22.5081728,0.567602823 36.3611458,0.567602823 C71.8579349,0.567602823 88.9566078,23.2891625 88.9566078,62.4584098 C88.9566078,93.4043948 73.1527248,113.963713 45.2315622,113.963713\" id=\"path30\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g32\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(509.576747, 125.294950)\"\u003e\n+ \u003cpath d=\"M68.636665,129.10638 C85.5189579,129.10638 96.3414476,123.480366 103.484314,117.853189 L111.669527,132.029302 C100.513161,141.811145 85.5073245,147.06845 69.5021849,147.06845 C29.0274926,147.06845 0.673569983,122.3975 0.673569983,72.6252464 C0.673569983,20.4709215 31.2622559,0.12910638 66.2553217,0.12910638 C83.7879179,0.12910638 98.7227909,4.24073748 108.462217,8.35236859 L108.063194,64.0763105 L108.063194,70.6502677 L108.063194,81.6057001 L56.1168719,81.6057001 L56.1168719,64.0763105 L89.2323178,64.0763105 L89.6313411,21.7701271 C85.3025779,19.6055598 77.7269514,17.8748364 67.554765,17.8748364 C39.4172223,17.8748364 20.5863462,35.5717154 20.5863462,72.8415868 C20.5863462,110.711628 40.0663623,129.10638 68.636665,129.10638\" id=\"path34\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g36\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(692.388992, 124.376085)\"\u003e\n+ \u003cpath d=\"M19.7766662,145.390067 L1.16216997,145.390067 L1.2226633,121.585642 L1.2226633,111.846834 L1.2226633,106.170806 L1.2226633,96.2656714 L1.2226633,39.5681976 L1.2226633,39.3518572 C1.2226633,16.4127939 11.1796331,1.04797161 39.5335557,1.04797161 C43.4504989,1.04797161 47.2836822,1.40388649 51.0051854,2.07965952 L51.0051854,18.7925385 C48.3109055,18.3796307 45.4351455,18.1446804 42.3476589,18.1446804 C26.763646,18.1446804 19.8371595,26.1516022 19.8371595,39.5681976 L19.8371595,96.2656714 L51.0051854,96.2656714 L51.0051854,111.846834 L19.8371595,111.846834 L19.7766662,145.390067 L19.7766662,145.390067 Z\" id=\"path38\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cpath d=\"M646.318899,128.021188 L664.933395,128.021188 L664.933395,236.223966 L646.318899,236.223966 L646.318899,128.021188 L646.318899,128.021188 Z\" id=\"path40\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cpath d=\"M646.318899,251.154944 L664.933395,251.154944 L664.933395,269.766036 L646.318899,269.766036 L646.318899,251.154944 L646.318899,251.154944 Z\" id=\"path42\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cg id=\"g44\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.464170, 0.676006)\"\u003e\n+ \u003cpath d=\"M429.269989,169.815599 L405.225053,243.802859 L357.571431,390.440955 C355.120288,397.984955 344.444378,397.984955 341.992071,390.440955 L294.337286,243.802859 L136.094873,243.802859 L88.4389245,390.440955 C85.9877812,397.984955 75.3118715,397.984955 72.8595648,390.440955 L25.2059427,243.802859 L1.16216997,169.815599 C-1.03187664,163.067173 1.37156997,155.674379 7.11261982,151.503429 L215.215498,0.336141836 L423.319539,151.503429 C429.060589,155.674379 431.462873,163.067173 429.269989,169.815599\" id=\"path46\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g48\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(135.410135, 1.012147)\"\u003e\n+ \u003cpath d=\"M80.269998,0 L80.269998,0 L159.391786,243.466717 L1.14820997,243.466717 L80.269998,0 L80.269998,0 Z\" id=\"path50\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g52\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\"\u003e\n+ \u003cg id=\"path54\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g56\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(24.893471, 1.012613)\"\u003e\n+ \u003cpath d=\"M190.786662,0 L111.664874,243.465554 L0.777106647,243.465554 L190.786662,0 L190.786662,0 Z\" id=\"path58\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g60\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\"\u003e\n+ \u003cg id=\"path62\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g64\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.077245, 0.223203)\"\u003e\n+ \u003cpath d=\"M25.5933327,244.255313 L25.5933327,244.255313 L1.54839663,170.268052 C-0.644486651,163.519627 1.75779662,156.126833 7.50000981,151.957046 L215.602888,0.789758846 L25.5933327,244.255313 L25.5933327,244.255313 Z\" id=\"path66\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g68\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\"\u003e\n+ \u003cg id=\"path70\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g72\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(25.670578, 244.478283)\"\u003e\n+ \u003cpath d=\"M0,0 L110.887767,0 L63.2329818,146.638096 C60.7806751,154.183259 50.1047654,154.183259 47.6536221,146.638096 L0,0 L0,0 Z\" id=\"path74\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g76\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\"\u003e\n+ \u003cpath d=\"M0,0 L79.121788,243.465554 L190.009555,243.465554 L0,0 L0,0 Z\" id=\"path78\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g80\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(214.902910, 0.223203)\"\u003e\n+ \u003cpath d=\"M190.786662,244.255313 L190.786662,244.255313 L214.831598,170.268052 C217.024481,163.519627 214.622198,156.126833 208.879985,151.957046 L0.777106647,0.789758846 L190.786662,244.255313 L190.786662,244.255313 Z\" id=\"path82\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g84\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(294.009575, 244.478283)\"\u003e\n+ \u003cpath d=\"M111.679997,0 L0.79222998,0 L48.4470155,146.638096 C50.8993221,154.183259 61.5752318,154.183259 64.0263751,146.638096 L111.679997,0 L111.679997,0 Z\" id=\"path86\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+\u003c/svg\u003e\n\\ No newline at end of file\n", + "new_path": "files/images/wm.svg", + "old_path": "files/images/wm.svg", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/files/lfs/lfs_object.iso\n@@ -0,0 +1,4 @@\n+version https://git-lfs.github.com/spec/v1\n+oid sha256:91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897\n+size 1575078\n+\n", + "new_path": "files/lfs/lfs_object.iso", + "old_path": "files/lfs/lfs_object.iso", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- a/files/ruby/popen.rb\n+++ b/files/ruby/popen.rb\n@@ -6,12 +6,18 @@ module Popen\n \n def popen(cmd, path=nil)\n unless cmd.is_a?(Array)\n- raise \"System commands must be given as an array of strings\"\n+ raise RuntimeError, \"System commands must be given as an array of strings\"\n end\n \n path ||= Dir.pwd\n- vars = { \"PWD\" =\u003e path }\n- options = { chdir: path }\n+\n+ vars = {\n+ \"PWD\" =\u003e path\n+ }\n+\n+ options = {\n+ chdir: path\n+ }\n \n unless File.directory?(path)\n FileUtils.mkdir_p(path)\n@@ -19,6 +25,7 @@ module Popen\n \n @cmd_output = \"\"\n @cmd_status = 0\n+\n Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|\n @cmd_output \u003c\u003c stdout.read\n @cmd_output \u003c\u003c stderr.read\n", + "new_path": "files/ruby/popen.rb", + "old_path": "files/ruby/popen.rb", + "a_mode": "100644", + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- a/files/ruby/regex.rb\n+++ b/files/ruby/regex.rb\n@@ -19,14 +19,12 @@ module Gitlab\n end\n \n def archive_formats_regex\n- #|zip|tar| tar.gz | tar.bz2 |\n- /(zip|tar|tar\\.gz|tgz|gz|tar\\.bz2|tbz|tbz2|tb2|bz2)/\n+ /(zip|tar|7z|tar\\.gz|tgz|gz|tar\\.bz2|tbz|tbz2|tb2|bz2)/\n end\n \n def git_reference_regex\n # Valid git ref regex, see:\n # https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html\n-\n %r{\n (?!\n (?# doesn't begins with)\n", + "new_path": "files/ruby/regex.rb", + "old_path": "files/ruby/regex.rb", + "a_mode": "100644", + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/files/whitespace\n@@ -0,0 +1 @@\n+test \n", + "new_path": "files/whitespace", + "old_path": "files/whitespace", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/foo/bar/.gitkeep\n", + "new_path": "foo/bar/.gitkeep", + "old_path": "foo/bar/.gitkeep", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/gitlab-grack\n@@ -0,0 +1 @@\n+Subproject commit 645f6c4c82fd3f5e06f67134450a570b795e55a6\n", + "new_path": "gitlab-grack", + "old_path": "gitlab-grack", + "a_mode": "0", + "b_mode": "160000", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/gitlab-shell\n@@ -0,0 +1 @@\n+Subproject commit 79bceae69cb5750d6567b223597999bfa91cb3b9\n", + "new_path": "gitlab-shell", + "old_path": "gitlab-shell", + "a_mode": "0", + "b_mode": "160000", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/test\n", + "new_path": "test", + "old_path": "test", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + } + ], + "merge_request_id": 14, + "created_at": "2016-06-14T15:02:24.770Z", + "updated_at": "2016-06-14T15:02:25.007Z", + "base_commit_sha": "ae73cb07c9eeaf35924a10f713b364d32b2dd34f", + "real_size": "15" + }, + "events": [ + { + "id": 224, + "target_type": "MergeRequest", + "target_id": 14, + "title": null, + "data": null, + "project_id": 36, + "created_at": "2016-06-14T15:02:25.113Z", + "updated_at": "2016-06-14T15:02:25.113Z", + "action": 1, + "author_id": 1 + }, + { + "id": 174, + "target_type": "MergeRequest", + "target_id": 14, + "title": null, + "data": null, + "project_id": 5, + "created_at": "2016-06-14T15:02:25.113Z", + "updated_at": "2016-06-14T15:02:25.113Z", + "action": 1, + "author_id": 20 + } + ] + }, + { + "id": 13, + "target_branch": "improve/awesome", + "source_branch": "test-8", + "source_project_id": 5, + "author_id": 16, + "assignee_id": 25, + "title": "Voluptates consequatur eius nemo amet libero animi illum delectus tempore.", + "created_at": "2016-06-14T15:02:24.415Z", + "updated_at": "2016-06-14T15:02:59.958Z", + "milestone_id": 17, + "state": "opened", + "merge_status": "unchecked", + "target_project_id": 5, + "iid": 5, + "description": "Est eaque quasi qui qui. Similique voluptatem impedit iusto ratione reprehenderit. Itaque est illum ut nulla aut.", + "position": 0, + "locked_at": null, + "updated_by_id": null, + "merge_error": null, + "merge_params": { + "force_remove_source_branch": null + }, + "merge_when_build_succeeds": false, + "merge_user_id": null, + "merge_commit_sha": null, + "deleted_at": null, + "notes": [ + { + "id": 793, + "note": "In illum maxime aperiam nulla est aspernatur.", + "noteable_type": "MergeRequest", + "author_id": 26, + "created_at": "2016-06-14T15:02:59.782Z", + "updated_at": "2016-06-14T15:02:59.782Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 13, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 4" + }, + "events": [ + + ] + }, + { + "id": 794, + "note": "Enim quia perferendis cum distinctio tenetur optio voluptas veniam.", + "noteable_type": "MergeRequest", + "author_id": 25, + "created_at": "2016-06-14T15:02:59.807Z", + "updated_at": "2016-06-14T15:02:59.807Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 13, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 795, + "note": "Dolor ad quia quis pariatur ducimus.", + "noteable_type": "MergeRequest", + "author_id": 22, + "created_at": "2016-06-14T15:02:59.831Z", + "updated_at": "2016-06-14T15:02:59.831Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 13, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 796, + "note": "Et a odio voluptate aut.", + "noteable_type": "MergeRequest", + "author_id": 20, + "created_at": "2016-06-14T15:02:59.854Z", + "updated_at": "2016-06-14T15:02:59.854Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 13, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 797, + "note": "Quis nihil temporibus voluptatum modi minima a ut.", + "noteable_type": "MergeRequest", + "author_id": 16, + "created_at": "2016-06-14T15:02:59.879Z", + "updated_at": "2016-06-14T15:02:59.879Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 13, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 798, + "note": "Ut alias consequatur in nostrum.", + "noteable_type": "MergeRequest", + "author_id": 15, + "created_at": "2016-06-14T15:02:59.904Z", + "updated_at": "2016-06-14T15:02:59.904Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 13, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 799, + "note": "Voluptatibus aperiam assumenda et neque sint libero.", + "noteable_type": "MergeRequest", + "author_id": 6, + "created_at": "2016-06-14T15:02:59.926Z", + "updated_at": "2016-06-14T15:02:59.926Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 13, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 800, + "note": "Veritatis voluptatem dolor dolores magni quo ut ipsa fuga.", + "noteable_type": "MergeRequest", + "author_id": 1, + "created_at": "2016-06-14T15:02:59.956Z", + "updated_at": "2016-06-14T15:02:59.956Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 13, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] + } + ], + "merge_request_diff": { + "id": 13, + "state": "collected", + "st_commits": [ + { + "id": "0bfedc29d30280c7e8564e19f654584b459e5868", + "message": "fixes #10\n", + "parent_ids": [ + "be93687618e4b132087f430a4d8fc3a609c9b77c" + ], + "authored_date": "2016-01-19T15:25:23.000+01:00", + "author_name": "James Lopez", + "author_email": "james@jameslopez.es", + "committed_date": "2016-01-19T15:25:23.000+01:00", + "committer_name": "James Lopez", + "committer_email": "james@jameslopez.es" + }, { "id": "be93687618e4b132087f430a4d8fc3a609c9b77c", "message": "Merge branch 'master' into 'master'\r\n\r\nLFS object pointer.\r\n\r\n\r\n\r\nSee merge request !6", @@ -3456,466 +4651,7 @@ "renamed_file": false, "deleted_file": false, "too_large": false - } - ], - "merge_request_id": 15, - "created_at": "2016-03-22T15:13:45.692Z", - "updated_at": "2016-03-22T15:13:45.808Z", - "base_commit_sha": "5937ac0a7beb003549fc5fd26fc247adbce4a52e", - "real_size": "6" - } - }, - { - "id": 14, - "target_branch": "test-1", - "source_branch": "test-10", - "source_project_id": 5, - "author_id": 10, - "assignee_id": 1, - "title": "Tempore aliquid sit amet odit qui cum iusto voluptatibus asperiores.", - "created_at": "2016-03-22T15:13:45.442Z", - "updated_at": "2016-03-22T15:20:30.735Z", - "milestone_id": 10, - "state": "opened", - "merge_status": "unchecked", - "target_project_id": 5, - "iid": 6, - "description": "Quis et et autem saepe ut. Eum corporis tempore cum dolore. Molestiae pariatur voluptatem officia perferendis aut veniam.", - "position": 0, - "locked_at": null, - "updated_by_id": null, - "merge_error": null, - "merge_params": { - - }, - "merge_when_build_succeeds": false, - "merge_user_id": null, - "merge_commit_sha": null, - "deleted_at": null, - "notes": [ - { - "id": 1239, - "note": "Aspernatur suscipit veritatis aliquid rerum.", - "noteable_type": "MergeRequest", - "author_id": 1, - "created_at": "2016-03-22T15:20:30.731Z", - "updated_at": "2016-03-22T15:20:30.731Z", - "project_id": 5, - "attachment": { - "url": null }, - "line_code": null, - "commit_id": null, - "noteable_id": 14, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 1238, - "note": "Rerum deleniti omnis porro commodi.", - "noteable_type": "MergeRequest", - "author_id": 3, - "created_at": "2016-03-22T15:20:30.701Z", - "updated_at": "2016-03-22T15:20:30.701Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 14, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 1237, - "note": "Eaque ut magnam rerum non dolores esse.", - "noteable_type": "MergeRequest", - "author_id": 4, - "created_at": "2016-03-22T15:20:30.667Z", - "updated_at": "2016-03-22T15:20:30.667Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 14, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 1236, - "note": "Fugit et aut similique illum ut natus maiores et.", - "noteable_type": "MergeRequest", - "author_id": 10, - "created_at": "2016-03-22T15:20:30.637Z", - "updated_at": "2016-03-22T15:20:30.637Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 14, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 1235, - "note": "Qui qui temporibus eos aliquam.", - "noteable_type": "MergeRequest", - "author_id": 12, - "created_at": "2016-03-22T15:20:30.608Z", - "updated_at": "2016-03-22T15:20:30.608Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 14, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 1234, - "note": "Voluptates hic dolorum aut inventore.", - "noteable_type": "MergeRequest", - "author_id": 22, - "created_at": "2016-03-22T15:20:30.575Z", - "updated_at": "2016-03-22T15:20:30.575Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 14, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 1233, - "note": "Dolorum iure at dolor dolores numquam iusto.", - "noteable_type": "MergeRequest", - "author_id": 24, - "created_at": "2016-03-22T15:20:30.548Z", - "updated_at": "2016-03-22T15:20:30.548Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 14, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 1232, - "note": "Nihil est eum aspernatur amet minus et corporis consectetur.", - "noteable_type": "MergeRequest", - "author_id": 26, - "created_at": "2016-03-22T15:20:30.517Z", - "updated_at": "2016-03-22T15:20:30.517Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 14, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 4" - } - } - ], - "merge_request_diff": { - "id": 14, - "state": "collected", - "st_commits": [ - { - "id": "bce96ecee98f51fa5d91021e6c42859a35a701ad", - "message": "fixes #10\n", - "parent_ids": [ - "be93687618e4b132087f430a4d8fc3a609c9b77c" - ], - "authored_date": "2016-01-19T15:40:05.000+01:00", - "author_name": "Test Lopez", - "author_email": "Test@Testlopez.es", - "committed_date": "2016-01-19T15:40:05.000+01:00", - "committer_name": "Test Lopez", - "committer_email": "Test@Testlopez.es" - } - ], - "st_diffs": [ - { - "diff": "--- /dev/null\n+++ b/test\n", - "new_path": "test", - "old_path": "test", - "a_mode": "0", - "b_mode": "100644", - "new_file": true, - "renamed_file": false, - "deleted_file": false, - "too_large": false - } - ], - "merge_request_id": 14, - "created_at": "2016-03-22T15:13:45.444Z", - "updated_at": "2016-03-22T15:13:45.486Z", - "base_commit_sha": "be93687618e4b132087f430a4d8fc3a609c9b77c", - "real_size": "1" - } - }, - { - "id": 13, - "target_branch": "test-11", - "source_branch": "test-12", - "source_project_id": 5, - "author_id": 1, - "assignee_id": 26, - "title": "Voluptas minus sunt voluptatum quis quia ut velit distinctio itaque.", - "created_at": "2016-03-22T15:13:45.164Z", - "updated_at": "2016-03-22T15:20:30.994Z", - "milestone_id": 11, - "state": "opened", - "merge_status": "unchecked", - "target_project_id": 5, - "iid": 5, - "description": "Ea ut modi consectetur et minus beatae. Et sunt ducimus praesentium libero officia maiores voluptas cumque. Rerum in aut corporis et ullam omnis.", - "position": 0, - "locked_at": null, - "updated_by_id": null, - "merge_error": null, - "merge_params": { - - }, - "merge_when_build_succeeds": false, - "merge_user_id": null, - "merge_commit_sha": null, - "deleted_at": null, - "notes": [ - { - "id": 1247, - "note": "Non error magnam placeat cupiditate eum.", - "noteable_type": "MergeRequest", - "author_id": 1, - "created_at": "2016-03-22T15:20:30.989Z", - "updated_at": "2016-03-22T15:20:30.989Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 13, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 1246, - "note": "Eos optio et architecto eligendi ea est nihil.", - "noteable_type": "MergeRequest", - "author_id": 3, - "created_at": "2016-03-22T15:20:30.957Z", - "updated_at": "2016-03-22T15:20:30.957Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 13, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 1245, - "note": "Reprehenderit in atque dolor et repudiandae a est.", - "noteable_type": "MergeRequest", - "author_id": 4, - "created_at": "2016-03-22T15:20:30.928Z", - "updated_at": "2016-03-22T15:20:30.928Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 13, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 1244, - "note": "Numquam fugit doloremque iure odio et.", - "noteable_type": "MergeRequest", - "author_id": 10, - "created_at": "2016-03-22T15:20:30.902Z", - "updated_at": "2016-03-22T15:20:30.902Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 13, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 1243, - "note": "Doloribus laboriosam id harum voluptatum vitae ut quam.", - "noteable_type": "MergeRequest", - "author_id": 12, - "created_at": "2016-03-22T15:20:30.863Z", - "updated_at": "2016-03-22T15:20:30.863Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 13, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 1242, - "note": "Harum et ut ipsum dolore ea.", - "noteable_type": "MergeRequest", - "author_id": 22, - "created_at": "2016-03-22T15:20:30.832Z", - "updated_at": "2016-03-22T15:20:30.832Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 13, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 1241, - "note": "Corporis sed soluta ut est modi natus ab.", - "noteable_type": "MergeRequest", - "author_id": 24, - "created_at": "2016-03-22T15:20:30.802Z", - "updated_at": "2016-03-22T15:20:30.802Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 13, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 1240, - "note": "Corrupti totam tenetur officiis ratione dolores est qui vel.", - "noteable_type": "MergeRequest", - "author_id": 26, - "created_at": "2016-03-22T15:20:30.771Z", - "updated_at": "2016-03-22T15:20:30.771Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 13, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 4" - } - } - ], - "merge_request_diff": { - "id": 13, - "state": "collected", - "st_commits": [ - { - "id": "a4e5dfebf42e34596526acb8611bc7ed80e4eb3f", - "message": "fixes #10\n", - "parent_ids": [ - "be93687618e4b132087f430a4d8fc3a609c9b77c" - ], - "authored_date": "2016-01-19T15:44:02.000+01:00", - "author_name": "Test Lopez", - "author_email": "Test@Testlopez.es", - "committed_date": "2016-01-19T15:44:02.000+01:00", - "committer_name": "Test Lopez", - "committer_email": "Test@Testlopez.es" - } - ], - "st_diffs": [ { "diff": "--- /dev/null\n+++ b/test\n", "new_path": "test", @@ -3929,34 +4665,60 @@ } ], "merge_request_id": 13, - "created_at": "2016-03-22T15:13:45.167Z", - "updated_at": "2016-03-22T15:13:45.216Z", - "base_commit_sha": "be93687618e4b132087f430a4d8fc3a609c9b77c", - "real_size": "1" - } + "created_at": "2016-06-14T15:02:24.420Z", + "updated_at": "2016-06-14T15:02:24.561Z", + "base_commit_sha": "5937ac0a7beb003549fc5fd26fc247adbce4a52e", + "real_size": "7" + }, + "events": [ + { + "id": 225, + "target_type": "MergeRequest", + "target_id": 13, + "title": null, + "data": null, + "project_id": 36, + "created_at": "2016-06-14T15:02:24.636Z", + "updated_at": "2016-06-14T15:02:24.636Z", + "action": 1, + "author_id": 16 + }, + { + "id": 173, + "target_type": "MergeRequest", + "target_id": 13, + "title": null, + "data": null, + "project_id": 5, + "created_at": "2016-06-14T15:02:24.636Z", + "updated_at": "2016-06-14T15:02:24.636Z", + "action": 1, + "author_id": 16 + } + ] }, { "id": 12, - "target_branch": "test-15", + "target_branch": "flatten-dirs", "source_branch": "test-2", "source_project_id": 5, - "author_id": 24, - "assignee_id": 12, - "title": "In assumenda nam quaerat qui eos sit facilis enim quia quis.", - "created_at": "2016-03-22T15:13:44.837Z", - "updated_at": "2016-03-22T15:20:31.258Z", - "milestone_id": 10, + "author_id": 1, + "assignee_id": 22, + "title": "In a rerum harum nihil accusamus aut quia nobis non.", + "created_at": "2016-06-14T15:02:24.000Z", + "updated_at": "2016-06-14T15:03:00.225Z", + "milestone_id": 19, "state": "opened", "merge_status": "unchecked", "target_project_id": 5, "iid": 4, - "description": "Soluta excepturi quis iste vero delectus rerum. Consequatur possimus aliquam necessitatibus deleniti rerum est impedit. Eius rem et consequatur assumenda est commodi.", + "description": "Nam magnam odit velit rerum. Sapiente dolore sunt saepe debitis. Culpa maiores ut ad dolores dolorem et.", "position": 0, "locked_at": null, "updated_by_id": null, "merge_error": null, "merge_params": { - + "force_remove_source_branch": null }, "merge_when_build_succeeds": false, "merge_user_id": null, @@ -3964,159 +4726,12 @@ "deleted_at": null, "notes": [ { - "id": 1255, - "note": "Quibusdam rem aut similique ipsum recusandae ut accusamus.", - "noteable_type": "MergeRequest", - "author_id": 1, - "created_at": "2016-03-22T15:20:31.253Z", - "updated_at": "2016-03-22T15:20:31.253Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 12, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 1254, - "note": "Cumque sed omnis ipsa et magnam dolorem et.", - "noteable_type": "MergeRequest", - "author_id": 3, - "created_at": "2016-03-22T15:20:31.224Z", - "updated_at": "2016-03-22T15:20:31.224Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 12, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 1253, - "note": "Molestiae beatae id consequatur nam minus quia.", - "noteable_type": "MergeRequest", - "author_id": 4, - "created_at": "2016-03-22T15:20:31.195Z", - "updated_at": "2016-03-22T15:20:31.195Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 12, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 1252, - "note": "Voluptatem dolorem dignissimos itaque tempora quas ut.", - "noteable_type": "MergeRequest", - "author_id": 10, - "created_at": "2016-03-22T15:20:31.166Z", - "updated_at": "2016-03-22T15:20:31.166Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 12, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 1251, - "note": "Debitis qui quibusdam voluptas repellat veritatis dicta rerum id.", - "noteable_type": "MergeRequest", - "author_id": 12, - "created_at": "2016-03-22T15:20:31.137Z", - "updated_at": "2016-03-22T15:20:31.137Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 12, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 1250, - "note": "Suscipit optio ad voluptatem dignissimos temporibus amet molestias ut.", - "noteable_type": "MergeRequest", - "author_id": 22, - "created_at": "2016-03-22T15:20:31.107Z", - "updated_at": "2016-03-22T15:20:31.107Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 12, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 1249, - "note": "Nemo aut vitae et ducimus autem ex dolores.", - "noteable_type": "MergeRequest", - "author_id": 24, - "created_at": "2016-03-22T15:20:31.073Z", - "updated_at": "2016-03-22T15:20:31.073Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 12, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 1248, - "note": "Repellendus eaque ex molestiae laudantium placeat quidem vitae recusandae.", + "id": 801, + "note": "Nihil dicta molestias expedita atque.", "noteable_type": "MergeRequest", "author_id": 26, - "created_at": "2016-03-22T15:20:31.038Z", - "updated_at": "2016-03-22T15:20:31.038Z", + "created_at": "2016-06-14T15:03:00.001Z", + "updated_at": "2016-06-14T15:03:00.001Z", "project_id": 5, "attachment": { "url": null @@ -4127,9 +4742,180 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] + }, + { + "id": 802, + "note": "Illum culpa voluptas enim accusantium deserunt.", + "noteable_type": "MergeRequest", + "author_id": 25, + "created_at": "2016-06-14T15:03:00.034Z", + "updated_at": "2016-06-14T15:03:00.034Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 12, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 803, + "note": "Dicta esse aliquam laboriosam unde alias.", + "noteable_type": "MergeRequest", + "author_id": 22, + "created_at": "2016-06-14T15:03:00.065Z", + "updated_at": "2016-06-14T15:03:00.065Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 12, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 804, + "note": "Dicta autem et sed molestiae ut quae.", + "noteable_type": "MergeRequest", + "author_id": 20, + "created_at": "2016-06-14T15:03:00.097Z", + "updated_at": "2016-06-14T15:03:00.097Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 12, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 805, + "note": "Ut ut temporibus voluptas dolore quia velit.", + "noteable_type": "MergeRequest", + "author_id": 16, + "created_at": "2016-06-14T15:03:00.129Z", + "updated_at": "2016-06-14T15:03:00.129Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 12, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 806, + "note": "Dolores similique sint pariatur error id quia fugit aut.", + "noteable_type": "MergeRequest", + "author_id": 15, + "created_at": "2016-06-14T15:03:00.162Z", + "updated_at": "2016-06-14T15:03:00.162Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 12, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 807, + "note": "Quisquam provident nihil aperiam voluptatem.", + "noteable_type": "MergeRequest", + "author_id": 6, + "created_at": "2016-06-14T15:03:00.193Z", + "updated_at": "2016-06-14T15:03:00.193Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 12, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 808, + "note": "Similique quo vero expedita deserunt ipsam earum.", + "noteable_type": "MergeRequest", + "author_id": 1, + "created_at": "2016-06-14T15:03:00.224Z", + "updated_at": "2016-06-14T15:03:00.224Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 12, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] } ], "merge_request_diff": { @@ -4143,14 +4929,229 @@ "be93687618e4b132087f430a4d8fc3a609c9b77c" ], "authored_date": "2016-01-19T14:08:21.000+01:00", - "author_name": "Test Lopez", - "author_email": "Test@Testlopez.es", + "author_name": "James Lopez", + "author_email": "james@jameslopez.es", "committed_date": "2016-01-19T14:08:21.000+01:00", - "committer_name": "Test Lopez", - "committer_email": "Test@Testlopez.es" + "committer_name": "James Lopez", + "committer_email": "james@jameslopez.es" + }, + { + "id": "be93687618e4b132087f430a4d8fc3a609c9b77c", + "message": "Merge branch 'master' into 'master'\r\n\r\nLFS object pointer.\r\n\r\n\r\n\r\nSee merge request !6", + "parent_ids": [ + "5f923865dde3436854e9ceb9cdb7815618d4e849", + "048721d90c449b244b7b4c53a9186b04330174ec" + ], + "authored_date": "2015-12-07T12:52:12.000+01:00", + "author_name": "Marin Jankovski", + "author_email": "marin@gitlab.com", + "committed_date": "2015-12-07T12:52:12.000+01:00", + "committer_name": "Marin Jankovski", + "committer_email": "marin@gitlab.com" + }, + { + "id": "048721d90c449b244b7b4c53a9186b04330174ec", + "message": "LFS object pointer.\n", + "parent_ids": [ + "5f923865dde3436854e9ceb9cdb7815618d4e849" + ], + "authored_date": "2015-12-07T11:54:28.000+01:00", + "author_name": "Marin Jankovski", + "author_email": "maxlazio@gmail.com", + "committed_date": "2015-12-07T11:54:28.000+01:00", + "committer_name": "Marin Jankovski", + "committer_email": "maxlazio@gmail.com" + }, + { + "id": "5f923865dde3436854e9ceb9cdb7815618d4e849", + "message": "GitLab currently doesn't support patches that involve a merge commit: add a commit here\n", + "parent_ids": [ + "d2d430676773caa88cdaf7c55944073b2fd5561a" + ], + "authored_date": "2015-11-13T16:27:12.000+01:00", + "author_name": "Stan Hu", + "author_email": "stanhu@gmail.com", + "committed_date": "2015-11-13T16:27:12.000+01:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@gmail.com" + }, + { + "id": "d2d430676773caa88cdaf7c55944073b2fd5561a", + "message": "Merge branch 'add-svg' into 'master'\r\n\r\nAdd GitLab SVG\r\n\r\nAdded to test preview of sanitized SVG images\r\n\r\nSee merge request !5", + "parent_ids": [ + "59e29889be61e6e0e5e223bfa9ac2721d31605b8", + "2ea1f3dec713d940208fb5ce4a38765ecb5d3f73" + ], + "authored_date": "2015-11-13T08:50:17.000+01:00", + "author_name": "Stan Hu", + "author_email": "stanhu@gmail.com", + "committed_date": "2015-11-13T08:50:17.000+01:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@gmail.com" + }, + { + "id": "2ea1f3dec713d940208fb5ce4a38765ecb5d3f73", + "message": "Add GitLab SVG\n", + "parent_ids": [ + "59e29889be61e6e0e5e223bfa9ac2721d31605b8" + ], + "authored_date": "2015-11-13T08:39:43.000+01:00", + "author_name": "Stan Hu", + "author_email": "stanhu@gmail.com", + "committed_date": "2015-11-13T08:39:43.000+01:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@gmail.com" + }, + { + "id": "59e29889be61e6e0e5e223bfa9ac2721d31605b8", + "message": "Merge branch 'whitespace' into 'master'\r\n\r\nadd whitespace test file\r\n\r\nSorry, I did a mistake.\r\nGit ignore empty files.\r\nSo I add a new whitespace test file.\r\n\r\nSee merge request !4", + "parent_ids": [ + "19e2e9b4ef76b422ce1154af39a91323ccc57434", + "66eceea0db202bb39c4e445e8ca28689645366c5" + ], + "authored_date": "2015-11-13T07:21:40.000+01:00", + "author_name": "Stan Hu", + "author_email": "stanhu@gmail.com", + "committed_date": "2015-11-13T07:21:40.000+01:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@gmail.com" + }, + { + "id": "66eceea0db202bb39c4e445e8ca28689645366c5", + "message": "add spaces in whitespace file\n", + "parent_ids": [ + "08f22f255f082689c0d7d39d19205085311542bc" + ], + "authored_date": "2015-11-13T06:01:27.000+01:00", + "author_name": "윤민식", + "author_email": "minsik.yoon@samsung.com", + "committed_date": "2015-11-13T06:01:27.000+01:00", + "committer_name": "윤민식", + "committer_email": "minsik.yoon@samsung.com" + }, + { + "id": "08f22f255f082689c0d7d39d19205085311542bc", + "message": "remove emtpy file.(beacase git ignore empty file)\nadd whitespace test file.\n", + "parent_ids": [ + "c642fe9b8b9f28f9225d7ea953fe14e74748d53b" + ], + "authored_date": "2015-11-13T06:00:16.000+01:00", + "author_name": "윤민식", + "author_email": "minsik.yoon@samsung.com", + "committed_date": "2015-11-13T06:00:16.000+01:00", + "committer_name": "윤민식", + "committer_email": "minsik.yoon@samsung.com" + }, + { + "id": "19e2e9b4ef76b422ce1154af39a91323ccc57434", + "message": "Merge branch 'whitespace' into 'master'\r\n\r\nadd spaces\r\n\r\nTo test this pull request.(https://github.com/gitlabhq/gitlabhq/pull/9757)\r\nJust add whitespaces.\r\n\r\nSee merge request !3", + "parent_ids": [ + "c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd", + "c642fe9b8b9f28f9225d7ea953fe14e74748d53b" + ], + "authored_date": "2015-11-13T05:23:14.000+01:00", + "author_name": "Stan Hu", + "author_email": "stanhu@gmail.com", + "committed_date": "2015-11-13T05:23:14.000+01:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@gmail.com" + }, + { + "id": "c642fe9b8b9f28f9225d7ea953fe14e74748d53b", + "message": "add whitespace in empty\n", + "parent_ids": [ + "9a944d90955aaf45f6d0c88f30e27f8d2c41cec0" + ], + "authored_date": "2015-11-13T05:08:45.000+01:00", + "author_name": "윤민식", + "author_email": "minsik.yoon@samsung.com", + "committed_date": "2015-11-13T05:08:45.000+01:00", + "committer_name": "윤민식", + "committer_email": "minsik.yoon@samsung.com" + }, + { + "id": "9a944d90955aaf45f6d0c88f30e27f8d2c41cec0", + "message": "add empty file\n", + "parent_ids": [ + "c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd" + ], + "authored_date": "2015-11-13T05:08:04.000+01:00", + "author_name": "윤민식", + "author_email": "minsik.yoon@samsung.com", + "committed_date": "2015-11-13T05:08:04.000+01:00", + "committer_name": "윤민식", + "committer_email": "minsik.yoon@samsung.com" + }, + { + "id": "c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd", + "message": "Add ISO-8859 test file\n", + "parent_ids": [ + "e56497bb5f03a90a51293fc6d516788730953899" + ], + "authored_date": "2015-08-25T17:53:12.000+02:00", + "author_name": "Stan Hu", + "author_email": "stanhu@packetzoom.com", + "committed_date": "2015-08-25T17:53:12.000+02:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@packetzoom.com" } ], "st_diffs": [ + { + "diff": "--- a/CHANGELOG\n+++ b/CHANGELOG\n@@ -1,4 +1,6 @@\n-v 6.7.0\n+v6.8.0\n+\n+v6.7.0\n - Add support for Gemnasium as a Project Service (Olivier Gonzalez)\n - Add edit file button to MergeRequest diff\n - Public groups (Jason Hollingsworth)\n", + "new_path": "CHANGELOG", + "old_path": "CHANGELOG", + "a_mode": "100644", + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/encoding/iso8859.txt\n@@ -0,0 +1 @@\n+Äü\n", + "new_path": "encoding/iso8859.txt", + "old_path": "encoding/iso8859.txt", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/files/images/wm.svg\n@@ -0,0 +1,78 @@\n+\u003c?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?\u003e\n+\u003csvg width=\"1300px\" height=\"680px\" viewBox=\"0 0 1300 680\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\"\u003e\n+ \u003c!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch --\u003e\n+ \u003ctitle\u003ewm\u003c/title\u003e\n+ \u003cdesc\u003eCreated with Sketch.\u003c/desc\u003e\n+ \u003cdefs\u003e\n+ \u003cpath id=\"path-1\" d=\"M-69.8,1023.54607 L1675.19996,1023.54607 L1675.19996,0 L-69.8,0 L-69.8,1023.54607 L-69.8,1023.54607 Z\"\u003e\u003c/path\u003e\n+ \u003c/defs\u003e\n+ \u003cg id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\"\u003e\n+ \u003cpath d=\"M1300,680 L0,680 L0,0 L1300,0 L1300,680 L1300,680 Z\" id=\"bg\" fill=\"#30353E\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cg id=\"gitlab_logo\" sketch:type=\"MSLayerGroup\" transform=\"translate(-262.000000, -172.000000)\"\u003e\n+ \u003cg id=\"g10\" transform=\"translate(872.500000, 512.354581) scale(1, -1) translate(-872.500000, -512.354581) translate(0.000000, 0.290751)\"\u003e\n+ \u003cg id=\"g12\" transform=\"translate(1218.022652, 440.744871)\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\n+ \u003cpath d=\"M-50.0233338,141.900706 L-69.07059,141.900706 L-69.0100967,0.155858152 L8.04444805,0.155858152 L8.04444805,17.6840847 L-49.9628405,17.6840847 L-50.0233338,141.900706 L-50.0233338,141.900706 Z\" id=\"path14\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g16\"\u003e\n+ \u003cg id=\"g18-Clipped\"\u003e\n+ \u003cmask id=\"mask-2\" sketch:name=\"path22\" fill=\"white\"\u003e\n+ \u003cuse xlink:href=\"#path-1\"\u003e\u003c/use\u003e\n+ \u003c/mask\u003e\n+ \u003cg id=\"path22\"\u003e\u003c/g\u003e\n+ \u003cg id=\"g18\" mask=\"url(#mask-2)\"\u003e\n+ \u003cg transform=\"translate(382.736659, 312.879425)\"\u003e\n+ \u003cg id=\"g24\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(852.718192, 124.992771)\"\u003e\n+ \u003cpath d=\"M63.9833317,27.9148929 C59.2218085,22.9379001 51.2134221,17.9597442 40.3909323,17.9597442 C25.8888194,17.9597442 20.0453962,25.1013043 20.0453962,34.4074318 C20.0453962,48.4730484 29.7848226,55.1819277 50.5642821,55.1819277 C54.4602853,55.1819277 60.7364685,54.7492469 63.9833317,54.1002256 L63.9833317,27.9148929 L63.9833317,27.9148929 Z M44.2869356,113.827628 C28.9053426,113.827628 14.7975996,108.376082 3.78897657,99.301416 L10.5211864,87.6422957 C18.3131929,92.1866076 27.8374026,96.7320827 41.4728323,96.7320827 C57.0568452,96.7320827 63.9833317,88.7239978 63.9833317,75.3074024 L63.9833317,68.3821827 C60.9528485,69.0312039 54.6766653,69.4650479 50.7806621,69.4650479 C17.4476729,69.4650479 0.565379986,57.7791759 0.565379986,33.3245665 C0.565379986,11.4683685 13.9844297,0.43151772 34.3299658,0.43151772 C48.0351955,0.43151772 61.1692285,6.70771614 65.7143717,16.8780421 L69.1776149,3.02876588 L82.5978279,3.02876588 L82.5978279,75.5237428 C82.5978279,98.462806 72.6408582,113.827628 44.2869356,113.827628 L44.2869356,113.827628 Z\" id=\"path26\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g28\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(959.546624, 124.857151)\"\u003e\n+ \u003cpath d=\"M37.2266657,17.4468081 C30.0837992,17.4468081 23.8064527,18.3121698 19.0449295,20.4767371 L19.0449295,79.2306079 L19.0449295,86.0464943 C25.538656,91.457331 33.5470425,95.3526217 43.7203922,95.3526217 C62.1173451,95.3526217 69.2602116,82.3687072 69.2602116,61.3767077 C69.2602116,31.5135879 57.7885819,17.4468081 37.2266657,17.4468081 M45.2315622,113.963713 C28.208506,113.963713 19.0449295,102.384849 19.0449295,102.384849 L19.0449295,120.67143 L18.9844362,144.908535 L10.3967097,144.908535 L0.371103324,144.908535 L0.431596656,6.62629771 C9.73826309,2.73100702 22.5081728,0.567602823 36.3611458,0.567602823 C71.8579349,0.567602823 88.9566078,23.2891625 88.9566078,62.4584098 C88.9566078,93.4043948 73.1527248,113.963713 45.2315622,113.963713\" id=\"path30\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g32\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(509.576747, 125.294950)\"\u003e\n+ \u003cpath d=\"M68.636665,129.10638 C85.5189579,129.10638 96.3414476,123.480366 103.484314,117.853189 L111.669527,132.029302 C100.513161,141.811145 85.5073245,147.06845 69.5021849,147.06845 C29.0274926,147.06845 0.673569983,122.3975 0.673569983,72.6252464 C0.673569983,20.4709215 31.2622559,0.12910638 66.2553217,0.12910638 C83.7879179,0.12910638 98.7227909,4.24073748 108.462217,8.35236859 L108.063194,64.0763105 L108.063194,70.6502677 L108.063194,81.6057001 L56.1168719,81.6057001 L56.1168719,64.0763105 L89.2323178,64.0763105 L89.6313411,21.7701271 C85.3025779,19.6055598 77.7269514,17.8748364 67.554765,17.8748364 C39.4172223,17.8748364 20.5863462,35.5717154 20.5863462,72.8415868 C20.5863462,110.711628 40.0663623,129.10638 68.636665,129.10638\" id=\"path34\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g36\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(692.388992, 124.376085)\"\u003e\n+ \u003cpath d=\"M19.7766662,145.390067 L1.16216997,145.390067 L1.2226633,121.585642 L1.2226633,111.846834 L1.2226633,106.170806 L1.2226633,96.2656714 L1.2226633,39.5681976 L1.2226633,39.3518572 C1.2226633,16.4127939 11.1796331,1.04797161 39.5335557,1.04797161 C43.4504989,1.04797161 47.2836822,1.40388649 51.0051854,2.07965952 L51.0051854,18.7925385 C48.3109055,18.3796307 45.4351455,18.1446804 42.3476589,18.1446804 C26.763646,18.1446804 19.8371595,26.1516022 19.8371595,39.5681976 L19.8371595,96.2656714 L51.0051854,96.2656714 L51.0051854,111.846834 L19.8371595,111.846834 L19.7766662,145.390067 L19.7766662,145.390067 Z\" id=\"path38\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cpath d=\"M646.318899,128.021188 L664.933395,128.021188 L664.933395,236.223966 L646.318899,236.223966 L646.318899,128.021188 L646.318899,128.021188 Z\" id=\"path40\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cpath d=\"M646.318899,251.154944 L664.933395,251.154944 L664.933395,269.766036 L646.318899,269.766036 L646.318899,251.154944 L646.318899,251.154944 Z\" id=\"path42\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cg id=\"g44\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.464170, 0.676006)\"\u003e\n+ \u003cpath d=\"M429.269989,169.815599 L405.225053,243.802859 L357.571431,390.440955 C355.120288,397.984955 344.444378,397.984955 341.992071,390.440955 L294.337286,243.802859 L136.094873,243.802859 L88.4389245,390.440955 C85.9877812,397.984955 75.3118715,397.984955 72.8595648,390.440955 L25.2059427,243.802859 L1.16216997,169.815599 C-1.03187664,163.067173 1.37156997,155.674379 7.11261982,151.503429 L215.215498,0.336141836 L423.319539,151.503429 C429.060589,155.674379 431.462873,163.067173 429.269989,169.815599\" id=\"path46\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g48\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(135.410135, 1.012147)\"\u003e\n+ \u003cpath d=\"M80.269998,0 L80.269998,0 L159.391786,243.466717 L1.14820997,243.466717 L80.269998,0 L80.269998,0 Z\" id=\"path50\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g52\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\"\u003e\n+ \u003cg id=\"path54\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g56\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(24.893471, 1.012613)\"\u003e\n+ \u003cpath d=\"M190.786662,0 L111.664874,243.465554 L0.777106647,243.465554 L190.786662,0 L190.786662,0 Z\" id=\"path58\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g60\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\"\u003e\n+ \u003cg id=\"path62\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g64\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.077245, 0.223203)\"\u003e\n+ \u003cpath d=\"M25.5933327,244.255313 L25.5933327,244.255313 L1.54839663,170.268052 C-0.644486651,163.519627 1.75779662,156.126833 7.50000981,151.957046 L215.602888,0.789758846 L25.5933327,244.255313 L25.5933327,244.255313 Z\" id=\"path66\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g68\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\"\u003e\n+ \u003cg id=\"path70\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g72\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(25.670578, 244.478283)\"\u003e\n+ \u003cpath d=\"M0,0 L110.887767,0 L63.2329818,146.638096 C60.7806751,154.183259 50.1047654,154.183259 47.6536221,146.638096 L0,0 L0,0 Z\" id=\"path74\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g76\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\"\u003e\n+ \u003cpath d=\"M0,0 L79.121788,243.465554 L190.009555,243.465554 L0,0 L0,0 Z\" id=\"path78\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g80\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(214.902910, 0.223203)\"\u003e\n+ \u003cpath d=\"M190.786662,244.255313 L190.786662,244.255313 L214.831598,170.268052 C217.024481,163.519627 214.622198,156.126833 208.879985,151.957046 L0.777106647,0.789758846 L190.786662,244.255313 L190.786662,244.255313 Z\" id=\"path82\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g84\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(294.009575, 244.478283)\"\u003e\n+ \u003cpath d=\"M111.679997,0 L0.79222998,0 L48.4470155,146.638096 C50.8993221,154.183259 61.5752318,154.183259 64.0263751,146.638096 L111.679997,0 L111.679997,0 Z\" id=\"path86\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+\u003c/svg\u003e\n\\ No newline at end of file\n", + "new_path": "files/images/wm.svg", + "old_path": "files/images/wm.svg", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/files/lfs/lfs_object.iso\n@@ -0,0 +1,4 @@\n+version https://git-lfs.github.com/spec/v1\n+oid sha256:91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897\n+size 1575078\n+\n", + "new_path": "files/lfs/lfs_object.iso", + "old_path": "files/lfs/lfs_object.iso", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/files/whitespace\n@@ -0,0 +1 @@\n+test \n", + "new_path": "files/whitespace", + "old_path": "files/whitespace", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, { "diff": "--- /dev/null\n+++ b/test\n", "new_path": "test", @@ -4164,34 +5165,60 @@ } ], "merge_request_id": 12, - "created_at": "2016-03-22T15:13:44.840Z", - "updated_at": "2016-03-22T15:13:44.908Z", - "base_commit_sha": "be93687618e4b132087f430a4d8fc3a609c9b77c", - "real_size": "1" - } + "created_at": "2016-06-14T15:02:24.006Z", + "updated_at": "2016-06-14T15:02:24.169Z", + "base_commit_sha": "e56497bb5f03a90a51293fc6d516788730953899", + "real_size": "6" + }, + "events": [ + { + "id": 226, + "target_type": "MergeRequest", + "target_id": 12, + "title": null, + "data": null, + "project_id": 36, + "created_at": "2016-06-14T15:02:24.253Z", + "updated_at": "2016-06-14T15:02:24.253Z", + "action": 1, + "author_id": 1 + }, + { + "id": 172, + "target_type": "MergeRequest", + "target_id": 12, + "title": null, + "data": null, + "project_id": 5, + "created_at": "2016-06-14T15:02:24.253Z", + "updated_at": "2016-06-14T15:02:24.253Z", + "action": 1, + "author_id": 1 + } + ] }, { "id": 11, - "target_branch": "test-3", - "source_branch": "test-5", + "target_branch": "test-15", + "source_branch": "'test'", "source_project_id": 5, - "author_id": 26, - "assignee_id": 12, - "title": "Magni aut reprehenderit ut accusantium est eum.", - "created_at": "2016-03-22T15:13:44.494Z", - "updated_at": "2016-03-22T15:20:31.886Z", - "milestone_id": 10, + "author_id": 16, + "assignee_id": 16, + "title": "Corporis provident similique perspiciatis dolores eos animi.", + "created_at": "2016-06-14T15:02:23.767Z", + "updated_at": "2016-06-14T15:03:00.475Z", + "milestone_id": 18, "state": "opened", "merge_status": "unchecked", "target_project_id": 5, "iid": 3, - "description": "Et hic maxime harum ullam. Nulla velit pariatur libero recusandae. Dolor est earum laboriosam harum quo.", + "description": "Libero nesciunt mollitia quis odit eos vero quasi. Iure voluptatem ut sint pariatur voluptates ut aut. Laborum possimus unde illum ipsum eum.", "position": 0, "locked_at": null, "updated_by_id": null, "merge_error": null, "merge_params": { - + "force_remove_source_branch": null }, "merge_when_build_succeeds": false, "merge_user_id": null, @@ -4199,159 +5226,12 @@ "deleted_at": null, "notes": [ { - "id": 1263, - "note": "Beatae incidunt exercitationem voluptates recusandae fuga quia enim.", - "noteable_type": "MergeRequest", - "author_id": 1, - "created_at": "2016-03-22T15:20:31.883Z", - "updated_at": "2016-03-22T15:20:31.883Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 11, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 1262, - "note": "Illum sunt id consequuntur fugit et quo ullam eum.", - "noteable_type": "MergeRequest", - "author_id": 3, - "created_at": "2016-03-22T15:20:31.860Z", - "updated_at": "2016-03-22T15:20:31.860Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 11, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 1261, - "note": "Alias reiciendis autem ipsa sequi autem nemo odio.", - "noteable_type": "MergeRequest", - "author_id": 4, - "created_at": "2016-03-22T15:20:31.456Z", - "updated_at": "2016-03-22T15:20:31.456Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 11, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 1260, - "note": "Maxime nisi odit eos nulla vel ex accusamus velit.", - "noteable_type": "MergeRequest", - "author_id": 10, - "created_at": "2016-03-22T15:20:31.426Z", - "updated_at": "2016-03-22T15:20:31.426Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 11, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 1259, - "note": "Excepturi et qui sapiente ut ducimus sunt nesciunt.", - "noteable_type": "MergeRequest", - "author_id": 12, - "created_at": "2016-03-22T15:20:31.397Z", - "updated_at": "2016-03-22T15:20:31.397Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 11, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 1258, - "note": "Quis rerum dolores et dolorem modi neque ullam doloribus.", - "noteable_type": "MergeRequest", - "author_id": 22, - "created_at": "2016-03-22T15:20:31.364Z", - "updated_at": "2016-03-22T15:20:31.364Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 11, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 1257, - "note": "Voluptatum et mollitia neque aut.", - "noteable_type": "MergeRequest", - "author_id": 24, - "created_at": "2016-03-22T15:20:31.328Z", - "updated_at": "2016-03-22T15:20:31.328Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 11, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 1256, - "note": "Rerum laudantium dolor natus doloribus voluptas aliquid a.", + "id": 809, + "note": "Omnis ratione laboriosam dolores qui.", "noteable_type": "MergeRequest", "author_id": 26, - "created_at": "2016-03-22T15:20:31.298Z", - "updated_at": "2016-03-22T15:20:31.298Z", + "created_at": "2016-06-14T15:03:00.260Z", + "updated_at": "2016-06-14T15:03:00.260Z", "project_id": 5, "attachment": { "url": null @@ -4362,13 +5242,445 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] + }, + { + "id": 810, + "note": "Voluptas voluptates pariatur dolores maxime est voluptas.", + "noteable_type": "MergeRequest", + "author_id": 25, + "created_at": "2016-06-14T15:03:00.290Z", + "updated_at": "2016-06-14T15:03:00.290Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 11, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 811, + "note": "Sit perspiciatis facilis ipsum consequatur.", + "noteable_type": "MergeRequest", + "author_id": 22, + "created_at": "2016-06-14T15:03:00.323Z", + "updated_at": "2016-06-14T15:03:00.323Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 11, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 812, + "note": "Ut neque aliquam nam et est.", + "noteable_type": "MergeRequest", + "author_id": 20, + "created_at": "2016-06-14T15:03:00.349Z", + "updated_at": "2016-06-14T15:03:00.349Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 11, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 813, + "note": "Et debitis rerum minima sit aut dolorem.", + "noteable_type": "MergeRequest", + "author_id": 16, + "created_at": "2016-06-14T15:03:00.374Z", + "updated_at": "2016-06-14T15:03:00.374Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 11, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 814, + "note": "Ea nisi earum fugit iste aperiam consequatur.", + "noteable_type": "MergeRequest", + "author_id": 15, + "created_at": "2016-06-14T15:03:00.397Z", + "updated_at": "2016-06-14T15:03:00.397Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 11, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 815, + "note": "Amet ratione consequatur laudantium rerum voluptas est nobis.", + "noteable_type": "MergeRequest", + "author_id": 6, + "created_at": "2016-06-14T15:03:00.450Z", + "updated_at": "2016-06-14T15:03:00.450Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 11, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 816, + "note": "Ab ducimus cumque quia dolorem vitae sint beatae rerum.", + "noteable_type": "MergeRequest", + "author_id": 1, + "created_at": "2016-06-14T15:03:00.474Z", + "updated_at": "2016-06-14T15:03:00.474Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 11, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] } ], "merge_request_diff": { "id": 11, + "state": "empty", + "st_commits": null, + "st_diffs": [ + + ], + "merge_request_id": 11, + "created_at": "2016-06-14T15:02:23.772Z", + "updated_at": "2016-06-14T15:02:23.833Z", + "base_commit_sha": "e56497bb5f03a90a51293fc6d516788730953899", + "real_size": null + }, + "events": [ + { + "id": 227, + "target_type": "MergeRequest", + "target_id": 11, + "title": null, + "data": null, + "project_id": 36, + "created_at": "2016-06-14T15:02:23.865Z", + "updated_at": "2016-06-14T15:02:23.865Z", + "action": 1, + "author_id": 16 + }, + { + "id": 171, + "target_type": "MergeRequest", + "target_id": 11, + "title": null, + "data": null, + "project_id": 5, + "created_at": "2016-06-14T15:02:23.865Z", + "updated_at": "2016-06-14T15:02:23.865Z", + "action": 1, + "author_id": 16 + } + ] + }, + { + "id": 10, + "target_branch": "feature", + "source_branch": "test-5", + "source_project_id": 5, + "author_id": 20, + "assignee_id": 25, + "title": "Eligendi reprehenderit doloribus quia et sit id.", + "created_at": "2016-06-14T15:02:23.014Z", + "updated_at": "2016-06-14T15:03:00.685Z", + "milestone_id": 20, + "state": "opened", + "merge_status": "unchecked", + "target_project_id": 5, + "iid": 2, + "description": "Ut dolor quia aliquid dolore et nisi. Est minus suscipit enim quaerat sapiente consequatur rerum. Eveniet provident consequatur dolor accusantium reiciendis.", + "position": 0, + "locked_at": null, + "updated_by_id": null, + "merge_error": null, + "merge_params": { + "force_remove_source_branch": null + }, + "merge_when_build_succeeds": false, + "merge_user_id": null, + "merge_commit_sha": null, + "deleted_at": null, + "notes": [ + { + "id": 817, + "note": "Recusandae et voluptas enim qui et.", + "noteable_type": "MergeRequest", + "author_id": 26, + "created_at": "2016-06-14T15:03:00.510Z", + "updated_at": "2016-06-14T15:03:00.510Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 10, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 4" + }, + "events": [ + + ] + }, + { + "id": 818, + "note": "Asperiores dolorem rerum ipsum totam.", + "noteable_type": "MergeRequest", + "author_id": 25, + "created_at": "2016-06-14T15:03:00.538Z", + "updated_at": "2016-06-14T15:03:00.538Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 10, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 819, + "note": "Qui quam et iure quasi provident cumque itaque sequi.", + "noteable_type": "MergeRequest", + "author_id": 22, + "created_at": "2016-06-14T15:03:00.562Z", + "updated_at": "2016-06-14T15:03:00.562Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 10, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 820, + "note": "Sint accusantium aliquid iste qui iusto minus vel.", + "noteable_type": "MergeRequest", + "author_id": 20, + "created_at": "2016-06-14T15:03:00.585Z", + "updated_at": "2016-06-14T15:03:00.585Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 10, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 821, + "note": "Dolor corrupti dolorem blanditiis voluptas.", + "noteable_type": "MergeRequest", + "author_id": 16, + "created_at": "2016-06-14T15:03:00.610Z", + "updated_at": "2016-06-14T15:03:00.610Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 10, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 822, + "note": "Est perferendis assumenda aliquam aliquid sit ipsum ullam aut.", + "noteable_type": "MergeRequest", + "author_id": 15, + "created_at": "2016-06-14T15:03:00.635Z", + "updated_at": "2016-06-14T15:03:00.635Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 10, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 823, + "note": "Hic neque reiciendis quaerat maiores.", + "noteable_type": "MergeRequest", + "author_id": 6, + "created_at": "2016-06-14T15:03:00.659Z", + "updated_at": "2016-06-14T15:03:00.659Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 10, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 824, + "note": "Sequi architecto doloribus ut vel autem.", + "noteable_type": "MergeRequest", + "author_id": 1, + "created_at": "2016-06-14T15:03:00.683Z", + "updated_at": "2016-06-14T15:03:00.683Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 10, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] + } + ], + "merge_request_diff": { + "id": 10, "state": "collected", "st_commits": [ { @@ -4378,249 +5690,420 @@ "be93687618e4b132087f430a4d8fc3a609c9b77c" ], "authored_date": "2016-01-19T14:43:23.000+01:00", - "author_name": "Test Lopez", - "author_email": "Test@Testlopez.es", + "author_name": "James Lopez", + "author_email": "james@jameslopez.es", "committed_date": "2016-01-19T14:43:23.000+01:00", - "committer_name": "Test Lopez", - "committer_email": "Test@Testlopez.es" + "committer_name": "James Lopez", + "committer_email": "james@jameslopez.es" + }, + { + "id": "be93687618e4b132087f430a4d8fc3a609c9b77c", + "message": "Merge branch 'master' into 'master'\r\n\r\nLFS object pointer.\r\n\r\n\r\n\r\nSee merge request !6", + "parent_ids": [ + "5f923865dde3436854e9ceb9cdb7815618d4e849", + "048721d90c449b244b7b4c53a9186b04330174ec" + ], + "authored_date": "2015-12-07T12:52:12.000+01:00", + "author_name": "Marin Jankovski", + "author_email": "marin@gitlab.com", + "committed_date": "2015-12-07T12:52:12.000+01:00", + "committer_name": "Marin Jankovski", + "committer_email": "marin@gitlab.com" + }, + { + "id": "048721d90c449b244b7b4c53a9186b04330174ec", + "message": "LFS object pointer.\n", + "parent_ids": [ + "5f923865dde3436854e9ceb9cdb7815618d4e849" + ], + "authored_date": "2015-12-07T11:54:28.000+01:00", + "author_name": "Marin Jankovski", + "author_email": "maxlazio@gmail.com", + "committed_date": "2015-12-07T11:54:28.000+01:00", + "committer_name": "Marin Jankovski", + "committer_email": "maxlazio@gmail.com" + }, + { + "id": "5f923865dde3436854e9ceb9cdb7815618d4e849", + "message": "GitLab currently doesn't support patches that involve a merge commit: add a commit here\n", + "parent_ids": [ + "d2d430676773caa88cdaf7c55944073b2fd5561a" + ], + "authored_date": "2015-11-13T16:27:12.000+01:00", + "author_name": "Stan Hu", + "author_email": "stanhu@gmail.com", + "committed_date": "2015-11-13T16:27:12.000+01:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@gmail.com" + }, + { + "id": "d2d430676773caa88cdaf7c55944073b2fd5561a", + "message": "Merge branch 'add-svg' into 'master'\r\n\r\nAdd GitLab SVG\r\n\r\nAdded to test preview of sanitized SVG images\r\n\r\nSee merge request !5", + "parent_ids": [ + "59e29889be61e6e0e5e223bfa9ac2721d31605b8", + "2ea1f3dec713d940208fb5ce4a38765ecb5d3f73" + ], + "authored_date": "2015-11-13T08:50:17.000+01:00", + "author_name": "Stan Hu", + "author_email": "stanhu@gmail.com", + "committed_date": "2015-11-13T08:50:17.000+01:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@gmail.com" + }, + { + "id": "2ea1f3dec713d940208fb5ce4a38765ecb5d3f73", + "message": "Add GitLab SVG\n", + "parent_ids": [ + "59e29889be61e6e0e5e223bfa9ac2721d31605b8" + ], + "authored_date": "2015-11-13T08:39:43.000+01:00", + "author_name": "Stan Hu", + "author_email": "stanhu@gmail.com", + "committed_date": "2015-11-13T08:39:43.000+01:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@gmail.com" + }, + { + "id": "59e29889be61e6e0e5e223bfa9ac2721d31605b8", + "message": "Merge branch 'whitespace' into 'master'\r\n\r\nadd whitespace test file\r\n\r\nSorry, I did a mistake.\r\nGit ignore empty files.\r\nSo I add a new whitespace test file.\r\n\r\nSee merge request !4", + "parent_ids": [ + "19e2e9b4ef76b422ce1154af39a91323ccc57434", + "66eceea0db202bb39c4e445e8ca28689645366c5" + ], + "authored_date": "2015-11-13T07:21:40.000+01:00", + "author_name": "Stan Hu", + "author_email": "stanhu@gmail.com", + "committed_date": "2015-11-13T07:21:40.000+01:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@gmail.com" + }, + { + "id": "66eceea0db202bb39c4e445e8ca28689645366c5", + "message": "add spaces in whitespace file\n", + "parent_ids": [ + "08f22f255f082689c0d7d39d19205085311542bc" + ], + "authored_date": "2015-11-13T06:01:27.000+01:00", + "author_name": "윤민식", + "author_email": "minsik.yoon@samsung.com", + "committed_date": "2015-11-13T06:01:27.000+01:00", + "committer_name": "윤민식", + "committer_email": "minsik.yoon@samsung.com" + }, + { + "id": "08f22f255f082689c0d7d39d19205085311542bc", + "message": "remove emtpy file.(beacase git ignore empty file)\nadd whitespace test file.\n", + "parent_ids": [ + "c642fe9b8b9f28f9225d7ea953fe14e74748d53b" + ], + "authored_date": "2015-11-13T06:00:16.000+01:00", + "author_name": "윤민식", + "author_email": "minsik.yoon@samsung.com", + "committed_date": "2015-11-13T06:00:16.000+01:00", + "committer_name": "윤민식", + "committer_email": "minsik.yoon@samsung.com" + }, + { + "id": "19e2e9b4ef76b422ce1154af39a91323ccc57434", + "message": "Merge branch 'whitespace' into 'master'\r\n\r\nadd spaces\r\n\r\nTo test this pull request.(https://github.com/gitlabhq/gitlabhq/pull/9757)\r\nJust add whitespaces.\r\n\r\nSee merge request !3", + "parent_ids": [ + "c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd", + "c642fe9b8b9f28f9225d7ea953fe14e74748d53b" + ], + "authored_date": "2015-11-13T05:23:14.000+01:00", + "author_name": "Stan Hu", + "author_email": "stanhu@gmail.com", + "committed_date": "2015-11-13T05:23:14.000+01:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@gmail.com" + }, + { + "id": "c642fe9b8b9f28f9225d7ea953fe14e74748d53b", + "message": "add whitespace in empty\n", + "parent_ids": [ + "9a944d90955aaf45f6d0c88f30e27f8d2c41cec0" + ], + "authored_date": "2015-11-13T05:08:45.000+01:00", + "author_name": "윤민식", + "author_email": "minsik.yoon@samsung.com", + "committed_date": "2015-11-13T05:08:45.000+01:00", + "committer_name": "윤민식", + "committer_email": "minsik.yoon@samsung.com" + }, + { + "id": "9a944d90955aaf45f6d0c88f30e27f8d2c41cec0", + "message": "add empty file\n", + "parent_ids": [ + "c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd" + ], + "authored_date": "2015-11-13T05:08:04.000+01:00", + "author_name": "윤민식", + "author_email": "minsik.yoon@samsung.com", + "committed_date": "2015-11-13T05:08:04.000+01:00", + "committer_name": "윤민식", + "committer_email": "minsik.yoon@samsung.com" + }, + { + "id": "c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd", + "message": "Add ISO-8859 test file\n", + "parent_ids": [ + "e56497bb5f03a90a51293fc6d516788730953899" + ], + "authored_date": "2015-08-25T17:53:12.000+02:00", + "author_name": "Stan Hu", + "author_email": "stanhu@packetzoom.com", + "committed_date": "2015-08-25T17:53:12.000+02:00", + "committer_name": "Stan Hu", + "committer_email": "stanhu@packetzoom.com" + }, + { + "id": "e56497bb5f03a90a51293fc6d516788730953899", + "message": "Merge branch 'tree_helper_spec' into 'master'\n\nAdd directory structure for tree_helper spec\n\nThis directory structure is needed for a testing the method flatten_tree(tree) in the TreeHelper module\n\nSee [merge request #275](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/275#note_732774)\n\nSee merge request !2\n", + "parent_ids": [ + "5937ac0a7beb003549fc5fd26fc247adbce4a52e", + "4cd80ccab63c82b4bad16faa5193fbd2aa06df40" + ], + "authored_date": "2015-01-10T22:23:29.000+01:00", + "author_name": "Sytse Sijbrandij", + "author_email": "sytse@gitlab.com", + "committed_date": "2015-01-10T22:23:29.000+01:00", + "committer_name": "Sytse Sijbrandij", + "committer_email": "sytse@gitlab.com" + }, + { + "id": "4cd80ccab63c82b4bad16faa5193fbd2aa06df40", + "message": "add directory structure for tree_helper spec\n", + "parent_ids": [ + "5937ac0a7beb003549fc5fd26fc247adbce4a52e" + ], + "authored_date": "2015-01-10T21:28:18.000+01:00", + "author_name": "marmis85", + "author_email": "marmis85@gmail.com", + "committed_date": "2015-01-10T21:28:18.000+01:00", + "committer_name": "marmis85", + "committer_email": "marmis85@gmail.com" + }, + { + "id": "5937ac0a7beb003549fc5fd26fc247adbce4a52e", + "message": "Add submodule from gitlab.com\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", + "parent_ids": [ + "570e7b2abdd848b95f2f578043fc23bd6f6fd24d" + ], + "authored_date": "2014-02-27T10:01:38.000+01:00", + "author_name": "Dmitriy Zaporozhets", + "author_email": "dmitriy.zaporozhets@gmail.com", + "committed_date": "2014-02-27T10:01:38.000+01:00", + "committer_name": "Dmitriy Zaporozhets", + "committer_email": "dmitriy.zaporozhets@gmail.com" + }, + { + "id": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d", + "message": "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", + "parent_ids": [ + "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9" + ], + "authored_date": "2014-02-27T09:57:31.000+01:00", + "author_name": "Dmitriy Zaporozhets", + "author_email": "dmitriy.zaporozhets@gmail.com", + "committed_date": "2014-02-27T09:57:31.000+01:00", + "committer_name": "Dmitriy Zaporozhets", + "committer_email": "dmitriy.zaporozhets@gmail.com" + }, + { + "id": "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9", + "message": "More submodules\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", + "parent_ids": [ + "d14d6c0abdd253381df51a723d58691b2ee1ab08" + ], + "authored_date": "2014-02-27T09:54:21.000+01:00", + "author_name": "Dmitriy Zaporozhets", + "author_email": "dmitriy.zaporozhets@gmail.com", + "committed_date": "2014-02-27T09:54:21.000+01:00", + "committer_name": "Dmitriy Zaporozhets", + "committer_email": "dmitriy.zaporozhets@gmail.com" + }, + { + "id": "d14d6c0abdd253381df51a723d58691b2ee1ab08", + "message": "Remove ds_store files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", + "parent_ids": [ + "c1acaa58bbcbc3eafe538cb8274ba387047b69f8" + ], + "authored_date": "2014-02-27T09:49:50.000+01:00", + "author_name": "Dmitriy Zaporozhets", + "author_email": "dmitriy.zaporozhets@gmail.com", + "committed_date": "2014-02-27T09:49:50.000+01:00", + "committer_name": "Dmitriy Zaporozhets", + "committer_email": "dmitriy.zaporozhets@gmail.com" + }, + { + "id": "c1acaa58bbcbc3eafe538cb8274ba387047b69f8", + "message": "Ignore DS files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", + "parent_ids": [ + "ae73cb07c9eeaf35924a10f713b364d32b2dd34f" + ], + "authored_date": "2014-02-27T09:48:32.000+01:00", + "author_name": "Dmitriy Zaporozhets", + "author_email": "dmitriy.zaporozhets@gmail.com", + "committed_date": "2014-02-27T09:48:32.000+01:00", + "committer_name": "Dmitriy Zaporozhets", + "committer_email": "dmitriy.zaporozhets@gmail.com" } ], "st_diffs": [ { - "diff": "--- /dev/null\n+++ b/test\n", - "new_path": "test", - "old_path": "test", + "diff": "Binary files a/.DS_Store and /dev/null differ\n", + "new_path": ".DS_Store", + "old_path": ".DS_Store", + "a_mode": "100644", + "b_mode": "0", + "new_file": false, + "renamed_file": false, + "deleted_file": true, + "too_large": false + }, + { + "diff": "--- a/.gitignore\n+++ b/.gitignore\n@@ -17,3 +17,4 @@ rerun.txt\n pickle-email-*.html\n .project\n config/initializers/secret_token.rb\n+.DS_Store\n", + "new_path": ".gitignore", + "old_path": ".gitignore", + "a_mode": "100644", + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- a/.gitmodules\n+++ b/.gitmodules\n@@ -1,3 +1,9 @@\n [submodule \"six\"]\n \tpath = six\n \turl = git://github.com/randx/six.git\n+[submodule \"gitlab-shell\"]\n+\tpath = gitlab-shell\n+\turl = https://github.com/gitlabhq/gitlab-shell.git\n+[submodule \"gitlab-grack\"]\n+\tpath = gitlab-grack\n+\turl = https://gitlab.com/gitlab-org/gitlab-grack.git\n", + "new_path": ".gitmodules", + "old_path": ".gitmodules", + "a_mode": "100644", + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- a/CHANGELOG\n+++ b/CHANGELOG\n@@ -1,4 +1,6 @@\n-v 6.7.0\n+v6.8.0\n+\n+v6.7.0\n - Add support for Gemnasium as a Project Service (Olivier Gonzalez)\n - Add edit file button to MergeRequest diff\n - Public groups (Jason Hollingsworth)\n", + "new_path": "CHANGELOG", + "old_path": "CHANGELOG", + "a_mode": "100644", + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/encoding/iso8859.txt\n@@ -0,0 +1 @@\n+Äü\n", + "new_path": "encoding/iso8859.txt", + "old_path": "encoding/iso8859.txt", "a_mode": "0", "b_mode": "100644", "new_file": true, "renamed_file": false, "deleted_file": false, "too_large": false - } - ], - "merge_request_id": 11, - "created_at": "2016-03-22T15:13:44.497Z", - "updated_at": "2016-03-22T15:13:44.547Z", - "base_commit_sha": "be93687618e4b132087f430a4d8fc3a609c9b77c", - "real_size": "1" - } - }, - { - "id": 10, - "target_branch": "test-6", - "source_branch": "test-7", - "source_project_id": 5, - "author_id": 22, - "assignee_id": 4, - "title": "Rerum commodi corporis quis qui fugit sed ut.", - "created_at": "2016-03-22T15:13:44.103Z", - "updated_at": "2016-03-22T15:20:32.096Z", - "milestone_id": 11, - "state": "opened", - "merge_status": "unchecked", - "target_project_id": 5, - "iid": 2, - "description": "Laudantium vel dignissimos aspernatur quis aut. Dolores et doloremque ipsa quia voluptate modi labore. Ipsa provident repellat error et nihil.", - "position": 0, - "locked_at": null, - "updated_by_id": null, - "merge_error": null, - "merge_params": { - - }, - "merge_when_build_succeeds": false, - "merge_user_id": null, - "merge_commit_sha": null, - "deleted_at": null, - "notes": [ - { - "id": 1271, - "note": "Quod ut ut quisquam et ut dolorem dolor.", - "noteable_type": "MergeRequest", - "author_id": 1, - "created_at": "2016-03-22T15:20:32.093Z", - "updated_at": "2016-03-22T15:20:32.093Z", - "project_id": 5, - "attachment": { - "url": null }, - "line_code": null, - "commit_id": null, - "noteable_id": 10, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 1270, - "note": "Sed deserunt et explicabo rem repellat voluptatem.", - "noteable_type": "MergeRequest", - "author_id": 3, - "created_at": "2016-03-22T15:20:32.070Z", - "updated_at": "2016-03-22T15:20:32.070Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 10, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 1269, - "note": "Veritatis architecto omnis consequatur et optio.", - "noteable_type": "MergeRequest", - "author_id": 4, - "created_at": "2016-03-22T15:20:32.046Z", - "updated_at": "2016-03-22T15:20:32.046Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 10, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 1268, - "note": "Omnis suscipit odio molestiae debitis quia autem magni.", - "noteable_type": "MergeRequest", - "author_id": 10, - "created_at": "2016-03-22T15:20:32.019Z", - "updated_at": "2016-03-22T15:20:32.019Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 10, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 1267, - "note": "Molestias est sunt est tempora consequatur cupiditate magnam.", - "noteable_type": "MergeRequest", - "author_id": 12, - "created_at": "2016-03-22T15:20:31.993Z", - "updated_at": "2016-03-22T15:20:31.993Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 10, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 1266, - "note": "Ratione blanditiis eveniet voluptatem nostrum rerum excepturi in molestiae.", - "noteable_type": "MergeRequest", - "author_id": 22, - "created_at": "2016-03-22T15:20:31.969Z", - "updated_at": "2016-03-22T15:20:31.969Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 10, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 1265, - "note": "Illo voluptatibus vel odio ea.", - "noteable_type": "MergeRequest", - "author_id": 24, - "created_at": "2016-03-22T15:20:31.944Z", - "updated_at": "2016-03-22T15:20:31.944Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 10, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 1264, - "note": "Earum veritatis quis facere itaque iure.", - "noteable_type": "MergeRequest", - "author_id": 26, - "created_at": "2016-03-22T15:20:31.919Z", - "updated_at": "2016-03-22T15:20:31.919Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 10, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 4" - } - } - ], - "merge_request_diff": { - "id": 10, - "state": "collected", - "st_commits": [ { - "id": "b42bb86cea49bdcef943e521584b7f417d8ddd3d", - "message": "fixes #10\n", - "parent_ids": [ - "be93687618e4b132087f430a4d8fc3a609c9b77c" - ], - "authored_date": "2016-01-19T15:03:09.000+01:00", - "author_name": "Test Lopez", - "author_email": "Test@Testlopez.es", - "committed_date": "2016-01-19T15:03:09.000+01:00", - "committer_name": "Test Lopez", - "committer_email": "Test@Testlopez.es" - } - ], - "st_diffs": [ + "diff": "Binary files a/files/.DS_Store and /dev/null differ\n", + "new_path": "files/.DS_Store", + "old_path": "files/.DS_Store", + "a_mode": "100644", + "b_mode": "0", + "new_file": false, + "renamed_file": false, + "deleted_file": true, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/files/images/wm.svg\n@@ -0,0 +1,78 @@\n+\u003c?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?\u003e\n+\u003csvg width=\"1300px\" height=\"680px\" viewBox=\"0 0 1300 680\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\"\u003e\n+ \u003c!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch --\u003e\n+ \u003ctitle\u003ewm\u003c/title\u003e\n+ \u003cdesc\u003eCreated with Sketch.\u003c/desc\u003e\n+ \u003cdefs\u003e\n+ \u003cpath id=\"path-1\" d=\"M-69.8,1023.54607 L1675.19996,1023.54607 L1675.19996,0 L-69.8,0 L-69.8,1023.54607 L-69.8,1023.54607 Z\"\u003e\u003c/path\u003e\n+ \u003c/defs\u003e\n+ \u003cg id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\"\u003e\n+ \u003cpath d=\"M1300,680 L0,680 L0,0 L1300,0 L1300,680 L1300,680 Z\" id=\"bg\" fill=\"#30353E\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cg id=\"gitlab_logo\" sketch:type=\"MSLayerGroup\" transform=\"translate(-262.000000, -172.000000)\"\u003e\n+ \u003cg id=\"g10\" transform=\"translate(872.500000, 512.354581) scale(1, -1) translate(-872.500000, -512.354581) translate(0.000000, 0.290751)\"\u003e\n+ \u003cg id=\"g12\" transform=\"translate(1218.022652, 440.744871)\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\n+ \u003cpath d=\"M-50.0233338,141.900706 L-69.07059,141.900706 L-69.0100967,0.155858152 L8.04444805,0.155858152 L8.04444805,17.6840847 L-49.9628405,17.6840847 L-50.0233338,141.900706 L-50.0233338,141.900706 Z\" id=\"path14\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g16\"\u003e\n+ \u003cg id=\"g18-Clipped\"\u003e\n+ \u003cmask id=\"mask-2\" sketch:name=\"path22\" fill=\"white\"\u003e\n+ \u003cuse xlink:href=\"#path-1\"\u003e\u003c/use\u003e\n+ \u003c/mask\u003e\n+ \u003cg id=\"path22\"\u003e\u003c/g\u003e\n+ \u003cg id=\"g18\" mask=\"url(#mask-2)\"\u003e\n+ \u003cg transform=\"translate(382.736659, 312.879425)\"\u003e\n+ \u003cg id=\"g24\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(852.718192, 124.992771)\"\u003e\n+ \u003cpath d=\"M63.9833317,27.9148929 C59.2218085,22.9379001 51.2134221,17.9597442 40.3909323,17.9597442 C25.8888194,17.9597442 20.0453962,25.1013043 20.0453962,34.4074318 C20.0453962,48.4730484 29.7848226,55.1819277 50.5642821,55.1819277 C54.4602853,55.1819277 60.7364685,54.7492469 63.9833317,54.1002256 L63.9833317,27.9148929 L63.9833317,27.9148929 Z M44.2869356,113.827628 C28.9053426,113.827628 14.7975996,108.376082 3.78897657,99.301416 L10.5211864,87.6422957 C18.3131929,92.1866076 27.8374026,96.7320827 41.4728323,96.7320827 C57.0568452,96.7320827 63.9833317,88.7239978 63.9833317,75.3074024 L63.9833317,68.3821827 C60.9528485,69.0312039 54.6766653,69.4650479 50.7806621,69.4650479 C17.4476729,69.4650479 0.565379986,57.7791759 0.565379986,33.3245665 C0.565379986,11.4683685 13.9844297,0.43151772 34.3299658,0.43151772 C48.0351955,0.43151772 61.1692285,6.70771614 65.7143717,16.8780421 L69.1776149,3.02876588 L82.5978279,3.02876588 L82.5978279,75.5237428 C82.5978279,98.462806 72.6408582,113.827628 44.2869356,113.827628 L44.2869356,113.827628 Z\" id=\"path26\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g28\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(959.546624, 124.857151)\"\u003e\n+ \u003cpath d=\"M37.2266657,17.4468081 C30.0837992,17.4468081 23.8064527,18.3121698 19.0449295,20.4767371 L19.0449295,79.2306079 L19.0449295,86.0464943 C25.538656,91.457331 33.5470425,95.3526217 43.7203922,95.3526217 C62.1173451,95.3526217 69.2602116,82.3687072 69.2602116,61.3767077 C69.2602116,31.5135879 57.7885819,17.4468081 37.2266657,17.4468081 M45.2315622,113.963713 C28.208506,113.963713 19.0449295,102.384849 19.0449295,102.384849 L19.0449295,120.67143 L18.9844362,144.908535 L10.3967097,144.908535 L0.371103324,144.908535 L0.431596656,6.62629771 C9.73826309,2.73100702 22.5081728,0.567602823 36.3611458,0.567602823 C71.8579349,0.567602823 88.9566078,23.2891625 88.9566078,62.4584098 C88.9566078,93.4043948 73.1527248,113.963713 45.2315622,113.963713\" id=\"path30\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g32\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(509.576747, 125.294950)\"\u003e\n+ \u003cpath d=\"M68.636665,129.10638 C85.5189579,129.10638 96.3414476,123.480366 103.484314,117.853189 L111.669527,132.029302 C100.513161,141.811145 85.5073245,147.06845 69.5021849,147.06845 C29.0274926,147.06845 0.673569983,122.3975 0.673569983,72.6252464 C0.673569983,20.4709215 31.2622559,0.12910638 66.2553217,0.12910638 C83.7879179,0.12910638 98.7227909,4.24073748 108.462217,8.35236859 L108.063194,64.0763105 L108.063194,70.6502677 L108.063194,81.6057001 L56.1168719,81.6057001 L56.1168719,64.0763105 L89.2323178,64.0763105 L89.6313411,21.7701271 C85.3025779,19.6055598 77.7269514,17.8748364 67.554765,17.8748364 C39.4172223,17.8748364 20.5863462,35.5717154 20.5863462,72.8415868 C20.5863462,110.711628 40.0663623,129.10638 68.636665,129.10638\" id=\"path34\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g36\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(692.388992, 124.376085)\"\u003e\n+ \u003cpath d=\"M19.7766662,145.390067 L1.16216997,145.390067 L1.2226633,121.585642 L1.2226633,111.846834 L1.2226633,106.170806 L1.2226633,96.2656714 L1.2226633,39.5681976 L1.2226633,39.3518572 C1.2226633,16.4127939 11.1796331,1.04797161 39.5335557,1.04797161 C43.4504989,1.04797161 47.2836822,1.40388649 51.0051854,2.07965952 L51.0051854,18.7925385 C48.3109055,18.3796307 45.4351455,18.1446804 42.3476589,18.1446804 C26.763646,18.1446804 19.8371595,26.1516022 19.8371595,39.5681976 L19.8371595,96.2656714 L51.0051854,96.2656714 L51.0051854,111.846834 L19.8371595,111.846834 L19.7766662,145.390067 L19.7766662,145.390067 Z\" id=\"path38\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cpath d=\"M646.318899,128.021188 L664.933395,128.021188 L664.933395,236.223966 L646.318899,236.223966 L646.318899,128.021188 L646.318899,128.021188 Z\" id=\"path40\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cpath d=\"M646.318899,251.154944 L664.933395,251.154944 L664.933395,269.766036 L646.318899,269.766036 L646.318899,251.154944 L646.318899,251.154944 Z\" id=\"path42\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003cg id=\"g44\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.464170, 0.676006)\"\u003e\n+ \u003cpath d=\"M429.269989,169.815599 L405.225053,243.802859 L357.571431,390.440955 C355.120288,397.984955 344.444378,397.984955 341.992071,390.440955 L294.337286,243.802859 L136.094873,243.802859 L88.4389245,390.440955 C85.9877812,397.984955 75.3118715,397.984955 72.8595648,390.440955 L25.2059427,243.802859 L1.16216997,169.815599 C-1.03187664,163.067173 1.37156997,155.674379 7.11261982,151.503429 L215.215498,0.336141836 L423.319539,151.503429 C429.060589,155.674379 431.462873,163.067173 429.269989,169.815599\" id=\"path46\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g48\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(135.410135, 1.012147)\"\u003e\n+ \u003cpath d=\"M80.269998,0 L80.269998,0 L159.391786,243.466717 L1.14820997,243.466717 L80.269998,0 L80.269998,0 Z\" id=\"path50\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g52\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\"\u003e\n+ \u003cg id=\"path54\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g56\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(24.893471, 1.012613)\"\u003e\n+ \u003cpath d=\"M190.786662,0 L111.664874,243.465554 L0.777106647,243.465554 L190.786662,0 L190.786662,0 Z\" id=\"path58\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g60\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\"\u003e\n+ \u003cg id=\"path62\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g64\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.077245, 0.223203)\"\u003e\n+ \u003cpath d=\"M25.5933327,244.255313 L25.5933327,244.255313 L1.54839663,170.268052 C-0.644486651,163.519627 1.75779662,156.126833 7.50000981,151.957046 L215.602888,0.789758846 L25.5933327,244.255313 L25.5933327,244.255313 Z\" id=\"path66\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g68\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\"\u003e\n+ \u003cg id=\"path70\"\u003e\u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g72\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(25.670578, 244.478283)\"\u003e\n+ \u003cpath d=\"M0,0 L110.887767,0 L63.2329818,146.638096 C60.7806751,154.183259 50.1047654,154.183259 47.6536221,146.638096 L0,0 L0,0 Z\" id=\"path74\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g76\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\"\u003e\n+ \u003cpath d=\"M0,0 L79.121788,243.465554 L190.009555,243.465554 L0,0 L0,0 Z\" id=\"path78\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g80\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(214.902910, 0.223203)\"\u003e\n+ \u003cpath d=\"M190.786662,244.255313 L190.786662,244.255313 L214.831598,170.268052 C217.024481,163.519627 214.622198,156.126833 208.879985,151.957046 L0.777106647,0.789758846 L190.786662,244.255313 L190.786662,244.255313 Z\" id=\"path82\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003cg id=\"g84\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(294.009575, 244.478283)\"\u003e\n+ \u003cpath d=\"M111.679997,0 L0.79222998,0 L48.4470155,146.638096 C50.8993221,154.183259 61.5752318,154.183259 64.0263751,146.638096 L111.679997,0 L111.679997,0 Z\" id=\"path86\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"\u003e\u003c/path\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+ \u003c/g\u003e\n+\u003c/svg\u003e\n\\ No newline at end of file\n", + "new_path": "files/images/wm.svg", + "old_path": "files/images/wm.svg", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/files/lfs/lfs_object.iso\n@@ -0,0 +1,4 @@\n+version https://git-lfs.github.com/spec/v1\n+oid sha256:91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897\n+size 1575078\n+\n", + "new_path": "files/lfs/lfs_object.iso", + "old_path": "files/lfs/lfs_object.iso", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- a/files/ruby/popen.rb\n+++ b/files/ruby/popen.rb\n@@ -6,12 +6,18 @@ module Popen\n \n def popen(cmd, path=nil)\n unless cmd.is_a?(Array)\n- raise \"System commands must be given as an array of strings\"\n+ raise RuntimeError, \"System commands must be given as an array of strings\"\n end\n \n path ||= Dir.pwd\n- vars = { \"PWD\" =\u003e path }\n- options = { chdir: path }\n+\n+ vars = {\n+ \"PWD\" =\u003e path\n+ }\n+\n+ options = {\n+ chdir: path\n+ }\n \n unless File.directory?(path)\n FileUtils.mkdir_p(path)\n@@ -19,6 +25,7 @@ module Popen\n \n @cmd_output = \"\"\n @cmd_status = 0\n+\n Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|\n @cmd_output \u003c\u003c stdout.read\n @cmd_output \u003c\u003c stderr.read\n", + "new_path": "files/ruby/popen.rb", + "old_path": "files/ruby/popen.rb", + "a_mode": "100644", + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- a/files/ruby/regex.rb\n+++ b/files/ruby/regex.rb\n@@ -19,14 +19,12 @@ module Gitlab\n end\n \n def archive_formats_regex\n- #|zip|tar| tar.gz | tar.bz2 |\n- /(zip|tar|tar\\.gz|tgz|gz|tar\\.bz2|tbz|tbz2|tb2|bz2)/\n+ /(zip|tar|7z|tar\\.gz|tgz|gz|tar\\.bz2|tbz|tbz2|tb2|bz2)/\n end\n \n def git_reference_regex\n # Valid git ref regex, see:\n # https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html\n-\n %r{\n (?!\n (?# doesn't begins with)\n", + "new_path": "files/ruby/regex.rb", + "old_path": "files/ruby/regex.rb", + "a_mode": "100644", + "b_mode": "100644", + "new_file": false, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/files/whitespace\n@@ -0,0 +1 @@\n+test \n", + "new_path": "files/whitespace", + "old_path": "files/whitespace", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/foo/bar/.gitkeep\n", + "new_path": "foo/bar/.gitkeep", + "old_path": "foo/bar/.gitkeep", + "a_mode": "0", + "b_mode": "100644", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/gitlab-grack\n@@ -0,0 +1 @@\n+Subproject commit 645f6c4c82fd3f5e06f67134450a570b795e55a6\n", + "new_path": "gitlab-grack", + "old_path": "gitlab-grack", + "a_mode": "0", + "b_mode": "160000", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, + { + "diff": "--- /dev/null\n+++ b/gitlab-shell\n@@ -0,0 +1 @@\n+Subproject commit 79bceae69cb5750d6567b223597999bfa91cb3b9\n", + "new_path": "gitlab-shell", + "old_path": "gitlab-shell", + "a_mode": "0", + "b_mode": "160000", + "new_file": true, + "renamed_file": false, + "deleted_file": false, + "too_large": false + }, { "diff": "--- /dev/null\n+++ b/test\n", "new_path": "test", @@ -4634,34 +6117,60 @@ } ], "merge_request_id": 10, - "created_at": "2016-03-22T15:13:44.107Z", - "updated_at": "2016-03-22T15:13:44.190Z", - "base_commit_sha": "be93687618e4b132087f430a4d8fc3a609c9b77c", - "real_size": "1" - } + "created_at": "2016-06-14T15:02:23.019Z", + "updated_at": "2016-06-14T15:02:23.493Z", + "base_commit_sha": "ae73cb07c9eeaf35924a10f713b364d32b2dd34f", + "real_size": "15" + }, + "events": [ + { + "id": 228, + "target_type": "MergeRequest", + "target_id": 10, + "title": null, + "data": null, + "project_id": 36, + "created_at": "2016-06-14T15:02:23.660Z", + "updated_at": "2016-06-14T15:02:23.660Z", + "action": 1, + "author_id": 1 + }, + { + "id": 170, + "target_type": "MergeRequest", + "target_id": 10, + "title": null, + "data": null, + "project_id": 5, + "created_at": "2016-06-14T15:02:23.660Z", + "updated_at": "2016-06-14T15:02:23.660Z", + "action": 1, + "author_id": 20 + } + ] }, { "id": 9, - "target_branch": "test-8", - "source_branch": "test-9", + "target_branch": "test-6", + "source_branch": "test-12", "source_project_id": 5, - "author_id": 24, - "assignee_id": 3, - "title": "Saepe et neque ut vero nobis et voluptatum facere qui minima.", - "created_at": "2016-03-22T15:13:43.792Z", - "updated_at": "2016-03-22T15:20:32.309Z", - "milestone_id": 10, + "author_id": 16, + "assignee_id": 6, + "title": "Et ipsam voluptas velit sequi illum ut.", + "created_at": "2016-06-14T15:02:22.825Z", + "updated_at": "2016-06-14T15:03:00.904Z", + "milestone_id": 16, "state": "opened", "merge_status": "unchecked", "target_project_id": 5, "iid": 1, - "description": "Autem enim aliquam labore qui voluptas ut voluptatem. Et corrupti sit fuga dolores alias iusto voluptatem. Excepturi ut saepe accusamus neque distinctio.", + "description": "Eveniet nihil ratione veniam similique qui aut sapiente tempora. Sed praesentium iusto dignissimos possimus id repudiandae quo nihil. Qui doloremque autem et iure fugit.", "position": 0, "locked_at": null, "updated_by_id": null, "merge_error": null, "merge_params": { - + "force_remove_source_branch": null }, "merge_when_build_succeeds": false, "merge_user_id": null, @@ -4669,159 +6178,12 @@ "deleted_at": null, "notes": [ { - "id": 1279, - "note": "A corrupti nesciunt pariatur ea.", - "noteable_type": "MergeRequest", - "author_id": 1, - "created_at": "2016-03-22T15:20:32.307Z", - "updated_at": "2016-03-22T15:20:32.307Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 9, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Administrator" - } - }, - { - "id": 1278, - "note": "Adipisci aut ut et voluptate numquam.", - "noteable_type": "MergeRequest", - "author_id": 3, - "created_at": "2016-03-22T15:20:32.281Z", - "updated_at": "2016-03-22T15:20:32.281Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 9, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Alexie Trantow" - } - }, - { - "id": 1277, - "note": "Adipisci voluptatem quod ut placeat repellendus deleniti.", - "noteable_type": "MergeRequest", - "author_id": 4, - "created_at": "2016-03-22T15:20:32.255Z", - "updated_at": "2016-03-22T15:20:32.255Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 9, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Julius Moore" - } - }, - { - "id": 1276, - "note": "Vitae et doloremque aut et aspernatur velit placeat sed.", - "noteable_type": "MergeRequest", - "author_id": 10, - "created_at": "2016-03-22T15:20:32.230Z", - "updated_at": "2016-03-22T15:20:32.230Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 9, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Robyn McCullough Jr." - } - }, - { - "id": 1275, - "note": "Quos cupiditate nesciunt expedita aspernatur.", - "noteable_type": "MergeRequest", - "author_id": 12, - "created_at": "2016-03-22T15:20:32.207Z", - "updated_at": "2016-03-22T15:20:32.207Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 9, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "Vladimir McCullough" - } - }, - { - "id": 1274, - "note": "Optio rem inventore dicta praesentium sit.", - "noteable_type": "MergeRequest", - "author_id": 22, - "created_at": "2016-03-22T15:20:32.181Z", - "updated_at": "2016-03-22T15:20:32.181Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 9, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 0" - } - }, - { - "id": 1273, - "note": "Sit incidunt molestiae maxime officiis rerum necessitatibus.", - "noteable_type": "MergeRequest", - "author_id": 24, - "created_at": "2016-03-22T15:20:32.159Z", - "updated_at": "2016-03-22T15:20:32.159Z", - "project_id": 5, - "attachment": { - "url": null - }, - "line_code": null, - "commit_id": null, - "noteable_id": 9, - "system": false, - "st_diff": null, - "updated_by_id": null, - "author": { - "name": "User 2" - } - }, - { - "id": 1272, - "note": "Autem ut non itaque molestiae nisi quia officiis doloribus.", + "id": 825, + "note": "Aliquid voluptatem consequatur voluptas ex perspiciatis.", "noteable_type": "MergeRequest", "author_id": 26, - "created_at": "2016-03-22T15:20:32.129Z", - "updated_at": "2016-03-22T15:20:32.129Z", + "created_at": "2016-06-14T15:03:00.722Z", + "updated_at": "2016-06-14T15:03:00.722Z", "project_id": 5, "attachment": { "url": null @@ -4832,9 +6194,180 @@ "system": false, "st_diff": null, "updated_by_id": null, - "author": { + "author": { "name": "User 4" - } + }, + "events": [ + + ] + }, + { + "id": 826, + "note": "Itaque optio voluptatem praesentium voluptas.", + "noteable_type": "MergeRequest", + "author_id": 25, + "created_at": "2016-06-14T15:03:00.745Z", + "updated_at": "2016-06-14T15:03:00.745Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 9, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 3" + }, + "events": [ + + ] + }, + { + "id": 827, + "note": "Ut est corporis fuga asperiores delectus excepturi aperiam.", + "noteable_type": "MergeRequest", + "author_id": 22, + "created_at": "2016-06-14T15:03:00.771Z", + "updated_at": "2016-06-14T15:03:00.771Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 9, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "User 0" + }, + "events": [ + + ] + }, + { + "id": 828, + "note": "Similique ea dolore officiis temporibus.", + "noteable_type": "MergeRequest", + "author_id": 20, + "created_at": "2016-06-14T15:03:00.798Z", + "updated_at": "2016-06-14T15:03:00.798Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 9, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ottis Schuster II" + }, + "events": [ + + ] + }, + { + "id": 829, + "note": "Qui laudantium qui quae quis.", + "noteable_type": "MergeRequest", + "author_id": 16, + "created_at": "2016-06-14T15:03:00.828Z", + "updated_at": "2016-06-14T15:03:00.828Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 9, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Rhett Emmerich IV" + }, + "events": [ + + ] + }, + { + "id": 830, + "note": "Et vel voluptas amet laborum qui soluta.", + "noteable_type": "MergeRequest", + "author_id": 15, + "created_at": "2016-06-14T15:03:00.850Z", + "updated_at": "2016-06-14T15:03:00.850Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 9, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Burdette Bernier" + }, + "events": [ + + ] + }, + { + "id": 831, + "note": "Enim ad consequuntur assumenda provident voluptatem similique deleniti.", + "noteable_type": "MergeRequest", + "author_id": 6, + "created_at": "2016-06-14T15:03:00.876Z", + "updated_at": "2016-06-14T15:03:00.876Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 9, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Ari Wintheiser" + }, + "events": [ + + ] + }, + { + "id": 832, + "note": "Officiis sequi commodi pariatur totam fugiat voluptas corporis dignissimos.", + "noteable_type": "MergeRequest", + "author_id": 1, + "created_at": "2016-06-14T15:03:00.902Z", + "updated_at": "2016-06-14T15:03:00.902Z", + "project_id": 5, + "attachment": { + "url": null + }, + "line_code": null, + "commit_id": null, + "noteable_id": 9, + "system": false, + "st_diff": null, + "updated_by_id": null, + "author": { + "name": "Administrator" + }, + "events": [ + + ] } ], "merge_request_diff": { @@ -4842,17 +6375,17 @@ "state": "collected", "st_commits": [ { - "id": "e239ba8c97b80b2874579a4d625ea9628f4c8ff5", + "id": "a4e5dfebf42e34596526acb8611bc7ed80e4eb3f", "message": "fixes #10\n", "parent_ids": [ "be93687618e4b132087f430a4d8fc3a609c9b77c" ], - "authored_date": "2016-01-19T15:38:06.000+01:00", - "author_name": "Test Lopez", - "author_email": "Test@Testlopez.es", - "committed_date": "2016-01-19T15:38:06.000+01:00", - "committer_name": "Test Lopez", - "committer_email": "Test@Testlopez.es" + "authored_date": "2016-01-19T15:44:02.000+01:00", + "author_name": "James Lopez", + "author_email": "james@jameslopez.es", + "committed_date": "2016-01-19T15:44:02.000+01:00", + "committer_name": "James Lopez", + "committer_email": "james@jameslopez.es" } ], "st_diffs": [ @@ -4869,11 +6402,37 @@ } ], "merge_request_id": 9, - "created_at": "2016-03-22T15:13:43.794Z", - "updated_at": "2016-03-22T15:13:43.848Z", + "created_at": "2016-06-14T15:02:22.829Z", + "updated_at": "2016-06-14T15:02:22.900Z", "base_commit_sha": "be93687618e4b132087f430a4d8fc3a609c9b77c", "real_size": "1" - } + }, + "events": [ + { + "id": 229, + "target_type": "MergeRequest", + "target_id": 9, + "title": null, + "data": null, + "project_id": 36, + "created_at": "2016-06-14T15:02:22.927Z", + "updated_at": "2016-06-14T15:02:22.927Z", + "action": 1, + "author_id": 16 + }, + { + "id": 169, + "target_type": "MergeRequest", + "target_id": 9, + "title": null, + "data": null, + "project_id": 5, + "created_at": "2016-06-14T15:02:22.927Z", + "updated_at": "2016-06-14T15:02:22.927Z", + "action": 1, + "author_id": 16 + } + ] } ], "pipelines": [ @@ -5360,5 +6919,464 @@ } ] } + ], + "variables": [ + + ], + "triggers": [ + + ], + "deploy_keys": [ + + ], + "services": [ + { + "id": 164, + "title": null, + "project_id": 5, + "created_at": "2016-06-14T15:02:07.372Z", + "updated_at": "2016-06-14T15:02:07.372Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "issue_tracker", + "default": true, + "wiki_page_events": true + }, + { + "id": 100, + "title": "JetBrains TeamCity CI", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.315Z", + "updated_at": "2016-06-14T15:01:51.315Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "ci", + "default": false, + "wiki_page_events": true + }, + { + "id": 99, + "title": "Slack", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.303Z", + "updated_at": "2016-06-14T15:01:51.303Z", + "active": false, + "properties": { + "notify_only_broken_builds": true + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "common", + "default": false, + "wiki_page_events": true + }, + { + "id": 98, + "title": "Redmine", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.289Z", + "updated_at": "2016-06-14T15:01:51.289Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "issue_tracker", + "default": false, + "wiki_page_events": true + }, + { + "id": 97, + "title": "Pushover", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.277Z", + "updated_at": "2016-06-14T15:01:51.277Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "common", + "default": false, + "wiki_page_events": true + }, + { + "id": 96, + "title": "PivotalTracker", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.267Z", + "updated_at": "2016-06-14T15:01:51.267Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "common", + "default": false, + "wiki_page_events": true + }, + { + "id": 95, + "title": "JIRA", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.255Z", + "updated_at": "2016-06-14T15:01:51.255Z", + "active": false, + "properties": { + "api_url": "", + "jira_issue_transition_id": "2" + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "issue_tracker", + "default": false, + "wiki_page_events": true + }, + { + "id": 94, + "title": "Irker (IRC gateway)", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.232Z", + "updated_at": "2016-06-14T15:01:51.232Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "common", + "default": false, + "wiki_page_events": true + }, + { + "id": 93, + "title": "HipChat", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.219Z", + "updated_at": "2016-06-14T15:01:51.219Z", + "active": false, + "properties": { + "notify_only_broken_builds": true + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "common", + "default": false, + "wiki_page_events": true + }, + { + "id": 92, + "title": "Gemnasium", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.202Z", + "updated_at": "2016-06-14T15:01:51.202Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "common", + "default": false, + "wiki_page_events": true + }, + { + "id": 91, + "title": "Flowdock", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.182Z", + "updated_at": "2016-06-14T15:01:51.182Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "common", + "default": false, + "wiki_page_events": true + }, + { + "id": 90, + "title": "External Wiki", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.166Z", + "updated_at": "2016-06-14T15:01:51.166Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "common", + "default": false, + "wiki_page_events": true + }, + { + "id": 89, + "title": "Emails on push", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.153Z", + "updated_at": "2016-06-14T15:01:51.153Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "common", + "default": false, + "wiki_page_events": true + }, + { + "id": 88, + "title": "Drone CI", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.139Z", + "updated_at": "2016-06-14T15:01:51.139Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "ci", + "default": false, + "wiki_page_events": true + }, + { + "id": 87, + "title": "Custom Issue Tracker", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.125Z", + "updated_at": "2016-06-14T15:01:51.125Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "issue_tracker", + "default": false, + "wiki_page_events": true + }, + { + "id": 86, + "title": "Campfire", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.113Z", + "updated_at": "2016-06-14T15:01:51.113Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "common", + "default": false, + "wiki_page_events": true + }, + { + "id": 85, + "title": "Builds emails", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.090Z", + "updated_at": "2016-06-14T15:01:51.090Z", + "active": false, + "properties": { + "notify_only_broken_builds": true + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "common", + "default": false, + "wiki_page_events": true + }, + { + "id": 84, + "title": "Buildkite", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.080Z", + "updated_at": "2016-06-14T15:01:51.080Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "ci", + "default": false, + "wiki_page_events": true + }, + { + "id": 83, + "title": "Atlassian Bamboo CI", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.067Z", + "updated_at": "2016-06-14T15:01:51.067Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "ci", + "default": false, + "wiki_page_events": true + }, + { + "id": 82, + "title": "Assembla", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.047Z", + "updated_at": "2016-06-14T15:01:51.047Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "common", + "default": false, + "wiki_page_events": true + }, + { + "id": 81, + "title": "Asana", + "project_id": 5, + "created_at": "2016-06-14T15:01:51.031Z", + "updated_at": "2016-06-14T15:01:51.031Z", + "active": false, + "properties": { + + }, + "template": false, + "push_events": true, + "issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "build_events": true, + "category": "common", + "default": false, + "wiki_page_events": true + } + ], + "hooks": [ + + ], + "protected_branches": [ + ] } \ No newline at end of file From 29b78800b52ff4999d61d19765322046c411735d Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 29 Jun 2016 13:59:21 +0200 Subject: [PATCH 19/98] updated integration test file --- .../import_export/test_project_export.tar.gz | Bin 345686 -> 687442 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/spec/features/projects/import_export/test_project_export.tar.gz b/spec/features/projects/import_export/test_project_export.tar.gz index 1fd04416d959363f9d348438c978330e58d2c704..7bb0d26b21c03d96db4363bd0543422bcf5df536 100644 GIT binary patch delta 181119 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≥uudpn9SQ#e}H`NLc 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%0AAV6-XvRwMvJ{(1ZHL>Vw&@Y zA?pmMoyFQBt3%J8>WMe?kBVWkU9n&t+wXEckN|$OLvUR$@g9s^mC<(>%dMgUB7C@}-$4nBW++{W3 z_6g2brS-@DeC9x<<&R^(;6AEpJVT6)|fKM)m>R?xa3Ai?*m zN-wfWX9yfCUP`dBOovACehCpK(wi~bx%=$b(R+OW6BGv zU48o2DF8J1%9(+sTo>jD}=-;o{eD9Dh~cKseBg9FY5 zpl$r*Mb<%t`K9;|!CXq>u+Y;y1B_`$wc>7q8Dwv9aU!rF1{ev-VcOOjm9AKdzzncV zryr49>X&B}*RgnRZ`ebBnhcmR753S4bd(8|R>i4Ij>ctL8_SNSE5yoz<3WerYo2M* zCRJM`6~g&Ho=+-}fqoD>`096mQRp0e?s2a(WQziwNrEQ}Xk2%hN-xYgyoSAG6rshtz5dHC)j+q@@?Q~wgmBI#Sn~S5XY7|te4vsO` zDlHdpi=kCrtcK&4ujqzRzux!Pm;J--Q@3CDujY80f)B;7YZENj;?t`%y|v~;>1LDq za^p?EPd}IsSiUxJGY!LbW!86Ssh>xxP3qJr6C`xbq8##nZ1T1(4x+~$$gH=LrQ305 z+Yk@5ky3#PXfl`0d&4}JZnVunbguOkzS>Z}vgaoBtD186IvlT)O7v8fjruOJl`}@A9*krgZJ0t6pju{^!{vfj()fWfQlto90yjk*h@%$9i{w@KR`{GGboaV{Gjn_v2{u0&>9+awkVVC5?jsj20qxC8nmimP7a+3%Ni>ZMj5=c z-RsFM0Zy{1*8|N?oxD%^@0V%JNPR7)bwW7UGV{iXvrq>xkt5921lcU2CA?_g)Drz} z^5B*!ix*wa;m1v_FR*OK!Gcpd)z1(b-}#okpXGypNLw(fxW6yMM2TWu>q>($lf2$P zUw?DCLDs-`QYF*(T_7LqZap_G<@)`NVbh5qiUd^_ z10|B=ZJ`oxi=L}9R}GJJd11#i^!-dM+$z&iSN7WPyl}xY&0(_p6D&`SgAG3f9&Z)y z0QBkX-mz9igEW;BA@8~`QXo#waeBY=f33WK#Ly!)D3&vt7Y|Gx=MCV!{LBCN<%OXpL`N8Xk91 zA1F%yd$QaqJ5FfK{S?K7C*!)=hO}p+Q8C~9f2C7I+&ByN+#vhExOk^1O_-otvuxY8 zZQHhOTV1wocG$nfHQ_o^kzqyn59ute=!H@PWzJ8K_ik ze}<~Pfx-n}ux3KL(x4ID`*mr24V|nOihnPO4eUwq&HbihEqb!lUFV55Cep4^?G;2q zhgkBObOu#OdPt}jZ78$WbWiD@+=j(ur!;pU@D>?_wLo!GBX_HuiH;m-msc?Zc8-=V z3&vGq((2XQ0q2>#^NpZ(-|OF$q8}7ie<{Yl{fB^qY=xG8V-a{&-u z73jd2ovypVDcHzNXTE@AEQf(Q1_67*^LqQ@A#h*Vr7Tr4zhqC3L?PlfOG2br%K8s( zE8mM2-zw&X3v-t^0r`*fpe=u>a`Z#?)GALpE}ZJPQqVQLD%Onnh{mT9I~H9Me+}9K z6Tdhj3)@ih0Tgc;3rJa2C>QceYx2G}s^E^od}{O(gz}|NiY;69Hxu9wu)z#-&J<(^ zwca7ix}f^$ZNrkY@uh+Dqx9cJB;h%ij3qO+nl~2}X)7ZvsziX$(xjmLHr}gY!qs^m zFT=8Q^tivCqH8UFHufD0jCSa=e^2Iy5>4&YyRg=doHYWCGaqT{1*6LVfPp%pJAe>za5uD-Da zVhb;RjFY`9(stXEDs}iY8{V@9CWZ`st1o|UqL!Ku3L0KymNGw-K~u;$v;8$>cMHbE z_gJ8b!yq0@jIEB0FMv!XE+4#vf!$kC;Ra(2MG_qo;3$(CHauet7r|sv_$_LFESW@dTFEb}EA5Qm1 zl=xk@v|Ne~U8{NGdgjQ1c7^){`W{$t{bDkL0l_g9|GV-U5e{xA~1*{=Vqd|lq z%UeOL?s?>oeUSRpvFrjtaaXXp49~TLr#)>5H<3feKZRI0UUdSzr$KE-FHRFEHE^UI z39|9;NJ$`u^E9Xmb;ge&l-HqEywF%hMze>7-0Sa$kfyOfKSnSie zp&6t@!=EMyv0&mV5(Oi*wqjo-rm=(3x-@10E`hK(=M#^2YFHTv%AWE{3 zP@vwB0rQYRKn2J^KuWT}An2g~FBbgI93&9j|3e5uB|-l?fBYXvfcig>pdqmNHGp=QXjCi&le#D<+N4ORNf8GSBNd{#6#926nq9@3Ip3SvS z=7R6*mh;}hyM`znr0i!ztd9@Wa!5N&NWqdj&1;_SPjJ$Ls)ZLA$PYuUh?MVh&=PJP za-=F<-sP}Z+JMA|3|mxpt1qN*V!a6+T)=Ef@p~R~jN**ImveK*+HgE^(XuAATj0~D zx}##Ff1}dp?hc5kfgniRdQM&x+*oMDTjn>n94jIIZ}Btau_1KD%c4UkGLdb?f6Nd@ zWi)78gNbcds(%p&p39`Sfqzc!)EYvlf{ql;cIoK)G=hmf^Ke>Z6=ik$D{d?=Cp)*56!t%AKji)w;N%&=4TDISl3kmmZji}+FzLJE6{olBS(>SO=`LrgHsTwk(Xm zI;XP57d$;y62XPI>Lz1E*`bi!{Y@CO4l>1k7qG75zU!nM_^XB4ry&Gu(1)zAhuS$(-7{U$AiN{@ zq~0t0&;uzoNETNqGqHKmc)MP~AZ^6v>P#LkQAk=tS-^jAaO!OgNEUg4k&d{wT0=o? zwoaCY&VVn8!(_YKp=9W{e-8HNmD})E>bWrfVC$7VSvYaBxx^2ie<^cRi|c?rjq@Gv zvMqPy`Q_cO3?gLvpIbx)G6jQ2crZ{x>+aERK&YSxXMJLFvIylZ(ZbNy#LEgXH;-&y z+^Fc_O6NbRYJWiv2p&!L*MoWG-e}vp;W;L|X*>nd=356;`%cDwF3`of}8-4EpRl6YwJ2wffay7>#1@Tb%;f zHe+D6&ZN2)FDxW=SY1x?kYCFjPnvUyQhrH9)dZBvXc|-wIgDzQE?w?64{eS7F}FQv z*I1U}vEA0|Y3`u-f8#l~s<4gqS1!R>^-rbR>1b73DOD*4fgnr-AaV7=yhvzTov3UZ zt-OWByAhQD&#yAJ0Oq9m!;HZoTd!lhR`JZh0yGH_2MdF-NP9L)UuR=0w9`?h5k%L! zHp~9ppXiM+m^(?B98Di!GPQ_9%!(L&9ZTvAFzZP^v7*@3fAKw9_mJC(s(r=X@@i~- znTg(38ZV_8K;;p!=mcO3L{FWqT4@xiy=2F}pi+57a8iPQ#f6+|VDKomL;>!pno&_8 zsHHuaXLG9Nv9V2P>NJ(2=n@rvxdfsUEG`y8<1ZLt_+puCsxQq1@hsX{{rQ(H0QHs+ z?D}vJwd&@!e{Ⓢ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�F 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 XF)=YQF)=YQu`l93x>1Od0B{Wej4NU# delta 82593 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 From d18bc9786c67677ac6c6cad7564e6b5a4cb09c89 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 29 Jun 2016 14:01:28 +0200 Subject: [PATCH 20/98] fix final line missing --- app/models/concerns/eventable.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/concerns/eventable.rb b/app/models/concerns/eventable.rb index 56aa7176de..aa23b350a0 100644 --- a/app/models/concerns/eventable.rb +++ b/app/models/concerns/eventable.rb @@ -12,4 +12,4 @@ module Eventable event.save! end end -end \ No newline at end of file +end From f85f5a4516ef4c7809a52f6fba7cfb1120c3b971 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 29 Jun 2016 14:09:18 +0200 Subject: [PATCH 21/98] add changelog --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 27dd870855..b28a243750 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -25,6 +25,7 @@ v 8.9.3 (unreleased) - Fix encrypted data backwards compatibility after upgrading attr_encrypted gem - Update mobile button icons to be more inline with typical UI paradigms - Fixes missing avatar on system notes. !4954 + - Fixes issues importing events in Import/Export. Import/Export version bumped to 0.1.1 v 8.9.2 - Fix visibility of snippets when searching. @@ -75,7 +76,6 @@ v 8.9.1 - Remove duplicate 'New Page' button on edit wiki page v 8.9.0 -v 8.9.0 (unreleased) - Fix group visibility form layout in application settings - Fix builds API response not including commit data - Fix error when CI job variables key specified but not defined From c740445ad3825da4e5f7fea943be561ece982443 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 24 Jun 2016 17:26:28 +0200 Subject: [PATCH 22/98] Added RuboCop cops for checking DB migrations There are currently two cops for this: * Migration/AddIndex: checks if indexes are added concurrently * Migration/ColumnWithDefault: checks if columns with default values are added in a concurrent manner Both cops are fairly simple and make no attempt at correcting the code as this is quite hard to do (e.g. modifications may need to be applied in various places in the same file). They however should provide enough to catch people ignoring the comments in generated migrations telling them to use add_concurrent_index or add_column_with_default. --- .rubocop.yml | 4 +- rubocop/cop/migration/add_index.rb | 46 ++++++++++++++++++ rubocop/cop/migration/column_with_default.rb | 50 ++++++++++++++++++++ rubocop/migration_helpers.rb | 10 ++++ rubocop/rubocop.rb | 3 ++ 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 rubocop/cop/migration/add_index.rb create mode 100644 rubocop/cop/migration/column_with_default.rb create mode 100644 rubocop/migration_helpers.rb create mode 100644 rubocop/rubocop.rb diff --git a/.rubocop.yml b/.rubocop.yml index dbdabbb9d4..23ed0c82e8 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,4 +1,6 @@ -require: rubocop-rspec +require: + - rubocop-rspec + - ./rubocop/rubocop AllCops: TargetRubyVersion: 2.1 diff --git a/rubocop/cop/migration/add_index.rb b/rubocop/cop/migration/add_index.rb new file mode 100644 index 0000000000..d9247a1f7e --- /dev/null +++ b/rubocop/cop/migration/add_index.rb @@ -0,0 +1,46 @@ +module RuboCop + module Cop + module Migration + # Cop that checks if indexes are added in a concurrent manner. + class AddIndex < RuboCop::Cop::Cop + include MigrationHelpers + + MSG = 'add_index requires downtime, use add_concurrent_index instead' + + def on_def(node) + return unless in_migration?(node) + + new_tables = [] + + node.each_descendant(:send) do |send_node| + first_arg = first_argument(send_node) + + # The first argument of "create_table" / "add_index" is the table + # name. + new_tables << first_arg if create_table?(send_node) + + next if method_name(send_node) != :add_index + + # Using "add_index" is fine for newly created tables as there's no + # data in these tables yet. + next if new_tables.include?(first_arg) + + add_offense(send_node, :selector) + end + end + + def create_table?(node) + method_name(node) == :create_table + end + + def method_name(node) + node.children[1] + end + + def first_argument(node) + node.children[2] ? node.children[0] : nil + end + end + end + end +end diff --git a/rubocop/cop/migration/column_with_default.rb b/rubocop/cop/migration/column_with_default.rb new file mode 100644 index 0000000000..97ee8b1104 --- /dev/null +++ b/rubocop/cop/migration/column_with_default.rb @@ -0,0 +1,50 @@ +module RuboCop + module Cop + module Migration + # Cop that checks if columns are added in a way that doesn't require + # downtime. + class ColumnWithDefault < RuboCop::Cop::Cop + include MigrationHelpers + + WHITELISTED_TABLES = [:application_settings] + + MSG = 'add_column with a default value requires downtime, ' \ + 'use add_column_with_default instead' + + def on_send(node) + return unless in_migration?(node) + + name = node.children[1] + + return unless name == :add_column + + # Ignore whitelisted tables. + return if table_whitelisted?(node.children[2]) + + opts = node.children.last + + return unless opts && opts.type == :hash + + opts.each_node(:pair) do |pair| + if hash_key_type(pair) == :sym && hash_key_name(pair) == :default + add_offense(node, :selector) + end + end + end + + def table_whitelisted?(symbol) + symbol && symbol.type == :sym && + WHITELISTED_TABLES.include?(symbol.children[0]) + end + + def hash_key_type(pair) + pair.children[0].type + end + + def hash_key_name(pair) + pair.children[0].children[0] + end + end + end + end +end diff --git a/rubocop/migration_helpers.rb b/rubocop/migration_helpers.rb new file mode 100644 index 0000000000..3160a784a0 --- /dev/null +++ b/rubocop/migration_helpers.rb @@ -0,0 +1,10 @@ +module RuboCop + # Module containing helper methods for writing migration cops. + module MigrationHelpers + # Returns true if the given node originated from the db/migrate directory. + def in_migration?(node) + File.dirname(node.location.expression.source_buffer.name). + end_with?('db/migrate') + end + end +end diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb new file mode 100644 index 0000000000..7922e19768 --- /dev/null +++ b/rubocop/rubocop.rb @@ -0,0 +1,3 @@ +require_relative 'migration_helpers' +require_relative 'cop/migration/add_index' +require_relative 'cop/migration/column_with_default' From 9798ac77ed3a1e6106f22c3304f431763ec2cf45 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 29 Jun 2016 15:16:04 +0200 Subject: [PATCH 23/98] Enable Style/SpaceAfterColon Rubocop cops --- .rubocop.yml | 2 +- app/controllers/ci/projects_controller.rb | 2 +- app/helpers/projects_helper.rb | 4 ++-- config/routes.rb | 2 +- features/steps/groups.rb | 2 +- spec/features/projects/import_export/import_file_spec.rb | 2 +- spec/lib/gitlab/import_export/reader_spec.rb | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index dbdabbb9d4..718af49cd4 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -532,7 +532,7 @@ Style/SingleLineMethods: # Use spaces after colons. Style/SpaceAfterColon: - Enabled: false + Enabled: true # Use spaces after commas. Style/SpaceAfterComma: diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb index 8bf71a1adb..aa894fde36 100644 --- a/app/controllers/ci/projects_controller.rb +++ b/app/controllers/ci/projects_controller.rb @@ -25,7 +25,7 @@ module Ci return render_404 unless @project image = Ci::ImageForBuildService.new.execute(@project, params) - send_file image.path, filename: image.name, disposition: 'inline', type:"image/svg+xml" + send_file image.path, filename: image.name, disposition: 'inline', type: "image/svg+xml" end protected diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index d91e3332e4..26796b08fa 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -15,7 +15,7 @@ module ProjectsHelper def link_to_member_avatar(author, opts = {}) default_opts = { avatar: true, name: true, size: 16, author_class: 'author', title: ":name" } opts = default_opts.merge(opts) - image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar] + image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt: '') if opts[:avatar] end def link_to_member(project, author, opts = {}, &block) @@ -27,7 +27,7 @@ module ProjectsHelper author_html = "" # Build avatar image tag - author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar] + author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt: '') if opts[:avatar] # Build name span tag if opts[:by_username] diff --git a/config/routes.rb b/config/routes.rb index bdfb16a66b..2aab73720f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -653,7 +653,7 @@ Rails.application.routes.draw do get '/wikis/*id', to: 'wikis#show', as: 'wiki', constraints: WIKI_SLUG_ID delete '/wikis/*id', to: 'wikis#destroy', constraints: WIKI_SLUG_ID put '/wikis/*id', to: 'wikis#update', constraints: WIKI_SLUG_ID - post '/wikis/*id/markdown_preview', to:'wikis#markdown_preview', constraints: WIKI_SLUG_ID, as: 'wiki_markdown_preview' + post '/wikis/*id/markdown_preview', to: 'wikis#markdown_preview', constraints: WIKI_SLUG_ID, as: 'wiki_markdown_preview' end resource :repository, only: [:show, :create] do diff --git a/features/steps/groups.rb b/features/steps/groups.rb index 483370f41c..4fa7d7c656 100644 --- a/features/steps/groups.rb +++ b/features/steps/groups.rb @@ -93,7 +93,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps step 'I should see new group "Owned" avatar' do expect(owned_group.avatar).to be_instance_of AvatarUploader - expect(owned_group.avatar.url).to eq "/uploads/group/avatar/#{Group.find_by(name:"Owned").id}/banana_sample.gif" + expect(owned_group.avatar.url).to eq "/uploads/group/avatar/#{Group.find_by(name: "Owned").id}/banana_sample.gif" end step 'I should see the "Remove avatar" button' do diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb index c5fb0fc783..9d66f76ef5 100644 --- a/spec/features/projects/import_export/import_file_spec.rb +++ b/spec/features/projects/import_export/import_file_spec.rb @@ -24,7 +24,7 @@ feature 'project import', feature: true, js: true do visit new_project_path select2('2', from: '#project_namespace_id') - fill_in :project_path, with:'test-project-path', visible: true + fill_in :project_path, with: 'test-project-path', visible: true click_link 'GitLab export' expect(page).to have_content('GitLab project export') diff --git a/spec/lib/gitlab/import_export/reader_spec.rb b/spec/lib/gitlab/import_export/reader_spec.rb index 109522fa62..211ef68dfa 100644 --- a/spec/lib/gitlab/import_export/reader_spec.rb +++ b/spec/lib/gitlab/import_export/reader_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::ImportExport::Reader, lib: true do - let(:shared) { Gitlab::ImportExport::Shared.new(relative_path:'') } + let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: '') } let(:test_config) { 'spec/support/import_export/import_export.yml' } let(:project_tree_hash) do { From 28bafd5354427d27cabe40966bd069a75984e2b1 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 29 Jun 2016 15:23:44 +0200 Subject: [PATCH 24/98] Enable Style/SpaceAfterComma Rubocop cop --- .rubocop.yml | 2 +- app/helpers/page_layout_helper.rb | 2 +- app/models/network/graph.rb | 4 ++-- app/models/project_services/hipchat_service.rb | 2 +- app/models/project_services/jira_service.rb | 2 +- app/models/user.rb | 2 +- app/uploaders/lfs_object_uploader.rb | 2 +- config/initializers/devise.rb | 2 +- config/initializers/sidekiq.rb | 2 +- features/steps/project/forked_merge_requests.rb | 2 +- lib/api/group_members.rb | 2 +- lib/gitlab/backend/grack_auth.rb | 2 +- lib/gitlab/o_auth/auth_hash.rb | 2 +- spec/features/issues_spec.rb | 2 +- spec/lib/gitlab/o_auth/user_spec.rb | 4 ++-- spec/requests/api/projects_spec.rb | 6 +++--- 16 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 718af49cd4..bba45c7fb5 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -536,7 +536,7 @@ Style/SpaceAfterColon: # Use spaces after commas. Style/SpaceAfterComma: - Enabled: false + Enabled: true # Do not put a space between a method name and the opening parenthesis in a # method definition. diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb index e4e8b934bc..22387d6645 100644 --- a/app/helpers/page_layout_helper.rb +++ b/app/helpers/page_layout_helper.rb @@ -52,7 +52,7 @@ module PageLayoutHelper raise ArgumentError, 'cannot provide more than two attributes' if map.length > 2 @page_card_attributes ||= {} - @page_card_attributes = map.reject { |_,v| v.blank? } if map.present? + @page_card_attributes = map.reject { |_, v| v.blank? } if map.present? @page_card_attributes end diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb index a2aee2f925..345041a6ad 100644 --- a/app/models/network/graph.rb +++ b/app/models/network/graph.rb @@ -54,7 +54,7 @@ module Network @map = {} @reserved = {} - @commits.each_with_index do |c,i| + @commits.each_with_index do |c, i| c.time = i days[i] = c.committed_date @map[c.id] = c @@ -116,7 +116,7 @@ module Network end def commits_sort_by_ref - @commits.sort do |a,b| + @commits.sort do |a, b| if include_ref?(a) -1 elsif include_ref?(b) diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 0ff4f4c8dd..23e5b16221 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -106,7 +106,7 @@ class HipchatService < Service else message << "pushed to #{ref_type} #{ref} " - message << "of #{project.name_with_namespace.gsub!(/\s/,'')} " + message << "of #{project.name_with_namespace.gsub!(/\s/, '')} " message << "(Compare changes)" push[:commits].take(MAX_COMMITS).each do |commit| diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index beda89d396..8b3296c712 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -124,7 +124,7 @@ class JiraService < IssueTrackerService def build_api_url_from_project_url server = URI(project_url) - default_ports = [["http",80],["https",443]].include?([server.scheme,server.port]) + default_ports = [["http", 80], ["https", 443]].include?([server.scheme, server.port]) server_url = "#{server.scheme}://#{server.host}" server_url.concat(":#{server.port}") unless default_ports "#{server_url}/rest/api/#{DEFAULT_API_VERSION}" diff --git a/app/models/user.rb b/app/models/user.rb index 767d6366c7..eac716b120 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -764,7 +764,7 @@ class User < ActiveRecord::Base unless email_domains.blank? match_found = email_domains.any? do |domain| - escaped = Regexp.escape(domain).gsub('\*','.*?') + escaped = Regexp.escape(domain).gsub('\*', '.*?') regexp = Regexp.new "^#{escaped}$", Regexp::IGNORECASE email_domain = Mail::Address.new(self.email).domain email_domain =~ regexp diff --git a/app/uploaders/lfs_object_uploader.rb b/app/uploaders/lfs_object_uploader.rb index 28085b3108..046a1d641a 100644 --- a/app/uploaders/lfs_object_uploader.rb +++ b/app/uploaders/lfs_object_uploader.rb @@ -4,7 +4,7 @@ class LfsObjectUploader < CarrierWave::Uploader::Base storage :file def store_dir - "#{Gitlab.config.lfs.storage_path}/#{model.oid[0,2]}/#{model.oid[2,2]}" + "#{Gitlab.config.lfs.storage_path}/#{model.oid[0, 2]}/#{model.oid[2, 2]}" end def cache_dir diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 021bdb1125..73977341b7 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -212,7 +212,7 @@ Devise.setup do |config| if Gitlab::LDAP::Config.enabled? Gitlab.config.ldap.servers.values.each do |server| if server['allow_username_or_email_login'] - email_stripping_proc = ->(name) {name.gsub(/@.*\z/,'')} + email_stripping_proc = ->(name) {name.gsub(/@.*\z/, '')} else email_stripping_proc = ->(name) {name} end diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb index 7a2b9a7f6c..593c14a289 100644 --- a/config/initializers/sidekiq.rb +++ b/config/initializers/sidekiq.rb @@ -13,7 +13,7 @@ Sidekiq.configure_server do |config| # UGLY Hack to get nested hash from settingslogic cron_jobs = JSON.parse(Gitlab.config.cron_jobs.to_json) # UGLY hack: Settingslogic doesn't allow 'class' key - cron_jobs.each { |k,v| cron_jobs[k]['class'] = cron_jobs[k].delete('job_class') } + cron_jobs.each { |k, v| cron_jobs[k]['class'] = cron_jobs[k].delete('job_class') } Sidekiq::Cron::Job.load_from_hash! cron_jobs # Database pool should be at least `sidekiq_concurrency` + 2 diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb index 0ead83d693..6b56a77b83 100644 --- a/features/steps/project/forked_merge_requests.rb +++ b/features/steps/project/forked_merge_requests.rb @@ -153,6 +153,6 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps # Verify a link is generated against the correct project def verify_commit_link(container_div, container_project) # This should force a wait for the javascript to execute - expect(find(:div,container_div).find(".commit_short_id")['href']).to have_content "#{container_project.path_with_namespace}/commit" + expect(find(:div, container_div).find(".commit_short_id")['href']).to have_content "#{container_project.path_with_namespace}/commit" end end diff --git a/lib/api/group_members.rb b/lib/api/group_members.rb index ab9b7c602b..dbe5bb08d3 100644 --- a/lib/api/group_members.rb +++ b/lib/api/group_members.rb @@ -77,7 +77,7 @@ module API member = group.group_members.find_by(user_id: params[:user_id]) if member.nil? - render_api_error!("404 Not Found - user_id:#{params[:user_id]} not a member of group #{group.name}",404) + render_api_error!("404 Not Found - user_id:#{params[:user_id]} not a member of group #{group.name}", 404) else member.destroy end diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index ab7b811c5d..ad412f56cc 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -22,7 +22,7 @@ module Grack # Need this if under RELATIVE_URL_ROOT unless Gitlab.config.gitlab.relative_url_root.empty? # If website is mounted using relative_url_root need to remove it first - @env['PATH_INFO'] = @request.path.sub(Gitlab.config.gitlab.relative_url_root,'') + @env['PATH_INFO'] = @request.path.sub(Gitlab.config.gitlab.relative_url_root, '') else @env['PATH_INFO'] = @request.path end diff --git a/lib/gitlab/o_auth/auth_hash.rb b/lib/gitlab/o_auth/auth_hash.rb index 36e5c2670b..7d6911a1ab 100644 --- a/lib/gitlab/o_auth/auth_hash.rb +++ b/lib/gitlab/o_auth/auth_hash.rb @@ -66,7 +66,7 @@ module Gitlab # Get the first part of the email address (before @) # In addtion in removes illegal characters def generate_username(email) - email.match(/^[^@]*/)[0].mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/,'').to_s + email.match(/^[^@]*/)[0].mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/, '').to_s end def generate_temporarily_email(username) diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index 5065dfb849..17df66e73b 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -92,7 +92,7 @@ describe 'Issues', feature: true do end context 'on edit form' do - let(:issue) { create(:issue, author: @user,project: project, due_date: Date.today.at_beginning_of_month.to_s) } + let(:issue) { create(:issue, author: @user, project: project, due_date: Date.today.at_beginning_of_month.to_s) } before do visit edit_namespace_project_issue_path(project.namespace, project, issue) diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb index 6727a83e58..5ec5ab40b6 100644 --- a/spec/lib/gitlab/o_auth/user_spec.rb +++ b/spec/lib/gitlab/o_auth/user_spec.rb @@ -122,7 +122,7 @@ describe Gitlab::OAuth::User, lib: true do before do allow(ldap_user).to receive(:uid) { uid } allow(ldap_user).to receive(:username) { uid } - allow(ldap_user).to receive(:email) { ['johndoe@example.com','john2@example.com'] } + allow(ldap_user).to receive(:email) { ['johndoe@example.com', 'john2@example.com'] } allow(ldap_user).to receive(:dn) { 'uid=user1,ou=People,dc=example' } allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user) end @@ -203,7 +203,7 @@ describe Gitlab::OAuth::User, lib: true do stub_omniauth_config(auto_link_ldap_user: true) allow(ldap_user).to receive(:uid) { uid } allow(ldap_user).to receive(:username) { uid } - allow(ldap_user).to receive(:email) { ['johndoe@example.com','john2@example.com'] } + allow(ldap_user).to receive(:email) { ['johndoe@example.com', 'john2@example.com'] } allow(ldap_user).to receive(:dn) { 'uid=user1,ou=People,dc=example' } allow(oauth_user).to receive(:ldap_person).and_return(ldap_user) end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 41b5ed9bc3..5c909d8b3b 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -217,7 +217,7 @@ describe API::API, api: true do post api('/projects', user), project - project.each_pair do |k,v| + project.each_pair do |k, v| expect(json_response[k.to_s]).to eq(v) end end @@ -325,7 +325,7 @@ describe API::API, api: true do post api("/projects/user/#{user.id}", admin), project - project.each_pair do |k,v| + project.each_pair do |k, v| next if k == :path expect(json_response[k.to_s]).to eq(v) end @@ -805,7 +805,7 @@ describe API::API, api: true do context 'when authenticated' do it 'should return an array of projects' do - get api("/projects/search/#{query}",user) + get api("/projects/search/#{query}", user) expect(response).to have_http_status(200) expect(json_response).to be_an Array expect(json_response.size).to eq(6) From 8c29b0b06554eb9549fe9bd2f33e80ce149752fd Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 28 Jun 2016 15:14:11 -0700 Subject: [PATCH 25/98] Memoize the maximum access level for the author of notes In #19273, we saw that retrieving ProjectTeam#human_max_access for each note takes the bulk of the time when rendering certain issues or merge requests. We observe that most of the comments in an issue are typically done by the same users. This MR memoizes the max access level by user ID. --- app/helpers/notes_helper.rb | 8 ++++++ app/views/projects/notes/_note.html.haml | 2 +- spec/helpers/notes_helper_spec.rb | 32 ++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 spec/helpers/notes_helper_spec.rb diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index b401c8385b..80d588aaf5 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -69,4 +69,12 @@ module NotesHelper button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button', data: data, title: 'Add a reply' end + + def note_max_access_for_user(note) + user_id = note.author.id + project = note.project + @max_access_by_user_id ||= Hash.new { |hash, key| hash[key] = project.team.human_max_access(key) } + + @max_access_by_user_id[user_id] + end end diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index a5e163b91e..af0046886f 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -17,7 +17,7 @@ %a{ href: "##{dom_id(note)}" } = time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note-created-ago') .note-actions - - access = note.project.team.human_max_access(note.author.id) + - access = note_max_access_for_user(note) - if access and not note.system %span.note-role.hidden-xs= access - if current_user and not note.system diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb new file mode 100644 index 0000000000..8325af0dcf --- /dev/null +++ b/spec/helpers/notes_helper_spec.rb @@ -0,0 +1,32 @@ +require "spec_helper" + +describe NotesHelper do + describe "#notes_max_access_for_users" do + let(:owner) { create(:owner) } + let(:group) { create(:group) } + let(:project) { create(:empty_project, namespace: group) } + let(:master) { create(:user) } + let(:reporter) { create(:user) } + let(:guest) { create(:user) } + + let(:owner_note) { create(:note, author: owner, project: project) } + let(:master_note) { create(:note, author: master, project: project) } + let(:reporter_note) { create(:note, author: reporter, project: project) } + let!(:notes) { [owner_note, master_note, reporter_note] } + + before do + group.add_owner(owner) + project.team << [master, :master] + project.team << [reporter, :reporter] + project.team << [guest, :guest] + end + + it 'return human access levels' do + expect(helper.note_max_access_for_user(owner_note)).to eq('Owner') + expect(helper.note_max_access_for_user(master_note)).to eq('Master') + expect(helper.note_max_access_for_user(reporter_note)).to eq('Reporter') + # Call it again to ensure value is cached + expect(helper.note_max_access_for_user(owner_note)).to eq('Owner') + end + end +end From c8d66594e0104a6647b403faea1283e430e158a5 Mon Sep 17 00:00:00 2001 From: winniehell Date: Mon, 27 Jun 2016 14:03:46 +0200 Subject: [PATCH 26/98] Align flash messages with left side of page content (!4959) --- CHANGELOG | 1 + app/assets/javascripts/flash.js.coffee | 12 ++++++++++-- app/assets/stylesheets/framework/flash.scss | 7 +++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c27ad4a467..585f53aa0d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ v 8.10.0 (unreleased) - Fix commit builds API, return all builds for all pipelines for given commit. !4849 - Replace Haml with Hamlit to make view rendering faster. !3666 - Wrap code blocks on Activies and Todos page. !4783 (winniehell) + - Align flash messages with left side of page content !4959 (winniehell) - Display last commit of deleted branch in push events !4699 (winniehell) - Add Sidekiq queue duration to transaction metrics. - Let Workhorse serve format-patch diffs diff --git a/app/assets/javascripts/flash.js.coffee b/app/assets/javascripts/flash.js.coffee index 4f73d215b8..b76d214790 100644 --- a/app/assets/javascripts/flash.js.coffee +++ b/app/assets/javascripts/flash.js.coffee @@ -4,11 +4,19 @@ class @Flash @flash.html("") innerDiv = $('

', - class: "flash-#{type}", - text: message + class: "flash-#{type}" ) innerDiv.appendTo(".flash-container") + textDiv = $("
", + class: "flash-text", + text: message + ) + textDiv.appendTo(innerDiv) + + if @flash.parent().hasClass('content-wrapper') + textDiv.addClass('container-fluid container-limited') + @flash.click -> $(@).fadeOut() @flash.show() diff --git a/app/assets/stylesheets/framework/flash.scss b/app/assets/stylesheets/framework/flash.scss index 1bfd021399..a951a2b97f 100644 --- a/app/assets/stylesheets/framework/flash.scss +++ b/app/assets/stylesheets/framework/flash.scss @@ -16,4 +16,11 @@ @extend .alert-danger; margin: 0; } + + .flash-notice, .flash-alert { + .container-fluid.flash-text { + background: transparent; + } + } } + From 0601ce1871b16d212a938e684f4d9413e62c3f0b Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Mon, 20 Jun 2016 21:50:19 +0200 Subject: [PATCH 27/98] Avoid instantiation of a Git::Tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only needed when the project view is ‘Files view’ --- CHANGELOG | 1 + app/controllers/projects_controller.rb | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index c27ad4a467..7a92f9f52d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,7 @@ v 8.10.0 (unreleased) - Fix user creation with stronger minimum password requirements !4054 (nathan-pmt) - PipelinesFinder uses git cache data - Check for conflicts with existing Project's wiki path when creating a new project. + - Don't instantiate a git tree on Projects show default view - Remove unused front-end variable -> default_issues_tracker - Add API endpoint for a group issues !4520 (mahcsig) - Add Bugzilla integration !4930 (iamtjg) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 2b1f50fd01..12e0d5a841 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -4,7 +4,8 @@ class ProjectsController < Projects::ApplicationController before_action :authenticate_user!, except: [:show, :activity, :refs] before_action :project, except: [:new, :create] before_action :repository, except: [:new, :create] - before_action :assign_ref_vars, :tree, only: [:show], if: :repo_exists? + before_action :assign_ref_vars, only: [:show], if: :repo_exists? + before_action :tree, only: [:show], if: :project_view_files? # Authorize before_action :authorize_admin_project!, only: [:edit, :update, :housekeeping, :download_export, :export, :remove_export, :generate_new_export] @@ -303,6 +304,10 @@ class ProjectsController < Projects::ApplicationController project.repository_exists? && !project.empty_repo? end + def project_view_files? + current_user && current_user.project_view == 'files' + end + # Override extract_ref from ExtractsPath, which returns the branch and file path # for the blob/tree, which in this case is just the root of the default branch. # This way we avoid to access the repository.ref_names. From 98238a27c7b0e5d4c7a674a78c859150966e6f8b Mon Sep 17 00:00:00 2001 From: Josh Frye Date: Tue, 28 Jun 2016 22:30:01 -0400 Subject: [PATCH 28/98] Loop all disks when displaying system info --- Gemfile | 1 + Gemfile.lock | 3 +++ .../admin/system_info_controller.rb | 25 ++++++++++++++++--- app/views/admin/system_info/show.html.haml | 7 ++++-- config/dependency_decisions.yml | 6 +++++ spec/features/admin/admin_system_info_spec.rb | 2 +- 6 files changed, 38 insertions(+), 6 deletions(-) diff --git a/Gemfile b/Gemfile index a238677099..4f7d7cf708 100644 --- a/Gemfile +++ b/Gemfile @@ -349,3 +349,4 @@ gem 'health_check', '~> 1.5.1' # System information gem 'vmstat', '~> 2.1.0' +gem 'sys-filesystem', '~> 1.1.6' diff --git a/Gemfile.lock b/Gemfile.lock index c1d2f1fdf5..48465331a6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -716,6 +716,8 @@ GEM activerecord (>= 4.1, < 5.1) state_machines-activemodel (>= 0.3.0) stringex (2.5.2) + sys-filesystem (1.1.6) + ffi systemu (2.6.5) task_list (1.0.2) html-pipeline @@ -970,6 +972,7 @@ DEPENDENCIES spring-commands-teaspoon (~> 0.0.2) sprockets (~> 3.6.0) state_machines-activerecord (~> 0.4.0) + sys-filesystem (~> 1.1.6) task_list (~> 1.0.2) teaspoon (~> 1.1.0) teaspoon-jasmine (~> 2.2.0) diff --git a/app/controllers/admin/system_info_controller.rb b/app/controllers/admin/system_info_controller.rb index 3c67370b66..cc63009cdc 100644 --- a/app/controllers/admin/system_info_controller.rb +++ b/app/controllers/admin/system_info_controller.rb @@ -1,13 +1,32 @@ class Admin::SystemInfoController < Admin::ApplicationController def show + excluded_mounts = [ + "nobrowse", + "read-only", + "ro" + ] + system_info = Vmstat.snapshot + mounts = Sys::Filesystem.mounts + + @disks = [] + mounts.each do |mount| + options = mount.options.split(', ') + + next unless excluded_mounts.each { |em| break if options.include?(em) } + + disk = Sys::Filesystem.stat(mount.mount_point) + @disks.push({ + bytes_total: disk.bytes_total, + bytes_used: disk.bytes_used, + disk_name: mount.name, + mount_path: disk.path + }) + end @cpus = system_info.cpus.length @mem_used = system_info.memory.active_bytes @mem_total = system_info.memory.total_bytes - - @disk_used = system_info.disks[0].used_bytes - @disk_total = system_info.disks[0].total_bytes end end diff --git a/app/views/admin/system_info/show.html.haml b/app/views/admin/system_info/show.html.haml index 3ef2f20b58..1bf0ac1ff7 100644 --- a/app/views/admin/system_info/show.html.haml +++ b/app/views/admin/system_info/show.html.haml @@ -17,6 +17,9 @@ %h1= "#{number_to_human_size(@mem_used)} / #{number_to_human_size(@mem_total)}" .col-sm-4 .light-well - %h4 Disk + %h4 Disks .data - %h1= "#{number_to_human_size(@disk_used)} / #{number_to_human_size(@disk_total)}" + - @disks.each do |disk| + %h1= "#{number_to_human_size(disk[:bytes_used])} / #{number_to_human_size(disk[:bytes_total])}" + %p= "#{disk[:disk_name]}" + %p= "#{disk[:mount_path]}" diff --git a/config/dependency_decisions.yml b/config/dependency_decisions.yml index 436a2c5e17..293f2b71d6 100644 --- a/config/dependency_decisions.yml +++ b/config/dependency_decisions.yml @@ -181,3 +181,9 @@ :why: Equivalent to LGPLv2 :versions: [] :when: 2016-06-07 17:14:10.907682000 Z +- - :whitelist + - Artistic 2.0 + - :who: Josh Frye + :why: Disk/mount information display on Admin pages + :versions: [] + :when: 2016-06-29 16:32:45.432113000 Z diff --git a/spec/features/admin/admin_system_info_spec.rb b/spec/features/admin/admin_system_info_spec.rb index dbc1d829b6..f4e5c26b51 100644 --- a/spec/features/admin/admin_system_info_spec.rb +++ b/spec/features/admin/admin_system_info_spec.rb @@ -11,7 +11,7 @@ describe 'Admin System Info' do expect(page).to have_content 'CPU' expect(page).to have_content 'Memory' - expect(page).to have_content 'Disk' + expect(page).to have_content 'Disks' end end end From 20688cdf0711f0d7d70abdf01db5a4f3a0671c6c Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 29 Jun 2016 06:11:42 -0700 Subject: [PATCH 29/98] Be explicit which project and user ID are memoized --- app/helpers/notes_helper.rb | 10 ++++++---- spec/helpers/notes_helper_spec.rb | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 80d588aaf5..e85ba76887 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -71,10 +71,12 @@ module NotesHelper end def note_max_access_for_user(note) - user_id = note.author.id - project = note.project - @max_access_by_user_id ||= Hash.new { |hash, key| hash[key] = project.team.human_max_access(key) } + @max_access_by_user_id ||= Hash.new do |hash, key| + project = key[:project] + hash[key] = project.team.human_max_access(key[:user_id]) + end - @max_access_by_user_id[user_id] + full_key = { project: note.project, user_id: note.author_id } + @max_access_by_user_id[full_key] end end diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb index 8325af0dcf..08a9350325 100644 --- a/spec/helpers/notes_helper_spec.rb +++ b/spec/helpers/notes_helper_spec.rb @@ -22,11 +22,25 @@ describe NotesHelper do end it 'return human access levels' do + original_method = project.team.method(:human_max_access) + expect_any_instance_of(ProjectTeam).to receive(:human_max_access).exactly(3).times do |*args| + original_method.call(args[1]) + end + expect(helper.note_max_access_for_user(owner_note)).to eq('Owner') expect(helper.note_max_access_for_user(master_note)).to eq('Master') expect(helper.note_max_access_for_user(reporter_note)).to eq('Reporter') # Call it again to ensure value is cached expect(helper.note_max_access_for_user(owner_note)).to eq('Owner') end + + it 'handles access in different projects' do + second_project = create(:empty_project) + second_project.team << [master, :reporter] + other_note = create(:note, author: master, project: second_project) + + expect(helper.note_max_access_for_user(master_note)).to eq('Master') + expect(helper.note_max_access_for_user(other_note)).to eq('Reporter') + end end end From c600cf83488398cf66b10af85ed9490fe9457bd4 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sat, 25 Jun 2016 23:29:28 -0700 Subject: [PATCH 30/98] Fix database migrations when Redis is not running If Redis were not running or USE_DB were set to false, the application settings retrieval would fail completely. This change only attempts to use the cache if the system actually wants to connect to the DB and rescues any failures in talking to Redis. Closes #17557 --- lib/gitlab/current_settings.rb | 10 +++++--- spec/lib/gitlab/current_settings_spec.rb | 29 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 spec/lib/gitlab/current_settings_spec.rb diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index 28c34429c1..67d6be3515 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -9,10 +9,14 @@ module Gitlab end def ensure_application_settings! - settings = ::ApplicationSetting.cached + if connect_to_db? + begin + settings = ::ApplicationSetting.cached + # In case Redis isn't running or the Redis UNIX socket file is not available + rescue ::Redis::BaseError, ::Errno::ENOENT + settings = ::ApplicationSetting.last + end - if !settings && connect_to_db? - settings = ::ApplicationSetting.current settings ||= ::ApplicationSetting.create_from_defaults unless ActiveRecord::Migrator.needs_migration? end diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb new file mode 100644 index 0000000000..f2d2f7b5d3 --- /dev/null +++ b/spec/lib/gitlab/current_settings_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +describe Gitlab::CurrentSettings do + describe '#current_application_settings' do + it 'attempts to use cached values first' do + allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(true) + expect(ApplicationSetting).to receive(:cached).and_call_original + expect(ApplicationSetting).not_to receive(:last) + + expect(current_application_settings).to be_a(ApplicationSetting) + end + + it 'does not attempt to connect to DB or Redis' do + allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(false) + expect(ApplicationSetting).not_to receive(:current) + expect(ApplicationSetting).not_to receive(:last) + + expect(current_application_settings).to eq fake_application_settings + end + + it 'falls back to DB if Redis fails' do + allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(true) + expect(ApplicationSetting).to receive(:cached).and_raise(::Redis::BaseError) + expect(ApplicationSetting).to receive(:last).and_call_original + + expect(current_application_settings).to be_a(ApplicationSetting) + end + end +end From d10642a4b86d91faf7a3ffa508b4e8067213b14c Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 29 Jun 2016 14:28:41 -0700 Subject: [PATCH 31/98] Handle case when Redis cache returns an empty setting --- lib/gitlab/current_settings.rb | 2 +- spec/lib/gitlab/current_settings_spec.rb | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index 67d6be3515..54b46e5d23 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -11,7 +11,7 @@ module Gitlab def ensure_application_settings! if connect_to_db? begin - settings = ::ApplicationSetting.cached + settings = ::ApplicationSetting.current # In case Redis isn't running or the Redis UNIX socket file is not available rescue ::Redis::BaseError, ::Errno::ENOENT settings = ::ApplicationSetting.last diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb index f2d2f7b5d3..004341ffd0 100644 --- a/spec/lib/gitlab/current_settings_spec.rb +++ b/spec/lib/gitlab/current_settings_spec.rb @@ -4,7 +4,7 @@ describe Gitlab::CurrentSettings do describe '#current_application_settings' do it 'attempts to use cached values first' do allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(true) - expect(ApplicationSetting).to receive(:cached).and_call_original + expect(ApplicationSetting).to receive(:current).and_return(::ApplicationSetting.create_from_defaults) expect(ApplicationSetting).not_to receive(:last) expect(current_application_settings).to be_a(ApplicationSetting) @@ -18,9 +18,16 @@ describe Gitlab::CurrentSettings do expect(current_application_settings).to eq fake_application_settings end + it 'falls back to DB if Redis returns an empty value' do + allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(true) + expect(ApplicationSetting).to receive(:last).and_call_original + + expect(current_application_settings).to be_a(ApplicationSetting) + end + it 'falls back to DB if Redis fails' do allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(true) - expect(ApplicationSetting).to receive(:cached).and_raise(::Redis::BaseError) + expect(ApplicationSetting).to receive(:current).and_raise(::Redis::BaseError) expect(ApplicationSetting).to receive(:last).and_call_original expect(current_application_settings).to be_a(ApplicationSetting) From 6c9f5a50e99d60b37512a584d3888f5737675921 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Thu, 23 Jun 2016 18:36:30 -0500 Subject: [PATCH 32/98] Skip element that is wrapped by a link This fixes the double request being made to the same URL --- app/assets/javascripts/tree.js.coffee | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/tree.js.coffee b/app/assets/javascripts/tree.js.coffee index de8eebcd0b..f51cb47b6c 100644 --- a/app/assets/javascripts/tree.js.coffee +++ b/app/assets/javascripts/tree.js.coffee @@ -5,7 +5,9 @@ class @TreeView # Code browser tree slider # Make the entire tree-item row clickable, but not if clicking another link (like a commit message) $(".tree-content-holder .tree-item").on 'click', (e) -> - if (e.target.nodeName != "A") + $clickedEl = $(e.target) + + if not $clickedEl.is('a') and not $clickedEl.is('.str-truncated') path = $('.tree-item-file-name a', this).attr('href') Turbolinks.visit(path) From 6a626a465c3f9157d2f40b371f141982ebc91caa Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Mon, 27 Jun 2016 11:34:25 -0500 Subject: [PATCH 33/98] Fixes opening files on a new tab with meta key + click or using mouse middle button --- app/assets/javascripts/tree.js.coffee | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/tree.js.coffee b/app/assets/javascripts/tree.js.coffee index f51cb47b6c..83de584f2d 100644 --- a/app/assets/javascripts/tree.js.coffee +++ b/app/assets/javascripts/tree.js.coffee @@ -6,10 +6,14 @@ class @TreeView # Make the entire tree-item row clickable, but not if clicking another link (like a commit message) $(".tree-content-holder .tree-item").on 'click', (e) -> $clickedEl = $(e.target) + path = $('.tree-item-file-name a', this).attr('href') if not $clickedEl.is('a') and not $clickedEl.is('.str-truncated') - path = $('.tree-item-file-name a', this).attr('href') - Turbolinks.visit(path) + if e.metaKey or e.which is 2 + e.preventDefault() + window.open path, '_blank' + else + Turbolinks.visit path # Show the "Loading commit data" for only the first element $('span.log_loading:first').removeClass('hide') From d17046dbbc0c1212ab61cf1a9e1ea3aca54c9b72 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Mon, 27 Jun 2016 11:48:02 -0500 Subject: [PATCH 34/98] Update CHANGELOG --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 775ea60681..1301a5b5f0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -23,6 +23,9 @@ v 8.10.0 (unreleased) - Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w) - Add basic system information like memory and disk usage to the admin panel +v 8.9.4 (unreleased) + - Fixes middle click and double request when navigating through the file browser !4891 + v 8.9.3 - Fix encrypted data backwards compatibility after upgrading attr_encrypted gem. !4963 - Fix rendering of commit notes. !4953 From 8cdee2bab24bb909fc103bc9d4eab51c73090101 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Tue, 28 Jun 2016 20:10:06 +0100 Subject: [PATCH 35/98] Exposed 'onToggleHelp() to window object so showHelp() can be a global function' Removed from window and used static method --- app/assets/javascripts/shortcuts.js.coffee | 6 +++--- app/views/help/index.html.haml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/shortcuts.js.coffee b/app/assets/javascripts/shortcuts.js.coffee index c03877e9b0..3319a67a79 100644 --- a/app/assets/javascripts/shortcuts.js.coffee +++ b/app/assets/javascripts/shortcuts.js.coffee @@ -9,12 +9,12 @@ class @Shortcuts onToggleHelp: (e) => e.preventDefault() - @toggleHelp(@enabledHelp) + Shortcuts.toggleHelp(@enabledHelp) - toggleMarkdownPreview: (e) => + toggleMarkdownPreview: (e) -> $(document).triggerHandler('markdown-preview:toggle', [e]) - toggleHelp: (location) -> + @toggleHelp: (location) -> $modal = $('#modal-shortcuts') if $modal.length diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index 57bc91ea5a..57601ae9be 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -36,6 +36,6 @@ %ul.well-list %li= link_to 'See our website for getting help', promo_url + '/getting-help/' %li= link_to 'Use the search bar on the top of this page', '#', onclick: 'Shortcuts.focusSearch(event)' - %li= link_to 'Use shortcuts', '#', onclick: 'Shortcuts.showHelp(event)' + %li= link_to 'Use shortcuts', '#', onclick: 'Shortcuts.toggleHelp()' %li= link_to 'Get a support subscription', 'https://about.gitlab.com/pricing/' %li= link_to 'Compare GitLab editions', 'https://about.gitlab.com/features/#compare' From 86359ec854314574dccea75247f45590262b05c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Wed, 22 Jun 2016 17:04:51 -0400 Subject: [PATCH 36/98] Refactor repository paths handling to allow multiple git mount points --- CHANGELOG | 1 + GITLAB_SHELL_VERSION | 2 +- app/helpers/projects_helper.rb | 4 +- app/models/namespace.rb | 93 ++++++---- app/models/project.rb | 20 ++- app/models/project_wiki.rb | 4 +- app/models/repository.rb | 2 +- app/services/projects/destroy_service.rb | 6 +- app/services/projects/housekeeping_service.rb | 2 +- app/services/projects/import_service.rb | 2 +- app/services/projects/transfer_service.rb | 4 +- app/views/projects/imports/new.html.haml | 2 +- app/workers/post_receive.rb | 6 +- app/workers/repository_fork_worker.rb | 2 +- config/gitlab.teatro.yml | 6 +- config/gitlab.yml.example | 14 +- config/initializers/1_settings.rb | 9 +- config/initializers/6_validations.rb | 24 +++ ...5742_add_repository_storage_to_projects.rb | 12 ++ db/schema.rb | 27 +-- doc/README.md | 1 + doc/administration/repository_storages.md | 18 ++ doc/raketasks/import.md | 3 +- lib/api/internal.rb | 36 ++-- lib/backup/repository.rb | 26 +-- lib/gitlab/backend/shell.rb | 81 ++++----- lib/gitlab/github_import/importer.rb | 2 +- lib/tasks/gitlab/check.rake | 167 ++++++++++-------- lib/tasks/gitlab/cleanup.rake | 71 ++++---- lib/tasks/gitlab/import.rake | 104 +++++------ lib/tasks/gitlab/info.rake | 5 +- lib/tasks/gitlab/list_repos.rake | 2 +- lib/tasks/gitlab/shell.rake | 10 +- lib/tasks/gitlab/task_helpers.rake | 12 +- spec/helpers/projects_helper_spec.rb | 10 +- spec/initializers/6_validations_spec.rb | 41 +++++ spec/lib/gitlab/backend/shell_spec.rb | 5 + spec/models/namespace_spec.rb | 10 +- spec/models/project_spec.rb | 41 ++++- spec/requests/api/internal_spec.rb | 2 + spec/services/destroy_group_service_spec.rb | 8 +- .../projects/housekeeping_service_spec.rb | 2 +- spec/services/projects/import_service_spec.rb | 12 +- spec/support/test_env.rb | 11 +- spec/tasks/gitlab/backup_rake_spec.rb | 142 +++++++++------ spec/workers/post_receive_spec.rb | 2 +- spec/workers/repository_fork_worker_spec.rb | 9 +- 47 files changed, 675 insertions(+), 400 deletions(-) create mode 100644 config/initializers/6_validations.rb create mode 100644 db/migrate/20160608195742_add_repository_storage_to_projects.rb create mode 100644 doc/administration/repository_storages.md create mode 100644 spec/initializers/6_validations_spec.rb diff --git a/CHANGELOG b/CHANGELOG index 764df7cf55..6b23ce2b27 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.10.0 (unreleased) - Fix commit builds API, return all builds for all pipelines for given commit. !4849 - Replace Haml with Hamlit to make view rendering faster. !3666 + - Refactor repository paths handling to allow multiple git mount points - Wrap code blocks on Activies and Todos page. !4783 (winniehell) - Align flash messages with left side of page content !4959 (winniehell) - Display last commit of deleted branch in push events !4699 (winniehell) diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index 4a36342fca..fd2a01863f 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -3.0.0 +3.1.0 diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 26796b08fa..f312a7ccca 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -327,9 +327,9 @@ module ProjectsHelper end end - def sanitize_repo_path(message) + def sanitize_repo_path(project, message) return '' unless message.present? - message.strip.gsub(Gitlab.config.gitlab_shell.repos_path.chomp('/'), "[REPOS PATH]") + message.strip.gsub(project.repository_storage_path.chomp('/'), "[REPOS PATH]") end end diff --git a/app/models/namespace.rb b/app/models/namespace.rb index da19462f26..8b52cc824c 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -21,8 +21,10 @@ class Namespace < ActiveRecord::Base delegate :name, to: :owner, allow_nil: true, prefix: true - after_create :ensure_dir_exist after_update :move_dir, if: :path_changed? + + # Save the storage paths before the projects are destroyed to use them on after destroy + before_destroy(prepend: true) { @old_repository_storage_paths = repository_storage_paths } after_destroy :rm_dir scope :root, -> { where('type IS NULL') } @@ -87,51 +89,35 @@ class Namespace < ActiveRecord::Base owner_name end - def ensure_dir_exist - gitlab_shell.add_namespace(path) - end - - def rm_dir - # Move namespace directory into trash. - # We will remove it later async - new_path = "#{path}+#{id}+deleted" - - if gitlab_shell.mv_namespace(path, new_path) - message = "Namespace directory \"#{path}\" moved to \"#{new_path}\"" - Gitlab::AppLogger.info message - - # Remove namespace directroy async with delay so - # GitLab has time to remove all projects first - GitlabShellWorker.perform_in(5.minutes, :rm_namespace, new_path) - end - end - def move_dir - # Ensure old directory exists before moving it - gitlab_shell.add_namespace(path_was) - if any_project_has_container_registry_tags? raise Exception.new('Namespace cannot be moved, because at least one project has tags in container registry') end - if gitlab_shell.mv_namespace(path_was, path) - Gitlab::UploadsTransfer.new.rename_namespace(path_was, path) + # Move the namespace directory in all storages paths used by member projects + repository_storage_paths.each do |repository_storage_path| + # Ensure old directory exists before moving it + gitlab_shell.add_namespace(repository_storage_path, path_was) - # If repositories moved successfully we need to - # send update instructions to users. - # However we cannot allow rollback since we moved namespace dir - # So we basically we mute exceptions in next actions - begin - send_update_instructions - rescue - # Returning false does not rollback after_* transaction but gives - # us information about failing some of tasks - false + unless gitlab_shell.mv_namespace(repository_storage_path, path_was, path) + # if we cannot move namespace directory we should rollback + # db changes in order to prevent out of sync between db and fs + raise Exception.new('namespace directory cannot be moved') end - else - # if we cannot move namespace directory we should rollback - # db changes in order to prevent out of sync between db and fs - raise Exception.new('namespace directory cannot be moved') + end + + Gitlab::UploadsTransfer.new.rename_namespace(path_was, path) + + # If repositories moved successfully we need to + # send update instructions to users. + # However we cannot allow rollback since we moved namespace dir + # So we basically we mute exceptions in next actions + begin + send_update_instructions + rescue + # Returning false does not rollback after_* transaction but gives + # us information about failing some of tasks + false end end @@ -152,4 +138,33 @@ class Namespace < ActiveRecord::Base def find_fork_of(project) projects.joins(:forked_project_link).find_by('forked_project_links.forked_from_project_id = ?', project.id) end + + private + + def repository_storage_paths + # We need to get the storage paths for all the projects, even the ones that are + # pending delete. Unscoping also get rids of the default order, which causes + # problems with SELECT DISTINCT. + Project.unscoped do + projects.select('distinct(repository_storage)').to_a.map(&:repository_storage_path) + end + end + + def rm_dir + # Remove the namespace directory in all storages paths used by member projects + @old_repository_storage_paths.each do |repository_storage_path| + # Move namespace directory into trash. + # We will remove it later async + new_path = "#{path}+#{id}+deleted" + + if gitlab_shell.mv_namespace(repository_storage_path, path, new_path) + message = "Namespace directory \"#{path}\" moved to \"#{new_path}\"" + Gitlab::AppLogger.info message + + # Remove namespace directroy async with delay so + # GitLab has time to remove all projects first + GitlabShellWorker.perform_in(5.minutes, :rm_namespace, repository_storage_path, new_path) + end + end + end end diff --git a/app/models/project.rb b/app/models/project.rb index 73ded09c16..2f6901e0e3 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -26,6 +26,9 @@ class Project < ActiveRecord::Base default_value_for :container_registry_enabled, gitlab_config_features.container_registry default_value_for(:shared_runners_enabled) { current_application_settings.shared_runners_enabled } + after_create :ensure_dir_exist + after_save :ensure_dir_exist, if: :namespace_id_changed? + # set last_activity_at to the same as created_at after_create :set_last_activity_at def set_last_activity_at @@ -165,6 +168,9 @@ class Project < ActiveRecord::Base validate :visibility_level_allowed_by_group validate :visibility_level_allowed_as_fork validate :check_wiki_path_conflict + validates :repository_storage, + presence: true, + inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } } add_authentication_token_field :runners_token before_save :ensure_runners_token @@ -376,6 +382,10 @@ class Project < ActiveRecord::Base end end + def repository_storage_path + Gitlab.config.repositories.storages[repository_storage] + end + def team @team ||= ProjectTeam.new(self) end @@ -842,12 +852,12 @@ class Project < ActiveRecord::Base raise Exception.new('Project cannot be renamed, because tags are present in its container registry') end - if gitlab_shell.mv_repository(old_path_with_namespace, new_path_with_namespace) + if gitlab_shell.mv_repository(repository_storage_path, old_path_with_namespace, new_path_with_namespace) # If repository moved successfully we need to send update instructions to users. # However we cannot allow rollback since we moved repository # So we basically we mute exceptions in next actions begin - gitlab_shell.mv_repository("#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki") + gitlab_shell.mv_repository(repository_storage_path, "#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki") send_move_instructions(old_path_with_namespace) reset_events_cache @@ -988,7 +998,7 @@ class Project < ActiveRecord::Base def create_repository # Forked import is handled asynchronously unless forked? - if gitlab_shell.add_repository(path_with_namespace) + if gitlab_shell.add_repository(repository_storage_path, path_with_namespace) repository.after_create true else @@ -1140,4 +1150,8 @@ class Project < ActiveRecord::Base _, status = Gitlab::Popen.popen(%W(find #{export_path} -not -path #{export_path} -delete)) status.zero? end + + def ensure_dir_exist + gitlab_shell.add_namespace(repository_storage_path, namespace.path) + end end diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb index 25d82929c0..a255710f57 100644 --- a/app/models/project_wiki.rb +++ b/app/models/project_wiki.rb @@ -159,7 +159,7 @@ class ProjectWiki private def init_repo(path_with_namespace) - gitlab_shell.add_repository(path_with_namespace) + gitlab_shell.add_repository(project.repository_storage_path, path_with_namespace) end def commit_details(action, message = nil, title = nil) @@ -173,7 +173,7 @@ class ProjectWiki end def path_to_repo - @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git") + @path_to_repo ||= File.join(project.repository_storage_path, "#{path_with_namespace}.git") end def update_project_activity diff --git a/app/models/repository.rb b/app/models/repository.rb index 2a6a3b086c..f45c3d06ab 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -39,7 +39,7 @@ class Repository # Return absolute path to repository def path_to_repo @path_to_repo ||= File.expand_path( - File.join(Gitlab.config.gitlab_shell.repos_path, path_with_namespace + ".git") + File.join(@project.repository_storage_path, path_with_namespace + ".git") ) end diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index f09072975c..882606e38d 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -51,13 +51,13 @@ module Projects return true if params[:skip_repo] == true # There is a possibility project does not have repository or wiki - return true unless gitlab_shell.exists?(path + '.git') + return true unless gitlab_shell.exists?(project.repository_storage_path, path + '.git') new_path = removal_path(path) - if gitlab_shell.mv_repository(path, new_path) + if gitlab_shell.mv_repository(project.repository_storage_path, path, new_path) log_info("Repository \"#{path}\" moved to \"#{new_path}\"") - GitlabShellWorker.perform_in(5.minutes, :remove_repository, new_path) + GitlabShellWorker.perform_in(5.minutes, :remove_repository, project.repository_storage_path, new_path) else false end diff --git a/app/services/projects/housekeeping_service.rb b/app/services/projects/housekeeping_service.rb index 43db29315a..a47df22f1b 100644 --- a/app/services/projects/housekeeping_service.rb +++ b/app/services/projects/housekeeping_service.rb @@ -24,7 +24,7 @@ module Projects def execute raise LeaseTaken unless try_obtain_lease - GitlabShellOneShotWorker.perform_async(:gc, @project.path_with_namespace) + GitlabShellOneShotWorker.perform_async(:gc, @project.repository_storage_path, @project.path_with_namespace) ensure Gitlab::Metrics.measure(:reset_pushes_since_gc) do @project.update_column(:pushes_since_gc, 0) diff --git a/app/services/projects/import_service.rb b/app/services/projects/import_service.rb index 9159ec0895..163ebf26c8 100644 --- a/app/services/projects/import_service.rb +++ b/app/services/projects/import_service.rb @@ -42,7 +42,7 @@ module Projects def import_repository begin - gitlab_shell.import_repository(project.path_with_namespace, project.import_url) + gitlab_shell.import_repository(project.repository_storage_path, project.path_with_namespace, project.import_url) rescue Gitlab::Shell::Error => e raise Error, "Error importing repository #{project.import_url} into #{project.path_with_namespace} - #{e.message}" end diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 03b57dea51..bc7f8bf433 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -50,12 +50,12 @@ module Projects project.send_move_instructions(old_path) # Move main repository - unless gitlab_shell.mv_repository(old_path, new_path) + unless gitlab_shell.mv_repository(project.repository_storage_path, old_path, new_path) raise TransferError.new('Cannot move project') end # Move wiki repo also if present - gitlab_shell.mv_repository("#{old_path}.wiki", "#{new_path}.wiki") + gitlab_shell.mv_repository(project.repository_storage_path, "#{old_path}.wiki", "#{new_path}.wiki") # clear project cached events project.reset_events_cache diff --git a/app/views/projects/imports/new.html.haml b/app/views/projects/imports/new.html.haml index a8a8caf728..2cd8d03e30 100644 --- a/app/views/projects/imports/new.html.haml +++ b/app/views/projects/imports/new.html.haml @@ -10,7 +10,7 @@ .panel-body %pre :preserve - #{sanitize_repo_path(@project.import_error)} + #{sanitize_repo_path(@project, @project.import_error)} = form_for @project, url: namespace_project_import_path(@project.namespace, @project), method: :post, html: { class: 'form-horizontal' } do |f| = render "shared/import_form", f: f diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index f3327ca9e6..09035a7cf2 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -4,10 +4,10 @@ class PostReceive sidekiq_options queue: :post_receive def perform(repo_path, identifier, changes) - if repo_path.start_with?(Gitlab.config.gitlab_shell.repos_path.to_s) - repo_path.gsub!(Gitlab.config.gitlab_shell.repos_path.to_s, "") + if path = Gitlab.config.repositories.storages.find { |p| repo_path.start_with?(p[1].to_s) } + repo_path.gsub!(path[1].to_s, "") else - log("Check gitlab.yml config for correct gitlab_shell.repos_path variable. \"#{Gitlab.config.gitlab_shell.repos_path}\" does not match \"#{repo_path}\"") + log("Check gitlab.yml config for correct repositories.storages values. No repository storage path matches \"#{repo_path}\"") end post_received = Gitlab::GitPostReceive.new(repo_path, identifier, changes) diff --git a/app/workers/repository_fork_worker.rb b/app/workers/repository_fork_worker.rb index d947f10551..f7604e48f8 100644 --- a/app/workers/repository_fork_worker.rb +++ b/app/workers/repository_fork_worker.rb @@ -12,7 +12,7 @@ class RepositoryForkWorker return end - result = gitlab_shell.fork_repository(source_path, target_path) + result = gitlab_shell.fork_repository(project.repository_storage_path, source_path, target_path) unless result logger.error("Unable to fork project #{project_id} for repository #{source_path} -> #{target_path}") project.mark_import_as_failed('The project could not be forked.') diff --git a/config/gitlab.teatro.yml b/config/gitlab.teatro.yml index 01c8dc5ff9..75b79b837e 100644 --- a/config/gitlab.teatro.yml +++ b/config/gitlab.teatro.yml @@ -47,11 +47,13 @@ production: &base backup: path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/) + repositories: + storages: # REPO PATHS MUST NOT BE A SYMLINK!!! + default: /apps/repositories/ + gitlab_shell: path: /apps/gitlab-shell/ - # REPOS_PATH MUST NOT BE A SYMLINK!!! - repos_path: /apps/repositories/ hooks_path: /apps/gitlab-shell/hooks/ upload_pack: true diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 75e1a3c109..325eca7286 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -428,6 +428,13 @@ production: &base satellites: path: /home/git/gitlab-satellites/ + ## Repositories settings + repositories: + # Paths where repositories can be stored. Give the canonicalized absolute pathname. + # NOTE: REPOS PATHS MUST NOT CONTAIN ANY SYMLINK!!! + storages: # You must have at least a `default` storage path. + default: /home/git/repositories/ + ## Backup settings backup: path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/) @@ -452,9 +459,6 @@ production: &base ## GitLab Shell settings gitlab_shell: path: /home/git/gitlab-shell/ - - # REPOS_PATH MUST NOT BE A SYMLINK!!! - repos_path: /home/git/repositories/ hooks_path: /home/git/gitlab-shell/hooks/ # File that contains the secret key for verifying access for gitlab-shell. @@ -528,11 +532,13 @@ test: # user: YOUR_USERNAME satellites: path: tmp/tests/gitlab-satellites/ + repositories: + storages: + default: tmp/tests/repositories/ backup: path: tmp/tests/backups gitlab_shell: path: tmp/tests/gitlab-shell/ - repos_path: tmp/tests/repositories/ hooks_path: tmp/tests/gitlab-shell/hooks/ issues_tracker: redmine: diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index c6dc1e4ab3..a93996cec7 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -304,13 +304,20 @@ Settings.gitlab_shell['hooks_path'] ||= Settings.gitlab['user_home'] + '/gitla Settings.gitlab_shell['secret_file'] ||= Rails.root.join('.gitlab_shell_secret') Settings.gitlab_shell['receive_pack'] = true if Settings.gitlab_shell['receive_pack'].nil? Settings.gitlab_shell['upload_pack'] = true if Settings.gitlab_shell['upload_pack'].nil? -Settings.gitlab_shell['repos_path'] ||= Settings.gitlab['user_home'] + '/repositories/' Settings.gitlab_shell['ssh_host'] ||= Settings.gitlab.ssh_host Settings.gitlab_shell['ssh_port'] ||= 22 Settings.gitlab_shell['ssh_user'] ||= Settings.gitlab.user Settings.gitlab_shell['owner_group'] ||= Settings.gitlab.user Settings.gitlab_shell['ssh_path_prefix'] ||= Settings.send(:build_gitlab_shell_ssh_path_prefix) +# +# Repositories +# +Settings['repositories'] ||= Settingslogic.new({}) +Settings.repositories['storages'] ||= {} +# Setting gitlab_shell.repos_path is DEPRECATED and WILL BE REMOVED in version 9.0 +Settings.repositories.storages['default'] ||= Settings.gitlab_shell['repos_path'] || Settings.gitlab['user_home'] + '/repositories/' + # # Backup # diff --git a/config/initializers/6_validations.rb b/config/initializers/6_validations.rb new file mode 100644 index 0000000000..3ba9e36c56 --- /dev/null +++ b/config/initializers/6_validations.rb @@ -0,0 +1,24 @@ +def storage_name_valid?(name) + !!(name =~ /\A[a-zA-Z0-9\-_]+\z/) +end + +def find_parent_path(name, path) + Gitlab.config.repositories.storages.detect do |n, p| + name != n && path.chomp('/').start_with?(p.chomp('/')) + end +end + +def error(message) + raise "#{message}. Please fix this in your gitlab.yml before starting GitLab." +end + +error('No repository storage path defined') if Gitlab.config.repositories.storages.empty? + +Gitlab.config.repositories.storages.each do |name, path| + error("\"#{name}\" is not a valid storage name") unless storage_name_valid?(name) + + parent_name, _parent_path = find_parent_path(name, path) + if parent_name + error("#{name} is a nested path of #{parent_name}. Nested paths are not supported for repository storages") + end +end diff --git a/db/migrate/20160608195742_add_repository_storage_to_projects.rb b/db/migrate/20160608195742_add_repository_storage_to_projects.rb new file mode 100644 index 0000000000..c700d2b569 --- /dev/null +++ b/db/migrate/20160608195742_add_repository_storage_to_projects.rb @@ -0,0 +1,12 @@ +class AddRepositoryStorageToProjects < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + disable_ddl_transaction! + + def up + add_column_with_default(:projects, :repository_storage, :string, default: 'default') + end + + def down + remove_column(:projects, :repository_storage) + end +end diff --git a/db/schema.rb b/db/schema.rb index 7a8377f687..a7173116b1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -796,38 +796,39 @@ ActiveRecord::Schema.define(version: 20160620115026) do t.datetime "created_at" t.datetime "updated_at" t.integer "creator_id" - t.boolean "issues_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 "merge_requests_enabled", default: true, null: false + t.boolean "wiki_enabled", default: true, null: false t.integer "namespace_id" - t.boolean "snippets_enabled", default: true, null: false + t.boolean "snippets_enabled", default: true, null: false t.datetime "last_activity_at" t.string "import_url" - t.integer "visibility_level", default: 0, null: false - t.boolean "archived", default: false, null: false + 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.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 t.boolean "pending_delete", default: false - t.boolean "public_builds", default: true, null: false + t.boolean "public_builds", default: true, null: false t.integer "pushes_since_gc", default: 0 t.boolean "last_repository_check_failed" t.datetime "last_repository_check_at" t.boolean "container_registry_enabled" - t.boolean "only_allow_merge_if_build_succeeds", default: false, null: false + t.boolean "only_allow_merge_if_build_succeeds", default: false, null: false t.boolean "has_external_issue_tracker" + t.string "repository_storage", default: "default", null: false end add_index "projects", ["builds_enabled", "shared_runners_enabled"], name: "index_projects_on_builds_enabled_and_shared_runners_enabled", using: :btree diff --git a/doc/README.md b/doc/README.md index be0d17084c..b98d6812a8 100644 --- a/doc/README.md +++ b/doc/README.md @@ -34,6 +34,7 @@ - [Operations](operations/README.md) Keeping GitLab up and running. - [Raketasks](raketasks/README.md) Backups, maintenance, automatic webhook setup and the importing of projects. - [Repository checks](administration/repository_checks.md) Periodic Git repository checks. +- [Repository storages](administration/repository_storages.md) Manage the paths used to store repositories. - [Security](security/README.md) Learn what you can do to further secure your GitLab instance. - [System hooks](system_hooks/system_hooks.md) Notifications when users, projects and keys are changed. - [Update](update/README.md) Update guides to upgrade your installation. diff --git a/doc/administration/repository_storages.md b/doc/administration/repository_storages.md new file mode 100644 index 0000000000..81bfe17315 --- /dev/null +++ b/doc/administration/repository_storages.md @@ -0,0 +1,18 @@ +# Repository storages + +GitLab allows you to define repository storage paths to enable distribution of +storage load between several mount points. + +## For installations from source + +Add your repository storage paths in your `gitlab.yml` under repositories -> storages, using key -> value pairs. + +>**Notes:** +- You must have at least one storage path called `default`. +- In order for backups to work correctly the storage path must **not** be a +mount point and the GitLab user should have correct permissions for the parent +directory of the path. + +## For omnibus installations + +Follow the instructions at https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/configuration.md#storing-git-data-in-an-alternative-directory diff --git a/doc/raketasks/import.md b/doc/raketasks/import.md index 8a38937062..2b305cb5c9 100644 --- a/doc/raketasks/import.md +++ b/doc/raketasks/import.md @@ -14,7 +14,8 @@ - For omnibus-gitlab, it is located at: `/var/opt/gitlab/git-data/repositories` by default, unless you changed it in the `/etc/gitlab/gitlab.rb` file. - For installations from source, it is usually located at: `/home/git/repositories` or you can see where -your repositories are located by looking at `config/gitlab.yml` under the `gitlab_shell => repos_path` entry. +your repositories are located by looking at `config/gitlab.yml` under the `repositories => storages` entries +(you'll usually use the `default` storage path to start). New folder needs to have git user ownership and read/write/execute access for git user and its group: diff --git a/lib/api/internal.rb b/lib/api/internal.rb index 1d361569d5..b32503e851 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -20,6 +20,20 @@ module API @wiki ||= params[:project].end_with?('.wiki') && !Project.find_with_namespace(params[:project]) end + + def project + @project ||= begin + project_path = params[:project] + + # Check for *.wiki repositories. + # Strip out the .wiki from the pathname before finding the + # project. This applies the correct project permissions to + # the wiki repository as well. + project_path.chomp!('.wiki') if wiki? + + Project.find_with_namespace(project_path) + end + end end post "/allowed" do @@ -32,16 +46,6 @@ module API User.find_by(id: params[:user_id]) end - project_path = params[:project] - - # Check for *.wiki repositories. - # Strip out the .wiki from the pathname before finding the - # project. This applies the correct project permissions to - # the wiki repository as well. - project_path.chomp!('.wiki') if wiki? - - project = Project.find_with_namespace(project_path) - access = if wiki? Gitlab::GitAccessWiki.new(actor, project) @@ -49,7 +53,17 @@ module API Gitlab::GitAccess.new(actor, project) end - access.check(params[:action], params[:changes]) + access_status = access.check(params[:action], params[:changes]) + + response = { status: access_status.status, message: access_status.message } + + if access_status.status + # Return the repository full path so that gitlab-shell has it when + # handling ssh commands + response[:repository_path] = project.repository.path_to_repo + end + + response end # diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb index 7b91215d50..b9773f98d7 100644 --- a/lib/backup/repository.rb +++ b/lib/backup/repository.rb @@ -2,8 +2,6 @@ require 'yaml' module Backup class Repository - attr_reader :repos_path - def dump prepare @@ -50,10 +48,12 @@ module Backup end def restore - if File.exists?(repos_path) + Gitlab.config.repositories.storages.each do |name, path| + next unless File.exists?(path) + # Move repos dir to 'repositories.old' dir - bk_repos_path = File.join(repos_path, '..', 'repositories.old.' + Time.now.to_i.to_s) - FileUtils.mv(repos_path, bk_repos_path) + bk_repos_path = File.join(path, '..', 'repositories.old.' + Time.now.to_i.to_s) + FileUtils.mv(path, bk_repos_path) end FileUtils.mkdir_p(repos_path) @@ -61,7 +61,7 @@ module Backup Project.find_each(batch_size: 1000) do |project| $progress.print " * #{project.path_with_namespace} ... " - project.namespace.ensure_dir_exist if project.namespace + project.ensure_dir_exist if File.exists?(path_to_bundle(project)) FileUtils.mkdir_p(path_to_repo(project)) @@ -100,8 +100,8 @@ module Backup end $progress.print 'Put GitLab hooks in repositories dirs'.color(:yellow) - cmd = "#{Gitlab.config.gitlab_shell.path}/bin/create-hooks" - if system(cmd) + cmd = %W(#{Gitlab.config.gitlab_shell.path}/bin/create-hooks) + repository_storage_paths_args + if system(*cmd) $progress.puts " [DONE]".color(:green) else puts " [FAILED]".color(:red) @@ -120,10 +120,6 @@ module Backup File.join(backup_repos_path, project.path_with_namespace + ".bundle") end - def repos_path - Gitlab.config.gitlab_shell.repos_path - end - def backup_repos_path File.join(Gitlab.config.backup.path, "repositories") end @@ -139,5 +135,11 @@ module Backup def silent {err: '/dev/null', out: '/dev/null'} end + + private + + def repository_storage_paths_args + Gitlab.config.repositories.storages.values + end end end diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index 3e3986d638..e31840ef91 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -18,77 +18,82 @@ module Gitlab # Init new repository # + # storage - project's storage path # name - project path with namespace # # Ex. - # add_repository("gitlab/gitlab-ci") + # add_repository("/path/to/storage", "gitlab/gitlab-ci") # - def add_repository(name) + def add_repository(storage, name) Gitlab::Utils.system_silent([gitlab_shell_projects_path, - 'add-project', "#{name}.git"]) + 'add-project', storage, "#{name}.git"]) end # Import repository # + # storage - project's storage path # name - project path with namespace # # Ex. - # import_repository("gitlab/gitlab-ci", "https://github.com/randx/six.git") + # import_repository("/path/to/storage", "gitlab/gitlab-ci", "https://github.com/randx/six.git") # - def import_repository(name, url) - output, status = Popen::popen([gitlab_shell_projects_path, 'import-project', "#{name}.git", url, '900']) + def import_repository(storage, name, url) + output, status = Popen::popen([gitlab_shell_projects_path, 'import-project', + storage, "#{name}.git", url, '900']) raise Error, output unless status.zero? true end # Move repository - # + # storage - project's storage path # path - project path with namespace # new_path - new project path with namespace # # Ex. - # mv_repository("gitlab/gitlab-ci", "randx/gitlab-ci-new") + # mv_repository("/path/to/storage", "gitlab/gitlab-ci", "randx/gitlab-ci-new") # - def mv_repository(path, new_path) + def mv_repository(storage, path, new_path) Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'mv-project', - "#{path}.git", "#{new_path}.git"]) + storage, "#{path}.git", "#{new_path}.git"]) end # Fork repository to new namespace - # + # storage - project's storage path # path - project path with namespace # fork_namespace - namespace for forked project # # Ex. - # fork_repository("gitlab/gitlab-ci", "randx") + # fork_repository("/path/to/storage", "gitlab/gitlab-ci", "randx") # - def fork_repository(path, fork_namespace) + def fork_repository(storage, path, fork_namespace) Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'fork-project', - "#{path}.git", fork_namespace]) + storage, "#{path}.git", fork_namespace]) end # Remove repository from file system # + # storage - project's storage path # name - project path with namespace # # Ex. - # remove_repository("gitlab/gitlab-ci") + # remove_repository("/path/to/storage", "gitlab/gitlab-ci") # - def remove_repository(name) + def remove_repository(storage, name) Gitlab::Utils.system_silent([gitlab_shell_projects_path, - 'rm-project', "#{name}.git"]) + 'rm-project', storage, "#{name}.git"]) end # Gc repository # + # storage - project storage path # path - project path with namespace # # Ex. - # gc("gitlab/gitlab-ci") + # gc("/path/to/storage", "gitlab/gitlab-ci") # - def gc(path) + def gc(storage, path) Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'gc', - "#{path}.git"]) + storage, "#{path}.git"]) end # Add new key to gitlab-shell @@ -133,31 +138,31 @@ module Gitlab # Add empty directory for storing repositories # # Ex. - # add_namespace("gitlab") + # add_namespace("/path/to/storage", "gitlab") # - def add_namespace(name) - FileUtils.mkdir(full_path(name), mode: 0770) unless exists?(name) + def add_namespace(storage, name) + FileUtils.mkdir(full_path(storage, name), mode: 0770) unless exists?(storage, name) end # Remove directory from repositories storage # Every repository inside this directory will be removed too # # Ex. - # rm_namespace("gitlab") + # rm_namespace("/path/to/storage", "gitlab") # - def rm_namespace(name) - FileUtils.rm_r(full_path(name), force: true) + def rm_namespace(storage, name) + FileUtils.rm_r(full_path(storage, name), force: true) end # Move namespace directory inside repositories storage # # Ex. - # mv_namespace("gitlab", "gitlabhq") + # mv_namespace("/path/to/storage", "gitlab", "gitlabhq") # - def mv_namespace(old_name, new_name) - return false if exists?(new_name) || !exists?(old_name) + def mv_namespace(storage, old_name, new_name) + return false if exists?(storage, new_name) || !exists?(storage, old_name) - FileUtils.mv(full_path(old_name), full_path(new_name)) + FileUtils.mv(full_path(storage, old_name), full_path(storage, new_name)) end def url_to_repo(path) @@ -176,11 +181,11 @@ module Gitlab # Check if such directory exists in repositories. # # Usage: - # exists?('gitlab') - # exists?('gitlab/cookies.git') + # exists?(storage, 'gitlab') + # exists?(storage, 'gitlab/cookies.git') # - def exists?(dir_name) - File.exist?(full_path(dir_name)) + def exists?(storage, dir_name) + File.exist?(full_path(storage, dir_name)) end protected @@ -193,14 +198,10 @@ module Gitlab File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}") end - def repos_path - Gitlab.config.gitlab_shell.repos_path - end - - def full_path(dir_name) + def full_path(storage, dir_name) raise ArgumentError.new("Directory name can't be blank") if dir_name.blank? - File.join(repos_path, dir_name) + File.join(storage, dir_name) end def gitlab_shell_projects_path diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index 2286ac8829..730978d502 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -167,7 +167,7 @@ module Gitlab def import_wiki unless project.wiki_enabled? wiki = WikiFormatter.new(project) - gitlab_shell.import_repository(wiki.path_with_namespace, wiki.import_url) + gitlab_shell.import_repository(project.repository_storage_path, wiki.path_with_namespace, wiki.import_url) project.update_attribute(:wiki_enabled, true) end diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 12d6ac45fb..e9a4e37ec4 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -356,97 +356,108 @@ namespace :gitlab do ######################## def check_repo_base_exists - print "Repo base directory exists? ... " + puts "Repo base directory exists?" - repo_base_path = Gitlab.config.gitlab_shell.repos_path + Gitlab.config.repositories.storages.each do |name, repo_base_path| + print "#{name}... " - if File.exists?(repo_base_path) - puts "yes".color(:green) - else - puts "no".color(:red) - puts "#{repo_base_path} is missing".color(:red) - try_fixing_it( - "This should have been created when setting up GitLab Shell.", - "Make sure it's set correctly in config/gitlab.yml", - "Make sure GitLab Shell is installed correctly." - ) - for_more_information( - see_installation_guide_section "GitLab Shell" - ) - fix_and_rerun + if File.exists?(repo_base_path) + puts "yes".color(:green) + else + puts "no".color(:red) + puts "#{repo_base_path} is missing".color(:red) + try_fixing_it( + "This should have been created when setting up GitLab Shell.", + "Make sure it's set correctly in config/gitlab.yml", + "Make sure GitLab Shell is installed correctly." + ) + for_more_information( + see_installation_guide_section "GitLab Shell" + ) + fix_and_rerun + end end end def check_repo_base_is_not_symlink - print "Repo base directory is a symlink? ... " + puts "Repo storage directories are symlinks?" - repo_base_path = Gitlab.config.gitlab_shell.repos_path - unless File.exists?(repo_base_path) - puts "can't check because of previous errors".color(:magenta) - return - end + Gitlab.config.repositories.storages.each do |name, repo_base_path| + print "#{name}... " - unless File.symlink?(repo_base_path) - puts "no".color(:green) - else - puts "yes".color(:red) - try_fixing_it( - "Make sure it's set to the real directory in config/gitlab.yml" - ) - fix_and_rerun + unless File.exists?(repo_base_path) + puts "can't check because of previous errors".color(:magenta) + return + end + + unless File.symlink?(repo_base_path) + puts "no".color(:green) + else + puts "yes".color(:red) + try_fixing_it( + "Make sure it's set to the real directory in config/gitlab.yml" + ) + fix_and_rerun + end end end def check_repo_base_permissions - print "Repo base access is drwxrws---? ... " + puts "Repo paths access is drwxrws---?" - repo_base_path = Gitlab.config.gitlab_shell.repos_path - unless File.exists?(repo_base_path) - puts "can't check because of previous errors".color(:magenta) - return - end + Gitlab.config.repositories.storages.each do |name, repo_base_path| + print "#{name}... " - if File.stat(repo_base_path).mode.to_s(8).ends_with?("2770") - puts "yes".color(:green) - else - puts "no".color(:red) - try_fixing_it( - "sudo chmod -R ug+rwX,o-rwx #{repo_base_path}", - "sudo chmod -R ug-s #{repo_base_path}", - "sudo find #{repo_base_path} -type d -print0 | sudo xargs -0 chmod g+s" - ) - for_more_information( - see_installation_guide_section "GitLab Shell" - ) - fix_and_rerun + unless File.exists?(repo_base_path) + puts "can't check because of previous errors".color(:magenta) + return + end + + if File.stat(repo_base_path).mode.to_s(8).ends_with?("2770") + puts "yes".color(:green) + else + puts "no".color(:red) + try_fixing_it( + "sudo chmod -R ug+rwX,o-rwx #{repo_base_path}", + "sudo chmod -R ug-s #{repo_base_path}", + "sudo find #{repo_base_path} -type d -print0 | sudo xargs -0 chmod g+s" + ) + for_more_information( + see_installation_guide_section "GitLab Shell" + ) + fix_and_rerun + end end end def check_repo_base_user_and_group gitlab_shell_ssh_user = Gitlab.config.gitlab_shell.ssh_user gitlab_shell_owner_group = Gitlab.config.gitlab_shell.owner_group - print "Repo base owned by #{gitlab_shell_ssh_user}:#{gitlab_shell_owner_group}? ... " + puts "Repo paths owned by #{gitlab_shell_ssh_user}:#{gitlab_shell_owner_group}?" - repo_base_path = Gitlab.config.gitlab_shell.repos_path - unless File.exists?(repo_base_path) - puts "can't check because of previous errors".color(:magenta) - return - end + Gitlab.config.repositories.storages.each do |name, repo_base_path| + print "#{name}... " - uid = uid_for(gitlab_shell_ssh_user) - gid = gid_for(gitlab_shell_owner_group) - if File.stat(repo_base_path).uid == uid && File.stat(repo_base_path).gid == gid - puts "yes".color(:green) - else - puts "no".color(:red) - puts " User id for #{gitlab_shell_ssh_user}: #{uid}. Groupd id for #{gitlab_shell_owner_group}: #{gid}".color(:blue) - try_fixing_it( - "sudo chown -R #{gitlab_shell_ssh_user}:#{gitlab_shell_owner_group} #{repo_base_path}" - ) - for_more_information( - see_installation_guide_section "GitLab Shell" - ) - fix_and_rerun + unless File.exists?(repo_base_path) + puts "can't check because of previous errors".color(:magenta) + return + end + + uid = uid_for(gitlab_shell_ssh_user) + gid = gid_for(gitlab_shell_owner_group) + if File.stat(repo_base_path).uid == uid && File.stat(repo_base_path).gid == gid + puts "yes".color(:green) + else + puts "no".color(:red) + puts " User id for #{gitlab_shell_ssh_user}: #{uid}. Groupd id for #{gitlab_shell_owner_group}: #{gid}".color(:blue) + try_fixing_it( + "sudo chown -R #{gitlab_shell_ssh_user}:#{gitlab_shell_owner_group} #{repo_base_path}" + ) + for_more_information( + see_installation_guide_section "GitLab Shell" + ) + fix_and_rerun + end end end @@ -473,7 +484,7 @@ namespace :gitlab do else puts "wrong or missing hooks".color(:red) try_fixing_it( - sudo_gitlab("#{File.join(gitlab_shell_path, 'bin/create-hooks')}"), + sudo_gitlab("#{File.join(gitlab_shell_path, 'bin/create-hooks')} #{repository_storage_paths_args.join(' ')}"), 'Check the hooks_path in config/gitlab.yml', 'Check your gitlab-shell installation' ) @@ -785,13 +796,13 @@ namespace :gitlab do namespace :repo do desc "GitLab | Check the integrity of the repositories managed by GitLab" task check: :environment do - namespace_dirs = Dir.glob( - File.join(Gitlab.config.gitlab_shell.repos_path, '*') - ) + Gitlab.config.repositories.storages.each do |name, path| + namespace_dirs = Dir.glob(File.join(path, '*')) - namespace_dirs.each do |namespace_dir| - repo_dirs = Dir.glob(File.join(namespace_dir, '*')) - repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) } + namespace_dirs.each do |namespace_dir| + repo_dirs = Dir.glob(File.join(namespace_dir, '*')) + repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) } + end end end end @@ -799,12 +810,12 @@ namespace :gitlab do namespace :user do desc "GitLab | Check the integrity of a specific user's repositories" task :check_repos, [:username] => :environment do |t, args| - username = args[:username] || prompt("Check repository integrity for which username? ".color(:blue)) + username = args[:username] || prompt("Check repository integrity for fsername? ".color(:blue)) user = User.find_by(username: username) if user repo_dirs = user.authorized_projects.map do |p| File.join( - Gitlab.config.gitlab_shell.repos_path, + p.repository_storage_path, "#{p.path_with_namespace}.git" ) end diff --git a/lib/tasks/gitlab/cleanup.rake b/lib/tasks/gitlab/cleanup.rake index ab0028d660..b7cbdc6cd7 100644 --- a/lib/tasks/gitlab/cleanup.rake +++ b/lib/tasks/gitlab/cleanup.rake @@ -5,36 +5,36 @@ namespace :gitlab do warn_user_is_not_gitlab remove_flag = ENV['REMOVE'] - namespaces = Namespace.pluck(:path) - git_base_path = Gitlab.config.gitlab_shell.repos_path - all_dirs = Dir.glob(git_base_path + '/*') + Gitlab.config.repositories.storages.each do |name, git_base_path| + all_dirs = Dir.glob(git_base_path + '/*') - puts git_base_path.color(:yellow) - puts "Looking for directories to remove... " + puts git_base_path.color(:yellow) + puts "Looking for directories to remove... " - all_dirs.reject! do |dir| - # skip if git repo - dir =~ /.git$/ - end + all_dirs.reject! do |dir| + # skip if git repo + dir =~ /.git$/ + end - all_dirs.reject! do |dir| - dir_name = File.basename dir + all_dirs.reject! do |dir| + dir_name = File.basename dir - # skip if namespace present - namespaces.include?(dir_name) - end + # skip if namespace present + namespaces.include?(dir_name) + end - all_dirs.each do |dir_path| + all_dirs.each do |dir_path| - if remove_flag - if FileUtils.rm_rf dir_path - puts "Removed...#{dir_path}".color(:red) + if remove_flag + if FileUtils.rm_rf dir_path + puts "Removed...#{dir_path}".color(:red) + else + puts "Cannot remove #{dir_path}".color(:red) + end else - puts "Cannot remove #{dir_path}".color(:red) + puts "Can be removed: #{dir_path}".color(:red) end - else - puts "Can be removed: #{dir_path}".color(:red) end end @@ -48,20 +48,21 @@ namespace :gitlab do warn_user_is_not_gitlab move_suffix = "+orphaned+#{Time.now.to_i}" - repo_root = Gitlab.config.gitlab_shell.repos_path - # Look for global repos (legacy, depth 1) and normal repos (depth 2) - IO.popen(%W(find #{repo_root} -mindepth 1 -maxdepth 2 -name *.git)) do |find| - find.each_line do |path| - path.chomp! - repo_with_namespace = path. - sub(repo_root, ''). - sub(%r{^/*}, ''). - chomp('.git'). - chomp('.wiki') - next if Project.find_with_namespace(repo_with_namespace) - new_path = path + move_suffix - puts path.inspect + ' -> ' + new_path.inspect - File.rename(path, new_path) + Gitlab.config.repositories.storages.each do |name, repo_root| + # Look for global repos (legacy, depth 1) and normal repos (depth 2) + IO.popen(%W(find #{repo_root} -mindepth 1 -maxdepth 2 -name *.git)) do |find| + find.each_line do |path| + path.chomp! + repo_with_namespace = path. + sub(repo_root, ''). + sub(%r{^/*}, ''). + chomp('.git'). + chomp('.wiki') + next if Project.find_with_namespace(repo_with_namespace) + new_path = path + move_suffix + puts path.inspect + ' -> ' + new_path.inspect + File.rename(path, new_path) + end end end end diff --git a/lib/tasks/gitlab/import.rake b/lib/tasks/gitlab/import.rake index 4753f00c26..dbdd4e977e 100644 --- a/lib/tasks/gitlab/import.rake +++ b/lib/tasks/gitlab/import.rake @@ -2,73 +2,73 @@ namespace :gitlab do namespace :import do # How to use: # - # 1. copy the bare repos under the repos_path (commonly /home/git/repositories) + # 1. copy the bare repos under the repository storage paths (commonly the default path is /home/git/repositories) # 2. run: bundle exec rake gitlab:import:repos RAILS_ENV=production # # Notes: # * The project owner will set to the first administator of the system # * Existing projects will be skipped # - desc "GitLab | Import bare repositories from gitlab_shell -> repos_path into GitLab project instance" + desc "GitLab | Import bare repositories from repositories -> storages into GitLab project instance" task repos: :environment do + Gitlab.config.repositories.storages.each do |name, git_base_path| + repos_to_import = Dir.glob(git_base_path + '/**/*.git') - git_base_path = Gitlab.config.gitlab_shell.repos_path - repos_to_import = Dir.glob(git_base_path + '/**/*.git') + repos_to_import.each do |repo_path| + # strip repo base path + repo_path[0..git_base_path.length] = '' - repos_to_import.each do |repo_path| - # strip repo base path - repo_path[0..git_base_path.length] = '' + path = repo_path.sub(/\.git$/, '') + group_name, name = File.split(path) + group_name = nil if group_name == '.' - path = repo_path.sub(/\.git$/, '') - group_name, name = File.split(path) - group_name = nil if group_name == '.' + puts "Processing #{repo_path}".color(:yellow) - puts "Processing #{repo_path}".color(:yellow) - - if path.end_with?('.wiki') - puts " * Skipping wiki repo" - next - end - - project = Project.find_with_namespace(path) - - if project - puts " * #{project.name} (#{repo_path}) exists" - else - user = User.admins.reorder("id").first - - project_params = { - name: name, - path: name - } - - # find group namespace - if group_name - group = Namespace.find_by(path: group_name) - # create group namespace - unless group - group = Group.new(:name => group_name) - group.path = group_name - group.owner = user - if group.save - puts " * Created Group #{group.name} (#{group.id})".color(:green) - else - puts " * Failed trying to create group #{group.name}".color(:red) - end - end - # set project group - project_params[:namespace_id] = group.id + if path.end_with?('.wiki') + puts " * Skipping wiki repo" + next end - project = Projects::CreateService.new(user, project_params).execute + project = Project.find_with_namespace(path) - if project.persisted? - puts " * Created #{project.name} (#{repo_path})".color(:green) - project.update_repository_size - project.update_commit_count + if project + puts " * #{project.name} (#{repo_path}) exists" else - puts " * Failed trying to create #{project.name} (#{repo_path})".color(:red) - puts " Errors: #{project.errors.messages}".color(:red) + user = User.admins.reorder("id").first + + project_params = { + name: name, + path: name + } + + # find group namespace + if group_name + group = Namespace.find_by(path: group_name) + # create group namespace + unless group + group = Group.new(:name => group_name) + group.path = group_name + group.owner = user + if group.save + puts " * Created Group #{group.name} (#{group.id})".color(:green) + else + puts " * Failed trying to create group #{group.name}".color(:red) + end + end + # set project group + project_params[:namespace_id] = group.id + end + + project = Projects::CreateService.new(user, project_params).execute + + if project.persisted? + puts " * Created #{project.name} (#{repo_path})".color(:green) + project.update_repository_size + project.update_commit_count + else + puts " * Failed trying to create #{project.name} (#{repo_path})".color(:red) + puts " Errors: #{project.errors.messages}".color(:red) + end end end end diff --git a/lib/tasks/gitlab/info.rake b/lib/tasks/gitlab/info.rake index 352b566df2..fe43d40e6d 100644 --- a/lib/tasks/gitlab/info.rake +++ b/lib/tasks/gitlab/info.rake @@ -62,7 +62,10 @@ namespace :gitlab do puts "" puts "GitLab Shell".color(:yellow) puts "Version:\t#{gitlab_shell_version || "unknown".color(:red)}" - puts "Repositories:\t#{Gitlab.config.gitlab_shell.repos_path}" + puts "Repository storage paths:" + Gitlab.config.repositories.storages.each do |name, path| + puts "- #{name}: \t#{path}" + end puts "Hooks:\t\t#{Gitlab.config.gitlab_shell.hooks_path}" puts "Git:\t\t#{Gitlab.config.git.bin_path}" diff --git a/lib/tasks/gitlab/list_repos.rake b/lib/tasks/gitlab/list_repos.rake index c7596e7abc..ffcc76e549 100644 --- a/lib/tasks/gitlab/list_repos.rake +++ b/lib/tasks/gitlab/list_repos.rake @@ -9,7 +9,7 @@ namespace :gitlab do scope = scope.where('id IN (?) OR namespace_id in (?)', project_ids, namespace_ids) end scope.find_each do |project| - base = File.join(Gitlab.config.gitlab_shell.repos_path, project.path_with_namespace) + base = File.join(project.repository_storage_path, project.path_with_namespace) puts base + '.git' puts base + '.wiki.git' end diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake index b1648a4602..263798e9c2 100644 --- a/lib/tasks/gitlab/shell.rake +++ b/lib/tasks/gitlab/shell.rake @@ -12,7 +12,6 @@ namespace :gitlab do gitlab_url = Gitlab.config.gitlab.url # gitlab-shell requires a / at the end of the url gitlab_url += '/' unless gitlab_url.end_with?('/') - repos_path = Gitlab.config.gitlab_shell.repos_path target_dir = Gitlab.config.gitlab_shell.path # Clone if needed @@ -35,7 +34,6 @@ namespace :gitlab do user: user, gitlab_url: gitlab_url, http_settings: {self_signed_cert: false}.stringify_keys, - repos_path: repos_path, auth_file: File.join(home_dir, ".ssh", "authorized_keys"), redis: { bin: %x{which redis-cli}.chomp, @@ -58,10 +56,10 @@ namespace :gitlab do File.open("config.yml", "w+") {|f| f.puts config.to_yaml} # Launch installation process - system(*%W(bin/install)) + system(*%W(bin/install) + repository_storage_paths_args) # (Re)create hooks - system(*%W(bin/create-hooks)) + system(*%W(bin/create-hooks) + repository_storage_paths_args) end # Required for debian packaging with PKGR: Setup .ssh/environment with @@ -87,7 +85,8 @@ namespace :gitlab do if File.exists?(path_to_repo) print '-' else - if Gitlab::Shell.new.add_repository(project.path_with_namespace) + if Gitlab::Shell.new.add_repository(project.repository_storage_path, + project.path_with_namespace) print '.' else print 'F' @@ -138,4 +137,3 @@ namespace :gitlab do system(*%W(#{Gitlab.config.git.bin_path} reset --hard #{tag})) end end - diff --git a/lib/tasks/gitlab/task_helpers.rake b/lib/tasks/gitlab/task_helpers.rake index d0c019044b..ab96b1d359 100644 --- a/lib/tasks/gitlab/task_helpers.rake +++ b/lib/tasks/gitlab/task_helpers.rake @@ -125,10 +125,16 @@ namespace :gitlab do end def all_repos - IO.popen(%W(find #{Gitlab.config.gitlab_shell.repos_path} -mindepth 2 -maxdepth 2 -type d -name *.git)) do |find| - find.each_line do |path| - yield path.chomp + Gitlab.config.repositories.storages.each do |name, path| + IO.popen(%W(find #{path} -mindepth 2 -maxdepth 2 -type d -name *.git)) do |find| + find.each_line do |path| + yield path.chomp + end end end end + + def repository_storage_paths_args + Gitlab.config.repositories.storages.values + end end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 09e0bbfd00..604204cca0 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -123,11 +123,17 @@ describe ProjectsHelper do end describe '#sanitized_import_error' do + let(:project) { create(:project) } + + before do + allow(project).to receive(:repository_storage_path).and_return('/base/repo/path') + end + it 'removes the repo path' do - repo = File.join(Gitlab.config.gitlab_shell.repos_path, '/namespace/test.git') + repo = '/base/repo/path/namespace/test.git' import_error = "Could not clone #{repo}\n" - expect(sanitize_repo_path(import_error)).to eq('Could not clone [REPOS PATH]/namespace/test.git') + expect(sanitize_repo_path(project, import_error)).to eq('Could not clone [REPOS PATH]/namespace/test.git') end end end diff --git a/spec/initializers/6_validations_spec.rb b/spec/initializers/6_validations_spec.rb new file mode 100644 index 0000000000..5178bd130f --- /dev/null +++ b/spec/initializers/6_validations_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe '6_validations', lib: true do + context 'with correct settings' do + before do + mock_storages('foo' => '/a/b/c', 'bar' => 'a/b/d') + end + + it 'passes through' do + expect { load_validations }.not_to raise_error + end + end + + context 'with invalid storage names' do + before do + mock_storages('name with spaces' => '/a/b/c') + end + + it 'throws an error' do + expect { load_validations }.to raise_error('"name with spaces" is not a valid storage name. Please fix this in your gitlab.yml before starting GitLab.') + end + end + + context 'with nested storage paths' do + before do + mock_storages('foo' => '/a/b/c', 'bar' => '/a/b/c/d') + end + + it 'throws an error' do + expect { load_validations }.to raise_error('bar is a nested path of foo. Nested paths are not supported for repository storages. Please fix this in your gitlab.yml before starting GitLab.') + end + end + + def mock_storages(storages) + allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + end + + def load_validations + load File.join(__dir__, '../../config/initializers/6_validations.rb') + end +end diff --git a/spec/lib/gitlab/backend/shell_spec.rb b/spec/lib/gitlab/backend/shell_spec.rb index fd869f48b5..e15f13f985 100644 --- a/spec/lib/gitlab/backend/shell_spec.rb +++ b/spec/lib/gitlab/backend/shell_spec.rb @@ -13,6 +13,11 @@ describe Gitlab::Shell, lib: true do it { is_expected.to respond_to :add_repository } it { is_expected.to respond_to :remove_repository } it { is_expected.to respond_to :fork_repository } + it { is_expected.to respond_to :gc } + it { is_expected.to respond_to :add_namespace } + it { is_expected.to respond_to :rm_namespace } + it { is_expected.to respond_to :mv_namespace } + it { is_expected.to respond_to :exists? } it { expect(gitlab_shell.url_to_repo('diaspora')).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + "diaspora.git") } diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 4e68ac5e63..cbea407f9b 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -57,6 +57,7 @@ describe Namespace, models: true do describe :move_dir do before do @namespace = create :namespace + @project = create :project, namespace: @namespace allow(@namespace).to receive(:path_changed?).and_return(true) end @@ -87,8 +88,13 @@ describe Namespace, models: true do end describe :rm_dir do - it "should remove dir" do - expect(namespace.rm_dir).to be_truthy + let!(:project) { create(:project, namespace: namespace) } + let!(:path) { File.join(Gitlab.config.repositories.storages.default, namespace.path) } + + before { namespace.destroy } + + it "should remove its dirs when deleted" do + expect(File.exist?(path)).to be(false) end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index d305cd9ff1..ee1142fa3a 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -56,6 +56,7 @@ describe Project, models: true do it { is_expected.to validate_length_of(:description).is_within(0..2000) } it { is_expected.to validate_presence_of(:creator) } it { is_expected.to validate_presence_of(:namespace) } + it { is_expected.to validate_presence_of(:repository_storage) } it 'should not allow new projects beyond user limits' do project2 = build(:project) @@ -84,6 +85,20 @@ describe Project, models: true do end end end + + context 'repository storages inclussion' do + let(:project2) { build(:project, repository_storage: 'missing') } + + before do + storages = { 'custom' => 'tmp/tests/custom_repositories' } + allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + end + + it "should not allow repository storages that don't match a label in the configuration" do + expect(project2).not_to be_valid + expect(project2.errors[:repository_storage].first).to match(/is not included in the list/) + end + end end describe 'default_scope' do @@ -131,6 +146,24 @@ describe Project, models: true do end end + describe '#repository_storage_path' do + let(:project) { create(:project, repository_storage: 'custom') } + + before do + FileUtils.mkdir('tmp/tests/custom_repositories') + storages = { 'custom' => 'tmp/tests/custom_repositories' } + allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + end + + after do + FileUtils.rm_rf('tmp/tests/custom_repositories') + end + + it 'returns the repository storage path' do + expect(project.repository_storage_path).to eq('tmp/tests/custom_repositories') + end + end + it 'should return valid url to repo' do project = Project.new(path: 'somewhere') expect(project.url_to_repo).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + 'somewhere.git') @@ -729,12 +762,12 @@ describe Project, models: true do expect(gitlab_shell).to receive(:mv_repository). ordered. - with("#{ns}/foo", "#{ns}/#{project.path}"). + with(project.repository_storage_path, "#{ns}/foo", "#{ns}/#{project.path}"). and_return(true) expect(gitlab_shell).to receive(:mv_repository). ordered. - with("#{ns}/foo.wiki", "#{ns}/#{project.path}.wiki"). + with(project.repository_storage_path, "#{ns}/foo.wiki", "#{ns}/#{project.path}.wiki"). and_return(true) expect_any_instance_of(SystemHooksService). @@ -826,7 +859,7 @@ describe Project, models: true do context 'using a regular repository' do it 'creates the repository' do expect(shell).to receive(:add_repository). - with(project.path_with_namespace). + with(project.repository_storage_path, project.path_with_namespace). and_return(true) expect(project.repository).to receive(:after_create) @@ -836,7 +869,7 @@ describe Project, models: true do it 'adds an error if the repository could not be created' do expect(shell).to receive(:add_repository). - with(project.path_with_namespace). + with(project.repository_storage_path, project.path_with_namespace). and_return(false) expect(project.repository).not_to receive(:after_create) diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index 437c89c357..fcea45f19b 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -72,6 +72,7 @@ describe API::API, api: true do expect(response).to have_http_status(200) expect(json_response["status"]).to be_truthy + expect(json_response["repository_path"]).to eq(project.repository.path_to_repo) end end @@ -81,6 +82,7 @@ describe API::API, api: true do expect(response).to have_http_status(200) expect(json_response["status"]).to be_truthy + expect(json_response["repository_path"]).to eq(project.repository.path_to_repo) end end end diff --git a/spec/services/destroy_group_service_spec.rb b/spec/services/destroy_group_service_spec.rb index afa89b8417..eca8ddd8ea 100644 --- a/spec/services/destroy_group_service_spec.rb +++ b/spec/services/destroy_group_service_spec.rb @@ -23,8 +23,8 @@ describe DestroyGroupService, services: true do Sidekiq::Testing.inline! { destroy_group(group, user) } end - it { expect(gitlab_shell.exists?(group.path)).to be_falsey } - it { expect(gitlab_shell.exists?(remove_path)).to be_falsey } + it { expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_falsey } + it { expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_falsey } end context 'Sidekiq fake' do @@ -33,8 +33,8 @@ describe DestroyGroupService, services: true do Sidekiq::Testing.fake! { destroy_group(group, user) } end - it { expect(gitlab_shell.exists?(group.path)).to be_falsey } - it { expect(gitlab_shell.exists?(remove_path)).to be_truthy } + it { expect(gitlab_shell.exists?(project.repository_storage_path, group.path)).to be_falsey } + it { expect(gitlab_shell.exists?(project.repository_storage_path, remove_path)).to be_truthy } end end diff --git a/spec/services/projects/housekeeping_service_spec.rb b/spec/services/projects/housekeeping_service_spec.rb index 4c5ced7e74..bd4dc6a0f7 100644 --- a/spec/services/projects/housekeeping_service_spec.rb +++ b/spec/services/projects/housekeeping_service_spec.rb @@ -12,7 +12,7 @@ describe Projects::HousekeepingService do it 'enqueues a sidekiq job' do expect(subject).to receive(:try_obtain_lease).and_return(true) - expect(GitlabShellOneShotWorker).to receive(:perform_async).with(:gc, project.path_with_namespace) + expect(GitlabShellOneShotWorker).to receive(:perform_async).with(:gc, project.repository_storage_path, project.path_with_namespace) subject.execute expect(project.pushes_since_gc).to eq(0) diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb index 068c9a1219..d5d4d7c56e 100644 --- a/spec/services/projects/import_service_spec.rb +++ b/spec/services/projects/import_service_spec.rb @@ -36,7 +36,7 @@ describe Projects::ImportService, services: true do end it 'succeeds if repository import is successfully' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.path_with_namespace, project.import_url).and_return(true) + expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_return(true) result = subject.execute @@ -44,7 +44,7 @@ describe Projects::ImportService, services: true do end it 'fails if repository import fails' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.path_with_namespace, project.import_url).and_raise(Gitlab::Shell::Error.new('Failed to import the repository')) + expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_raise(Gitlab::Shell::Error.new('Failed to import the repository')) result = subject.execute @@ -64,7 +64,7 @@ describe Projects::ImportService, services: true do end it 'succeeds if importer succeeds' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.path_with_namespace, project.import_url).and_return(true) + expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_return(true) expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_return(true) result = subject.execute @@ -74,7 +74,7 @@ describe Projects::ImportService, services: true do it 'flushes various caches' do expect_any_instance_of(Gitlab::Shell).to receive(:import_repository). - with(project.path_with_namespace, project.import_url). + with(project.repository_storage_path, project.path_with_namespace, project.import_url). and_return(true) expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute). @@ -90,7 +90,7 @@ describe Projects::ImportService, services: true do end it 'fails if importer fails' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.path_with_namespace, project.import_url).and_return(true) + expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_return(true) expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_return(false) result = subject.execute @@ -100,7 +100,7 @@ describe Projects::ImportService, services: true do end it 'fails if importer raise an error' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.path_with_namespace, project.import_url).and_return(true) + expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_return(true) expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_raise(Projects::ImportService::Error.new('Github: failed to connect API')) result = subject.execute diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 426bf53f19..be5331e477 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -80,8 +80,9 @@ module TestEnv end def setup_gitlab_shell - unless File.directory?(Rails.root.join(*%w(tmp tests gitlab-shell))) - `rake gitlab:shell:install` + unless File.directory?(Gitlab.config.gitlab_shell.path) + # TODO: Remove `[shards]` when gitlab-shell v3.1.0 is published + `rake gitlab:shell:install[shards]` end end @@ -127,14 +128,14 @@ module TestEnv def copy_repo(project) base_repo_path = File.expand_path(factory_repo_path_bare) - target_repo_path = File.expand_path(repos_path + "/#{project.namespace.path}/#{project.path}.git") + target_repo_path = File.expand_path(project.repository_storage_path + "/#{project.namespace.path}/#{project.path}.git") FileUtils.mkdir_p(target_repo_path) FileUtils.cp_r("#{base_repo_path}/.", target_repo_path) FileUtils.chmod_R 0755, target_repo_path end def repos_path - Gitlab.config.gitlab_shell.repos_path + Gitlab.config.repositories.storages.default end def backup_path @@ -143,7 +144,7 @@ module TestEnv def copy_forked_repo_with_submodules(project) base_repo_path = File.expand_path(forked_repo_path_bare) - target_repo_path = File.expand_path(repos_path + "/#{project.namespace.path}/#{project.path}.git") + target_repo_path = File.expand_path(project.repository_storage_path + "/#{project.namespace.path}/#{project.path}.git") FileUtils.mkdir_p(target_repo_path) FileUtils.cp_r("#{base_repo_path}/.", target_repo_path) FileUtils.chmod_R 0755, target_repo_path diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb index 25da091713..02308530d1 100644 --- a/spec/tasks/gitlab/backup_rake_spec.rb +++ b/spec/tasks/gitlab/backup_rake_spec.rb @@ -98,67 +98,107 @@ describe 'gitlab:app namespace rake task' do @backup_tar = tars_glob.first end - before do - create_backup - end - - after do - FileUtils.rm(@backup_tar) - end - - context 'archive file permissions' do - it 'should set correct permissions on the tar file' do - expect(File.exist?(@backup_tar)).to be_truthy - expect(File::Stat.new(@backup_tar).mode.to_s(8)).to eq('100600') + context 'tar creation' do + before do + create_backup end - context 'with custom archive_permissions' do - before do - allow(Gitlab.config.backup).to receive(:archive_permissions).and_return(0651) - # We created a backup in a before(:all) so it got the default permissions. - # We now need to do some work to create a _new_ backup file using our stub. - FileUtils.rm(@backup_tar) - create_backup + after do + FileUtils.rm(@backup_tar) + end + + context 'archive file permissions' do + it 'should set correct permissions on the tar file' do + expect(File.exist?(@backup_tar)).to be_truthy + expect(File::Stat.new(@backup_tar).mode.to_s(8)).to eq('100600') end - it 'uses the custom permissions' do - expect(File::Stat.new(@backup_tar).mode.to_s(8)).to eq('100651') + context 'with custom archive_permissions' do + before do + allow(Gitlab.config.backup).to receive(:archive_permissions).and_return(0651) + # We created a backup in a before(:all) so it got the default permissions. + # We now need to do some work to create a _new_ backup file using our stub. + FileUtils.rm(@backup_tar) + create_backup + end + + it 'uses the custom permissions' do + expect(File::Stat.new(@backup_tar).mode.to_s(8)).to eq('100651') + end end end - end - it 'should set correct permissions on the tar contents' do - tar_contents, exit_status = Gitlab::Popen.popen( - %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz lfs.tar.gz registry.tar.gz} - ) - expect(exit_status).to eq(0) - expect(tar_contents).to match('db/') - expect(tar_contents).to match('uploads.tar.gz') - expect(tar_contents).to match('repositories/') - expect(tar_contents).to match('builds.tar.gz') - expect(tar_contents).to match('artifacts.tar.gz') - expect(tar_contents).to match('lfs.tar.gz') - expect(tar_contents).to match('registry.tar.gz') - expect(tar_contents).not_to match(/^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz|artifacts.tar.gz|registry.tar.gz)\/$/) - end - - it 'should delete temp directories' do - temp_dirs = Dir.glob( - File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds,artifacts,lfs,registry}') - ) - - expect(temp_dirs).to be_empty - end - - context 'registry disabled' do - let(:enable_registry) { false } - - it 'should not create registry.tar.gz' do + it 'should set correct permissions on the tar contents' do tar_contents, exit_status = Gitlab::Popen.popen( - %W{tar -tvf #{@backup_tar}} + %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz lfs.tar.gz registry.tar.gz} ) expect(exit_status).to eq(0) - expect(tar_contents).not_to match('registry.tar.gz') + expect(tar_contents).to match('db/') + expect(tar_contents).to match('uploads.tar.gz') + expect(tar_contents).to match('repositories/') + expect(tar_contents).to match('builds.tar.gz') + expect(tar_contents).to match('artifacts.tar.gz') + expect(tar_contents).to match('lfs.tar.gz') + expect(tar_contents).to match('registry.tar.gz') + expect(tar_contents).not_to match(/^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz|artifacts.tar.gz|registry.tar.gz)\/$/) + end + + it 'should delete temp directories' do + temp_dirs = Dir.glob( + File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds,artifacts,lfs,registry}') + ) + + expect(temp_dirs).to be_empty + end + + context 'registry disabled' do + let(:enable_registry) { false } + + it 'should not create registry.tar.gz' do + tar_contents, exit_status = Gitlab::Popen.popen( + %W{tar -tvf #{@backup_tar}} + ) + expect(exit_status).to eq(0) + expect(tar_contents).not_to match('registry.tar.gz') + end + end + end + + context 'multiple repository storages' do + let(:project_a) { create(:project, repository_storage: 'default') } + let(:project_b) { create(:project, repository_storage: 'custom') } + + before do + FileUtils.mkdir('tmp/tests/default_storage') + FileUtils.mkdir('tmp/tests/custom_storage') + storages = { + 'default' => 'tmp/tests/default_storage', + 'custom' => 'tmp/tests/custom_storage' + } + allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + + # Create the projects now, after mocking the settings but before doing the backup + project_a + project_b + + # We only need a backup of the repositories for this test + ENV["SKIP"] = "db,uploads,builds,artifacts,lfs,registry" + create_backup + end + + after do + FileUtils.rm_rf('tmp/tests/default_storage') + FileUtils.rm_rf('tmp/tests/custom_storage') + FileUtils.rm(@backup_tar) + end + + it 'should include repositories in all repository storages' do + tar_contents, exit_status = Gitlab::Popen.popen( + %W{tar -tvf #{@backup_tar} repositories} + ) + expect(exit_status).to eq(0) + expect(tar_contents).to match("repositories/#{project_a.path_with_namespace}.bundle") + expect(tar_contents).to match("repositories/#{project_b.path_with_namespace}.bundle") end end end # backup_create task diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index b8e73682c9..20b1a343c2 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -91,6 +91,6 @@ describe PostReceive do end def pwd(project) - File.join(Gitlab.config.gitlab_shell.repos_path, project.path_with_namespace) + File.join(Gitlab.config.repositories.storages.default, project.path_with_namespace) end end diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb index 4ef05eb29d..5f762282b5 100644 --- a/spec/workers/repository_fork_worker_spec.rb +++ b/spec/workers/repository_fork_worker_spec.rb @@ -14,6 +14,7 @@ describe RepositoryForkWorker do describe "#perform" do it "creates a new repository from a fork" do expect(shell).to receive(:fork_repository).with( + project.repository_storage_path, project.path_with_namespace, fork_project.namespace.path ).and_return(true) @@ -25,9 +26,11 @@ describe RepositoryForkWorker do end it 'flushes various caches' do - expect(shell).to receive(:fork_repository). - with(project.path_with_namespace, fork_project.namespace.path). - and_return(true) + expect(shell).to receive(:fork_repository).with( + project.repository_storage_path, + project.path_with_namespace, + fork_project.namespace.path + ).and_return(true) expect_any_instance_of(Repository).to receive(:expire_emptiness_caches). and_call_original From 20b9bb2029972c5f5334d6d684e0d60edb034c5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Fri, 24 Jun 2016 15:06:46 -0400 Subject: [PATCH 37/98] Create (if necessary) and link the gitlab-shell secret file on the rake install task --- .../initializers/gitlab_shell_secret_token.rb | 20 +--------------- lib/gitlab/backend/shell.rb | 17 ++++++++++++++ lib/tasks/gitlab/shell.rake | 2 ++ spec/lib/gitlab/backend/shell_spec.rb | 23 +++++++++++++++++++ 4 files changed, 43 insertions(+), 19 deletions(-) diff --git a/config/initializers/gitlab_shell_secret_token.rb b/config/initializers/gitlab_shell_secret_token.rb index 751fccead0..7454c33c9d 100644 --- a/config/initializers/gitlab_shell_secret_token.rb +++ b/config/initializers/gitlab_shell_secret_token.rb @@ -1,19 +1 @@ -# Be sure to restart your server when you modify this file. - -require 'securerandom' - -# Your secret key for verifying the gitlab_shell. - - -secret_file = Gitlab.config.gitlab_shell.secret_file - -unless File.exist? secret_file - # Generate a new token of 16 random hexadecimal characters and store it in secret_file. - token = SecureRandom.hex(16) - File.write(secret_file, token) -end - -link_path = File.join(Gitlab.config.gitlab_shell.path, '.gitlab_shell_secret') -if File.exist?(Gitlab.config.gitlab_shell.path) && !File.exist?(link_path) - FileUtils.symlink(secret_file, link_path) -end +Gitlab::Shell.new.generate_and_link_secret_token diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index e31840ef91..34e0143a82 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -1,3 +1,5 @@ +require 'securerandom' + module Gitlab class Shell class Error < StandardError; end @@ -188,6 +190,21 @@ module Gitlab File.exist?(full_path(storage, dir_name)) end + # Create (if necessary) and link the secret token file + def generate_and_link_secret_token + secret_file = Gitlab.config.gitlab_shell.secret_file + unless File.exist? secret_file + # Generate a new token of 16 random hexadecimal characters and store it in secret_file. + token = SecureRandom.hex(16) + File.write(secret_file, token) + end + + link_path = File.join(gitlab_shell_path, '.gitlab_shell_secret') + if File.exist?(gitlab_shell_path) && !File.exist?(link_path) + FileUtils.symlink(secret_file, link_path) + end + end + protected def gitlab_shell_path diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake index 263798e9c2..c85ebdf861 100644 --- a/lib/tasks/gitlab/shell.rake +++ b/lib/tasks/gitlab/shell.rake @@ -71,6 +71,8 @@ namespace :gitlab do File.open(File.join(home_dir, ".ssh", "environment"), "w+") do |f| f.puts "PATH=#{ENV['PATH']}" end + + Gitlab::Shell.new.generate_and_link_secret_token end desc "GitLab | Setup gitlab-shell" diff --git a/spec/lib/gitlab/backend/shell_spec.rb b/spec/lib/gitlab/backend/shell_spec.rb index e15f13f985..6e5ba21138 100644 --- a/spec/lib/gitlab/backend/shell_spec.rb +++ b/spec/lib/gitlab/backend/shell_spec.rb @@ -21,6 +21,29 @@ describe Gitlab::Shell, lib: true do it { expect(gitlab_shell.url_to_repo('diaspora')).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + "diaspora.git") } + describe 'generate_and_link_secret_token' do + let(:secret_file) { 'tmp/tests/.secret_shell_test' } + let(:link_file) { 'tmp/tests/shell-secret-test/.gitlab_shell_secret' } + + before do + allow(Gitlab.config.gitlab_shell).to receive(:path).and_return('tmp/tests/shell-secret-test') + allow(Gitlab.config.gitlab_shell).to receive(:secret_file).and_return(secret_file) + FileUtils.mkdir('tmp/tests/shell-secret-test') + gitlab_shell.generate_and_link_secret_token + end + + after do + FileUtils.rm_rf('tmp/tests/shell-secret-test') + FileUtils.rm_rf(secret_file) + end + + it 'creates and links the secret token file' do + expect(File.exist?(secret_file)).to be(true) + expect(File.symlink?(link_file)).to be(true) + expect(File.readlink(link_file)).to eq(secret_file) + end + end + describe Gitlab::Shell::KeyAdder, lib: true do describe '#add_key' do it 'normalizes space characters in the key' do From 4a8a69837a9a14fca39bf089099b581602d983f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Wed, 29 Jun 2016 23:35:00 -0400 Subject: [PATCH 38/98] Add Application Setting to configure default Repository Path for new projects --- CHANGELOG | 1 + .../admin/application_settings_controller.rb | 1 + app/helpers/application_settings_helper.rb | 8 ++++++++ app/models/application_setting.rb | 5 +++++ app/models/project.rb | 1 + .../admin/application_settings/_form.html.haml | 9 +++++++++ ..._repository_storage_to_application_settings.rb | 5 +++++ db/schema.rb | 1 + doc/api/settings.md | 7 +++++-- lib/api/entities.rb | 1 + spec/models/application_setting_spec.rb | 10 ++++++++++ spec/models/project_spec.rb | 15 +++++++++++++++ spec/requests/api/settings_spec.rb | 9 ++++++++- 13 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 db/migrate/20160614182521_add_repository_storage_to_application_settings.rb diff --git a/CHANGELOG b/CHANGELOG index 6b23ce2b27..68df9aa620 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ v 8.10.0 (unreleased) - Fix commit builds API, return all builds for all pipelines for given commit. !4849 - Replace Haml with Hamlit to make view rendering faster. !3666 - Refactor repository paths handling to allow multiple git mount points + - Add Application Setting to configure default Repository Path for new projects - Wrap code blocks on Activies and Todos page. !4783 (winniehell) - Align flash messages with left side of page content !4959 (winniehell) - Display last commit of deleted branch in push events !4699 (winniehell) diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index f4eda864aa..5f65dd3aff 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -109,6 +109,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :metrics_packet_size, :send_user_confirmation_email, :container_registry_token_expire_delay, + :repository_storage, restricted_visibility_levels: [], import_sources: [], disabled_oauth_sign_in_sources: [] diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 55313fd835..6e580c62cc 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -78,4 +78,12 @@ module ApplicationSettingsHelper end end end + + def repository_storage_options_for_select + options = Gitlab.config.repositories.storages.map do |name, path| + ["#{name} - #{path}", name] + end + + options_for_select(options, @application_setting.repository_storage) + end end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index d914b0b26e..5fa6eacd23 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -55,6 +55,10 @@ class ApplicationSetting < ActiveRecord::Base presence: true, numericality: { only_integer: true, greater_than: 0 } + validates :repository_storage, + presence: true, + inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } } + validates_each :restricted_visibility_levels do |record, attr, value| unless value.nil? value.each do |level| @@ -134,6 +138,7 @@ class ApplicationSetting < ActiveRecord::Base disabled_oauth_sign_in_sources: [], send_user_confirmation_email: false, container_registry_token_expire_delay: 5, + repository_storage: 'default', ) end diff --git a/app/models/project.rb b/app/models/project.rb index 2f6901e0e3..6a950ee830 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -24,6 +24,7 @@ class Project < ActiveRecord::Base default_value_for :wiki_enabled, gitlab_config_features.wiki default_value_for :snippets_enabled, gitlab_config_features.snippets default_value_for :container_registry_enabled, gitlab_config_features.container_registry + default_value_for(:repository_storage) { current_application_settings.repository_storage } default_value_for(:shared_runners_enabled) { current_application_settings.shared_runners_enabled } after_create :ensure_dir_exist diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 30ab071716..c1f70bc186 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -310,6 +310,15 @@ .col-sm-10 = f.text_field :sentry_dsn, class: 'form-control' + %fieldset + %legend Repository Storage + .form-group + = f.label :repository_storage, 'Storage path for new projects', class: 'control-label col-sm-2' + .col-sm-10 + = f.select :repository_storage, repository_storage_options_for_select, {}, class: 'form-control' + .help-block + You can manage the repository storage paths in your gitlab.yml configuration file + %fieldset %legend Repository Checks .form-group diff --git a/db/migrate/20160614182521_add_repository_storage_to_application_settings.rb b/db/migrate/20160614182521_add_repository_storage_to_application_settings.rb new file mode 100644 index 0000000000..6dae91b700 --- /dev/null +++ b/db/migrate/20160614182521_add_repository_storage_to_application_settings.rb @@ -0,0 +1,5 @@ +class AddRepositoryStorageToApplicationSettings < ActiveRecord::Migration + def change + add_column :application_settings, :repository_storage, :string, default: 'default' + end +end diff --git a/db/schema.rb b/db/schema.rb index a7173116b1..beb723c3bc 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -85,6 +85,7 @@ ActiveRecord::Schema.define(version: 20160620115026) do t.boolean "send_user_confirmation_email", default: false t.integer "container_registry_token_expire_delay", default: 5 t.text "after_sign_up_text" + t.string "repository_storage", default: "default" end create_table "audit_events", force: :cascade do |t| diff --git a/doc/api/settings.md b/doc/api/settings.md index b5152311f2..741c5a2958 100644 --- a/doc/api/settings.md +++ b/doc/api/settings.md @@ -38,7 +38,8 @@ Example response: "default_project_visibility" : 0, "gravatar_enabled" : true, "sign_in_text" : null, - "container_registry_token_expire_delay": 5 + "container_registry_token_expire_delay": 5, + "repository_storage": "default" } ``` @@ -66,6 +67,7 @@ PUT /application/settings | `user_oauth_applications` | boolean | no | Allow users to register any application to use GitLab as an OAuth provider | | `after_sign_out_path` | string | no | Where to redirect users after logout | | `container_registry_token_expire_delay` | integer | no | Container Registry token duration in minutes | +| `repository_storage` | string | no | Storage path for new projects. The value should be the name of one of the repository storage paths defined in your gitlab.yml | ```bash curl -X PUT -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/application/settings?signup_enabled=false&default_project_visibility=1 @@ -93,6 +95,7 @@ Example response: "restricted_signup_domains": [], "user_oauth_applications": true, "after_sign_out_path": "", - "container_registry_token_expire_delay": 5 + "container_registry_token_expire_delay": 5, + "repository_storage": "default" } ``` diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 5a23a18fe9..4e2a43e45e 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -376,6 +376,7 @@ module API expose :user_oauth_applications expose :after_sign_out_path expose :container_registry_token_expire_delay + expose :repository_storage end class Release < Grape::Entity diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index d84f3e998f..2ea1320267 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -40,6 +40,16 @@ describe ApplicationSetting, models: true do it_behaves_like 'an object with email-formated attributes', :admin_notification_email do subject { setting } end + + context 'repository storages inclussion' do + before do + storages = { 'custom' => 'tmp/tests/custom_repositories' } + allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + end + + it { is_expected.to allow_value('custom').for(:repository_storage) } + it { is_expected.not_to allow_value('alternative').for(:repository_storage) } + end end context 'restricted signup domains' do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index ee1142fa3a..42308035d8 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -607,6 +607,21 @@ describe Project, models: true do end end + context 'repository storage by default' do + let(:project) { create(:empty_project) } + + subject { project.repository_storage } + + before do + storages = { 'alternative_storage' => '/some/path' } + allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + stub_application_setting(repository_storage: 'alternative_storage') + allow_any_instance_of(Project).to receive(:ensure_dir_exist).and_return(true) + end + + it { is_expected.to eq('alternative_storage') } + end + context 'shared runners by default' do let(:project) { create(:empty_project) } diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb index f756101c51..6629a5a65e 100644 --- a/spec/requests/api/settings_spec.rb +++ b/spec/requests/api/settings_spec.rb @@ -14,16 +14,23 @@ describe API::API, 'Settings', api: true do expect(json_response).to be_an Hash expect(json_response['default_projects_limit']).to eq(42) expect(json_response['signin_enabled']).to be_truthy + expect(json_response['repository_storage']).to eq('default') end end describe "PUT /application/settings" do + before do + storages = { 'custom' => 'tmp/tests/custom_repositories' } + allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + end + it "should update application settings" do put api("/application/settings", admin), - default_projects_limit: 3, signin_enabled: false + default_projects_limit: 3, signin_enabled: false, repository_storage: 'custom' expect(response).to have_http_status(200) expect(json_response['default_projects_limit']).to eq(3) expect(json_response['signin_enabled']).to be_falsey + expect(json_response['repository_storage']).to eq('custom') end end end From 860785f00757a47e0e3ace973444ba5ad6d9c174 Mon Sep 17 00:00:00 2001 From: DJ Mountney Date: Mon, 27 Jun 2016 12:43:28 -0700 Subject: [PATCH 39/98] Make Rack::Request use our trusted proxies when filtering IP addresses This allows us to control the trusted proxies while deployed in a private network. Normally Rack::Request will trust all private IPs as trusted proxies, which can caue problems if your users are connection on you network via private IP ranges. Normally in a rails app this is handled by action_dispatch request, but rack_attack is specifically using the Rack::Request object instead. --- CHANGELOG | 1 + config/initializers/trusted_proxies.rb | 13 +++++++++++++ spec/initializers/trusted_proxies_spec.rb | 12 ++++++++---- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 764df7cf55..286e2815de 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,7 @@ v 8.10.0 (unreleased) - Wrap code blocks on Activies and Todos page. !4783 (winniehell) - Align flash messages with left side of page content !4959 (winniehell) - Display last commit of deleted branch in push events !4699 (winniehell) + - Apply the trusted_proxies config to the rack request object for use with rack_attack - Add Sidekiq queue duration to transaction metrics. - Let Workhorse serve format-patch diffs - Make images fit to the size of the viewport !4810 diff --git a/config/initializers/trusted_proxies.rb b/config/initializers/trusted_proxies.rb index d256a16d42..df4a933e22 100644 --- a/config/initializers/trusted_proxies.rb +++ b/config/initializers/trusted_proxies.rb @@ -1,3 +1,16 @@ +# Override Rack::Request to make use of the same list of trusted_proxies +# as the ActionDispatch::Request object. This is necessary for libraries +# like rack_attack where they don't use ActionDispatch, and we want them +# to block/throttle requests on private networks. +# Rack Attack specific issue: https://github.com/kickstarter/rack-attack/issues/145 +module Rack + class Request + def trusted_proxy?(ip) + Rails.application.config.action_dispatch.trusted_proxies.any? { |proxy| proxy === ip } + end + end +end + Rails.application.config.action_dispatch.trusted_proxies = ( [ '127.0.0.1', '::1' ] + Array(Gitlab.config.gitlab.trusted_proxies) ).map { |proxy| IPAddr.new(proxy) } diff --git a/spec/initializers/trusted_proxies_spec.rb b/spec/initializers/trusted_proxies_spec.rb index 4bb149f25f..14c8df954a 100644 --- a/spec/initializers/trusted_proxies_spec.rb +++ b/spec/initializers/trusted_proxies_spec.rb @@ -6,14 +6,16 @@ describe 'trusted_proxies', lib: true do set_trusted_proxies([]) end - it 'preserves private IPs as remote_ip' do + it 'preserves private IPs' do request = stub_request('HTTP_X_FORWARDED_FOR' => '10.1.5.89') expect(request.remote_ip).to eq('10.1.5.89') + expect(request.ip).to eq('10.1.5.89') end - it 'filters out localhost from remote_ip' do + it 'filters out localhost' do request = stub_request('HTTP_X_FORWARDED_FOR' => '1.1.1.1, 10.1.5.89, 127.0.0.1') expect(request.remote_ip).to eq('10.1.5.89') + expect(request.ip).to eq('10.1.5.89') end end @@ -22,9 +24,10 @@ describe 'trusted_proxies', lib: true do set_trusted_proxies([ "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16" ]) end - it 'filters out private and local IPs from remote_ip' do + it 'filters out private and local IPs' do request = stub_request('HTTP_X_FORWARDED_FOR' => '1.2.3.6, 1.1.1.1, 10.1.5.89, 127.0.0.1') expect(request.remote_ip).to eq('1.1.1.1') + expect(request.ip).to eq('1.1.1.1') end end @@ -33,9 +36,10 @@ describe 'trusted_proxies', lib: true do set_trusted_proxies([ "60.98.25.47" ]) end - it 'filters out proxy IP from remote_ip' do + it 'filters out proxy IP' do request = stub_request('HTTP_X_FORWARDED_FOR' => '1.2.3.6, 1.1.1.1, 60.98.25.47, 127.0.0.1') expect(request.remote_ip).to eq('1.1.1.1') + expect(request.ip).to eq('1.1.1.1') end end From 7f345be2b05c83a8df451d015af1ad615bdf38f5 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Thu, 30 Jun 2016 09:27:38 +0200 Subject: [PATCH 40/98] Fix wrong line in changelog --- CHANGELOG | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 764df7cf55..bbdc823281 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -92,7 +92,6 @@ v 8.9.1 - Remove duplicate 'New Page' button on edit wiki page v 8.9.0 -v 8.9.0 (unreleased) - Fix group visibility form layout in application settings - Fix builds API response not including commit data - Fix error when CI job variables key specified but not defined From 5987ad256985ffd2b964b4c030babc4102325e2c Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Thu, 23 Jun 2016 17:25:14 -0500 Subject: [PATCH 41/98] Add sub nav to file view --- app/views/projects/blob/show.html.haml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/views/projects/blob/show.html.haml b/app/views/projects/blob/show.html.haml index ed670dae88..8d77bdbe38 100644 --- a/app/views/projects/blob/show.html.haml +++ b/app/views/projects/blob/show.html.haml @@ -1,12 +1,15 @@ +- @no_container = true - page_title @blob.path, @ref += render "projects/commits/head" -= render 'projects/last_push' +%div{ class: (container_class) } + = render 'projects/last_push' -%div#tree-holder.tree-holder - = render 'blob', blob: @blob + %div#tree-holder.tree-holder + = render 'blob', blob: @blob -- if can_edit_blob?(@blob) - = render 'projects/blob/remove' + - if can_edit_blob?(@blob) + = render 'projects/blob/remove' - - title = "Replace #{@blob.name}" - = render 'projects/blob/upload', title: title, placeholder: title, button_title: 'Replace file', form_path: namespace_project_update_blob_path(@project.namespace, @project, @id), method: :put + - title = "Replace #{@blob.name}" + = render 'projects/blob/upload', title: title, placeholder: title, button_title: 'Replace file', form_path: namespace_project_update_blob_path(@project.namespace, @project, @id), method: :put From f06220411996165cbe4be96d438aa268f5827ed2 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Thu, 23 Jun 2016 17:34:33 -0500 Subject: [PATCH 42/98] Update CHANGELOG --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 764df7cf55..cf7f8eda43 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -42,6 +42,9 @@ v 8.9.3 - Fix missing avatar on system notes. !4954 - Reduce overhead and optimize ProjectTeam#max_member_access performance. !4973 - Use update_columns to by_pass all the dirty code on active_record. !4985 + - Update mobile button icons to be more inline with typical UI paradigms +v 8.9.3 + - Add sub nav to file page view v 8.9.2 - Fix visibility of snippets when searching. From 2485c5ded880634b3e9b4e2c96564a3e4775ac16 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 28 Jun 2016 16:39:41 +0200 Subject: [PATCH 43/98] Fix changelog for 8.9.3 Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index cf7f8eda43..680b684112 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -42,8 +42,10 @@ v 8.9.3 - Fix missing avatar on system notes. !4954 - Reduce overhead and optimize ProjectTeam#max_member_access performance. !4973 - Use update_columns to by_pass all the dirty code on active_record. !4985 +v 8.9.3 (unreleased) + - Decreased min width of screen to 1280px for pinned sidebar + - Fix encrypted data backwards compatibility after upgrading attr_encrypted gem - Update mobile button icons to be more inline with typical UI paradigms -v 8.9.3 - Add sub nav to file page view v 8.9.2 From 13d5d99e94fb43d3883973f76508da890ad907d8 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 29 Jun 2016 22:17:34 +0200 Subject: [PATCH 44/98] Move changelot item "Add sub nav to file page view" to 8.9.4 Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 680b684112..ca7c3f29c7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -26,6 +26,7 @@ v 8.10.0 (unreleased) v 8.9.4 (unreleased) - Fixes middle click and double request when navigating through the file browser !4891 + - Add sub nav to file page view v 8.9.3 - Fix encrypted data backwards compatibility after upgrading attr_encrypted gem. !4963 @@ -42,11 +43,9 @@ v 8.9.3 - Fix missing avatar on system notes. !4954 - Reduce overhead and optimize ProjectTeam#max_member_access performance. !4973 - Use update_columns to by_pass all the dirty code on active_record. !4985 -v 8.9.3 (unreleased) - Decreased min width of screen to 1280px for pinned sidebar - Fix encrypted data backwards compatibility after upgrading attr_encrypted gem - Update mobile button icons to be more inline with typical UI paradigms - - Add sub nav to file page view v 8.9.2 - Fix visibility of snippets when searching. From 7a2f25a80dccd689fdba39223fe18c746306b1de Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Wed, 29 Jun 2016 18:42:24 +0200 Subject: [PATCH 45/98] Remove coveralls as its unused --- Gemfile | 1 - Gemfile.lock | 10 ---------- lib/tasks/test.rake | 4 +--- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/Gemfile b/Gemfile index 52de9ef981..7d9c9dd168 100644 --- a/Gemfile +++ b/Gemfile @@ -303,7 +303,6 @@ group :development, :test do gem 'rubocop', '~> 0.40.0', require: false gem 'rubocop-rspec', '~> 1.5.0', require: false gem 'scss_lint', '~> 0.47.0', require: false - gem 'coveralls', '~> 0.8.2', require: false gem 'simplecov', '~> 0.11.0', require: false gem 'flog', require: false gem 'flay', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 4c5350ba63..352940cc75 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -141,12 +141,6 @@ GEM colorize (0.7.7) concurrent-ruby (1.0.2) connection_pool (2.2.0) - coveralls (0.8.13) - json (~> 1.8) - simplecov (~> 0.11.0) - term-ansicolor (~> 1.3) - thor (~> 0.19.1) - tins (~> 1.6.0) crack (0.4.3) safe_yaml (~> 1.0.0) creole (0.5.0) @@ -729,8 +723,6 @@ GEM teaspoon-jasmine (2.2.0) teaspoon (>= 1.0.0) temple (0.7.7) - term-ansicolor (1.3.2) - tins (~> 1.0) test_after_commit (0.4.2) activerecord (>= 3.2) thin (1.6.4) @@ -751,7 +743,6 @@ GEM mime-types multi_json (~> 1.7) twitter-stream (~> 0.1) - tins (1.6.0) turbolinks (2.5.3) coffee-rails twitter-stream (0.1.16) @@ -841,7 +832,6 @@ DEPENDENCIES chronic_duration (~> 0.10.6) coffee-rails (~> 4.1.0) connection_pool (~> 2.0) - coveralls (~> 0.8.2) creole (~> 0.5.0) d3_rails (~> 3.5.0) database_cleaner (~> 1.4.0) diff --git a/lib/tasks/test.rake b/lib/tasks/test.rake index c5666d49e6..21c0e5f1d4 100644 --- a/lib/tasks/test.rake +++ b/lib/tasks/test.rake @@ -6,8 +6,6 @@ task :test do end unless Rails.env.production? - require 'coveralls/rake/task' - Coveralls::RakeTask.new desc "GitLab | Run all tests on CI with simplecov" - task :test_ci => [:rubocop, :brakeman, 'teaspoon', :spinach, :spec, 'coveralls:push'] + task test_ci: [:rubocop, :brakeman, 'teaspoon', :spinach, :spec] end From 94cec500c534ac8b35d7d7d9c807646faa800fec Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 28 Jun 2016 14:05:32 +0200 Subject: [PATCH 46/98] Do not show build retry link when build is active --- app/views/projects/builds/_sidebar.html.haml | 2 +- .../projects/builds/show.html.haml_spec.rb | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 spec/views/projects/builds/show.html.haml_spec.rb diff --git a/app/views/projects/builds/_sidebar.html.haml b/app/views/projects/builds/_sidebar.html.haml index cab21f0cf1..a1dc79aaf5 100644 --- a/app/views/projects/builds/_sidebar.html.haml +++ b/app/views/projects/builds/_sidebar.html.haml @@ -40,7 +40,7 @@ .block{ class: ("block-first" if !@build.coverage && !(can?(current_user, :read_build, @project) && (@build.artifacts? || @build.artifacts_expired?))) } .title Build details - - if @build.retryable? + - if @build.retryable? && !@build.active? = link_to "Retry", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'pull-right', method: :post - if @build.merge_request %p.build-detail-row diff --git a/spec/views/projects/builds/show.html.haml_spec.rb b/spec/views/projects/builds/show.html.haml_spec.rb new file mode 100644 index 0000000000..cd18d19ef5 --- /dev/null +++ b/spec/views/projects/builds/show.html.haml_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe 'projects/builds/show' do + include Devise::TestHelpers + + let(:build) { create(:ci_build) } + let(:project) { build.project } + + before do + assign(:build, build) + assign(:project, project) + + allow(view).to receive(:can?).and_return(true) + end + + context 'when build is running' do + before do + build.run! + render + end + + it 'does not show retry button' do + expect(rendered).not_to have_link('Retry') + end + end + + context 'when build is not running' do + before do + build.success! + render + end + + it 'shows retry button' do + expect(rendered).to have_link('Retry') + end + end +end From f9c5f18d448de3fefced3149550263adc83af1bf Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 28 Jun 2016 14:24:43 +0200 Subject: [PATCH 47/98] Improve method that tells if build is retryable This method now should return false if build is not completed. If build is running then it is not retryable, therefore `Ci::Build#retryable?` returned wrong value. This commit changes this behavior --- app/models/ci/build.rb | 2 +- app/views/projects/builds/_sidebar.html.haml | 2 +- spec/models/build_spec.rb | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 2b0bec3313..c11f8e6884 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -90,7 +90,7 @@ module Ci end def retryable? - project.builds_enabled? && commands.present? + project.builds_enabled? && commands.present? && complete? end def retried? diff --git a/app/views/projects/builds/_sidebar.html.haml b/app/views/projects/builds/_sidebar.html.haml index a1dc79aaf5..cab21f0cf1 100644 --- a/app/views/projects/builds/_sidebar.html.haml +++ b/app/views/projects/builds/_sidebar.html.haml @@ -40,7 +40,7 @@ .block{ class: ("block-first" if !@build.coverage && !(can?(current_user, :read_build, @project) && (@build.artifacts? || @build.artifacts_expired?))) } .title Build details - - if @build.retryable? && !@build.active? + - if @build.retryable? = link_to "Retry", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'pull-right', method: :post - if @build.merge_request %p.build-detail-row diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb index 8154001cf4..97b28686d8 100644 --- a/spec/models/build_spec.rb +++ b/spec/models/build_spec.rb @@ -669,4 +669,22 @@ describe Ci::Build, models: true do expect(build.commit).to eq project.commit end end + + describe '#retryable?' do + context 'when build is running' do + before { build.run! } + + it 'should return false' do + expect(build.retryable?).to be false + end + end + + context 'when build is finished' do + before { build.success! } + + it 'should return true' do + expect(build.retryable?).to be true + end + end + end end From d75787b265c771234ae3da5cca6baf8e0ff8d345 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 28 Jun 2016 14:27:52 +0200 Subject: [PATCH 48/98] Add Changelog entry for build sidebar retry link fix --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index ca7c3f29c7..59c56cc6d0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -44,6 +44,7 @@ v 8.9.3 - Reduce overhead and optimize ProjectTeam#max_member_access performance. !4973 - Use update_columns to by_pass all the dirty code on active_record. !4985 - Decreased min width of screen to 1280px for pinned sidebar + - Do not show build retry link in build sidebar when build is not finished yet - Fix encrypted data backwards compatibility after upgrading attr_encrypted gem - Update mobile button icons to be more inline with typical UI paradigms From 8223e280711f7d42a34816d681dffd3b2c881990 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 30 Jun 2016 11:06:49 +0200 Subject: [PATCH 49/98] Move Changelog entry for build retry fix to 8.9.4 --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 59c56cc6d0..7a5b778f63 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -25,6 +25,7 @@ v 8.10.0 (unreleased) - Add basic system information like memory and disk usage to the admin panel v 8.9.4 (unreleased) + - Do not show build retry link in build sidebar when build is not finished yet - Fixes middle click and double request when navigating through the file browser !4891 - Add sub nav to file page view @@ -44,7 +45,6 @@ v 8.9.3 - Reduce overhead and optimize ProjectTeam#max_member_access performance. !4973 - Use update_columns to by_pass all the dirty code on active_record. !4985 - Decreased min width of screen to 1280px for pinned sidebar - - Do not show build retry link in build sidebar when build is not finished yet - Fix encrypted data backwards compatibility after upgrading attr_encrypted gem - Update mobile button icons to be more inline with typical UI paradigms From a4ce2d126d969722af7152c4be2c8a6dde3104b5 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 28 Jun 2016 17:50:17 +0200 Subject: [PATCH 50/98] Handle external issues in IssueReferenceFilter IssueReferenceFilter will end up processing internal issue references when a project uses an external issues tracker while still using internal issue references (in the form of `#\d+`). This commit ensures that these links are rendered as external issue links, regardless of whether the project one currently views uses an internal or external issues tracker. Fixes gitlab-org/gitlab-ce#19036, gitlab-com/performance#16 --- .../filter/abstract_reference_filter.rb | 14 ++++++++----- lib/banzai/filter/issue_reference_filter.rb | 20 +++++++++++++++++++ lib/banzai/filter/reference_filter.rb | 2 +- .../filter/issue_reference_filter_spec.rb | 13 ++++++++++++ 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb index 81d6627113..d77a5e3ff0 100644 --- a/lib/banzai/filter/abstract_reference_filter.rb +++ b/lib/banzai/filter/abstract_reference_filter.rb @@ -160,11 +160,7 @@ module Banzai title = object_link_title(object) klass = reference_class(object_sym) - data = data_attribute( - original: link_text || match, - project: project.id, - object_sym => object.id - ) + data = data_attributes_for(link_text || match, project, object) if matches.names.include?("url") && matches[:url] url = matches[:url] @@ -183,6 +179,14 @@ module Banzai end end + def data_attributes_for(text, project, object) + data_attribute( + original: text, + project: project.id, + object_sym => object.id + ) + end + def object_link_text_extras(object, matches) extras = [] diff --git a/lib/banzai/filter/issue_reference_filter.rb b/lib/banzai/filter/issue_reference_filter.rb index 5351272f42..4042e9a4c2 100644 --- a/lib/banzai/filter/issue_reference_filter.rb +++ b/lib/banzai/filter/issue_reference_filter.rb @@ -46,6 +46,26 @@ module Banzai end end + def object_link_title(object) + if object.is_a?(ExternalIssue) + "Issue in #{object.project.external_issue_tracker.title}" + else + super + end + end + + def data_attributes_for(text, project, object) + if object.is_a?(ExternalIssue) + data_attribute( + project: project.id, + external_issue: object.id, + reference_type: ExternalIssueReferenceFilter.reference_type + ) + else + super + end + end + def find_projects_for_paths(paths) super(paths).includes(:gitlab_issue_tracker_service) end diff --git a/lib/banzai/filter/reference_filter.rb b/lib/banzai/filter/reference_filter.rb index 2d6f34c9cd..bf058241cd 100644 --- a/lib/banzai/filter/reference_filter.rb +++ b/lib/banzai/filter/reference_filter.rb @@ -29,7 +29,7 @@ module Banzai def data_attribute(attributes = {}) attributes = attributes.reject { |_, v| v.nil? } - attributes[:reference_type] = self.class.reference_type + attributes[:reference_type] ||= self.class.reference_type attributes.delete(:original) if context[:no_original_data] attributes.map { |key, value| %Q(data-#{key.to_s.dasherize}="#{escape_once(value)}") }.join(" ") end diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb index 8d6ce114aa..a005b4990e 100644 --- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb @@ -199,6 +199,19 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do end end + context 'referencing external issues' do + let(:project) { create(:redmine_project) } + + it 'renders internal issue IDs as external issue links' do + doc = reference_filter('#1') + link = doc.css('a').first + + expect(link.attr('data-reference-type')).to eq('external_issue') + expect(link.attr('title')).to eq('Issue in Redmine') + expect(link.attr('data-external-issue')).to eq('1') + end + end + describe '#issues_per_Project' do context 'using an internal issue tracker' do it 'returns a Hash containing the issues per project' do From 4fca633a317eb065145d3cc687f62eabcb8e8af2 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 29 Jun 2016 19:25:44 -0700 Subject: [PATCH 51/98] Fix broken spec in git_push_service_spec by stubbing an external issue tracker --- spec/services/git_push_service_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index f99ad046f0..cab9a03d83 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -314,6 +314,8 @@ describe GitPushService, services: true do it "doesn't close issues when external issue tracker is in use" do allow_any_instance_of(Project).to receive(:default_issues_tracker?). and_return(false) + external_issue_tracker = double(title: 'My Tracker', issue_path: issue.iid) + allow_any_instance_of(Project).to receive(:external_issue_tracker).and_return(external_issue_tracker) # The push still shouldn't create cross-reference notes. expect do From bf970141a165f3379c1623eb1deece26207a6134 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 30 Jun 2016 11:58:34 +0100 Subject: [PATCH 52/98] Expiry date on pinned nav cookie --- app/assets/javascripts/application.js.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee index b6dbf2d0cc..30d452f575 100644 --- a/app/assets/javascripts/application.js.coffee +++ b/app/assets/javascripts/application.js.coffee @@ -261,7 +261,7 @@ $ -> # Sidenav pinning if $window.width() < 1280 and $.cookie('pin_nav') is 'true' - $.cookie('pin_nav', 'false', { path: '/' }) + $.cookie('pin_nav', 'false', { path: '/', expires: 365 * 10 }) $('.page-with-sidebar') .toggleClass('page-sidebar-collapsed page-sidebar-expanded') .removeClass('page-sidebar-pinned') @@ -292,7 +292,7 @@ $ -> .toggleClass('header-collapsed header-expanded') # Save settings - $.cookie 'pin_nav', doPinNav, { path: '/' } + $.cookie 'pin_nav', doPinNav, { path: '/', expires: 365 * 10 } if $.cookie('pin_nav') is 'true' or doPinNav tooltipText = 'Unpin navigation' From efd70c18784690473b93714982e75c0c87210588 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 30 Jun 2016 13:31:52 +0200 Subject: [PATCH 53/98] Enable Style/UnneededCapitalW Rubocop cop --- .rubocop.yml | 2 +- lib/gitlab/key_fingerprint.rb | 2 +- spec/lib/gitlab/popen_spec.rb | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index cc3055ef66..cdcfd8150e 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -681,7 +681,7 @@ Style/UnlessElse: # Checks for %W when interpolation is not needed. Style/UnneededCapitalW: - Enabled: false + Enabled: true # TODO: Enable UnneededInterpolation Cop. # Checks for strings that are just an interpolated expression. diff --git a/lib/gitlab/key_fingerprint.rb b/lib/gitlab/key_fingerprint.rb index 8684b4636e..b75ae512d9 100644 --- a/lib/gitlab/key_fingerprint.rb +++ b/lib/gitlab/key_fingerprint.rb @@ -39,7 +39,7 @@ module Gitlab # OpenSSH 6.8 introduces a new default output format for fingerprints. # Check the version and decide which command to use. - version_output, version_status = popen(%W(ssh -V)) + version_output, version_status = popen(%w(ssh -V)) return false unless version_status.zero? version_matches = version_output.match(/OpenSSH_(?\d+)\.(?\d+)/) diff --git a/spec/lib/gitlab/popen_spec.rb b/spec/lib/gitlab/popen_spec.rb index 795cf24127..e8b236426e 100644 --- a/spec/lib/gitlab/popen_spec.rb +++ b/spec/lib/gitlab/popen_spec.rb @@ -10,7 +10,7 @@ describe 'Gitlab::Popen', lib: true, no_db: true do context 'zero status' do before do - @output, @status = @klass.new.popen(%W(ls), path) + @output, @status = @klass.new.popen(%w(ls), path) end it { expect(@status).to be_zero } @@ -19,7 +19,7 @@ describe 'Gitlab::Popen', lib: true, no_db: true do context 'non-zero status' do before do - @output, @status = @klass.new.popen(%W(cat NOTHING), path) + @output, @status = @klass.new.popen(%w(cat NOTHING), path) end it { expect(@status).to eq(1) } @@ -34,7 +34,7 @@ describe 'Gitlab::Popen', lib: true, no_db: true do context 'without a directory argument' do before do - @output, @status = @klass.new.popen(%W(ls)) + @output, @status = @klass.new.popen(%w(ls)) end it { expect(@status).to be_zero } From cc324eb4ab6f10386dccd891f6b3fdd14b91d2e6 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Thu, 30 Jun 2016 13:46:35 +0200 Subject: [PATCH 54/98] Ensure that branch and tag names are given in API --- lib/api/branches.rb | 8 ++++---- lib/api/tags.rb | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/api/branches.rb b/lib/api/branches.rb index 231840148d..9f9ae75ff6 100644 --- a/lib/api/branches.rb +++ b/lib/api/branches.rb @@ -25,7 +25,7 @@ module API # branch (required) - The name of the branch # Example Request: # GET /projects/:id/repository/branches/:branch - get ':id/repository/branches/:branch', requirements: { branch: /.*/ } do + get ':id/repository/branches/:branch', requirements: { branch: /.+/ } do @branch = user_project.repository.branches.find { |item| item.name == params[:branch] } not_found!("Branch") unless @branch present @branch, with: Entities::RepoObject, project: user_project @@ -39,7 +39,7 @@ module API # Example Request: # PUT /projects/:id/repository/branches/:branch/protect put ':id/repository/branches/:branch/protect', - requirements: { branch: /.*/ } do + requirements: { branch: /.+/ } do authorize_admin_project @@ -59,7 +59,7 @@ module API # Example Request: # PUT /projects/:id/repository/branches/:branch/unprotect put ':id/repository/branches/:branch/unprotect', - requirements: { branch: /.*/ } do + requirements: { branch: /.+/ } do authorize_admin_project @@ -101,7 +101,7 @@ module API # Example Request: # DELETE /projects/:id/repository/branches/:branch delete ":id/repository/branches/:branch", - requirements: { branch: /.*/ } do + requirements: { branch: /.+/ } do authorize_push_project result = DeleteBranchService.new(user_project, current_user). execute(params[:branch]) diff --git a/lib/api/tags.rb b/lib/api/tags.rb index 3e1ed3fe5c..7b675e05fb 100644 --- a/lib/api/tags.rb +++ b/lib/api/tags.rb @@ -61,7 +61,7 @@ module API # tag_name (required) - The name of the tag # Example Request: # DELETE /projects/:id/repository/tags/:tag - delete ":id/repository/tags/:tag_name", requirements: { tag_name: /.*/ } do + delete ":id/repository/tags/:tag_name", requirements: { tag_name: /.+/ } do authorize_push_project result = DeleteTagService.new(user_project, current_user). execute(params[:tag_name]) @@ -83,7 +83,7 @@ module API # description (required) - Release notes with markdown support # Example Request: # POST /projects/:id/repository/tags/:tag_name/release - post ':id/repository/tags/:tag_name/release', requirements: { tag_name: /.*/ } do + post ':id/repository/tags/:tag_name/release', requirements: { tag_name: /.+/ } do authorize_push_project required_attributes! [:description] result = CreateReleaseService.new(user_project, current_user). @@ -104,7 +104,7 @@ module API # description (required) - Release notes with markdown support # Example Request: # PUT /projects/:id/repository/tags/:tag_name/release - put ':id/repository/tags/:tag_name/release', requirements: { tag_name: /.*/ } do + put ':id/repository/tags/:tag_name/release', requirements: { tag_name: /.+/ } do authorize_push_project required_attributes! [:description] result = UpdateReleaseService.new(user_project, current_user). From 13fc95acc4b8ca418de2af383a6f0e1ccee9e9a2 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Thu, 30 Jun 2016 16:01:26 +0300 Subject: [PATCH 55/98] Remove unnecessary parens --- app/views/admin/background_jobs/show.html.haml | 2 +- app/views/admin/builds/index.html.haml | 2 +- app/views/admin/dashboard/index.html.haml | 2 +- app/views/admin/groups/index.html.haml | 5 ++--- app/views/admin/health_check/show.html.haml | 2 +- app/views/admin/logs/show.html.haml | 2 +- app/views/admin/projects/index.html.haml | 2 +- app/views/admin/runners/index.html.haml | 2 +- app/views/admin/system_info/show.html.haml | 2 +- app/views/admin/users/index.html.haml | 2 +- app/views/groups/show.html.haml | 2 +- app/views/projects/_home_panel.html.haml | 2 +- app/views/projects/_last_push.html.haml | 2 +- app/views/projects/blob/show.html.haml | 2 +- app/views/projects/branches/index.html.haml | 4 ++-- app/views/projects/builds/index.html.haml | 2 +- app/views/projects/commits/show.html.haml | 2 +- app/views/projects/compare/index.html.haml | 2 +- app/views/projects/compare/show.html.haml | 2 +- app/views/projects/environments/index.html.haml | 2 +- app/views/projects/environments/show.html.haml | 2 +- app/views/projects/graphs/ci.html.haml | 2 +- app/views/projects/graphs/commits.html.haml | 2 +- app/views/projects/graphs/languages.html.haml | 2 +- app/views/projects/graphs/show.html.haml | 2 +- app/views/projects/issues/index.html.haml | 2 +- app/views/projects/labels/index.html.haml | 2 +- app/views/projects/merge_requests/index.html.haml | 2 +- app/views/projects/milestones/index.html.haml | 2 +- app/views/projects/network/_head.html.haml | 2 +- app/views/projects/network/show.html.haml | 2 +- app/views/projects/pipelines/index.html.haml | 2 +- app/views/projects/show.html.haml | 2 +- app/views/projects/tags/index.html.haml | 4 ++-- app/views/projects/tree/show.html.haml | 2 +- app/views/projects/wikis/_new.html.haml | 2 +- app/views/projects/wikis/edit.html.haml | 2 +- app/views/projects/wikis/git_access.html.haml | 2 +- app/views/projects/wikis/history.html.haml | 2 +- app/views/projects/wikis/pages.html.haml | 2 +- app/views/projects/wikis/show.html.haml | 2 +- 41 files changed, 44 insertions(+), 45 deletions(-) diff --git a/app/views/admin/background_jobs/show.html.haml b/app/views/admin/background_jobs/show.html.haml index 654d261aa9..4f680b507c 100644 --- a/app/views/admin/background_jobs/show.html.haml +++ b/app/views/admin/background_jobs/show.html.haml @@ -2,7 +2,7 @@ - page_title "Background Jobs" = render 'admin/background_jobs/head' -%div{ class: (container_class) } +%div{ class: container_class } %h3.page-title Background Jobs %p.light GitLab uses #{link_to "sidekiq", "http://sidekiq.org/"} library for async job processing diff --git a/app/views/admin/builds/index.html.haml b/app/views/admin/builds/index.html.haml index efd5b12cfe..1e60205f91 100644 --- a/app/views/admin/builds/index.html.haml +++ b/app/views/admin/builds/index.html.haml @@ -1,7 +1,7 @@ - @no_container = true = render "admin/dashboard/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area %ul.nav-links diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 4682016a88..a2ac407c15 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -1,7 +1,7 @@ - @no_container = true = render "admin/dashboard/head" -%div{ class: (container_class) } +%div{ class: container_class } .admin-dashboard.prepend-top-default .row .col-md-4 diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index 4f1996ef7a..94aa5f5a94 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -2,7 +2,7 @@ - page_title "Groups" = render "admin/dashboard/head" -%div{ class: (container_class) } +%div{ class: container_class } %h3.page-title Groups (#{number_with_delimiter(@groups.total_count)}) @@ -39,7 +39,6 @@ = link_to 'New Group', new_admin_group_path, class: "btn btn-new" %ul.content-list - - @groups.each do |group| - = render 'group', group: group + = render @groups = paginate @groups, theme: "gitlab" diff --git a/app/views/admin/health_check/show.html.haml b/app/views/admin/health_check/show.html.haml index 7b8407f915..e79303240f 100644 --- a/app/views/admin/health_check/show.html.haml +++ b/app/views/admin/health_check/show.html.haml @@ -2,7 +2,7 @@ - page_title "Health Check" = render 'admin/background_jobs/head' -%div{ class: (container_class) } +%div{ class: container_class } %h3.page-title Health Check .bs-callout.clearfix diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml index 5ddc3b9ea8..676812121d 100644 --- a/app/views/admin/logs/show.html.haml +++ b/app/views/admin/logs/show.html.haml @@ -5,7 +5,7 @@ Gitlab::RepositoryCheckLogger] = render 'admin/background_jobs/head' -%div{ class: (container_class) } +%div{ class: container_class } %ul.nav-links.log-tabs - loggers.each do |klass| %li{ class: (klass == Gitlab::GitLogger ? 'active' : '') } diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 4822cb693c..7d2eb42322 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -3,7 +3,7 @@ = render 'shared/show_aside' = render "admin/dashboard/head" -%div{ class: (container_class) } +%div{ class: container_class } .row.prepend-top-default %aside.col-md-3 .panel.admin-filter diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml index 5eff77aff2..114bea92fc 100644 --- a/app/views/admin/runners/index.html.haml +++ b/app/views/admin/runners/index.html.haml @@ -1,7 +1,7 @@ - @no_container = true = render "admin/dashboard/head" -%div{ class: (container_class) } +%div{ class: container_class } %p.prepend-top-default %span diff --git a/app/views/admin/system_info/show.html.haml b/app/views/admin/system_info/show.html.haml index 3ef2f20b58..247db29586 100644 --- a/app/views/admin/system_info/show.html.haml +++ b/app/views/admin/system_info/show.html.haml @@ -2,7 +2,7 @@ - page_title "System Info" = render 'admin/background_jobs/head' -%div{ class: (container_class) } +%div{ class: container_class } .prepend-top-default .row .col-sm-4 diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index d0a696da64..21bb99a792 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -3,7 +3,7 @@ = render 'shared/show_aside' = render "admin/dashboard/head" -%div{ class: (container_class) } +%div{ class: container_class } .admin-filter %ul.nav-links %li{class: "#{'active' unless params[:filter]}"} diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index a0a6762edc..69f634e75b 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -5,7 +5,7 @@ = auto_discovery_link_tag(:atom, group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} activity") .cover-block.groups-cover-block - %div{ class: (container_class) } + %div{ class: container_class } = link_to group_icon(@group), target: '_blank' do = image_tag group_icon(@group), class: "avatar group-avatar s70" .group-info diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml index 86ea08dd22..8ce23379fb 100644 --- a/app/views/projects/_home_panel.html.haml +++ b/app/views/projects/_home_panel.html.haml @@ -1,6 +1,6 @@ - empty_repo = @project.empty_repo? .project-home-panel.cover-block.clearfix{:class => ("empty-project" if empty_repo)} - %div{ class: (container_class) } + %div{ class: container_class } .row .project-image-container = project_icon(@project, alt: '', class: 'project-avatar avatar s70') diff --git a/app/views/projects/_last_push.html.haml b/app/views/projects/_last_push.html.haml index e0ca2a3109..434d8644b8 100644 --- a/app/views/projects/_last_push.html.haml +++ b/app/views/projects/_last_push.html.haml @@ -1,7 +1,7 @@ - if event = last_push_event - if show_last_push_widget?(event) .row-content-block.top-block.clear-block.hidden-xs - %div{ class: (container_class) } + %div{ class: container_class } .event-last-push .event-last-push-text %span You pushed to diff --git a/app/views/projects/blob/show.html.haml b/app/views/projects/blob/show.html.haml index 8d77bdbe38..0ab78a39cf 100644 --- a/app/views/projects/blob/show.html.haml +++ b/app/views/projects/blob/show.html.haml @@ -2,7 +2,7 @@ - page_title @blob.path, @ref = render "projects/commits/head" -%div{ class: (container_class) } +%div{ class: container_class } = render 'projects/last_push' %div#tree-holder.tree-holder diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml index e0367c4027..77b405f1f3 100644 --- a/app/views/projects/branches/index.html.haml +++ b/app/views/projects/branches/index.html.haml @@ -2,7 +2,7 @@ - page_title "Branches" = render "projects/commits/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area .nav-text Protected branches can be managed in project settings @@ -27,7 +27,7 @@ = sort_title_recently_updated = link_to namespace_project_branches_path(sort: 'last_updated') do = sort_title_oldest_updated - - unless @branches.empty? + - if @branches.any? %ul.content-list.all-branches - @branches.each do |branch| = render "projects/branches/branch", branch: branch diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml index 181547316a..a131289ee9 100644 --- a/app/views/projects/builds/index.html.haml +++ b/app/views/projects/builds/index.html.haml @@ -2,7 +2,7 @@ - page_title "Builds" = render "projects/pipelines/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area %ul.nav-links %li{class: ('active' if @scope.nil?)} diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index 51ca4eb903..9a44ba9497 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -7,7 +7,7 @@ = render "head" -%div{ class: (container_class) } +%div{ class: container_class } .row-content-block.second-block.content-component-block .tree-ref-holder = render 'shared/ref_switcher', destination: 'commits' diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml index b22285c11e..e9ff8e90dd 100644 --- a/app/views/projects/compare/index.html.haml +++ b/app/views/projects/compare/index.html.haml @@ -2,7 +2,7 @@ - page_title "Compare" = render "projects/commits/head" -%div{ class: (container_class) } +%div{ class: container_class } .sub-header-block Compare branches, tags or commit ranges. %br diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml index f4ec7b767f..28a50e7031 100644 --- a/app/views/projects/compare/show.html.haml +++ b/app/views/projects/compare/show.html.haml @@ -2,7 +2,7 @@ - page_title "#{params[:from]}...#{params[:to]}" = render "projects/commits/head" -%div{ class: (container_class) } +%div{ class: container_class } .sub-header-block.no-bottom-space = render "form" diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index a03f117291..5242021243 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -2,7 +2,7 @@ - page_title "Environments" = render "projects/pipelines/head" -%div{ class: (container_class) } +%div{ class: container_class } - if can?(current_user, :create_environment, @project) && !@environments.blank? .top-area .nav-controls diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml index 4c15e2759d..53c62ef234 100644 --- a/app/views/projects/environments/show.html.haml +++ b/app/views/projects/environments/show.html.haml @@ -2,7 +2,7 @@ - page_title "Environments" = render "projects/pipelines/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area .col-md-9 %h3.page-title= @environment.name.titleize diff --git a/app/views/projects/graphs/ci.html.haml b/app/views/projects/graphs/ci.html.haml index e695d3ae36..6be4273b6a 100644 --- a/app/views/projects/graphs/ci.html.haml +++ b/app/views/projects/graphs/ci.html.haml @@ -2,7 +2,7 @@ - page_title "Continuous Integration", "Graphs" = render 'head' -%div{ class: (container_class) } +%div{ class: container_class } .sub-header-block .oneline A collection of graphs for Continuous Integration diff --git a/app/views/projects/graphs/commits.html.haml b/app/views/projects/graphs/commits.html.haml index 0daffe68f6..65db8af494 100644 --- a/app/views/projects/graphs/commits.html.haml +++ b/app/views/projects/graphs/commits.html.haml @@ -2,7 +2,7 @@ - page_title "Commits", "Graphs" = render 'head' -%div{ class: (container_class) } +%div{ class: container_class } .sub-header-block .tree-ref-holder = render 'shared/ref_switcher', destination: 'graphs_commits' diff --git a/app/views/projects/graphs/languages.html.haml b/app/views/projects/graphs/languages.html.haml index 6d97f552a8..fcfcae0be2 100644 --- a/app/views/projects/graphs/languages.html.haml +++ b/app/views/projects/graphs/languages.html.haml @@ -2,7 +2,7 @@ - page_title "Languages", "Graphs" = render 'head' -%div{ class: (container_class) } +%div{ class: container_class } .sub-header-block .oneline Programming languages used in this repository diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml index 9f7e2a361f..a985b442b2 100644 --- a/app/views/projects/graphs/show.html.haml +++ b/app/views/projects/graphs/show.html.haml @@ -2,7 +2,7 @@ - page_title "Contributors", "Graphs" = render 'head' -%div{ class: (container_class) } +%div{ class: container_class } .sub-header-block .tree-ref-holder = render 'shared/ref_switcher', destination: 'graphs' diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml index cd876b5ea6..7ce4c1e555 100644 --- a/app/views/projects/issues/index.html.haml +++ b/app/views/projects/issues/index.html.haml @@ -6,7 +6,7 @@ - if current_user = auto_discovery_link_tag(:atom, namespace_project_issues_url(@project.namespace, @project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues") -%div{ class: (container_class) } +%div{ class: container_class } .top-area = render 'shared/issuable/nav', type: :issues .nav-controls diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml index aa4d69550e..db66a0edbd 100644 --- a/app/views/projects/labels/index.html.haml +++ b/app/views/projects/labels/index.html.haml @@ -3,7 +3,7 @@ - hide_class = '' = render "projects/issues/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area.adjust .nav-text Labels can be applied to issues and merge requests. Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging. diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml index 9f948d41dd..ace275c689 100644 --- a/app/views/projects/merge_requests/index.html.haml +++ b/app/views/projects/merge_requests/index.html.haml @@ -3,7 +3,7 @@ = render "projects/issues/head" = render 'projects/last_push' -%div{ class: (container_class) } +%div{ class: container_class } .top-area = render 'shared/issuable/nav', type: :merge_requests .nav-controls diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml index b0e0bdfff5..ad2bfbec91 100644 --- a/app/views/projects/milestones/index.html.haml +++ b/app/views/projects/milestones/index.html.haml @@ -2,7 +2,7 @@ - page_title "Milestones" = render "projects/issues/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area = render 'shared/milestones_filter' diff --git a/app/views/projects/network/_head.html.haml b/app/views/projects/network/_head.html.haml index 86295a3d01..8f6805268d 100644 --- a/app/views/projects/network/_head.html.haml +++ b/app/views/projects/network/_head.html.haml @@ -1,6 +1,6 @@ - @no_container = true -%div{ class: (container_class) } +%div{ class: container_class } .row-content-block.second-block.content-component-block .tree-ref-holder = render partial: 'shared/ref_switcher', locals: {destination: 'graph'} diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml index 3ca30b4ba6..091af4df4a 100644 --- a/app/views/projects/network/show.html.haml +++ b/app/views/projects/network/show.html.haml @@ -4,7 +4,7 @@ = page_specific_javascript_tag('network/application.js') = render "projects/commits/head" = render "head" -%div{ class: (container_class) } +%div{ class: container_class } .project-network .controls = form_tag namespace_project_network_path(@project.namespace, @project, @id), method: :get, class: 'form-inline network-form' do |f| diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml index b70693eeb6..28b475d5c2 100644 --- a/app/views/projects/pipelines/index.html.haml +++ b/app/views/projects/pipelines/index.html.haml @@ -2,7 +2,7 @@ - page_title "Pipelines" = render "projects/pipelines/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area %ul.nav-links %li{class: ('active' if @scope.nil?)} diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 15f0d85194..f6e81af263 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -13,7 +13,7 @@ = render "home_panel" .project-stats.row-content-block.second-block - %div{ class: (container_class) } + %div{ class: container_class } %ul.nav %li = link_to project_files_path(@project) do diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml index 4ca1f58ac5..c375bb6dd1 100644 --- a/app/views/projects/tags/index.html.haml +++ b/app/views/projects/tags/index.html.haml @@ -2,7 +2,7 @@ - page_title "Tags" = render "projects/commits/head" -%div{ class: (container_class) } +%div{ class: container_class } .top-area .nav-text Tags give the ability to mark specific points in history as being important @@ -25,7 +25,7 @@ = sort_title_oldest_updated .tags - - unless @tags.empty? + - if @tags.any? %ul.content-list = render partial: 'tag', collection: @tags diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml index 2abcfcdd7b..bf5360b4de 100644 --- a/app/views/projects/tree/show.html.haml +++ b/app/views/projects/tree/show.html.haml @@ -7,7 +7,7 @@ = render 'projects/last_push' = render "projects/commits/head" -%div{ class: (container_class) } +%div{ class: container_class } .tree-controls = render 'projects/find_file_link' - if can? current_user, :download_code, @project diff --git a/app/views/projects/wikis/_new.html.haml b/app/views/projects/wikis/_new.html.haml index 4f8abcdc8e..c32cb122c2 100644 --- a/app/views/projects/wikis/_new.html.haml +++ b/app/views/projects/wikis/_new.html.haml @@ -1,6 +1,6 @@ - @no_container = true -%div{ class: (container_class) } +%div{ class: container_class } %div#modal-new-wiki.modal .modal-dialog .modal-content diff --git a/app/views/projects/wikis/edit.html.haml b/app/views/projects/wikis/edit.html.haml index 817bf9b3f6..233538bb48 100644 --- a/app/views/projects/wikis/edit.html.haml +++ b/app/views/projects/wikis/edit.html.haml @@ -2,7 +2,7 @@ - page_title "Edit", @page.title.capitalize, "Wiki" = render 'nav' -%div{ class: (container_class) } +%div{ class: container_class } .top-area .nav-text %strong diff --git a/app/views/projects/wikis/git_access.html.haml b/app/views/projects/wikis/git_access.html.haml index 6caf7230f3..b8811a28dd 100644 --- a/app/views/projects/wikis/git_access.html.haml +++ b/app/views/projects/wikis/git_access.html.haml @@ -2,7 +2,7 @@ - page_title "Git Access", "Wiki" = render 'nav' -%div{ class: (container_class) } +%div{ class: container_class } .sub-header-block %span.oneline Git access for diff --git a/app/views/projects/wikis/history.html.haml b/app/views/projects/wikis/history.html.haml index 630ee35b70..4c0b14e2c4 100644 --- a/app/views/projects/wikis/history.html.haml +++ b/app/views/projects/wikis/history.html.haml @@ -1,6 +1,6 @@ - page_title "History", @page.title.capitalize, "Wiki" = render 'nav' -%div{ class: (container_class) } +%div{ class: container_class } .top-area .nav-text %strong diff --git a/app/views/projects/wikis/pages.html.haml b/app/views/projects/wikis/pages.html.haml index 81d9f391c1..9c10acd4cb 100644 --- a/app/views/projects/wikis/pages.html.haml +++ b/app/views/projects/wikis/pages.html.haml @@ -3,7 +3,7 @@ = render 'nav' -%div{ class: (container_class) } +%div{ class: container_class } %ul.content-list - @wiki_pages.each do |wiki_page| %li diff --git a/app/views/projects/wikis/show.html.haml b/app/views/projects/wikis/show.html.haml index 76f9b1ecd7..5cebb538cf 100644 --- a/app/views/projects/wikis/show.html.haml +++ b/app/views/projects/wikis/show.html.haml @@ -2,7 +2,7 @@ - page_title @page.title.capitalize, "Wiki" = render 'nav' -%div{ class: (container_class) } +%div{ class: container_class } .top-area .nav-text %strong= @page.title.capitalize From 59413153f574c939ca9652d9684410a9608a93c2 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 30 Jun 2016 21:26:50 +0800 Subject: [PATCH 56/98] Use warning for locked runners: Feedback from: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4961#note_12794221 --- app/views/admin/runners/_runner.html.haml | 2 +- app/views/admin/runners/index.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/admin/runners/_runner.html.haml b/app/views/admin/runners/_runner.html.haml index 875fa086db..64893b38c5 100644 --- a/app/views/admin/runners/_runner.html.haml +++ b/app/views/admin/runners/_runner.html.haml @@ -5,7 +5,7 @@ - else %span.label.label-info specific - if runner.locked? - %span.label.label-danger locked + %span.label.label-warning locked - unless runner.active? %span.label.label-danger paused diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml index 24b2312d20..b5c6b5effe 100644 --- a/app/views/admin/runners/index.html.haml +++ b/app/views/admin/runners/index.html.haml @@ -40,7 +40,7 @@ %span.label.label-info specific \- run builds from assigned projects %li - %span.label.label-danger locked + %span.label.label-warning locked \- runner cannot be assigned to other projects %li %span.label.label-danger paused From 63477fd27f3eeff5d5f612b27ed71c76926934d2 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 30 Jun 2016 21:38:29 +0800 Subject: [PATCH 57/98] Disable Metrics/CyclomaticComplexity for Ability.allowed There's little point to cut that down. --- app/models/ability.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/ability.rb b/app/models/ability.rb index 0add2f5a34..ba1f2ae407 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -1,5 +1,6 @@ class Ability class << self + # rubocop: disable Metrics/CyclomaticComplexity def allowed(user, subject) return anonymous_abilities(user, subject) if user.nil? return [] unless user.is_a?(User) From 5fe85bc8cae98d6996907fd5ce86760b72319306 Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Tue, 28 Jun 2016 11:39:29 +0200 Subject: [PATCH 58/98] Expire branch/tag git data when needed. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When pushing commits to existing branches we don’t need to flush branch git data (branch names / counts) When flushes the cache when pushing commits skip to flush branch and tag git data (names / counts) because those operations are managed explicitly in each case Repopulated expired cache as soon as possible --- CHANGELOG | 1 + app/models/repository.rb | 16 +++++----- spec/models/repository_spec.rb | 14 +++++---- spec/services/git_push_service_spec.rb | 36 ++++++++++++++++++++++ spec/services/git_tag_push_service_spec.rb | 25 +++++++++++++++ 5 files changed, 78 insertions(+), 14 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4fbffb4143..38bcbbb024 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -21,6 +21,7 @@ v 8.10.0 (unreleased) - PipelinesFinder uses git cache data - Check for conflicts with existing Project's wiki path when creating a new project. - Remove unused front-end variable -> default_issues_tracker + - Better caching of git calls on ProjectsController#show. - Add API endpoint for a group issues !4520 (mahcsig) - Add Bugzilla integration !4930 (iamtjg) - Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w) diff --git a/app/models/repository.rb b/app/models/repository.rb index f45c3d06ab..eb232ea681 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -246,24 +246,26 @@ class Repository end end + # Keys for data that can be affected for any commit push. def cache_keys - %i(size branch_names tag_names branch_count tag_count commit_count + %i(size commit_count readme version contribution_guide changelog license_blob license_key gitignore) end + # Keys for data on branch/tag operations. + def cache_keys_for_branches_and_tags + %i(branch_names tag_names branch_count tag_count) + end + def build_cache - cache_keys.each do |key| + (cache_keys + cache_keys_for_branches_and_tags).each do |key| unless cache.exist?(key) send(key) end end end - def expire_gitignore - cache.expire(:gitignore) - end - def expire_tags_cache cache.expire(:tag_names) @tags = nil @@ -286,8 +288,6 @@ class Repository # This ensures this particular cache is flushed after the first commit to a # new repository. expire_emptiness_caches if empty? - expire_branch_count_cache - expire_tag_count_cache end def expire_branch_cache(branch_name = nil) diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index d8350000bf..8ae083d713 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -531,8 +531,6 @@ describe Repository, models: true do describe '#expire_cache' do it 'expires all caches' do expect(repository).to receive(:expire_branch_cache) - expect(repository).to receive(:expire_branch_count_cache) - expect(repository).to receive(:expire_tag_count_cache) repository.expire_cache end @@ -1055,12 +1053,14 @@ describe Repository, models: true do let(:cache) { repository.send(:cache) } it 'builds the caches if they do not already exist' do + cache_keys = repository.cache_keys + repository.cache_keys_for_branches_and_tags + expect(cache).to receive(:exist?). - exactly(repository.cache_keys.length). + exactly(cache_keys.length). times. and_return(false) - repository.cache_keys.each do |key| + cache_keys.each do |key| expect(repository).to receive(key) end @@ -1068,12 +1068,14 @@ describe Repository, models: true do end it 'does not build any caches that already exist' do + cache_keys = repository.cache_keys + repository.cache_keys_for_branches_and_tags + expect(cache).to receive(:exist?). - exactly(repository.cache_keys.length). + exactly(cache_keys.length). times. and_return(true) - repository.cache_keys.each do |key| + cache_keys.each do |key| expect(repository).not_to receive(key) end diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index f99ad046f0..1ceb7c3e6f 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -40,6 +40,18 @@ describe GitPushService, services: true do subject end + + it 'flushes the branches cache' do + expect(project.repository).to receive(:expire_branches_cache) + + subject + end + + it 'flushes the branch count cache' do + expect(project.repository).to receive(:expire_branch_count_cache) + + subject + end end context 'existing branch' do @@ -52,6 +64,18 @@ describe GitPushService, services: true do subject end + + it 'does not flush the branches cache' do + expect(project.repository).not_to receive(:expire_branches_cache) + + subject + end + + it 'does not flush the branch count cache' do + expect(project.repository).not_to receive(:expire_branch_count_cache) + + subject + end end context 'rm branch' do @@ -66,6 +90,18 @@ describe GitPushService, services: true do subject end + it 'flushes the branches cache' do + expect(project.repository).to receive(:expire_branches_cache) + + subject + end + + it 'flushes the branch count cache' do + expect(project.repository).to receive(:expire_branch_count_cache) + + subject + end + it 'flushes general cached data' do expect(project.repository).to receive(:expire_cache). with('master', newrev) diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb index a63656e626..a4fcd44882 100644 --- a/spec/services/git_tag_push_service_spec.rb +++ b/spec/services/git_tag_push_service_spec.rb @@ -11,6 +11,31 @@ describe GitTagPushService, services: true do let(:newrev) { "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b" } # gitlab-test: git rev-parse refs/tags/v1.1.0 let(:ref) { 'refs/tags/v1.1.0' } + describe "Push tags" do + subject do + service.execute + service + end + + it 'flushes general cached data' do + expect(project.repository).to receive(:expire_cache) + + subject + end + + it 'flushes the tags cache' do + expect(project.repository).to receive(:expire_tags_cache) + + subject + end + + it 'flushes the tag count cache' do + expect(project.repository).to receive(:expire_tag_count_cache) + + subject + end + end + describe "Git Tag Push Data" do before do service.execute From 805b9a834708a46d52a6dbad48b881a21a3cad1e Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 30 Jun 2016 16:06:31 +0100 Subject: [PATCH 59/98] Updated breakpoint for sidebar pinning --- app/assets/javascripts/application.js.coffee | 2 +- app/assets/stylesheets/framework/variables.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee index 05080d50ce..20fe5a5cc2 100644 --- a/app/assets/javascripts/application.js.coffee +++ b/app/assets/javascripts/application.js.coffee @@ -269,7 +269,7 @@ $ -> new Aside() # Sidenav pinning - if $window.width() < 1280 and $.cookie('pin_nav') is 'true' + if $window.width() < 1024 and $.cookie('pin_nav') is 'true' $.cookie('pin_nav', 'false', { path: '/', expires: 365 * 10 }) $('.page-with-sidebar') .toggleClass('page-sidebar-collapsed page-sidebar-expanded') diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 87f8a17659..211a9af234 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -7,7 +7,7 @@ $gutter_collapsed_width: 62px; $gutter_width: 290px; $gutter_inner_width: 258px; $sidebar-transition-duration: .15s; -$sidebar-breakpoint: 1280px; +$sidebar-breakpoint: 1024px; /* * UI elements From e8a8b0b818c96934ad1f2326053efa4d31c8850e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Thu, 30 Jun 2016 11:52:38 -0400 Subject: [PATCH 60/98] Remove hardcoded gitlab-shell version in test env now that the required tag is published --- spec/support/test_env.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index be5331e477..9f9ef20f99 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -81,8 +81,7 @@ module TestEnv def setup_gitlab_shell unless File.directory?(Gitlab.config.gitlab_shell.path) - # TODO: Remove `[shards]` when gitlab-shell v3.1.0 is published - `rake gitlab:shell:install[shards]` + `rake gitlab:shell:install` end end From 12aa1f898dbfea3aaeb2de351ac1cccef304717f Mon Sep 17 00:00:00 2001 From: Eric K Idema Date: Mon, 2 May 2016 11:22:38 -0400 Subject: [PATCH 61/98] Import from Github using Personal Access Tokens. This stands as an alternative to using OAuth to access a user's Github repositories. This is setup in such a way that it can be used without OAuth configuration. From a UI perspective, the how to import modal has been replaced by a full page, which includes a form for posting a personal access token back to the Import::GithubController. If the user has logged in via GitHub, skip the Personal Access Token and go directly to Github for an access token via OAuth. --- app/controllers/import/github_controller.rb | 25 ++++++++-- app/views/import/github/new.html.haml | 37 +++++++++++++++ .../projects/_github_import_modal.html.haml | 13 ----- app/views/projects/new.html.haml | 12 ++--- config/initializers/rack_attack.rb.example | 3 +- config/routes.rb | 1 + .../importing/import_projects_from_github.md | 16 +++++-- features/dashboard/new_project.feature | 2 +- features/steps/dashboard/new_project.rb | 10 +--- lib/gitlab/github_import/client.rb | 47 +++++++++++++------ .../import/github_controller_spec.rb | 43 +++++++++++++++++ spec/lib/gitlab/github_import/client_spec.rb | 14 ++++++ 12 files changed, 168 insertions(+), 55 deletions(-) create mode 100644 app/views/import/github/new.html.haml delete mode 100644 app/views/projects/_github_import_modal.html.haml diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb index 67bf4190e7..95852c6941 100644 --- a/app/controllers/import/github_controller.rb +++ b/app/controllers/import/github_controller.rb @@ -1,14 +1,29 @@ class Import::GithubController < Import::BaseController before_action :verify_github_import_enabled - before_action :github_auth, except: :callback + before_action :github_auth, except: [:callback, :new, :personal_access_token] rescue_from Octokit::Unauthorized, with: :github_unauthorized + helper_method :logged_in_with_github? + + def new + if logged_in_with_github? + go_to_github_for_permissions + elsif session[:github_access_token] + redirect_to status_import_github_url + end + end + def callback session[:github_access_token] = client.get_token(params[:code]) redirect_to status_import_github_url end + def personal_access_token + session[:github_access_token] = params[:personal_access_token] + redirect_to status_import_github_url + end + def status @repos = client.repos @already_added_projects = current_user.created_projects.where(import_type: "github") @@ -57,10 +72,14 @@ class Import::GithubController < Import::BaseController end def github_unauthorized - go_to_github_for_permissions + session[:github_access_token] = nil + redirect_to new_import_github_url, + alert: 'Access denied to your GitHub account.' end - private + def logged_in_with_github? + current_user.identities.exists?(provider: 'github') + end def access_params { github_access_token: session[:github_access_token] } diff --git a/app/views/import/github/new.html.haml b/app/views/import/github/new.html.haml new file mode 100644 index 0000000000..b071d2214c --- /dev/null +++ b/app/views/import/github/new.html.haml @@ -0,0 +1,37 @@ +- page_title "GitHub Import" +- header_title "Projects", root_path + +%h3.page-title + = icon 'github', text: 'Import Projects from GitHub' + +%p.light + To import a project from GitHub, you can use a + = link_to 'Personal Access Token', 'https://github.com/settings/tokens' + to access your GitHub account. When you create your Personal Access Token, + you will need to select the repo scope, so we can display a + list of your public and private repositories which are available for import. + += form_tag personal_access_token_import_github_path, method: :post, class: 'form-inline' do + .form-group + = text_field_tag :personal_access_token, '', class: 'form-control', placeholder: "Personal Access Token", size: 40 + = submit_tag 'List Repositories', class: 'btn btn-create' + +- if github_import_configured? + - unless logged_in_with_github? + %hr + %p.light + Note: If you go to + = link_to 'your profile', profile_account_path + and connect your account to GitHub, you can import projects without + generating a Personal Access Token. +- else + %hr + %p.light + Note: + - if current_user.admin? + As an administrator you may like to configure + - else + Consider asking your GitLab administrator to configure + = link_to 'GitHub integration', help_page_path("integration", "github") + which will allow login via GitHub and allow importing projects without + generating a Personal Access Token. diff --git a/app/views/projects/_github_import_modal.html.haml b/app/views/projects/_github_import_modal.html.haml deleted file mode 100644 index 46ad155935..0000000000 --- a/app/views/projects/_github_import_modal.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -%div#github_import_modal.modal - .modal-dialog - .modal-content - .modal-header - %a.close{href: "#", "data-dismiss" => "modal"} × - %h3 Import projects from GitHub - .modal-body - To enable importing projects from GitHub, - - if current_user.admin? - as administrator you need to configure - - else - ask your Gitlab administrator to configure - == #{link_to 'OAuth integration', help_page_path("integration", "github")}. diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 8a73b07735..05f33b78a4 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -23,6 +23,7 @@ .input-group-addon = root_url = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user, display_path: true), {}, {class: 'select2 js-select-namespace', tabindex: 1} + - else .input-group-addon.static-namespace #{root_url}#{current_user.username}/ @@ -44,15 +45,8 @@ .col-sm-12.import-buttons %div - if github_import_enabled? - - if github_import_configured? - = link_to status_import_github_path, class: 'btn import_github' do - %i.fa.fa-github - GitHub - - else - = link_to '#', class: 'how_to_import_link btn import_github' do - %i.fa.fa-github - GitHub - = render 'github_import_modal' + = link_to new_import_github_path, class: 'btn import_github' do + = icon 'github', text: 'GitHub' %div - if bitbucket_import_enabled? - if bitbucket_import_configured? diff --git a/config/initializers/rack_attack.rb.example b/config/initializers/rack_attack.rb.example index 30d05f1615..69052c029f 100644 --- a/config/initializers/rack_attack.rb.example +++ b/config/initializers/rack_attack.rb.example @@ -10,7 +10,8 @@ paths_to_be_protected = [ "#{Rails.application.config.relative_url_root}/api/#{API::API.version}/session", "#{Rails.application.config.relative_url_root}/users", "#{Rails.application.config.relative_url_root}/users/confirmation", - "#{Rails.application.config.relative_url_root}/unsubscribes/" + "#{Rails.application.config.relative_url_root}/unsubscribes/", + "#{Rails.application.config.relative_url_root}/import/github/personal_access_token" ] diff --git a/config/routes.rb b/config/routes.rb index 2aab73720f..c04780fec8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -139,6 +139,7 @@ Rails.application.routes.draw do # namespace :import do resource :github, only: [:create, :new], controller: :github do + post :personal_access_token get :status get :callback get :jobs diff --git a/doc/workflow/importing/import_projects_from_github.md b/doc/workflow/importing/import_projects_from_github.md index a7dfac2c12..60894d52a7 100644 --- a/doc/workflow/importing/import_projects_from_github.md +++ b/doc/workflow/importing/import_projects_from_github.md @@ -1,8 +1,10 @@ # Import your project from GitHub to GitLab >**Note:** -In order to enable the GitHub import setting, you should first -enable the [GitHub integration][gh-import] in your GitLab instance. +In order to enable the GitHub import setting, you may also want to +enable the [GitHub integration][gh-import] in your GitLab instance. This +configuration is optional, you will be able import your GitHub repositories +with a Personal Access Token. At its current state, GitHub importer can import: @@ -20,9 +22,13 @@ It is not yet possible to import your cross-repository pull requests (those from forks). We are working on improving this in the near future. 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 **GitHub** link and, if you are logged in via the GitHub +integration, you will be redirected to GitHub for permission to access your +projects. After accepting, you'll be automatically redirected to the importer. + +If you are not using the GitHub integration, when you click the **GithHub** link +you'll be presented with instructions for creating Personal Access Token on +GitHub. Once you upload your token, you'll be taken to the importer. ![New project page on GitLab](img/import_projects_from_github_new_project_page.png) diff --git a/features/dashboard/new_project.feature b/features/dashboard/new_project.feature index 56b4a639c0..32c88965bc 100644 --- a/features/dashboard/new_project.feature +++ b/features/dashboard/new_project.feature @@ -21,7 +21,7 @@ Background: Scenario: I should see instructions on how to import from GitHub Given I see "New Project" page When I click on "Import project from GitHub" - Then I see instructions on how to import from GitHub + Then I am redirected to the Github import page @javascript Scenario: I should see Google Code import page diff --git a/features/steps/dashboard/new_project.rb b/features/steps/dashboard/new_project.rb index 31f8924c38..0bd621da0f 100644 --- a/features/steps/dashboard/new_project.rb +++ b/features/steps/dashboard/new_project.rb @@ -28,14 +28,8 @@ class Spinach::Features::NewProject < Spinach::FeatureSteps first('.import_github').click end - step 'I see instructions on how to import from GitHub' do - github_modal = first('.modal-body') - expect(github_modal).to be_visible - expect(github_modal).to have_content "To enable importing projects from GitHub" - - page.all('.modal-body').each do |element| - expect(element).not_to be_visible unless element == github_modal - end + step 'I am redirected to the Github import page' do + expect(current_path).to eq new_import_github_path end step 'I click on "Repo by URL"' do diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb index d325eca6d9..043f10d96a 100644 --- a/lib/gitlab/github_import/client.rb +++ b/lib/gitlab/github_import/client.rb @@ -4,26 +4,39 @@ module Gitlab GITHUB_SAFE_REMAINING_REQUESTS = 100 GITHUB_SAFE_SLEEP_TIME = 500 - attr_reader :client, :api + attr_reader :access_token def initialize(access_token) - @client = ::OAuth2::Client.new( + @access_token = access_token + + if access_token + ::Octokit.auto_paginate = false + end + end + + def api + @api ||= ::Octokit::Client.new( + access_token: access_token, + api_endpoint: github_options[:site], + # If there is no config, we're connecting to github.com and we + # should verify ssl. + connection_options: { + ssl: { verify: config ? config['verify_ssl'] : true } + } + ) + end + + def client + unless config + raise Projects::ImportService::Error, + 'OAuth configuration for GitHub missing.' + end + + @client ||= ::OAuth2::Client.new( config.app_id, config.app_secret, github_options.merge(ssl: { verify: config['verify_ssl'] }) ) - - if access_token - ::Octokit.auto_paginate = false - - @api = ::Octokit::Client.new( - access_token: access_token, - api_endpoint: github_options[:site], - connection_options: { - ssl: { verify: config['verify_ssl'] } - } - ) - end end def authorize_url(redirect_uri) @@ -56,7 +69,11 @@ module Gitlab end def github_options - config["args"]["client_options"].deep_symbolize_keys + if config + config["args"]["client_options"].deep_symbolize_keys + else + OmniAuth::Strategies::GitHub.default_options[:client_options].symbolize_keys + end end def rate_limit diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb index c55a3c2820..51d5952685 100644 --- a/spec/controllers/import/github_controller_spec.rb +++ b/spec/controllers/import/github_controller_spec.rb @@ -16,6 +16,24 @@ describe Import::GithubController do allow(controller).to receive(:github_import_enabled?).and_return(true) end + describe "GET new" do + it "redirects to GitHub for an access token if logged in with GitHub" do + allow(controller).to receive(:logged_in_with_github?).and_return(true) + expect(controller).to receive(:go_to_github_for_permissions) + + get :new + end + + it "redirects to status if we already have a token" do + assign_session_token + allow(controller).to receive(:logged_in_with_github?).and_return(false) + + get :new + + expect(controller).to redirect_to(status_import_github_url) + end + end + describe "GET callback" do it "updates access token" do token = "asdasd12345" @@ -32,6 +50,20 @@ describe Import::GithubController do end end + describe "POST personal_access_token" do + it "updates access token" do + token = "asdfasdf9876" + + allow_any_instance_of(Gitlab::GithubImport::Client). + to receive(:user).and_return(true) + + post :personal_access_token, personal_access_token: token + + expect(session[:github_access_token]).to eq(token) + expect(controller).to redirect_to(status_import_github_url) + end + end + describe "GET status" do before do @repo = OpenStruct.new(login: 'vim', full_name: 'asd/vim') @@ -59,6 +91,17 @@ describe Import::GithubController do expect(assigns(:already_added_projects)).to eq([@project]) expect(assigns(:repos)).to eq([]) end + + it "handles an invalid access token" do + allow_any_instance_of(Gitlab::GithubImport::Client). + to receive(:repos).and_raise(Octokit::Unauthorized) + + get :status + + expect(session[:github_access_token]).to eq(nil) + expect(controller).to redirect_to(new_import_github_url) + expect(flash[:alert]).to eq('Access denied to your GitHub account.') + end end describe "POST create" do diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb index 7c21cbe96d..3b023a3544 100644 --- a/spec/lib/gitlab/github_import/client_spec.rb +++ b/spec/lib/gitlab/github_import/client_spec.rb @@ -20,6 +20,20 @@ describe Gitlab::GithubImport::Client, lib: true do expect { client.api }.not_to raise_error end + context 'when config is missing' do + before do + allow(Gitlab.config.omniauth).to receive(:providers).and_return([]) + end + + it 'is still possible to get an Octokit client' do + expect { client.api }.not_to raise_error + end + + it 'is not be possible to get an OAuth2 client' do + expect { client.client }.to raise_error(Projects::ImportService::Error) + end + end + context 'allow SSL verification to be configurable on API' do before do github_provider['verify_ssl'] = false From ce6635406c8e2e4d336d6d7738a1e4916036871c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 27 Jun 2016 13:42:22 +0200 Subject: [PATCH 62/98] Make GH one-off auth the default again for importing GH projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Advertise the PAT as an alternative unless GH import is not configured. Signed-off-by: Rémy Coutable --- CHANGELOG | 1 + app/controllers/import/github_controller.rb | 2 +- app/views/import/github/new.html.haml | 36 +++++++++++-------- .../importing/import_projects_from_github.md | 8 +++-- features/dashboard/new_project.feature | 2 +- features/steps/dashboard/new_project.rb | 2 +- 6 files changed, 30 insertions(+), 21 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 52329ef928..b954cb3838 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,6 +18,7 @@ v 8.10.0 (unreleased) - Exclude email check from the standard health check - Fix changing issue state columns in milestone view - Add notification settings dropdown for groups + - Allow importing from Github using Personal Access Tokens. (Eric K Idema) - Fix user creation with stronger minimum password requirements !4054 (nathan-pmt) - PipelinesFinder uses git cache data - Check for conflicts with existing Project's wiki path when creating a new project. diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb index 95852c6941..9c1b0eb20f 100644 --- a/app/controllers/import/github_controller.rb +++ b/app/controllers/import/github_controller.rb @@ -1,6 +1,6 @@ class Import::GithubController < Import::BaseController before_action :verify_github_import_enabled - before_action :github_auth, except: [:callback, :new, :personal_access_token] + before_action :github_auth, only: [:status, :jobs, :create] rescue_from Octokit::Unauthorized, with: :github_unauthorized diff --git a/app/views/import/github/new.html.haml b/app/views/import/github/new.html.haml index b071d2214c..435ed7bd4c 100644 --- a/app/views/import/github/new.html.haml +++ b/app/views/import/github/new.html.haml @@ -4,29 +4,35 @@ %h3.page-title = icon 'github', text: 'Import Projects from GitHub' -%p.light - To import a project from GitHub, you can use a - = link_to 'Personal Access Token', 'https://github.com/settings/tokens' - to access your GitHub account. When you create your Personal Access Token, +- if github_import_configured? + %p + To import a GitHub project, you first need to authorize GitLab to access + the list of your GitHub repositories: + + = link_to 'List Your GitHub Repositories', status_import_github_path, class: 'btn btn-success' + + %hr + +%p + - if github_import_configured? + Alternatively, + - else + To import a GitHub project, + you can use a + = succeed '.' do + = link_to 'Personal Access Token', 'https://github.com/settings/tokens' + When you create your Personal Access Token, you will need to select the repo scope, so we can display a list of your public and private repositories which are available for import. = form_tag personal_access_token_import_github_path, method: :post, class: 'form-inline' do .form-group = text_field_tag :personal_access_token, '', class: 'form-control', placeholder: "Personal Access Token", size: 40 - = submit_tag 'List Repositories', class: 'btn btn-create' + = submit_tag 'List Your GitHub Repositories', class: 'btn btn-success' -- if github_import_configured? - - unless logged_in_with_github? - %hr - %p.light - Note: If you go to - = link_to 'your profile', profile_account_path - and connect your account to GitHub, you can import projects without - generating a Personal Access Token. -- else +- unless github_import_configured? %hr - %p.light + %p Note: - if current_user.admin? As an administrator you may like to configure diff --git a/doc/workflow/importing/import_projects_from_github.md b/doc/workflow/importing/import_projects_from_github.md index 60894d52a7..a2b2a4b88f 100644 --- a/doc/workflow/importing/import_projects_from_github.md +++ b/doc/workflow/importing/import_projects_from_github.md @@ -26,9 +26,11 @@ Click on the **GitHub** link and, if you are logged in via the GitHub integration, you will be redirected to GitHub for permission to access your projects. After accepting, you'll be automatically redirected to the importer. -If you are not using the GitHub integration, when you click the **GithHub** link -you'll be presented with instructions for creating Personal Access Token on -GitHub. Once you upload your token, you'll be taken to the importer. +If you are not using the GitHub integration, you can still perform a one-off +authorization with GitHub to access your projects. + +Alternatively, you can also enter a GitHub Personal Access Token. Once you enter +your token, you'll be taken to the importer. ![New project page on GitLab](img/import_projects_from_github_new_project_page.png) diff --git a/features/dashboard/new_project.feature b/features/dashboard/new_project.feature index 32c88965bc..8ddafb6a7a 100644 --- a/features/dashboard/new_project.feature +++ b/features/dashboard/new_project.feature @@ -21,7 +21,7 @@ Background: Scenario: I should see instructions on how to import from GitHub Given I see "New Project" page When I click on "Import project from GitHub" - Then I am redirected to the Github import page + Then I am redirected to the GitHub import page @javascript Scenario: I should see Google Code import page diff --git a/features/steps/dashboard/new_project.rb b/features/steps/dashboard/new_project.rb index 0bd621da0f..09373168da 100644 --- a/features/steps/dashboard/new_project.rb +++ b/features/steps/dashboard/new_project.rb @@ -28,7 +28,7 @@ class Spinach::Features::NewProject < Spinach::FeatureSteps first('.import_github').click end - step 'I am redirected to the Github import page' do + step 'I am redirected to the GitHub import page' do expect(current_path).to eq new_import_github_path end From 422eca27eebb6ddf625170a84b0fccf0ce30f348 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Thu, 30 Jun 2016 19:20:36 +0200 Subject: [PATCH 63/98] Remove coveralls lines --- features/support/env.rb | 5 ----- spec/spec_helper.rb | 5 ----- 2 files changed, 10 deletions(-) diff --git a/features/support/env.rb b/features/support/env.rb index edc08cf098..ab3f0ca7ae 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -2,11 +2,6 @@ if ENV['SIMPLECOV'] require 'simplecov' end -if ENV['COVERALLS'] - require 'coveralls' - Coveralls.wear_merged! -end - ENV['RAILS_ENV'] = 'test' require './config/environment' require 'rspec/expectations' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b43f38ef20..606da1b760 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -3,11 +3,6 @@ if ENV['SIMPLECOV'] SimpleCov.start :rails end -if ENV['COVERALLS'] - require 'coveralls' - Coveralls.wear_merged! -end - ENV["RAILS_ENV"] ||= 'test' require File.expand_path("../../config/environment", __FILE__) From 7dbc3d97d1b4706fa7bc92dc7f89c33e7a1cee01 Mon Sep 17 00:00:00 2001 From: Josh Frye Date: Thu, 30 Jun 2016 09:47:24 -0400 Subject: [PATCH 64/98] Catch permission denied errors and ignore the disk --- .../admin/system_info_controller.rb | 49 ++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/app/controllers/admin/system_info_controller.rb b/app/controllers/admin/system_info_controller.rb index cc63009cdc..e4c7300882 100644 --- a/app/controllers/admin/system_info_controller.rb +++ b/app/controllers/admin/system_info_controller.rb @@ -1,27 +1,54 @@ class Admin::SystemInfoController < Admin::ApplicationController - def show - excluded_mounts = [ - "nobrowse", - "read-only", - "ro" - ] + EXCLUDED_MOUNT_OPTIONS = [ + 'nobrowse', + 'read-only', + 'ro' + ] + EXCLUDED_MOUNT_TYPES = [ + 'autofs', + 'binfmt_misc', + 'cgroup', + 'debugfs', + 'devfs', + 'devpts', + 'devtmpfs', + 'efivarfs', + 'fuse.gvfsd-fuse', + 'fuseblk', + 'fusectl', + 'hugetlbfs', + 'mqueue', + 'proc', + 'pstore', + 'securityfs', + 'sysfs', + 'tmpfs', + 'tracefs', + 'vfat' + ] + + def show system_info = Vmstat.snapshot mounts = Sys::Filesystem.mounts @disks = [] mounts.each do |mount| - options = mount.options.split(', ') + mount_options = mount.options.split(',') - next unless excluded_mounts.each { |em| break if options.include?(em) } + next if (EXCLUDED_MOUNT_OPTIONS & mount_options).any? + next if (EXCLUDED_MOUNT_TYPES & [mount.mount_type]).any? - disk = Sys::Filesystem.stat(mount.mount_point) - @disks.push({ + begin + disk = Sys::Filesystem.stat(mount.mount_point) + @disks.push({ bytes_total: disk.bytes_total, bytes_used: disk.bytes_used, disk_name: mount.name, mount_path: disk.path - }) + }) + rescue Sys::Filesystem::Error + end end @cpus = system_info.cpus.length From 9418d1bf6b71984ffabb04b30206be9e49e110de Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Thu, 30 Jun 2016 14:35:00 -0500 Subject: [PATCH 65/98] Remove additional entries from CHANGELOG --- CHANGELOG | 3 --- 1 file changed, 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 1d83894b42..241b076b20 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -49,10 +49,7 @@ v 8.9.3 - Fix missing avatar on system notes. !4954 - Reduce overhead and optimize ProjectTeam#max_member_access performance. !4973 - Use update_columns to by_pass all the dirty code on active_record. !4985 - - Decreased min width of screen to 1280px for pinned sidebar - Fix restore Rake task warning message output !4980 - - Fix encrypted data backwards compatibility after upgrading attr_encrypted gem - - Update mobile button icons to be more inline with typical UI paradigms v 8.9.2 - Fix visibility of snippets when searching. From 3041c43380ba6e5d8bbc029a9dcfecfdcf7bcf47 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 30 Jun 2016 16:34:05 -0400 Subject: [PATCH 66/98] Update CHANGELOG for 8.9.4, 8.8.7, and 8.7.9. [ci skip] --- CHANGELOG | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 241b076b20..4b754c2aba 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -29,10 +29,19 @@ v 8.10.0 (unreleased) - Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w) - Add basic system information like memory and disk usage to the admin panel -v 8.9.4 (unreleased) - - Do not show build retry link in build sidebar when build is not finished yet - - Fixes middle click and double request when navigating through the file browser !4891 - - Add sub nav to file page view +v 8.9.4 + - Fix privilege escalation issue with OAuth external users. + - Ensure references to private repos aren't shown to logged-out users. + - Fixed search field blur not removing focus. !4704 + - Resolve "Sub nav isn't showing on file view". !4890 + - Fixes middle click and double request when navigating through the file browser. !4891 + - Fixed URL on label button when filtering. !4897 + - Fixed commit avatar alignment. !4933 + - Do not show build retry link when build is active. !4967 + - Fix restore Rake task warning message output. !4980 + - Handle external issues in IssueReferenceFilter. !4988 + - Expiry date on pinned nav cookie. !5009 + - Updated breakpoint for sidebar pinning. !5019 v 8.9.3 - Fix encrypted data backwards compatibility after upgrading attr_encrypted gem. !4963 @@ -253,6 +262,10 @@ v 8.9.0 - Add tooltip to pin/unpin navbar - Add new sub nav style to Wiki and Graphs sub navigation +v 8.8.7 + - Fix privilege escalation issue with OAuth external users. + - Ensure references to private repos aren't shown to logged-out users. + v 8.8.6 - Fix visibility of snippets when searching. - Update omniauth-saml to 1.6.0 !4951 @@ -387,6 +400,10 @@ v 8.8.0 - When creating a .gitignore file a dropdown with templates will be provided - Shows the issue/MR list search/filter form and corrects the mobile styling for guest users. #17562 +v 8.7.9 + - Fix privilege escalation issue with OAuth external users. + - Ensure references to private repos aren't shown to logged-out users. + v 8.7.8 - Fix visibility of snippets when searching. - Update omniauth-saml to 1.6.0 !4951 From 44230e12bb2a7ea3d91a6a9a2bfd1543198f1b9b Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Thu, 30 Jun 2016 16:11:57 -0600 Subject: [PATCH 67/98] Upgrade Sprockets and Sprockets Rails. Upgrade Sprockets from 3.6.0 to 3.6.2. Changelog: https://github.com/rails/sprockets/blob/3.x/CHANGELOG.md Upgrade Sprockets Rails from 3.0.4 to 3.1.1. Changelog: https://github.com/rails/sprockets-rails/compare/v3.0.4...v3.1.1 --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f99b373dbb..5e5554d4fc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -700,10 +700,10 @@ GEM spring (>= 0.9.1) spring-commands-teaspoon (0.0.2) spring (>= 0.9.1) - sprockets (3.6.0) + sprockets (3.6.2) concurrent-ruby (~> 1.0) rack (> 1, < 3) - sprockets-rails (3.0.4) + sprockets-rails (3.1.1) actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) From eb70f051a6fb69542aa4436d808bf32271219da8 Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Thu, 30 Jun 2016 16:18:05 -0600 Subject: [PATCH 68/98] Remove quiet_assets in favor of built-in sprockets-rails config. quiet_assets has been seemingly abandoned, and now sprockets-rails has the feature built-in! From this PR: https://github.com/rails/sprockets-rails/pull/355 --- Gemfile | 1 - Gemfile.lock | 3 --- config/environments/development.rb | 3 +++ 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 5213a59cab..58efe6a252 100644 --- a/Gemfile +++ b/Gemfile @@ -251,7 +251,6 @@ group :development do gem 'brakeman', '~> 3.3.0', require: false gem 'letter_opener_web', '~> 1.3.0' - gem 'quiet_assets', '~> 1.0.2' gem 'rerun', '~> 0.11.0' gem 'bullet', require: false gem 'rblineprof', platform: :mri, require: false diff --git a/Gemfile.lock b/Gemfile.lock index 5e5554d4fc..b1f2c8c142 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -499,8 +499,6 @@ GEM pry-rails (0.3.4) pry (>= 0.9.10) pyu-ruby-sasl (0.0.3.3) - quiet_assets (1.0.3) - railties (>= 3.1, < 5.0) rack (1.6.4) rack-accept (0.4.5) rack (>= 0.4) @@ -920,7 +918,6 @@ DEPENDENCIES poltergeist (~> 1.9.0) premailer-rails (~> 1.9.0) pry-rails - quiet_assets (~> 1.0.2) rack-attack (~> 4.3.1) rack-cors (~> 0.4.0) rack-oauth2 (~> 1.2.1) diff --git a/config/environments/development.rb b/config/environments/development.rb index 8cca0039b4..45a8c1add3 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -42,4 +42,7 @@ Rails.application.configure do config.action_mailer.preview_path = 'spec/mailers/previews' config.eager_load = false + + # Do not log asset requests + config.assets.quiet = true end From 8f7cde0f61d743f35d6907a0b3a1fca340ed987d Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Thu, 30 Jun 2016 16:30:16 -0600 Subject: [PATCH 69/98] Upgrade sass-rails. Upgrade sass-rails from 5.0.4 to 5.0.5. Includes support for Rails 5. Changelog: https://github.com/rails/sass-rails/releases --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f99b373dbb..1bed6ea15a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -634,8 +634,8 @@ GEM sanitize (2.1.0) nokogiri (>= 1.4.4) sass (3.4.22) - sass-rails (5.0.4) - railties (>= 4.0.0, < 5.0) + sass-rails (5.0.5) + railties (>= 4.0.0, < 6) sass (~> 3.1) sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) From fe833adccd0797bb9a00c051ac718d1df3adacc4 Mon Sep 17 00:00:00 2001 From: Marcia Ramos Date: Fri, 1 Jul 2016 03:17:39 +0000 Subject: [PATCH 70/98] adding link to .gitlab-ci.yml templates - closes #18998 --- doc/ci/examples/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/ci/examples/README.md b/doc/ci/examples/README.md index 27bc21c292..c134106bfd 100644 --- a/doc/ci/examples/README.md +++ b/doc/ci/examples/README.md @@ -14,3 +14,4 @@ - [Blog post about using GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/) - [Repo's with examples for various languages](https://gitlab.com/groups/gitlab-examples) - [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml) +- [A collection of useful .gitlab-ci.yml templates](https://gitlab.com/gitlab-org/gitlab-ci-yml) From a1f224d3f7b43bf2f58917e5045dcc2bdb33964d Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Fri, 11 Mar 2016 16:04:42 -0300 Subject: [PATCH 71/98] Add Todos API --- app/models/todo.rb | 7 ++ app/views/dashboard/todos/_todo.html.haml | 2 +- lib/api/api.rb | 1 + lib/api/entities.rb | 29 ++++++ lib/api/todos.rb | 54 +++++++++++ spec/factories/todos.rb | 4 + spec/requests/api/todos_spec.rb | 107 ++++++++++++++++++++++ 7 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 lib/api/todos.rb create mode 100644 spec/requests/api/todos_spec.rb diff --git a/app/models/todo.rb b/app/models/todo.rb index 2792fa9b9a..42faecdf7f 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -34,6 +34,13 @@ class Todo < ActiveRecord::Base action == BUILD_FAILED end + def action_name + case action + when Todo::ASSIGNED then 'assigned you' + when Todo::MENTIONED then 'mentioned you on' + end + end + def body if note.present? note.note diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml index 98f302d2f9..421885eef5 100644 --- a/app/views/dashboard/todos/_todo.html.haml +++ b/app/views/dashboard/todos/_todo.html.haml @@ -11,7 +11,7 @@ - else (removed) %span.todo-label - = todo_action_name(todo) + = todo.action_name - if todo.target = todo_target_link(todo) - else diff --git a/lib/api/api.rb b/lib/api/api.rb index c3fff8b2f8..3d7d67510a 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -58,6 +58,7 @@ module API mount ::API::SystemHooks mount ::API::Tags mount ::API::Templates + mount ::API::Todos mount ::API::Triggers mount ::API::Users mount ::API::Variables diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 4e2a43e45e..171a5da642 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -56,6 +56,10 @@ module API expose :id expose :name, :name_with_namespace expose :path, :path_with_namespace + + expose :web_url do |project, options| + Gitlab::Application.routes.url_helpers.namespace_project_url(project.namespace, project) + end end class Project < Grape::Entity @@ -272,6 +276,31 @@ module API expose :id, :project_id, :group_id, :group_access end + class Todo < Grape::Entity + expose :id + expose :project, using: Entities::BasicProjectDetails + expose :author, using: Entities::UserBasic + expose :action_name + expose :target_id + expose :target_type + expose :target_reference do |todo, options| + todo.target.to_reference + end + + expose :target_url do |todo, options| + target_type = todo.target_type.underscore + target_url = "namespace_project_#{target_type}_url" + target_anchor = "note_#{todo.note_id}" if todo.note.present? + + Gitlab::Application.routes.url_helpers.public_send(target_url, + todo.project.namespace, todo.project, todo.target, anchor: target_anchor) + end + + expose :body + expose :state + expose :created_at + end + class Namespace < Grape::Entity expose :id, :path, :kind end diff --git a/lib/api/todos.rb b/lib/api/todos.rb new file mode 100644 index 0000000000..f45c0ae634 --- /dev/null +++ b/lib/api/todos.rb @@ -0,0 +1,54 @@ +module API + # Todos API + class Todos < Grape::API + before { authenticate! } + + resource :todos do + helpers do + def find_todos + TodosFinder.new(current_user, params).execute + end + end + + # Get a todo list + # + # Example Request: + # GET /todos + get do + @todos = find_todos + @todos = paginate @todos + + present @todos, with: Entities::Todo + end + + # Mark todo as done + # + # Parameters: + # id: (required) - The ID of the todo being marked as done + # + # Example Request: + # + # DELETE /todos/:id + # + delete ':id' do + @todo = current_user.todos.find(params[:id]) + @todo.done + + present @todo, with: Entities::Todo + end + + # Mark all todos as done + # + # Example Request: + # + # DELETE /todos + # + delete do + @todos = find_todos + @todos.each(&:done) + + present @todos, with: Entities::Todo + end + end + end +end diff --git a/spec/factories/todos.rb b/spec/factories/todos.rb index f426e27afe..7fc20cd555 100644 --- a/spec/factories/todos.rb +++ b/spec/factories/todos.rb @@ -22,5 +22,9 @@ FactoryGirl.define do trait :build_failed do action { Todo::BUILD_FAILED } end + + trait :done do + state :done + end end end diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb new file mode 100644 index 0000000000..20d5782867 --- /dev/null +++ b/spec/requests/api/todos_spec.rb @@ -0,0 +1,107 @@ +require 'spec_helper' + +describe API::Todos, api: true do + include ApiHelpers + + let(:project_1) { create(:project) } + let(:project_2) { create(:project) } + let(:author_1) { create(:user) } + let(:author_2) { create(:user) } + let(:john_doe) { create(:user, username: 'john_doe') } + let(:merge_request) { create(:merge_request, source_project: project_1) } + let!(:pending_1) { create(:todo, project: project_1, author: author_1, user: john_doe) } + let!(:pending_2) { create(:todo, project: project_2, author: author_2, user: john_doe) } + let!(:pending_3) { create(:todo, project: project_1, author: author_2, user: john_doe, target: merge_request) } + let!(:done) { create(:todo, :done, project: project_1, author: author_1, user: john_doe) } + + describe 'GET /todos' do + context 'when unauthenticated' do + it 'should return authentication error' do + get api('/todos') + expect(response.status).to eq(401) + end + end + + context 'when authenticated' do + it 'should return an array of pending todos for current user' do + get api('/todos', john_doe) + expect(response.status).to eq(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(3) + end + + context 'and using the author filter' do + it 'should filter based on author_id param' do + get api('/todos', john_doe), { author_id: author_2.id } + expect(response.status).to eq(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(2) + end + end + + context 'and using the type filter' do + it 'should filter based on type param' do + get api('/todos', john_doe), { type: 'MergeRequest' } + expect(response.status).to eq(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + end + end + + context 'and using the state filter' do + it 'should filter based on state param' do + get api('/todos', john_doe), { state: 'done' } + expect(response.status).to eq(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + end + end + + context 'and using the project filter' do + it 'should filter based on project_id param' do + project_2.team << [john_doe, :developer] + get api('/todos', john_doe), { project_id: project_2.id } + expect(response.status).to eq(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + end + end + end + end + + describe 'DELETE /todos/:id' do + context 'when unauthenticated' do + it 'should return authentication error' do + delete api("/todos/#{pending_1.id}") + expect(response.status).to eq(401) + end + end + + context 'when authenticated' do + it 'should mark a todo as done' do + delete api("/todos/#{pending_1.id}", john_doe) + expect(response.status).to eq(200) + expect(pending_1.reload).to be_done + end + end + end + + describe 'DELETE /todos' do + context 'when unauthenticated' do + it 'should return authentication error' do + delete api('/todos') + expect(response.status).to eq(401) + end + end + + context 'when authenticated' do + it 'should mark all todos as done' do + delete api('/todos', john_doe) + expect(response.status).to eq(200) + expect(pending_1.reload).to be_done + expect(pending_2.reload).to be_done + expect(pending_3.reload).to be_done + end + end + end +end From 25dcd051372f6426b0ca5c73a4be6b8b075a21e7 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Wed, 18 May 2016 23:18:04 +0200 Subject: [PATCH 72/98] Fix rebase --- lib/api/entities.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 171a5da642..67d2c396b3 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -56,10 +56,6 @@ module API expose :id expose :name, :name_with_namespace expose :path, :path_with_namespace - - expose :web_url do |project, options| - Gitlab::Application.routes.url_helpers.namespace_project_url(project.namespace, project) - end end class Project < Grape::Entity From b94088d5124b08349e5bd99c49a8ae3fcc5f5e6b Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Fri, 20 May 2016 23:17:13 +0200 Subject: [PATCH 73/98] Make tests follow the guidelines --- spec/requests/api/todos_spec.rb | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb index 20d5782867..7ad6d26c42 100644 --- a/spec/requests/api/todos_spec.rb +++ b/spec/requests/api/todos_spec.rb @@ -16,23 +16,26 @@ describe API::Todos, api: true do describe 'GET /todos' do context 'when unauthenticated' do - it 'should return authentication error' do + it 'returns authentication error' do get api('/todos') + expect(response.status).to eq(401) end end context 'when authenticated' do - it 'should return an array of pending todos for current user' do + it 'returns an array of pending todos for current user' do get api('/todos', john_doe) + expect(response.status).to eq(200) expect(json_response).to be_an Array expect(json_response.length).to eq(3) end context 'and using the author filter' do - it 'should filter based on author_id param' do + it 'filters based on author_id param' do get api('/todos', john_doe), { author_id: author_2.id } + expect(response.status).to eq(200) expect(json_response).to be_an Array expect(json_response.length).to eq(2) @@ -40,8 +43,9 @@ describe API::Todos, api: true do end context 'and using the type filter' do - it 'should filter based on type param' do + it 'filters based on type param' do get api('/todos', john_doe), { type: 'MergeRequest' } + expect(response.status).to eq(200) expect(json_response).to be_an Array expect(json_response.length).to eq(1) @@ -49,8 +53,9 @@ describe API::Todos, api: true do end context 'and using the state filter' do - it 'should filter based on state param' do + it 'filters based on state param' do get api('/todos', john_doe), { state: 'done' } + expect(response.status).to eq(200) expect(json_response).to be_an Array expect(json_response.length).to eq(1) @@ -58,9 +63,10 @@ describe API::Todos, api: true do end context 'and using the project filter' do - it 'should filter based on project_id param' do + it 'filters based on project_id param' do project_2.team << [john_doe, :developer] get api('/todos', john_doe), { project_id: project_2.id } + expect(response.status).to eq(200) expect(json_response).to be_an Array expect(json_response.length).to eq(1) @@ -71,15 +77,17 @@ describe API::Todos, api: true do describe 'DELETE /todos/:id' do context 'when unauthenticated' do - it 'should return authentication error' do + it 'returns authentication error' do delete api("/todos/#{pending_1.id}") + expect(response.status).to eq(401) end end context 'when authenticated' do - it 'should mark a todo as done' do + it 'marks a todo as done' do delete api("/todos/#{pending_1.id}", john_doe) + expect(response.status).to eq(200) expect(pending_1.reload).to be_done end @@ -88,15 +96,17 @@ describe API::Todos, api: true do describe 'DELETE /todos' do context 'when unauthenticated' do - it 'should return authentication error' do + it 'returns authentication error' do delete api('/todos') + expect(response.status).to eq(401) end end context 'when authenticated' do - it 'should mark all todos as done' do + it 'marks all todos as done' do delete api('/todos', john_doe) + expect(response.status).to eq(200) expect(pending_1.reload).to be_done expect(pending_2.reload).to be_done From 39e6f504fcb8c6cab511a50cdefd76e821bfec17 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Sat, 21 May 2016 19:01:11 +0200 Subject: [PATCH 74/98] Move to helper, no instance variables --- app/models/todo.rb | 7 ------- app/views/dashboard/todos/_todo.html.haml | 2 +- lib/api/todos.rb | 18 +++++++++--------- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/app/models/todo.rb b/app/models/todo.rb index 42faecdf7f..2792fa9b9a 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -34,13 +34,6 @@ class Todo < ActiveRecord::Base action == BUILD_FAILED end - def action_name - case action - when Todo::ASSIGNED then 'assigned you' - when Todo::MENTIONED then 'mentioned you on' - end - end - def body if note.present? note.note diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml index 421885eef5..98f302d2f9 100644 --- a/app/views/dashboard/todos/_todo.html.haml +++ b/app/views/dashboard/todos/_todo.html.haml @@ -11,7 +11,7 @@ - else (removed) %span.todo-label - = todo.action_name + = todo_action_name(todo) - if todo.target = todo_target_link(todo) - else diff --git a/lib/api/todos.rb b/lib/api/todos.rb index f45c0ae634..db1f16cec5 100644 --- a/lib/api/todos.rb +++ b/lib/api/todos.rb @@ -14,11 +14,11 @@ module API # # Example Request: # GET /todos + # get do - @todos = find_todos - @todos = paginate @todos + todos = find_todos - present @todos, with: Entities::Todo + present paginate(todos), with: Entities::Todo end # Mark todo as done @@ -31,10 +31,10 @@ module API # DELETE /todos/:id # delete ':id' do - @todo = current_user.todos.find(params[:id]) - @todo.done + todo = current_user.todos.find(params[:id]) + todo.done - present @todo, with: Entities::Todo + present todo, with: Entities::Todo end # Mark all todos as done @@ -44,10 +44,10 @@ module API # DELETE /todos # delete do - @todos = find_todos - @todos.each(&:done) + todos = find_todos + todos.each(&:done) - present @todos, with: Entities::Todo + present paginate(todos), with: Entities::Todo end end end From f3abd18c9c7da9c53bea2f08c2326a15ba5948f3 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Fri, 10 Jun 2016 12:24:38 +0200 Subject: [PATCH 75/98] Add user to project to see todos --- lib/api/entities.rb | 2 +- spec/requests/api/todos_spec.rb | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 67d2c396b3..88f7fc7ff6 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -276,7 +276,7 @@ module API expose :id expose :project, using: Entities::BasicProjectDetails expose :author, using: Entities::UserBasic - expose :action_name + #expose :action_name expose :target_id expose :target_type expose :target_reference do |todo, options| diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb index 7ad6d26c42..147028ba1c 100644 --- a/spec/requests/api/todos_spec.rb +++ b/spec/requests/api/todos_spec.rb @@ -14,6 +14,11 @@ describe API::Todos, api: true do let!(:pending_3) { create(:todo, project: project_1, author: author_2, user: john_doe, target: merge_request) } let!(:done) { create(:todo, :done, project: project_1, author: author_1, user: john_doe) } + before do + project_1.team << [john_doe, :developer] + project_2.team << [john_doe, :developer] + end + describe 'GET /todos' do context 'when unauthenticated' do it 'returns authentication error' do From 69397d559f837cb55fd50d5d0459523854dcec06 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Fri, 10 Jun 2016 13:02:41 +0200 Subject: [PATCH 76/98] Assert response body --- spec/requests/api/todos_spec.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb index 147028ba1c..1960db59c9 100644 --- a/spec/requests/api/todos_spec.rb +++ b/spec/requests/api/todos_spec.rb @@ -35,6 +35,16 @@ describe API::Todos, api: true do expect(response.status).to eq(200) expect(json_response).to be_an Array expect(json_response.length).to eq(3) + expect(json_response[0]['id']).to eq(pending_3.id) + expect(json_response[0]['project']).to be_a Hash + expect(json_response[0]['author']).to be_a Hash + expect(json_response[0]['target_id']).to be_present + expect(json_response[0]['target_type']).to be_present + expect(json_response[0]['target_reference']).to be_present + expect(json_response[0]['target_url']).to be_present + expect(json_response[0]['body']).to be_present + expect(json_response[0]['state']).to eq('pending') + expect(json_response[0]['created_at']).to be_present end context 'and using the author filter' do @@ -69,7 +79,6 @@ describe API::Todos, api: true do context 'and using the project filter' do it 'filters based on project_id param' do - project_2.team << [john_doe, :developer] get api('/todos', john_doe), { project_id: project_2.id } expect(response.status).to eq(200) @@ -113,6 +122,8 @@ describe API::Todos, api: true do delete api('/todos', john_doe) expect(response.status).to eq(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(3) expect(pending_1.reload).to be_done expect(pending_2.reload).to be_done expect(pending_3.reload).to be_done From 631765748ebff2307a078dc6d50ef8367f3c5ff0 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Wed, 15 Jun 2016 13:20:30 +0200 Subject: [PATCH 77/98] Expose action_name --- app/models/todo.rb | 11 +++++++++++ lib/api/entities.rb | 2 +- spec/requests/api/todos_spec.rb | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/models/todo.rb b/app/models/todo.rb index 2792fa9b9a..3ba67078d4 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -4,6 +4,13 @@ class Todo < ActiveRecord::Base BUILD_FAILED = 3 MARKED = 4 + ACTION_NAMES = { + ASSIGNED => :assigned, + MENTIONED => :mentioned, + BUILD_FAILED => :build_failed, + MARKED => :marked + } + belongs_to :author, class_name: "User" belongs_to :note belongs_to :project @@ -34,6 +41,10 @@ class Todo < ActiveRecord::Base action == BUILD_FAILED end + def action_name + ACTION_NAMES[action] + end + def body if note.present? note.note diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 88f7fc7ff6..67d2c396b3 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -276,7 +276,7 @@ module API expose :id expose :project, using: Entities::BasicProjectDetails expose :author, using: Entities::UserBasic - #expose :action_name + expose :action_name expose :target_id expose :target_type expose :target_reference do |todo, options| diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb index 1960db59c9..8d54b4fd3d 100644 --- a/spec/requests/api/todos_spec.rb +++ b/spec/requests/api/todos_spec.rb @@ -44,6 +44,7 @@ describe API::Todos, api: true do expect(json_response[0]['target_url']).to be_present expect(json_response[0]['body']).to be_present expect(json_response[0]['state']).to eq('pending') + expect(json_response[0]['action_name']).to eq('assigned') expect(json_response[0]['created_at']).to be_present end From 40c685c510fff48e0dc6a49c61704e8244ec6034 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Wed, 15 Jun 2016 16:06:38 +0200 Subject: [PATCH 78/98] pass paginated array when deleting notes --- lib/api/todos.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/todos.rb b/lib/api/todos.rb index db1f16cec5..10fd2aac09 100644 --- a/lib/api/todos.rb +++ b/lib/api/todos.rb @@ -47,7 +47,7 @@ module API todos = find_todos todos.each(&:done) - present paginate(todos), with: Entities::Todo + present paginate(Kaminari.paginate_array(todos)), with: Entities::Todo end end end From 03dcb690451b254d02cb65b656c141d1c3161802 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Fri, 1 Jul 2016 17:39:48 +0800 Subject: [PATCH 79/98] Update CHANGELOG 8.9.5 for runners related fixes --- CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 4b754c2aba..12661bfba6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -29,6 +29,10 @@ v 8.10.0 (unreleased) - Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w) - Add basic system information like memory and disk usage to the admin panel +v 8.9.5 (unreleased) + - Fix assigning shared runners as admins + - Show "locked" label for locked runners on runners admin + v 8.9.4 - Fix privilege escalation issue with OAuth external users. - Ensure references to private repos aren't shown to logged-out users. From 4bcad1cbddca92e27c19a1c6c0872a01ef318f69 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 1 Jul 2016 11:46:56 +0200 Subject: [PATCH 80/98] Groundwork for Kerberos SPNEGO (EE feature) --- .../projects/git_http_controller.rb | 39 +++++++++++++++++-- app/helpers/kerberos_spnego_helper.rb | 9 +++++ spec/requests/git_http_spec.rb | 27 +++++++------ 3 files changed, 59 insertions(+), 16 deletions(-) create mode 100644 app/helpers/kerberos_spnego_helper.rb diff --git a/app/controllers/projects/git_http_controller.rb b/app/controllers/projects/git_http_controller.rb index f907d63258..62c3fa8de5 100644 --- a/app/controllers/projects/git_http_controller.rb +++ b/app/controllers/projects/git_http_controller.rb @@ -1,4 +1,9 @@ +# This file should be identical in GitLab Community Edition and Enterprise Edition + class Projects::GitHttpController < Projects::ApplicationController + include ActionController::HttpAuthentication::Basic + include KerberosSpnegoHelper + attr_reader :user # Git clients will not know what authenticity token to send along @@ -40,9 +45,12 @@ class Projects::GitHttpController < Projects::ApplicationController private def authenticate_user - return if project && project.public? && upload_pack? + if project && project.public? && upload_pack? + return # Allow access + end - authenticate_or_request_with_http_basic do |login, password| + if allow_basic_auth? && basic_auth_provided? + login, password = user_name_and_password(request) auth_result = Gitlab::Auth.find_for_git_client(login, password, project: project, ip: request.ip) if auth_result.type == :ci && upload_pack? @@ -53,8 +61,31 @@ class Projects::GitHttpController < Projects::ApplicationController @user = auth_result.user end - ci? || user + if ci? || user + return # Allow access + end + elsif allow_kerberos_spnego_auth? && spnego_provided? + @user = find_kerberos_user + + if user + send_final_spnego_response + return # Allow access + end end + + send_challenges + render plain: "HTTP Basic: Access denied\n", status: 401 + end + + def basic_auth_provided? + has_basic_credentials?(request) + end + + def send_challenges + challenges = [] + challenges << 'Basic realm="GitLab"' if allow_basic_auth? + challenges << spnego_challenge if allow_kerberos_spnego_auth? + headers['Www-Authenticate'] = challenges.join("\n") if challenges.any? end def ensure_project_found! @@ -120,7 +151,7 @@ class Projects::GitHttpController < Projects::ApplicationController end def render_not_found - render text: 'Not Found', status: :not_found + render plain: 'Not Found', status: :not_found end def ci? diff --git a/app/helpers/kerberos_spnego_helper.rb b/app/helpers/kerberos_spnego_helper.rb new file mode 100644 index 0000000000..f5b0aa7549 --- /dev/null +++ b/app/helpers/kerberos_spnego_helper.rb @@ -0,0 +1,9 @@ +module KerberosSpnegoHelper + def allow_basic_auth? + true # different behavior in GitLab Enterprise Edition + end + + def allow_kerberos_spnego_auth? + false # different behavior in GitLab Enterprise Edition + end +end diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index bae56334be..82ab582bea 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -350,23 +350,23 @@ describe 'Git HTTP requests', lib: true do end def clone_get(project, options={}) - get "/#{project}/info/refs", { service: 'git-upload-pack' }, auth_env(*options.values_at(:user, :password)) + get "/#{project}/info/refs", { service: 'git-upload-pack' }, auth_env(*options.values_at(:user, :password, :spnego_request_token)) end def clone_post(project, options={}) - post "/#{project}/git-upload-pack", {}, auth_env(*options.values_at(:user, :password)) + post "/#{project}/git-upload-pack", {}, auth_env(*options.values_at(:user, :password, :spnego_request_token)) end def push_get(project, options={}) - get "/#{project}/info/refs", { service: 'git-receive-pack' }, auth_env(*options.values_at(:user, :password)) + get "/#{project}/info/refs", { service: 'git-receive-pack' }, auth_env(*options.values_at(:user, :password, :spnego_request_token)) end def push_post(project, options={}) - post "/#{project}/git-receive-pack", {}, auth_env(*options.values_at(:user, :password)) + post "/#{project}/git-receive-pack", {}, auth_env(*options.values_at(:user, :password, :spnego_request_token)) end - def download(project, user: nil, password: nil) - args = [project, { user: user, password: password }] + def download(project, user: nil, password: nil, spnego_request_token: nil) + args = [project, { user: user, password: password, spnego_request_token: spnego_request_token }] clone_get(*args) yield response @@ -375,8 +375,8 @@ describe 'Git HTTP requests', lib: true do yield response end - def upload(project, user: nil, password: nil) - args = [project, { user: user, password: password }] + def upload(project, user: nil, password: nil, spnego_request_token: nil) + args = [project, { user: user, password: password, spnego_request_token: spnego_request_token }] push_get(*args) yield response @@ -385,11 +385,14 @@ describe 'Git HTTP requests', lib: true do yield response end - def auth_env(user, password) + def auth_env(user, password, spnego_request_token) + env = {} if user && password - { 'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user, password) } - else - {} + env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(user, password) + elsif spnego_request_token + env['HTTP_AUTHORIZATION'] = "Negotiate #{::Base64.strict_encode64('opaque_request_token')}" end + + env end end From 521454831ee9e899e046ed288596865df55e8832 Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Fri, 1 Jul 2016 11:16:48 +0200 Subject: [PATCH 81/98] Metrics for Rouge::Plugins::Redcarpet and Rouge::Formatters::HTMLGitlab --- CHANGELOG | 1 + config/initializers/metrics.rb | 3 +++ lib/banzai/filter/syntax_highlight_filter.rb | 9 +++++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4b754c2aba..25611f173a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -26,6 +26,7 @@ v 8.10.0 (unreleased) - Better caching of git calls on ProjectsController#show. - Add API endpoint for a group issues !4520 (mahcsig) - Add Bugzilla integration !4930 (iamtjg) + - Metrics for Rouge::Plugins::Redcarpet and Rouge::Formatters::HTMLGitlab - Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w) - Add basic system information like memory and disk usage to the admin panel diff --git a/config/initializers/metrics.rb b/config/initializers/metrics.rb index 75f89d524e..44601f2b2b 100644 --- a/config/initializers/metrics.rb +++ b/config/initializers/metrics.rb @@ -132,6 +132,9 @@ if Gitlab::Metrics.enabled? config.instrument_instance_methods(API::Helpers) config.instrument_instance_methods(RepositoryCheck::SingleRepositoryWorker) + + config.instrument_instance_methods(Rouge::Plugins::Redcarpet) + config.instrument_instance_methods(Rouge::Formatters::HTMLGitlab) end GC::Profiler.enable diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb index 62a79c62e2..536b478979 100644 --- a/lib/banzai/filter/syntax_highlight_filter.rb +++ b/lib/banzai/filter/syntax_highlight_filter.rb @@ -27,12 +27,17 @@ module Banzai highlighted = "
#{code}
" end - # Replace the parent `pre` element with the entire highlighted block - node.parent.replace(highlighted) + # Extracted to a method to measure it + replace_parent_pre_element(node, highlighted) end private + def replace_parent_pre_element(node, highlighted) + # Replace the parent `pre` element with the entire highlighted block + node.parent.replace(highlighted) + end + # Override Rouge::Plugins::Redcarpet#rouge_formatter def rouge_formatter(lexer) Rouge::Formatters::HTMLGitlab.new( From 8625bd362245cad49e268d7bcd82e987f70ba044 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Wed, 22 Jun 2016 18:46:17 +0200 Subject: [PATCH 82/98] Improve the request / withdraw access button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- CHANGELOG | 5 +++-- app/assets/stylesheets/framework/mobile.scss | 4 ++++ app/assets/stylesheets/pages/groups.scss | 13 ++++++++----- app/assets/stylesheets/pages/projects.scss | 12 ------------ app/views/groups/show.html.haml | 9 +++------ app/views/projects/_home_panel.html.haml | 2 +- .../members/_access_request_buttons.html.haml | 4 ++-- .../img/access_requests_management.png | Bin 15105 -> 15686 bytes doc/workflow/groups.md | 2 +- .../groups/access_requests_management.png | Bin 15193 -> 15829 bytes doc/workflow/groups/request_access_button.png | Bin 30470 -> 49067 bytes .../groups/withdraw_access_request_button.png | Bin 31681 -> 49941 bytes 12 files changed, 22 insertions(+), 29 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e2fa16e4ee..78aee0b0b9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -31,8 +31,9 @@ v 8.10.0 (unreleased) - Add basic system information like memory and disk usage to the admin panel v 8.9.5 (unreleased) - - Fix assigning shared runners as admins - - Show "locked" label for locked runners on runners admin + - Improve the request / withdraw access button. !4860 + - Fix assigning shared runners as admins. !4961 + - Show "locked" label for locked runners on runners admin. !4961 v 8.9.4 - Fix privilege escalation issue with OAuth external users. diff --git a/app/assets/stylesheets/framework/mobile.scss b/app/assets/stylesheets/framework/mobile.scss index c74682dfef..367c7d0194 100644 --- a/app/assets/stylesheets/framework/mobile.scss +++ b/app/assets/stylesheets/framework/mobile.scss @@ -71,6 +71,10 @@ display: none; } + .group-right-buttons { + display: none; + } + .container .title { padding-left: 15px !important; } diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss index 101faf5917..3d79f4400e 100644 --- a/app/assets/stylesheets/pages/groups.scss +++ b/app/assets/stylesheets/pages/groups.scss @@ -41,14 +41,17 @@ } .groups-cover-block { - .container-fluid { position: relative; } - .access-request-button { - @include btn-gray; - margin-right: 10px; - text-transform: none; + .group-right-buttons { + position: absolute; + right: 16px; + .btn { + @include btn-gray; + padding: 3px 10px; + background-color: $background-color; + } } } diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 89ce1b2df2..817c298292 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -266,18 +266,6 @@ @media (max-width: $screen-md-max) { top: 0; } - - .access-request-button { - position: absolute; - right: 0; - bottom: 61px; - - @media (max-width: $screen-md-max) { - position: relative; - bottom: 0; - margin-right: 10px; - } - } } @media (max-width: $screen-md-max) { diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 69f634e75b..a83eb7e88b 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -15,18 +15,15 @@ %span.visibility-icon.has-tooltip{ data: { container: 'body' }, title: visibility_icon_description(@group) } = visibility_level_icon(@group.visibility_level, fw: false) - %span.hidden-xs + .group-right-buttons.btn-group + - if current_user + .pull-left.append-right-10= render 'shared/members/access_request_buttons', source: @group = render 'shared/notifications/button', notification_setting: @notification_setting - - if current_user - .pull-right - = render 'shared/members/access_request_buttons', source: @group - - if @group.description.present? .cover-desc.description = markdown(@group.description, pipeline: :description) - %div{ class: container_class } .top-area %ul.nav-links diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml index 8ce23379fb..540efa4780 100644 --- a/app/views/projects/_home_panel.html.haml +++ b/app/views/projects/_home_panel.html.haml @@ -31,7 +31,7 @@ .project-repo-buttons.btn-group.project-right-buttons - if current_user - = render 'shared/members/access_request_buttons', source: @project + .pull-left.append-right-10= render 'shared/members/access_request_buttons', source: @project = render "projects/buttons/download" = render 'projects/buttons/dropdown' diff --git a/app/views/shared/members/_access_request_buttons.html.haml b/app/views/shared/members/_access_request_buttons.html.haml index 480e8ba6c8..c56418f052 100644 --- a/app/views/shared/members/_access_request_buttons.html.haml +++ b/app/views/shared/members/_access_request_buttons.html.haml @@ -7,8 +7,8 @@ = link_to 'Withdraw Access Request', polymorphic_path([:leave, source, :members]), method: :delete, data: { confirm: remove_member_message(member) }, - class: 'btn access-request-button hidden-xs' + class: 'btn' - else = link_to 'Request Access', polymorphic_path([:request_access, source, :members]), method: :post, - class: 'btn access-request-button hidden-xs' + class: 'btn' diff --git a/doc/workflow/add-user/img/access_requests_management.png b/doc/workflow/add-user/img/access_requests_management.png index e9641cb4f85b9112a2ab2bfc4868081fe28caaae..5c9b510ba9ded53271e25134779e766f5602bab0 100644 GIT binary patch literal 15686 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 diff --git a/doc/workflow/groups.md b/doc/workflow/groups.md index 1a316e8097..9b50286b17 100644 --- a/doc/workflow/groups.md +++ b/doc/workflow/groups.md @@ -51,7 +51,7 @@ If necessary, you can increase the access level of an individual user for a spec ![Barry effectively has 'Master' access to GitLab CI now](groups/override_access_level.png) -## Request access to a group +## Requesting access to a group As a user, you can request to be a member of a group. Go to the group you'd like to be a member of, and click the **Request Access** button on the right diff --git a/doc/workflow/groups/access_requests_management.png b/doc/workflow/groups/access_requests_management.png index ffede8e9bd68495ad70e5ac2b12fc47d7da03260..5202434f00f6a8eef27a2ce9a58de2b6572a5767 100644 GIT binary patch literal 15829 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 R#xD)zWt64Ay)_K{e*nQQB|HEC literal 15193 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

j&Z!9{rC2X%k0mWS{oB#wwV6bf;# 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 OrgBnBl9l2{0sj|;x~w(; literal 31681 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

X?W4o!gAIX~< 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 From fd9cd5ae8cd2d2f5488635b264eb86d89d768d66 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Thu, 16 Jun 2016 11:12:42 +0200 Subject: [PATCH 83/98] Add todos API documentation and changelog --- CHANGELOG | 1 + doc/api/README.md | 1 + doc/api/todos.md | 217 ++++++++++++++++++++++++++++++++++++++++++++++ lib/api/todos.rb | 4 +- 4 files changed, 220 insertions(+), 3 deletions(-) create mode 100644 doc/api/todos.md diff --git a/CHANGELOG b/CHANGELOG index 4b754c2aba..98d23ea682 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,7 @@ v 8.10.0 (unreleased) - Fix changing issue state columns in milestone view - Add notification settings dropdown for groups - Allow importing from Github using Personal Access Tokens. (Eric K Idema) + - API: Todos !3188 (Robert Schilling) - Fix user creation with stronger minimum password requirements !4054 (nathan-pmt) - PipelinesFinder uses git cache data - Check for conflicts with existing Project's wiki path when creating a new project. diff --git a/doc/api/README.md b/doc/api/README.md index 288f7f9ee6..d1e6c54c52 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -36,6 +36,7 @@ following locations: - [System Hooks](system_hooks.md) - [Tags](tags.md) - [Users](users.md) +- [Todos](todos.md) ### Internal CI API diff --git a/doc/api/todos.md b/doc/api/todos.md new file mode 100644 index 0000000000..1d38e4acf1 --- /dev/null +++ b/doc/api/todos.md @@ -0,0 +1,217 @@ +# Todos + +**Note:** This feature was [introduced][ce-3188] in GitLab 8.10 + +## Get a list of todos + +Returns a list of todos. When no filter is applied, it returns all pending todos +for the current user. Different filters allow the user to + +``` +GET /todos +``` + +Parameters: + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `action_id` | integer | no | The ID of the action of the todo. See the table below for the ID mapping | +| `author_id` | integer | no | The ID of an author | +| `project_id` | integer | no | The ID of a project | +| `state` | string | no | The state of the todo. Can be either `pending` or `done` | +| `type` | string | no | The type of an todo. Can be either `Issue` or `MergeRequest` | + +| `action_id` | Action | +| ----------- | ------ | +| 1 | Issuable assigned | +| 2 | Mentioned in issuable | +| 3 | Build failed | +| 4 | Todo marked for you | + + +```bash +curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/todos +``` + +Example Response: + +```json +[ + { + "id": 130, + "project": { + "id": 1, + "name": "Underscore", + "name_with_namespace": "Documentcloud / Underscore", + "path": "underscore", + "path_with_namespace": "documentcloud/underscore" + }, + "author": { + "name": "Juwan Abbott", + "username": "halle", + "id": 8, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/a0086c7b9e0d73312f32ff745fdcb43e?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/halle" + }, + "action_name": "assigned", + "target_id": 71, + "target_type": "Issue", + "target_reference": "#1", + "target_url": "https://gitlab.example.com/documentcloud/underscore/issues/1", + "body": "At voluptas qui nulla soluta qui et.", + "state": "pending", + "created_at": "2016-05-20T20:52:00.626Z" + }, + { + "id": 129, + "project": { + "id": 1, + "name": "Underscore", + "name_with_namespace": "Documentcloud / Underscore", + "path": "underscore", + "path_with_namespace": "documentcloud/underscore" + }, + "author": { + "name": "Juwan Abbott", + "username": "halle", + "id": 8, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/a0086c7b9e0d73312f32ff745fdcb43e?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/halle" + }, + "action_name": "mentioned", + "target_id": 79, + "target_type": "Issue", + "target_reference": "#9", + "target_url": "https://gitlab.example.com/documentcloud/underscore/issues/9#note_959", + "body": "@root Fix this shit", + "state": "pending", + "created_at": "2016-05-20T20:51:51.503Z" + } +] +``` + +## Mark a todo as done + +Marks a single pending todo given by its ID for the current user as done. The to +marked as done is returned in the response. + +``` +DELETE /todos/:id +``` + +Parameters: + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer | yes | The ID of a todo | + +```bash +curl -X DELETE -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/todos/130 +``` + +Example Response: + +```json +{ + "id": 130, + "project": { + "id": 1, + "name": "Underscore", + "name_with_namespace": "Documentcloud / Underscore", + "path": "underscore", + "path_with_namespace": "documentcloud/underscore" + }, + "author": { + "name": "Juwan Abbott", + "username": "halle", + "id": 8, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/a0086c7b9e0d73312f32ff745fdcb43e?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/halle" + }, + "action_name": "assigned", + "target_id": 71, + "target_type": "Issue", + "target_reference": "#1", + "target_url": "https://gitlab.example.com/documentcloud/underscore/issues/1", + "body": "At voluptas qui nulla soluta qui et.", + "state": "done", + "created_at": "2016-05-20T20:52:00.626Z" +} +``` + +## Mark all todos as done + +Marks all pending todos for the current user as done. All todos marked as done +are returned in the response. + +``` +DELETE /todos +``` + +```bash +curl -X DELETE -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/todos +``` + +Example Response: + +```json +[ + { + "id": 130, + "project": { + "id": 1, + "name": "Underscore", + "name_with_namespace": "Documentcloud / Underscore", + "path": "underscore", + "path_with_namespace": "documentcloud/underscore" + }, + "author": { + "name": "Juwan Abbott", + "username": "halle", + "id": 8, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/a0086c7b9e0d73312f32ff745fdcb43e?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/halle" + }, + "action_name": "assigned", + "target_id": 71, + "target_type": "Issue", + "target_reference": "#1", + "target_url": "https://gitlab.example.com/documentcloud/underscore/issues/1", + "body": "At voluptas qui nulla soluta qui et.", + "state": "done", + "created_at": "2016-05-20T20:52:00.626Z" + }, + { + "id": 129, + "project": { + "id": 1, + "name": "Underscore", + "name_with_namespace": "Documentcloud / Underscore", + "path": "underscore", + "path_with_namespace": "documentcloud/underscore" + }, + "author": { + "name": "Juwan Abbott", + "username": "halle", + "id": 8, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/a0086c7b9e0d73312f32ff745fdcb43e?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/halle" + }, + "action_name": "mentioned", + "target_id": 79, + "target_type": "Issue", + "target_reference": "#9", + "target_url": "https://gitlab.example.com/documentcloud/underscore/issues/9#note_959", + "body": "@root Fix this shit", + "state": "done", + "created_at": "2016-05-20T20:51:51.503Z" + } +] +``` + +[ce-3188]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3188 diff --git a/lib/api/todos.rb b/lib/api/todos.rb index 10fd2aac09..67714a796c 100644 --- a/lib/api/todos.rb +++ b/lib/api/todos.rb @@ -21,13 +21,12 @@ module API present paginate(todos), with: Entities::Todo end - # Mark todo as done + # Mark a todo as done # # Parameters: # id: (required) - The ID of the todo being marked as done # # Example Request: - # # DELETE /todos/:id # delete ':id' do @@ -40,7 +39,6 @@ module API # Mark all todos as done # # Example Request: - # # DELETE /todos # delete do From 3942621329b20307c1676d60324c8f47ea1e1b37 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Wed, 22 Jun 2016 19:15:09 +0200 Subject: [PATCH 84/98] Expose target, filter by state as string --- app/finders/todos_finder.rb | 21 ++ doc/api/todos.md | 447 ++++++++++++++++++++++++-------- lib/api/entities.rb | 8 +- lib/api/todos.rb | 6 +- spec/requests/api/todos_spec.rb | 15 +- 5 files changed, 377 insertions(+), 120 deletions(-) diff --git a/app/finders/todos_finder.rb b/app/finders/todos_finder.rb index 58a00f88af..7806d9e4cc 100644 --- a/app/finders/todos_finder.rb +++ b/app/finders/todos_finder.rb @@ -25,6 +25,7 @@ class TodosFinder def execute items = current_user.todos items = by_action_id(items) + items = by_action(items) items = by_author(items) items = by_project(items) items = by_state(items) @@ -43,6 +44,18 @@ class TodosFinder params[:action_id] end + def to_action_id + Todo::ACTION_NAMES.key(action.to_sym) + end + + def action? + action.present? && to_action_id + end + + def action + params[:action] + end + def author? params[:author_id].present? end @@ -96,6 +109,14 @@ class TodosFinder params[:type] end + def by_action(items) + if action? + items = items.where(action: to_action_id) + end + + items + end + def by_action_id(items) if action_id? items = items.where(action: action_id) diff --git a/doc/api/todos.md b/doc/api/todos.md index 1d38e4acf1..29e7366441 100644 --- a/doc/api/todos.md +++ b/doc/api/todos.md @@ -5,7 +5,7 @@ ## Get a list of todos Returns a list of todos. When no filter is applied, it returns all pending todos -for the current user. Different filters allow the user to +for the current user. Different filters allow the user to precise the request. ``` GET /todos @@ -15,19 +15,11 @@ Parameters: | Attribute | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `action_id` | integer | no | The ID of the action of the todo. See the table below for the ID mapping | +| `action` | string | no | The action to be filtered. Can be `assigned`, `mentioned`, `build_failed`, or `marked`. | | `author_id` | integer | no | The ID of an author | | `project_id` | integer | no | The ID of a project | | `state` | string | no | The state of the todo. Can be either `pending` or `done` | -| `type` | string | no | The type of an todo. Can be either `Issue` or `MergeRequest` | - -| `action_id` | Action | -| ----------- | ------ | -| 1 | Issuable assigned | -| 2 | Mentioned in issuable | -| 3 | Build failed | -| 4 | Todo marked for you | - +| `type` | string | no | The type of a todo. Can be either `Issue` or `MergeRequest` | ```bash curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/todos @@ -38,64 +30,158 @@ Example Response: ```json [ { - "id": 130, + "id": 102, "project": { - "id": 1, - "name": "Underscore", - "name_with_namespace": "Documentcloud / Underscore", - "path": "underscore", - "path_with_namespace": "documentcloud/underscore" + "id": 2, + "name": "Gitlab Ce", + "name_with_namespace": "Gitlab Org / Gitlab Ce", + "path": "gitlab-ce", + "path_with_namespace": "gitlab-org/gitlab-ce" }, "author": { - "name": "Juwan Abbott", - "username": "halle", - "id": 8, + "name": "Administrator", + "username": "root", + "id": 1, "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/a0086c7b9e0d73312f32ff745fdcb43e?s=80&d=identicon", - "web_url": "https://gitlab.example.com/u/halle" + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/root" }, - "action_name": "assigned", - "target_id": 71, - "target_type": "Issue", - "target_reference": "#1", - "target_url": "https://gitlab.example.com/documentcloud/underscore/issues/1", - "body": "At voluptas qui nulla soluta qui et.", + "action_name": "marked", + "target_type": "MergeRequest", + "target": { + "id": 34, + "iid": 7, + "project_id": 2, + "title": "Dolores in voluptatem tenetur praesentium omnis repellendus voluptatem quaerat.", + "description": "Et ea et omnis illum cupiditate. Dolor aspernatur tenetur ducimus facilis est nihil. Quo esse cupiditate molestiae illo corrupti qui quidem dolor.", + "state": "opened", + "created_at": "2016-06-17T07:49:24.419Z", + "updated_at": "2016-06-17T07:52:43.484Z", + "target_branch": "tutorials_git_tricks", + "source_branch": "DNSBL_docs", + "upvotes": 0, + "downvotes": 0, + "author": { + "name": "Maxie Medhurst", + "username": "craig_rutherford", + "id": 12, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/a0d477b3ea21970ce6ffcbb817b0b435?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/craig_rutherford" + }, + "assignee": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/root" + }, + "source_project_id": 2, + "target_project_id": 2, + "labels": [], + "work_in_progress": false, + "milestone": { + "id": 32, + "iid": 2, + "project_id": 2, + "title": "v1.0", + "description": "Assumenda placeat ea voluptatem voluptate qui.", + "state": "active", + "created_at": "2016-06-17T07:47:34.163Z", + "updated_at": "2016-06-17T07:47:34.163Z", + "due_date": null + }, + "merge_when_build_succeeds": false, + "merge_status": "cannot_be_merged", + "subscribed": true, + "user_notes_count": 7 + }, + "target_url": "https://gitlab.example.com/gitlab-org/gitlab-ce/merge_requests/7", + "body": "Dolores in voluptatem tenetur praesentium omnis repellendus voluptatem quaerat.", "state": "pending", - "created_at": "2016-05-20T20:52:00.626Z" + "created_at": "2016-06-17T07:52:35.225Z" }, { - "id": 129, + "id": 98, "project": { - "id": 1, - "name": "Underscore", - "name_with_namespace": "Documentcloud / Underscore", - "path": "underscore", - "path_with_namespace": "documentcloud/underscore" + "id": 2, + "name": "Gitlab Ce", + "name_with_namespace": "Gitlab Org / Gitlab Ce", + "path": "gitlab-ce", + "path_with_namespace": "gitlab-org/gitlab-ce" }, "author": { - "name": "Juwan Abbott", - "username": "halle", - "id": 8, + "name": "Maxie Medhurst", + "username": "craig_rutherford", + "id": 12, "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/a0086c7b9e0d73312f32ff745fdcb43e?s=80&d=identicon", - "web_url": "https://gitlab.example.com/u/halle" + "avatar_url": "http://www.gravatar.com/avatar/a0d477b3ea21970ce6ffcbb817b0b435?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/craig_rutherford" }, - "action_name": "mentioned", - "target_id": 79, - "target_type": "Issue", - "target_reference": "#9", - "target_url": "https://gitlab.example.com/documentcloud/underscore/issues/9#note_959", - "body": "@root Fix this shit", + "action_name": "assigned", + "target_type": "MergeRequest", + "target": { + "id": 34, + "iid": 7, + "project_id": 2, + "title": "Dolores in voluptatem tenetur praesentium omnis repellendus voluptatem quaerat.", + "description": "Et ea et omnis illum cupiditate. Dolor aspernatur tenetur ducimus facilis est nihil. Quo esse cupiditate molestiae illo corrupti qui quidem dolor.", + "state": "opened", + "created_at": "2016-06-17T07:49:24.419Z", + "updated_at": "2016-06-17T07:52:43.484Z", + "target_branch": "tutorials_git_tricks", + "source_branch": "DNSBL_docs", + "upvotes": 0, + "downvotes": 0, + "author": { + "name": "Maxie Medhurst", + "username": "craig_rutherford", + "id": 12, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/a0d477b3ea21970ce6ffcbb817b0b435?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/craig_rutherford" + }, + "assignee": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/root" + }, + "source_project_id": 2, + "target_project_id": 2, + "labels": [], + "work_in_progress": false, + "milestone": { + "id": 32, + "iid": 2, + "project_id": 2, + "title": "v1.0", + "description": "Assumenda placeat ea voluptatem voluptate qui.", + "state": "active", + "created_at": "2016-06-17T07:47:34.163Z", + "updated_at": "2016-06-17T07:47:34.163Z", + "due_date": null + }, + "merge_when_build_succeeds": false, + "merge_status": "cannot_be_merged", + "subscribed": true, + "user_notes_count": 7 + }, + "target_url": "https://gitlab.example.com/gitlab-org/gitlab-ce/merge_requests/7", + "body": "Dolores in voluptatem tenetur praesentium omnis repellendus voluptatem quaerat.", "state": "pending", - "created_at": "2016-05-20T20:51:51.503Z" + "created_at": "2016-06-17T07:49:24.624Z" } ] ``` ## Mark a todo as done -Marks a single pending todo given by its ID for the current user as done. The to -marked as done is returned in the response. +Marks a single pending todo given by its ID for the current user as done. The +todo marked as done is returned in the response. ``` DELETE /todos/:id @@ -115,30 +201,77 @@ Example Response: ```json { - "id": 130, - "project": { - "id": 1, - "name": "Underscore", - "name_with_namespace": "Documentcloud / Underscore", - "path": "underscore", - "path_with_namespace": "documentcloud/underscore" - }, - "author": { - "name": "Juwan Abbott", - "username": "halle", - "id": 8, - "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/a0086c7b9e0d73312f32ff745fdcb43e?s=80&d=identicon", - "web_url": "https://gitlab.example.com/u/halle" - }, - "action_name": "assigned", - "target_id": 71, - "target_type": "Issue", - "target_reference": "#1", - "target_url": "https://gitlab.example.com/documentcloud/underscore/issues/1", - "body": "At voluptas qui nulla soluta qui et.", - "state": "done", - "created_at": "2016-05-20T20:52:00.626Z" + "id": 102, + "project": { + "id": 2, + "name": "Gitlab Ce", + "name_with_namespace": "Gitlab Org / Gitlab Ce", + "path": "gitlab-ce", + "path_with_namespace": "gitlab-org/gitlab-ce" + }, + "author": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/root" + }, + "action_name": "marked", + "target_type": "MergeRequest", + "target": { + "id": 34, + "iid": 7, + "project_id": 2, + "title": "Dolores in voluptatem tenetur praesentium omnis repellendus voluptatem quaerat.", + "description": "Et ea et omnis illum cupiditate. Dolor aspernatur tenetur ducimus facilis est nihil. Quo esse cupiditate molestiae illo corrupti qui quidem dolor.", + "state": "opened", + "created_at": "2016-06-17T07:49:24.419Z", + "updated_at": "2016-06-17T07:52:43.484Z", + "target_branch": "tutorials_git_tricks", + "source_branch": "DNSBL_docs", + "upvotes": 0, + "downvotes": 0, + "author": { + "name": "Maxie Medhurst", + "username": "craig_rutherford", + "id": 12, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/a0d477b3ea21970ce6ffcbb817b0b435?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/craig_rutherford" + }, + "assignee": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/root" + }, + "source_project_id": 2, + "target_project_id": 2, + "labels": [], + "work_in_progress": false, + "milestone": { + "id": 32, + "iid": 2, + "project_id": 2, + "title": "v1.0", + "description": "Assumenda placeat ea voluptatem voluptate qui.", + "state": "active", + "created_at": "2016-06-17T07:47:34.163Z", + "updated_at": "2016-06-17T07:47:34.163Z", + "due_date": null + }, + "merge_when_build_succeeds": false, + "merge_status": "cannot_be_merged", + "subscribed": true, + "user_notes_count": 7 + }, + "target_url": "https://gitlab.example.com/gitlab-org/gitlab-ce/merge_requests/7", + "body": "Dolores in voluptatem tenetur praesentium omnis repellendus voluptatem quaerat.", + "state": "done", + "created_at": "2016-06-17T07:52:35.225Z" } ``` @@ -160,57 +293,151 @@ Example Response: ```json [ { - "id": 130, + "id": 102, "project": { - "id": 1, - "name": "Underscore", - "name_with_namespace": "Documentcloud / Underscore", - "path": "underscore", - "path_with_namespace": "documentcloud/underscore" + "id": 2, + "name": "Gitlab Ce", + "name_with_namespace": "Gitlab Org / Gitlab Ce", + "path": "gitlab-ce", + "path_with_namespace": "gitlab-org/gitlab-ce" }, "author": { - "name": "Juwan Abbott", - "username": "halle", - "id": 8, + "name": "Administrator", + "username": "root", + "id": 1, "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/a0086c7b9e0d73312f32ff745fdcb43e?s=80&d=identicon", - "web_url": "https://gitlab.example.com/u/halle" + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/root" }, - "action_name": "assigned", - "target_id": 71, - "target_type": "Issue", - "target_reference": "#1", - "target_url": "https://gitlab.example.com/documentcloud/underscore/issues/1", - "body": "At voluptas qui nulla soluta qui et.", + "action_name": "marked", + "target_type": "MergeRequest", + "target": { + "id": 34, + "iid": 7, + "project_id": 2, + "title": "Dolores in voluptatem tenetur praesentium omnis repellendus voluptatem quaerat.", + "description": "Et ea et omnis illum cupiditate. Dolor aspernatur tenetur ducimus facilis est nihil. Quo esse cupiditate molestiae illo corrupti qui quidem dolor.", + "state": "opened", + "created_at": "2016-06-17T07:49:24.419Z", + "updated_at": "2016-06-17T07:52:43.484Z", + "target_branch": "tutorials_git_tricks", + "source_branch": "DNSBL_docs", + "upvotes": 0, + "downvotes": 0, + "author": { + "name": "Maxie Medhurst", + "username": "craig_rutherford", + "id": 12, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/a0d477b3ea21970ce6ffcbb817b0b435?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/craig_rutherford" + }, + "assignee": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/root" + }, + "source_project_id": 2, + "target_project_id": 2, + "labels": [], + "work_in_progress": false, + "milestone": { + "id": 32, + "iid": 2, + "project_id": 2, + "title": "v1.0", + "description": "Assumenda placeat ea voluptatem voluptate qui.", + "state": "active", + "created_at": "2016-06-17T07:47:34.163Z", + "updated_at": "2016-06-17T07:47:34.163Z", + "due_date": null + }, + "merge_when_build_succeeds": false, + "merge_status": "cannot_be_merged", + "subscribed": true, + "user_notes_count": 7 + }, + "target_url": "https://gitlab.example.com/gitlab-org/gitlab-ce/merge_requests/7", + "body": "Dolores in voluptatem tenetur praesentium omnis repellendus voluptatem quaerat.", "state": "done", - "created_at": "2016-05-20T20:52:00.626Z" + "created_at": "2016-06-17T07:52:35.225Z" }, { - "id": 129, + "id": 98, "project": { - "id": 1, - "name": "Underscore", - "name_with_namespace": "Documentcloud / Underscore", - "path": "underscore", - "path_with_namespace": "documentcloud/underscore" + "id": 2, + "name": "Gitlab Ce", + "name_with_namespace": "Gitlab Org / Gitlab Ce", + "path": "gitlab-ce", + "path_with_namespace": "gitlab-org/gitlab-ce" }, "author": { - "name": "Juwan Abbott", - "username": "halle", - "id": 8, + "name": "Maxie Medhurst", + "username": "craig_rutherford", + "id": 12, "state": "active", - "avatar_url": "http://www.gravatar.com/avatar/a0086c7b9e0d73312f32ff745fdcb43e?s=80&d=identicon", - "web_url": "https://gitlab.example.com/u/halle" + "avatar_url": "http://www.gravatar.com/avatar/a0d477b3ea21970ce6ffcbb817b0b435?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/craig_rutherford" }, - "action_name": "mentioned", - "target_id": 79, - "target_type": "Issue", - "target_reference": "#9", - "target_url": "https://gitlab.example.com/documentcloud/underscore/issues/9#note_959", - "body": "@root Fix this shit", + "action_name": "assigned", + "target_type": "MergeRequest", + "target": { + "id": 34, + "iid": 7, + "project_id": 2, + "title": "Dolores in voluptatem tenetur praesentium omnis repellendus voluptatem quaerat.", + "description": "Et ea et omnis illum cupiditate. Dolor aspernatur tenetur ducimus facilis est nihil. Quo esse cupiditate molestiae illo corrupti qui quidem dolor.", + "state": "opened", + "created_at": "2016-06-17T07:49:24.419Z", + "updated_at": "2016-06-17T07:52:43.484Z", + "target_branch": "tutorials_git_tricks", + "source_branch": "DNSBL_docs", + "upvotes": 0, + "downvotes": 0, + "author": { + "name": "Maxie Medhurst", + "username": "craig_rutherford", + "id": 12, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/a0d477b3ea21970ce6ffcbb817b0b435?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/craig_rutherford" + }, + "assignee": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/root" + }, + "source_project_id": 2, + "target_project_id": 2, + "labels": [], + "work_in_progress": false, + "milestone": { + "id": 32, + "iid": 2, + "project_id": 2, + "title": "v1.0", + "description": "Assumenda placeat ea voluptatem voluptate qui.", + "state": "active", + "created_at": "2016-06-17T07:47:34.163Z", + "updated_at": "2016-06-17T07:47:34.163Z", + "due_date": null + }, + "merge_when_build_succeeds": false, + "merge_status": "cannot_be_merged", + "subscribed": true, + "user_notes_count": 7 + }, + "target_url": "https://gitlab.example.com/gitlab-org/gitlab-ce/merge_requests/7", + "body": "Dolores in voluptatem tenetur praesentium omnis repellendus voluptatem quaerat.", "state": "done", - "created_at": "2016-05-20T20:51:51.503Z" - } + "created_at": "2016-06-17T07:49:24.624Z" + }, ] ``` diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 67d2c396b3..8cc4368b5c 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -277,16 +277,16 @@ module API expose :project, using: Entities::BasicProjectDetails expose :author, using: Entities::UserBasic expose :action_name - expose :target_id expose :target_type - expose :target_reference do |todo, options| - todo.target.to_reference + + expose :target do |todo, options| + Entities.const_get(todo.target_type).represent(todo.target, options) end expose :target_url do |todo, options| target_type = todo.target_type.underscore target_url = "namespace_project_#{target_type}_url" - target_anchor = "note_#{todo.note_id}" if todo.note.present? + target_anchor = "note_#{todo.note_id}" if todo.note_id? Gitlab::Application.routes.url_helpers.public_send(target_url, todo.project.namespace, todo.project, todo.target, anchor: target_anchor) diff --git a/lib/api/todos.rb b/lib/api/todos.rb index 67714a796c..8334baad1b 100644 --- a/lib/api/todos.rb +++ b/lib/api/todos.rb @@ -18,7 +18,7 @@ module API get do todos = find_todos - present paginate(todos), with: Entities::Todo + present paginate(todos), with: Entities::Todo, current_user: current_user end # Mark a todo as done @@ -33,7 +33,7 @@ module API todo = current_user.todos.find(params[:id]) todo.done - present todo, with: Entities::Todo + present todo, with: Entities::Todo, current_user: current_user end # Mark all todos as done @@ -45,7 +45,7 @@ module API todos = find_todos todos.each(&:done) - present paginate(Kaminari.paginate_array(todos)), with: Entities::Todo + present paginate(Kaminari.paginate_array(todos)), with: Entities::Todo, current_user: current_user end end end diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb index 8d54b4fd3d..f93f37e359 100644 --- a/spec/requests/api/todos_spec.rb +++ b/spec/requests/api/todos_spec.rb @@ -9,7 +9,7 @@ describe API::Todos, api: true do let(:author_2) { create(:user) } let(:john_doe) { create(:user, username: 'john_doe') } let(:merge_request) { create(:merge_request, source_project: project_1) } - let!(:pending_1) { create(:todo, project: project_1, author: author_1, user: john_doe) } + let!(:pending_1) { create(:todo, :mentioned, project: project_1, author: author_1, user: john_doe) } let!(:pending_2) { create(:todo, project: project_2, author: author_2, user: john_doe) } let!(:pending_3) { create(:todo, project: project_1, author: author_2, user: john_doe, target: merge_request) } let!(:done) { create(:todo, :done, project: project_1, author: author_1, user: john_doe) } @@ -38,9 +38,8 @@ describe API::Todos, api: true do expect(json_response[0]['id']).to eq(pending_3.id) expect(json_response[0]['project']).to be_a Hash expect(json_response[0]['author']).to be_a Hash - expect(json_response[0]['target_id']).to be_present expect(json_response[0]['target_type']).to be_present - expect(json_response[0]['target_reference']).to be_present + expect(json_response[0]['target']).to be_a Hash expect(json_response[0]['target_url']).to be_present expect(json_response[0]['body']).to be_present expect(json_response[0]['state']).to eq('pending') @@ -87,6 +86,16 @@ describe API::Todos, api: true do expect(json_response.length).to eq(1) end end + + context 'and using the action filter' do + it 'filters based on action param' do + get api('/todos', john_doe), { action: 'mentioned' } + + expect(response.status).to eq(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + end + end end end From 87ac9c9850d602fd18654498ab3fa005d2b85ac7 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Tue, 28 Jun 2016 18:04:44 +0200 Subject: [PATCH 85/98] Support creating a todo on issuables via API --- doc/api/issues.md | 93 ++++++++++++++++++++++++++++++- doc/api/merge_requests.md | 98 +++++++++++++++++++++++++++++++++ lib/api/todos.rb | 30 ++++++++++ spec/requests/api/todos_spec.rb | 49 ++++++++++++++++- 4 files changed, 268 insertions(+), 2 deletions(-) diff --git a/doc/api/issues.md b/doc/api/issues.md index 708fc691f6..3ced787b23 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -594,12 +594,103 @@ Example response: "id": 11, "state": "active", "avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon", - "web_url": "http://lgitlab.example.com/u/orville" + "web_url": "https://gitlab.example.com/u/orville" }, "subscribed": false } ``` +## Create a todo + +Manually creates a todo for the current user on an issue. If the request is +successful, status code `200` together with the created todo is returned. If +there already exists a todo for the user on that issue, status code `304` is +returned. + +``` +POST /projects/:id/issues/:issue_id/todo +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer | yes | The ID of a project | +| `issue_id` | integer | yes | The ID of a project's issue | + +```bash +curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/issues/93/todo +``` + +Example response: + +```json +{ + "id": 112, + "project": { + "id": 5, + "name": "Gitlab Ci", + "name_with_namespace": "Gitlab Org / Gitlab Ci", + "path": "gitlab-ci", + "path_with_namespace": "gitlab-org/gitlab-ci" + }, + "author": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/root" + }, + "action_name": "marked", + "target_type": "Issue", + "target": { + "id": 93, + "iid": 10, + "project_id": 5, + "title": "Vel voluptas atque dicta mollitia adipisci qui at.", + "description": "Tempora laboriosam sint magni sed voluptas similique.", + "state": "closed", + "created_at": "2016-06-17T07:47:39.486Z", + "updated_at": "2016-07-01T11:09:13.998Z", + "labels": [], + "milestone": { + "id": 26, + "iid": 1, + "project_id": 5, + "title": "v0.0", + "description": "Accusantium nostrum rerum quae quia quis nesciunt suscipit id.", + "state": "closed", + "created_at": "2016-06-17T07:47:33.832Z", + "updated_at": "2016-06-17T07:47:33.832Z", + "due_date": null + }, + "assignee": { + "name": "Jarret O'Keefe", + "username": "francisca", + "id": 14, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/a7fa515d53450023c83d62986d0658a8?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/francisca" + }, + "author": { + "name": "Maxie Medhurst", + "username": "craig_rutherford", + "id": 12, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/a0d477b3ea21970ce6ffcbb817b0b435?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/craig_rutherford" + }, + "subscribed": true, + "user_notes_count": 7, + "upvotes": 0, + "downvotes": 0 + }, + "target_url": "https://gitlab.example.com/gitlab-org/gitlab-ci/issues/10", + "body": "Vel voluptas atque dicta mollitia adipisci qui at.", + "state": "pending", + "created_at": "2016-07-01T11:09:13.992Z" +} +``` + ## Comments on issues Comments are done via the [notes](notes.md) resource. diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 2930f615fc..f60b0d0ebc 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -776,3 +776,101 @@ Example response: "subscribed": false } ``` + +## Create a todo + +Manually creates a todo for the current user on a merge request. If the +request is successful, status code `200` together with the created todo is +returned. If there already exists a todo for the user on that merge request, +status code `304` is returned. + +``` +POST /projects/:id/merge_requests/:merge_request_id/todo +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer | yes | The ID of a project | +| `merge_request_id` | integer | yes | The ID of the merge request | + +```bash +curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/merge_requests/27/todo +``` + +Example response: + +```json +{ + "id": 113, + "project": { + "id": 3, + "name": "Gitlab Ci", + "name_with_namespace": "Gitlab Org / Gitlab Ci", + "path": "gitlab-ci", + "path_with_namespace": "gitlab-org/gitlab-ci" + }, + "author": { + "name": "Administrator", + "username": "root", + "id": 1, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/root" + }, + "action_name": "marked", + "target_type": "MergeRequest", + "target": { + "id": 27, + "iid": 7, + "project_id": 3, + "title": "Et voluptas laudantium minus nihil recusandae ut accusamus earum aut non.", + "description": "Veniam sunt nihil modi earum cumque illum delectus. Nihil ad quis distinctio quia. Autem eligendi at quibusdam repellendus.", + "state": "opened", + "created_at": "2016-06-17T07:48:04.330Z", + "updated_at": "2016-07-01T11:14:15.537Z", + "target_branch": "allow_regex_for_project_skip_ref", + "source_branch": "backup", + "upvotes": 0, + "downvotes": 0, + "author": { + "name": "Jarret O'Keefe", + "username": "francisca", + "id": 14, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/a7fa515d53450023c83d62986d0658a8?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/francisca" + }, + "assignee": { + "name": "Dr. Gabrielle Strosin", + "username": "barrett.krajcik", + "id": 4, + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/733005fcd7e6df12d2d8580171ccb966?s=80&d=identicon", + "web_url": "https://gitlab.example.com/u/barrett.krajcik" + }, + "source_project_id": 3, + "target_project_id": 3, + "labels": [], + "work_in_progress": false, + "milestone": { + "id": 27, + "iid": 2, + "project_id": 3, + "title": "v1.0", + "description": "Quis ea accusantium animi hic fuga assumenda.", + "state": "active", + "created_at": "2016-06-17T07:47:33.840Z", + "updated_at": "2016-06-17T07:47:33.840Z", + "due_date": null + }, + "merge_when_build_succeeds": false, + "merge_status": "unchecked", + "subscribed": true, + "user_notes_count": 7 + }, + "target_url": "https://gitlab.example.com/gitlab-org/gitlab-ci/merge_requests/7", + "body": "Et voluptas laudantium minus nihil recusandae ut accusamus earum aut non.", + "state": "pending", + "created_at": "2016-07-01T11:14:15.530Z" +} +``` diff --git a/lib/api/todos.rb b/lib/api/todos.rb index 8334baad1b..2a6bfa98ca 100644 --- a/lib/api/todos.rb +++ b/lib/api/todos.rb @@ -3,6 +3,36 @@ module API class Todos < Grape::API before { authenticate! } + ISSUABLE_TYPES = { + 'merge_requests' => ->(id) { user_project.merge_requests.find(id) }, + 'issues' => ->(id) { find_project_issue(id) } + } + + resource :projects do + ISSUABLE_TYPES.each do |type, finder| + type_id_str = "#{type.singularize}_id".to_sym + + # Create a todo on an issuable + # + # Parameters: + # id (required) - The ID of a project + # issuable_id (required) - The ID of an issuable + # Example Request: + # POST /projects/:id/issues/:issuable_id/todo + # POST /projects/:id/merge_requests/:issuable_id/todo + post ":id/#{type}/:#{type_id_str}/todo" do + issuable = instance_exec(params[type_id_str], &finder) + todo = TodoService.new.mark_todo(issuable, current_user).first + + if todo + present todo, with: Entities::Todo, current_user: current_user + else + not_modified! + end + end + end + end + resource :todos do helpers do def find_todos diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb index f93f37e359..92a4fa216c 100644 --- a/spec/requests/api/todos_spec.rb +++ b/spec/requests/api/todos_spec.rb @@ -11,7 +11,7 @@ describe API::Todos, api: true do let(:merge_request) { create(:merge_request, source_project: project_1) } let!(:pending_1) { create(:todo, :mentioned, project: project_1, author: author_1, user: john_doe) } let!(:pending_2) { create(:todo, project: project_2, author: author_2, user: john_doe) } - let!(:pending_3) { create(:todo, project: project_1, author: author_2, user: john_doe, target: merge_request) } + let!(:pending_3) { create(:todo, project: project_1, author: author_2, user: john_doe) } let!(:done) { create(:todo, :done, project: project_1, author: author_1, user: john_doe) } before do @@ -59,6 +59,8 @@ describe API::Todos, api: true do context 'and using the type filter' do it 'filters based on type param' do + create(:todo, project: project_1, author: author_2, user: john_doe, target: merge_request) + get api('/todos', john_doe), { type: 'MergeRequest' } expect(response.status).to eq(200) @@ -140,4 +142,49 @@ describe API::Todos, api: true do end end end + + shared_examples 'an issuable' do |issuable_type| + it 'creates a todo on an issuable' do + post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.id}/todo", john_doe) + + expect(response.status).to eq(201) + expect(json_response['project']).to be_a Hash + expect(json_response['author']).to be_a Hash + expect(json_response['target_type']).to eq(issuable.class.name) + expect(json_response['target']).to be_a Hash + expect(json_response['target_url']).to be_present + expect(json_response['body']).to be_present + expect(json_response['state']).to eq('pending') + expect(json_response['action_name']).to eq('marked') + expect(json_response['created_at']).to be_present + end + + it 'returns 304 there already exist a todo on that issuable' do + create(:todo, project: project_1, author: author_1, user: john_doe, target: issuable) + + post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.id}/todo", john_doe) + + expect(response.status).to eq(304) + end + + it 'returns 404 if the issuable is not found' do + post api("/projects/#{project_1.id}/#{issuable_type}/123/todo", john_doe) + + expect(response.status).to eq(404) + end + end + + describe 'POST :id/issuable_type/:issueable_id/todo' do + context 'for an issue' do + it_behaves_like 'an issuable', 'issues' do + let(:issuable) { create(:issue, author: author_1, project: project_1) } + end + end + + context 'for a merge request' do + it_behaves_like 'an issuable', 'merge_requests' do + let(:issuable) { merge_request } + end + end + end end From f29c30475e621dedae24791ae9b144b6bef2f80a Mon Sep 17 00:00:00 2001 From: James Lopez Date: Fri, 1 Jul 2016 15:34:10 +0200 Subject: [PATCH 86/98] use has_many relationship with events --- app/models/concerns/eventable.rb | 15 --------------- app/models/issue.rb | 3 ++- app/models/merge_request.rb | 3 ++- app/models/milestone.rb | 2 +- app/models/note.rb | 2 +- lib/gitlab/import_export/relation_factory.rb | 1 + .../import_export/project_tree_restorer_spec.rb | 6 ++++++ 7 files changed, 13 insertions(+), 19 deletions(-) delete mode 100644 app/models/concerns/eventable.rb diff --git a/app/models/concerns/eventable.rb b/app/models/concerns/eventable.rb deleted file mode 100644 index aa23b350a0..0000000000 --- a/app/models/concerns/eventable.rb +++ /dev/null @@ -1,15 +0,0 @@ -module Eventable - extend ActiveSupport::Concern - - def events - Event.where(target_id: id, target_type: self.class.to_s) - end - - def events=(events) - events.each do |event| - event.target_id = id - event.data.deep_symbolize_keys! if event.data - event.save! - end - end -end diff --git a/app/models/issue.rb b/app/models/issue.rb index ae177c041e..60abd47409 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -6,7 +6,6 @@ class Issue < ActiveRecord::Base include Referable include Sortable include Taskable - include Eventable DueDateStruct = Struct.new(:title, :name).freeze NoDueDate = DueDateStruct.new('No Due Date', '0').freeze @@ -20,6 +19,8 @@ class Issue < ActiveRecord::Base belongs_to :project belongs_to :moved_to, class_name: 'Issue' + has_many :events, as: :target, dependent: :destroy + validates :project, presence: true scope :cared, ->(user) { where(assignee_id: user) } diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 326a0430eb..5ebc8f0c99 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -5,7 +5,6 @@ class MergeRequest < ActiveRecord::Base include Sortable include Taskable include Importable - include Eventable belongs_to :target_project, foreign_key: :target_project_id, class_name: "Project" belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project" @@ -13,6 +12,8 @@ class MergeRequest < ActiveRecord::Base has_one :merge_request_diff, dependent: :destroy + has_many :events, as: :target, dependent: :destroy + serialize :merge_params, Hash after_create :create_merge_request_diff, unless: :importing diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 2283376c8a..2bd7f19803 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -11,13 +11,13 @@ class Milestone < ActiveRecord::Base include Referable include StripAttribute include Milestoneish - include Eventable belongs_to :project has_many :issues has_many :labels, -> { distinct.reorder('labels.title') }, through: :issues has_many :merge_requests has_many :participants, -> { distinct.reorder('users.name') }, through: :issues, source: :assignee + has_many :events, as: :target, dependent: :destroy scope :active, -> { with_state(:active) } scope :closed, -> { with_state(:closed) } diff --git a/app/models/note.rb b/app/models/note.rb index ed26fb2d88..c2bb117eb0 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -5,7 +5,6 @@ class Note < ActiveRecord::Base include Mentionable include Awardable include Importable - include Eventable # Attribute containing rendered and redacted Markdown as generated by # Banzai::ObjectRenderer. @@ -22,6 +21,7 @@ class Note < ActiveRecord::Base belongs_to :updated_by, class_name: "User" has_many :todos, dependent: :destroy + has_many :events, as: :target, dependent: :destroy delegate :gfm_reference, :local_reference, to: :noteable delegate :name, to: :project, prefix: true diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb index 92bf7e0a2f..3fd89e08f0 100644 --- a/lib/gitlab/import_export/relation_factory.rb +++ b/lib/gitlab/import_export/relation_factory.rb @@ -33,6 +33,7 @@ module Gitlab update_user_references update_project_references reset_ci_tokens if @relation_name == 'Ci::Trigger' + @relation_hash['data'].deep_symbolize_keys! if @relation_name == :events && @relation_hash['data'] generate_imported_object end diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb index 23036ab810..e401ca9907 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -24,6 +24,12 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do expect(Ci::Pipeline.first.notes).not_to be_empty end + + it 'restores the correct event' do + restored_project_json + + expect(Event.where.not(data: nil).first.data[:ref]).not_to be_empty + end end end end From 1586846790045fe294ec558a8f9ee65e94fbe49f Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Fri, 1 Jul 2016 07:57:01 -0600 Subject: [PATCH 87/98] Upgrade seed-fu from 2.3.5 to 2.3.6 Adds Rails 5 support. Changelog: https://github.com/mbleigh/seed-fu/blob/master/CHANGELOG.md#version-236 --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f99b373dbb..8e125fc8e0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -649,9 +649,9 @@ GEM sdoc (0.3.20) json (>= 1.1.3) rdoc (~> 3.10) - seed-fu (2.3.5) - activerecord (>= 3.1, < 4.3) - activesupport (>= 3.1, < 4.3) + seed-fu (2.3.6) + activerecord (>= 3.1) + activesupport (>= 3.1) select2-rails (3.5.9.3) thor (~> 0.14) sentry-raven (1.1.0) From 44544b34819ae65d0f500fce7259f74a1ec1bde3 Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Fri, 1 Jul 2016 08:02:04 -0600 Subject: [PATCH 88/98] Upgrade Sidekiq from 4.1.2 to 4.1.4. Adds a dependency on Sinatra and allows Sinatra 2 for eventual support of Rack 2. Changelog: https://github.com/mperham/sidekiq/blob/master/Changes.md#414 --- Gemfile.lock | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f99b373dbb..b8f34d88ae 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -662,10 +662,11 @@ GEM rack shoulda-matchers (2.8.0) activesupport (>= 3.0.0) - sidekiq (4.1.2) + sidekiq (4.1.4) concurrent-ruby (~> 1.0) connection_pool (~> 2.2, >= 2.2.0) redis (~> 3.2, >= 3.2.1) + sinatra (>= 1.4.7) sidekiq-cron (0.4.0) redis-namespace (>= 1.5.2) rufus-scheduler (>= 2.0.24) @@ -676,8 +677,8 @@ GEM json (~> 1.8) simplecov-html (~> 0.10.0) simplecov-html (0.10.0) - sinatra (1.4.6) - rack (~> 1.4) + sinatra (1.4.7) + rack (~> 1.5) rack-protection (~> 1.4) tilt (>= 1.3, < 3) six (0.2.0) From cc154fc47b4ae2c81d9b8d92d725b4a082ed7727 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 1 Jul 2016 15:03:36 +0100 Subject: [PATCH 89/98] Cache autocomplete results --- app/assets/javascripts/gfm_auto_complete.js.coffee | 7 +++++-- app/views/layouts/_init_auto_complete.html.haml | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/gfm_auto_complete.js.coffee b/app/assets/javascripts/gfm_auto_complete.js.coffee index 190bb38504..b7d040bae8 100644 --- a/app/assets/javascripts/gfm_auto_complete.js.coffee +++ b/app/assets/javascripts/gfm_auto_complete.js.coffee @@ -4,7 +4,7 @@ window.GitLab ?= {} GitLab.GfmAutoComplete = dataLoading: false dataLoaded: false - + cachedData: {} dataSource: '' # Emoji @@ -55,7 +55,7 @@ GitLab.GfmAutoComplete = @setupAtWho() if @dataSource - if !@dataLoading + if not @dataLoading and not @cachedData @dataLoading = true # We should wait until initializations are done @@ -70,6 +70,8 @@ GitLab.GfmAutoComplete = @loadData(data) , 1000) + if @cachedData? + @loadData(@cachedData) setupAtWho: -> # Emoji @@ -205,6 +207,7 @@ GitLab.GfmAutoComplete = $.getJSON(dataSource) loadData: (data) -> + @cachedData = data @dataLoaded = true # load members diff --git a/app/views/layouts/_init_auto_complete.html.haml b/app/views/layouts/_init_auto_complete.html.haml index 96b3848542..12e7ed0e79 100644 --- a/app/views/layouts/_init_auto_complete.html.haml +++ b/app/views/layouts/_init_auto_complete.html.haml @@ -3,4 +3,5 @@ - if @noteable :javascript GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_namespace_project_path(project.namespace, project, type: @noteable.class, type_id: params[:id])}" + GitLab.GfmAutoComplete.cachedData = undefined; GitLab.GfmAutoComplete.setup(); From e7319d0a2570b229d3bbd3e64b95c8b4a2dedd69 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Fri, 1 Jul 2016 16:22:03 +0200 Subject: [PATCH 90/98] Many squashed commits --- CHANGELOG | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 7f4d9451d5..a019f56c0f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -31,17 +31,11 @@ v 8.10.0 (unreleased) - Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w) - Add basic system information like memory and disk usage to the admin panel -v 8.9.3 (unreleased) - - Decreased min width of screen to 1280px for pinned sidebar - - Fix encrypted data backwards compatibility after upgrading attr_encrypted gem - - Update mobile button icons to be more inline with typical UI paradigms - - Fixes missing avatar on system notes. !4954 - - Fixes issues importing events in Import/Export. Import/Export version bumped to 0.1.1 - - Improve performance of obtaining the maximum access of a user in a project v 8.9.5 (unreleased) - Improve the request / withdraw access button. !4860 - Fix assigning shared runners as admins. !4961 - Show "locked" label for locked runners on runners admin. !4961 + - Fixes issues importing events in Import/Export. Import/Export version bumped to 0.1.1 v 8.9.4 - Fix privilege escalation issue with OAuth external users. From fb056c78a7348b8f00024c908fa4b13c606cc1a7 Mon Sep 17 00:00:00 2001 From: Connor Shea Date: Fri, 1 Jul 2016 09:34:02 -0600 Subject: [PATCH 91/98] Upgrade Thin from 1.6.1 to 1.7.0. Includes support for Rack 2. Changelog: https://github.com/macournoyer/thin/blob/master/CHANGELOG --- Gemfile | 2 +- Gemfile.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 5213a59cab..1c360d165f 100644 --- a/Gemfile +++ b/Gemfile @@ -265,7 +265,7 @@ group :development do gem "sdoc", '~> 0.3.20' # thin instead webrick - gem 'thin', '~> 1.6.1' + gem 'thin', '~> 1.7.0' end group :development, :test do diff --git a/Gemfile.lock b/Gemfile.lock index f99b373dbb..195cc7a9d3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -727,10 +727,10 @@ GEM temple (0.7.7) test_after_commit (0.4.2) activerecord (>= 3.2) - thin (1.6.4) + thin (1.7.0) daemons (~> 1.0, >= 1.0.9) eventmachine (~> 1.0, >= 1.0.4) - rack (~> 1.0) + rack (>= 1, < 3) thor (0.19.1) thread_safe (0.3.5) tilt (2.0.5) @@ -973,7 +973,7 @@ DEPENDENCIES teaspoon (~> 1.1.0) teaspoon-jasmine (~> 2.2.0) test_after_commit (~> 0.4.2) - thin (~> 1.6.1) + thin (~> 1.7.0) tinder (~> 1.10.0) turbolinks (~> 2.5.0) u2f (~> 0.2.1) From bd78f5733ca546bf940438b84aefa2fa3abacb36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 27 Jun 2016 16:20:57 +0200 Subject: [PATCH 92/98] Exclude requesters from Project#members, Group#members and User#members MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And create new Project#requesters, Group#requesters scopes. Signed-off-by: Rémy Coutable --- app/controllers/admin/groups_controller.rb | 1 + app/controllers/admin/projects_controller.rb | 3 +- .../concerns/membership_actions.rb | 5 +- .../groups/group_members_controller.rb | 6 +- .../projects/project_members_controller.rb | 9 ++- app/helpers/members_helper.rb | 11 ++++ app/models/group.rb | 9 +-- app/models/member.rb | 2 - app/models/project.rb | 8 ++- app/models/project_team.rb | 14 ++-- app/views/admin/groups/show.html.haml | 8 +-- app/views/admin/projects/show.html.haml | 12 ++-- .../groups/group_members/index.html.haml | 10 +-- .../layouts/nav/_group_settings.html.haml | 2 +- app/views/layouts/nav/_project.html.haml | 2 +- .../_shared_group_members.html.haml | 2 +- .../projects/project_members/index.html.haml | 6 +- .../members/_access_request_buttons.html.haml | 16 ++--- app/views/shared/members/_requests.html.haml | 6 +- .../groups/group_members_controller_spec.rb | 6 +- .../project_members_controller_spec.rb | 6 +- .../owner_manages_access_requests_spec.rb | 2 +- .../members/user_requests_access_spec.rb | 8 +-- .../master_manages_access_requests_spec.rb | 2 +- .../members/user_requests_access_spec.rb | 8 +-- spec/helpers/members_helper_spec.rb | 66 +++++++++++++++++++ spec/mailers/notify_spec.rb | 10 +-- .../concerns/access_requestable_spec.rb | 4 +- spec/models/group_spec.rb | 29 ++++++++ spec/models/member_spec.rb | 20 +----- spec/models/project_spec.rb | 30 +++++++++ 31 files changed, 225 insertions(+), 98 deletions(-) diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb index a6db4690df..94b5aaa71d 100644 --- a/app/controllers/admin/groups_controller.rb +++ b/app/controllers/admin/groups_controller.rb @@ -10,6 +10,7 @@ class Admin::GroupsController < Admin::ApplicationController def show @members = @group.members.order("access_level DESC").page(params[:members_page]) + @requesters = @group.requesters @projects = @group.projects.page(params[:projects_page]) end diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index 87986fdf8b..4c9c6362ff 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -20,7 +20,8 @@ class Admin::ProjectsController < Admin::ApplicationController @group_members = @group.members.order("access_level DESC").page(params[:group_members_page]) end - @project_members = @project.project_members.page(params[:project_members_page]) + @project_members = @project.members.page(params[:project_members_page]) + @requesters = @project.requesters end def transfer diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb index 52dc396af6..52682ef9dc 100644 --- a/app/controllers/concerns/membership_actions.rb +++ b/app/controllers/concerns/membership_actions.rb @@ -10,7 +10,7 @@ module MembershipActions end def approve_access_request - @member = membershipable.members.request.find(params[:id]) + @member = membershipable.requesters.find(params[:id]) return render_403 unless can?(current_user, action_member_permission(:update, @member), @member) @@ -20,7 +20,8 @@ module MembershipActions end def leave - @member = membershipable.members.find_by(user_id: current_user) + @member = membershipable.members.find_by(user_id: current_user) || + membershipable.requesters.find_by(user_id: current_user) Members::DestroyService.new(@member, current_user).execute source_type = @member.real_source_type.humanize(capitalize: false) diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb index 2c49fe3833..9fc41a1253 100644 --- a/app/controllers/groups/group_members_controller.rb +++ b/app/controllers/groups/group_members_controller.rb @@ -7,7 +7,7 @@ class Groups::GroupMembersController < Groups::ApplicationController def index @project = @group.projects.find(params[:project_id]) if params[:project_id] @members = @group.group_members - @members = @members.non_pending unless can?(current_user, :admin_group, @group) + @members = @members.non_invite unless can?(current_user, :admin_group, @group) if params[:search].present? users = @group.users.search(params[:search]).to_a @@ -15,6 +15,7 @@ class Groups::GroupMembersController < Groups::ApplicationController end @members = @members.order('access_level DESC').page(params[:page]).per(50) + @requesters = @group.requesters if can?(current_user, :admin_group, @group) @group_member = @group.group_members.new end @@ -34,7 +35,8 @@ class Groups::GroupMembersController < Groups::ApplicationController end def destroy - @group_member = @group.group_members.find(params[:id]) + @group_member = @group.members.find_by(id: params[:id]) || + @group.requesters.find_by(id: params[:id]) Members::DestroyService.new(@group_member, current_user).execute diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 6ba32d3340..3435a11896 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -6,7 +6,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController def index @project_members = @project.project_members - @project_members = @project_members.non_pending unless can?(current_user, :admin_project, @project) + @project_members = @project_members.non_invite unless can?(current_user, :admin_project, @project) if params[:search].present? users = @project.users.search(params[:search]).to_a @@ -19,7 +19,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController if @group @group_members = @group.group_members - @group_members = @group_members.non_pending unless can?(current_user, :admin_group, @group) + @group_members = @group_members.non_invite unless can?(current_user, :admin_group, @group) if params[:search].present? users = @group.users.search(params[:search]).to_a @@ -29,6 +29,8 @@ class Projects::ProjectMembersController < Projects::ApplicationController @group_members = @group_members.order('access_level DESC') end + @requesters = @project.requesters if can?(current_user, :admin_project, @project) + @project_member = @project.project_members.new @project_group_links = @project.project_group_links end @@ -48,7 +50,8 @@ class Projects::ProjectMembersController < Projects::ApplicationController end def destroy - @project_member = @project.project_members.find(params[:id]) + @project_member = @project.members.find_by(id: params[:id]) || + @project.requesters.find_by(id: params[:id]) Members::DestroyService.new(@project_member, current_user).execute diff --git a/app/helpers/members_helper.rb b/app/helpers/members_helper.rb index ec106418f2..c70cd19b58 100644 --- a/app/helpers/members_helper.rb +++ b/app/helpers/members_helper.rb @@ -12,6 +12,17 @@ module MembersHelper can?(current_user, action_member_permission(:admin, member), member.source) end + def can_see_request_access_button?(source) + source_parent = source.respond_to?(:group) && source.group + + return false if source_parent && source.group.members.exists?(user_id: current_user.id) + return false if source_parent && source.group.requesters.exists?(user_id: current_user.id) + return false if source.members.exists?(user_id: current_user.id) + return true if source.requesters.exists?(user_id: current_user.id) + + true + end + def remove_member_message(member, user: nil) user = current_user if defined?(current_user) diff --git a/app/models/group.rb b/app/models/group.rb index c70c719e33..a8be7004ee 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -6,15 +6,16 @@ class Group < Namespace include AccessRequestable include Referable - has_many :group_members, dependent: :destroy, as: :source, class_name: 'GroupMember' + has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'GroupMember' alias_method :members, :group_members - has_many :users, -> { where(members: { requested_at: nil }) }, through: :group_members - + has_many :users, through: :group_members has_many :owners, - -> { where(members: { requested_at: nil, access_level: Gitlab::Access::OWNER }) }, + -> { where(members: { access_level: Gitlab::Access::OWNER }) }, through: :group_members, source: :user + has_many :requesters, -> { where.not(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'GroupMember' + has_many :project_group_links, dependent: :destroy has_many :shared_projects, through: :project_group_links, source: :project has_many :notification_settings, dependent: :destroy, as: :source diff --git a/app/models/member.rb b/app/models/member.rb index 57161397e2..44db3d977f 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -30,8 +30,6 @@ class Member < ActiveRecord::Base scope :invite, -> { where.not(invite_token: nil) } scope :non_invite, -> { where(invite_token: nil) } scope :request, -> { where.not(requested_at: nil) } - scope :non_request, -> { where(requested_at: nil) } - scope :non_pending, -> { non_request.non_invite } scope :has_access, -> { where('access_level > 0') } scope :guests, -> { where(access_level: GUEST) } diff --git a/app/models/project.rb b/app/models/project.rb index 6a950ee830..ae96f00a70 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -108,9 +108,13 @@ class Project < ActiveRecord::Base has_many :snippets, dependent: :destroy, class_name: 'ProjectSnippet' has_many :hooks, dependent: :destroy, class_name: 'ProjectHook' has_many :protected_branches, dependent: :destroy - has_many :project_members, dependent: :destroy, as: :source, class_name: 'ProjectMember' + + has_many :project_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'ProjectMember' alias_method :members, :project_members - has_many :users, -> { where(members: { requested_at: nil }) }, through: :project_members + has_many :users, through: :project_members + + has_many :requesters, -> { where.not(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'ProjectMember' + has_many :deploy_keys_projects, dependent: :destroy has_many :deploy_keys, through: :deploy_keys_projects has_many :users_star_projects, dependent: :destroy diff --git a/app/models/project_team.rb b/app/models/project_team.rb index 0865b979ce..0b70093064 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -22,12 +22,12 @@ class ProjectTeam end def find_member(user_id) - member = project.members.non_request.find_by(user_id: user_id) + member = project.members.find_by(user_id: user_id) # If user is not in project members # we should check for group membership if group && !member - member = group.members.non_request.find_by(user_id: user_id) + member = group.members.find_by(user_id: user_id) end member @@ -137,10 +137,10 @@ class ProjectTeam def max_member_access(user_id) access = [] - access += project.members.non_request.where(user_id: user_id).has_access.pluck(:access_level) + access += project.members.where(user_id: user_id).has_access.pluck(:access_level) if group - access += group.members.non_request.where(user_id: user_id).has_access.pluck(:access_level) + access += group.members.where(user_id: user_id).has_access.pluck(:access_level) end if project.invited_groups.any? && project.allowed_to_share_with_group? @@ -168,14 +168,14 @@ class ProjectTeam end def fetch_members(level = nil) - project_members = project.members.non_request - group_members = group ? group.members.non_request : [] + project_members = project.members + group_members = group ? group.members : [] invited_members = [] if project.invited_groups.any? && project.allowed_to_share_with_group? project.project_group_links.each do |group_link| invited_group = group_link.group - im = invited_group.members.non_request + im = invited_group.members if level int_level = GroupMember.access_level_roles[level.to_s.singularize.titleize] diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 50770465f0..522153b37e 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -89,16 +89,16 @@ %hr = button_tag 'Add users to group', class: "btn btn-create" - = render 'shared/members/requests', membership_source: @group, members: @members.request + = render 'shared/members/requests', membership_source: @group, requesters: @requesters .panel.panel-default .panel-heading %strong= @group.name group members - %span.badge= @group.members.non_request.size + %span.badge= @group.members.size .pull-right = link_to icon('pencil-square-o', text: 'Manage Access'), polymorphic_url([@group, :members]), class: "btn btn-xs" %ul.well-list.group-users-list.content-list - = render partial: 'shared/members/member', collection: @members.non_request, as: :member, locals: { show_controls: false } + = render partial: 'shared/members/member', collection: @members, as: :member, locals: { show_controls: false } .panel-footer - = paginate @members.non_request, param_name: 'members_page', theme: 'gitlab' + = paginate @members, param_name: 'members_page', theme: 'gitlab' diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 461d588415..82d3169c6f 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -137,16 +137,16 @@ .panel-heading %strong= @group.name group members - %span.badge= @group_members.non_request.size + %span.badge= @group_members.size .pull-right = link_to admin_group_path(@group), class: 'btn btn-xs' do = icon('pencil-square-o', text: 'Manage Access') %ul.well-list.content-list - = render partial: 'shared/members/member', collection: @group_members.non_request, as: :member, locals: { show_controls: false } + = render partial: 'shared/members/member', collection: @group_members, as: :member, locals: { show_controls: false } .panel-footer - = paginate @group_members.non_request, param_name: 'group_members_page', theme: 'gitlab' + = paginate @group_members, param_name: 'group_members_page', theme: 'gitlab' - = render 'shared/members/requests', membership_source: @project, members: @project_members.request + = render 'shared/members/requests', membership_source: @project, requesters: @requesters .panel.panel-default .panel-heading @@ -156,6 +156,6 @@ .pull-right = link_to icon('pencil-square-o', text: 'Manage Access'), polymorphic_url([@project, :members]), class: "btn btn-xs" %ul.well-list.project_members.content-list - = render partial: 'shared/members/member', collection: @project_members.non_request, as: :member, locals: { show_controls: false } + = render partial: 'shared/members/member', collection: @project_members, as: :member, locals: { show_controls: false } .panel-footer - = paginate @project_members.non_request, param_name: 'project_members_page', theme: 'gitlab' + = paginate @project_members, param_name: 'project_members_page', theme: 'gitlab' diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml index d6acade84f..90f362c052 100644 --- a/app/views/groups/group_members/index.html.haml +++ b/app/views/groups/group_members/index.html.haml @@ -1,7 +1,7 @@ - page_title "Members" .group-members-page.prepend-top-default - - if current_user && current_user.can?(:admin_group_member, @group) + - if can?(current_user, :admin_group_member, @group) .panel.panel-default .panel-heading Add new user to group @@ -11,13 +11,13 @@ .new-group-member-holder = render "new_group_member" - = render 'shared/members/requests', membership_source: @group, members: @members.request + = render 'shared/members/requests', membership_source: @group, requesters: @requesters .panel.panel-default .panel-heading %strong #{@group.name} group members - %span.badge= @members.non_request.size + %span.badge= @members.size .controls = form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form' do .form-group @@ -25,8 +25,8 @@ = button_tag class: 'btn', title: 'Search' do = icon("search") %ul.content-list - = render partial: 'shared/members/member', collection: @members.non_request, as: :member - = paginate @members.non_request, theme: 'gitlab' + = render partial: 'shared/members/member', collection: @members, as: :member + = paginate @members, theme: 'gitlab' :javascript $('form.member-search-form').on('submit', function(event) { diff --git a/app/views/layouts/nav/_group_settings.html.haml b/app/views/layouts/nav/_group_settings.html.haml index 3a24b09ab7..bf9a7ecb78 100644 --- a/app/views/layouts/nav/_group_settings.html.haml +++ b/app/views/layouts/nav/_group_settings.html.haml @@ -1,6 +1,6 @@ - if current_user - can_edit = can?(current_user, :admin_group, @group) - - member = @group.members.non_request.find_by(user_id: current_user.id) + - member = @group.members.find_by(user_id: current_user.id) - can_leave = member && can?(current_user, :destroy_group_member, member) .controls diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index dcef427cda..9e65d94186 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -7,7 +7,7 @@ %ul.dropdown-menu.dropdown-menu-align-right - can_edit = can?(current_user, :admin_project, @project) -# We don't use @project.team.find_member because it searches for group members too... - - member = @project.members.non_request.find_by(user_id: current_user.id) + - member = @project.members.find_by(user_id: current_user.id) - can_leave = member && can?(current_user, :destroy_project_member, member) = render 'layouts/nav/project_settings', can_edit: can_edit diff --git a/app/views/projects/project_members/_shared_group_members.html.haml b/app/views/projects/project_members/_shared_group_members.html.haml index 840b57c2e6..77370c14de 100644 --- a/app/views/projects/project_members/_shared_group_members.html.haml +++ b/app/views/projects/project_members/_shared_group_members.html.haml @@ -1,6 +1,6 @@ - @project_group_links.each do |group_links| - shared_group = group_links.group - - shared_group_members = shared_group.members.non_request + - shared_group_members = shared_group.members - shared_group_users_count = shared_group_members.size .panel.panel-default .panel-heading diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index a2026c41d0..9031f01b49 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -13,12 +13,12 @@ Users with access to this project are listed below. = render "new_project_member" - = render 'shared/members/requests', membership_source: @project, members: @project_members.request + = render 'shared/members/requests', membership_source: @project, requesters: @requesters - = render 'team', members: @project_members.non_request + = render 'team', members: @project_members - if @group - = render "group_members", members: @group_members.non_request + = render "group_members", members: @group_members - if @project_group_links.any? && @project.allowed_to_share_with_group? = render "shared_group_members" diff --git a/app/views/shared/members/_access_request_buttons.html.haml b/app/views/shared/members/_access_request_buttons.html.haml index c56418f052..35dcdccc92 100644 --- a/app/views/shared/members/_access_request_buttons.html.haml +++ b/app/views/shared/members/_access_request_buttons.html.haml @@ -1,13 +1,9 @@ -- member = source.members.find_by(user_id: current_user.id) -- group_member = source.group.members.find_by(user_id: current_user.id) if source.respond_to?(:group) && source.group - -- unless group_member - - if member - - if member.request? - = link_to 'Withdraw Access Request', polymorphic_path([:leave, source, :members]), - method: :delete, - data: { confirm: remove_member_message(member) }, - class: 'btn' +- if can_see_request_access_button?(source) + - if requester = source.requesters.find_by(user_id: current_user.id) + = link_to 'Withdraw Access Request', polymorphic_path([:leave, source, :members]), + method: :delete, + data: { confirm: remove_member_message(requester) }, + class: 'btn' - else = link_to 'Request Access', polymorphic_path([:request_access, source, :members]), method: :post, diff --git a/app/views/shared/members/_requests.html.haml b/app/views/shared/members/_requests.html.haml index e4bd2bdc26..40b39e850b 100644 --- a/app/views/shared/members/_requests.html.haml +++ b/app/views/shared/members/_requests.html.haml @@ -1,8 +1,8 @@ -- if members.any? +- if requesters.any? .panel.panel-default .panel-heading %strong= membership_source.name access requests - %span.badge= members.size + %span.badge= requesters.size %ul.content-list - = render partial: 'shared/members/member', collection: members, as: :member + = render partial: 'shared/members/member', collection: requesters, as: :member diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb index ddc54108a7..c34475976c 100644 --- a/spec/controllers/groups/group_members_controller_spec.rb +++ b/spec/controllers/groups/group_members_controller_spec.rb @@ -133,7 +133,7 @@ describe Groups::GroupMembersController do expect(response).to set_flash.to 'Your access request to the group has been withdrawn.' expect(response).to redirect_to(group_path(group)) - expect(group.members.request).to be_empty + expect(group.requesters).to be_empty expect(group.users).not_to include user end end @@ -153,7 +153,7 @@ describe Groups::GroupMembersController do expect(response).to set_flash.to 'Your request for access has been queued for review.' expect(response).to redirect_to(group_path(group)) - expect(group.members.request.exists?(user_id: user)).to be_truthy + expect(group.requesters.exists?(user_id: user)).to be_truthy expect(group.users).not_to include user end end @@ -175,7 +175,7 @@ describe Groups::GroupMembersController do let(:group_requester) { create(:user) } let(:member) do group.request_access(group_requester) - group.members.request.find_by(user_id: group_requester) + group.requesters.find_by(user_id: group_requester) end context 'when user does not have enough rights' do diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb index 29aaceb230..5e2a8cf384 100644 --- a/spec/controllers/projects/project_members_controller_spec.rb +++ b/spec/controllers/projects/project_members_controller_spec.rb @@ -187,7 +187,7 @@ describe Projects::ProjectMembersController do expect(response).to set_flash.to 'Your access request to the project has been withdrawn.' expect(response).to redirect_to(namespace_project_path(project.namespace, project)) - expect(project.members.request).to be_empty + expect(project.requesters).to be_empty expect(project.users).not_to include user end end @@ -210,7 +210,7 @@ describe Projects::ProjectMembersController do expect(response).to redirect_to( namespace_project_path(project.namespace, project) ) - expect(project.members.request.exists?(user_id: user)).to be_truthy + expect(project.requesters.exists?(user_id: user)).to be_truthy expect(project.users).not_to include user end end @@ -233,7 +233,7 @@ describe Projects::ProjectMembersController do let(:team_requester) { create(:user) } let(:member) do project.request_access(team_requester) - project.members.request.find_by(user_id: team_requester.id) + project.requesters.find_by(user_id: team_requester.id) end context 'when user does not have enough rights' do diff --git a/spec/features/groups/members/owner_manages_access_requests_spec.rb b/spec/features/groups/members/owner_manages_access_requests_spec.rb index 321c9bad7d..2aae3e0026 100644 --- a/spec/features/groups/members/owner_manages_access_requests_spec.rb +++ b/spec/features/groups/members/owner_manages_access_requests_spec.rb @@ -41,7 +41,7 @@ feature 'Groups > Members > Owner manages access requests', feature: true do def expect_visible_access_request(group, user) - expect(group.members.request.exists?(user_id: user)).to be_truthy + expect(group.requesters.exists?(user_id: user)).to be_truthy expect(page).to have_content "#{group.name} access requests 1" expect(page).to have_content user.name end diff --git a/spec/features/groups/members/user_requests_access_spec.rb b/spec/features/groups/members/user_requests_access_spec.rb index 4944301c93..d1a6a98ab7 100644 --- a/spec/features/groups/members/user_requests_access_spec.rb +++ b/spec/features/groups/members/user_requests_access_spec.rb @@ -18,7 +18,7 @@ feature 'Groups > Members > User requests access', feature: true do expect(ActionMailer::Base.deliveries.last.to).to eq [owner.notification_email] expect(ActionMailer::Base.deliveries.last.subject).to match "Request to join the #{group.name} group" - expect(group.members.request.exists?(user_id: user)).to be_truthy + expect(group.requesters.exists?(user_id: user)).to be_truthy expect(page).to have_content 'Your request for access has been queued for review.' expect(page).to have_content 'Withdraw Access Request' @@ -42,7 +42,7 @@ feature 'Groups > Members > User requests access', feature: true do scenario 'user is not listed in the group members page' do click_link 'Request Access' - expect(group.members.request.exists?(user_id: user)).to be_truthy + expect(group.requesters.exists?(user_id: user)).to be_truthy click_link 'Members' @@ -54,11 +54,11 @@ feature 'Groups > Members > User requests access', feature: true do scenario 'user can withdraw its request for access' do click_link 'Request Access' - expect(group.members.request.exists?(user_id: user)).to be_truthy + expect(group.requesters.exists?(user_id: user)).to be_truthy click_link 'Withdraw Access Request' - expect(group.members.request.exists?(user_id: user)).to be_falsey + expect(group.requesters.exists?(user_id: user)).to be_falsey expect(page).to have_content 'Your access request to the group has been withdrawn.' end end diff --git a/spec/features/projects/members/master_manages_access_requests_spec.rb b/spec/features/projects/members/master_manages_access_requests_spec.rb index aa2d906fa2..f7fcd9b673 100644 --- a/spec/features/projects/members/master_manages_access_requests_spec.rb +++ b/spec/features/projects/members/master_manages_access_requests_spec.rb @@ -40,7 +40,7 @@ feature 'Projects > Members > Master manages access requests', feature: true do end def expect_visible_access_request(project, user) - expect(project.members.request.exists?(user_id: user)).to be_truthy + expect(project.requesters.exists?(user_id: user)).to be_truthy expect(page).to have_content "#{project.name} access requests 1" expect(page).to have_content user.name end diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb index af420c170e..f2fe3ef364 100644 --- a/spec/features/projects/members/user_requests_access_spec.rb +++ b/spec/features/projects/members/user_requests_access_spec.rb @@ -17,7 +17,7 @@ feature 'Projects > Members > User requests access', feature: true do expect(ActionMailer::Base.deliveries.last.to).to eq [master.notification_email] expect(ActionMailer::Base.deliveries.last.subject).to eq "Request to join the #{project.name_with_namespace} project" - expect(project.members.request.exists?(user_id: user)).to be_truthy + expect(project.requesters.exists?(user_id: user)).to be_truthy expect(page).to have_content 'Your request for access has been queued for review.' expect(page).to have_content 'Withdraw Access Request' @@ -27,7 +27,7 @@ feature 'Projects > Members > User requests access', feature: true do scenario 'user is not listed in the project members page' do click_link 'Request Access' - expect(project.members.request.exists?(user_id: user)).to be_truthy + expect(project.requesters.exists?(user_id: user)).to be_truthy open_project_settings_menu click_link 'Members' @@ -41,11 +41,11 @@ feature 'Projects > Members > User requests access', feature: true do scenario 'user can withdraw its request for access' do click_link 'Request Access' - expect(project.members.request.exists?(user_id: user)).to be_truthy + expect(project.requesters.exists?(user_id: user)).to be_truthy click_link 'Withdraw Access Request' - expect(project.members.request.exists?(user_id: user)).to be_falsey + expect(project.requesters.exists?(user_id: user)).to be_falsey expect(page).to have_content 'Your access request to the project has been withdrawn.' end diff --git a/spec/helpers/members_helper_spec.rb b/spec/helpers/members_helper_spec.rb index f75fdb739f..7b2155e9a4 100644 --- a/spec/helpers/members_helper_spec.rb +++ b/spec/helpers/members_helper_spec.rb @@ -57,6 +57,72 @@ describe MembersHelper do end end + describe '#can_see_request_access_button?' do + let(:user) { create(:user) } + let(:group) { create(:group, :public) } + let(:project) { create(:project, :public, group: group) } + + before do + allow(helper).to receive(:current_user).and_return(user) + end + + context 'source is a group' do + context 'current_user is not a member' do + it 'returns true' do + expect(helper.can_see_request_access_button?(group)).to be_truthy + end + end + + context 'current_user is a member' do + it 'returns false' do + group.add_owner(user) + + expect(helper.can_see_request_access_button?(group)).to be_falsy + end + end + + context 'current_user is a requester' do + it 'returns true' do + group.request_access(user) + + expect(helper.can_see_request_access_button?(group)).to be_truthy + end + end + end + + context 'source is a project' do + context 'current_user is not a member' do + it 'returns true' do + expect(helper.can_see_request_access_button?(project)).to be_truthy + end + end + + context 'current_user is a group member' do + it 'returns false' do + group.add_owner(user) + + expect(helper.can_see_request_access_button?(project)).to be_falsy + end + end + + context 'current_user is a group requester' do + it 'returns false' do + group.request_access(user) + + expect(helper.can_see_request_access_button?(project)).to be_falsy + end + end + + context 'current_user is a member' do + it 'returns false' do + project.team << [user, :master] + + expect(helper.can_see_request_access_button?(project)).to be_falsy + end + end + end + end + describe '#remove_member_message' do let(:requester) { build(:user) } let(:project) { create(:project) } diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index ae55a01ebe..e527d649e3 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -406,7 +406,7 @@ describe Notify do let(:user) { create(:user) } let(:project_member) do project.request_access(user) - project.members.request.find_by(user_id: user.id) + project.requesters.find_by(user_id: user.id) end subject { Notify.member_access_requested_email('project', project_member.id) } @@ -433,7 +433,7 @@ describe Notify do let(:user) { create(:user) } let(:project_member) do project.request_access(user) - project.members.request.find_by(user_id: user.id) + project.requesters.find_by(user_id: user.id) end subject { Notify.member_access_requested_email('project', project_member.id) } @@ -459,7 +459,7 @@ describe Notify do let(:user) { create(:user) } let(:project_member) do project.request_access(user) - project.members.request.find_by(user_id: user.id) + project.requesters.find_by(user_id: user.id) end subject { Notify.member_access_denied_email('project', project.id, user.id) } @@ -684,7 +684,7 @@ describe Notify do let(:user) { create(:user) } let(:group_member) do group.request_access(user) - group.members.request.find_by(user_id: user.id) + group.requesters.find_by(user_id: user.id) end subject { Notify.member_access_requested_email('group', group_member.id) } @@ -705,7 +705,7 @@ describe Notify do let(:user) { create(:user) } let(:group_member) do group.request_access(user) - group.members.request.find_by(user_id: user.id) + group.requesters.find_by(user_id: user.id) end subject { Notify.member_access_denied_email('group', group.id, user.id) } diff --git a/spec/models/concerns/access_requestable_spec.rb b/spec/models/concerns/access_requestable_spec.rb index 9830787696..96eee0e8bd 100644 --- a/spec/models/concerns/access_requestable_spec.rb +++ b/spec/models/concerns/access_requestable_spec.rb @@ -16,7 +16,7 @@ describe AccessRequestable do before { group.request_access(user) } - it { expect(group.members.request.exists?(user_id: user)).to be_truthy } + it { expect(group.requesters.exists?(user_id: user)).to be_truthy } end end @@ -34,7 +34,7 @@ describe AccessRequestable do before { project.request_access(user) } - it { expect(project.members.request.exists?(user_id: user)).to be_truthy } + it { expect(project.requesters.exists?(user_id: user)).to be_truthy } end end end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 2c19aa3f67..a878ff1b22 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -7,9 +7,38 @@ describe Group, models: true do it { is_expected.to have_many :projects } it { is_expected.to have_many(:group_members).dependent(:destroy) } it { is_expected.to have_many(:users).through(:group_members) } + it { is_expected.to have_many(:owners).through(:group_members) } + it { is_expected.to have_many(:requesters).dependent(:destroy) } it { is_expected.to have_many(:project_group_links).dependent(:destroy) } it { is_expected.to have_many(:shared_projects).through(:project_group_links) } it { is_expected.to have_many(:notification_settings).dependent(:destroy) } + + describe '#members & #requesters' do + let(:requester) { create(:user) } + let(:developer) { create(:user) } + before do + group.request_access(requester) + group.add_developer(developer) + end + + describe '#members' do + it 'includes members and exclude requesters' do + member_user_ids = group.members.pluck(:user_id) + + expect(member_user_ids).to include(developer.id) + expect(member_user_ids).not_to include(requester.id) + end + end + + describe '#requesters' do + it 'does not include requesters' do + requester_user_ids = group.requesters.pluck(:user_id) + + expect(requester_user_ids).to include(requester.id) + expect(requester_user_ids).not_to include(developer.id) + end + end + end end describe 'modules' do diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb index e9134a3d28..40181a8b90 100644 --- a/spec/models/member_spec.rb +++ b/spec/models/member_spec.rb @@ -73,10 +73,10 @@ describe Member, models: true do @accepted_invite_member = project.members.invite.find_by_invite_email('toto2@example.com').tap { |u| u.accept_invite!(accepted_invite_user) } requested_user = create(:user).tap { |u| project.request_access(u) } - @requested_member = project.members.request.find_by(user_id: requested_user.id) + @requested_member = project.requesters.find_by(user_id: requested_user.id) accepted_request_user = create(:user).tap { |u| project.request_access(u) } - @accepted_request_member = project.members.request.find_by(user_id: accepted_request_user.id).tap { |m| m.accept_request } + @accepted_request_member = project.requesters.find_by(user_id: accepted_request_user.id).tap { |m| m.accept_request } end describe '.invite' do @@ -103,22 +103,6 @@ describe Member, models: true do it { expect(described_class.request).not_to include @accepted_request_member } end - describe '.non_request' do - it { expect(described_class.non_request).to include @master } - it { expect(described_class.non_request).to include @invited_member } - it { expect(described_class.non_request).to include @accepted_invite_member } - it { expect(described_class.non_request).not_to include @requested_member } - it { expect(described_class.non_request).to include @accepted_request_member } - end - - describe '.non_pending' do - it { expect(described_class.non_pending).to include @master } - it { expect(described_class.non_pending).not_to include @invited_member } - it { expect(described_class.non_pending).to include @accepted_invite_member } - it { expect(described_class.non_pending).not_to include @requested_member } - it { expect(described_class.non_pending).to include @accepted_request_member } - end - describe '.owners_and_masters' do it { expect(described_class.owners_and_masters).to include @owner } it { expect(described_class.owners_and_masters).to include @master } diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 42308035d8..a8c777d1e3 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -11,6 +11,8 @@ describe Project, models: true do it { is_expected.to have_many(:issues).dependent(:destroy) } it { is_expected.to have_many(:milestones).dependent(:destroy) } it { is_expected.to have_many(:project_members).dependent(:destroy) } + it { is_expected.to have_many(:users).through(:project_members) } + it { is_expected.to have_many(:requesters).dependent(:destroy) } it { is_expected.to have_many(:notes).dependent(:destroy) } it { is_expected.to have_many(:snippets).class_name('ProjectSnippet').dependent(:destroy) } it { is_expected.to have_many(:deploy_keys_projects).dependent(:destroy) } @@ -31,6 +33,34 @@ describe Project, models: true do it { is_expected.to have_many(:environments).dependent(:destroy) } it { is_expected.to have_many(:deployments).dependent(:destroy) } it { is_expected.to have_many(:todos).dependent(:destroy) } + + describe '#members & #requesters' do + let(:project) { create(:project) } + let(:requester) { create(:user) } + let(:developer) { create(:user) } + before do + project.request_access(requester) + project.team << [developer, :developer] + end + + describe '#members' do + it 'includes members and exclude requesters' do + member_user_ids = project.members.pluck(:user_id) + + expect(member_user_ids).to include(developer.id) + expect(member_user_ids).not_to include(requester.id) + end + end + + describe '#requesters' do + it 'does not include requesters' do + requester_user_ids = project.requesters.pluck(:user_id) + + expect(requester_user_ids).to include(requester.id) + expect(requester_user_ids).not_to include(developer.id) + end + end + end end describe 'modules' do From 4bfe10d5f972c64241cfdd0393d4d55a63092dc4 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 30 Jun 2016 12:12:16 -0700 Subject: [PATCH 93/98] Fix emoji paths in relative root configurations If a site specifies a relative URL root, emoji files would omit the path from the URL, leading to lots of 404s. Closes #15642 --- lib/gitlab/award_emoji.rb | 11 ++++++++++- spec/lib/gitlab/award_emoji_spec.rb | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/award_emoji.rb b/lib/gitlab/award_emoji.rb index 51b1df9ecb..c94bfc0e65 100644 --- a/lib/gitlab/award_emoji.rb +++ b/lib/gitlab/award_emoji.rb @@ -66,8 +66,17 @@ module Gitlab def self.urls @urls ||= begin path = File.join(Rails.root, 'fixtures', 'emojis', 'digests.json') + # Construct the full asset path ourselves because + # ActionView::Helpers::AssetUrlHelper.asset_url is slow for hundreds + # of entries since it has to do a lot of extra work (e.g. regexps). prefix = Gitlab::Application.config.assets.prefix digest = Gitlab::Application.config.assets.digest + base = + if defined?(Gitlab::Application.config.relative_url_root) && Gitlab::Application.config.relative_url_root + Gitlab::Application.config.relative_url_root + else + '' + end JSON.parse(File.read(path)).map do |hash| if digest @@ -76,7 +85,7 @@ module Gitlab fname = hash['unicode'] end - { name: hash['name'], path: "#{prefix}/#{fname}.png" } + { name: hash['name'], path: File.join(base, prefix, "#{fname}.png") } end end end diff --git a/spec/lib/gitlab/award_emoji_spec.rb b/spec/lib/gitlab/award_emoji_spec.rb index 0f3852b172..00a110e31f 100644 --- a/spec/lib/gitlab/award_emoji_spec.rb +++ b/spec/lib/gitlab/award_emoji_spec.rb @@ -2,6 +2,10 @@ require 'spec_helper' describe Gitlab::AwardEmoji do describe '.urls' do + after do + Gitlab::AwardEmoji.instance_variable_set(:@urls, nil) + end + subject { Gitlab::AwardEmoji.urls } it { is_expected.to be_an_instance_of(Array) } @@ -15,6 +19,17 @@ describe Gitlab::AwardEmoji do end end end + + context 'handles relative root' do + it 'includes the full path' do + allow(Gitlab::Application.config).to receive(:relative_url_root).and_return('/gitlab') + + subject.each do |hash| + expect(hash[:name]).to be_an_instance_of(String) + expect(hash[:path]).to start_with('/gitlab') + end + end + end end describe '.emoji_by_category' do From d71983f599afd3b81bdda42eec3e989ef7ea02d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 1 Jul 2016 17:15:48 +0200 Subject: [PATCH 94/98] Fix snippets comments not displayed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The issue was that @notes were not passed to Banzai::NoteRenderer.render in Projects::SnippetsController#show. This was forgotten in d470f3d1. Signed-off-by: Rémy Coutable --- app/controllers/projects/snippets_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb index 6d2901a24a..6d0a7ee103 100644 --- a/app/controllers/projects/snippets_controller.rb +++ b/app/controllers/projects/snippets_controller.rb @@ -54,7 +54,7 @@ class Projects::SnippetsController < Projects::ApplicationController def show @note = @project.notes.new(noteable: @snippet) - @notes = @snippet.notes.fresh + @notes = Banzai::NoteRenderer.render(@snippet.notes.fresh, @project, current_user) @noteable = @snippet end From 8353cc6111e12fa819debe188776d7b6195ffaad Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Fri, 1 Jul 2016 16:04:24 -0300 Subject: [PATCH 95/98] Fix import button when import fail due the namespace already been taken --- app/assets/javascripts/importer_status.js.coffee | 2 +- app/views/import/base/create.js.haml | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/importer_status.js.coffee b/app/assets/javascripts/importer_status.js.coffee index b0edc89564..ec42c992e9 100644 --- a/app/assets/javascripts/importer_status.js.coffee +++ b/app/assets/javascripts/importer_status.js.coffee @@ -13,7 +13,7 @@ class @ImporterStatus id = $tr.attr('id').replace('repo_', '') if $tr.find('.import-target input').length > 0 new_namespace = $tr.find('.import-target input').prop('value') - $tr.find('.import-target').empty().append("#{new_namespace} / #{$tr.find('.import-target').data('project_name')}") + $tr.find('.import-target').empty().append("#{new_namespace}/#{$tr.find('.import-target').data('project_name')}") $btn .disable() diff --git a/app/views/import/base/create.js.haml b/app/views/import/base/create.js.haml index dfebf7768d..804ad88468 100644 --- a/app/views/import/base/create.js.haml +++ b/app/views/import/base/create.js.haml @@ -1,6 +1,8 @@ - if @already_been_taken :plain - target_field = $("tr#repo_#{@repo_id} .import-target") + tr = $("tr#repo_#{@repo_id}") + target_field = tr.find(".import-target") + import_button = tr.find(".btn-import") origin_target = target_field.text() project_name = "#{@project_name}" origin_namespace = "#{@target_namespace}" @@ -10,6 +12,7 @@ target_field.append("/" + project_name) target_field.data("project_name", project_name) target_field.find('input').prop("value", origin_namespace) + import_button.enable().removeClass('is-loading') - elsif @access_denied :plain job = $("tr#repo_#{@repo_id}") From 3d69d01e1fe78427f00e3e89e94975819c764806 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Fri, 1 Jul 2016 16:43:02 -0300 Subject: [PATCH 96/98] Cache results from jQuery selectors to retrieve namespace name --- app/assets/javascripts/importer_status.js.coffee | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/importer_status.js.coffee b/app/assets/javascripts/importer_status.js.coffee index ec42c992e9..eb046eb2ef 100644 --- a/app/assets/javascripts/importer_status.js.coffee +++ b/app/assets/javascripts/importer_status.js.coffee @@ -7,13 +7,16 @@ class @ImporterStatus $('.js-add-to-import') .off 'click' .on 'click', (e) => - new_namespace = null $btn = $(e.currentTarget) $tr = $btn.closest('tr') + $target_field = $tr.find('.import-target') + $namespace_input = $target_field.find('input') id = $tr.attr('id').replace('repo_', '') - if $tr.find('.import-target input').length > 0 - new_namespace = $tr.find('.import-target input').prop('value') - $tr.find('.import-target').empty().append("#{new_namespace}/#{$tr.find('.import-target').data('project_name')}") + new_namespace = null + + if $namespace_input.length > 0 + new_namespace = $namespace_input.prop('value') + $target_field.empty().append("#{new_namespace}/#{$target_field.data('project_name')}") $btn .disable() From 9dab692a2be2624ee2dddd6ae54accb2c28e4f93 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Fri, 1 Jul 2016 16:05:39 -0300 Subject: [PATCH 97/98] Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index ac14af9d2d..2f93fcdbaa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -37,6 +37,7 @@ v 8.9.5 (unreleased) - Fix assigning shared runners as admins. !4961 - Show "locked" label for locked runners on runners admin. !4961 - Fixes issues importing events in Import/Export. Import/Export version bumped to 0.1.1 + - Fix import button disabled when import process fail due to the namespace already been taken. v 8.9.4 - Fix privilege escalation issue with OAuth external users. From 9e211091a85c20adea63b89111240350d6d8ffcb Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 1 Jul 2016 21:56:17 +0200 Subject: [PATCH 98/98] Enable Style/EmptyLines cop, remove redundant ones --- .rubocop.yml | 2 +- app/controllers/admin/hooks_controller.rb | 1 - app/controllers/confirmations_controller.rb | 1 - app/controllers/import/base_controller.rb | 1 - app/controllers/import/fogbugz_controller.rb | 2 -- app/controllers/import/gitorious_controller.rb | 1 - app/controllers/import/google_code_controller.rb | 2 -- app/controllers/invites_controller.rb | 1 - app/controllers/projects/issues_controller.rb | 1 - app/controllers/projects/network_controller.rb | 1 - app/controllers/projects/wikis_controller.rb | 1 - app/helpers/emails_helper.rb | 1 - app/helpers/issuables_helper.rb | 1 - app/helpers/search_helper.rb | 1 - app/models/concerns/issuable.rb | 1 - app/models/members/project_member.rb | 1 - app/models/project_services/bugzilla_service.rb | 2 -- app/models/project_services/custom_issue_tracker_service.rb | 2 -- app/models/project_services/drone_ci_service.rb | 1 - app/models/project_services/issue_tracker_service.rb | 1 - app/models/project_services/jira_service.rb | 1 - app/models/project_services/redmine_service.rb | 1 - app/models/repository.rb | 1 - app/models/user.rb | 1 - app/services/create_release_service.rb | 1 - app/services/issues/base_service.rb | 1 - app/services/merge_requests/base_service.rb | 1 - .../merge_requests/merge_when_build_succeeds_service.rb | 1 - app/services/milestones/destroy_service.rb | 1 - app/services/projects/download_service.rb | 1 - app/services/projects/import_export/export_service.rb | 1 - app/services/system_note_service.rb | 1 - app/services/update_release_service.rb | 1 - app/services/wiki_pages/base_service.rb | 1 - config/initializers/1_settings.rb | 4 ---- config/routes.rb | 2 -- features/steps/dashboard/new_project.rb | 1 - features/steps/explore/projects.rb | 3 --- features/steps/project/archived.rb | 1 - features/steps/project/issues/issues.rb | 5 ----- features/steps/project/project_find_file.rb | 1 - features/steps/shared/issuable.rb | 1 - features/steps/snippet_search.rb | 1 - lib/api/award_emoji.rb | 1 - lib/api/branches.rb | 2 -- lib/api/builds.rb | 1 - lib/api/milestones.rb | 1 - lib/api/project_hooks.rb | 1 - lib/api/project_members.rb | 1 - lib/api/projects.rb | 2 -- lib/api/services.rb | 1 - lib/banzai/filter/image_link_filter.rb | 1 - lib/banzai/filter/wiki_link_filter.rb | 1 - lib/banzai/pipeline/full_pipeline.rb | 1 - lib/ci/charts.rb | 1 - lib/disable_email_interceptor.rb | 1 - lib/gitlab/asciidoc.rb | 1 - lib/gitlab/backend/grack_auth.rb | 1 - lib/gitlab/diff/parser.rb | 1 - lib/gitlab/import_export/importer.rb | 1 - lib/gitlab/import_export/members_mapper.rb | 1 - lib/gitlab/import_export/project_creator.rb | 1 - lib/gitlab/import_export/project_tree_restorer.rb | 1 - lib/gitlab/import_export/reader.rb | 2 -- lib/gitlab/import_export/relation_factory.rb | 1 - lib/gitlab/import_export/shared.rb | 1 - lib/gitlab/import_export/uploads_saver.rb | 1 - lib/gitlab/import_export/version_checker.rb | 1 - lib/gitlab/import_export/version_saver.rb | 1 - lib/gitlab/import_sources.rb | 2 -- lib/gitlab/lfs/response.rb | 1 - lib/gitlab/other_markup.rb | 1 - lib/gitlab/regex.rb | 6 ------ lib/gitlab/saml/auth_hash.rb | 2 -- lib/gitlab/saml/config.rb | 2 -- lib/gitlab/saml/user.rb | 1 - lib/uploaded_file.rb | 1 - spec/controllers/application_controller_spec.rb | 1 - spec/controllers/profiles/accounts_controller_spec.rb | 1 - spec/controllers/projects/branches_controller_spec.rb | 2 -- spec/controllers/projects/forks_controller_spec.rb | 2 -- spec/controllers/projects/labels_controller_spec.rb | 1 - spec/controllers/projects/merge_requests_controller_spec.rb | 2 -- spec/controllers/projects/repositories_controller_spec.rb | 1 - spec/controllers/projects/tree_controller_spec.rb | 1 - spec/controllers/projects_controller_spec.rb | 3 --- spec/controllers/users_controller_spec.rb | 1 - spec/features/admin/admin_hooks_spec.rb | 2 -- spec/features/dashboard/user_filters_projects_spec.rb | 1 - spec/features/gitlab_flavored_markdown_spec.rb | 2 -- .../groups/members/owner_manages_access_requests_spec.rb | 1 - spec/features/issues/filter_issues_spec.rb | 6 ------ spec/features/issues_spec.rb | 4 ---- spec/features/projects/commit/builds_spec.rb | 1 - spec/features/projects/commits/cherry_pick_spec.rb | 1 - .../projects/labels/issues_sorted_by_priority_spec.rb | 3 --- spec/features/search_spec.rb | 5 ----- spec/features/security/group/internal_access_spec.rb | 1 - spec/features/security/group/private_access_spec.rb | 1 - spec/features/security/group/public_access_spec.rb | 1 - spec/features/signup_spec.rb | 2 -- spec/features/tags/master_deletes_tag_spec.rb | 1 - spec/features/users_spec.rb | 1 - spec/finders/group_projects_finder_spec.rb | 2 -- spec/finders/snippets_finder_spec.rb | 1 - spec/helpers/visibility_level_helper_spec.rb | 2 -- spec/initializers/settings_spec.rb | 2 -- spec/lib/banzai/pipeline/wiki_pipeline_spec.rb | 1 - spec/lib/ci/charts_spec.rb | 1 - spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 1 - spec/lib/gitlab/asciidoc_spec.rb | 3 --- spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb | 1 - spec/lib/gitlab/diff/inline_diff_marker_spec.rb | 1 - spec/lib/gitlab/fogbugz_import/client_spec.rb | 1 - spec/lib/gitlab/git_access_spec.rb | 1 - spec/lib/gitlab/github_import/label_formatter_spec.rb | 1 - spec/lib/gitlab/google_code_import/importer_spec.rb | 1 - spec/lib/gitlab/import_export/members_mapper_spec.rb | 1 - spec/lib/gitlab/import_export/project_tree_restorer_spec.rb | 1 - spec/lib/gitlab/import_export/project_tree_saver_spec.rb | 2 -- spec/lib/gitlab/import_export/reader_spec.rb | 1 - spec/lib/gitlab/import_export/repo_bundler_spec.rb | 1 - spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb | 1 - spec/lib/gitlab/ldap/auth_hash_spec.rb | 1 - spec/lib/gitlab/o_auth/user_spec.rb | 3 --- spec/lib/gitlab/push_data_builder_spec.rb | 1 - spec/lib/gitlab/saml/user_spec.rb | 1 - spec/lib/gitlab/url_sanitizer_spec.rb | 1 - spec/mailers/notify_spec.rb | 5 ----- spec/models/build_spec.rb | 1 - spec/models/concerns/issuable_spec.rb | 1 - spec/models/concerns/strip_attribute_spec.rb | 1 - spec/models/email_spec.rb | 2 -- spec/models/forked_project_link_spec.rb | 3 --- spec/models/identity_spec.rb | 1 - spec/models/members/project_member_spec.rb | 1 - spec/models/namespace_spec.rb | 1 - spec/models/project_services/jira_service_spec.rb | 2 -- .../slack_service/wiki_page_message_spec.rb | 1 - spec/models/repository_spec.rb | 1 - spec/models/service_spec.rb | 2 -- spec/requests/api/api_helpers_spec.rb | 1 - spec/requests/api/award_emoji_spec.rb | 1 - spec/requests/api/commit_statuses_spec.rb | 1 - spec/requests/api/doorkeeper_access_spec.rb | 1 - spec/requests/api/labels_spec.rb | 1 - spec/requests/api/notes_spec.rb | 3 --- spec/requests/api/projects_spec.rb | 1 - spec/requests/api/services_spec.rb | 1 - spec/requests/api/settings_spec.rb | 1 - spec/requests/api/users_spec.rb | 1 - spec/routing/admin_routing_spec.rb | 1 - spec/routing/project_routing_spec.rb | 1 - spec/routing/routing_spec.rb | 1 - spec/services/git_hooks_service_spec.rb | 2 -- spec/services/git_push_service_spec.rb | 6 ------ spec/services/merge_requests/refresh_service_spec.rb | 1 - spec/services/notification_service_spec.rb | 5 ----- spec/services/projects/transfer_service_spec.rb | 1 - spec/support/jira_service_helper.rb | 1 - spec/tasks/gitlab/backup_rake_spec.rb | 1 - spec/workers/project_cache_worker_spec.rb | 1 - 162 files changed, 1 insertion(+), 238 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index cdcfd8150e..cd13f58151 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -193,7 +193,7 @@ Style/EmptyLineBetweenDefs: # Don't use several empty lines in a row. Style/EmptyLines: - Enabled: false + Enabled: true # Keep blank lines around access modifiers. Style/EmptyLinesAroundAccessModifier: diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb index 4e85b6b4cf..cbfc458141 100644 --- a/app/controllers/admin/hooks_controller.rb +++ b/app/controllers/admin/hooks_controller.rb @@ -22,7 +22,6 @@ class Admin::HooksController < Admin::ApplicationController redirect_to admin_hooks_path end - def test @hook = SystemHook.find(params[:hook_id]) data = { diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb index 7b66ad3f92..3da44b9b88 100644 --- a/app/controllers/confirmations_controller.rb +++ b/app/controllers/confirmations_controller.rb @@ -1,5 +1,4 @@ class ConfirmationsController < Devise::ConfirmationsController - def almost_there flash[:notice] = nil render layout: "devise_empty" diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb index 93a7ace353..7e8597a5eb 100644 --- a/app/controllers/import/base_controller.rb +++ b/app/controllers/import/base_controller.rb @@ -1,5 +1,4 @@ class Import::BaseController < ApplicationController - private def get_or_create_namespace diff --git a/app/controllers/import/fogbugz_controller.rb b/app/controllers/import/fogbugz_controller.rb index 1830039085..99b10b2f9b 100644 --- a/app/controllers/import/fogbugz_controller.rb +++ b/app/controllers/import/fogbugz_controller.rb @@ -5,7 +5,6 @@ class Import::FogbugzController < Import::BaseController rescue_from Fogbugz::AuthenticationException, with: :fogbugz_unauthorized def new - end def callback @@ -22,7 +21,6 @@ class Import::FogbugzController < Import::BaseController end def new_user_map - end def create_user_map diff --git a/app/controllers/import/gitorious_controller.rb b/app/controllers/import/gitorious_controller.rb index eecbe380c9..a4c4ad2302 100644 --- a/app/controllers/import/gitorious_controller.rb +++ b/app/controllers/import/gitorious_controller.rb @@ -44,5 +44,4 @@ class Import::GitoriousController < Import::BaseController def verify_gitorious_import_enabled render_404 unless gitorious_import_enabled? end - end diff --git a/app/controllers/import/google_code_controller.rb b/app/controllers/import/google_code_controller.rb index e0de31f225..8d0de158f9 100644 --- a/app/controllers/import/google_code_controller.rb +++ b/app/controllers/import/google_code_controller.rb @@ -3,7 +3,6 @@ class Import::GoogleCodeController < Import::BaseController before_action :user_map, only: [:new_user_map, :create_user_map] def new - end def callback @@ -34,7 +33,6 @@ class Import::GoogleCodeController < Import::BaseController end def new_user_map - end def create_user_map diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index 94bb108c5f..58964a0e65 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -5,7 +5,6 @@ class InvitesController < ApplicationController respond_to :html def show - end def accept diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 8b8df68073..b6e80762e3 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -76,7 +76,6 @@ class Projects::IssuesController < Projects::ApplicationController render json: @issue.to_json(include: [:milestone, :labels]) end end - end def create diff --git a/app/controllers/projects/network_controller.rb b/app/controllers/projects/network_controller.rb index b181c47bae..34318391dd 100644 --- a/app/controllers/projects/network_controller.rb +++ b/app/controllers/projects/network_controller.rb @@ -7,7 +7,6 @@ class Projects::NetworkController < Projects::ApplicationController before_action :authorize_download_code! def show - @url = namespace_project_network_path(@project.namespace, @project, @ref, @options.merge(format: :json)) @commit_url = namespace_project_commit_path(@project.namespace, @project, 'ae45ca32').gsub("ae45ca32", "%s") diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb index 7ec1e73b3b..607fe9c7fe 100644 --- a/app/controllers/projects/wikis_controller.rb +++ b/app/controllers/projects/wikis_controller.rb @@ -124,5 +124,4 @@ class Projects::WikisController < Projects::ApplicationController def wiki_params params[:wiki].slice(:title, :content, :format, :message) end - end diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb index 8466d0aa0b..2843ad96ef 100644 --- a/app/helpers/emails_helper.rb +++ b/app/helpers/emails_helper.rb @@ -1,5 +1,4 @@ module EmailsHelper - # Google Actions # https://developers.google.com/gmail/markup/reference/go-to-action def email_action(url) diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 8231ce49fa..294b7e92b8 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -1,5 +1,4 @@ module IssuablesHelper - def sidebar_gutter_toggle_icon sidebar_gutter_collapsed? ? icon('angle-double-left') : icon('angle-double-right') end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index d2f94d4ae6..f9fc525df6 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -1,5 +1,4 @@ module SearchHelper - def search_autocomplete_opts(term) return unless current_user diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index d6f55885dd..acb6f5a299 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -58,7 +58,6 @@ module Issuable scope :references_project, -> { references(:project) } scope :non_archived, -> { join_project.where(projects: { archived: false }) } - delegate :name, :email, to: :author, diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index e9d3a82ba1..f39afc61ce 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -15,7 +15,6 @@ class ProjectMember < Member before_destroy :delete_member_todos class << self - # Add users to project teams with passed access option # # access can be an integer representing a access code diff --git a/app/models/project_services/bugzilla_service.rb b/app/models/project_services/bugzilla_service.rb index 260f603095..81af55aa29 100644 --- a/app/models/project_services/bugzilla_service.rb +++ b/app/models/project_services/bugzilla_service.rb @@ -1,5 +1,4 @@ class BugzillaService < IssueTrackerService - prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url def title @@ -21,5 +20,4 @@ class BugzillaService < IssueTrackerService def to_param 'bugzilla' end - end diff --git a/app/models/project_services/custom_issue_tracker_service.rb b/app/models/project_services/custom_issue_tracker_service.rb index 8f2db46a7b..63a5ed1448 100644 --- a/app/models/project_services/custom_issue_tracker_service.rb +++ b/app/models/project_services/custom_issue_tracker_service.rb @@ -1,5 +1,4 @@ class CustomIssueTrackerService < IssueTrackerService - prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url def title @@ -31,5 +30,4 @@ class CustomIssueTrackerService < IssueTrackerService { type: 'text', name: 'new_issue_url', placeholder: 'New Issue url' } ] end - end diff --git a/app/models/project_services/drone_ci_service.rb b/app/models/project_services/drone_ci_service.rb index 966dbc41d7..5e4dd101c5 100644 --- a/app/models/project_services/drone_ci_service.rb +++ b/app/models/project_services/drone_ci_service.rb @@ -1,5 +1,4 @@ class DroneCiService < CiService - prop_accessor :drone_url, :token, :enable_ssl_verification validates :drone_url, presence: true, url: true, if: :activated? diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb index 87ecb3b8b8..d1df6d0292 100644 --- a/app/models/project_services/issue_tracker_service.rb +++ b/app/models/project_services/issue_tracker_service.rb @@ -1,5 +1,4 @@ class IssueTrackerService < Service - validates :project_url, :issues_url, :new_issue_url, presence: true, url: true, if: :activated? default_value_for :category, 'issue_tracker' diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 8b3296c712..27bf08bf7d 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -190,7 +190,6 @@ class JiraService < IssueTrackerService end end - def auth require 'base64' Base64.urlsafe_encode64("#{self.username}:#{self.password}") diff --git a/app/models/project_services/redmine_service.rb b/app/models/project_services/redmine_service.rb index 11cce3e056..f634e0772c 100644 --- a/app/models/project_services/redmine_service.rb +++ b/app/models/project_services/redmine_service.rb @@ -1,5 +1,4 @@ class RedmineService < IssueTrackerService - prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url def title diff --git a/app/models/repository.rb b/app/models/repository.rb index eb232ea681..11ecb281a5 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -875,7 +875,6 @@ class Repository merge_base(ancestor_id, descendant_id) == ancestor_id end - def search_files(query, ref) offset = 2 args = %W(#{Gitlab.config.git.bin_path} grep -i -I -n --before-context #{offset} --after-context #{offset} -E -e #{Regexp.escape(query)} #{ref || root_ref}) diff --git a/app/models/user.rb b/app/models/user.rb index eac716b120..5036a3e300 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -852,7 +852,6 @@ class User < ActiveRecord::Base projects.select(:id), groups.joins(:shared_projects).select(:project_id)] - if min_access_level scope = { access_level: Gitlab::Access.values.select { |access| access >= min_access_level } } relations = [relations.shift] + relations.map { |relation| relation.where(members: scope) } diff --git a/app/services/create_release_service.rb b/app/services/create_release_service.rb index e06a6f2f47..f029db72d4 100644 --- a/app/services/create_release_service.rb +++ b/app/services/create_release_service.rb @@ -2,7 +2,6 @@ require_relative 'base_service' class CreateReleaseService < BaseService def execute(tag_name, release_description) - repository = project.repository existing_tag = repository.find_tag(tag_name) diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb index 772f5c5fff..089b0f527e 100644 --- a/app/services/issues/base_service.rb +++ b/app/services/issues/base_service.rb @@ -1,6 +1,5 @@ module Issues class BaseService < ::IssuableBaseService - def hook_data(issue, action) issue_data = issue.to_hook_data(current_user) issue_url = Gitlab::UrlBuilder.build(issue) diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb index bc93ba2552..bc3606a14c 100644 --- a/app/services/merge_requests/base_service.rb +++ b/app/services/merge_requests/base_service.rb @@ -1,6 +1,5 @@ module MergeRequests class BaseService < ::IssuableBaseService - def create_note(merge_request) SystemNoteService.change_status(merge_request, merge_request.target_project, current_user, merge_request.state, nil) end diff --git a/app/services/merge_requests/merge_when_build_succeeds_service.rb b/app/services/merge_requests/merge_when_build_succeeds_service.rb index 12edfb2d67..870f570518 100644 --- a/app/services/merge_requests/merge_when_build_succeeds_service.rb +++ b/app/services/merge_requests/merge_when_build_succeeds_service.rb @@ -40,6 +40,5 @@ module MergeRequests error("Can't cancel the automatic merge", 406) end end - end end diff --git a/app/services/milestones/destroy_service.rb b/app/services/milestones/destroy_service.rb index 2414966505..e457212508 100644 --- a/app/services/milestones/destroy_service.rb +++ b/app/services/milestones/destroy_service.rb @@ -1,7 +1,6 @@ module Milestones class DestroyService < Milestones::BaseService def execute(milestone) - Milestone.transaction do update_params = { milestone: nil } diff --git a/app/services/projects/download_service.rb b/app/services/projects/download_service.rb index 6386f57fb0..f06a3d44c1 100644 --- a/app/services/projects/download_service.rb +++ b/app/services/projects/download_service.rb @@ -1,6 +1,5 @@ module Projects class DownloadService < BaseService - WHITELIST = [ /^[^.]+\.fogbugz.com$/ ] diff --git a/app/services/projects/import_export/export_service.rb b/app/services/projects/import_export/export_service.rb index 80c7193efc..3f507d5c40 100644 --- a/app/services/projects/import_export/export_service.rb +++ b/app/services/projects/import_export/export_service.rb @@ -1,7 +1,6 @@ module Projects module ImportExport class ExportService < BaseService - def execute(_options = {}) @shared = Gitlab::ImportExport::Shared.new(relative_path: File.join(project.path_with_namespace, 'work')) save_all diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 4e8fa0818b..b868d2e7e8 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -293,7 +293,6 @@ class SystemNoteService end end - def self.cross_reference?(note_text) note_text.start_with?(cross_reference_note_prefix) end diff --git a/app/services/update_release_service.rb b/app/services/update_release_service.rb index 25eb13ef09..0c0f68d169 100644 --- a/app/services/update_release_service.rb +++ b/app/services/update_release_service.rb @@ -2,7 +2,6 @@ require_relative 'base_service' class UpdateReleaseService < BaseService def execute(tag_name, release_description) - repository = project.repository existing_tag = repository.find_tag(tag_name) diff --git a/app/services/wiki_pages/base_service.rb b/app/services/wiki_pages/base_service.rb index 4c0a2c6b4d..14317ea65c 100644 --- a/app/services/wiki_pages/base_service.rb +++ b/app/services/wiki_pages/base_service.rb @@ -1,6 +1,5 @@ module WikiPages class BaseService < ::BaseService - def hook_data(page, action) hook_data = { object_kind: page.class.name.underscore, diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index a93996cec7..51d93e8cde 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -96,7 +96,6 @@ class Settings < Settingslogic end end - # Default settings Settings['ldap'] ||= Settingslogic.new({}) Settings.ldap['enabled'] = false if Settings.ldap['enabled'].nil? @@ -124,7 +123,6 @@ if Settings.ldap['enabled'] || Rails.env.test? end end - Settings['omniauth'] ||= Settingslogic.new({}) Settings.omniauth['enabled'] = false if Settings.omniauth['enabled'].nil? Settings.omniauth['auto_sign_in_with_provider'] = false if Settings.omniauth['auto_sign_in_with_provider'].nil? @@ -218,7 +216,6 @@ Settings.gitlab['restricted_signup_domains'] ||= [] Settings.gitlab['import_sources'] ||= %w[github bitbucket gitlab gitorious google_code fogbugz git gitlab_project] Settings.gitlab['trusted_proxies'] ||= [] - # # CI # @@ -348,7 +345,6 @@ Settings.git['timeout'] ||= 10 Settings['satellites'] ||= Settingslogic.new({}) Settings.satellites['path'] = File.expand_path(Settings.satellites['path'] || "tmp/repo_satellites/", Rails.root) - # # Extra customization # diff --git a/config/routes.rb b/config/routes.rb index c04780fec8..1572656b8c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -133,7 +133,6 @@ Rails.application.routes.draw do # resources :notification_settings, only: [:create, :update] - # # Import # @@ -466,7 +465,6 @@ Rails.application.routes.draw do resources :namespaces, path: '/', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only: [] do resources(:projects, constraints: { id: /[a-zA-Z.0-9_\-]+(? service for project # diff --git a/lib/banzai/filter/image_link_filter.rb b/lib/banzai/filter/image_link_filter.rb index 8aa6f8f124..f0fb6084a3 100644 --- a/lib/banzai/filter/image_link_filter.rb +++ b/lib/banzai/filter/image_link_filter.rb @@ -8,7 +8,6 @@ module Banzai # of the anchor, and then replace the img with the link-wrapped version. def call doc.xpath('descendant-or-self::img[not(ancestor::a)]').each do |img| - div = doc.document.create_element( 'div', class: 'image-container' diff --git a/lib/banzai/filter/wiki_link_filter.rb b/lib/banzai/filter/wiki_link_filter.rb index 1bb6d6bba8..269d5bf74f 100644 --- a/lib/banzai/filter/wiki_link_filter.rb +++ b/lib/banzai/filter/wiki_link_filter.rb @@ -8,7 +8,6 @@ module Banzai # Context options: # :project_wiki class WikiLinkFilter < HTML::Pipeline::Filter - def call return doc unless project_wiki? diff --git a/lib/banzai/pipeline/full_pipeline.rb b/lib/banzai/pipeline/full_pipeline.rb index d47ddfda4b..3c974f7317 100644 --- a/lib/banzai/pipeline/full_pipeline.rb +++ b/lib/banzai/pipeline/full_pipeline.rb @@ -1,7 +1,6 @@ module Banzai module Pipeline class FullPipeline < CombinedPipeline.new(PlainMarkdownPipeline, GfmPipeline) - end end end diff --git a/lib/ci/charts.rb b/lib/ci/charts.rb index 5270108ef0..1d7126a432 100644 --- a/lib/ci/charts.rb +++ b/lib/ci/charts.rb @@ -13,7 +13,6 @@ module Ci collect end - def push(from, to, format) @labels << from.strftime(format) @total << project.builds. diff --git a/lib/disable_email_interceptor.rb b/lib/disable_email_interceptor.rb index 1b80be112a..cee664b895 100644 --- a/lib/disable_email_interceptor.rb +++ b/lib/disable_email_interceptor.rb @@ -1,6 +1,5 @@ # Read about interceptors in http://guides.rubyonrails.org/action_mailer_basics.html#intercepting-emails class DisableEmailInterceptor - def self.delivering_email(message) message.perform_deliveries = false Rails.logger.info "Emails disabled! Interceptor prevented sending mail #{message.subject}" diff --git a/lib/gitlab/asciidoc.rb b/lib/gitlab/asciidoc.rb index 0b9c2e730f..1a22ad9acf 100644 --- a/lib/gitlab/asciidoc.rb +++ b/lib/gitlab/asciidoc.rb @@ -4,7 +4,6 @@ module Gitlab # Parser/renderer for the AsciiDoc format that uses Asciidoctor and filters # the resulting HTML through HTML pipeline filters. module Asciidoc - DEFAULT_ADOC_ATTRS = [ 'showtitle', 'idprefix=user-content-', 'idseparator=-', 'env=gitlab', 'env-gitlab', 'source-highlighter=html-pipeline' diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index ad412f56cc..478f145bfe 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -8,7 +8,6 @@ module Grack end class Auth < Rack::Auth::Basic - attr_accessor :user, :project, :env def call(env) diff --git a/lib/gitlab/diff/parser.rb b/lib/gitlab/diff/parser.rb index 522dd2b942..59a2367b65 100644 --- a/lib/gitlab/diff/parser.rb +++ b/lib/gitlab/diff/parser.rb @@ -40,7 +40,6 @@ module Gitlab line_obj_index += 1 end - case line[0] when "+" line_new += 1 diff --git a/lib/gitlab/import_export/importer.rb b/lib/gitlab/import_export/importer.rb index 595b20a09b..8f66f48cbf 100644 --- a/lib/gitlab/import_export/importer.rb +++ b/lib/gitlab/import_export/importer.rb @@ -1,7 +1,6 @@ module Gitlab module ImportExport class Importer - def initialize(project) @archive_file = project.import_source @current_user = project.creator diff --git a/lib/gitlab/import_export/members_mapper.rb b/lib/gitlab/import_export/members_mapper.rb index c569a35a48..b459054c19 100644 --- a/lib/gitlab/import_export/members_mapper.rb +++ b/lib/gitlab/import_export/members_mapper.rb @@ -1,7 +1,6 @@ module Gitlab module ImportExport class MembersMapper - attr_reader :missing_author_ids def initialize(exported_members:, user:, project:) diff --git a/lib/gitlab/import_export/project_creator.rb b/lib/gitlab/import_export/project_creator.rb index 89388d1984..77bb3ca658 100644 --- a/lib/gitlab/import_export/project_creator.rb +++ b/lib/gitlab/import_export/project_creator.rb @@ -1,7 +1,6 @@ module Gitlab module ImportExport class ProjectCreator - def initialize(namespace_id, current_user, file, project_path) @namespace_id = namespace_id @current_user = current_user diff --git a/lib/gitlab/import_export/project_tree_restorer.rb b/lib/gitlab/import_export/project_tree_restorer.rb index dd71b92c52..0ac6ff01e3 100644 --- a/lib/gitlab/import_export/project_tree_restorer.rb +++ b/lib/gitlab/import_export/project_tree_restorer.rb @@ -1,7 +1,6 @@ module Gitlab module ImportExport class ProjectTreeRestorer - def initialize(user:, shared:, project:) @path = File.join(shared.export_path, 'project.json') @user = user diff --git a/lib/gitlab/import_export/reader.rb b/lib/gitlab/import_export/reader.rb index 19defd8f03..15f5dd3103 100644 --- a/lib/gitlab/import_export/reader.rb +++ b/lib/gitlab/import_export/reader.rb @@ -1,7 +1,6 @@ module Gitlab module ImportExport class Reader - attr_reader :tree def initialize(shared:) @@ -55,7 +54,6 @@ module Gitlab @json_config_hash end - # If the model is a hash, process the sub_models, which could also be hashes # If there is a list, add to an existing array, otherwise use hash syntax # +current_key+ main model that will be a key in the hash diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb index 3fd89e08f0..9824df3f27 100644 --- a/lib/gitlab/import_export/relation_factory.rb +++ b/lib/gitlab/import_export/relation_factory.rb @@ -1,7 +1,6 @@ module Gitlab module ImportExport class RelationFactory - OVERRIDES = { snippets: :project_snippets, pipelines: 'Ci::Pipeline', statuses: 'commit_status', diff --git a/lib/gitlab/import_export/shared.rb b/lib/gitlab/import_export/shared.rb index 6aff05b886..5d6de8bc47 100644 --- a/lib/gitlab/import_export/shared.rb +++ b/lib/gitlab/import_export/shared.rb @@ -1,7 +1,6 @@ module Gitlab module ImportExport class Shared - attr_reader :errors, :opts def initialize(opts) diff --git a/lib/gitlab/import_export/uploads_saver.rb b/lib/gitlab/import_export/uploads_saver.rb index 7292e9d971..d6f4fa5751 100644 --- a/lib/gitlab/import_export/uploads_saver.rb +++ b/lib/gitlab/import_export/uploads_saver.rb @@ -1,7 +1,6 @@ module Gitlab module ImportExport class UploadsSaver - def initialize(project:, shared:) @project = project @shared = shared diff --git a/lib/gitlab/import_export/version_checker.rb b/lib/gitlab/import_export/version_checker.rb index cf5c62c5e3..abfc694b87 100644 --- a/lib/gitlab/import_export/version_checker.rb +++ b/lib/gitlab/import_export/version_checker.rb @@ -1,7 +1,6 @@ module Gitlab module ImportExport class VersionChecker - def self.check!(*args) new(*args).check! end diff --git a/lib/gitlab/import_export/version_saver.rb b/lib/gitlab/import_export/version_saver.rb index f7f73dc934..9b642d740b 100644 --- a/lib/gitlab/import_export/version_saver.rb +++ b/lib/gitlab/import_export/version_saver.rb @@ -1,7 +1,6 @@ module Gitlab module ImportExport class VersionSaver - def initialize(shared:) @shared = shared end diff --git a/lib/gitlab/import_sources.rb b/lib/gitlab/import_sources.rb index 948d43582c..59a05411fe 100644 --- a/lib/gitlab/import_sources.rb +++ b/lib/gitlab/import_sources.rb @@ -24,8 +24,6 @@ module Gitlab 'GitLab export' => 'gitlab_project' } end - end - end end diff --git a/lib/gitlab/lfs/response.rb b/lib/gitlab/lfs/response.rb index e3ed2f6791..811363405a 100644 --- a/lib/gitlab/lfs/response.rb +++ b/lib/gitlab/lfs/response.rb @@ -1,7 +1,6 @@ module Gitlab module Lfs class Response - def initialize(project, user, ci, request) @origin_project = project @project = storage_project(project) diff --git a/lib/gitlab/other_markup.rb b/lib/gitlab/other_markup.rb index 746ec28333..4e2f8ed558 100644 --- a/lib/gitlab/other_markup.rb +++ b/lib/gitlab/other_markup.rb @@ -1,7 +1,6 @@ module Gitlab # Parser/renderer for markups without other special support code. module OtherMarkup - # Public: Converts the provided markup into HTML. # # input - the source text in a markup format diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb index c84c68f96f..ffad5e17c7 100644 --- a/lib/gitlab/regex.rb +++ b/lib/gitlab/regex.rb @@ -13,7 +13,6 @@ module Gitlab "Cannot start with '-' or end in '.'." \ end - def namespace_name_regex @namespace_name_regex ||= /\A[\p{Alnum}\p{Pd}_\. ]*\z/.freeze end @@ -22,7 +21,6 @@ module Gitlab "can contain only letters, digits, '_', '.', dash and space." end - def project_name_regex @project_name_regex ||= /\A[\p{Alnum}_][\p{Alnum}\p{Pd}_\. ]*\z/.freeze end @@ -32,7 +30,6 @@ module Gitlab "It must start with letter, digit or '_'." end - def project_path_regex @project_path_regex ||= /\A[a-zA-Z0-9_.][a-zA-Z0-9_\-\.]*(? User filters projects", feature: true do - describe 'filtering personal projects' do before do user = create(:user) diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb index 7852c39fee..a89ac09f23 100644 --- a/spec/features/gitlab_flavored_markdown_spec.rb +++ b/spec/features/gitlab_flavored_markdown_spec.rb @@ -81,7 +81,6 @@ describe "GitLab Flavored Markdown", feature: true do end end - describe "for merge requests" do before do @merge_request = create(:merge_request, source_project: project, target_project: project, title: "fix #{issue.to_reference}") @@ -100,7 +99,6 @@ describe "GitLab Flavored Markdown", feature: true do end end - describe "for milestones" do before do @milestone = create(:milestone, diff --git a/spec/features/groups/members/owner_manages_access_requests_spec.rb b/spec/features/groups/members/owner_manages_access_requests_spec.rb index 321c9bad7d..51690e3949 100644 --- a/spec/features/groups/members/owner_manages_access_requests_spec.rb +++ b/spec/features/groups/members/owner_manages_access_requests_spec.rb @@ -39,7 +39,6 @@ feature 'Groups > Members > Owner manages access requests', feature: true do expect(ActionMailer::Base.deliveries.last.subject).to match "Access to the #{group.name} group was denied" end - def expect_visible_access_request(group, user) expect(group.members.request.exists?(user_id: user)).to be_truthy expect(page).to have_content "#{group.name} access requests 1" diff --git a/spec/features/issues/filter_issues_spec.rb b/spec/features/issues/filter_issues_spec.rb index 4bcb105b17..006a06b823 100644 --- a/spec/features/issues/filter_issues_spec.rb +++ b/spec/features/issues/filter_issues_spec.rb @@ -14,7 +14,6 @@ describe 'Filter issues', feature: true do end describe 'Filter issues for assignee from issues#index' do - before do visit namespace_project_issues_path(project.namespace, project) @@ -36,7 +35,6 @@ describe 'Filter issues', feature: true do expect(find('.js-assignee-search .dropdown-toggle-text')).to have_content(user.name) end - it 'should not change when all link is clicked' do find('.issues-state-filters a', text: "All").click @@ -46,7 +44,6 @@ describe 'Filter issues', feature: true do end describe 'Filter issues for milestone from issues#index' do - before do visit namespace_project_issues_path(project.namespace, project) @@ -68,7 +65,6 @@ describe 'Filter issues', feature: true do expect(find('.js-milestone-select .dropdown-toggle-text')).to have_content(milestone.title) end - it 'should not change when all link is clicked' do find('.issues-state-filters a', text: "All").click @@ -113,7 +109,6 @@ describe 'Filter issues', feature: true do end describe 'Filter issues for assignee and label from issues#index' do - before do visit namespace_project_issues_path(project.namespace, project) @@ -144,7 +139,6 @@ describe 'Filter issues', feature: true do expect(find('.js-label-select .dropdown-toggle-text')).to have_content(label.title) end - it 'should not change when all link is clicked' do find('.issues-state-filters a', text: "All").click diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index 17df66e73b..d51c9abea1 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -361,7 +361,6 @@ describe 'Issues', feature: true do let(:issue) { create(:issue, project: project, author: @user, assignee: @user) } context 'by authorized user' do - it 'allows user to select unassigned', js: true do visit namespace_project_issue_path(project.namespace, project, issue) @@ -420,7 +419,6 @@ describe 'Issues', feature: true do end context 'by unauthorized user' do - let(:guest) { create(:user) } before do @@ -442,8 +440,6 @@ describe 'Issues', feature: true do let!(:milestone) { create(:milestone, project: project) } context 'by authorized user' do - - it 'allows user to select unassigned', js: true do visit namespace_project_issue_path(project.namespace, project, issue) diff --git a/spec/features/projects/commit/builds_spec.rb b/spec/features/projects/commit/builds_spec.rb index 15c381c0f5..fcdf7870f3 100644 --- a/spec/features/projects/commit/builds_spec.rb +++ b/spec/features/projects/commit/builds_spec.rb @@ -20,7 +20,6 @@ feature 'project commit builds' do visit builds_namespace_project_commit_path(project.namespace, project, project.commit.sha) - expect(page).to have_content('Builds') end end diff --git a/spec/features/projects/commits/cherry_pick_spec.rb b/spec/features/projects/commits/cherry_pick_spec.rb index f88c0616b5..1b4ff6b6f1 100644 --- a/spec/features/projects/commits/cherry_pick_spec.rb +++ b/spec/features/projects/commits/cherry_pick_spec.rb @@ -5,7 +5,6 @@ describe 'Cherry-pick Commits' do let(:master_pickable_commit) { project.commit('7d3b0f7cff5f37573aea97cebfd5692ea1689924') } let(:master_pickable_merge) { project.commit('e56497bb5f03a90a51293fc6d516788730953899') } - before do login_as :user project.team << [@user, :master] diff --git a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb index 461f173792..81b0c991d4 100644 --- a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb +++ b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' feature 'Issue prioritization', feature: true do - let(:user) { create(:user) } let(:project) { create(:project, name: 'test', namespace: user.namespace) } @@ -15,7 +14,6 @@ feature 'Issue prioritization', feature: true do # According to https://gitlab.com/gitlab-org/gitlab-ce/issues/14189#note_4360653 context 'when issues have one label' do scenario 'Are sorted properly' do - # Issues issue_1 = create(:issue, title: 'issue_1', project: project) issue_2 = create(:issue, title: 'issue_2', project: project) @@ -46,7 +44,6 @@ feature 'Issue prioritization', feature: true do context 'when issues have multiple labels' do scenario 'Are sorted properly' do - # Issues issue_1 = create(:issue, title: 'issue_1', project: project) issue_2 = create(:issue, title: 'issue_2', project: project) diff --git a/spec/features/search_spec.rb b/spec/features/search_spec.rb index b9e63a7152..85923f0a19 100644 --- a/spec/features/search_spec.rb +++ b/spec/features/search_spec.rb @@ -48,9 +48,7 @@ describe "Search", feature: true do end end - describe 'Right header search field', feature: true do - describe 'Search in project page' do before do visit namespace_project_path(project.namespace, project) @@ -73,7 +71,6 @@ describe "Search", feature: true do end context 'click the links in the category search dropdown', js: true do - before do page.find('#search').click end @@ -124,6 +121,4 @@ describe "Search", feature: true do end end end - - end diff --git a/spec/features/security/group/internal_access_spec.rb b/spec/features/security/group/internal_access_spec.rb index 71b783b727..35fcef7a71 100644 --- a/spec/features/security/group/internal_access_spec.rb +++ b/spec/features/security/group/internal_access_spec.rb @@ -76,7 +76,6 @@ describe 'Internal Group access', feature: true do it { is_expected.to be_denied_for :visitor } end - describe 'GET /groups/:path/group_members' do subject { group_group_members_path(group) } diff --git a/spec/features/security/group/private_access_spec.rb b/spec/features/security/group/private_access_spec.rb index cc9aee802f..75a9334262 100644 --- a/spec/features/security/group/private_access_spec.rb +++ b/spec/features/security/group/private_access_spec.rb @@ -76,7 +76,6 @@ describe 'Private Group access', feature: true do it { is_expected.to be_denied_for :visitor } end - describe 'GET /groups/:path/group_members' do subject { group_group_members_path(group) } diff --git a/spec/features/security/group/public_access_spec.rb b/spec/features/security/group/public_access_spec.rb index db986683db..6c5ee93970 100644 --- a/spec/features/security/group/public_access_spec.rb +++ b/spec/features/security/group/public_access_spec.rb @@ -76,7 +76,6 @@ describe 'Public Group access', feature: true do it { is_expected.to be_allowed_for :visitor } end - describe 'GET /groups/:path/group_members' do subject { group_group_members_path(group) } diff --git a/spec/features/signup_spec.rb b/spec/features/signup_spec.rb index 4229e82b44..a752c1d723 100644 --- a/spec/features/signup_spec.rb +++ b/spec/features/signup_spec.rb @@ -2,7 +2,6 @@ require 'spec_helper' feature 'Signup', feature: true do describe 'signup with no errors' do - context "when sending confirmation email" do before { allow_any_instance_of(ApplicationSetting).to receive(:send_user_confirmation_email).and_return(true) } @@ -40,7 +39,6 @@ feature 'Signup', feature: true do expect(page).to have_content("Welcome! You have signed up successfully.") end end - end describe 'signup with errors' do diff --git a/spec/features/tags/master_deletes_tag_spec.rb b/spec/features/tags/master_deletes_tag_spec.rb index f0990118e3..0f30f56253 100644 --- a/spec/features/tags/master_deletes_tag_spec.rb +++ b/spec/features/tags/master_deletes_tag_spec.rb @@ -22,7 +22,6 @@ feature 'Master deletes tag', feature: true do namespace_project_tags_path(project.namespace, project)) expect(page).not_to have_content 'v1.1.0' end - end context 'from a specific tag page' do diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb index cf11604039..b5a94fe038 100644 --- a/spec/features/users_spec.rb +++ b/spec/features/users_spec.rb @@ -47,5 +47,4 @@ feature 'Users', feature: true do def number_of_errors_on_page(page) page.find('#error_explanation').find('ul').all('li').count end - end diff --git a/spec/finders/group_projects_finder_spec.rb b/spec/finders/group_projects_finder_spec.rb index fdd3849816..fbe09b28b3 100644 --- a/spec/finders/group_projects_finder_spec.rb +++ b/spec/finders/group_projects_finder_spec.rb @@ -12,14 +12,12 @@ describe GroupProjectsFinder do let!(:shared_project_2) { create(:project, :private, path: '4') } let!(:shared_project_3) { create(:project, :internal, path: '5') } - before do shared_project_1.project_group_links.create(group_access: Gitlab::Access::MASTER, group: group) shared_project_2.project_group_links.create(group_access: Gitlab::Access::MASTER, group: group) shared_project_3.project_group_links.create(group_access: Gitlab::Access::MASTER, group: group) end - describe 'with a group member current user' do before { group.add_user(current_user, Gitlab::Access::MASTER) } diff --git a/spec/finders/snippets_finder_spec.rb b/spec/finders/snippets_finder_spec.rb index 810016c965..28bdc18e84 100644 --- a/spec/finders/snippets_finder_spec.rb +++ b/spec/finders/snippets_finder_spec.rb @@ -69,7 +69,6 @@ describe SnippetsFinder do expect(snippets).to include(@snippet3) expect(snippets).not_to include(@snippet2, @snippet1) end - end context 'by_project filter' do diff --git a/spec/helpers/visibility_level_helper_spec.rb b/spec/helpers/visibility_level_helper_spec.rb index 5e7594170c..db3ad1b99e 100644 --- a/spec/helpers/visibility_level_helper_spec.rb +++ b/spec/helpers/visibility_level_helper_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' describe VisibilityLevelHelper do - let(:project) { build(:project) } let(:group) { build(:group) } let(:personal_snippet) { build(:personal_snippet) } @@ -90,6 +89,5 @@ describe VisibilityLevelHelper do expect(skip_level?(snippet, Gitlab::VisibilityLevel::PRIVATE)).to be_falsey end end - end end diff --git a/spec/initializers/settings_spec.rb b/spec/initializers/settings_spec.rb index 1bcae8a27d..47b4e43182 100644 --- a/spec/initializers/settings_spec.rb +++ b/spec/initializers/settings_spec.rb @@ -2,7 +2,6 @@ require 'spec_helper' require_relative '../../config/initializers/1_settings' describe Settings, lib: true do - describe '#host_without_www' do context 'URL with protocol' do it 'returns the host' do @@ -41,5 +40,4 @@ describe Settings, lib: true do end end end - end diff --git a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb index 72bc6a0b70..51c89ac488 100644 --- a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb +++ b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb @@ -59,7 +59,6 @@ describe Banzai::Pipeline::WikiPipeline do { "when GitLab is hosted at a root URL" => '/', "when GitLab is hosted at a relative URL" => '/nested/relative/gitlab' }.each do |test_name, relative_url_root| - context test_name do before do allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return(relative_url_root) diff --git a/spec/lib/ci/charts_spec.rb b/spec/lib/ci/charts_spec.rb index 9c6b4ea508..97f2e97b06 100644 --- a/spec/lib/ci/charts_spec.rb +++ b/spec/lib/ci/charts_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' describe Ci::Charts, lib: true do - context "build_times" do before do @pipeline = FactoryGirl.create(:ci_pipeline) diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 2ca9f554b0..ec658668c6 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -143,7 +143,6 @@ module Ci end it "returns build only for specified type" do - config = YAML.dump({ before_script: ["pwd"], rspec: { script: "rspec", type: "test", only: ["master", "deploy"] }, diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb index 736bf78720..32ca823984 100644 --- a/spec/lib/gitlab/asciidoc_spec.rb +++ b/spec/lib/gitlab/asciidoc_spec.rb @@ -3,13 +3,11 @@ require 'nokogiri' module Gitlab describe Asciidoc, lib: true do - let(:input) { 'ascii' } let(:context) { {} } let(:html) { 'H2O' } context "without project" do - it "should convert the input using Asciidoctor and default options" do expected_asciidoc_opts = { safe: :secure, @@ -24,7 +22,6 @@ module Gitlab end context "with asciidoc_opts" do - let(:asciidoc_opts) { { safe: :safe, attributes: ['foo'] } } it "should merge the options with default ones" do diff --git a/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb b/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb index 711a3e1c7d..abc93e1b44 100644 --- a/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb +++ b/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb @@ -128,7 +128,6 @@ describe Gitlab::Ci::Build::Artifacts::Metadata::Entry do subject { |example| path(example).children } it { expect(subject.count).to eq 3 } end - end describe 'path/dir_1/subdir/subfile', path: 'path/dir_1/subdir/subfile' do diff --git a/spec/lib/gitlab/diff/inline_diff_marker_spec.rb b/spec/lib/gitlab/diff/inline_diff_marker_spec.rb index ea5c31011f..198ff977f2 100644 --- a/spec/lib/gitlab/diff/inline_diff_marker_spec.rb +++ b/spec/lib/gitlab/diff/inline_diff_marker_spec.rb @@ -2,7 +2,6 @@ require 'spec_helper' describe Gitlab::Diff::InlineDiffMarker, lib: true do describe '#inline_diffs' do - context "when the rich text is html safe" do let(:raw) { "abc 'def'" } let(:rich) { %{abc 'def'}.html_safe } diff --git a/spec/lib/gitlab/fogbugz_import/client_spec.rb b/spec/lib/gitlab/fogbugz_import/client_spec.rb index 2dc71be025..252cd4c55c 100644 --- a/spec/lib/gitlab/fogbugz_import/client_spec.rb +++ b/spec/lib/gitlab/fogbugz_import/client_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' describe Gitlab::FogbugzImport::Client, lib: true do - let(:client) { described_class.new(uri: '', token: '') } let(:one_user) { { 'people' => { 'person' => { "ixPerson" => "2", "sFullName" => "James" } } } } let(:two_users) { { 'people' => { 'person' => [one_user, { "ixPerson" => "3" }] } } } diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index 9b3a0e3a75..9b7986fa12 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -65,7 +65,6 @@ describe Gitlab::GitAccess, lib: true do expect(access.can_push_to_branch?(@branch.name)).to be_falsey end end - end describe 'download_access_check' do diff --git a/spec/lib/gitlab/github_import/label_formatter_spec.rb b/spec/lib/gitlab/github_import/label_formatter_spec.rb index e94440a7fb..87593e32db 100644 --- a/spec/lib/gitlab/github_import/label_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/label_formatter_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' describe Gitlab::GithubImport::LabelFormatter, lib: true do - describe '#attributes' do it 'returns formatted attributes' do project = create(:project) diff --git a/spec/lib/gitlab/google_code_import/importer_spec.rb b/spec/lib/gitlab/google_code_import/importer_spec.rb index 647631271e..54f85f8cff 100644 --- a/spec/lib/gitlab/google_code_import/importer_spec.rb +++ b/spec/lib/gitlab/google_code_import/importer_spec.rb @@ -19,7 +19,6 @@ describe Gitlab::GoogleCodeImport::Importer, lib: true do end describe "#execute" do - it "imports status labels" do subject.execute diff --git a/spec/lib/gitlab/import_export/members_mapper_spec.rb b/spec/lib/gitlab/import_export/members_mapper_spec.rb index f135a285df..6d5aa0d04a 100644 --- a/spec/lib/gitlab/import_export/members_mapper_spec.rb +++ b/spec/lib/gitlab/import_export/members_mapper_spec.rb @@ -2,7 +2,6 @@ require 'spec_helper' describe Gitlab::ImportExport::MembersMapper, services: true do describe 'map members' do - let(:user) { create(:user) } let(:project) { create(:project, :public, name: 'searchable_project') } let(:user2) { create(:user) } diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb index e401ca9907..a72aaa44e8 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -2,7 +2,6 @@ require 'spec_helper' describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do describe 'restore project tree' do - let(:user) { create(:user) } let(:namespace) { create(:namespace, owner: user) } let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: "", project_path: 'path') } diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb index 3b98045a2f..a75eaa4d51 100644 --- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb @@ -2,7 +2,6 @@ require 'spec_helper' describe Gitlab::ImportExport::ProjectTreeSaver, services: true do describe 'saves the project tree into a json object' do - let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) } let(:project_tree_saver) { described_class.new(project: project, shared: shared) } let(:export_path) { "#{Dir::tmpdir}/project_tree_saver_spec" } @@ -23,7 +22,6 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do end context 'JSON' do - let(:saved_project_json) do project_tree_saver.save project_json(project_tree_saver.full_path) diff --git a/spec/lib/gitlab/import_export/reader_spec.rb b/spec/lib/gitlab/import_export/reader_spec.rb index 211ef68dfa..b76e14deca 100644 --- a/spec/lib/gitlab/import_export/reader_spec.rb +++ b/spec/lib/gitlab/import_export/reader_spec.rb @@ -25,7 +25,6 @@ describe Gitlab::ImportExport::Reader, lib: true do end context 'individual scenarios' do - it 'generates the correct hash for a single project relation' do setup_yaml(project_tree: [:issues]) diff --git a/spec/lib/gitlab/import_export/repo_bundler_spec.rb b/spec/lib/gitlab/import_export/repo_bundler_spec.rb index 590a9a7e1a..135e99bc95 100644 --- a/spec/lib/gitlab/import_export/repo_bundler_spec.rb +++ b/spec/lib/gitlab/import_export/repo_bundler_spec.rb @@ -2,7 +2,6 @@ require 'spec_helper' describe Gitlab::ImportExport::RepoSaver, services: true do describe 'bundle a project Git repo' do - let(:user) { create(:user) } let!(:project) { create(:project, :public, name: 'searchable_project') } let(:export_path) { "#{Dir::tmpdir}/project_tree_saver_spec" } diff --git a/spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb b/spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb index b9ffc8694a..b628da0f3e 100644 --- a/spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb +++ b/spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb @@ -2,7 +2,6 @@ require 'spec_helper' describe Gitlab::ImportExport::WikiRepoSaver, services: true do describe 'bundle a wiki Git repo' do - let(:user) { create(:user) } let!(:project) { create(:project, :public, name: 'searchable_project') } let(:export_path) { "#{Dir::tmpdir}/project_tree_saver_spec" } diff --git a/spec/lib/gitlab/ldap/auth_hash_spec.rb b/spec/lib/gitlab/ldap/auth_hash_spec.rb index 6a53ed1db6..69c4905115 100644 --- a/spec/lib/gitlab/ldap/auth_hash_spec.rb +++ b/spec/lib/gitlab/ldap/auth_hash_spec.rb @@ -32,7 +32,6 @@ describe Gitlab::LDAP::AuthHash, lib: true do end context "without overridden attributes" do - it "has the correct username" do expect(auth_hash.username).to eq("123456") end diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb index 5ec5ab40b6..dd113d7334 100644 --- a/spec/lib/gitlab/o_auth/user_spec.rb +++ b/spec/lib/gitlab/o_auth/user_spec.rb @@ -128,7 +128,6 @@ describe Gitlab::OAuth::User, lib: true do end context "and no account for the LDAP user" do - it "creates a user with dual LDAP and omniauth identities" do oauth_user.save @@ -169,7 +168,6 @@ describe Gitlab::OAuth::User, lib: true do end end end - end describe 'blocking' do @@ -255,7 +253,6 @@ describe Gitlab::OAuth::User, lib: true do end end - context 'sign-in' do before do oauth_user.save diff --git a/spec/lib/gitlab/push_data_builder_spec.rb b/spec/lib/gitlab/push_data_builder_spec.rb index 7fc34139ef..6bd7393aaa 100644 --- a/spec/lib/gitlab/push_data_builder_spec.rb +++ b/spec/lib/gitlab/push_data_builder_spec.rb @@ -4,7 +4,6 @@ describe Gitlab::PushDataBuilder, lib: true do let(:project) { create(:project) } let(:user) { create(:user) } - describe '.build_sample' do let(:data) { described_class.build_sample(project, user) } diff --git a/spec/lib/gitlab/saml/user_spec.rb b/spec/lib/gitlab/saml/user_spec.rb index 2753aecc1f..56bf08e704 100644 --- a/spec/lib/gitlab/saml/user_spec.rb +++ b/spec/lib/gitlab/saml/user_spec.rb @@ -214,7 +214,6 @@ describe Gitlab::Saml::User, lib: true do end end end - end describe 'blocking' do diff --git a/spec/lib/gitlab/url_sanitizer_spec.rb b/spec/lib/gitlab/url_sanitizer_spec.rb index de55334118..59024d3290 100644 --- a/spec/lib/gitlab/url_sanitizer_spec.rb +++ b/spec/lib/gitlab/url_sanitizer_spec.rb @@ -64,5 +64,4 @@ describe Gitlab::UrlSanitizer, lib: true do expect(sanitizer.full_url).to eq('user@server:project.git') end end - end diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index ae55a01ebe..016856a62f 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -984,7 +984,6 @@ describe Notify do end context "when set to send from committer email if domain matches" do - let(:send_from_committer_email) { true } before do @@ -992,7 +991,6 @@ describe Notify do end context "when the committer email domain is within the GitLab domain" do - before do user.update_attribute(:email, "user@company.com") user.confirm @@ -1010,7 +1008,6 @@ describe Notify do end context "when the committer email domain is not completely within the GitLab domain" do - before do user.update_attribute(:email, "user@something.company.com") user.confirm @@ -1028,7 +1025,6 @@ describe Notify do end context "when the committer email domain is outside the GitLab domain" do - before do user.update_attribute(:email, "user@mpany.com") user.confirm @@ -1084,5 +1080,4 @@ describe Notify do is_expected.to have_body_text /#{diff_path}/ end end - end diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb index 97b28686d8..e817178887 100644 --- a/spec/models/build_spec.rb +++ b/spec/models/build_spec.rb @@ -323,7 +323,6 @@ describe Ci::Build, models: true do expect_any_instance_of(Ci::Runner).to receive(:can_pick?).and_return(false) is_expected.to be_falsey end - end end diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index 89730ab8eb..60e4bbc856 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -170,7 +170,6 @@ describe Issue, "Issuable" do end end - describe '#subscribed?' do context 'user is not a participant in the issue' do before { allow(issue).to receive(:participants).with(user).and_return([]) } diff --git a/spec/models/concerns/strip_attribute_spec.rb b/spec/models/concerns/strip_attribute_spec.rb index 6445e29c3e..c3af7a0960 100644 --- a/spec/models/concerns/strip_attribute_spec.rb +++ b/spec/models/concerns/strip_attribute_spec.rb @@ -16,5 +16,4 @@ describe Milestone, "StripAttribute" do it { expect(milestone.title).to eq('8.3') } end - end diff --git a/spec/models/email_spec.rb b/spec/models/email_spec.rb index 5d0bd31db5..d9df9e0f90 100644 --- a/spec/models/email_spec.rb +++ b/spec/models/email_spec.rb @@ -1,11 +1,9 @@ require 'spec_helper' describe Email, models: true do - describe 'validations' do it_behaves_like 'an object with email-formated attributes', :email do subject { build(:email) } end end - end diff --git a/spec/models/forked_project_link_spec.rb b/spec/models/forked_project_link_spec.rb index 3b817608ce..fa1a0d4e0c 100644 --- a/spec/models/forked_project_link_spec.rb +++ b/spec/models/forked_project_link_spec.rb @@ -23,14 +23,12 @@ describe :forked_from_project do let(:project_from) { create(:project) } let(:project_to) { create(:project, forked_project_link: forked_project_link) } - before :each do forked_project_link.forked_from_project = project_from forked_project_link.forked_to_project = project_to forked_project_link.save! end - it "project_to should know it is forked" do expect(project_to.forked?).to be_truthy end @@ -43,7 +41,6 @@ describe :forked_from_project do expect(forked_project_link).to receive(:destroy) project_to.destroy end - end def fork_project(from_project, user) diff --git a/spec/models/identity_spec.rb b/spec/models/identity_spec.rb index 1b987588f5..b3aed66a5b 100644 --- a/spec/models/identity_spec.rb +++ b/spec/models/identity_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' RSpec.describe Identity, models: true do - describe 'relations' do it { is_expected.to belong_to(:user) } end diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb index bbf65edb27..4c10346243 100644 --- a/spec/models/members/project_member_spec.rb +++ b/spec/models/members/project_member_spec.rb @@ -119,7 +119,6 @@ describe ProjectMember, models: true do it { expect(@project_1.users).to include(@user_1) } it { expect(@project_1.users).to include(@user_2) } - it { expect(@project_2.users).to include(@user_1) } it { expect(@project_2.users).to include(@user_2) } end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index cbea407f9b..5f68cd2b06 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -109,7 +109,6 @@ describe Namespace, models: true do end describe ".clean_path" do - let!(:user) { create(:user, username: "johngitlab-etc") } let!(:namespace) { create(:namespace, path: "JohnGitLab-etc1") } diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index c951732454..5a97cf370d 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -154,11 +154,9 @@ describe JiraService, models: true do expect(@jira_service.password).to eq("password") expect(@jira_service.api_url).to eq("http://jira_edited.example.com/rest/api/2") end - end end - describe "Validations" do context "active" do before do diff --git a/spec/models/project_services/slack_service/wiki_page_message_spec.rb b/spec/models/project_services/slack_service/wiki_page_message_spec.rb index 6ecab645b4..46dedb66c7 100644 --- a/spec/models/project_services/slack_service/wiki_page_message_spec.rb +++ b/spec/models/project_services/slack_service/wiki_page_message_spec.rb @@ -47,7 +47,6 @@ describe SlackService::WikiPageMessage, models: true do context 'when :action == "create"' do before { args[:object_attributes][:action] = 'create' } - it 'it returns the attachment for a new wiki page' do expect(subject.attachments).to eq([ { diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 8ae083d713..851b8b241d 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -855,7 +855,6 @@ describe Repository, models: true do repository.after_create end - end describe "#copy_gitattributes" do diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index 2f000dbc01..96bbbec9ea 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' describe Service, models: true do - describe "Associations" do it { is_expected.to belong_to :project } it { is_expected.to have_one :service_hook } @@ -176,7 +175,6 @@ describe Service, models: true do ) end - it "returns nil when the property has not been assigned a new value" do service.username = "key_changed" expect(service.bamboo_url_was).to be_nil diff --git a/spec/requests/api/api_helpers_spec.rb b/spec/requests/api/api_helpers_spec.rb index f22db61e74..8302595388 100644 --- a/spec/requests/api/api_helpers_spec.rb +++ b/spec/requests/api/api_helpers_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' describe API::Helpers, api: true do - include API::Helpers include ApiHelpers diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb index ed78d582bd..72a6d45f47 100644 --- a/spec/requests/api/award_emoji_spec.rb +++ b/spec/requests/api/award_emoji_spec.rb @@ -62,7 +62,6 @@ describe API::API, api: true do end end - describe "GET /projects/:id/awardable/:awardable_id/award_emoji/:award_id" do context 'on an issue' do it "returns the award emoji" do diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb index 6668f3543f..2da01da7fa 100644 --- a/spec/requests/api/commit_statuses_spec.rb +++ b/spec/requests/api/commit_statuses_spec.rb @@ -11,7 +11,6 @@ describe API::CommitStatuses, api: true do let(:developer) { create_user(:developer) } let(:sha) { commit.id } - describe "GET /projects/:id/repository/commits/:sha/statuses" do let(:get_url) { "/projects/#{project.id}/repository/commits/#{sha}/statuses" } diff --git a/spec/requests/api/doorkeeper_access_spec.rb b/spec/requests/api/doorkeeper_access_spec.rb index 881b818b5e..5262a62376 100644 --- a/spec/requests/api/doorkeeper_access_spec.rb +++ b/spec/requests/api/doorkeeper_access_spec.rb @@ -7,7 +7,6 @@ describe API::API, api: true do let!(:application) { Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user) } let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id } - describe "when unauthenticated" do it "returns authentication success" do get api("/user"), access_token: token.token diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb index 3973677998..0404cf31ff 100644 --- a/spec/requests/api/labels_spec.rb +++ b/spec/requests/api/labels_spec.rb @@ -11,7 +11,6 @@ describe API::API, api: true do project.team << [user, :master] end - describe 'GET /projects/:id/labels' do it 'should return project labels' do get api("/projects/#{project.id}/labels", user) diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index bacd01f8e7..65c53211dd 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -159,7 +159,6 @@ describe API::API, api: true do end end - context "and current user can view the note" do it "should return an issue note by id" do get api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes/#{cross_reference_note.id}", private_user) @@ -221,7 +220,6 @@ describe API::API, api: true do expect(Time.parse(json_response['created_at'])).to be_within(1.second).of(creation_time) end end - end context "when noteable is a Snippet" do @@ -396,5 +394,4 @@ describe API::API, api: true do end end end - end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 5c909d8b3b..611dd2a2a8 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -707,7 +707,6 @@ describe API::API, api: true do end describe 'DELETE /projects/:id/fork' do - it "shouldn't be visible to users outside group" do delete api("/projects/#{project_fork_target.id}/fork", user) expect(response).to have_http_status(404) diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb index bf7eaaaaae..a2446e1280 100644 --- a/spec/requests/api/services_spec.rb +++ b/spec/requests/api/services_spec.rb @@ -87,7 +87,6 @@ describe API::API, api: true do expect(response).to have_http_status(403) end - end end end diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb index 6629a5a65e..684c2cd8e2 100644 --- a/spec/requests/api/settings_spec.rb +++ b/spec/requests/api/settings_spec.rb @@ -6,7 +6,6 @@ describe API::API, 'Settings', api: true do let(:user) { create(:user) } let(:admin) { create(:admin) } - describe "GET /application/settings" do it "should return application settings" do get api("/application/settings", admin) diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 056256a29f..e43e3e269b 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -246,7 +246,6 @@ describe API::API, api: true do end describe "GET /users/sign_up" do - it "should redirect to sign in page" do get "/users/sign_up" expect(response).to have_http_status(302) diff --git a/spec/routing/admin_routing_spec.rb b/spec/routing/admin_routing_spec.rb index b5ed8584c8..8b19936ae6 100644 --- a/spec/routing/admin_routing_spec.rb +++ b/spec/routing/admin_routing_spec.rb @@ -95,7 +95,6 @@ describe Admin::HooksController, "routing" do it "to #destroy" do expect(delete("/admin/hooks/1")).to route_to('admin/hooks#destroy', id: '1') end - end # admin_logs GET /admin/logs(.:format) admin/logs#show diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 538f44e4f3..620f328a11 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -165,7 +165,6 @@ describe Projects::TagsController, 'routing' do end end - # project_deploy_keys GET /:project_id/deploy_keys(.:format) deploy_keys#index # POST /:project_id/deploy_keys(.:format) deploy_keys#create # new_project_deploy_key GET /:project_id/deploy_keys/new(.:format) deploy_keys#new diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb index de13c0db5d..8a8e131c57 100644 --- a/spec/routing/routing_spec.rb +++ b/spec/routing/routing_spec.rb @@ -253,7 +253,6 @@ describe RootController, 'routing' do end end - # new_user_session GET /users/sign_in(.:format) devise/sessions#new # user_session POST /users/sign_in(.:format) devise/sessions#create # destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy diff --git a/spec/services/git_hooks_service_spec.rb b/spec/services/git_hooks_service_spec.rb index 2bb9c3b3db..6367ac832e 100644 --- a/spec/services/git_hooks_service_spec.rb +++ b/spec/services/git_hooks_service_spec.rb @@ -16,7 +16,6 @@ describe GitHooksService, services: true do end describe '#execute' do - context 'when receive hooks were successful' do it 'should call post-receive hook' do hook = double(trigger: true) @@ -48,6 +47,5 @@ describe GitHooksService, services: true do end.to raise_error(GitHooksService::PreReceiveError) end end - end end diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index 48d374883d..afabeed4a8 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -14,7 +14,6 @@ describe GitPushService, services: true do end describe 'Push branches' do - let(:oldrev) { @oldrev } let(:newrev) { @newrev } @@ -23,7 +22,6 @@ describe GitPushService, services: true do end context 'new branch' do - let(:oldrev) { @blankrev } it { is_expected.to be_truthy } @@ -55,7 +53,6 @@ describe GitPushService, services: true do end context 'existing branch' do - it { is_expected.to be_truthy } it 'flushes general cached data' do @@ -79,7 +76,6 @@ describe GitPushService, services: true do end context 'rm branch' do - let(:newrev) { @blankrev } it { is_expected.to be_truthy } @@ -223,7 +219,6 @@ describe GitPushService, services: true do end end - describe "Webhooks" do context "execute webhooks" do it "when pushing a branch for the first time" do @@ -491,7 +486,6 @@ describe GitPushService, services: true do end end - it 'increments the push counter' do expect(housekeeping).to receive(:increment!) diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 31b93850c7..7d5cb87606 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -175,7 +175,6 @@ describe MergeRequests::RefreshService, services: true do end end - def reload_mrs @merge_request.reload @fork_merge_request.reload diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 776a6ab5ed..54719cbb8d 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -95,7 +95,6 @@ describe NotificationService, services: true do notification.new_note(note) end - it { should_not_email(@u_lazy_participant) } end end @@ -377,7 +376,6 @@ describe NotificationService, services: true do end describe '#reassigned_issue' do - before do update_custom_notification(:reassign_issue, @u_guest_custom, project) update_custom_notification(:reassign_issue, @u_custom_global) @@ -566,7 +564,6 @@ describe NotificationService, services: true do end describe '#close_issue' do - before do update_custom_notification(:close_issue, @u_guest_custom, project) update_custom_notification(:close_issue, @u_custom_global) @@ -712,7 +709,6 @@ describe NotificationService, services: true do should_email(subscriber) end - context 'participating' do context 'by assignee' do before do @@ -880,7 +876,6 @@ describe NotificationService, services: true do end describe '#merged_merge_request' do - before do update_custom_notification(:merge_merge_request, @u_guest_custom, project) update_custom_notification(:merge_merge_request, @u_custom_global) diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index d5aa115a07..57c71544df 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -71,5 +71,4 @@ describe Projects::TransferService, services: true do it { expect(private_project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE) } end end - end diff --git a/spec/support/jira_service_helper.rb b/spec/support/jira_service_helper.rb index 5ebe095743..f3ea206f38 100644 --- a/spec/support/jira_service_helper.rb +++ b/spec/support/jira_service_helper.rb @@ -1,5 +1,4 @@ module JiraServiceHelper - def jira_service_settings properties = { "title" => "JIRA tracker", diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb index 02308530d1..d2c056d8e1 100644 --- a/spec/tasks/gitlab/backup_rake_spec.rb +++ b/spec/tasks/gitlab/backup_rake_spec.rb @@ -76,7 +76,6 @@ describe 'gitlab:app namespace rake task' do expect { run_rake_task('gitlab:backup:restore') }.not_to raise_error end end - end # backup_restore task describe 'backup_create' do diff --git a/spec/workers/project_cache_worker_spec.rb b/spec/workers/project_cache_worker_spec.rb index 7e59bd2fce..5785a6a06f 100644 --- a/spec/workers/project_cache_worker_spec.rb +++ b/spec/workers/project_cache_worker_spec.rb @@ -7,7 +7,6 @@ describe ProjectCacheWorker do describe '#perform' do it 'updates project cache data' do - expect_any_instance_of(Repository).to receive(:size) expect_any_instance_of(Repository).to receive(:commit_count)