From 2acb8a3085ad64ce56625a9d63f01f9398e757a3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Jul 2016 14:09:23 +0300 Subject: Change merge request diff index to be not uniq Signed-off-by: Dmitriy Zaporozhets --- ...20160725104020_merge_request_diff_remove_uniq.rb | 21 +++++++++++++++++++++ .../20160725104452_merge_request_diff_add_index.rb | 17 +++++++++++++++++ db/schema.rb | 14 +++++++------- 3 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 db/migrate/20160725104020_merge_request_diff_remove_uniq.rb create mode 100644 db/migrate/20160725104452_merge_request_diff_add_index.rb diff --git a/db/migrate/20160725104020_merge_request_diff_remove_uniq.rb b/db/migrate/20160725104020_merge_request_diff_remove_uniq.rb new file mode 100644 index 00000000000..c8cbd2718ff --- /dev/null +++ b/db/migrate/20160725104020_merge_request_diff_remove_uniq.rb @@ -0,0 +1,21 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class MergeRequestDiffRemoveUniq < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + disable_ddl_transaction! + + DOWNTIME = false + + def up + if index_exists?(:merge_request_diffs, :merge_request_id) + remove_index :merge_request_diffs, :merge_request_id + end + end + + def down + unless index_exists?(:merge_request_diffs, :merge_request_id) + add_concurrent_index :merge_request_diffs, :merge_request_id, unique: true + end + end +end diff --git a/db/migrate/20160725104452_merge_request_diff_add_index.rb b/db/migrate/20160725104452_merge_request_diff_add_index.rb new file mode 100644 index 00000000000..6d04242dd25 --- /dev/null +++ b/db/migrate/20160725104452_merge_request_diff_add_index.rb @@ -0,0 +1,17 @@ +class MergeRequestDiffAddIndex < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + disable_ddl_transaction! + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + def up + add_concurrent_index :merge_request_diffs, :merge_request_id + end + + def down + if index_exists?(:merge_request_diffs, :merge_request_id) + remove_index :merge_request_diffs, :merge_request_id + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 5b35a528e71..e3eecfebfd4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160726093600) do +ActiveRecord::Schema.define(version: 20160725104452) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -84,8 +84,8 @@ ActiveRecord::Schema.define(version: 20160726093600) do t.string "health_check_access_token" t.boolean "send_user_confirmation_email", default: false t.integer "container_registry_token_expire_delay", default: 5 - t.boolean "user_default_external", default: false, null: false t.text "after_sign_up_text" + t.boolean "user_default_external", default: false, null: false t.string "repository_storage", default: "default" t.string "enabled_git_access_protocol" t.boolean "domain_blacklist_enabled", default: false @@ -167,8 +167,8 @@ ActiveRecord::Schema.define(version: 20160726093600) do t.text "artifacts_metadata" t.integer "erased_by_id" t.datetime "erased_at" - t.string "environment" t.datetime "artifacts_expire_at" + t.string "environment" t.integer "artifacts_size" t.string "when" t.text "yaml_variables" @@ -605,7 +605,7 @@ ActiveRecord::Schema.define(version: 20160726093600) do t.string "start_commit_sha" end - add_index "merge_request_diffs", ["merge_request_id"], name: "index_merge_request_diffs_on_merge_request_id", unique: true, using: :btree + add_index "merge_request_diffs", ["merge_request_id"], name: "index_merge_request_diffs_on_merge_request_id", using: :btree create_table "merge_requests", force: :cascade do |t| t.string "target_branch", null: false @@ -782,10 +782,10 @@ ActiveRecord::Schema.define(version: 20160726093600) do t.integer "user_id", null: false t.string "token", null: false t.string "name", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false t.boolean "revoked", default: false t.datetime "expires_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "personal_access_tokens", ["token"], name: "index_personal_access_tokens_on_token", unique: true, using: :btree @@ -847,8 +847,8 @@ ActiveRecord::Schema.define(version: 20160726093600) do 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 - t.boolean "has_external_wiki" t.boolean "request_access_enabled", default: true, null: false + t.boolean "has_external_wiki" end add_index "projects", ["builds_enabled", "shared_runners_enabled"], name: "index_projects_on_builds_enabled_and_shared_runners_enabled", using: :btree -- cgit v1.2.1 From 2afcc9e910bde32507e14be452c9f7681f5497e4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Jul 2016 14:10:21 +0300 Subject: Create new version of merge request diff on push instead of updating existing one Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index f1b9c1d6feb..ef0b7da048e 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -10,8 +10,7 @@ class MergeRequest < ActiveRecord::Base belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project" belongs_to :merge_user, class_name: "User" - has_one :merge_request_diff, dependent: :destroy - + has_many :merge_request_diffs, dependent: :destroy has_many :events, as: :target, dependent: :destroy serialize :merge_params, Hash @@ -294,7 +293,9 @@ class MergeRequest < ActiveRecord::Base end def reload_diff - return unless merge_request_diff && open? + return unless open? + + merge_request_diff = merge_request_diffs.create old_diff_refs = self.diff_refs @@ -691,4 +692,8 @@ class MergeRequest < ActiveRecord::Base def keep_around_commit project.repository.keep_around(self.merge_commit_sha) end + + def merge_request_diff + merge_request_diffs.first + end end -- cgit v1.2.1 From ceff8106433187613eb97d13952fc96c4806b847 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Jul 2016 17:04:55 +0300 Subject: Create merge request diff on merge request creation Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index ef0b7da048e..88c5987d485 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -286,6 +286,10 @@ class MergeRequest < ActiveRecord::Base end end + def create_merge_request_diff + merge_request_diffs.create + end + def update_merge_request_diff if source_branch_changed? || target_branch_changed? reload_diff -- cgit v1.2.1 From 94ca25c9b8c62f9995fbd571c33954754950e1da Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 25 Jul 2016 18:42:57 +0300 Subject: Improve merge request diff creation and update tests Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request.rb | 6 +----- spec/models/merge_request_spec.rb | 28 ++++++++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 88c5987d485..cc1d0c18437 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -299,12 +299,8 @@ class MergeRequest < ActiveRecord::Base def reload_diff return unless open? - merge_request_diff = merge_request_diffs.create - old_diff_refs = self.diff_refs - - merge_request_diff.reload_content - + create_merge_request_diff new_diff_refs = self.diff_refs update_diff_notes_positions( diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index a0e3c26e542..03e4ae574ef 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -9,7 +9,7 @@ describe MergeRequest, models: true do it { is_expected.to belong_to(:target_project).with_foreign_key(:target_project_id).class_name('Project') } it { is_expected.to belong_to(:source_project).with_foreign_key(:source_project_id).class_name('Project') } it { is_expected.to belong_to(:merge_user).class_name("User") } - it { is_expected.to have_one(:merge_request_diff).dependent(:destroy) } + it { is_expected.to have_many(:merge_request_diffs).dependent(:destroy) } end describe 'modules' do @@ -134,7 +134,7 @@ describe MergeRequest, models: true do context 'when there are MR diffs' do it 'delegates to the MR diffs' do - merge_request.merge_request_diff = MergeRequestDiff.new + merge_request.merge_request_diffs.build expect(merge_request.merge_request_diff).to receive(:diffs).with(options) @@ -654,22 +654,26 @@ describe MergeRequest, models: true do let(:commit) { subject.project.commit(sample_commit.id) } - it "reloads the diff content" do - expect(subject.merge_request_diff).to receive(:reload_content) - + it "does not change existing merge request diff" do + expect(subject.merge_request_diff).not_to receive(:reload_content) subject.reload_diff end + it "creates new merge request diff" do + expect { subject.reload_diff }.to change { subject.merge_request_diffs.count }.by(1) + end + it "updates diff note positions" do old_diff_refs = subject.diff_refs - merge_request_diff = subject.merge_request_diff - # Update merge_request_diff so that #diff_refs will return commit.diff_refs - allow(merge_request_diff).to receive(:reload_content) do - merge_request_diff.base_commit_sha = commit.parent_id - merge_request_diff.start_commit_sha = commit.parent_id - merge_request_diff.head_commit_sha = commit.sha + allow(subject).to receive(:create_merge_request_diff) do + subject.merge_request_diffs.create( + importing: true, + base_commit_sha: commit.parent_id, + start_commit_sha: commit.parent_id, + head_commit_sha: commit.sha + ) end expect(Notes::DiffPositionUpdateService).to receive(:new).with( @@ -679,8 +683,8 @@ describe MergeRequest, models: true do new_diff_refs: commit.diff_refs, paths: note.position.paths ).and_call_original - expect_any_instance_of(Notes::DiffPositionUpdateService).to receive(:execute).with(note) + expect_any_instance_of(Notes::DiffPositionUpdateService).to receive(:execute).with(note) expect_any_instance_of(DiffNote).to receive(:save).once subject.reload_diff -- cgit v1.2.1 From b8fef7eb5948344f4d442a52637cad168f4c5bf1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Jul 2016 18:24:25 +0300 Subject: Add ability to render different merge request versions Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/merge_requests_controller.rb | 8 +++++++- app/models/merge_request_diff.rb | 10 ++++++++++ .../projects/merge_requests/show/_diffs.html.haml | 5 +++-- .../projects/merge_requests/show/_versions.html.haml | 18 ++++++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 app/views/projects/merge_requests/show/_versions.html.haml diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 03166294ddd..a886af713d5 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -81,7 +81,13 @@ class Projects::MergeRequestsController < Projects::ApplicationController def diffs apply_diff_view_cookie! - @merge_request_diff = @merge_request.merge_request_diff + @merge_request_diff = + if params[:diff_id] + @merge_request.merge_request_diffs.find(params[:diff_id]) + else + @merge_request.merge_request_diff + end + respond_to do |format| format.html { define_discussion_vars } diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 3f520c8f3ff..a92f597225a 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -96,6 +96,16 @@ class MergeRequestDiff < ActiveRecord::Base end end + def diff_refs + return unless start_commit || base_commit + + Gitlab::Diff::DiffRefs.new( + base_sha: base_commit_sha, + start_sha: start_commit_sha, + head_sha: head_commit_sha + ) + end + private # Collect array of Git::Commit objects diff --git a/app/views/projects/merge_requests/show/_diffs.html.haml b/app/views/projects/merge_requests/show/_diffs.html.haml index 1b0bae86ad4..e26499cc144 100644 --- a/app/views/projects/merge_requests/show/_diffs.html.haml +++ b/app/views/projects/merge_requests/show/_diffs.html.haml @@ -1,6 +1,7 @@ - if @merge_request_diff.collected? - = render "projects/diffs/diffs", diffs: @merge_request.diffs(diff_options), - project: @merge_request.project, diff_refs: @merge_request.diff_refs + = render 'projects/merge_requests/show/versions' + = render "projects/diffs/diffs", diffs: @merge_request_diff.diffs(diff_options), + project: @merge_request.project, diff_refs: @merge_request_diff.diff_refs - elsif @merge_request_diff.empty? .nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch} - else diff --git a/app/views/projects/merge_requests/show/_versions.html.haml b/app/views/projects/merge_requests/show/_versions.html.haml new file mode 100644 index 00000000000..2764786d9bf --- /dev/null +++ b/app/views/projects/merge_requests/show/_versions.html.haml @@ -0,0 +1,18 @@ +- if @merge_request.merge_request_diffs.size > 1 + - latest_diff = @merge_request.merge_request_diff + .light-well + Merge Request version + + %span.dropdown.inline + %a.dropdown-toggle{ data: {toggle: :dropdown} } + %strong.monospace #{@merge_request_diff.base_commit.short_id}..#{@merge_request_diff.head_commit.short_id} + %span.caret + %ul.dropdown-menu + - @merge_request.merge_request_diffs.each do |merge_request_diff| + %li{ class: ('active' if merge_request_diff == latest_diff) } + = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request, diff_id: merge_request_diff.id) do + %strong.monospace + #{merge_request_diff.base_commit.short_id}..#{merge_request_diff.head_commit.short_id} + %br + %small + = time_ago_with_tooltip(merge_request_diff.created_at) -- cgit v1.2.1 From dbd58dc4bb638be33f98336410ae6f4ede15f737 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 26 Jul 2016 20:03:45 +0300 Subject: Improve merge request version switcher Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/dropdowns.scss | 6 ++++++ app/assets/stylesheets/pages/merge_requests.scss | 6 ++++++ .../merge_requests/show/_versions.html.haml | 24 ++++++++++++++-------- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index c54eb0d6479..28346423541 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -17,6 +17,12 @@ .dropdown { position: relative; + + .btn-link { + &:hover { + cursor: pointer; + } + } } .open { diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 0a661e529f0..14ded0eec72 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -371,3 +371,9 @@ } } } + +.mr-version-switch { + background: $background-color; + padding: $gl-btn-padding; + border-bottom: 1px solid $border-color; +} diff --git a/app/views/projects/merge_requests/show/_versions.html.haml b/app/views/projects/merge_requests/show/_versions.html.haml index 2764786d9bf..5c0098bcf98 100644 --- a/app/views/projects/merge_requests/show/_versions.html.haml +++ b/app/views/projects/merge_requests/show/_versions.html.haml @@ -1,18 +1,24 @@ -- if @merge_request.merge_request_diffs.size > 1 - - latest_diff = @merge_request.merge_request_diff - .light-well - Merge Request version +- diffs_count = @merge_request.merge_request_diffs.count +- if diffs_count > 1 + - latest_diff = @merge_request.merge_request_diff + .mr-version-switch + Version:  %span.dropdown.inline - %a.dropdown-toggle{ data: {toggle: :dropdown} } - %strong.monospace #{@merge_request_diff.base_commit.short_id}..#{@merge_request_diff.head_commit.short_id} + %a.btn-link.dropdown-toggle{ data: {toggle: :dropdown} } + %strong.monospace< + - if latest_diff == @merge_request_diff + #{"latest"} + - else + #{@merge_request_diff.base_commit.short_id}..#{@merge_request_diff.head_commit.short_id} %span.caret - %ul.dropdown-menu + %ul.dropdown-menu.dropdown-menu-selectable - @merge_request.merge_request_diffs.each do |merge_request_diff| - %li{ class: ('active' if merge_request_diff == latest_diff) } - = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request, diff_id: merge_request_diff.id) do + %li + = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request, diff_id: merge_request_diff.id), class: ('is-active' if merge_request_diff == @merge_request_diff) do %strong.monospace #{merge_request_diff.base_commit.short_id}..#{merge_request_diff.head_commit.short_id} %br %small + = time_ago_with_tooltip(merge_request_diff.created_at) -- cgit v1.2.1 From 6190216541adb04fd0ce4b21862e6b253b868671 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Jul 2016 11:27:06 +0300 Subject: Add small visual improvements to merge request version switch Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/pages/merge_requests.scss | 6 +++++- app/views/projects/merge_requests/show/_versions.html.haml | 9 ++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 14ded0eec72..7d8f58ca5af 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -375,5 +375,9 @@ .mr-version-switch { background: $background-color; padding: $gl-btn-padding; - border-bottom: 1px solid $border-color; + color: $gl-placeholder-color; + + a.btn-link { + color: $gl-dark-link-color; + } } diff --git a/app/views/projects/merge_requests/show/_versions.html.haml b/app/views/projects/merge_requests/show/_versions.html.haml index 5c0098bcf98..8b7d866941c 100644 --- a/app/views/projects/merge_requests/show/_versions.html.haml +++ b/app/views/projects/merge_requests/show/_versions.html.haml @@ -10,15 +10,18 @@ - if latest_diff == @merge_request_diff #{"latest"} - else - #{@merge_request_diff.base_commit.short_id}..#{@merge_request_diff.head_commit.short_id} + #{@merge_request_diff.head_commit.short_id} %span.caret %ul.dropdown-menu.dropdown-menu-selectable - @merge_request.merge_request_diffs.each do |merge_request_diff| %li = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request, diff_id: merge_request_diff.id), class: ('is-active' if merge_request_diff == @merge_request_diff) do %strong.monospace - #{merge_request_diff.base_commit.short_id}..#{merge_request_diff.head_commit.short_id} + #{merge_request_diff.head_commit.short_id} %br %small - = time_ago_with_tooltip(merge_request_diff.created_at) + + .pull-right + %span.monospace + git diff #{@merge_request_diff.base_commit.short_id}..#{@merge_request_diff.head_commit.short_id} -- cgit v1.2.1 From 09fa0139281d7a76d6b40991f7672187fea40e67 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Jul 2016 14:41:19 +0300 Subject: Refactor merge request diff Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request_diff.rb | 89 +++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 51 deletions(-) diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index a92f597225a..07bceda049c 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -8,7 +8,8 @@ class MergeRequestDiff < ActiveRecord::Base belongs_to :merge_request - delegate :source_branch_sha, :target_branch_sha, :target_branch, :source_branch, to: :merge_request, prefix: nil + delegate :source_branch_sha, :target_branch_sha, + :target_branch, :source_branch, to: :merge_request, prefix: nil state_machine :state, initial: :empty do state :collected @@ -24,9 +25,16 @@ class MergeRequestDiff < ActiveRecord::Base serialize :st_commits serialize :st_diffs + after_initialize :set_diff_range after_create :reload_content, unless: :importing? after_save :keep_around_commits, unless: :importing? + def set_diff_range + self.start_commit_sha ||= target_branch_sha + self.head_commit_sha ||= source_branch_sha + self.base_commit_sha ||= branch_base_sha + end + def reload_content reload_commits reload_diffs @@ -41,8 +49,8 @@ class MergeRequestDiff < ActiveRecord::Base @diffs_no_whitespace ||= begin compare = Gitlab::Git::Compare.new( repository.raw_repository, - self.start_commit_sha || self.target_branch_sha, - self.head_commit_sha || self.source_branch_sha, + start_commit_sha, + head_commit_sha ) compare.diffs(options) end @@ -65,35 +73,21 @@ class MergeRequestDiff < ActiveRecord::Base end def base_commit - return unless self.base_commit_sha + return unless base_commit_sha - project.commit(self.base_commit_sha) + project.commit(base_commit_sha) end def start_commit - return unless self.start_commit_sha + return unless start_commit_sha - project.commit(self.start_commit_sha) + project.commit(start_commit_sha) end def head_commit - return last_commit unless self.head_commit_sha + return last_commit unless head_commit_sha - project.commit(self.head_commit_sha) - end - - def compare - @compare ||= - begin - # Update ref for merge request - merge_request.fetch_ref - - Gitlab::Git::Compare.new( - repository.raw_repository, - self.target_branch_sha, - self.source_branch_sha - ) - end + project.commit(head_commit_sha) end def diff_refs @@ -108,16 +102,18 @@ class MergeRequestDiff < ActiveRecord::Base private - # Collect array of Git::Commit objects - # between target and source branches - def unmerged_commits - commits = compare.commits - - if commits.present? - commits = Commit.decorate(commits, merge_request.source_project).reverse - end + def compare + @compare ||= + begin + # Update ref for merge request + merge_request.fetch_ref - commits + Gitlab::Git::Compare.new( + repository.raw_repository, + start_commit_sha, + head_commit_sha + ) + end end def dump_commits(commits) @@ -133,21 +129,16 @@ class MergeRequestDiff < ActiveRecord::Base def reload_commits new_attributes = {} - commit_objects = unmerged_commits + commits = compare.commits - if commit_objects.present? - new_attributes[:st_commits] = dump_commits(commit_objects) + if commits.present? + commits = Commit.decorate(commits, merge_request.source_project).reverse + new_attributes[:st_commits] = dump_commits(commits) end update_columns_serialized(new_attributes) end - # Collect array of Git::Diff objects - # between target and source branches - def unmerged_diffs - compare.diffs(Commit.max_diff_options) - end - def dump_diffs(diffs) if diffs.respond_to?(:map) diffs.map(&:to_hash) @@ -177,7 +168,7 @@ class MergeRequestDiff < ActiveRecord::Base if commits.size.zero? new_attributes[:state] = :empty else - diff_collection = unmerged_diffs + diff_collection = compare.diffs(Commit.max_diff_options) if diff_collection.overflow? # Set our state to 'overflow' to make the #empty? and #collected? @@ -195,10 +186,6 @@ class MergeRequestDiff < ActiveRecord::Base new_attributes[:st_diffs] = new_diffs - new_attributes[:start_commit_sha] = self.target_branch_sha - new_attributes[:head_commit_sha] = self.source_branch_sha - new_attributes[:base_commit_sha] = branch_base_sha - update_columns_serialized(new_attributes) keep_around_commits @@ -213,9 +200,9 @@ class MergeRequestDiff < ActiveRecord::Base end def branch_base_commit - return unless self.source_branch_sha && self.target_branch_sha + return unless source_branch_sha && target_branch_sha - project.merge_base_commit(self.source_branch_sha, self.target_branch_sha) + project.merge_base_commit(source_branch_sha, target_branch_sha) end def branch_base_sha @@ -254,8 +241,8 @@ class MergeRequestDiff < ActiveRecord::Base end def keep_around_commits - repository.keep_around(target_branch_sha) - repository.keep_around(source_branch_sha) - repository.keep_around(branch_base_sha) + repository.keep_around(start_commit_sha) + repository.keep_around(head_commit_sha) + repository.keep_around(base_commit_sha) end end -- cgit v1.2.1 From 5d5f2cf3ef7bc238f75d9a73ce94efceec6f690e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 27 Jul 2016 17:55:12 +0300 Subject: Add feature test for merge request version Signed-off-by: Dmitriy Zaporozhets --- .../merge_requests/merge_request_versions_spec.rb | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 spec/features/merge_requests/merge_request_versions_spec.rb diff --git a/spec/features/merge_requests/merge_request_versions_spec.rb b/spec/features/merge_requests/merge_request_versions_spec.rb new file mode 100644 index 00000000000..862ead4e72e --- /dev/null +++ b/spec/features/merge_requests/merge_request_versions_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +feature 'Merge Request versions', js: true, feature: true do + before do + login_as :admin + merge_request = create(:merge_request, importing: true) + merge_request.merge_request_diffs.create(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') + merge_request.merge_request_diffs.create(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e') + project = merge_request.source_project + visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request) + end + + it 'show the latest version of the diff' do + page.within '.mr-version-switch' do + expect(page).to have_content 'Version: latest' + end + + expect(page).to have_content '8 changed files' + end + + describe 'switch between versions' do + before do + page.within '.mr-version-switch' do + find('.btn-link').click + #find('a', text: '6f6d7e7e').click + click_link '6f6d7e7e' + end + end + + it 'should show older version' do + page.within '.mr-version-switch' do + expect(page).to have_content 'Version: 6f6d7e7e' + end + + expect(page).to have_content '5 changed files' + end + end +end -- cgit v1.2.1 From 988836bc807a6e7ba5362fd8bddd330d1f3bf19b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Jul 2016 11:36:30 +0300 Subject: Refactor MergeRequestDiff model Since MergeRequestDiff is not about branches and current state of merge request diff anymore I removed most of branch related method and added validation for head/start/base commit sha. From this point MergeRequestDiff is about saving diff between branches only once at moment of creation. Once created MergeRequestDiff should not be changes. Because of that we should not rely on changes in source/target branches when read from MergeRequestDiff Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request_diff.rb | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 07bceda049c..1e529c84706 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -8,9 +8,6 @@ class MergeRequestDiff < ActiveRecord::Base belongs_to :merge_request - delegate :source_branch_sha, :target_branch_sha, - :target_branch, :source_branch, to: :merge_request, prefix: nil - state_machine :state, initial: :empty do state :collected state :overflow @@ -25,14 +22,23 @@ class MergeRequestDiff < ActiveRecord::Base serialize :st_commits serialize :st_diffs - after_initialize :set_diff_range - after_create :reload_content, unless: :importing? + validates :head_commit_sha, presence: true + validates :start_commit_sha, presence: true + validates :base_commit_sha, presence: true + + after_initialize :ensure_head_commit_sha, if: :persisted? + before_create :set_diff_range, unless: :importing? + after_create :reload_content, unless: :importing? after_save :keep_around_commits, unless: :importing? + def ensure_head_commit_sha + self.head_commit_sha ||= last_commit.sha + end + def set_diff_range - self.start_commit_sha ||= target_branch_sha - self.head_commit_sha ||= source_branch_sha - self.base_commit_sha ||= branch_base_sha + self.start_commit_sha ||= merge_request.target_branch_sha + self.head_commit_sha ||= merge_request.source_branch_sha + self.base_commit_sha ||= find_base_sha end def reload_content @@ -199,14 +205,10 @@ class MergeRequestDiff < ActiveRecord::Base project.repository end - def branch_base_commit - return unless source_branch_sha && target_branch_sha - - project.merge_base_commit(source_branch_sha, target_branch_sha) - end + def find_base_sha + return unless head_commit_sha && start_commit_sha - def branch_base_sha - branch_base_commit.try(:sha) + project.merge_base_commit(head_commit_sha, start_commit_sha).try(:sha) end def utf8_st_diffs -- cgit v1.2.1 From 964742f600f5fc5e07272982c4d3847ccc76ce00 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Jul 2016 13:46:27 +0300 Subject: Ensure merge request is created with valid diff object * Add merge_request_diff validation to merge_request model * Improve initialize of merge_request_diff object * Rename some merge_request_diff methods for clarity Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request.rb | 7 ++++++- app/models/merge_request_diff.rb | 41 +++++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index cc1d0c18437..618829891a0 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -15,7 +15,7 @@ class MergeRequest < ActiveRecord::Base serialize :merge_params, Hash - after_create :create_merge_request_diff, unless: :importing? + before_validation :ensure_merge_request_diff, on: :create, unless: :importing? after_update :update_merge_request_diff delegate :commits, :real_size, to: :merge_request_diff, prefix: nil @@ -95,6 +95,7 @@ class MergeRequest < ActiveRecord::Base validates :merge_user, presence: true, if: :merge_when_build_succeeds? validate :validate_branches, unless: [:allow_broken, :importing?] validate :validate_fork + validates_associated :merge_request_diff, on: :create, unless: [:allow_broken, :importing?] scope :by_branch, ->(branch_name) { where("(source_branch LIKE :branch) OR (target_branch LIKE :branch)", branch: branch_name) } scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) } @@ -286,6 +287,10 @@ class MergeRequest < ActiveRecord::Base end end + def ensure_merge_request_diff + merge_request_diff || merge_request_diffs.build + end + def create_merge_request_diff merge_request_diffs.create end diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 1e529c84706..da1e317027d 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -22,28 +22,31 @@ class MergeRequestDiff < ActiveRecord::Base serialize :st_commits serialize :st_diffs - validates :head_commit_sha, presence: true validates :start_commit_sha, presence: true + validates :head_commit_sha, presence: true validates :base_commit_sha, presence: true - after_initialize :ensure_head_commit_sha, if: :persisted? - before_create :set_diff_range, unless: :importing? - after_create :reload_content, unless: :importing? - after_save :keep_around_commits, unless: :importing? - - def ensure_head_commit_sha - self.head_commit_sha ||= last_commit.sha - end + after_initialize :set_diff_range, unless: :importing? + after_create :save_git_content, unless: :importing? + after_save :keep_around_commits, unless: :importing? def set_diff_range - self.start_commit_sha ||= merge_request.target_branch_sha - self.head_commit_sha ||= merge_request.source_branch_sha - self.base_commit_sha ||= find_base_sha + if persisted? + # Workaround for old MergeRequestDiff object + # that does not have head_commit_sha in the database + self.head_commit_sha ||= last_commit.sha + else + self.start_commit_sha ||= merge_request.target_branch_sha + self.head_commit_sha ||= merge_request.source_branch_sha + self.base_commit_sha ||= find_base_sha + end end - def reload_content - reload_commits - reload_diffs + # Collect information about commits and diff from repository + # and save it to the database as serialized data + def save_git_content + save_commits + save_diffs end def size @@ -130,9 +133,9 @@ class MergeRequestDiff < ActiveRecord::Base array.map { |hash| Commit.new(Gitlab::Git::Commit.new(hash), merge_request.source_project) } end - # Reload all commits related to current merge request from repo + # Load all commits related to current merge request diff from repo # and save it as array of hashes in st_commits db field - def reload_commits + def save_commits new_attributes = {} commits = compare.commits @@ -165,9 +168,9 @@ class MergeRequestDiff < ActiveRecord::Base end end - # Reload diffs between branches related to current merge request from repo + # Load diffs between branches related to current merge request diff from repo # and save it as array of hashes in st_diffs db field - def reload_diffs + def save_diffs new_attributes = {} new_diffs = [] -- cgit v1.2.1 From 5cad2d290219d29aa2be6e991b42b73ac9d87754 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Jul 2016 17:26:54 +0300 Subject: Add improvements to merge request versions * show commits count in the merge request version dropdown * initialize base/start commit sha for old merge request diffs from repo Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request_diff.rb | 4 +++- app/views/projects/merge_requests/show/_versions.html.haml | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index da1e317027d..2bc0b2636f4 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -34,7 +34,9 @@ class MergeRequestDiff < ActiveRecord::Base if persisted? # Workaround for old MergeRequestDiff object # that does not have head_commit_sha in the database - self.head_commit_sha ||= last_commit.sha + self.start_commit_sha ||= merge_request.target_branch_sha + self.head_commit_sha ||= last_commit.sha + self.base_commit_sha ||= find_base_sha else self.start_commit_sha ||= merge_request.target_branch_sha self.head_commit_sha ||= merge_request.source_branch_sha diff --git a/app/views/projects/merge_requests/show/_versions.html.haml b/app/views/projects/merge_requests/show/_versions.html.haml index 8b7d866941c..93a06154022 100644 --- a/app/views/projects/merge_requests/show/_versions.html.haml +++ b/app/views/projects/merge_requests/show/_versions.html.haml @@ -20,8 +20,9 @@ #{merge_request_diff.head_commit.short_id} %br %small + #{number_with_delimiter(merge_request_diff.commits.count)} #{'commit'.pluralize(merge_request_diff.commits.count)}, = time_ago_with_tooltip(merge_request_diff.created_at) .pull-right %span.monospace - git diff #{@merge_request_diff.base_commit.short_id}..#{@merge_request_diff.head_commit.short_id} + #{@merge_request_diff.base_commit.short_id}..#{@merge_request_diff.head_commit.short_id} -- cgit v1.2.1 From 8e031ce3b29b186858ddda2a28a6ea8f98b2f749 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Jul 2016 17:41:35 +0300 Subject: Remove requirement for base_commit_sha to allow creation of merge requests for orphaned branches Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request_diff.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 2bc0b2636f4..da0c15ddeea 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -22,9 +22,8 @@ class MergeRequestDiff < ActiveRecord::Base serialize :st_commits serialize :st_diffs - validates :start_commit_sha, presence: true - validates :head_commit_sha, presence: true - validates :base_commit_sha, presence: true + validates :start_commit_sha, presence: true, unless: :importing? + validates :head_commit_sha, presence: true, unless: :importing? after_initialize :set_diff_range, unless: :importing? after_create :save_git_content, unless: :importing? -- cgit v1.2.1 From b0a023842d4e9fc29db7fa6c7168528d9e4ac09d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Jul 2016 18:41:57 +0300 Subject: Reload merge request association reload when update code Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request.rb | 9 ++------- spec/models/merge_request_spec.rb | 5 ++--- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 618829891a0..08523e45c65 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -246,13 +246,7 @@ class MergeRequest < ActiveRecord::Base end def diff_refs - return unless diff_start_commit || diff_base_commit - - Gitlab::Diff::DiffRefs.new( - base_sha: diff_base_sha, - start_sha: diff_start_sha, - head_sha: diff_head_sha - ) + merge_request_diff.diff_refs end def validate_branches @@ -306,6 +300,7 @@ class MergeRequest < ActiveRecord::Base old_diff_refs = self.diff_refs create_merge_request_diff + merge_request_diffs.reload new_diff_refs = self.diff_refs update_diff_notes_positions( diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 03e4ae574ef..f095e23f7ac 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -291,7 +291,7 @@ describe MergeRequest, models: true do end it "can be removed if the last commit is the head of the source branch" do - allow(subject.source_project).to receive(:commit).and_return(subject.diff_head_commit) + allow(subject).to receive(:source_branch_head).and_return(subject.diff_head_commit) expect(subject.can_remove_source_branch?(user)).to be_truthy end @@ -655,7 +655,7 @@ describe MergeRequest, models: true do let(:commit) { subject.project.commit(sample_commit.id) } it "does not change existing merge request diff" do - expect(subject.merge_request_diff).not_to receive(:reload_content) + expect(subject.merge_request_diff).not_to receive(:save_git_content) subject.reload_diff end @@ -669,7 +669,6 @@ describe MergeRequest, models: true do # Update merge_request_diff so that #diff_refs will return commit.diff_refs allow(subject).to receive(:create_merge_request_diff) do subject.merge_request_diffs.create( - importing: true, base_commit_sha: commit.parent_id, start_commit_sha: commit.parent_id, head_commit_sha: commit.sha -- cgit v1.2.1 From 0e974b52d8f5806c24fdc80ef5b62b261f5be2ba Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Jul 2016 22:36:18 +0300 Subject: Refactor MergeRequestDiff initialize method Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request_diff.rb | 28 ++++++++++------------ .../merge_requests/merge_request_versions_spec.rb | 1 - 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index da0c15ddeea..940a1016302 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -25,22 +25,18 @@ class MergeRequestDiff < ActiveRecord::Base validates :start_commit_sha, presence: true, unless: :importing? validates :head_commit_sha, presence: true, unless: :importing? - after_initialize :set_diff_range, unless: :importing? - after_create :save_git_content, unless: :importing? - after_save :keep_around_commits, unless: :importing? - - def set_diff_range - if persisted? - # Workaround for old MergeRequestDiff object - # that does not have head_commit_sha in the database - self.start_commit_sha ||= merge_request.target_branch_sha - self.head_commit_sha ||= last_commit.sha - self.base_commit_sha ||= find_base_sha - else - self.start_commit_sha ||= merge_request.target_branch_sha - self.head_commit_sha ||= merge_request.source_branch_sha - self.base_commit_sha ||= find_base_sha - end + after_initialize :initialize_commits_sha, unless: :importing? + after_create :save_git_content, unless: :importing? + after_save :keep_around_commits, unless: :importing? + + # Those variables are used for collecting commits and diff from git repository. + # After object is created those sha are stored in the database. + # However some old MergeRequestDiff records don't + # have those variables in the database so we try to initialize it + def initialize_commits_sha + self.start_commit_sha ||= merge_request.target_branch_sha + self.head_commit_sha ||= last_commit.try(:sha) || merge_request.source_branch_sha + self.base_commit_sha ||= find_base_sha end # Collect information about commits and diff from repository diff --git a/spec/features/merge_requests/merge_request_versions_spec.rb b/spec/features/merge_requests/merge_request_versions_spec.rb index 862ead4e72e..577c910f11b 100644 --- a/spec/features/merge_requests/merge_request_versions_spec.rb +++ b/spec/features/merge_requests/merge_request_versions_spec.rb @@ -22,7 +22,6 @@ feature 'Merge Request versions', js: true, feature: true do before do page.within '.mr-version-switch' do find('.btn-link').click - #find('a', text: '6f6d7e7e').click click_link '6f6d7e7e' end end -- cgit v1.2.1 From 3c1dca0301366c63d1800aa11e73a82e68e120d0 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 28 Jul 2016 23:40:13 +0300 Subject: Add more tests to merge_request_diff and improve initialize Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request.rb | 4 +++- app/models/merge_request_diff.rb | 4 +--- spec/models/merge_request_diff_spec.rb | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 08523e45c65..6d36a5ba288 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -246,7 +246,9 @@ class MergeRequest < ActiveRecord::Base end def diff_refs - merge_request_diff.diff_refs + if merge_request_diff + merge_request_diff.diff_refs + end end def validate_branches diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 940a1016302..b668b62cdac 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -35,7 +35,7 @@ class MergeRequestDiff < ActiveRecord::Base # have those variables in the database so we try to initialize it def initialize_commits_sha self.start_commit_sha ||= merge_request.target_branch_sha - self.head_commit_sha ||= last_commit.try(:sha) || merge_request.source_branch_sha + self.head_commit_sha ||= persisted? ? last_commit.sha : merge_request.source_branch_sha self.base_commit_sha ||= find_base_sha end @@ -191,9 +191,7 @@ class MergeRequestDiff < ActiveRecord::Base end new_attributes[:st_diffs] = new_diffs - update_columns_serialized(new_attributes) - keep_around_commits end diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index 9a637c94fbe..16bba82181b 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -1,6 +1,23 @@ require 'spec_helper' describe MergeRequestDiff, models: true do + describe 'initialize new object' do + subject { build(:merge_request).merge_request_diffs.build } + + it { expect(subject).to be_valid } + it { expect(subject.head_commit_sha).to eq('5937ac0a7beb003549fc5fd26fc247adbce4a52e') } + it { expect(subject.base_commit_sha).to eq('ae73cb07c9eeaf35924a10f713b364d32b2dd34f') } + it { expect(subject.start_commit_sha).to eq('0b4bc9a49b562e85de7cc9e834518ea6828729b9') } + end + + describe 'create new record' do + subject { create(:merge_request) } + + it { expect(subject).to be_valid } + it { expect(subject.commits.count).to eq(5) } + it { expect(subject.diffs.count).to eq(8) } + end + describe '#diffs' do let(:mr) { create(:merge_request, :with_diffs) } let(:mr_diff) { mr.merge_request_diff } -- cgit v1.2.1 From f8aeb8cdac98108bca5d1be2a382c32df6a500e5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 1 Aug 2016 18:41:21 +0300 Subject: Change merge request diff creation from callback to part of the service Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/merge_requests_controller.rb | 1 - app/models/merge_request.rb | 5 ----- app/services/merge_requests/create_service.rb | 1 + spec/factories/merge_requests.rb | 6 ++++++ spec/models/merge_request_diff_spec.rb | 3 ++- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index a886af713d5..33188e88385 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -88,7 +88,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController @merge_request.merge_request_diff end - respond_to do |format| format.html { define_discussion_vars } format.json { render json: { html: view_to_html_string("projects/merge_requests/show/_diffs") } } diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 6d36a5ba288..85048f928dc 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -15,7 +15,6 @@ class MergeRequest < ActiveRecord::Base serialize :merge_params, Hash - before_validation :ensure_merge_request_diff, on: :create, unless: :importing? after_update :update_merge_request_diff delegate :commits, :real_size, to: :merge_request_diff, prefix: nil @@ -283,10 +282,6 @@ class MergeRequest < ActiveRecord::Base end end - def ensure_merge_request_diff - merge_request_diff || merge_request_diffs.build - end - def create_merge_request_diff merge_request_diffs.create end diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb index 96a25330af1..553d7443c86 100644 --- a/app/services/merge_requests/create_service.rb +++ b/app/services/merge_requests/create_service.rb @@ -16,6 +16,7 @@ module MergeRequests merge_request.target_project ||= source_project merge_request.author = current_user merge_request.merge_params['force_remove_source_branch'] = force_remove_source_branch + merge_request.merge_request_diffs.build if merge_request.save merge_request.update_attributes(label_ids: label_params) diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index c6a08d78b78..05851c49497 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -68,5 +68,11 @@ FactoryGirl.define do factory :closed_merge_request, traits: [:closed] factory :reopened_merge_request, traits: [:reopened] factory :merge_request_with_diffs, traits: [:with_diffs] + + after :create do |merge_request| + unless merge_request.merge_request_diff + merge_request.create_merge_request_diff + end + end end end diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index 16bba82181b..0a55515e8c6 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -11,9 +11,10 @@ describe MergeRequestDiff, models: true do end describe 'create new record' do - subject { create(:merge_request) } + subject { create(:merge_request).merge_request_diff } it { expect(subject).to be_valid } + it { expect(subject).to be_persisted } it { expect(subject.commits.count).to eq(5) } it { expect(subject.diffs.count).to eq(8) } end -- cgit v1.2.1 From 6515ec09bbfa25027d1b8a1240e09bc1c6edbcfb Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 2 Aug 2016 15:38:03 +0300 Subject: Chnage the way how merge request diff is initialized and saved Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request.rb | 15 +++----- app/models/merge_request_diff.rb | 54 +++++++++++++++------------ app/services/merge_requests/create_service.rb | 1 - features/project/merge_requests.feature | 2 +- features/steps/project/merge_requests.rb | 6 +-- spec/factories/merge_requests.rb | 6 --- spec/models/merge_request_diff_spec.rb | 12 ++---- 7 files changed, 44 insertions(+), 52 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 85048f928dc..6f2216ab5db 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -11,11 +11,13 @@ class MergeRequest < ActiveRecord::Base belongs_to :merge_user, class_name: "User" has_many :merge_request_diffs, dependent: :destroy + has_one :merge_request_diff has_many :events, as: :target, dependent: :destroy serialize :merge_params, Hash - after_update :update_merge_request_diff + after_create :ensure_merge_request_diff, unless: :importing? + after_update :reload_diff_if_branch_changed delegate :commits, :real_size, to: :merge_request_diff, prefix: nil @@ -94,7 +96,6 @@ class MergeRequest < ActiveRecord::Base validates :merge_user, presence: true, if: :merge_when_build_succeeds? validate :validate_branches, unless: [:allow_broken, :importing?] validate :validate_fork - validates_associated :merge_request_diff, on: :create, unless: [:allow_broken, :importing?] scope :by_branch, ->(branch_name) { where("(source_branch LIKE :branch) OR (target_branch LIKE :branch)", branch: branch_name) } scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) } @@ -282,11 +283,11 @@ class MergeRequest < ActiveRecord::Base end end - def create_merge_request_diff - merge_request_diffs.create + def ensure_merge_request_diff + merge_request_diff || create_merge_request_diff end - def update_merge_request_diff + def reload_diff_if_branch_changed if source_branch_changed? || target_branch_changed? reload_diff end @@ -689,8 +690,4 @@ class MergeRequest < ActiveRecord::Base def keep_around_commit project.repository.keep_around(self.merge_commit_sha) end - - def merge_request_diff - merge_request_diffs.first - end end diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index b668b62cdac..074d8f5d40a 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -22,28 +22,28 @@ class MergeRequestDiff < ActiveRecord::Base serialize :st_commits serialize :st_diffs - validates :start_commit_sha, presence: true, unless: :importing? - validates :head_commit_sha, presence: true, unless: :importing? + # For compatibility with old MergeRequestDiff which + # does not store those variables in database + after_initialize :ensure_commits_sha, if: :persisted? - after_initialize :initialize_commits_sha, unless: :importing? + # All diff information is collected from repository after object is created. + # It allows you to override variables like head_commit_sha before getting diff. after_create :save_git_content, unless: :importing? - after_save :keep_around_commits, unless: :importing? - - # Those variables are used for collecting commits and diff from git repository. - # After object is created those sha are stored in the database. - # However some old MergeRequestDiff records don't - # have those variables in the database so we try to initialize it - def initialize_commits_sha - self.start_commit_sha ||= merge_request.target_branch_sha - self.head_commit_sha ||= persisted? ? last_commit.sha : merge_request.source_branch_sha - self.base_commit_sha ||= find_base_sha - end # Collect information about commits and diff from repository # and save it to the database as serialized data def save_git_content + ensure_commits_sha save_commits + reload_commits save_diffs + keep_around_commits + end + + def ensure_commits_sha + self.start_commit_sha ||= merge_request.target_branch_sha + self.head_commit_sha ||= last_commit.try(:sha) || merge_request.source_branch_sha + self.base_commit_sha ||= find_base_sha end def size @@ -52,14 +52,15 @@ class MergeRequestDiff < ActiveRecord::Base def diffs(options={}) if options[:ignore_whitespace_change] - @diffs_no_whitespace ||= begin - compare = Gitlab::Git::Compare.new( - repository.raw_repository, - start_commit_sha, - head_commit_sha - ) - compare.diffs(options) - end + @diffs_no_whitespace ||= + begin + compare = Gitlab::Git::Compare.new( + repository.raw_repository, + start_commit_sha, + head_commit_sha + ) + compare.diffs(options) + end else @diffs ||= {} @diffs[options] ||= load_diffs(st_diffs, options) @@ -70,6 +71,11 @@ class MergeRequestDiff < ActiveRecord::Base @commits ||= load_commits(st_commits || []) end + def reload_commits + @commits = nil + commits + end + def last_commit commits.first end @@ -192,7 +198,6 @@ class MergeRequestDiff < ActiveRecord::Base new_attributes[:st_diffs] = new_diffs update_columns_serialized(new_attributes) - keep_around_commits end def project @@ -207,6 +212,9 @@ class MergeRequestDiff < ActiveRecord::Base return unless head_commit_sha && start_commit_sha project.merge_base_commit(head_commit_sha, start_commit_sha).try(:sha) + rescue Rugged::OdbError + # In case head or start commit does not exist in the repository any more + nil end def utf8_st_diffs diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb index 553d7443c86..96a25330af1 100644 --- a/app/services/merge_requests/create_service.rb +++ b/app/services/merge_requests/create_service.rb @@ -16,7 +16,6 @@ module MergeRequests merge_request.target_project ||= source_project merge_request.author = current_user merge_request.merge_params['force_remove_source_branch'] = force_remove_source_branch - merge_request.merge_request_diffs.build if merge_request.save merge_request.update_attributes(label_ids: label_params) diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature index 21768c15c17..7673b4284ef 100644 --- a/features/project/merge_requests.feature +++ b/features/project/merge_requests.feature @@ -24,7 +24,7 @@ Feature: Project Merge Requests Scenario: I should see target branch when it is different from default Given project "Shop" have "Bug NS-06" open merge request When I visit project "Shop" merge requests page - Then I should see "other_branch" branch + Then I should see "feature_conflict" branch Scenario: I should not see the numbers of diverged commits if the branch is rebased on the target Given project "Shop" have "Bug NS-07" open merge request with rebased branch diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb index da848afd48e..74e162aadee 100644 --- a/features/steps/project/merge_requests.rb +++ b/features/steps/project/merge_requests.rb @@ -56,8 +56,8 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps expect(find('.merge-request-info')).not_to have_content "master" end - step 'I should see "other_branch" branch' do - expect(page).to have_content "other_branch" + step 'I should see "feature_conflict" branch' do + expect(page).to have_content "feature_conflict" end step 'I should see "Bug NS-04" in merge requests' do @@ -122,7 +122,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps source_project: project, target_project: project, source_branch: 'fix', - target_branch: 'other_branch', + target_branch: 'feature_conflict', author: project.users.first, description: "# Description header" ) diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index 05851c49497..c6a08d78b78 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -68,11 +68,5 @@ FactoryGirl.define do factory :closed_merge_request, traits: [:closed] factory :reopened_merge_request, traits: [:reopened] factory :merge_request_with_diffs, traits: [:with_diffs] - - after :create do |merge_request| - unless merge_request.merge_request_diff - merge_request.create_merge_request_diff - end - end end end diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index 0a55515e8c6..f2954a39b08 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -1,15 +1,6 @@ require 'spec_helper' describe MergeRequestDiff, models: true do - describe 'initialize new object' do - subject { build(:merge_request).merge_request_diffs.build } - - it { expect(subject).to be_valid } - it { expect(subject.head_commit_sha).to eq('5937ac0a7beb003549fc5fd26fc247adbce4a52e') } - it { expect(subject.base_commit_sha).to eq('ae73cb07c9eeaf35924a10f713b364d32b2dd34f') } - it { expect(subject.start_commit_sha).to eq('0b4bc9a49b562e85de7cc9e834518ea6828729b9') } - end - describe 'create new record' do subject { create(:merge_request).merge_request_diff } @@ -17,6 +8,9 @@ describe MergeRequestDiff, models: true do it { expect(subject).to be_persisted } it { expect(subject.commits.count).to eq(5) } it { expect(subject.diffs.count).to eq(8) } + it { expect(subject.head_commit_sha).to eq('5937ac0a7beb003549fc5fd26fc247adbce4a52e') } + it { expect(subject.base_commit_sha).to eq('ae73cb07c9eeaf35924a10f713b364d32b2dd34f') } + it { expect(subject.start_commit_sha).to eq('0b4bc9a49b562e85de7cc9e834518ea6828729b9') } end describe '#diffs' do -- cgit v1.2.1 From 7cb8ceb5b9b7da6f9bd5f80a50eeca6727ac5902 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 2 Aug 2016 16:28:37 +0300 Subject: Fix creation and reload of the merge request diff Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request.rb | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 6f2216ab5db..8b0b413343c 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -11,7 +11,9 @@ class MergeRequest < ActiveRecord::Base belongs_to :merge_user, class_name: "User" has_many :merge_request_diffs, dependent: :destroy - has_one :merge_request_diff + has_one :merge_request_diff, + -> { order('merge_request_diffs.id DESC') } + has_many :events, as: :target, dependent: :destroy serialize :merge_params, Hash @@ -287,6 +289,15 @@ class MergeRequest < ActiveRecord::Base merge_request_diff || create_merge_request_diff end + def create_merge_request_diff + merge_request_diffs.create + reload_merge_request_diff + end + + def reload_merge_request_diff + merge_request_diff(true) + end + def reload_diff_if_branch_changed if source_branch_changed? || target_branch_changed? reload_diff @@ -298,7 +309,6 @@ class MergeRequest < ActiveRecord::Base old_diff_refs = self.diff_refs create_merge_request_diff - merge_request_diffs.reload new_diff_refs = self.diff_refs update_diff_notes_positions( -- cgit v1.2.1 From fc8d2fbc946d144d2a9d075d67a9f1fe1035da0e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 2 Aug 2016 17:52:20 +0300 Subject: Build diff_refs for merge request if merge request diff does not exist Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 8b0b413343c..56d5157298f 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -250,6 +250,12 @@ class MergeRequest < ActiveRecord::Base def diff_refs if merge_request_diff merge_request_diff.diff_refs + elsif diff_start_commit || diff_base_commit + Gitlab::Diff::DiffRefs.new( + base_sha: diff_base_sha, + start_sha: diff_start_sha, + head_sha: diff_head_sha + ) end end -- cgit v1.2.1 From 159998a460be6ca1ea5efd135a5c3aefeab2d9b6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 2 Aug 2016 18:07:50 +0300 Subject: Fix merge request spec for update diff note Signed-off-by: Dmitriy Zaporozhets --- spec/models/merge_request_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index f095e23f7ac..eb382f9ef84 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -673,6 +673,8 @@ describe MergeRequest, models: true do start_commit_sha: commit.parent_id, head_commit_sha: commit.sha ) + + subject.merge_request_diff(true) end expect(Notes::DiffPositionUpdateService).to receive(:new).with( -- cgit v1.2.1 From 9a5f40878c6d71e7fd4858f7fa1d948af6c371ae Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 3 Aug 2016 11:32:29 +0300 Subject: Add API to list merge request diff versions Signed-off-by: Dmitriy Zaporozhets --- doc/api/merge_requests.md | 90 +++++++++++++++++++++++++++ lib/api/api.rb | 1 + lib/api/entities.rb | 11 ++++ lib/api/merge_request_diffs.rb | 25 ++++++++ spec/requests/api/merge_request_diffs_spec.rb | 32 ++++++++++ 5 files changed, 159 insertions(+) create mode 100644 lib/api/merge_request_diffs.rb create mode 100644 spec/requests/api/merge_request_diffs_spec.rb diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index e00882e6d5d..cf262dc4a80 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -894,3 +894,93 @@ Example response: "created_at": "2016-07-01T11:14:15.530Z" } ``` + +## Get MR diff versions + +Get a list of merge request diff versions. + +``` +GET /projects/:id/merge_requests/:merge_request_id/versions +``` + +Parameters: + +- `id` (required) - The ID of a project +- `merge_request_id` (required) - The ID of MR + + +```json +[{ + "id": 110, + "head_commit_sha": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30", + "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd", + "start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd", + "created_at": "2016-07-26T14:44:48.926Z", + "merge_request_id": 105, + "state": "collected", + "real_size": "1", + "commits": [{ + "id": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30", + "short_id": "33e2ee85", + "title": "Change year to 2018", + "author_name": "Administrator", + "author_email": "admin@example.com", + "created_at": "2016-07-26T17:44:29.000+03:00", + "message": "Change year to 2018" + }, { + "id": "aa24655de48b36335556ac8a3cd8bb521f977cbd", + "short_id": "aa24655d", + "title": "Update LICENSE", + "author_name": "Administrator", + "author_email": "admin@example.com", + "created_at": "2016-07-25T17:21:53.000+03:00", + "message": "Update LICENSE" + }, { + "id": "3eed087b29835c48015768f839d76e5ea8f07a24", + "short_id": "3eed087b", + "title": "Add license", + "author_name": "Administrator", + "author_email": "admin@example.com", + "created_at": "2016-07-25T17:21:20.000+03:00", + "message": "Add license" + }], + "diffs": [{ + "old_path": "LICENSE", + "new_path": "LICENSE", + "a_mode": "0", + "b_mode": "100644", + "diff": "--- /dev/null\n+++ b/LICENSE\n@@ -0,0 +1,21 @@\n+The MIT License (MIT)\n+\n+Copyright (c) 2018 Administrator\n+\n+Permission is hereby granted, free of charge, to any person obtaining a copy\n+of this software and associated documentation files (the \"Software\"), to deal\n+in the Software without restriction, including without limitation the rights\n+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+copies of the Software, and to permit persons to whom the Software is\n+furnished to do so, subject to the following conditions:\n+\n+The above copyright notice and this permission notice shall be included in all\n+copies or substantial portions of the Software.\n+\n+THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n+SOFTWARE.\n", + "new_file": true, + "renamed_file": false, + "deleted_file": false + }] +}, { + "id": 108, + "head_commit_sha": "3eed087b29835c48015768f839d76e5ea8f07a24", + "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd", + "start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd", + "created_at": "2016-07-25T14:21:33.028Z", + "merge_request_id": 105, + "state": "collected", + "real_size": "1", + "commits": [{ + "id": "3eed087b29835c48015768f839d76e5ea8f07a24", + "short_id": "3eed087b", + "title": "Add license", + "author_name": "Administrator", + "author_email": "admin@example.com", + "created_at": "2016-07-25T17:21:20.000+03:00", + "message": "Add license" + }], + "diffs": [{ + "old_path": "LICENSE", + "new_path": "LICENSE", + "a_mode": "0", + "b_mode": "100644", + "diff": "--- /dev/null\n+++ b/LICENSE\n@@ -0,0 +1,21 @@\n+The MIT License (MIT)\n+\n+Copyright (c) 2016 Administrator\n+\n+Permission is hereby granted, free of charge, to any person obtaining a copy\n+of this software and associated documentation files (the \"Software\"), to deal\n+in the Software without restriction, including without limitation the rights\n+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+copies of the Software, and to permit persons to whom the Software is\n+furnished to do so, subject to the following conditions:\n+\n+The above copyright notice and this permission notice shall be included in all\n+copies or substantial portions of the Software.\n+\n+THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n+SOFTWARE.\n", + "new_file": true, + "renamed_file": false, + "deleted_file": false + }] +}] +``` diff --git a/lib/api/api.rb b/lib/api/api.rb index bd16806892b..9d8f297191f 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -67,5 +67,6 @@ module API mount ::API::Triggers mount ::API::Users mount ::API::Variables + mount ::API::MergeRequestDiffs end end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 3e21b7a0b8a..af069063f0c 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -228,6 +228,17 @@ module API end end + class MergeRequestDiff < Grape::Entity + expose :id, :head_commit_sha, :base_commit_sha, :start_commit_sha, + :created_at, :merge_request_id, :state, :real_size + + expose :commits, using: Entities::RepoCommit + + expose :diffs, using: Entities::RepoDiff do |compare, _| + compare.diffs(all_diffs: true).to_a + end + end + class SSHKey < Grape::Entity expose :id, :title, :key, :created_at end diff --git a/lib/api/merge_request_diffs.rb b/lib/api/merge_request_diffs.rb new file mode 100644 index 00000000000..4bd149d1603 --- /dev/null +++ b/lib/api/merge_request_diffs.rb @@ -0,0 +1,25 @@ +module API + # MergeRequestDiff API + class MergeRequestDiffs < Grape::API + before { authenticate! } + + resource :projects do + # List merge requests diff versions + # + # Parameters: + # id (required) - The ID of a project + # merge_request_id (required) - The ID of MR + # + # Example: + # GET /projects/:id/merge_requests/:merge_request_id/versions + # + get ":id/merge_requests/:merge_request_id/versions" do + merge_request = user_project.merge_requests. + find(params[:merge_request_id]) + + authorize! :read_merge_request, merge_request + present merge_request.merge_request_diffs, with: Entities::MergeRequestDiff + end + end + end +end diff --git a/spec/requests/api/merge_request_diffs_spec.rb b/spec/requests/api/merge_request_diffs_spec.rb new file mode 100644 index 00000000000..db076b4b9a5 --- /dev/null +++ b/spec/requests/api/merge_request_diffs_spec.rb @@ -0,0 +1,32 @@ +require "spec_helper" + +describe API::API, 'MergeRequestDiffs', api: true do + include ApiHelpers + + let!(:user) { create(:user) } + let!(:merge_request) { create(:merge_request, importing: true) } + let!(:project) { merge_request.target_project } + + before do + merge_request.merge_request_diffs.create(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') + merge_request.merge_request_diffs.create(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e') + project.team << [user, :master] + end + + describe 'GET /projects/:id/merge_requests/:merge_request_id/versions' do + context 'valid merge request' do + before { get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions", user) } + let(:merge_request_diff) { merge_request.merge_request_diffs.first } + + it { expect(response.status).to eq 200 } + it { expect(json_response.size).to eq(merge_request.merge_request_diffs.size) } + it { expect(json_response.first['id']).to eq(merge_request_diff.id) } + it { expect(json_response.first['head_commit_sha']).to eq(merge_request_diff.head_commit_sha) } + end + + it 'returns a 404 when merge_request_id not found' do + get api("/projects/#{project.id}/merge_requests/999/versions", user) + expect(response).to have_http_status(404) + end + end +end -- cgit v1.2.1 From 69096ad9da77ce51d544a8f23f4e8873df273f4e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 3 Aug 2016 11:58:09 +0300 Subject: Update merge request versions API to match styleguide Signed-off-by: Dmitriy Zaporozhets --- doc/api/merge_requests.md | 11 ++++++++--- lib/api/merge_request_diffs.rb | 19 ++++++++++--------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index cf262dc4a80..68b5172ed0d 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -903,11 +903,16 @@ Get a list of merge request diff versions. GET /projects/:id/merge_requests/:merge_request_id/versions ``` -Parameters: +| Attribute | Type | Required | Description | +| --------- | ------- | -------- | --------------------- | +| `id` | integer | yes | The ID of the project | +| `merge_request_id` | integer | yes | The ID of the merge request | -- `id` (required) - The ID of a project -- `merge_request_id` (required) - The ID of MR +```bash +curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/1/merge_requests/1/versions +``` +Example response: ```json [{ diff --git a/lib/api/merge_request_diffs.rb b/lib/api/merge_request_diffs.rb index 4bd149d1603..be954ff96ac 100644 --- a/lib/api/merge_request_diffs.rb +++ b/lib/api/merge_request_diffs.rb @@ -4,15 +4,16 @@ module API before { authenticate! } resource :projects do - # List merge requests diff versions - # - # Parameters: - # id (required) - The ID of a project - # merge_request_id (required) - The ID of MR - # - # Example: - # GET /projects/:id/merge_requests/:merge_request_id/versions - # + desc 'Get a list of merge request diff versions' do + detail 'This feature was introduced in GitLab 8.12.' + success Entities::MergeRequestDiff + end + + params do + requires :id, type: Integer, desc: 'The ID of a project' + requests :merge_request_id, type: Integer, desc: 'The ID of a merge request' + end + get ":id/merge_requests/:merge_request_id/versions" do merge_request = user_project.merge_requests. find(params[:merge_request_id]) -- cgit v1.2.1 From 08f5f897889dc7e7f00a65f56e988449350e60f2 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 3 Aug 2016 12:35:20 +0300 Subject: Fix project id param for merge request version API Signed-off-by: Dmitriy Zaporozhets --- doc/api/merge_requests.md | 2 +- lib/api/merge_request_diffs.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 68b5172ed0d..0c06cfcd876 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -905,7 +905,7 @@ GET /projects/:id/merge_requests/:merge_request_id/versions | Attribute | Type | Required | Description | | --------- | ------- | -------- | --------------------- | -| `id` | integer | yes | The ID of the project | +| `id` | String | yes | The ID of the project | | `merge_request_id` | integer | yes | The ID of the merge request | ```bash diff --git a/lib/api/merge_request_diffs.rb b/lib/api/merge_request_diffs.rb index be954ff96ac..a2f92f81107 100644 --- a/lib/api/merge_request_diffs.rb +++ b/lib/api/merge_request_diffs.rb @@ -10,8 +10,8 @@ module API end params do - requires :id, type: Integer, desc: 'The ID of a project' - requests :merge_request_id, type: Integer, desc: 'The ID of a merge request' + requires :id, type: String, desc: 'The ID of a project' + requires :merge_request_id, type: Integer, desc: 'The ID of a merge request' end get ":id/merge_requests/:merge_request_id/versions" do -- cgit v1.2.1 From d99d5198c2df6f931664b8096bcbfc28e8221145 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 8 Aug 2016 23:00:11 +0300 Subject: Add MergeRequest#branch_merge_base_commit method Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request.rb | 35 +++++++++++++++++++++++++++-------- spec/models/merge_request_spec.rb | 17 +++++++++++++++++ 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 56d5157298f..7e3444882ea 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -177,8 +177,8 @@ class MergeRequest < ActiveRecord::Base def diff_base_commit if persisted? merge_request_diff.base_commit - elsif diff_start_commit && diff_head_commit - self.target_project.merge_base_commit(diff_start_sha, diff_head_sha) + else + branch_merge_base_commit end end @@ -239,6 +239,15 @@ class MergeRequest < ActiveRecord::Base target_project.repository.commit(target_branch) if target_branch_ref end + def branch_merge_base_commit + start_sha = target_branch_sha + head_sha = source_branch_sha + + if start_sha && head_sha + target_project.merge_base_commit(start_sha, head_sha) + end + end + def target_branch_sha @target_branch_sha || target_branch_head.try(:sha) end @@ -247,15 +256,25 @@ class MergeRequest < ActiveRecord::Base @source_branch_sha || source_branch_head.try(:sha) end + def branch_merge_base_sha + branch_merge_base_commit.try(:sha) + end + def diff_refs if merge_request_diff merge_request_diff.diff_refs - elsif diff_start_commit || diff_base_commit - Gitlab::Diff::DiffRefs.new( - base_sha: diff_base_sha, - start_sha: diff_start_sha, - head_sha: diff_head_sha - ) + else + start_sha = target_branch_sha + head_sha = source_branch_sha + base_sha = branch_merge_base_sha + + if start_sha || base_sha + Gitlab::Diff::DiffRefs.new( + base_sha: base_sha, + start_sha: start_sha, + head_sha: head_sha + ) + end end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index eb382f9ef84..d32bec53a28 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -691,4 +691,21 @@ describe MergeRequest, models: true do subject.reload_diff end end + + describe '#branch_merge_base_commit' do + context 'source and target branch exist' do + it { expect(subject.branch_merge_base_commit.sha).to eq('ae73cb07c9eeaf35924a10f713b364d32b2dd34f') } + it { expect(subject.branch_merge_base_commit).to be_a(Commit) } + end + + context 'when the target branch does not exist' do + before do + subject.project.repository.raw_repository.delete_branch(subject.target_branch) + end + + it 'returns nil' do + expect(subject.branch_merge_base_commit).to be_nil + end + end + end end -- cgit v1.2.1 From 28e33df46bdffac3dc9388b56035db38dcdab5e3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 9 Aug 2016 15:16:50 +0300 Subject: Load merge request versions without loading whole diff from database Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request_diff.rb | 4 ++++ app/views/projects/merge_requests/show/_versions.html.haml | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 074d8f5d40a..24e09c4d57c 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -30,6 +30,10 @@ class MergeRequestDiff < ActiveRecord::Base # It allows you to override variables like head_commit_sha before getting diff. after_create :save_git_content, unless: :importing? + def self.select_without_diff + select(column_names - ['st_diffs']) + end + # Collect information about commits and diff from repository # and save it to the database as serialized data def save_git_content diff --git a/app/views/projects/merge_requests/show/_versions.html.haml b/app/views/projects/merge_requests/show/_versions.html.haml index 93a06154022..84c2b83e330 100644 --- a/app/views/projects/merge_requests/show/_versions.html.haml +++ b/app/views/projects/merge_requests/show/_versions.html.haml @@ -1,7 +1,7 @@ -- diffs_count = @merge_request.merge_request_diffs.count +- merge_request_diffs = @merge_request.merge_request_diffs.select_without_diff +- latest_diff = merge_request_diffs.first -- if diffs_count > 1 - - latest_diff = @merge_request.merge_request_diff +- if merge_request_diffs.size > 1 .mr-version-switch Version:  %span.dropdown.inline @@ -13,7 +13,7 @@ #{@merge_request_diff.head_commit.short_id} %span.caret %ul.dropdown-menu.dropdown-menu-selectable - - @merge_request.merge_request_diffs.each do |merge_request_diff| + - merge_request_diffs.each do |merge_request_diff| %li = link_to diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request, diff_id: merge_request_diff.id), class: ('is-active' if merge_request_diff == @merge_request_diff) do %strong.monospace -- cgit v1.2.1 From 445edcfacc583ba613a4b865b104d7d7e1f7ec0f Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 12 Aug 2016 13:08:16 +0300 Subject: Remove unnecessary   in merge request versions dropdown Signed-off-by: Dmitriy Zaporozhets --- app/views/projects/merge_requests/show/_versions.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/merge_requests/show/_versions.html.haml b/app/views/projects/merge_requests/show/_versions.html.haml index 84c2b83e330..15d94b16ced 100644 --- a/app/views/projects/merge_requests/show/_versions.html.haml +++ b/app/views/projects/merge_requests/show/_versions.html.haml @@ -3,7 +3,7 @@ - if merge_request_diffs.size > 1 .mr-version-switch - Version:  + Version: %span.dropdown.inline %a.btn-link.dropdown-toggle{ data: {toggle: :dropdown} } %strong.monospace< -- cgit v1.2.1 From ac072132b8f0e36badf297208a5964109dbed126 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 12 Aug 2016 14:44:49 +0300 Subject: Add single merge request diff API endpoint Signed-off-by: Dmitriy Zaporozhets --- doc/api/merge_requests.md | 72 ++++++++++++++++----------- lib/api/entities.rb | 2 + lib/api/merge_request_diffs.rb | 19 +++++++ spec/requests/api/merge_request_diffs_spec.rb | 17 +++++++ 4 files changed, 81 insertions(+), 29 deletions(-) diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 0c06cfcd876..130488bf7c1 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -916,6 +916,48 @@ Example response: ```json [{ + "id": 110, + "head_commit_sha": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30", + "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd", + "start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd", + "created_at": "2016-07-26T14:44:48.926Z", + "merge_request_id": 105, + "state": "collected", + "real_size": "1" +}, { + "id": 108, + "head_commit_sha": "3eed087b29835c48015768f839d76e5ea8f07a24", + "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd", + "start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd", + "created_at": "2016-07-25T14:21:33.028Z", + "merge_request_id": 105, + "state": "collected", + "real_size": "1" +}] +``` + +## Get a single MR diff version + +Get a single merge request diff version. + +``` +GET /projects/:id/merge_requests/:merge_request_id/versions/:version_id +``` + +| Attribute | Type | Required | Description | +| --------- | ------- | -------- | --------------------- | +| `id` | String | yes | The ID of the project | +| `merge_request_id` | integer | yes | The ID of the merge request | +| `version_id` | integer | yes | The ID of the merge request diff version | + +```bash +curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/1/merge_requests/1/versions/1 +``` + +Example response: + +```json +{ "id": 110, "head_commit_sha": "33e2ee8579fda5bc36accc9c6fbd0b4fefda9e30", "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd", @@ -959,33 +1001,5 @@ Example response: "renamed_file": false, "deleted_file": false }] -}, { - "id": 108, - "head_commit_sha": "3eed087b29835c48015768f839d76e5ea8f07a24", - "base_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd", - "start_commit_sha": "eeb57dffe83deb686a60a71c16c32f71046868fd", - "created_at": "2016-07-25T14:21:33.028Z", - "merge_request_id": 105, - "state": "collected", - "real_size": "1", - "commits": [{ - "id": "3eed087b29835c48015768f839d76e5ea8f07a24", - "short_id": "3eed087b", - "title": "Add license", - "author_name": "Administrator", - "author_email": "admin@example.com", - "created_at": "2016-07-25T17:21:20.000+03:00", - "message": "Add license" - }], - "diffs": [{ - "old_path": "LICENSE", - "new_path": "LICENSE", - "a_mode": "0", - "b_mode": "100644", - "diff": "--- /dev/null\n+++ b/LICENSE\n@@ -0,0 +1,21 @@\n+The MIT License (MIT)\n+\n+Copyright (c) 2016 Administrator\n+\n+Permission is hereby granted, free of charge, to any person obtaining a copy\n+of this software and associated documentation files (the \"Software\"), to deal\n+in the Software without restriction, including without limitation the rights\n+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+copies of the Software, and to permit persons to whom the Software is\n+furnished to do so, subject to the following conditions:\n+\n+The above copyright notice and this permission notice shall be included in all\n+copies or substantial portions of the Software.\n+\n+THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n+SOFTWARE.\n", - "new_file": true, - "renamed_file": false, - "deleted_file": false - }] -}] +} ``` diff --git a/lib/api/entities.rb b/lib/api/entities.rb index af069063f0c..f582b2ce250 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -231,7 +231,9 @@ module API class MergeRequestDiff < Grape::Entity expose :id, :head_commit_sha, :base_commit_sha, :start_commit_sha, :created_at, :merge_request_id, :state, :real_size + end + class MergeRequestDiffFull < MergeRequestDiff expose :commits, using: Entities::RepoCommit expose :diffs, using: Entities::RepoDiff do |compare, _| diff --git a/lib/api/merge_request_diffs.rb b/lib/api/merge_request_diffs.rb index a2f92f81107..07435d78468 100644 --- a/lib/api/merge_request_diffs.rb +++ b/lib/api/merge_request_diffs.rb @@ -21,6 +21,25 @@ module API authorize! :read_merge_request, merge_request present merge_request.merge_request_diffs, with: Entities::MergeRequestDiff end + + desc 'Get a single merge request diff version' do + detail 'This feature was introduced in GitLab 8.12.' + success Entities::MergeRequestDiffFull + end + + params do + requires :id, type: String, desc: 'The ID of a project' + requires :merge_request_id, type: Integer, desc: 'The ID of a merge request' + requires :version_id, type: Integer, desc: 'The ID of a merge request diff version' + end + + get ":id/merge_requests/:merge_request_id/versions/:version_id" do + merge_request = user_project.merge_requests. + find(params[:merge_request_id]) + + authorize! :read_merge_request, merge_request + present merge_request.merge_request_diffs.find(params[:version_id]), with: Entities::MergeRequestDiffFull + end end end end diff --git a/spec/requests/api/merge_request_diffs_spec.rb b/spec/requests/api/merge_request_diffs_spec.rb index db076b4b9a5..8f1e5ac9891 100644 --- a/spec/requests/api/merge_request_diffs_spec.rb +++ b/spec/requests/api/merge_request_diffs_spec.rb @@ -29,4 +29,21 @@ describe API::API, 'MergeRequestDiffs', api: true do expect(response).to have_http_status(404) end end + + describe 'GET /projects/:id/merge_requests/:merge_request_id/versions/:version_id' do + context 'valid merge request' do + before { get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions/#{merge_request_diff.id}", user) } + let(:merge_request_diff) { merge_request.merge_request_diffs.first } + + it { expect(response.status).to eq 200 } + it { expect(json_response['id']).to eq(merge_request_diff.id) } + it { expect(json_response['head_commit_sha']).to eq(merge_request_diff.head_commit_sha) } + it { expect(json_response['diffs'].size).to eq(merge_request_diff.diffs.size) } + end + + it 'returns a 404 when merge_request_id not found' do + get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/versions/999", user) + expect(response).to have_http_status(404) + end + end end -- cgit v1.2.1 From a8fe213ebbb4a1aa48a20c908ba989190d20f2a1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 12 Aug 2016 15:40:00 +0300 Subject: Add documentation for merge request versions Signed-off-by: Dmitriy Zaporozhets --- doc/workflow/merge_requests.md | 8 ++++++++ doc/workflow/merge_requests/versions.png | Bin 0 -> 100566 bytes 2 files changed, 8 insertions(+) create mode 100644 doc/workflow/merge_requests/versions.png diff --git a/doc/workflow/merge_requests.md b/doc/workflow/merge_requests.md index d2ec56e6504..a81b1080ca6 100644 --- a/doc/workflow/merge_requests.md +++ b/doc/workflow/merge_requests.md @@ -61,3 +61,11 @@ If you click the "Hide whitespace changes" button, you can see the diff without It is also working on commits compare view. ![Commit Compare](merge_requests/commit_compare.png) + +## Merge Requests versions + +Every time you push to merge request branch, a new version of merge request diff +is created. When you visit the merge request page you see latest version of changes. +However you can select an older one from version dropdown + +![Merge Request Versions](merge_requests/versions.png) diff --git a/doc/workflow/merge_requests/versions.png b/doc/workflow/merge_requests/versions.png new file mode 100644 index 00000000000..c0a6dfe6806 Binary files /dev/null and b/doc/workflow/merge_requests/versions.png differ -- cgit v1.2.1 From 29ac60d7fbb8208880408dbf98a94acd0ae73730 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 15 Aug 2016 15:20:36 +0300 Subject: Change the way old merge request diff handled Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request.rb | 2 +- app/models/merge_request_diff.rb | 29 ++++++++++++++++++----------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 7e3444882ea..b7c2afb0920 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -261,7 +261,7 @@ class MergeRequest < ActiveRecord::Base end def diff_refs - if merge_request_diff + if persisted? merge_request_diff.diff_refs else start_sha = target_branch_sha diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 24e09c4d57c..4c18775c44a 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -22,10 +22,6 @@ class MergeRequestDiff < ActiveRecord::Base serialize :st_commits serialize :st_diffs - # For compatibility with old MergeRequestDiff which - # does not store those variables in database - after_initialize :ensure_commits_sha, if: :persisted? - # All diff information is collected from repository after object is created. # It allows you to override variables like head_commit_sha before getting diff. after_create :save_git_content, unless: :importing? @@ -50,6 +46,20 @@ class MergeRequestDiff < ActiveRecord::Base self.base_commit_sha ||= find_base_sha end + # This method will rely on repository branch sha + # in case start_commit_sha is nil. Its necesarry for old merge request diff + # created before version 8.4 to work + def safe_start_commit_sha + start_commit_sha || merge_request.target_branch_sha + end + + # This method will rely on repository branch sha + # in case head_commit_sha is nil. Its necesarry for old merge request diff + # created before version 8.4 to work + def safe_head_commit_sha + head_commit_sha || last_commit.try(:sha) || merge_request.source_branch_sha + end + def size real_size.presence || diffs.size end @@ -60,8 +70,8 @@ class MergeRequestDiff < ActiveRecord::Base begin compare = Gitlab::Git::Compare.new( repository.raw_repository, - start_commit_sha, - head_commit_sha + safe_start_commit_sha, + safe_head_commit_sha ) compare.diffs(options) end @@ -126,8 +136,8 @@ class MergeRequestDiff < ActiveRecord::Base Gitlab::Git::Compare.new( repository.raw_repository, - start_commit_sha, - head_commit_sha + safe_start_commit_sha, + safe_head_commit_sha ) end end @@ -216,9 +226,6 @@ class MergeRequestDiff < ActiveRecord::Base return unless head_commit_sha && start_commit_sha project.merge_base_commit(head_commit_sha, start_commit_sha).try(:sha) - rescue Rugged::OdbError - # In case head or start commit does not exist in the repository any more - nil end def utf8_st_diffs -- cgit v1.2.1 From 94a7198ade54595d72797cab09db2c2a89172535 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 15 Aug 2016 16:25:29 +0300 Subject: Fix merge request diff create and head_commit_sha compatibility Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request_diff.rb | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 4c18775c44a..950b00f1001 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -42,8 +42,19 @@ class MergeRequestDiff < ActiveRecord::Base def ensure_commits_sha self.start_commit_sha ||= merge_request.target_branch_sha - self.head_commit_sha ||= last_commit.try(:sha) || merge_request.source_branch_sha + self.head_commit_sha ||= merge_request.source_branch_sha self.base_commit_sha ||= find_base_sha + save + end + + # Override head_commit_sha to keep compatibility with merge request diff + # created before version 8.4 that does not store head_commit_sha in separate db field. + def head_commit_sha + if persisted? && super.nil? + last_commit.try(:sha) + else + super + end end # This method will rely on repository branch sha @@ -57,7 +68,7 @@ class MergeRequestDiff < ActiveRecord::Base # in case head_commit_sha is nil. Its necesarry for old merge request diff # created before version 8.4 to work def safe_head_commit_sha - head_commit_sha || last_commit.try(:sha) || merge_request.source_branch_sha + head_commit_sha || merge_request.source_branch_sha end def size @@ -111,7 +122,7 @@ class MergeRequestDiff < ActiveRecord::Base end def head_commit - return last_commit unless head_commit_sha + return unless head_commit_sha project.commit(head_commit_sha) end -- cgit v1.2.1 From 643a368fa437725cbfffcfdc251055c4d125438c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 15 Aug 2016 17:57:19 +0300 Subject: Make merge request diff works with new FileCollection logic Signed-off-by: Dmitriy Zaporozhets --- .../projects/merge_requests_controller.rb | 2 +- app/models/merge_request.rb | 6 +- app/models/merge_request_diff.rb | 14 +++-- .../projects/merge_requests/show/_diffs.html.haml | 1 + lib/gitlab/diff/file_collection/merge_request.rb | 73 ---------------------- .../diff/file_collection/merge_request_diff.rb | 73 ++++++++++++++++++++++ 6 files changed, 87 insertions(+), 82 deletions(-) delete mode 100644 lib/gitlab/diff/file_collection/merge_request.rb create mode 100644 lib/gitlab/diff/file_collection/merge_request_diff.rb diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index a0b80c823fb..a4b1262896c 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -91,7 +91,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController respond_to do |format| format.html { define_discussion_vars } format.json do - @diffs = @merge_request.diffs(diff_options) + @diffs = @merge_request_diff.diffs(diff_options) render json: { html: view_to_html_string("projects/merge_requests/show/_diffs") } end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 7c3845ef538..104f9c7223d 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -172,10 +172,10 @@ class MergeRequest < ActiveRecord::Base end def diffs(diff_options = nil) - if self.compare - self.compare.diffs(diff_options) + if compare + compare.diffs(diff_options) else - Gitlab::Diff::FileCollection::MergeRequest.new(self, diff_options: diff_options) + merge_request_diff.diffs(diff_options) end end diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 8920641cfec..9a34d099acd 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -141,7 +141,13 @@ class MergeRequestDiff < ActiveRecord::Base base_commit_sha? && head_commit_sha? && start_commit_sha? end - private + def diffs(diff_options = nil) + Gitlab::Diff::FileCollection::MergeRequestDiff.new(self, diff_options: diff_options) + end + + def project + merge_request.target_project + end def compare @compare ||= @@ -157,6 +163,8 @@ class MergeRequestDiff < ActiveRecord::Base end end + private + def dump_commits(commits) commits.map(&:to_hash) end @@ -229,10 +237,6 @@ class MergeRequestDiff < ActiveRecord::Base update_columns_serialized(new_attributes) end - def project - merge_request.target_project - end - def repository project.repository end diff --git a/app/views/projects/merge_requests/show/_diffs.html.haml b/app/views/projects/merge_requests/show/_diffs.html.haml index 013b05628fa..99c71e1454a 100644 --- a/app/views/projects/merge_requests/show/_diffs.html.haml +++ b/app/views/projects/merge_requests/show/_diffs.html.haml @@ -1,4 +1,5 @@ - if @merge_request_diff.collected? + = render 'projects/merge_requests/show/versions' = render "projects/diffs/diffs", diffs: @diffs - elsif @merge_request_diff.empty? .nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch} diff --git a/lib/gitlab/diff/file_collection/merge_request.rb b/lib/gitlab/diff/file_collection/merge_request.rb deleted file mode 100644 index 4f946908e2f..00000000000 --- a/lib/gitlab/diff/file_collection/merge_request.rb +++ /dev/null @@ -1,73 +0,0 @@ -module Gitlab - module Diff - module FileCollection - class MergeRequest < Base - def initialize(merge_request, diff_options:) - @merge_request = merge_request - - super(merge_request, - project: merge_request.project, - diff_options: diff_options, - diff_refs: merge_request.diff_refs) - end - - def diff_files - super.tap { |_| store_highlight_cache } - end - - private - - # Extracted method to highlight in the same iteration to the diff_collection. - def decorate_diff!(diff) - diff_file = super - cache_highlight!(diff_file) if cacheable? - diff_file - end - - def highlight_diff_file_from_cache!(diff_file, cache_diff_lines) - diff_file.highlighted_diff_lines = cache_diff_lines.map do |line| - Gitlab::Diff::Line.init_from_hash(line) - end - end - - # - # If we find the highlighted diff files lines on the cache we replace existing diff_files lines (no highlighted) - # for the highlighted ones, so we just skip their execution. - # If the highlighted diff files lines are not cached we calculate and cache them. - # - # The content of the cache is a Hash where the key correspond to the file_path and the values are Arrays of - # hashes that represent serialized diff lines. - # - def cache_highlight!(diff_file) - file_path = diff_file.file_path - - if highlight_cache[file_path] - highlight_diff_file_from_cache!(diff_file, highlight_cache[file_path]) - else - highlight_cache[file_path] = diff_file.highlighted_diff_lines.map(&:to_hash) - end - end - - def highlight_cache - return @highlight_cache if defined?(@highlight_cache) - - @highlight_cache = Rails.cache.read(cache_key) || {} - @highlight_cache_was_empty = @highlight_cache.empty? - @highlight_cache - end - - def store_highlight_cache - Rails.cache.write(cache_key, highlight_cache) if @highlight_cache_was_empty - end - - def cacheable? - @merge_request.merge_request_diff.present? - end - - def cache_key - [@merge_request.merge_request_diff, 'highlighted-diff-files', diff_options] - end - end - end - end -end diff --git a/lib/gitlab/diff/file_collection/merge_request_diff.rb b/lib/gitlab/diff/file_collection/merge_request_diff.rb new file mode 100644 index 00000000000..36348b33943 --- /dev/null +++ b/lib/gitlab/diff/file_collection/merge_request_diff.rb @@ -0,0 +1,73 @@ +module Gitlab + module Diff + module FileCollection + class MergeRequestDiff < Base + def initialize(merge_request_diff, diff_options:) + @merge_request_diff = merge_request_diff + + super(merge_request_diff, + project: merge_request_diff.project, + diff_options: diff_options, + diff_refs: merge_request_diff.diff_refs) + end + + def diff_files + super.tap { |_| store_highlight_cache } + end + + private + + # Extracted method to highlight in the same iteration to the diff_collection. + def decorate_diff!(diff) + diff_file = super + cache_highlight!(diff_file) if cacheable? + diff_file + end + + def highlight_diff_file_from_cache!(diff_file, cache_diff_lines) + diff_file.highlighted_diff_lines = cache_diff_lines.map do |line| + Gitlab::Diff::Line.init_from_hash(line) + end + end + + # + # If we find the highlighted diff files lines on the cache we replace existing diff_files lines (no highlighted) + # for the highlighted ones, so we just skip their execution. + # If the highlighted diff files lines are not cached we calculate and cache them. + # + # The content of the cache is a Hash where the key correspond to the file_path and the values are Arrays of + # hashes that represent serialized diff lines. + # + def cache_highlight!(diff_file) + file_path = diff_file.file_path + + if highlight_cache[file_path] + highlight_diff_file_from_cache!(diff_file, highlight_cache[file_path]) + else + highlight_cache[file_path] = diff_file.highlighted_diff_lines.map(&:to_hash) + end + end + + def highlight_cache + return @highlight_cache if defined?(@highlight_cache) + + @highlight_cache = Rails.cache.read(cache_key) || {} + @highlight_cache_was_empty = @highlight_cache.empty? + @highlight_cache + end + + def store_highlight_cache + Rails.cache.write(cache_key, highlight_cache) if @highlight_cache_was_empty + end + + def cacheable? + @merge_request_diff.present? + end + + def cache_key + [@merge_request_diff, 'highlighted-diff-files', diff_options] + end + end + end + end +end -- cgit v1.2.1 From 49d63dc131da899ac2c91c26fe7e22f02da34dbd Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 15 Aug 2016 18:11:18 +0300 Subject: Fix and refactor merge request diff_refs method Signed-off-by: Dmitriy Zaporozhets --- app/models/diff_note.rb | 6 +----- app/models/merge_request.rb | 17 ++--------------- app/models/merge_request_diff.rb | 2 +- spec/models/merge_request_spec.rb | 13 +++++++------ 4 files changed, 11 insertions(+), 27 deletions(-) diff --git a/app/models/diff_note.rb b/app/models/diff_note.rb index c816deb4e0c..364e1a8341b 100644 --- a/app/models/diff_note.rb +++ b/app/models/diff_note.rb @@ -79,11 +79,7 @@ class DiffNote < Note end def noteable_diff_refs - if noteable.respond_to?(:diff_sha_refs) - noteable.diff_sha_refs - else - noteable.diff_refs - end + noteable.diff_refs end def set_original_position diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 104f9c7223d..007c2aa74e1 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -270,7 +270,7 @@ class MergeRequest < ActiveRecord::Base end def diff_refs - if persisted? + if merge_request_diff && merge_request_diff.diff_refs_by_sha? merge_request_diff.diff_refs else start_sha = target_branch_sha @@ -287,19 +287,6 @@ class MergeRequest < ActiveRecord::Base end end - # Return diff_refs instance trying to not touch the git repository - def diff_sha_refs - if merge_request_diff && merge_request_diff.diff_refs_by_sha? - return Gitlab::Diff::DiffRefs.new( - base_sha: merge_request_diff.base_commit_sha, - start_sha: merge_request_diff.start_commit_sha, - head_sha: merge_request_diff.head_commit_sha - ) - else - diff_refs - end - end - def validate_branches if target_project == source_project && target_branch == source_branch errors.add :branch_conflict, "You can not use same project/branch for source and target" @@ -716,7 +703,7 @@ class MergeRequest < ActiveRecord::Base end def support_new_diff_notes? - diff_sha_refs && diff_sha_refs.complete? + diff_refs && diff_refs.complete? end def update_diff_notes_positions(old_diff_refs:, new_diff_refs:) diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 9a34d099acd..a769d31ac93 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -128,7 +128,7 @@ class MergeRequestDiff < ActiveRecord::Base end def diff_refs - return unless start_commit || base_commit + return unless start_commit_sha || base_commit_sha Gitlab::Diff::DiffRefs.new( base_sha: base_commit_sha, diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 9de9f19a27c..7242c4fc8d3 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -723,7 +723,6 @@ describe MergeRequest, models: true do end end -<<<<<<< HEAD describe '#branch_merge_base_commit' do context 'source and target branch exist' do it { expect(subject.branch_merge_base_commit.sha).to eq('ae73cb07c9eeaf35924a10f713b364d32b2dd34f') } @@ -737,8 +736,11 @@ describe MergeRequest, models: true do it 'returns nil' do expect(subject.branch_merge_base_commit).to be_nil -======= - describe "#diff_sha_refs" do + end + end + end + + describe "#diff_refs" do context "with diffs" do subject { create(:merge_request, :with_diffs) } @@ -747,7 +749,7 @@ describe MergeRequest, models: true do expect_any_instance_of(Repository).not_to receive(:commit) - subject.diff_sha_refs + subject.diff_refs end it "returns expected diff_refs" do @@ -757,8 +759,7 @@ describe MergeRequest, models: true do head_sha: subject.merge_request_diff.head_commit_sha ) - expect(subject.diff_sha_refs).to eq(expected_diff_refs) ->>>>>>> master + expect(subject.diff_refs).to eq(expected_diff_refs) end end end -- cgit v1.2.1 From a94553a90c16b58c9cc9d56488e3aa3c35b8d699 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 15 Aug 2016 18:22:26 +0300 Subject: Fix merge request diffs spec Signed-off-by: Dmitriy Zaporozhets --- spec/models/merge_request_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 7242c4fc8d3..c066b65e7ba 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -159,7 +159,7 @@ describe MergeRequest, models: true do context 'when there are MR diffs' do it 'delegates to the MR diffs' do - merge_request.merge_request_diffs.build + merge_request.save expect(merge_request.merge_request_diff).to receive(:raw_diffs).with(hash_including(options)) -- cgit v1.2.1 From e067e699c3250882ea08594243b6c6d3ad84d6e0 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 19 Aug 2016 12:35:16 +0300 Subject: Make sure merge request is fetched before collecting base sha in merge request diff Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request_diff.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index a769d31ac93..42ab6b620bd 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -41,6 +41,7 @@ class MergeRequestDiff < ActiveRecord::Base end def ensure_commits_sha + merge_request.fetch_ref self.start_commit_sha ||= merge_request.target_branch_sha self.head_commit_sha ||= merge_request.source_branch_sha self.base_commit_sha ||= find_base_sha -- cgit v1.2.1 From 74461ccc1f1503c86102b7d8e790ebac0d28fc0b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 19 Aug 2016 12:35:40 +0300 Subject: Fix merge request versions api doc Signed-off-by: Dmitriy Zaporozhets --- doc/api/merge_requests.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 66957647d00..1cf4940198f 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -909,7 +909,7 @@ GET /projects/:id/merge_requests/:merge_request_id/versions | `merge_request_id` | integer | yes | The ID of the merge request | ```bash -curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/1/merge_requests/1/versions +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/1/merge_requests/1/versions ``` Example response: @@ -951,7 +951,7 @@ GET /projects/:id/merge_requests/:merge_request_id/versions/:version_id | `version_id` | integer | yes | The ID of the merge request diff version | ```bash -curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/1/merge_requests/1/versions/1 +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/1/merge_requests/1/versions/1 ``` Example response: -- cgit v1.2.1 From 06ac1c26a14be73f409138f2877c236f352bcdf9 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Sat, 20 Aug 2016 20:42:53 +0200 Subject: Add tests coverage report badge to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fee93d5f9c3..f00dec0ab82 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # GitLab [![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) +[![coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq) ## Canonical source -- cgit v1.2.1 From eb355dec8768ef128795309c6c9ffa296a6eee22 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 22 Aug 2016 14:18:58 +0300 Subject: Restore diff_sha_refs method Signed-off-by: Dmitriy Zaporozhets --- app/models/diff_note.rb | 6 +++++- app/models/merge_request.rb | 31 ++++++++++++++++--------------- spec/models/merge_request_spec.rb | 6 +++--- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/app/models/diff_note.rb b/app/models/diff_note.rb index 0c23c1c1934..c8320ff87fa 100644 --- a/app/models/diff_note.rb +++ b/app/models/diff_note.rb @@ -118,7 +118,11 @@ class DiffNote < Note end def noteable_diff_refs - noteable.diff_refs + if noteable.respond_to?(:diff_sha_refs) + noteable.diff_sha_refs + else + noteable.diff_refs + end end def set_original_position diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 14b785e6bd4..615e550cf05 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -265,28 +265,29 @@ class MergeRequest < ActiveRecord::Base @source_branch_sha || source_branch_head.try(:sha) end - def branch_merge_base_sha - branch_merge_base_commit.try(:sha) + def diff_refs + return unless diff_start_commit || diff_base_commit + + Gitlab::Diff::DiffRefs.new( + base_sha: diff_base_sha, + start_sha: diff_start_sha, + head_sha: diff_head_sha + ) end - def diff_refs + # Return diff_refs instance trying to not touch the git repository + def diff_sha_refs if merge_request_diff && merge_request_diff.diff_refs_by_sha? merge_request_diff.diff_refs else - start_sha = target_branch_sha - head_sha = source_branch_sha - base_sha = branch_merge_base_sha - - if start_sha || base_sha - Gitlab::Diff::DiffRefs.new( - base_sha: base_sha, - start_sha: start_sha, - head_sha: head_sha - ) - end + diff_refs end end + def branch_merge_base_sha + branch_merge_base_commit.try(:sha) + end + def validate_branches if target_project == source_project && target_branch == source_branch errors.add :branch_conflict, "You can not use same project/branch for source and target" @@ -748,7 +749,7 @@ class MergeRequest < ActiveRecord::Base end def has_complete_diff_refs? - diff_refs && diff_refs.complete? + diff_sha_refs && diff_sha_refs.complete? end def update_diff_notes_positions(old_diff_refs:, new_diff_refs:) diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 573c8c6c9ce..18d178be49c 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -782,7 +782,7 @@ describe MergeRequest, models: true do end end - describe "#diff_refs" do + describe "#diff_sha_refs" do context "with diffs" do subject { create(:merge_request, :with_diffs) } @@ -791,7 +791,7 @@ describe MergeRequest, models: true do expect_any_instance_of(Repository).not_to receive(:commit) - subject.diff_refs + subject.diff_sha_refs end it "returns expected diff_refs" do @@ -801,7 +801,7 @@ describe MergeRequest, models: true do head_sha: subject.merge_request_diff.head_commit_sha ) - expect(subject.diff_refs).to eq(expected_diff_refs) + expect(subject.diff_sha_refs).to eq(expected_diff_refs) end end end -- cgit v1.2.1 From dde44b83ddeae75a5c14810d0571ee5c7ab0a26d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 22 Aug 2016 15:30:23 +0300 Subject: Fix merge request diff api Signed-off-by: Dmitriy Zaporozhets --- lib/api/entities.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 3f050a8fd81..3241cb7ca56 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -246,7 +246,7 @@ module API expose :commits, using: Entities::RepoCommit expose :diffs, using: Entities::RepoDiff do |compare, _| - compare.diffs(all_diffs: true).to_a + compare.raw_diffs(all_diffs: true).to_a end end -- cgit v1.2.1 From d7a9dcc1b14d6abc723b232dbedd025469511cb7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 22 Aug 2016 15:44:48 +0300 Subject: Fix merge request diff cache service spec Signed-off-by: Dmitriy Zaporozhets --- spec/services/merge_requests/merge_request_diff_cache_service_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb b/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb index c4b87468275..807f89e80b7 100644 --- a/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb +++ b/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb @@ -6,7 +6,7 @@ describe MergeRequests::MergeRequestDiffCacheService do describe '#execute' do it 'retrieves the diff files to cache the highlighted result' do merge_request = create(:merge_request) - cache_key = [merge_request.merge_request_diff, 'highlighted-diff-files', Gitlab::Diff::FileCollection::MergeRequest.default_options] + cache_key = [merge_request.merge_request_diff, 'highlighted-diff-files', Gitlab::Diff::FileCollection::MergeRequestDiff.default_options] expect(Rails.cache).to receive(:read).with(cache_key).and_return({}) expect(Rails.cache).to receive(:write).with(cache_key, anything) -- cgit v1.2.1 From 7b3fd81673e595b48b4c0e5f1ca5f1ab806f8ac3 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 22 Aug 2016 18:21:28 +0300 Subject: Disable comments on older merge request diff Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/merge_requests_controller.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 438dd928853..eff959c781c 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -93,6 +93,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController respond_to do |format| format.html { define_discussion_vars } format.json do + if @merge_request_diff != @merge_request.merge_request_diff + # Disable comments if browsing older version of the diff + @diff_notes_disabled = true + end + @diffs = @merge_request_diff.diffs(diff_options) render json: { html: view_to_html_string("projects/merge_requests/show/_diffs") } -- cgit v1.2.1 From 4b1a98ba9847579db32da95ed479e2da098eb155 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 22 Aug 2016 21:15:06 +0300 Subject: Fix db schema via db:migrate:reset Signed-off-by: Dmitriy Zaporozhets --- db/schema.rb | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index 4947745b232..77f114ede45 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -70,11 +70,11 @@ ActiveRecord::Schema.define(version: 20160819221833) do t.string "recaptcha_site_key" t.string "recaptcha_private_key" t.integer "metrics_port", default: 8089 + t.boolean "akismet_enabled", default: false + t.string "akismet_api_key" t.integer "metrics_sample_interval", default: 15 t.boolean "sentry_enabled", default: false t.string "sentry_dsn" - t.boolean "akismet_enabled", default: false - t.string "akismet_api_key" t.boolean "email_author_in_body", default: false t.integer "default_group_visibility" t.boolean "repository_checks_enabled", default: false @@ -467,11 +467,10 @@ ActiveRecord::Schema.define(version: 20160819221833) do t.string "state" t.integer "iid" t.integer "updated_by_id" - t.integer "moved_to_id" t.boolean "confidential", default: false t.datetime "deleted_at" t.date "due_date" - t.integer "lock_version", default: 0, null: false + t.integer "moved_to_id" end add_index "issues", ["assignee_id"], name: "index_issues_on_assignee_id", using: :btree @@ -614,13 +613,12 @@ ActiveRecord::Schema.define(version: 20160819221833) do t.datetime "locked_at" t.integer "updated_by_id" t.string "merge_error" + t.text "merge_params" t.boolean "merge_when_build_succeeds", default: false, null: false t.integer "merge_user_id" t.string "merge_commit_sha" t.datetime "deleted_at" - t.integer "lock_version", default: 0, null: false t.string "in_progress_merge_commit_sha" - t.text "merge_params" end add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree @@ -915,9 +913,9 @@ ActiveRecord::Schema.define(version: 20160819221833) do t.string "type" t.string "title" t.integer "project_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "active", null: false + t.datetime "created_at" + t.datetime "updated_at" + t.boolean "active", default: false, null: false t.text "properties" t.boolean "template", default: false t.boolean "push_events", default: true @@ -962,8 +960,8 @@ ActiveRecord::Schema.define(version: 20160819221833) do t.string "noteable_type" t.string "title" t.text "description" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.boolean "submitted_as_ham", default: false, null: false end @@ -1034,13 +1032,13 @@ ActiveRecord::Schema.define(version: 20160819221833) do add_index "u2f_registrations", ["user_id"], name: "index_u2f_registrations_on_user_id", using: :btree create_table "user_agent_details", force: :cascade do |t| - t.string "user_agent", null: false - t.string "ip_address", null: false - t.integer "subject_id", null: false - t.string "subject_type", null: false + t.string "user_agent", null: false + t.string "ip_address", null: false + t.integer "subject_id", null: false + t.string "subject_type", null: false t.boolean "submitted", default: false, null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "users", force: :cascade do |t| @@ -1156,4 +1154,4 @@ ActiveRecord::Schema.define(version: 20160819221833) do add_foreign_key "protected_branch_merge_access_levels", "protected_branches" add_foreign_key "protected_branch_push_access_levels", "protected_branches" add_foreign_key "u2f_registrations", "users" -end \ No newline at end of file +end -- cgit v1.2.1 From 03671c30df268c787420cb163beb41d208a3c9e7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 22 Aug 2016 21:17:17 +0300 Subject: Add changelog item for merge request versions feature Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index c6a4fe5f5b8..88a2acd15d2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ Please view this file on the master branch, on stable branches it's out of date. +v 8.12.0 (unreleased) + - Add merge request versions !5467 + v 8.11.0 (unreleased) - Use test coverage value from the latest successful pipeline in badge. !5862 - Add test coverage report badge. !5708 -- cgit v1.2.1 From eff3c35410e97d4238ef93816e5164884c8b1369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Mon, 22 Aug 2016 19:57:43 +0000 Subject: Update merge_requests.md with a simpler way to check out a merge request The previous way was put under the "By modifying `.git/config` for a given repository" section. The disadvantage is that one has to modify `.git/config` for each repository that one uses. The new way was put under the "By adding a git alias" section. One has to create this git alias once, and then it will work from any repository, without having to modify `.git/config` over and over again. --- doc/workflow/merge_requests.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/workflow/merge_requests.md b/doc/workflow/merge_requests.md index d2ec56e6504..12ffa916a8f 100644 --- a/doc/workflow/merge_requests.md +++ b/doc/workflow/merge_requests.md @@ -15,6 +15,21 @@ Please note that you need to have builds configured to enable this feature. ## Checkout merge requests locally +### By adding a git alias + +Add the following alias to your `~/.gitconfig`: +``` +[alias] + mr = !sh -c 'git fetch origin merge-requests/$1/head:mr-$1 && git checkout mr-$1' - +``` +Now you can check out a particular merge request from any repository (it will use the `origin` remote) by: +``` +$ git mr 5 +``` +This will fetch the merge request into a local `mr-5` branch and check it out. + +### By modifying `.git/config` for a given repository + Locate the section for your GitLab remote in the `.git/config` file. It looks like this: ``` -- cgit v1.2.1 From c2d0bb9b034fb11b352ae7336c0fe8a7bd4cba48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Mon, 22 Aug 2016 20:17:23 +0000 Subject: Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index c6a4fe5f5b8..e5da0b45f66 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -163,6 +163,7 @@ v 8.11.0 (unreleased) - Eliminate unneeded calls to Repository#blob_at when listing commits with no path - Update gitlab_git gem to 10.4.7 - Simplify SQL queries of marking a todo as done + - Update merge_requests.md with a simpler way to check out a merge request. !5944 v 8.10.7 - Upgrade Hamlit to 2.6.1. !5873 -- cgit v1.2.1 From 251ded248dcda8c7a552e52ddb2582ad961e4bc0 Mon Sep 17 00:00:00 2001 From: Sebastiaan Lokhorst Date: Tue, 23 Aug 2016 17:33:59 +0000 Subject: Update Ruby version to 2.3 in Requirements --- doc/install/requirements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install/requirements.md b/doc/install/requirements.md index a65ac8a5f79..571f1a38358 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -32,7 +32,7 @@ Please consider using a virtual machine to run GitLab. ## Ruby versions -GitLab requires Ruby (MRI) 2.1.x and currently does not work with versions 2.2 or 2.3. +GitLab requires Ruby (MRI) 2.3. Support for Ruby versions below 2.3 (2.1, 2.2) will stop with GitLab 8.13. You will have to use the standard MRI implementation of Ruby. We love [JRuby](http://jruby.org/) and [Rubinius](http://rubini.us/) but GitLab -- cgit v1.2.1 From d04e8f4fc09832473f7b3794d617aaba9cb204aa Mon Sep 17 00:00:00 2001 From: Sebastiaan Lokhorst Date: Tue, 23 Aug 2016 18:12:27 +0000 Subject: Update Ruby version to 2.3 in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fee93d5f9c3..33d9407a0c1 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Instructions on how to start GitLab and how to run the tests can be found in the GitLab is a Ruby on Rails application that runs on the following software: - Ubuntu/Debian/CentOS/RHEL -- Ruby (MRI) 2.1 +- Ruby (MRI) 2.3 - Git 2.7.4+ - Redis 2.8+ - MySQL or PostgreSQL -- cgit v1.2.1 From d1ed0c76ec7e9ef4ec1ccff2756433997b3a2397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Tue, 23 Aug 2016 13:02:16 -0600 Subject: Add new lines after backticks and colons --- doc/workflow/merge_requests.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/workflow/merge_requests.md b/doc/workflow/merge_requests.md index 12ffa916a8f..adee26f0fe9 100644 --- a/doc/workflow/merge_requests.md +++ b/doc/workflow/merge_requests.md @@ -18,14 +18,18 @@ Please note that you need to have builds configured to enable this feature. ### By adding a git alias Add the following alias to your `~/.gitconfig`: + ``` [alias] mr = !sh -c 'git fetch origin merge-requests/$1/head:mr-$1 && git checkout mr-$1' - ``` + Now you can check out a particular merge request from any repository (it will use the `origin` remote) by: + ``` $ git mr 5 ``` + This will fetch the merge request into a local `mr-5` branch and check it out. ### By modifying `.git/config` for a given repository -- cgit v1.2.1 From a7bd1c23dd03f00d10b0ff4db655690283e2f88a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Tue, 23 Aug 2016 13:05:34 -0600 Subject: Modify the alias to allow specifying a remote Now the alias should be used as: git mr upstream 5 To check out a MR number 5 from the upstream remote, into a `mr-upstream-5` local branch. Also clarify that the `5` in the merge request is the number shown in GitLab. --- doc/workflow/merge_requests.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/workflow/merge_requests.md b/doc/workflow/merge_requests.md index adee26f0fe9..91fcfb02d39 100644 --- a/doc/workflow/merge_requests.md +++ b/doc/workflow/merge_requests.md @@ -21,16 +21,16 @@ Add the following alias to your `~/.gitconfig`: ``` [alias] - mr = !sh -c 'git fetch origin merge-requests/$1/head:mr-$1 && git checkout mr-$1' - + mr = !sh -c 'git fetch $1 merge-requests/$2/head:mr-$1-$2 && git checkout mr-$1-$2' - ``` -Now you can check out a particular merge request from any repository (it will use the `origin` remote) by: +Now you can check out a particular merge request from any repository and any remote, e.g. to check out a merge request number 5 as shown in GitLab from the `upstream` remote, do: ``` -$ git mr 5 +$ git mr upstream 5 ``` -This will fetch the merge request into a local `mr-5` branch and check it out. +This will fetch the merge request into a local `mr-upstream-5` branch and check it out. ### By modifying `.git/config` for a given repository -- cgit v1.2.1 From 009727fb80da7c3c2f4414b1e4d0a31c9e13ff68 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Mon, 22 Aug 2016 13:43:21 -0500 Subject: Remove ugly horizontal scrollbars in windows --- app/assets/stylesheets/pages/builds.scss | 2 +- app/assets/stylesheets/pages/pipelines.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss index c1bb250b42d..8c33e7d9a2e 100644 --- a/app/assets/stylesheets/pages/builds.scss +++ b/app/assets/stylesheets/pages/builds.scss @@ -150,7 +150,7 @@ border-top: 1px solid $border-color; border-bottom: 1px solid $border-color; max-height: 300px; - overflow: scroll; + overflow: auto; svg { position: relative; diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 6fa097e3bf1..8e7cfafe76f 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -265,7 +265,7 @@ .pipeline-visualization { position: relative; - min-width: 1220px; + min-width: 1200px; ul { padding: 0; -- cgit v1.2.1 From 2f4cde01c2849168c5cb1aea3902e0af8bcaced1 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Mon, 22 Aug 2016 13:51:38 -0500 Subject: Remove graph min width --- app/assets/stylesheets/pages/pipelines.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 8e7cfafe76f..7eb4e7ec676 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -265,7 +265,6 @@ .pipeline-visualization { position: relative; - min-width: 1200px; ul { padding: 0; -- cgit v1.2.1 From 3a9091b43d06ab499968571bfa13e1c613114e4d Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Tue, 23 Aug 2016 15:02:16 -0500 Subject: Fix overflow scroll --- app/assets/stylesheets/pages/merge_requests.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index fcdaf671538..4bfdc4a2b26 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -269,7 +269,7 @@ .builds { .table-holder { - overflow-x: scroll; + overflow-x: auto; } } -- cgit v1.2.1 From 75d48ae35bcdb8bfc0a6f661de32718710082856 Mon Sep 17 00:00:00 2001 From: winniehell Date: Wed, 24 Aug 2016 02:18:38 +0200 Subject: Add failing test for #21334 --- spec/lib/extracts_path_spec.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb index 86d04ecfa36..e10c1f5c547 100644 --- a/spec/lib/extracts_path_spec.rb +++ b/spec/lib/extracts_path_spec.rb @@ -51,6 +51,16 @@ describe ExtractsPath, lib: true do expect(@path).to eq(params[:path]) end end + + context 'subclass overrides get_id' do + it 'uses ref returned by get_id' do + allow_any_instance_of(self.class).to receive(:get_id){ '38008cb17ce1466d8fec2dfa6f6ab8dcfe5cf49e' } + + assign_ref_vars + + expect(@id).to eq(get_id) + end + end end describe '#extract_ref' do -- cgit v1.2.1 From 0762f680c653dff9ff45fe0ce72136b39e125979 Mon Sep 17 00:00:00 2001 From: tiagonbotelho Date: Mon, 22 Aug 2016 13:56:07 +0100 Subject: change from members using size to start using total_count in the group members page --- CHANGELOG | 1 + app/views/groups/group_members/index.html.haml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index ef38d3e29f5..d9b8372be18 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,7 @@ v 8.12.0 (unreleased) v 8.11.1 (unreleased) - Fix file links on project page when default view is Files !5933 + - Change using size to use count and caching it for number of group members v 8.11.0 - Use test coverage value from the latest successful pipeline in badge. !5862 diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml index 90f362c052b..f789796e942 100644 --- a/app/views/groups/group_members/index.html.haml +++ b/app/views/groups/group_members/index.html.haml @@ -17,7 +17,7 @@ .panel-heading %strong #{@group.name} group members - %span.badge= @members.size + %span.badge= @members.total_count .controls = form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form' do .form-group -- cgit v1.2.1 From 31b2c1ef880349c9579f41e501de0346e59f0a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Dequ=C3=A8nes=20=28Duck=29?= Date: Mon, 22 Aug 2016 12:47:58 +0900 Subject: expose 'only_allow_merge_if_build_succeeds' project setting in the API --- CHANGELOG | 1 + doc/api/projects.md | 24 +++++++++++++++++------- lib/api/entities.rb | 1 + lib/api/projects.rb | 9 ++++++--- spec/javascripts/fixtures/projects.json | 2 +- spec/requests/api/projects_spec.rb | 28 +++++++++++++++++++++++++++- 6 files changed, 53 insertions(+), 12 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ef38d3e29f5..c28daf5e6df 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ v 8.12.0 (unreleased) - Change merge_error column from string to text type - Optimistic locking for Issues and Merge Requests (title and description overriding prevention) - Added tests for diff notes + - Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck) v 8.11.1 (unreleased) - Fix file links on project page when default view is Files !5933 diff --git a/doc/api/projects.md b/doc/api/projects.md index 37d97b2db44..fe3c38750d6 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -84,7 +84,8 @@ Parameters: "star_count": 0, "runners_token": "b8547b1dc37721d05889db52fa2f02", "public_builds": true, - "shared_with_groups": [] + "shared_with_groups": [], + "only_allow_merge_if_build_succeeds": false }, { "id": 6, @@ -144,7 +145,8 @@ Parameters: "star_count": 0, "runners_token": "b8547b1dc37721d05889db52fa2f02", "public_builds": true, - "shared_with_groups": [] + "shared_with_groups": [], + "only_allow_merge_if_build_succeeds": false } ] ``` @@ -280,7 +282,8 @@ Parameters: "group_name": "Gitlab Org", "group_access_level": 10 } - ] + ], + "only_allow_merge_if_build_succeeds": false } ``` @@ -448,6 +451,7 @@ Parameters: - `visibility_level` (optional) - `import_url` (optional) - `public_builds` (optional) +- `only_allow_merge_if_build_succeeds` (optional) ### Create project for user @@ -473,6 +477,7 @@ Parameters: - `visibility_level` (optional) - `import_url` (optional) - `public_builds` (optional) +- `only_allow_merge_if_build_succeeds` (optional) ### Edit project @@ -499,6 +504,7 @@ Parameters: - `public` (optional) - if `true` same as setting visibility_level = 20 - `visibility_level` (optional) - `public_builds` (optional) +- `only_allow_merge_if_build_succeeds` (optional) On success, method returns 200 with the updated project. If parameters are invalid, 400 is returned. @@ -577,7 +583,8 @@ Example response: "forks_count": 0, "star_count": 1, "public_builds": true, - "shared_with_groups": [] + "shared_with_groups": [], + "only_allow_merge_if_build_succeeds": false } ``` @@ -643,7 +650,8 @@ Example response: "forks_count": 0, "star_count": 0, "public_builds": true, - "shared_with_groups": [] + "shared_with_groups": [], + "only_allow_merge_if_build_succeeds": false } ``` @@ -729,7 +737,8 @@ Example response: "star_count": 0, "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b", "public_builds": true, - "shared_with_groups": [] + "shared_with_groups": [], + "only_allow_merge_if_build_succeeds": false } ``` @@ -815,7 +824,8 @@ Example response: "star_count": 0, "runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b", "public_builds": true, - "shared_with_groups": [] + "shared_with_groups": [], + "only_allow_merge_if_build_succeeds": false } ``` diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 66b85ab1793..0f6d28f1821 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -90,6 +90,7 @@ module API expose :shared_with_groups do |project, options| SharedGroup.represent(project.project_group_links.all, options) end + expose :only_allow_merge_if_build_succeeds end class Member < UserBasic diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 60cfc103afd..71efd4f33ca 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -123,7 +123,8 @@ module API :public, :visibility_level, :import_url, - :public_builds] + :public_builds, + :only_allow_merge_if_build_succeeds] attrs = map_public_to_visibility_level(attrs) @project = ::Projects::CreateService.new(current_user, attrs).execute if @project.saved? @@ -172,7 +173,8 @@ module API :public, :visibility_level, :import_url, - :public_builds] + :public_builds, + :only_allow_merge_if_build_succeeds] attrs = map_public_to_visibility_level(attrs) @project = ::Projects::CreateService.new(user, attrs).execute if @project.saved? @@ -234,7 +236,8 @@ module API :shared_runners_enabled, :public, :visibility_level, - :public_builds] + :public_builds, + :only_allow_merge_if_build_succeeds] attrs = map_public_to_visibility_level(attrs) authorize_admin_project authorize! :rename_project, user_project if attrs[:name].present? diff --git a/spec/javascripts/fixtures/projects.json b/spec/javascripts/fixtures/projects.json index 84e8d0ba1e4..4919d77e5a4 100644 --- a/spec/javascripts/fixtures/projects.json +++ b/spec/javascripts/fixtures/projects.json @@ -1 +1 @@ -[{"id":9,"description":"","default_branch":null,"tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:root/test.git","http_url_to_repo":"http://localhost:3000/root/test.git","web_url":"http://localhost:3000/root/test","owner":{"name":"Administrator","username":"root","id":1,"state":"active","avatar_url":"http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon","web_url":"http://localhost:3000/u/root"},"name":"test","name_with_namespace":"Administrator / test","path":"test","path_with_namespace":"root/test","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-14T19:08:05.364Z","last_activity_at":"2016-01-14T19:08:07.418Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":1,"name":"root","path":"root","owner_id":1,"created_at":"2016-01-13T20:19:44.439Z","updated_at":"2016-01-13T20:19:44.439Z","description":"","avatar":null},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":0,"permissions":{"project_access":null,"group_access":null}},{"id":8,"description":"Voluptatem quae nulla eius numquam ullam voluptatibus quia modi.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:h5bp/html5-boilerplate.git","http_url_to_repo":"http://localhost:3000/h5bp/html5-boilerplate.git","web_url":"http://localhost:3000/h5bp/html5-boilerplate","name":"Html5 Boilerplate","name_with_namespace":"H5bp / Html5 Boilerplate","path":"html5-boilerplate","path_with_namespace":"h5bp/html5-boilerplate","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:57.525Z","last_activity_at":"2016-01-13T20:27:57.280Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":5,"name":"H5bp","path":"h5bp","owner_id":null,"created_at":"2016-01-13T20:19:57.239Z","updated_at":"2016-01-13T20:19:57.239Z","description":"Tempore accusantium possimus aut libero.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":5,"permissions":{"project_access":{"access_level":10,"notification_level":3},"group_access":{"access_level":50,"notification_level":3}}},{"id":7,"description":"Modi odio mollitia dolorem qui.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:twitter/typeahead-js.git","http_url_to_repo":"http://localhost:3000/twitter/typeahead-js.git","web_url":"http://localhost:3000/twitter/typeahead-js","name":"Typeahead.Js","name_with_namespace":"Twitter / Typeahead.Js","path":"typeahead-js","path_with_namespace":"twitter/typeahead-js","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:56.212Z","last_activity_at":"2016-01-13T20:27:51.496Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":4,"name":"Twitter","path":"twitter","owner_id":null,"created_at":"2016-01-13T20:19:54.480Z","updated_at":"2016-01-13T20:19:54.480Z","description":"Id voluptatem ipsa maiores omnis repudiandae et et.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":4,"permissions":{"project_access":null,"group_access":{"access_level":10,"notification_level":3}}},{"id":6,"description":"Omnis asperiores ipsa et beatae quidem necessitatibus quia.","default_branch":"master","tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:twitter/flight.git","http_url_to_repo":"http://localhost:3000/twitter/flight.git","web_url":"http://localhost:3000/twitter/flight","name":"Flight","name_with_namespace":"Twitter / Flight","path":"flight","path_with_namespace":"twitter/flight","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:54.754Z","last_activity_at":"2016-01-13T20:27:50.502Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":4,"name":"Twitter","path":"twitter","owner_id":null,"created_at":"2016-01-13T20:19:54.480Z","updated_at":"2016-01-13T20:19:54.480Z","description":"Id voluptatem ipsa maiores omnis repudiandae et et.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":4,"permissions":{"project_access":null,"group_access":{"access_level":10,"notification_level":3}}},{"id":5,"description":"Voluptatem commodi voluptate placeat architecto beatae illum dolores fugiat.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-test.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-test.git","web_url":"http://localhost:3000/gitlab-org/gitlab-test","name":"Gitlab Test","name_with_namespace":"Gitlab Org / Gitlab Test","path":"gitlab-test","path_with_namespace":"gitlab-org/gitlab-test","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:53.202Z","last_activity_at":"2016-01-13T20:27:41.626Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":5,"permissions":{"project_access":null,"group_access":{"access_level":50,"notification_level":3}}},{"id":4,"description":"Aut molestias quas est ut aperiam officia quod libero.","default_branch":"master","tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-shell.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-shell.git","web_url":"http://localhost:3000/gitlab-org/gitlab-shell","name":"Gitlab Shell","name_with_namespace":"Gitlab Org / Gitlab Shell","path":"gitlab-shell","path_with_namespace":"gitlab-org/gitlab-shell","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:51.882Z","last_activity_at":"2016-01-13T20:27:35.678Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":5,"permissions":{"project_access":{"access_level":20,"notification_level":3},"group_access":{"access_level":50,"notification_level":3}}},{"id":3,"description":"Excepturi molestiae quia repellendus omnis est illo illum eligendi.","default_branch":"master","tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-ci.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-ci.git","web_url":"http://localhost:3000/gitlab-org/gitlab-ci","name":"Gitlab Ci","name_with_namespace":"Gitlab Org / Gitlab Ci","path":"gitlab-ci","path_with_namespace":"gitlab-org/gitlab-ci","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:50.346Z","last_activity_at":"2016-01-13T20:27:30.115Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":3,"permissions":{"project_access":null,"group_access":{"access_level":50,"notification_level":3}}},{"id":2,"description":"Adipisci quaerat dignissimos enim sed ipsam dolorem quia.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":10,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-ce.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-ce.git","web_url":"http://localhost:3000/gitlab-org/gitlab-ce","name":"Gitlab Ce","name_with_namespace":"Gitlab Org / Gitlab Ce","path":"gitlab-ce","path_with_namespace":"gitlab-org/gitlab-ce","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:49.065Z","last_activity_at":"2016-01-13T20:26:58.454Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":5,"permissions":{"project_access":{"access_level":30,"notification_level":3},"group_access":{"access_level":50,"notification_level":3}}},{"id":1,"description":"Vel voluptatem maxime saepe ex quia.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:documentcloud/underscore.git","http_url_to_repo":"http://localhost:3000/documentcloud/underscore.git","web_url":"http://localhost:3000/documentcloud/underscore","name":"Underscore","name_with_namespace":"Documentcloud / Underscore","path":"underscore","path_with_namespace":"documentcloud/underscore","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:45.862Z","last_activity_at":"2016-01-13T20:25:03.106Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":2,"name":"Documentcloud","path":"documentcloud","owner_id":null,"created_at":"2016-01-13T20:19:44.464Z","updated_at":"2016-01-13T20:19:44.464Z","description":"Aut impedit perferendis fuga et ipsa repellat cupiditate et.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"open_issues_count":5,"permissions":{"project_access":null,"group_access":{"access_level":50,"notification_level":3}}}] +[{"id":9,"description":"","default_branch":null,"tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:root/test.git","http_url_to_repo":"http://localhost:3000/root/test.git","web_url":"http://localhost:3000/root/test","owner":{"name":"Administrator","username":"root","id":1,"state":"active","avatar_url":"http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon","web_url":"http://localhost:3000/u/root"},"name":"test","name_with_namespace":"Administrator / test","path":"test","path_with_namespace":"root/test","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-14T19:08:05.364Z","last_activity_at":"2016-01-14T19:08:07.418Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":1,"name":"root","path":"root","owner_id":1,"created_at":"2016-01-13T20:19:44.439Z","updated_at":"2016-01-13T20:19:44.439Z","description":"","avatar":null},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":false,"open_issues_count":0,"permissions":{"project_access":null,"group_access":null}},{"id":8,"description":"Voluptatem quae nulla eius numquam ullam voluptatibus quia modi.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:h5bp/html5-boilerplate.git","http_url_to_repo":"http://localhost:3000/h5bp/html5-boilerplate.git","web_url":"http://localhost:3000/h5bp/html5-boilerplate","name":"Html5 Boilerplate","name_with_namespace":"H5bp / Html5 Boilerplate","path":"html5-boilerplate","path_with_namespace":"h5bp/html5-boilerplate","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:57.525Z","last_activity_at":"2016-01-13T20:27:57.280Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":5,"name":"H5bp","path":"h5bp","owner_id":null,"created_at":"2016-01-13T20:19:57.239Z","updated_at":"2016-01-13T20:19:57.239Z","description":"Tempore accusantium possimus aut libero.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":false,"open_issues_count":5,"permissions":{"project_access":{"access_level":10,"notification_level":3},"group_access":{"access_level":50,"notification_level":3}}},{"id":7,"description":"Modi odio mollitia dolorem qui.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:twitter/typeahead-js.git","http_url_to_repo":"http://localhost:3000/twitter/typeahead-js.git","web_url":"http://localhost:3000/twitter/typeahead-js","name":"Typeahead.Js","name_with_namespace":"Twitter / Typeahead.Js","path":"typeahead-js","path_with_namespace":"twitter/typeahead-js","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:56.212Z","last_activity_at":"2016-01-13T20:27:51.496Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":4,"name":"Twitter","path":"twitter","owner_id":null,"created_at":"2016-01-13T20:19:54.480Z","updated_at":"2016-01-13T20:19:54.480Z","description":"Id voluptatem ipsa maiores omnis repudiandae et et.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":true,"open_issues_count":4,"permissions":{"project_access":null,"group_access":{"access_level":10,"notification_level":3}}},{"id":6,"description":"Omnis asperiores ipsa et beatae quidem necessitatibus quia.","default_branch":"master","tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:twitter/flight.git","http_url_to_repo":"http://localhost:3000/twitter/flight.git","web_url":"http://localhost:3000/twitter/flight","name":"Flight","name_with_namespace":"Twitter / Flight","path":"flight","path_with_namespace":"twitter/flight","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:54.754Z","last_activity_at":"2016-01-13T20:27:50.502Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":4,"name":"Twitter","path":"twitter","owner_id":null,"created_at":"2016-01-13T20:19:54.480Z","updated_at":"2016-01-13T20:19:54.480Z","description":"Id voluptatem ipsa maiores omnis repudiandae et et.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":true,"open_issues_count":4,"permissions":{"project_access":null,"group_access":{"access_level":10,"notification_level":3}}},{"id":5,"description":"Voluptatem commodi voluptate placeat architecto beatae illum dolores fugiat.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-test.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-test.git","web_url":"http://localhost:3000/gitlab-org/gitlab-test","name":"Gitlab Test","name_with_namespace":"Gitlab Org / Gitlab Test","path":"gitlab-test","path_with_namespace":"gitlab-org/gitlab-test","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:53.202Z","last_activity_at":"2016-01-13T20:27:41.626Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":false,"open_issues_count":5,"permissions":{"project_access":null,"group_access":{"access_level":50,"notification_level":3}}},{"id":4,"description":"Aut molestias quas est ut aperiam officia quod libero.","default_branch":"master","tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-shell.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-shell.git","web_url":"http://localhost:3000/gitlab-org/gitlab-shell","name":"Gitlab Shell","name_with_namespace":"Gitlab Org / Gitlab Shell","path":"gitlab-shell","path_with_namespace":"gitlab-org/gitlab-shell","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:51.882Z","last_activity_at":"2016-01-13T20:27:35.678Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":false,"open_issues_count":5,"permissions":{"project_access":{"access_level":20,"notification_level":3},"group_access":{"access_level":50,"notification_level":3}}},{"id":3,"description":"Excepturi molestiae quia repellendus omnis est illo illum eligendi.","default_branch":"master","tag_list":[],"public":true,"archived":false,"visibility_level":20,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-ci.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-ci.git","web_url":"http://localhost:3000/gitlab-org/gitlab-ci","name":"Gitlab Ci","name_with_namespace":"Gitlab Org / Gitlab Ci","path":"gitlab-ci","path_with_namespace":"gitlab-org/gitlab-ci","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:50.346Z","last_activity_at":"2016-01-13T20:27:30.115Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":false,"open_issues_count":3,"permissions":{"project_access":null,"group_access":{"access_level":50,"notification_level":3}}},{"id":2,"description":"Adipisci quaerat dignissimos enim sed ipsam dolorem quia.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":10,"ssh_url_to_repo":"phil@localhost:gitlab-org/gitlab-ce.git","http_url_to_repo":"http://localhost:3000/gitlab-org/gitlab-ce.git","web_url":"http://localhost:3000/gitlab-org/gitlab-ce","name":"Gitlab Ce","name_with_namespace":"Gitlab Org / Gitlab Ce","path":"gitlab-ce","path_with_namespace":"gitlab-org/gitlab-ce","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:49.065Z","last_activity_at":"2016-01-13T20:26:58.454Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":3,"name":"Gitlab Org","path":"gitlab-org","owner_id":null,"created_at":"2016-01-13T20:19:48.851Z","updated_at":"2016-01-13T20:19:48.851Z","description":"Magni mollitia quod quidem soluta nesciunt impedit.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":false,"open_issues_count":5,"permissions":{"project_access":{"access_level":30,"notification_level":3},"group_access":{"access_level":50,"notification_level":3}}},{"id":1,"description":"Vel voluptatem maxime saepe ex quia.","default_branch":"master","tag_list":[],"public":false,"archived":false,"visibility_level":0,"ssh_url_to_repo":"phil@localhost:documentcloud/underscore.git","http_url_to_repo":"http://localhost:3000/documentcloud/underscore.git","web_url":"http://localhost:3000/documentcloud/underscore","name":"Underscore","name_with_namespace":"Documentcloud / Underscore","path":"underscore","path_with_namespace":"documentcloud/underscore","issues_enabled":true,"merge_requests_enabled":true,"wiki_enabled":true,"builds_enabled":true,"snippets_enabled":false,"created_at":"2016-01-13T20:19:45.862Z","last_activity_at":"2016-01-13T20:25:03.106Z","shared_runners_enabled":true,"creator_id":1,"namespace":{"id":2,"name":"Documentcloud","path":"documentcloud","owner_id":null,"created_at":"2016-01-13T20:19:44.464Z","updated_at":"2016-01-13T20:19:44.464Z","description":"Aut impedit perferendis fuga et ipsa repellat cupiditate et.","avatar":{"url":null}},"avatar_url":null,"star_count":0,"forks_count":0,"only_allow_merge_if_build_succeeds":false,"open_issues_count":5,"permissions":{"project_access":null,"group_access":{"access_level":50,"notification_level":3}}}] diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 4742b3d0e37..63f2467be63 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -224,7 +224,8 @@ describe API::API, api: true do description: FFaker::Lorem.sentence, issues_enabled: false, merge_requests_enabled: false, - wiki_enabled: false + wiki_enabled: false, + only_allow_merge_if_build_succeeds: false }) post api('/projects', user), project @@ -276,6 +277,18 @@ describe API::API, api: true do expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE) end + it 'sets a project as allowing merge even if build fails' do + project = attributes_for(:project, { only_allow_merge_if_build_succeeds: false }) + post api('/projects', user), project + expect(json_response['only_allow_merge_if_build_succeeds']).to be_falsey + end + + it 'sets a project as allowing merge only if build succeeds' do + project = attributes_for(:project, { only_allow_merge_if_build_succeeds: true }) + post api('/projects', user), project + expect(json_response['only_allow_merge_if_build_succeeds']).to be_truthy + end + context 'when a visibility level is restricted' do before do @project = attributes_for(:project, { public: true }) @@ -384,6 +397,18 @@ describe API::API, api: true do expect(json_response['public']).to be_falsey expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE) end + + it 'sets a project as allowing merge even if build fails' do + project = attributes_for(:project, { only_allow_merge_if_build_succeeds: false }) + post api("/projects/user/#{user.id}", admin), project + expect(json_response['only_allow_merge_if_build_succeeds']).to be_falsey + end + + it 'sets a project as allowing merge only if build succeeds' do + project = attributes_for(:project, { only_allow_merge_if_build_succeeds: true }) + post api("/projects/user/#{user.id}", admin), project + expect(json_response['only_allow_merge_if_build_succeeds']).to be_truthy + end end describe "POST /projects/:id/uploads" do @@ -444,6 +469,7 @@ describe API::API, api: true do expect(json_response['shared_with_groups'][0]['group_id']).to eq(group.id) expect(json_response['shared_with_groups'][0]['group_name']).to eq(group.name) expect(json_response['shared_with_groups'][0]['group_access_level']).to eq(link.group_access) + expect(json_response['only_allow_merge_if_build_succeeds']).to eq(project.only_allow_merge_if_build_succeeds) end it 'returns a project by path name' do -- cgit v1.2.1 From ddbdf4e609c70dc6ed88860b5e1e65abde69ee94 Mon Sep 17 00:00:00 2001 From: winniehell Date: Wed, 24 Aug 2016 02:22:30 +0200 Subject: Restore get_id in ExtractsPath --- app/controllers/projects_controller.rb | 9 +-------- lib/extracts_path.rb | 13 ++++++++++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 2a6385c1029..fc52cd2f367 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -5,7 +5,7 @@ class ProjectsController < Projects::ApplicationController before_action :project, except: [:new, :create] before_action :repository, except: [:new, :create] before_action :assign_ref_vars, only: [:show], if: :repo_exists? - before_action :assign_tree_vars, only: [:show], if: [:repo_exists?, :project_view_files?] + before_action :tree, only: [:show], if: [:repo_exists?, :project_view_files?] # Authorize before_action :authorize_admin_project!, only: [:edit, :update, :housekeeping, :download_export, :export, :remove_export, :generate_new_export] @@ -332,11 +332,4 @@ class ProjectsController < Projects::ApplicationController def get_id project.repository.root_ref end - - # ExtractsPath will set @id = project.path on the show route, but it has to be the - # branch name for the tree view to work correctly. - def assign_tree_vars - @id = get_id - tree - end end diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index a293fa2752f..a4558d157c0 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -94,9 +94,7 @@ module ExtractsPath @options = params.select {|key, value| allowed_options.include?(key) && !value.blank? } @options = HashWithIndifferentAccess.new(@options) - @id = params[:id] || params[:ref] - @id += "/" + params[:path] unless params[:path].blank? - + @id = get_id @ref, @path = extract_ref(@id) @repo = @project.repository if @options[:extended_sha1].blank? @@ -118,4 +116,13 @@ module ExtractsPath def tree @tree ||= @repo.tree(@commit.id, @path) end + + private + + # overriden in subclasses, do not remove + def get_id + id = params[:id] || params[:ref] + id += "/" + params[:path] unless params[:path].blank? + id + end end -- cgit v1.2.1 From 5ddb51ba5a4c58db86645424211783af4e390166 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Wed, 24 Aug 2016 11:25:06 +0000 Subject: Update abuse_reports.js.es6 with prettier `window.gl` assignment --- app/assets/javascripts/abuse_reports.js.es6 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/assets/javascripts/abuse_reports.js.es6 b/app/assets/javascripts/abuse_reports.js.es6 index 748084b0307..2fe46b9fd06 100644 --- a/app/assets/javascripts/abuse_reports.js.es6 +++ b/app/assets/javascripts/abuse_reports.js.es6 @@ -1,4 +1,3 @@ -window.gl = window.gl || {}; ((global) => { const MAX_MESSAGE_LENGTH = 500; const MESSAGE_CELL_SELECTOR = '.abuse-reports .message'; @@ -36,4 +35,4 @@ window.gl = window.gl || {}; } global.AbuseReports = AbuseReports; -})(window.gl); +})(window.gl || (window.gl = {})); -- cgit v1.2.1 From 3ae4e1ebf7826340d0a4a15e350c614b6223f06f Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Wed, 24 Aug 2016 15:50:24 +0200 Subject: Use gitlab-workhorse 0.7.11 Versions 0.7.9 and 0.7.10 crash on previously valid 'authBackend' settings. --- GITLAB_WORKHORSE_VERSION | 2 +- doc/install/installation.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index 5b209ea2067..b4d6d12101f 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -0.7.10 +0.7.11 diff --git a/doc/install/installation.md b/doc/install/installation.md index b0ec9b4a961..d4b89fa8345 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -397,7 +397,7 @@ If you are not using Linux you may have to run `gmake` instead of cd /home/git sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git cd gitlab-workhorse - sudo -u git -H git checkout v0.7.10 + sudo -u git -H git checkout v0.7.11 sudo -u git -H make ### Initialize Database and Activate Advanced Features -- cgit v1.2.1 From ae4efc8d5e6a195452f0ecf550198575c63a49b9 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 23 Aug 2016 13:56:21 -0400 Subject: docs: update created_at docs for creating issues via API See also #19863. Fixes #18458. --- doc/api/issues.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/issues.md b/doc/api/issues.md index a665645ad0e..ff8038c78d1 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -323,7 +323,7 @@ POST /projects/:id/issues | `assignee_id` | integer | no | The ID of a user to assign issue | | `milestone_id` | integer | no | The ID of a milestone to assign issue | | `labels` | string | no | Comma-separated label names for an issue | -| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` | +| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) | | `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` | ```bash @@ -384,7 +384,7 @@ PUT /projects/:id/issues/:issue_id | `milestone_id` | integer | no | The ID of a milestone to assign the issue to | | `labels` | string | no | Comma-separated label names for an issue | | `state_event` | string | no | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it | -| `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` | +| `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) | | `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` | ```bash -- cgit v1.2.1 From a5f3bdc5c862944f755f1e61bf965a54e0a6d95d Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 23 Aug 2016 13:57:34 -0400 Subject: docs: fix table alignment --- doc/api/issues.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/issues.md b/doc/api/issues.md index ff8038c78d1..443ba50af73 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -324,7 +324,7 @@ POST /projects/:id/issues | `milestone_id` | integer | no | The ID of a milestone to assign issue | | `labels` | string | no | Comma-separated label names for an issue | | `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) | -| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` | +| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` | ```bash curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues?title=Issues%20with%20auth&labels=bug @@ -385,7 +385,7 @@ PUT /projects/:id/issues/:issue_id | `labels` | string | no | Comma-separated label names for an issue | | `state_event` | string | no | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it | | `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) | -| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` | +| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` | ```bash curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues/85?state_event=close -- cgit v1.2.1 From 9b470aebb993d7a5745f0e9fc17b207fe46b16fe Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 11 Aug 2016 18:11:16 -0400 Subject: url_builder: handle project snippets --- lib/gitlab/url_builder.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/gitlab/url_builder.rb b/lib/gitlab/url_builder.rb index fe65c246101..99d0c28e749 100644 --- a/lib/gitlab/url_builder.rb +++ b/lib/gitlab/url_builder.rb @@ -22,6 +22,8 @@ module Gitlab note_url when WikiPage wiki_page_url + when ProjectSnippet + project_snippet_url(object) else raise NotImplementedError.new("No URL builder defined for #{object.class}") end -- cgit v1.2.1 From e43c4060b67c1996b917bc00afa72122d1d00004 Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 2 Aug 2016 13:37:04 -0400 Subject: api: expose web_url for project entities This allows web hooks to have a URL back to entities without having to generate it themselves. --- CHANGELOG | 1 + doc/api/issues.md | 31 ++++++++++++++++++++---------- doc/api/merge_requests.md | 22 ++++++++++++++------- doc/api/project_snippets.md | 3 ++- lib/api/entities.rb | 12 ++++++++++++ spec/requests/api/issues_spec.rb | 1 + spec/requests/api/merge_requests_spec.rb | 1 + spec/requests/api/project_snippets_spec.rb | 1 + 8 files changed, 54 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ef38d3e29f5..cb3069c1ccd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.12.0 (unreleased) - Change merge_error column from string to text type + - Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel) - Optimistic locking for Issues and Merge Requests (title and description overriding prevention) - Added tests for diff notes diff --git a/doc/api/issues.md b/doc/api/issues.md index a665645ad0e..b5730574308 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -79,7 +79,8 @@ Example response: "labels" : [], "subscribed" : false, "user_notes_count": 1, - "due_date": "2016-07-22" + "due_date": "2016-07-22", + "web_url": "http://example.com/example/example/issues/6" } ] ``` @@ -156,7 +157,8 @@ Example response: "created_at" : "2016-01-04T15:31:46.176Z", "subscribed" : false, "user_notes_count": 1, - "due_date": null + "due_date": null, + "web_url": "http://example.com/example/example/issues/1" } ] ``` @@ -235,7 +237,8 @@ Example response: "created_at" : "2016-01-04T15:31:46.176Z", "subscribed" : false, "user_notes_count": 1, - "due_date": "2016-07-22" + "due_date": "2016-07-22", + "web_url": "http://example.com/example/example/issues/1" } ] ``` @@ -299,7 +302,8 @@ Example response: "created_at" : "2016-01-04T15:31:46.176Z", "subscribed": false, "user_notes_count": 1, - "due_date": null + "due_date": null, + "web_url": "http://example.com/example/example/issues/1" } ``` @@ -357,7 +361,8 @@ Example response: "milestone" : null, "subscribed" : true, "user_notes_count": 0, - "due_date": null + "due_date": null, + "web_url": "http://example.com/example/example/issues/14" } ``` @@ -418,7 +423,8 @@ Example response: "milestone" : null, "subscribed" : true, "user_notes_count": 0, - "due_date": "2016-07-22" + "due_date": "2016-07-22", + "web_url": "http://example.com/example/example/issues/15" } ``` @@ -496,7 +502,8 @@ Example response: "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon", "web_url": "https://gitlab.example.com/u/solon.cremin" }, - "due_date": null + "due_date": null, + "web_url": "http://example.com/example/example/issues/11" } ``` @@ -551,7 +558,8 @@ Example response: "avatar_url": "http://www.gravatar.com/avatar/7a190fecbaa68212a4b68aeb6e3acd10?s=80&d=identicon", "web_url": "https://gitlab.example.com/u/solon.cremin" }, - "due_date": null + "due_date": null, + "web_url": "http://example.com/example/example/issues/11" } ``` @@ -607,7 +615,8 @@ Example response: "web_url": "https://gitlab.example.com/u/orville" }, "subscribed": false, - "due_date": null + "due_date": null, + "web_url": "http://example.com/example/example/issues/12" } ``` @@ -693,7 +702,9 @@ Example response: "subscribed": true, "user_notes_count": 7, "upvotes": 0, - "downvotes": 0 + "downvotes": 0, + "due_date": null, + "web_url": "http://example.com/example/example/issues/110" }, "target_url": "https://gitlab.example.com/gitlab-org/gitlab-ci/issues/10", "body": "Vel voluptas atque dicta mollitia adipisci qui at.", diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 3e88a758936..f275762da3e 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -70,7 +70,8 @@ Parameters: "subscribed" : false, "user_notes_count": 1, "should_remove_source_branch": true, - "force_remove_source_branch": false + "force_remove_source_branch": false, + "web_url": "http://example.com/example/example/merge_requests/1" } ] ``` @@ -136,7 +137,8 @@ Parameters: "subscribed" : true, "user_notes_count": 1, "should_remove_source_branch": true, - "force_remove_source_branch": false + "force_remove_source_branch": false, + "web_url": "http://example.com/example/example/merge_requests/1" } ``` @@ -239,6 +241,7 @@ Parameters: "user_notes_count": 1, "should_remove_source_branch": true, "force_remove_source_branch": false, + "web_url": "http://example.com/example/example/merge_requests/1", "changes": [ { "old_path": "VERSION", @@ -321,7 +324,8 @@ Parameters: "subscribed" : true, "user_notes_count": 0, "should_remove_source_branch": true, - "force_remove_source_branch": false + "force_remove_source_branch": false, + "web_url": "http://example.com/example/example/merge_requests/1" } ``` @@ -395,7 +399,8 @@ Parameters: "subscribed" : true, "user_notes_count": 1, "should_remove_source_branch": true, - "force_remove_source_branch": false + "force_remove_source_branch": false, + "web_url": "http://example.com/example/example/merge_requests/1" } ``` @@ -496,7 +501,8 @@ Parameters: "subscribed" : true, "user_notes_count": 1, "should_remove_source_branch": true, - "force_remove_source_branch": false + "force_remove_source_branch": false, + "web_url": "http://example.com/example/example/merge_requests/1" } ``` @@ -565,7 +571,8 @@ Parameters: "subscribed" : true, "user_notes_count": 1, "should_remove_source_branch": true, - "force_remove_source_branch": false + "force_remove_source_branch": false, + "web_url": "http://example.com/example/example/merge_requests/1" } ``` @@ -886,7 +893,8 @@ Example response: "subscribed": true, "user_notes_count": 7, "should_remove_source_branch": true, - "force_remove_source_branch": false + "force_remove_source_branch": false, + "web_url": "http://example.com/example/example/merge_requests/1" }, "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.", diff --git a/doc/api/project_snippets.md b/doc/api/project_snippets.md index a7acf37b5bc..c6685f54a9d 100644 --- a/doc/api/project_snippets.md +++ b/doc/api/project_snippets.md @@ -53,7 +53,8 @@ Parameters: }, "expires_at": null, "updated_at": "2012-06-28T10:52:04Z", - "created_at": "2012-06-28T10:52:04Z" + "created_at": "2012-06-28T10:52:04Z", + "web_url": "http://example.com/example/example/snippets/1" } ``` diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 66b85ab1793..e6bc23b97d7 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -177,6 +177,10 @@ module API # TODO (rspeicher): Deprecated; remove in 9.0 expose(:expires_at) { |snippet| nil } + + expose :web_url do |snippet, options| + Gitlab::UrlBuilder.build(snippet) + end end class ProjectEntity < Grape::Entity @@ -206,6 +210,10 @@ module API expose :user_notes_count expose :upvotes, :downvotes expose :due_date + + expose :web_url do |issue, options| + Gitlab::UrlBuilder.build(issue) + end end class ExternalIssue < Grape::Entity @@ -229,6 +237,10 @@ module API expose :user_notes_count expose :should_remove_source_branch?, as: :should_remove_source_branch expose :force_remove_source_branch?, as: :force_remove_source_branch + + expose :web_url do |merge_request, options| + Gitlab::UrlBuilder.build(merge_request) + end end class MergeRequestChanges < MergeRequest diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index a40e1a93b71..b8038fc85a1 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -61,6 +61,7 @@ describe API::API, api: true do expect(response).to have_http_status(200) expect(json_response).to be_an Array expect(json_response.first['title']).to eq(issue.title) + expect(json_response.last).to have_key('web_url') end it "adds pagination headers and keep query params" do diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 617600d6173..baff872e28e 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -33,6 +33,7 @@ describe API::API, api: true do expect(json_response).to be_an Array expect(json_response.length).to eq(3) expect(json_response.last['title']).to eq(merge_request.title) + expect(json_response.last).to have_key('web_url') end it "returns an array of all merge_requests" do diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb index 42757ff21b0..01148f0a05e 100644 --- a/spec/requests/api/project_snippets_spec.rb +++ b/spec/requests/api/project_snippets_spec.rb @@ -30,6 +30,7 @@ describe API::API, api: true do expect(response).to have_http_status(200) expect(json_response.size).to eq(3) expect(json_response.map{ |snippet| snippet['id']} ).to include(public_snippet.id, internal_snippet.id, private_snippet.id) + expect(json_response.last).to have_key('web_url') end it 'hides private snippets from regular user' do -- cgit v1.2.1 From f413d7ed8014601497834e5093a1892dd616875b Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 23 Aug 2016 14:51:05 -0400 Subject: docs: document other project webhook fields --- doc/api/projects.md | 7 +++++++ spec/requests/api/project_hooks_spec.rb | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/doc/api/projects.md b/doc/api/projects.md index 37d97b2db44..0905bdea714 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -914,7 +914,10 @@ Parameters: "push_events": true, "issues_events": true, "merge_requests_events": true, + "tag_push_events": true, "note_events": true, + "build_events": true, + "pipeline_events": true, "enable_ssl_verification": true, "created_at": "2012-10-12T17:04:47Z" } @@ -937,6 +940,8 @@ Parameters: - `merge_requests_events` - Trigger hook on merge_requests events - `tag_push_events` - Trigger hook on push_tag events - `note_events` - Trigger hook on note events +- `build_events` - Trigger hook on build events +- `pipeline_events` - Trigger hook on pipeline events - `enable_ssl_verification` - Do SSL verification when triggering the hook ### Edit project hook @@ -957,6 +962,8 @@ Parameters: - `merge_requests_events` - Trigger hook on merge_requests events - `tag_push_events` - Trigger hook on push_tag events - `note_events` - Trigger hook on note events +- `build_events` - Trigger hook on build events +- `pipeline_events` - Trigger hook on pipeline events - `enable_ssl_verification` - Do SSL verification when triggering the hook ### Delete project hook diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb index 914e88c9487..4a585c78edf 100644 --- a/spec/requests/api/project_hooks_spec.rb +++ b/spec/requests/api/project_hooks_spec.rb @@ -57,6 +57,8 @@ describe API::API, 'ProjectHooks', api: true do expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events) expect(json_response['tag_push_events']).to eq(hook.tag_push_events) expect(json_response['note_events']).to eq(hook.note_events) + expect(json_response['build_events']).to eq(hook.build_events) + expect(json_response['pipeline_events']).to eq(hook.pipeline_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) end @@ -118,6 +120,8 @@ describe API::API, 'ProjectHooks', api: true do expect(json_response['merge_requests_events']).to eq(hook.merge_requests_events) expect(json_response['tag_push_events']).to eq(hook.tag_push_events) expect(json_response['note_events']).to eq(hook.note_events) + expect(json_response['build_events']).to eq(hook.build_events) + expect(json_response['pipeline_events']).to eq(hook.pipeline_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) end -- cgit v1.2.1 From 99c2f3b3c534386d1d8258fea23d3991695ff4fe Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Tue, 23 Aug 2016 14:54:44 -0400 Subject: api: expose wiki_page_events project hook field in the API --- CHANGELOG | 1 + doc/api/projects.md | 3 +++ lib/api/entities.rb | 2 +- lib/api/project_hooks.rb | 2 ++ spec/factories/project_hooks.rb | 1 + spec/requests/api/project_hooks_spec.rb | 4 ++++ 6 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index ef38d3e29f5..437e2d5d8fa 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.12.0 (unreleased) - Change merge_error column from string to text type - Optimistic locking for Issues and Merge Requests (title and description overriding prevention) + - Add `wiki_page_events` to project hook APIs (Ben Boeckel) - Added tests for diff notes v 8.11.1 (unreleased) diff --git a/doc/api/projects.md b/doc/api/projects.md index 0905bdea714..156deca932b 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -918,6 +918,7 @@ Parameters: "note_events": true, "build_events": true, "pipeline_events": true, + "wiki_page_events": true, "enable_ssl_verification": true, "created_at": "2012-10-12T17:04:47Z" } @@ -942,6 +943,7 @@ Parameters: - `note_events` - Trigger hook on note events - `build_events` - Trigger hook on build events - `pipeline_events` - Trigger hook on pipeline events +- `wiki_page_events` - Trigger hook on wiki page events - `enable_ssl_verification` - Do SSL verification when triggering the hook ### Edit project hook @@ -964,6 +966,7 @@ Parameters: - `note_events` - Trigger hook on note events - `build_events` - Trigger hook on build events - `pipeline_events` - Trigger hook on pipeline events +- `wiki_page_events` - Trigger hook on wiki page events - `enable_ssl_verification` - Do SSL verification when triggering the hook ### Delete project hook diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 66b85ab1793..3ecdc7d448a 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -49,7 +49,7 @@ module API class ProjectHook < Hook expose :project_id, :push_events expose :issues_events, :merge_requests_events, :tag_push_events - expose :note_events, :build_events, :pipeline_events + expose :note_events, :build_events, :pipeline_events, :wiki_page_events expose :enable_ssl_verification end diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb index 3f63cd678e8..14f5be3b5f6 100644 --- a/lib/api/project_hooks.rb +++ b/lib/api/project_hooks.rb @@ -46,6 +46,7 @@ module API :note_events, :build_events, :pipeline_events, + :wiki_page_events, :enable_ssl_verification ] @hook = user_project.hooks.new(attrs) @@ -80,6 +81,7 @@ module API :note_events, :build_events, :pipeline_events, + :wiki_page_events, :enable_ssl_verification ] diff --git a/spec/factories/project_hooks.rb b/spec/factories/project_hooks.rb index 4fd51a23490..424ecc65759 100644 --- a/spec/factories/project_hooks.rb +++ b/spec/factories/project_hooks.rb @@ -14,6 +14,7 @@ FactoryGirl.define do note_events true build_events true pipeline_events true + wiki_page_events true end end end diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb index 4a585c78edf..765dc8a8f66 100644 --- a/spec/requests/api/project_hooks_spec.rb +++ b/spec/requests/api/project_hooks_spec.rb @@ -34,6 +34,7 @@ describe API::API, 'ProjectHooks', api: true do expect(json_response.first['note_events']).to eq(true) expect(json_response.first['build_events']).to eq(true) expect(json_response.first['pipeline_events']).to eq(true) + expect(json_response.first['wiki_page_events']).to eq(true) expect(json_response.first['enable_ssl_verification']).to eq(true) end end @@ -59,6 +60,7 @@ describe API::API, 'ProjectHooks', api: true do expect(json_response['note_events']).to eq(hook.note_events) expect(json_response['build_events']).to eq(hook.build_events) expect(json_response['pipeline_events']).to eq(hook.pipeline_events) + expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) end @@ -95,6 +97,7 @@ describe API::API, 'ProjectHooks', api: true do expect(json_response['note_events']).to eq(false) expect(json_response['build_events']).to eq(false) expect(json_response['pipeline_events']).to eq(false) + expect(json_response['wiki_page_events']).to eq(false) expect(json_response['enable_ssl_verification']).to eq(true) end @@ -122,6 +125,7 @@ describe API::API, 'ProjectHooks', api: true do expect(json_response['note_events']).to eq(hook.note_events) expect(json_response['build_events']).to eq(hook.build_events) expect(json_response['pipeline_events']).to eq(hook.pipeline_events) + expect(json_response['wiki_page_events']).to eq(hook.wiki_page_events) expect(json_response['enable_ssl_verification']).to eq(hook.enable_ssl_verification) end -- cgit v1.2.1 From 3c09000e18dcbf6a74ed1f749db3184e309cf081 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 10 Aug 2016 18:22:21 -0300 Subject: Does not halt the GitHub import process when an error occurs --- app/models/project.rb | 2 - app/workers/repository_import_worker.rb | 2 + lib/gitlab/github_import/importer.rb | 82 +++++++------ lib/gitlab/github_import/pull_request_formatter.rb | 4 + spec/lib/gitlab/github_import/importer_spec.rb | 129 +++++++++++++++++++++ .../github_import/pull_request_formatter_spec.rb | 11 +- 6 files changed, 194 insertions(+), 36 deletions(-) create mode 100644 spec/lib/gitlab/github_import/importer_spec.rb diff --git a/app/models/project.rb b/app/models/project.rb index 1855760e694..8cf093be4c3 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -471,8 +471,6 @@ class Project < ActiveRecord::Base end def reset_cache_and_import_attrs - update(import_error: nil) - ProjectCacheWorker.perform_async(self.id) self.import_data.destroy if self.import_data diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb index e6701078f71..d2ca8813ab9 100644 --- a/app/workers/repository_import_worker.rb +++ b/app/workers/repository_import_worker.rb @@ -14,6 +14,8 @@ class RepositoryImportWorker import_url: @project.import_url, path: @project.path_with_namespace) + project.update_column(:import_error, nil) + result = Projects::ImportService.new(project, current_user).execute if result[:status] == :error diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index 9ddc8905bd6..86b49a5021a 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -3,12 +3,13 @@ module Gitlab class Importer include Gitlab::ShellAdapter - attr_reader :client, :project, :repo, :repo_url + attr_reader :client, :errors, :project, :repo, :repo_url def initialize(project) @project = project @repo = project.import_source @repo_url = project.import_url + @errors = [] if credentials @client = Client.new(credentials[:user]) @@ -18,8 +19,14 @@ module Gitlab end def execute - import_labels && import_milestones && import_issues && - import_pull_requests && import_wiki + import_labels + import_milestones + import_issues + import_pull_requests + import_wiki + handle_errors + + true end private @@ -28,22 +35,32 @@ module Gitlab @credentials ||= project.import_data.credentials if project.import_data end + def handle_errors + project.update_column(:import_error, errors.to_json) unless errors.empty? + end + def import_labels labels = client.labels(repo, per_page: 100) - labels.each { |raw| LabelFormatter.new(project, raw).create! } - true - rescue ActiveRecord::RecordInvalid => e - raise Projects::ImportService::Error, e.message + labels.each do |raw| + begin + LabelFormatter.new(project, raw).create! + rescue => e + errors << { type: :label, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message } + end + end end def import_milestones milestones = client.milestones(repo, state: :all, per_page: 100) - milestones.each { |raw| MilestoneFormatter.new(project, raw).create! } - true - rescue ActiveRecord::RecordInvalid => e - raise Projects::ImportService::Error, e.message + milestones.each do |raw| + begin + MilestoneFormatter.new(project, raw).create! + rescue => e + errors << { type: :milestone, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message } + end + end end def import_issues @@ -53,15 +70,15 @@ module Gitlab gh_issue = IssueFormatter.new(project, raw) if gh_issue.valid? - issue = gh_issue.create! - apply_labels(issue) - import_comments(issue) if gh_issue.has_comments? + begin + issue = gh_issue.create! + apply_labels(issue) + import_comments(issue) if gh_issue.has_comments? + rescue => e + errors << { type: :issue, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message } + end end end - - true - rescue ActiveRecord::RecordInvalid => e - raise Projects::ImportService::Error, e.message end def import_pull_requests @@ -77,14 +94,12 @@ module Gitlab apply_labels(merge_request) import_comments(merge_request) import_comments_on_diff(merge_request) - rescue ActiveRecord::RecordInvalid => e - raise Projects::ImportService::Error, e.message + rescue => e + errors << { type: :pull_request, url: Gitlab::UrlSanitizer.sanitize(pull_request.url), errors: e.message } ensure clean_up_restored_branches(pull_request) end end - - true end def restore_source_branch(pull_request) @@ -98,7 +113,7 @@ module Gitlab def remove_branch(name) project.repository.delete_branch(name) rescue Rugged::ReferenceError - nil + errors << { type: :remove_branch, name: name } end def clean_up_restored_branches(pull_request) @@ -112,9 +127,10 @@ module Gitlab issue = client.issue(repo, issuable.iid) if issue.labels.count > 0 - label_ids = issue.labels.map do |raw| - Label.find_by(LabelFormatter.new(project, raw).attributes).try(:id) - end + label_ids = issue.labels + .map { |raw| LabelFormatter.new(project, raw).attributes } + .map { |attrs| Label.find_by(attrs).try(:id) } + .compact issuable.update_attribute(:label_ids, label_ids) end @@ -132,8 +148,12 @@ module Gitlab def create_comments(issuable, comments) comments.each do |raw| - comment = CommentFormatter.new(project, raw) - issuable.notes.create!(comment.attributes) + begin + comment = CommentFormatter.new(project, raw) + issuable.notes.create!(comment.attributes) + rescue => e + errors << { type: :comment, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message } + end end end @@ -143,16 +163,12 @@ module Gitlab gitlab_shell.import_repository(project.repository_storage_path, wiki.path_with_namespace, wiki.import_url) project.update_attribute(:wiki_enabled, true) end - - true rescue Gitlab::Shell::Error => e # GitHub error message when the wiki repo has not been created, # this means that repo has wiki enabled, but have no pages. So, # we can skip the import. if e.message !~ /repository not exported/ - raise Projects::ImportService::Error, e.message - else - true + errors << { type: :wiki, errors: e.message } end end end diff --git a/lib/gitlab/github_import/pull_request_formatter.rb b/lib/gitlab/github_import/pull_request_formatter.rb index b84538a090a..04aa3664f64 100644 --- a/lib/gitlab/github_import/pull_request_formatter.rb +++ b/lib/gitlab/github_import/pull_request_formatter.rb @@ -56,6 +56,10 @@ module Gitlab end end + def url + raw_data.url + end + private def assigned? diff --git a/spec/lib/gitlab/github_import/importer_spec.rb b/spec/lib/gitlab/github_import/importer_spec.rb new file mode 100644 index 00000000000..2c8d86ef9b6 --- /dev/null +++ b/spec/lib/gitlab/github_import/importer_spec.rb @@ -0,0 +1,129 @@ +require 'spec_helper' + +describe Gitlab::GithubImport::Importer, lib: true do + describe '#execute' do + context 'when an error occurs' do + let(:project) { create(:project, import_url: 'https://github.com/octocat/Hello-World.git', wiki_enabled: false) } + let(:octocat) { double(id: 123456, login: 'octocat') } + let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') } + let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } + let(:repository) { double(id: 1, fork: false) } + let(:source_sha) { create(:commit, project: project).id } + let(:source_branch) { double(ref: 'feature', repo: repository, sha: source_sha) } + let(:target_sha) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit).id } + let(:target_branch) { double(ref: 'master', repo: repository, sha: target_sha) } + + let(:label) do + double( + name: 'Bug', + color: 'ff0000', + url: 'https://api.github.com/repos/octocat/Hello-World/labels/bug' + ) + end + + let(:milestone) do + double( + number: 1347, + state: 'open', + title: '1.0', + description: 'Version 1.0', + due_on: nil, + created_at: created_at, + updated_at: updated_at, + closed_at: nil, + url: 'https://api.github.com/repos/octocat/Hello-World/milestones/1' + ) + end + + let(:issue1) do + double( + number: 1347, + milestone: nil, + state: 'open', + title: 'Found a bug', + body: "I'm having a problem with this.", + assignee: nil, + user: octocat, + comments: 0, + pull_request: nil, + created_at: created_at, + updated_at: updated_at, + closed_at: nil, + url: 'https://api.github.com/repos/octocat/Hello-World/issues/1347' + ) + end + + let(:issue2) do + double( + number: 1348, + milestone: nil, + state: 'open', + title: nil, + body: "I'm having a problem with this.", + assignee: nil, + user: octocat, + comments: 0, + pull_request: nil, + created_at: created_at, + updated_at: updated_at, + closed_at: nil, + url: 'https://api.github.com/repos/octocat/Hello-World/issues/1348' + ) + end + + let(:pull_request) do + double( + number: 1347, + milestone: nil, + state: 'open', + title: 'New feature', + body: 'Please pull these awesome changes', + head: source_branch, + base: target_branch, + assignee: nil, + user: octocat, + created_at: created_at, + updated_at: updated_at, + closed_at: nil, + merged_at: nil, + url: 'https://api.github.com/repos/octocat/Hello-World/pulls/1347' + ) + end + + before do + allow(project).to receive(:import_data).and_return(double.as_null_object) + allow_any_instance_of(Octokit::Client).to receive(:rate_limit!).and_raise(Octokit::NotFound) + allow_any_instance_of(Octokit::Client).to receive(:labels).and_return([label, label]) + allow_any_instance_of(Octokit::Client).to receive(:milestones).and_return([milestone, milestone]) + allow_any_instance_of(Octokit::Client).to receive(:issues).and_return([issue1, issue2]) + allow_any_instance_of(Octokit::Client).to receive(:pull_requests).and_return([pull_request, pull_request]) + allow_any_instance_of(Octokit::Client).to receive(:last_response).and_return(double(rels: { next: nil })) + allow_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_raise(Gitlab::Shell::Error) + end + + it 'returns true' do + expect(described_class.new(project).execute).to eq true + end + + it 'does not raise an error' do + expect { described_class.new(project).execute }.not_to raise_error + end + + it 'stores error messages' do + errors = [ + { type: :label, url: "https://api.github.com/repos/octocat/Hello-World/labels/bug", errors: "Validation failed: Title has already been taken" }, + { type: :milestone, url: "https://api.github.com/repos/octocat/Hello-World/milestones/1", errors: "Validation failed: Title has already been taken" }, + { type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1347", errors: "Invalid Repository. Use user/repo format." }, + { type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1348", errors: "Validation failed: Title can't be blank, Title is too short (minimum is 0 characters)" }, + { type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Invalid Repository. Use user/repo format." }, + { type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Validation failed: Validate branches Cannot Create: This merge request already exists: [\"New feature\"]" }, + { type: :wiki, errors: "Gitlab::Shell::Error" } + ] + + described_class.new(project).execute + + expect(project.import_error).to eq errors.to_json + end + end + end +end diff --git a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb index aa28e360993..b667abf063d 100644 --- a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb @@ -27,7 +27,8 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do created_at: created_at, updated_at: updated_at, closed_at: nil, - merged_at: nil + merged_at: nil, + url: 'https://api.github.com/repos/octocat/Hello-World/pulls/1347' } end @@ -229,4 +230,12 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end end end + + describe '#url' do + let(:raw_data) { double(base_data) } + + it 'return raw url' do + expect(pull_request.url).to eq 'https://api.github.com/repos/octocat/Hello-World/pulls/1347' + end + end end -- cgit v1.2.1 From 2986de7c8c63c0a90f750adbfd843d3b2d50e25f Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 24 Aug 2016 12:14:06 -0300 Subject: Add readable error message when remote data could not be fully imported --- lib/gitlab/github_import/importer.rb | 7 ++++++- spec/lib/gitlab/github_import/importer_spec.rb | 23 +++++++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index 86b49a5021a..02ffb43d89b 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -36,7 +36,12 @@ module Gitlab end def handle_errors - project.update_column(:import_error, errors.to_json) unless errors.empty? + return unless errors.any? + + project.update_column(:import_error, { + message: 'The remote data could not be fully imported.', + errors: errors + }.to_json) end def import_labels diff --git a/spec/lib/gitlab/github_import/importer_spec.rb b/spec/lib/gitlab/github_import/importer_spec.rb index 2c8d86ef9b6..b7c3bc4e1a7 100644 --- a/spec/lib/gitlab/github_import/importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer_spec.rb @@ -110,19 +110,22 @@ describe Gitlab::GithubImport::Importer, lib: true do end it 'stores error messages' do - errors = [ - { type: :label, url: "https://api.github.com/repos/octocat/Hello-World/labels/bug", errors: "Validation failed: Title has already been taken" }, - { type: :milestone, url: "https://api.github.com/repos/octocat/Hello-World/milestones/1", errors: "Validation failed: Title has already been taken" }, - { type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1347", errors: "Invalid Repository. Use user/repo format." }, - { type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1348", errors: "Validation failed: Title can't be blank, Title is too short (minimum is 0 characters)" }, - { type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Invalid Repository. Use user/repo format." }, - { type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Validation failed: Validate branches Cannot Create: This merge request already exists: [\"New feature\"]" }, - { type: :wiki, errors: "Gitlab::Shell::Error" } - ] + error = { + message: 'The remote data could not be fully imported.', + errors: [ + { type: :label, url: "https://api.github.com/repos/octocat/Hello-World/labels/bug", errors: "Validation failed: Title has already been taken" }, + { type: :milestone, url: "https://api.github.com/repos/octocat/Hello-World/milestones/1", errors: "Validation failed: Title has already been taken" }, + { type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1347", errors: "Invalid Repository. Use user/repo format." }, + { type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1348", errors: "Validation failed: Title can't be blank, Title is too short (minimum is 0 characters)" }, + { type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Invalid Repository. Use user/repo format." }, + { type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Validation failed: Validate branches Cannot Create: This merge request already exists: [\"New feature\"]" }, + { type: :wiki, errors: "Gitlab::Shell::Error" } + ] + } described_class.new(project).execute - expect(project.import_error).to eq errors.to_json + expect(project.import_error).to eq error.to_json end end end -- cgit v1.2.1 From 8e52705776dce7021ac1a150253037f085638a46 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 24 Aug 2016 13:04:26 -0300 Subject: Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index ef38d3e29f5..b3cb9d4b3e1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,7 @@ v 8.12.0 (unreleased) - Added tests for diff notes v 8.11.1 (unreleased) + - Does not halt the GitHub import process when an error occurs - Fix file links on project page when default view is Files !5933 v 8.11.0 -- cgit v1.2.1 From 60ac1167d1324b4468e3ae85000feb2bf78a24e2 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Wed, 24 Aug 2016 11:29:18 -0500 Subject: Remove max height on pipelines graph --- app/assets/stylesheets/pages/pipelines.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 6fa097e3bf1..dcb3e48d686 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -254,7 +254,6 @@ width: 100%; overflow: auto; white-space: nowrap; - max-height: 500px; transition: max-height 0.3s, padding 0.3s; &.graph-collapsed { -- cgit v1.2.1 From cfe512d6e926a3f757d18e5269214c06b8f9643d Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Wed, 24 Aug 2016 13:13:26 +0200 Subject: Show "Create Merge Request" widget for push events to fork projects on the source project --- CHANGELOG | 3 +++ app/helpers/projects_helper.rb | 21 ++++++++++---------- app/models/user.rb | 4 ++-- spec/helpers/projects_helper_spec.rb | 38 ++++++++++++++++++++++++++++++++++++ spec/models/user_spec.rb | 10 ++++++++++ 5 files changed, 64 insertions(+), 12 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index ef38d3e29f5..65796fd808c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,9 @@ v 8.12.0 (unreleased) - Optimistic locking for Issues and Merge Requests (title and description overriding prevention) - Added tests for diff notes +v 8.11.2 (unreleased) + - Show "Create Merge Request" widget for push events to fork projects on the source project + v 8.11.1 (unreleased) - Fix file links on project page when default view is Files !5933 diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 249d18c4486..356f27f2d5d 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -116,6 +116,17 @@ module ProjectsHelper license.nickname || license.name end + def last_push_event + return unless current_user + + project_ids = [@project.id] + if fork = current_user.fork_of(@project) + project_ids << fork.id + end + + current_user.recent_push(project_ids) + end + private def get_project_nav_tabs(project, current_user) @@ -351,16 +362,6 @@ module ProjectsHelper namespace_project_new_blob_path(@project.namespace, @project, tree_join(ref), file_name: 'LICENSE') end - def last_push_event - return unless current_user - - if fork = current_user.fork_of(@project) - current_user.recent_push(fork.id) - else - current_user.recent_push(@project.id) - end - end - def readme_cache_key sha = @project.commit.try(:sha) || 'nil' [@project.path_with_namespace, sha, "readme"].join('-') diff --git a/app/models/user.rb b/app/models/user.rb index 48e83ab7e56..ad3cfbc03e4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -489,10 +489,10 @@ class User < ActiveRecord::Base (personal_projects.count.to_f / projects_limit) * 100 end - def recent_push(project_id = nil) + def recent_push(project_ids = nil) # Get push events not earlier than 2 hours ago events = recent_events.code_push.where("created_at > ?", Time.now - 2.hours) - events = events.where(project_id: project_id) if project_id + events = events.where(project_id: project_ids) if project_ids # Use the latest event that has not been pushed or merged recently events.recent.find do |event| diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 604204cca0a..284b58d8d5c 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -136,4 +136,42 @@ describe ProjectsHelper do expect(sanitize_repo_path(project, import_error)).to eq('Could not clone [REPOS PATH]/namespace/test.git') end end + + describe '#last_push_event' do + let(:user) { double(:user, fork_of: nil) } + let(:project) { double(:project, id: 1) } + + before do + allow(helper).to receive(:current_user).and_return(user) + helper.instance_variable_set(:@project, project) + end + + context 'when there is no current_user' do + let(:user) { nil } + + it 'returns nil' do + expect(helper.last_push_event).to eq(nil) + end + end + + it 'returns recent push on the current project' do + event = double(:event) + expect(user).to receive(:recent_push).with([project.id]).and_return(event) + + expect(helper.last_push_event).to eq(event) + end + + context 'when current user has a fork of the current project' do + let(:fork) { double(:fork, id: 2) } + + it 'returns recent push considering fork events' do + expect(user).to receive(:fork_of).with(project).and_return(fork) + + event_on_fork = double(:event) + expect(user).to receive(:recent_push).with([project.id, fork.id]).and_return(event_on_fork) + + expect(helper.last_push_event).to eq(event_on_fork) + end + end + end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 51e4780e2b1..8eb0c5033c9 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -920,6 +920,16 @@ describe User, models: true do expect(subject.recent_push).to eq(nil) end + + it "includes push events on any of the provided projects" do + expect(subject.recent_push(project1)).to eq(nil) + expect(subject.recent_push(project2)).to eq(push_event) + + push_data1 = Gitlab::DataBuilder::Push.build_sample(project1, subject) + push_event1 = create(:event, action: Event::PUSHED, project: project1, target: project1, author: subject, data: push_data1) + + expect(subject.recent_push([project1, project2])).to eq(push_event1) # Newest + end end describe '#authorized_groups' do -- cgit v1.2.1 From 170885edd6f3ea52792511586778e0dce8021cf7 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 18 Aug 2016 17:06:33 -0700 Subject: Add Sentry logging to API calls Closes #21043 --- CHANGELOG | 1 + app/controllers/application_controller.rb | 23 +--------------------- app/helpers/sentry_helper.rb | 27 ++++++++++++++++++++++++++ lib/api/api.rb | 12 ++---------- lib/api/helpers.rb | 32 +++++++++++++++++++++++++++++++ lib/ci/api/api.rb | 12 ++---------- spec/requests/api/api_helpers_spec.rb | 27 ++++++++++++++++++++++++++ 7 files changed, 92 insertions(+), 42 deletions(-) create mode 100644 app/helpers/sentry_helper.rb diff --git a/CHANGELOG b/CHANGELOG index 3e6066cfae0..ea9ebf740e1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ v 8.12.0 (unreleased) - Change merge_error column from string to text type - Optimistic locking for Issues and Merge Requests (title and description overriding prevention) - Add `wiki_page_events` to project hook APIs (Ben Boeckel) + - Add Sentry logging to API calls - Added tests for diff notes v 8.11.2 (unreleased) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 634d36a4467..70a2275592b 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -6,6 +6,7 @@ class ApplicationController < ActionController::Base include Gitlab::GonHelper include GitlabRoutingHelper include PageLayoutHelper + include SentryHelper include WorkhorseHelper before_action :authenticate_user_from_private_token! @@ -46,28 +47,6 @@ class ApplicationController < ActionController::Base protected - def sentry_context - if Rails.env.production? && current_application_settings.sentry_enabled - if current_user - Raven.user_context( - id: current_user.id, - email: current_user.email, - username: current_user.username, - ) - end - - Raven.tags_context(program: sentry_program_context) - end - end - - def sentry_program_context - if Sidekiq.server? - 'sidekiq' - else - 'rails' - end - end - # This filter handles both private tokens and personal access tokens def authenticate_user_from_private_token! token_string = params[:private_token].presence || request.headers['PRIVATE-TOKEN'].presence diff --git a/app/helpers/sentry_helper.rb b/app/helpers/sentry_helper.rb new file mode 100644 index 00000000000..f8cccade15b --- /dev/null +++ b/app/helpers/sentry_helper.rb @@ -0,0 +1,27 @@ +module SentryHelper + def sentry_enabled? + Rails.env.production? && current_application_settings.sentry_enabled? + end + + def sentry_context + return unless sentry_enabled? + + if current_user + Raven.user_context( + id: current_user.id, + email: current_user.email, + username: current_user.username, + ) + end + + Raven.tags_context(program: sentry_program_context) + end + + def sentry_program_context + if Sidekiq.server? + 'sidekiq' + else + 'rails' + end + end +end diff --git a/lib/api/api.rb b/lib/api/api.rb index 6b8bfbbdae6..ecbd5a6e2fa 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -18,22 +18,14 @@ module API end rescue_from :all do |exception| - # lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60 - # why is this not wrapped in something reusable? - trace = exception.backtrace - - message = "\n#{exception.class} (#{exception.message}):\n" - message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code) - message << " " << trace.join("\n ") - - API.logger.add Logger::FATAL, message - rack_response({ 'message' => '500 Internal Server Error' }.to_json, 500) + handle_api_exception(exception) end format :json content_type :txt, "text/plain" # Ensure the namespace is right, otherwise we might load Grape::API::Helpers + helpers ::SentryHelper helpers ::API::Helpers mount ::API::AccessRequests diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index d0469d6602d..da4b1bf9902 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -279,6 +279,24 @@ module API error!({ 'message' => message }, status) end + def handle_api_exception(exception) + if sentry_enabled? && report_exception?(exception) + define_params_for_grape_middleware + sentry_context + Raven.capture_exception(exception) + end + + # lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60 + trace = exception.backtrace + + message = "\n#{exception.class} (#{exception.message}):\n" + message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code) + message << " " << trace.join("\n ") + + API.logger.add Logger::FATAL, message + rack_response({ 'message' => '500 Internal Server Error' }.to_json, 500) + end + # Projects helpers def filter_projects(projects) @@ -419,5 +437,19 @@ module API Entities::Issue end end + + # The Grape Error Middleware only has access to env but no params. We workaround this by + # defining a method that returns the right value. + def define_params_for_grape_middleware + self.define_singleton_method(:params) { Rack::Request.new(env).params.symbolize_keys } + end + + # We could get a Grape or a standard Ruby exception. We should only report anything that + # is clearly an error. + def report_exception?(exception) + return true unless exception.respond_to?(:status) + + exception.status == 500 + end end end diff --git a/lib/ci/api/api.rb b/lib/ci/api/api.rb index 17bb99a2ae5..a6b9beecded 100644 --- a/lib/ci/api/api.rb +++ b/lib/ci/api/api.rb @@ -9,22 +9,14 @@ module Ci end rescue_from :all do |exception| - # lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60 - # why is this not wrapped in something reusable? - trace = exception.backtrace - - message = "\n#{exception.class} (#{exception.message}):\n" - message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code) - message << " " << trace.join("\n ") - - API.logger.add Logger::FATAL, message - rack_response({ 'message' => '500 Internal Server Error' }, 500) + handle_api_exception(exception) end content_type :txt, 'text/plain' content_type :json, 'application/json' format :json + helpers ::SentryHelper helpers ::Ci::API::Helpers helpers ::API::Helpers helpers Gitlab::CurrentSettings diff --git a/spec/requests/api/api_helpers_spec.rb b/spec/requests/api/api_helpers_spec.rb index c65510fadec..bbdf8f03c2b 100644 --- a/spec/requests/api/api_helpers_spec.rb +++ b/spec/requests/api/api_helpers_spec.rb @@ -3,6 +3,7 @@ require 'spec_helper' describe API::Helpers, api: true do include API::Helpers include ApiHelpers + include SentryHelper let(:user) { create(:user) } let(:admin) { create(:admin) } @@ -234,4 +235,30 @@ describe API::Helpers, api: true do expect(to_boolean(nil)).to be_nil end end + + describe '.handle_api_exception' do + before do + allow_any_instance_of(self.class).to receive(:sentry_enabled?).and_return(true) + allow_any_instance_of(self.class).to receive(:rack_response) + end + + it 'does not report a MethodNotAllowed exception to Sentry' do + exception = Grape::Exceptions::MethodNotAllowed.new({ 'X-GitLab-Test' => '1' }) + allow(exception).to receive(:backtrace).and_return(caller) + + expect(Raven).not_to receive(:capture_exception).with(exception) + + handle_api_exception(exception) + end + + it 'does report RuntimeError to Sentry' do + exception = RuntimeError.new('test error') + allow(exception).to receive(:backtrace).and_return(caller) + + expect_any_instance_of(self.class).to receive(:sentry_context) + expect(Raven).to receive(:capture_exception).with(exception) + + handle_api_exception(exception) + end + end end -- cgit v1.2.1 From bba85773519e972d036a933b1f054b6c76050c5f Mon Sep 17 00:00:00 2001 From: Drew Blessing Date: Tue, 26 Jul 2016 16:48:51 -0500 Subject: Add two factor recovery endpoint to internal API --- CHANGELOG | 1 + doc/README.md | 1 + doc/user/account/security.md | 3 ++ doc/user/account/two_factor_authentication.md | 68 +++++++++++++++++++++++++++ lib/api/internal.rb | 25 ++++++++++ spec/requests/api/internal_spec.rb | 62 ++++++++++++++++++++++++ 6 files changed, 160 insertions(+) create mode 100644 doc/user/account/security.md create mode 100644 doc/user/account/two_factor_authentication.md diff --git a/CHANGELOG b/CHANGELOG index 8b25b94b772..346618b0160 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.12.0 (unreleased) + - Add two-factor recovery endpoint to internal API !5510 - Change merge_error column from string to text type - Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel) - Optimistic locking for Issues and Merge Requests (title and description overriding prevention) diff --git a/doc/README.md b/doc/README.md index 195b7c7af62..047035dfb09 100644 --- a/doc/README.md +++ b/doc/README.md @@ -2,6 +2,7 @@ ## User documentation +- [Account Security](user/account/security.md) Securing your account via two-factor authentication, etc. - [API](api/README.md) Automate GitLab via a simple and powerful API. - [CI/CD](ci/README.md) GitLab Continuous Integration (CI) and Continuous Delivery (CD) getting started, `.gitlab-ci.yml` options, and examples. - [GitLab as OAuth2 authentication service provider](integration/oauth_provider.md). It allows you to login to other applications from GitLab. diff --git a/doc/user/account/security.md b/doc/user/account/security.md new file mode 100644 index 00000000000..816094bf8d2 --- /dev/null +++ b/doc/user/account/security.md @@ -0,0 +1,3 @@ +# Account Security + +- [Two-Factor Authentication](two_factor_authentication.md) diff --git a/doc/user/account/two_factor_authentication.md b/doc/user/account/two_factor_authentication.md new file mode 100644 index 00000000000..881358ed94d --- /dev/null +++ b/doc/user/account/two_factor_authentication.md @@ -0,0 +1,68 @@ +# Two-Factor Authentication + +## Recovery options + +If you lose your code generation device (such as your mobile phone) and you need +to disable two-factor authentication on your account, you have several options. + +### Use a saved recovery code + +When you enabled two-factor authentication for your account, a series of +recovery codes were generated. If you saved those codes somewhere safe, you +may use one to sign in. + +First, enter your username/email and password on the GitLab sign in page. When +prompted for a two-factor code, enter one of the recovery codes you saved +previously. + +> **Note:** Once a particular recovery code has been used, it cannot be used again. + You may still use the other saved recovery codes at a later time. + +### Generate new recovery codes using SSH + +It's not uncommon for users to forget to save the recovery codes when enabling +two-factor authentication. If you have an SSH key added to your GitLab account, +you can generate a new set of recovery codes using SSH. + +Run `ssh git@gitlab.example.com 2fa_recovery_codes`. You will be prompted to +confirm that you wish to generate new codes. If you choose to continue, any +previously saved codes will be invalidated. + +```bash +$ ssh git@gitlab.example.com 2fa_recovery_codes +Are you sure you want to generate new two-factor recovery codes? +Any existing recovery codes you saved will be invalidated. (yes/no) +yes + +Your two-factor authentication recovery codes are: + +119135e5a3ebce8e +11f6v2a498810dcd +3924c7ab2089c902 +e79a3398bfe4f224 +34bd7b74adbc8861 +f061691d5107df1a +169bf32a18e63e7f +b510e7422e81c947 +20dbed24c5e74663 +df9d3b9403b9c9f0 + +During sign in, use one of the codes above when prompted for +your two-factor code. Then, visit your Profile Settings and add +a new device so you do not lose access to your account again. +``` + +Next, go to the GitLab sign in page and enter your username/email and password. +When prompted for a two-factor code, enter one of the recovery codes obtained +from the command line output. + +> **Note:** After signing in, you should immediately visit your **Profile Settings + -> Account** to set up two-factor authentication with a new device. + +### Ask a GitLab administrator to disable two-factor on your account + +If the above two methods are not possible, you may ask a GitLab global +administrator to disable two-factor authentication for your account. Please +be aware that this will temporarily leave your account in a less secure state. +You should sign in and re-enable two-factor authentication as soon as possible +after the administrator disables it. diff --git a/lib/api/internal.rb b/lib/api/internal.rb index d8e9ac406c4..5b54c11ef62 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -101,6 +101,31 @@ module API {} end end + + post '/two_factor_recovery_codes' do + status 200 + + key = Key.find(params[:key_id]) + user = key.user + + # Make sure this isn't a deploy key + unless key.type.nil? + return { success: false, message: 'Deploy keys cannot be used to retrieve recovery codes' } + end + + unless user.present? + return { success: false, message: 'Could not find a user for the given key' } + end + + unless user.two_factor_enabled? + return { success: false, message: 'Two-factor authentication is not enabled for this user' } + end + + codes = user.generate_otp_backup_codes! + user.save! + + { success: true, recovery_codes: codes } + end end end end diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index be52f88831f..5d06abcfeb3 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -38,6 +38,68 @@ describe API::API, api: true do end end + describe 'GET /internal/two_factor_recovery_codes' do + it 'returns an error message when the key does not exist' do + post api('/internal/two_factor_recovery_codes'), + secret_token: secret_token, + key_id: 12345 + + expect(response).to have_http_status(404) + expect(json_response['message']).to eq('404 Not found') + end + + it 'returns an error message when the key is a deploy key' do + deploy_key = create(:deploy_key) + + post api('/internal/two_factor_recovery_codes'), + secret_token: secret_token, + key_id: deploy_key.id + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq('Deploy keys cannot be used to retrieve recovery codes') + end + + it 'returns an error message when the user does not exist' do + key_without_user = create(:key, user: nil) + + post api('/internal/two_factor_recovery_codes'), + secret_token: secret_token, + key_id: key_without_user.id + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq('Could not find a user for the given key') + expect(json_response['recovery_codes']).to be_nil + end + + context 'when two-factor is enabled' do + it 'returns new recovery codes when the user exists' do + allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(true) + allow_any_instance_of(User) + .to receive(:generate_otp_backup_codes!).and_return(%w(119135e5a3ebce8e 34bd7b74adbc8861)) + + post api('/internal/two_factor_recovery_codes'), + secret_token: secret_token, + key_id: key.id + + expect(json_response['success']).to be_truthy + expect(json_response['recovery_codes']).to match_array(%w(119135e5a3ebce8e 34bd7b74adbc8861)) + end + end + + context 'when two-factor is not enabled' do + it 'returns an error message' do + allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(false) + + post api('/internal/two_factor_recovery_codes'), + secret_token: secret_token, + key_id: key.id + + expect(json_response['success']).to be_falsey + expect(json_response['recovery_codes']).to be_nil + end + end + end + describe "GET /internal/discover" do it do get(api("/internal/discover"), key_id: key.id, secret_token: secret_token) -- cgit v1.2.1 From 23bed91b3fb21a92b836011677cc75c884188f10 Mon Sep 17 00:00:00 2001 From: De Wet Blomerus Date: Thu, 25 Aug 2016 04:55:32 +0200 Subject: rename Statuseable to HasStatus --- app/models/ci/pipeline.rb | 2 +- app/models/commit_status.rb | 2 +- app/models/concerns/has_status.rb | 93 ++++++++++++++++++++ app/models/concerns/statuseable.rb | 93 -------------------- app/services/ci/process_pipeline_service.rb | 2 +- spec/models/concerns/has_status_spec.rb | 129 ++++++++++++++++++++++++++++ spec/models/concerns/statuseable_spec.rb | 129 ---------------------------- 7 files changed, 225 insertions(+), 225 deletions(-) create mode 100644 app/models/concerns/has_status.rb delete mode 100644 app/models/concerns/statuseable.rb create mode 100644 spec/models/concerns/has_status_spec.rb delete mode 100644 spec/models/concerns/statuseable_spec.rb diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 087abe4cbb1..255fb33bdeb 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -1,7 +1,7 @@ module Ci class Pipeline < ActiveRecord::Base extend Ci::Model - include Statuseable + include HasStatus self.table_name = 'ci_commits' diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 84ceeac7d3e..9114af18496 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -1,5 +1,5 @@ class CommitStatus < ActiveRecord::Base - include Statuseable + include HasStatus include Importable self.table_name = 'ci_builds' diff --git a/app/models/concerns/has_status.rb b/app/models/concerns/has_status.rb new file mode 100644 index 00000000000..f7b8352405c --- /dev/null +++ b/app/models/concerns/has_status.rb @@ -0,0 +1,93 @@ +module HasStatus + extend ActiveSupport::Concern + + AVAILABLE_STATUSES = %w[created pending running success failed canceled skipped] + STARTED_STATUSES = %w[running success failed skipped] + ACTIVE_STATUSES = %w[pending running] + COMPLETED_STATUSES = %w[success failed canceled] + + class_methods do + def status_sql + scope = all.relevant + builds = scope.select('count(*)').to_sql + success = scope.success.select('count(*)').to_sql + ignored = scope.ignored.select('count(*)').to_sql if scope.respond_to?(:ignored) + ignored ||= '0' + pending = scope.pending.select('count(*)').to_sql + running = scope.running.select('count(*)').to_sql + canceled = scope.canceled.select('count(*)').to_sql + skipped = scope.skipped.select('count(*)').to_sql + + deduce_status = "(CASE + WHEN (#{builds})=0 THEN NULL + WHEN (#{builds})=(#{skipped}) THEN 'skipped' + WHEN (#{builds})=(#{success})+(#{ignored})+(#{skipped}) THEN 'success' + WHEN (#{builds})=(#{pending})+(#{skipped}) THEN 'pending' + WHEN (#{builds})=(#{canceled})+(#{success})+(#{ignored})+(#{skipped}) THEN 'canceled' + WHEN (#{running})+(#{pending})>0 THEN 'running' + ELSE 'failed' + END)" + + deduce_status + end + + def status + all.pluck(self.status_sql).first + end + + def started_at + all.minimum(:started_at) + end + + def finished_at + all.maximum(:finished_at) + end + end + + included do + validates :status, inclusion: { in: AVAILABLE_STATUSES } + + state_machine :status, initial: :created do + state :created, value: 'created' + state :pending, value: 'pending' + state :running, value: 'running' + state :failed, value: 'failed' + state :success, value: 'success' + state :canceled, value: 'canceled' + state :skipped, value: 'skipped' + end + + scope :created, -> { where(status: 'created') } + scope :relevant, -> { where.not(status: 'created') } + scope :running, -> { where(status: 'running') } + scope :pending, -> { where(status: 'pending') } + scope :success, -> { where(status: 'success') } + scope :failed, -> { where(status: 'failed') } + scope :canceled, -> { where(status: 'canceled') } + scope :skipped, -> { where(status: 'skipped') } + scope :running_or_pending, -> { where(status: [:running, :pending]) } + scope :finished, -> { where(status: [:success, :failed, :canceled]) } + end + + def started? + STARTED_STATUSES.include?(status) && started_at + end + + def active? + ACTIVE_STATUSES.include?(status) + end + + def complete? + COMPLETED_STATUSES.include?(status) + end + + private + + def calculate_duration + if started_at && finished_at + finished_at - started_at + elsif started_at + Time.now - started_at + end + end +end diff --git a/app/models/concerns/statuseable.rb b/app/models/concerns/statuseable.rb deleted file mode 100644 index 750f937b724..00000000000 --- a/app/models/concerns/statuseable.rb +++ /dev/null @@ -1,93 +0,0 @@ -module Statuseable - extend ActiveSupport::Concern - - AVAILABLE_STATUSES = %w[created pending running success failed canceled skipped] - STARTED_STATUSES = %w[running success failed skipped] - ACTIVE_STATUSES = %w[pending running] - COMPLETED_STATUSES = %w[success failed canceled] - - class_methods do - def status_sql - scope = all.relevant - builds = scope.select('count(*)').to_sql - success = scope.success.select('count(*)').to_sql - ignored = scope.ignored.select('count(*)').to_sql if scope.respond_to?(:ignored) - ignored ||= '0' - pending = scope.pending.select('count(*)').to_sql - running = scope.running.select('count(*)').to_sql - canceled = scope.canceled.select('count(*)').to_sql - skipped = scope.skipped.select('count(*)').to_sql - - deduce_status = "(CASE - WHEN (#{builds})=0 THEN NULL - WHEN (#{builds})=(#{skipped}) THEN 'skipped' - WHEN (#{builds})=(#{success})+(#{ignored})+(#{skipped}) THEN 'success' - WHEN (#{builds})=(#{pending})+(#{skipped}) THEN 'pending' - WHEN (#{builds})=(#{canceled})+(#{success})+(#{ignored})+(#{skipped}) THEN 'canceled' - WHEN (#{running})+(#{pending})>0 THEN 'running' - ELSE 'failed' - END)" - - deduce_status - end - - def status - all.pluck(self.status_sql).first - end - - def started_at - all.minimum(:started_at) - end - - def finished_at - all.maximum(:finished_at) - end - end - - included do - validates :status, inclusion: { in: AVAILABLE_STATUSES } - - state_machine :status, initial: :created do - state :created, value: 'created' - state :pending, value: 'pending' - state :running, value: 'running' - state :failed, value: 'failed' - state :success, value: 'success' - state :canceled, value: 'canceled' - state :skipped, value: 'skipped' - end - - scope :created, -> { where(status: 'created') } - scope :relevant, -> { where.not(status: 'created') } - scope :running, -> { where(status: 'running') } - scope :pending, -> { where(status: 'pending') } - scope :success, -> { where(status: 'success') } - scope :failed, -> { where(status: 'failed') } - scope :canceled, -> { where(status: 'canceled') } - scope :skipped, -> { where(status: 'skipped') } - scope :running_or_pending, -> { where(status: [:running, :pending]) } - scope :finished, -> { where(status: [:success, :failed, :canceled]) } - end - - def started? - STARTED_STATUSES.include?(status) && started_at - end - - def active? - ACTIVE_STATUSES.include?(status) - end - - def complete? - COMPLETED_STATUSES.include?(status) - end - - private - - def calculate_duration - if started_at && finished_at - finished_at - started_at - elsif started_at - Time.now - started_at - end - end -end diff --git a/app/services/ci/process_pipeline_service.rb b/app/services/ci/process_pipeline_service.rb index 6f7610d42ba..f049ed628db 100644 --- a/app/services/ci/process_pipeline_service.rb +++ b/app/services/ci/process_pipeline_service.rb @@ -34,7 +34,7 @@ module Ci end def process_build(build, current_status) - return false unless Statuseable::COMPLETED_STATUSES.include?(current_status) + return false unless HasStatus::COMPLETED_STATUSES.include?(current_status) if valid_statuses_for_when(build.when).include?(current_status) build.enqueue diff --git a/spec/models/concerns/has_status_spec.rb b/spec/models/concerns/has_status_spec.rb new file mode 100644 index 00000000000..e118432d098 --- /dev/null +++ b/spec/models/concerns/has_status_spec.rb @@ -0,0 +1,129 @@ +require 'spec_helper' + +describe HasStatus do + before do + @object = Object.new + @object.extend(HasStatus::ClassMethods) + end + + describe '.status' do + before do + allow(@object).to receive(:all).and_return(CommitStatus.where(id: statuses)) + end + + subject { @object.status } + + shared_examples 'build status summary' do + context 'all successful' do + let(:statuses) { Array.new(2) { create(type, status: :success) } } + it { is_expected.to eq 'success' } + end + + context 'at least one failed' do + let(:statuses) do + [create(type, status: :success), create(type, status: :failed)] + end + + it { is_expected.to eq 'failed' } + end + + context 'at least one running' do + let(:statuses) do + [create(type, status: :success), create(type, status: :running)] + end + + it { is_expected.to eq 'running' } + end + + context 'at least one pending' do + let(:statuses) do + [create(type, status: :success), create(type, status: :pending)] + end + + it { is_expected.to eq 'running' } + end + + context 'success and failed but allowed to fail' do + let(:statuses) do + [create(type, status: :success), + create(type, status: :failed, allow_failure: true)] + end + + it { is_expected.to eq 'success' } + end + + context 'one failed but allowed to fail' do + let(:statuses) { [create(type, status: :failed, allow_failure: true)] } + it { is_expected.to eq 'success' } + end + + context 'success and canceled' do + let(:statuses) do + [create(type, status: :success), create(type, status: :canceled)] + end + + it { is_expected.to eq 'canceled' } + end + + context 'one failed and one canceled' do + let(:statuses) do + [create(type, status: :failed), create(type, status: :canceled)] + end + + it { is_expected.to eq 'failed' } + end + + context 'one failed but allowed to fail and one canceled' do + let(:statuses) do + [create(type, status: :failed, allow_failure: true), + create(type, status: :canceled)] + end + + it { is_expected.to eq 'canceled' } + end + + context 'one running one canceled' do + let(:statuses) do + [create(type, status: :running), create(type, status: :canceled)] + end + + it { is_expected.to eq 'running' } + end + + context 'all canceled' do + let(:statuses) do + [create(type, status: :canceled), create(type, status: :canceled)] + end + it { is_expected.to eq 'canceled' } + end + + context 'success and canceled but allowed to fail' do + let(:statuses) do + [create(type, status: :success), + create(type, status: :canceled, allow_failure: true)] + end + + it { is_expected.to eq 'success' } + end + + context 'one finished and second running but allowed to fail' do + let(:statuses) do + [create(type, status: :success), + create(type, status: :running, allow_failure: true)] + end + + it { is_expected.to eq 'running' } + end + end + + context 'ci build statuses' do + let(:type) { :ci_build } + it_behaves_like 'build status summary' + end + + context 'generic commit statuses' do + let(:type) { :generic_commit_status } + it_behaves_like 'build status summary' + end + end +end diff --git a/spec/models/concerns/statuseable_spec.rb b/spec/models/concerns/statuseable_spec.rb deleted file mode 100644 index 8e0a2a2cbde..00000000000 --- a/spec/models/concerns/statuseable_spec.rb +++ /dev/null @@ -1,129 +0,0 @@ -require 'spec_helper' - -describe Statuseable do - before do - @object = Object.new - @object.extend(Statuseable::ClassMethods) - end - - describe '.status' do - before do - allow(@object).to receive(:all).and_return(CommitStatus.where(id: statuses)) - end - - subject { @object.status } - - shared_examples 'build status summary' do - context 'all successful' do - let(:statuses) { Array.new(2) { create(type, status: :success) } } - it { is_expected.to eq 'success' } - end - - context 'at least one failed' do - let(:statuses) do - [create(type, status: :success), create(type, status: :failed)] - end - - it { is_expected.to eq 'failed' } - end - - context 'at least one running' do - let(:statuses) do - [create(type, status: :success), create(type, status: :running)] - end - - it { is_expected.to eq 'running' } - end - - context 'at least one pending' do - let(:statuses) do - [create(type, status: :success), create(type, status: :pending)] - end - - it { is_expected.to eq 'running' } - end - - context 'success and failed but allowed to fail' do - let(:statuses) do - [create(type, status: :success), - create(type, status: :failed, allow_failure: true)] - end - - it { is_expected.to eq 'success' } - end - - context 'one failed but allowed to fail' do - let(:statuses) { [create(type, status: :failed, allow_failure: true)] } - it { is_expected.to eq 'success' } - end - - context 'success and canceled' do - let(:statuses) do - [create(type, status: :success), create(type, status: :canceled)] - end - - it { is_expected.to eq 'canceled' } - end - - context 'one failed and one canceled' do - let(:statuses) do - [create(type, status: :failed), create(type, status: :canceled)] - end - - it { is_expected.to eq 'failed' } - end - - context 'one failed but allowed to fail and one canceled' do - let(:statuses) do - [create(type, status: :failed, allow_failure: true), - create(type, status: :canceled)] - end - - it { is_expected.to eq 'canceled' } - end - - context 'one running one canceled' do - let(:statuses) do - [create(type, status: :running), create(type, status: :canceled)] - end - - it { is_expected.to eq 'running' } - end - - context 'all canceled' do - let(:statuses) do - [create(type, status: :canceled), create(type, status: :canceled)] - end - it { is_expected.to eq 'canceled' } - end - - context 'success and canceled but allowed to fail' do - let(:statuses) do - [create(type, status: :success), - create(type, status: :canceled, allow_failure: true)] - end - - it { is_expected.to eq 'success' } - end - - context 'one finished and second running but allowed to fail' do - let(:statuses) do - [create(type, status: :success), - create(type, status: :running, allow_failure: true)] - end - - it { is_expected.to eq 'running' } - end - end - - context 'ci build statuses' do - let(:type) { :ci_build } - it_behaves_like 'build status summary' - end - - context 'generic commit statuses' do - let(:type) { :generic_commit_status } - it_behaves_like 'build status summary' - end - end -end -- cgit v1.2.1 From 33694a5a6465785c2fcd5c8217197070cbd7b316 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Tue, 2 Aug 2016 10:16:41 -0500 Subject: use gitlab global root url as canonical base url for all javascript set cookies (closes #20435) --- CHANGELOG | 1 + app/assets/javascripts/activities.js | 2 +- app/assets/javascripts/application.js | 4 ++-- app/assets/javascripts/awards_handler.js | 1 + app/assets/javascripts/project.js | 8 ++------ app/assets/javascripts/right_sidebar.js | 2 +- app/assets/javascripts/user.js | 4 +--- spec/javascripts/awards_handler_spec.js | 32 ++++++++++++++++++++++++++++++-- 8 files changed, 39 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 518e80a360a..245219531aa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ v 8.12.0 (unreleased) - Add two-factor recovery endpoint to internal API !5510 - Change merge_error column from string to text type - Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel) + - Set path for all JavaScript cookies to honor GitLab's subdirectory setting !5627 (Mike Greiling) - Optimistic locking for Issues and Merge Requests (title and description overriding prevention) - Add `wiki_page_events` to project hook APIs (Ben Boeckel) - Add Sentry logging to API calls diff --git a/app/assets/javascripts/activities.js b/app/assets/javascripts/activities.js index 1ab3c2197d8..5ea6086ab77 100644 --- a/app/assets/javascripts/activities.js +++ b/app/assets/javascripts/activities.js @@ -26,7 +26,7 @@ event_filters = $.cookie("event_filter"); filter = sender.attr("id").split("_")[0]; $.cookie("event_filter", (event_filters !== filter ? filter : ""), { - path: '/' + path: gon.relative_url_root || '/' }); if (event_filters !== filter) { return sender.closest('li').toggleClass("active"); diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index fc354dfd677..43a679501a7 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -288,7 +288,7 @@ new Aside(); if ($window.width() < 1024 && $.cookie('pin_nav') === 'true') { $.cookie('pin_nav', 'false', { - path: '/', + path: gon.relative_url_root || '/', expires: 365 * 10 }); $('.page-with-sidebar').toggleClass('page-sidebar-collapsed page-sidebar-expanded').removeClass('page-sidebar-pinned'); @@ -313,7 +313,7 @@ $topNav.removeClass('header-pinned-nav').toggleClass('header-collapsed header-expanded'); } $.cookie('pin_nav', doPinNav, { - path: '/', + path: gon.relative_url_root || '/', expires: 365 * 10 }); if ($.cookie('pin_nav') === 'true' || doPinNav) { diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js index aee1c29eee3..ad12cb906e1 100644 --- a/app/assets/javascripts/awards_handler.js +++ b/app/assets/javascripts/awards_handler.js @@ -320,6 +320,7 @@ frequentlyUsedEmojis = this.getFrequentlyUsedEmojis(); frequentlyUsedEmojis.push(emoji); return $.cookie('frequently_used_emojis', frequentlyUsedEmojis.join(','), { + path: gon.relative_url_root || '/', expires: 365 }); }; diff --git a/app/assets/javascripts/project.js b/app/assets/javascripts/project.js index 4e1de4dfb72..66e097c0a28 100644 --- a/app/assets/javascripts/project.js +++ b/app/assets/javascripts/project.js @@ -17,19 +17,15 @@ return $(this).parents('form').submit(); }); $('.hide-no-ssh-message').on('click', function(e) { - var path; - path = '/'; $.cookie('hide_no_ssh_message', 'false', { - path: path + path: gon.relative_url_root || '/' }); $(this).parents('.no-ssh-key-message').remove(); return e.preventDefault(); }); $('.hide-no-password-message').on('click', function(e) { - var path; - path = '/'; $.cookie('hide_no_password_message', 'false', { - path: path + path: gon.relative_url_root || '/' }); $(this).parents('.no-password-message').remove(); return e.preventDefault(); diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js index dc4d5113826..e3d5f413c77 100644 --- a/app/assets/javascripts/right_sidebar.js +++ b/app/assets/javascripts/right_sidebar.js @@ -30,7 +30,7 @@ } if (!triggered) { return $.cookie("collapsed_gutter", $('.right-sidebar').hasClass('right-sidebar-collapsed'), { - path: '/' + path: gon.relative_url_root || '/' }); } }); diff --git a/app/assets/javascripts/user.js b/app/assets/javascripts/user.js index b46390ad8f4..6c4d88cf407 100644 --- a/app/assets/javascripts/user.js +++ b/app/assets/javascripts/user.js @@ -7,10 +7,8 @@ }); this.initTabs(); $('.hide-project-limit-message').on('click', function(e) { - var path; - path = '/'; $.cookie('hide_project_limit_message', 'false', { - path: path + path: gon.relative_url_root || '/' }); $(this).parents('.project-limit-message').remove(); return e.preventDefault(); diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js index fa32d0d7da5..c1c12b57b53 100644 --- a/spec/javascripts/awards_handler_spec.js +++ b/spec/javascripts/awards_handler_spec.js @@ -11,7 +11,7 @@ /*= require ./fixtures/emoji_menu */ (function() { - var awardsHandler, lazyAssert; + var awardsHandler, lazyAssert, urlRoot; awardsHandler = null; @@ -27,6 +27,7 @@ }; gon.award_menu_url = '/emojis'; + urlRoot = gon.relative_url_root; lazyAssert = function(done, assertFn) { return setTimeout(function() { @@ -45,9 +46,14 @@ return cb(); }; })(this)); - return spyOn(jQuery, 'get').and.callFake(function(req, cb) { + spyOn(jQuery, 'get').and.callFake(function(req, cb) { return cb(window.emojiMenu); }); + spyOn(jQuery, 'cookie'); + }); + afterEach(function() { + // restore original url root value + gon.relative_url_root = urlRoot; }); describe('::showEmojiMenu', function() { it('should show emoji menu when Add emoji button clicked', function(done) { @@ -189,6 +195,28 @@ return expect($thumbsUpEmoji.data("original-title")).toBe('sam'); }); }); + describe('::addEmojiToFrequentlyUsedList', function() { + it('should set a cookie with the correct default path', function() { + gon.relative_url_root = ''; + awardsHandler.addEmojiToFrequentlyUsedList('sunglasses'); + expect(jQuery.cookie) + .toHaveBeenCalledWith('frequently_used_emojis', 'sunglasses', { + path: '/', + expires: 365 + }) + ; + }); + it('should set a cookie with the correct custom root path', function() { + gon.relative_url_root = '/gitlab/subdir'; + awardsHandler.addEmojiToFrequentlyUsedList('alien'); + expect(jQuery.cookie) + .toHaveBeenCalledWith('frequently_used_emojis', 'alien', { + path: '/gitlab/subdir', + expires: 365 + }) + ; + }); + }); describe('search', function() { return it('should filter the emoji', function() { $('.js-add-award').eq(0).click(); -- cgit v1.2.1 From 96051549672084fabec9f67b1cf03c59e8ac3370 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sun, 31 Jul 2016 20:17:19 -0500 Subject: Automatically expand hidden discussions when accessed via a permalink hash (closes #19304) --- CHANGELOG | 1 + .../javascripts/behaviors/toggler_behavior.js | 30 +++++++++++++++++----- app/assets/javascripts/lib/utils/url_utility.js | 12 ++++++++- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 518e80a360a..46dfe2fd355 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,7 @@ v 8.12.0 (unreleased) - Optimistic locking for Issues and Merge Requests (title and description overriding prevention) - Add `wiki_page_events` to project hook APIs (Ben Boeckel) - Add Sentry logging to API calls + - Automatically expand hidden discussions when accessed by a permalink !5585 (Mike Greiling) - Added tests for diff notes - Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck) diff --git a/app/assets/javascripts/behaviors/toggler_behavior.js b/app/assets/javascripts/behaviors/toggler_behavior.js index 1b7b63489ea..8ac1ba7665e 100644 --- a/app/assets/javascripts/behaviors/toggler_behavior.js +++ b/app/assets/javascripts/behaviors/toggler_behavior.js @@ -1,10 +1,26 @@ -(function() { +(function(w) { $(function() { - return $("body").on("click", ".js-toggle-button", function(e) { - $(this).find('i').toggleClass('fa fa-chevron-down').toggleClass('fa fa-chevron-up'); - $(this).closest(".js-toggle-container").find(".js-toggle-content").toggle(); - return e.preventDefault(); + $('.js-toggle-button').on('click', function(e) { + e.preventDefault(); + $(this) + .find('.fa') + .toggleClass('fa-chevron-down fa-chevron-up') + .end() + .closest('.js-toggle-container') + .find('.js-toggle-content') + .toggle() + ; }); - }); -}).call(this); + // If we're accessing a permalink, ensure it is not inside a + // closed js-toggle-container! + var hash = w.gl.utils.getLocationHash(); + var anchor = hash && document.getElementById(hash); + var container = anchor && $(anchor).closest('.js-toggle-container'); + + if (container && container.find('.js-toggle-content').is(':hidden')) { + container.find('.js-toggle-button').trigger('click'); + anchor.scrollIntoView(); + } + }); +})(window); diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js index fffbfd19745..533310cc87c 100644 --- a/app/assets/javascripts/lib/utils/url_utility.js +++ b/app/assets/javascripts/lib/utils/url_utility.js @@ -43,7 +43,7 @@ } return newUrl; }; - return w.gl.utils.removeParamQueryString = function(url, param) { + w.gl.utils.removeParamQueryString = function(url, param) { var urlVariables, variables; url = decodeURIComponent(url); urlVariables = url.split('&'); @@ -59,6 +59,16 @@ return results; })()).join('&'); }; + w.gl.utils.getLocationHash = function(url) { + var hashIndex; + if (typeof url === 'undefined') { + // Note: We can't use window.location.hash here because it's + // not consistent across browsers - Firefox will pre-decode it + url = window.location.href; + } + hashIndex = url.indexOf('#'); + return hashIndex === -1 ? null : url.substring(hashIndex + 1); + }; })(window); }).call(this); -- cgit v1.2.1 From f8a7430b00cfe410b0274b8963f0de017ef098ee Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 24 Aug 2016 23:13:38 -0500 Subject: Fix unnecessary horizontal scroll area in pipeline visualizations --- app/assets/stylesheets/pages/pipelines.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 6fa097e3bf1..7eb4e7ec676 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -265,7 +265,6 @@ .pipeline-visualization { position: relative; - min-width: 1220px; ul { padding: 0; -- cgit v1.2.1 From 7629dc9982f5559972acf9d9b9d98f78ad53e54c Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Fri, 12 Aug 2016 17:38:09 +0200 Subject: Add specs to ensure a successful return on the UI when mark as done a already done todo. --- app/services/todo_service.rb | 3 ++- spec/features/todos/todos_spec.rb | 21 +++++++++++++++++++++ spec/services/todo_service_spec.rb | 21 +++++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb index e0ccb654590..2aab8c736d6 100644 --- a/app/services/todo_service.rb +++ b/app/services/todo_service.rb @@ -148,7 +148,8 @@ class TodoService def mark_todos_as_done_by_ids(ids, current_user) todos = current_user.todos.where(id: ids) - marked_todos = todos.update_all(state: :done) + # Only return those that are not really on that state + marked_todos = todos.where.not(state: :done).update_all(state: :done) current_user.update_todos_count_cache marked_todos end diff --git a/spec/features/todos/todos_spec.rb b/spec/features/todos/todos_spec.rb index 0342f4f1d97..32544f3f538 100644 --- a/spec/features/todos/todos_spec.rb +++ b/spec/features/todos/todos_spec.rb @@ -41,6 +41,27 @@ describe 'Dashboard Todos', feature: true do expect(page).to have_content("You're all done!") end end + + context 'todo is stale on the page' do + before do + todos = TodosFinder.new(user, state: :pending).execute + TodoService.new.mark_todos_as_done(todos, user) + end + + describe 'deleting the todo' do + before do + first('.done-todo').click + end + + it 'is removed from the list' do + expect(page).not_to have_selector('.todos-list .todo') + end + + it 'shows "All done" message' do + expect(page).to have_content("You're all done!") + end + end + end end context 'User has Todos with labels spanning multiple projects' do diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb index 296fd1bd5a4..cafcad3e3c0 100644 --- a/spec/services/todo_service_spec.rb +++ b/spec/services/todo_service_spec.rb @@ -496,6 +496,7 @@ describe TodoService, services: true do describe '#mark_todos_as_done' do let(:issue) { create(:issue, project: project, author: author, assignee: john_doe) } + let(:another_issue) { create(:issue, project: project, author: author, assignee: john_doe) } it 'marks a relation of todos as done' do create(:todo, :mentioned, user: john_doe, target: issue, project: project) @@ -518,6 +519,26 @@ describe TodoService, services: true do expect(TodoService.new.mark_todos_as_done([todo], john_doe)).to eq(1) end + context 'when some of the todos are done already' do + before do + create(:todo, :mentioned, user: john_doe, target: issue, project: project) + create(:todo, :mentioned, user: john_doe, target: another_issue, project: project) + end + + it 'returns the number of those still pending' do + TodoService.new.mark_pending_todos_as_done(issue, john_doe) + + expect(TodoService.new.mark_todos_as_done(Todo.all, john_doe)).to eq(1) + end + + it 'returns 0 if all are done' do + TodoService.new.mark_pending_todos_as_done(issue, john_doe) + TodoService.new.mark_pending_todos_as_done(another_issue, john_doe) + + expect(TodoService.new.mark_todos_as_done(Todo.all, john_doe)).to eq(0) + end + end + it 'caches the number of todos of a user', :caching do create(:todo, :mentioned, user: john_doe, target: issue, project: project) todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project) -- cgit v1.2.1 From 89fcdbe84c8591b72a2730658ece24f94551a1e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Steinblock?= Date: Thu, 25 Aug 2016 04:56:48 +0000 Subject: removed redundant word --- doc/workflow/merge_requests.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/workflow/merge_requests.md b/doc/workflow/merge_requests.md index 91fcfb02d39..334a119e522 100644 --- a/doc/workflow/merge_requests.md +++ b/doc/workflow/merge_requests.md @@ -53,7 +53,7 @@ It should look like this: fetch = +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/* ``` -Now you can fetch all the merge requests requests: +Now you can fetch all the merge requests: ``` $ git fetch origin -- cgit v1.2.1 From 44eb3197a9c30503a00384b3d688b64558b80397 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Tue, 23 Aug 2016 16:37:14 +0100 Subject: Handle non-UTF-8 conflicts gracefully These can't be resolved in the UI because if they aren't in a UTF-8 compatible encoding, they can't be rendered as JSON. Even if they could, we would be implicitly changing the file encoding anyway, which seems like a bad idea. --- CHANGELOG | 3 +++ doc/user/project/merge_requests/resolve_conflicts.md | 1 + lib/gitlab/conflict/parser.rb | 9 +++++++++ spec/features/merge_requests/conflicts_spec.rb | 3 ++- spec/lib/gitlab/conflict/parser_spec.rb | 5 +++++ spec/support/test_env.rb | 3 ++- 6 files changed, 22 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 518e80a360a..05517de501a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,9 @@ v 8.12.0 (unreleased) - Added tests for diff notes - Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck) +v 8.11.3 (unreleased) + - Don't try to show merge conflict resolution info if a merge conflict contains non-UTF-8 characters + v 8.11.2 (unreleased) - Show "Create Merge Request" widget for push events to fork projects on the source project diff --git a/doc/user/project/merge_requests/resolve_conflicts.md b/doc/user/project/merge_requests/resolve_conflicts.md index 44b76ffc8e6..4d7225bd820 100644 --- a/doc/user/project/merge_requests/resolve_conflicts.md +++ b/doc/user/project/merge_requests/resolve_conflicts.md @@ -26,6 +26,7 @@ this is similar to performing `git checkout feature; git merge master` locally. GitLab allows resolving conflicts in a file where all of the below are true: - The file is text, not binary +- The file is in a UTF-8 compatible encoding - The file does not already contain conflict markers - The file, with conflict markers added, is not over 200 KB in size - The file exists under the same path in both branches diff --git a/lib/gitlab/conflict/parser.rb b/lib/gitlab/conflict/parser.rb index 6eccded7872..2d4d55daeeb 100644 --- a/lib/gitlab/conflict/parser.rb +++ b/lib/gitlab/conflict/parser.rb @@ -13,10 +13,19 @@ module Gitlab class UnmergeableFile < ParserError end + class UnsupportedEncoding < ParserError + end + def parse(text, our_path:, their_path:, parent_file: nil) raise UnmergeableFile if text.blank? # Typically a binary file raise UnmergeableFile if text.length > 102400 + begin + text.to_json + rescue Encoding::UndefinedConversionError + raise UnsupportedEncoding + end + line_obj_index = 0 line_old = 1 line_new = 1 diff --git a/spec/features/merge_requests/conflicts_spec.rb b/spec/features/merge_requests/conflicts_spec.rb index 930c36ade2b..759edf8ec80 100644 --- a/spec/features/merge_requests/conflicts_spec.rb +++ b/spec/features/merge_requests/conflicts_spec.rb @@ -43,7 +43,8 @@ feature 'Merge request conflict resolution', js: true, feature: true do 'conflict-too-large' => 'when the conflicts contain a large file', 'conflict-binary-file' => 'when the conflicts contain a binary file', 'conflict-contains-conflict-markers' => 'when the conflicts contain a file with ambiguous conflict markers', - 'conflict-missing-side' => 'when the conflicts contain a file edited in one branch and deleted in another' + 'conflict-missing-side' => 'when the conflicts contain a file edited in one branch and deleted in another', + 'conflict-non-utf8' => 'when the conflicts contain a non-UTF-8 file', } UNRESOLVABLE_CONFLICTS.each do |source_branch, description| diff --git a/spec/lib/gitlab/conflict/parser_spec.rb b/spec/lib/gitlab/conflict/parser_spec.rb index 65a828accde..a1d2ca1e272 100644 --- a/spec/lib/gitlab/conflict/parser_spec.rb +++ b/spec/lib/gitlab/conflict/parser_spec.rb @@ -183,6 +183,11 @@ CONFLICT expect { parse_text('a' * 102401) }. to raise_error(Gitlab::Conflict::Parser::UnmergeableFile) end + + it 'raises UnsupportedEncoding when the file contains non-UTF-8 characters' do + expect { parse_text("a\xC4\xFC".force_encoding(Encoding::ASCII_8BIT)) }. + to raise_error(Gitlab::Conflict::Parser::UnsupportedEncoding) + end end end end diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index edbbfc3c9e5..c7a45fc4ff9 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -24,11 +24,12 @@ module TestEnv 'expand-collapse-lines' => '238e82d', 'video' => '8879059', 'crlf-diff' => '5938907', - 'conflict-start' => '14fa46b', + 'conflict-start' => '75284c7', 'conflict-resolvable' => '1450cd6', 'conflict-binary-file' => '259a6fb', 'conflict-contains-conflict-markers' => '5e0964c', 'conflict-missing-side' => 'eb227b3', + 'conflict-non-utf8' => 'd0a293c', 'conflict-too-large' => '39fa04f', } -- cgit v1.2.1 From 085e1f89f327ad4d679696fe4673d09e1840b236 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Wed, 24 Aug 2016 18:06:19 +0100 Subject: Handle unavailable system info For Linux with the grsecurity patches applied, paths in `/proc` may not be readable, so handle those cases and show a message rather than blowing up. --- CHANGELOG | 3 ++ app/controllers/admin/system_info_controller.rb | 8 ++--- app/views/admin/system_info/show.html.haml | 12 +++++-- spec/features/admin/admin_system_info_spec.rb | 47 ++++++++++++++++++++++--- 4 files changed, 57 insertions(+), 13 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 518e80a360a..f43eeb34d37 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,9 @@ v 8.12.0 (unreleased) - Added tests for diff notes - Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck) +v 8.11.3 (unreleased) + - Allow system info page to handle case where info is unavailable + v 8.11.2 (unreleased) - Show "Create Merge Request" widget for push events to fork projects on the source project diff --git a/app/controllers/admin/system_info_controller.rb b/app/controllers/admin/system_info_controller.rb index e4c73008826..ca04a17caa1 100644 --- a/app/controllers/admin/system_info_controller.rb +++ b/app/controllers/admin/system_info_controller.rb @@ -29,7 +29,8 @@ class Admin::SystemInfoController < Admin::ApplicationController ] def show - system_info = Vmstat.snapshot + @cpus = Vmstat.cpu rescue nil + @memory = Vmstat.memory rescue nil mounts = Sys::Filesystem.mounts @disks = [] @@ -50,10 +51,5 @@ class Admin::SystemInfoController < Admin::ApplicationController rescue Sys::Filesystem::Error end end - - @cpus = system_info.cpus.length - - @mem_used = system_info.memory.active_bytes - @mem_total = system_info.memory.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 6956e5ab795..7f3b95699db 100644 --- a/app/views/admin/system_info/show.html.haml +++ b/app/views/admin/system_info/show.html.haml @@ -9,12 +9,20 @@ .light-well %h4 CPU .data - %h1= "#{@cpus} cores" + - if @cpus + %h1= "#{@cpus.length} cores" + - else + %i.fa.fa-warning.text-warning + Unable to collect CPU info .col-sm-4 .light-well %h4 Memory .data - %h1= "#{number_to_human_size(@mem_used)} / #{number_to_human_size(@mem_total)}" + - if @memory + %h1= "#{number_to_human_size(@memory.active_bytes)} / #{number_to_human_size(@memory.total_bytes)}" + - else + %i.fa.fa-warning.text-warning + Unable to collect memory info .col-sm-4 .light-well %h4 Disks diff --git a/spec/features/admin/admin_system_info_spec.rb b/spec/features/admin/admin_system_info_spec.rb index f4e5c26b519..1df972843e2 100644 --- a/spec/features/admin/admin_system_info_spec.rb +++ b/spec/features/admin/admin_system_info_spec.rb @@ -6,12 +6,49 @@ describe 'Admin System Info' do end describe 'GET /admin/system_info' do - it 'shows system info page' do - visit admin_system_info_path + let(:cpu) { double(:cpu, length: 2) } + let(:memory) { double(:memory, active_bytes: 4294967296, total_bytes: 17179869184) } - expect(page).to have_content 'CPU' - expect(page).to have_content 'Memory' - expect(page).to have_content 'Disks' + context 'when all info is available' do + before do + allow(Vmstat).to receive(:cpu).and_return(cpu) + allow(Vmstat).to receive(:memory).and_return(memory) + visit admin_system_info_path + end + + it 'shows system info page' do + expect(page).to have_content 'CPU 2 cores' + expect(page).to have_content 'Memory 4 GB / 16 GB' + expect(page).to have_content 'Disks' + end + end + + context 'when CPU info is not available' do + before do + allow(Vmstat).to receive(:cpu).and_raise(Errno::ENOENT) + allow(Vmstat).to receive(:memory).and_return(memory) + visit admin_system_info_path + end + + it 'shows system info page with no CPU info' do + expect(page).to have_content 'CPU Unable to collect CPU info' + expect(page).to have_content 'Memory 4 GB / 16 GB' + expect(page).to have_content 'Disks' + end + end + + context 'when memory info is not available' do + before do + allow(Vmstat).to receive(:cpu).and_return(cpu) + allow(Vmstat).to receive(:memory).and_raise(Errno::ENOENT) + visit admin_system_info_path + end + + it 'shows system info page with no CPU info' do + expect(page).to have_content 'CPU 2 cores' + expect(page).to have_content 'Memory Unable to collect memory info' + expect(page).to have_content 'Disks' + end end end end -- cgit v1.2.1 From 3d98494815b9cb574a82c1e8b566ac9c2fadc1da Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 25 Aug 2016 08:30:17 +0100 Subject: Update vmstat for {Open,Net}BSD support --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 68547b6fac8..194379dd687 100644 --- a/Gemfile +++ b/Gemfile @@ -349,5 +349,5 @@ gem 'paranoia', '~> 2.0' gem 'health_check', '~> 2.1.0' # System information -gem 'vmstat', '~> 2.1.1' +gem 'vmstat', '~> 2.2' gem 'sys-filesystem', '~> 1.1.6' diff --git a/Gemfile.lock b/Gemfile.lock index 5511d718938..0c28975060c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -772,7 +772,7 @@ GEM coercible (~> 1.0) descendants_tracker (~> 0.0, >= 0.0.3) equalizer (~> 0.0, >= 0.0.9) - vmstat (2.1.1) + vmstat (2.2.0) warden (1.2.6) rack (>= 1.0) web-console (2.3.0) @@ -980,7 +980,7 @@ DEPENDENCIES unicorn-worker-killer (~> 0.4.2) version_sorter (~> 2.1.0) virtus (~> 1.0.1) - vmstat (~> 2.1.1) + vmstat (~> 2.2) web-console (~> 2.0) webmock (~> 1.21.0) wikicloth (= 0.8.1) -- cgit v1.2.1 From d64c15c5c391e8f49a9f261ba0e59bafb99d97fe Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 25 Aug 2016 10:59:30 +0300 Subject: Add code improvements to merge request version feature * Add MergeRequestDiff#latest? * Remove unnecessary variable assignment Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/merge_requests_controller.rb | 2 +- app/models/merge_request_diff.rb | 16 ++++++++-------- .../projects/merge_requests/show/_versions.html.haml | 3 +-- spec/models/merge_request_diff_spec.rb | 9 +++++++++ 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index eff959c781c..3be9bdb076d 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -93,7 +93,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController respond_to do |format| format.html { define_discussion_vars } format.json do - if @merge_request_diff != @merge_request.merge_request_diff + unless @merge_request_diff.latest? # Disable comments if browsing older version of the diff @diff_notes_disabled = true end diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 42ab6b620bd..e353bdb24b8 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -79,14 +79,10 @@ class MergeRequestDiff < ActiveRecord::Base def raw_diffs(options = {}) if options[:ignore_whitespace_change] @diffs_no_whitespace ||= - begin - compare = Gitlab::Git::Compare.new( - repository.raw_repository, - safe_start_commit_sha, - safe_head_commit_sha - ) - compare.diffs(options) - end + Gitlab::Git::Compare.new( + repository.raw_repository, + safe_start_commit_sha, + safe_head_commit_sha).diffs(options) else @raw_diffs ||= {} @raw_diffs[options] ||= load_diffs(st_diffs, options) @@ -164,6 +160,10 @@ class MergeRequestDiff < ActiveRecord::Base end end + def latest? + self == merge_request.merge_request_diff + end + private def dump_commits(commits) diff --git a/app/views/projects/merge_requests/show/_versions.html.haml b/app/views/projects/merge_requests/show/_versions.html.haml index 15d94b16ced..08c54f0aeff 100644 --- a/app/views/projects/merge_requests/show/_versions.html.haml +++ b/app/views/projects/merge_requests/show/_versions.html.haml @@ -1,5 +1,4 @@ - merge_request_diffs = @merge_request.merge_request_diffs.select_without_diff -- latest_diff = merge_request_diffs.first - if merge_request_diffs.size > 1 .mr-version-switch @@ -7,7 +6,7 @@ %span.dropdown.inline %a.btn-link.dropdown-toggle{ data: {toggle: :dropdown} } %strong.monospace< - - if latest_diff == @merge_request_diff + - if @merge_request_diff.latest? #{"latest"} - else #{@merge_request_diff.head_commit.short_id} diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index 2f3bb3ed2c4..e5b185dc3f6 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -13,6 +13,15 @@ describe MergeRequestDiff, models: true do it { expect(subject.start_commit_sha).to eq('0b4bc9a49b562e85de7cc9e834518ea6828729b9') } end + describe '#latest' do + let!(:mr) { create(:merge_request, :with_diffs) } + let!(:first_diff) { mr.merge_request_diff } + let!(:last_diff) { mr.create_merge_request_diff } + + it { expect(last_diff.latest?).to be_truthy } + it { expect(first_diff.latest?).to be_falsey } + end + describe '#diffs' do let(:mr) { create(:merge_request, :with_diffs) } let(:mr_diff) { mr.merge_request_diff } -- cgit v1.2.1 From 70fe671c299513a43797dc1e7ab0e32f14503175 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 25 Aug 2016 11:16:03 +0300 Subject: Make it more obvious when the user isn't currently viewing the latest mr version Signed-off-by: Dmitriy Zaporozhets --- app/views/projects/merge_requests/show/_versions.html.haml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/views/projects/merge_requests/show/_versions.html.haml b/app/views/projects/merge_requests/show/_versions.html.haml index 08c54f0aeff..2da70ce7137 100644 --- a/app/views/projects/merge_requests/show/_versions.html.haml +++ b/app/views/projects/merge_requests/show/_versions.html.haml @@ -22,6 +22,10 @@ #{number_with_delimiter(merge_request_diff.commits.count)} #{'commit'.pluralize(merge_request_diff.commits.count)}, = time_ago_with_tooltip(merge_request_diff.created_at) + - unless @merge_request_diff.latest? + %span.prepend-left-default + = icon('info-circle') + This version is not the latest one. Comments are disabled .pull-right %span.monospace #{@merge_request_diff.base_commit.short_id}..#{@merge_request_diff.head_commit.short_id} -- cgit v1.2.1 From cad63d4045623391d5e36ff541d531b6dfae7d81 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Thu, 25 Aug 2016 10:21:51 +0200 Subject: Use new image for Issue Board page [ci skip] --- doc/user/project/img/issue_board.png | Bin 200614 -> 275093 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/user/project/img/issue_board.png b/doc/user/project/img/issue_board.png index accd0900cbb..63c269f6dbc 100644 Binary files a/doc/user/project/img/issue_board.png and b/doc/user/project/img/issue_board.png differ -- cgit v1.2.1 From a943ccf10ecf2af3331927cb83268fbc70f43634 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 25 Aug 2016 11:58:17 +0300 Subject: Change the way merge request diff compare works * remove ref fetch (we do it during creation anyway) * remove safe_head_commit_sha for diff compare (do not depend on the source branch) Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request_diff.rb | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index e353bdb24b8..445179a4487 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -65,13 +65,6 @@ class MergeRequestDiff < ActiveRecord::Base start_commit_sha || merge_request.target_branch_sha end - # This method will rely on repository branch sha - # in case head_commit_sha is nil. Its necesarry for old merge request diff - # created before version 8.4 to work - def safe_head_commit_sha - head_commit_sha || merge_request.source_branch_sha - end - def size real_size.presence || raw_diffs.size end @@ -82,7 +75,7 @@ class MergeRequestDiff < ActiveRecord::Base Gitlab::Git::Compare.new( repository.raw_repository, safe_start_commit_sha, - safe_head_commit_sha).diffs(options) + head_commit_sha).diffs(options) else @raw_diffs ||= {} @raw_diffs[options] ||= load_diffs(st_diffs, options) @@ -148,16 +141,11 @@ class MergeRequestDiff < ActiveRecord::Base def compare @compare ||= - begin - # Update ref for merge request - merge_request.fetch_ref - - Gitlab::Git::Compare.new( - repository.raw_repository, - safe_start_commit_sha, - safe_head_commit_sha - ) - end + Gitlab::Git::Compare.new( + repository.raw_repository, + safe_start_commit_sha, + head_commit_sha + ) end def latest? -- cgit v1.2.1 From 4c8e9a8d27c34fe97216e12d17782f982818fb5c Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Thu, 18 Aug 2016 15:00:20 +0200 Subject: Remove gitorious --- CHANGELOG | 1 + app/assets/stylesheets/pages/import.scss | 19 ------ app/controllers/application_controller.rb | 6 +- app/controllers/import/gitorious_controller.rb | 47 --------------- app/models/application_setting.rb | 2 +- app/views/import/gitorious/status.html.haml | 54 ----------------- app/views/projects/new.html.haml | 5 -- config/initializers/1_settings.rb | 2 +- config/routes.rb | 6 -- doc/workflow/gitlab_flow.md | 2 +- features/steps/dashboard/new_project.rb | 1 - lib/gitlab/current_settings.rb | 2 +- lib/gitlab/gitorious_import.rb | 5 -- lib/gitlab/gitorious_import/client.rb | 29 --------- lib/gitlab/gitorious_import/project_creator.rb | 27 --------- lib/gitlab/gitorious_import/repository.rb | 35 ----------- lib/gitlab/import_sources.rb | 13 ++-- .../import/gitorious_controller_spec.rb | 69 ---------------------- .../gitorious_import/project_creator_spec.rb | 26 -------- 19 files changed, 12 insertions(+), 339 deletions(-) delete mode 100644 app/controllers/import/gitorious_controller.rb delete mode 100644 app/views/import/gitorious/status.html.haml delete mode 100644 lib/gitlab/gitorious_import.rb delete mode 100644 lib/gitlab/gitorious_import/client.rb delete mode 100644 lib/gitlab/gitorious_import/project_creator.rb delete mode 100644 lib/gitlab/gitorious_import/repository.rb delete mode 100644 spec/controllers/import/gitorious_controller_spec.rb delete mode 100644 spec/lib/gitlab/gitorious_import/project_creator_spec.rb diff --git a/CHANGELOG b/CHANGELOG index 518e80a360a..d0344837308 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,7 @@ v 8.12.0 (unreleased) - Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel) - Optimistic locking for Issues and Merge Requests (title and description overriding prevention) - Add `wiki_page_events` to project hook APIs (Ben Boeckel) + - Remove Gitorious import - Add Sentry logging to API calls - Added tests for diff notes - Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck) diff --git a/app/assets/stylesheets/pages/import.scss b/app/assets/stylesheets/pages/import.scss index 84cc35239f9..a4f76a9495a 100644 --- a/app/assets/stylesheets/pages/import.scss +++ b/app/assets/stylesheets/pages/import.scss @@ -1,22 +1,3 @@ -i.icon-gitorious { - display: inline-block; - background-position: 0 0; - background-size: contain; - background-repeat: no-repeat; -} - -i.icon-gitorious-small { - background-image: image-url('gitorious-logo-blue.png'); - width: 13px; - height: 13px; -} - -i.icon-gitorious-big { - background-image: image-url('gitorious-logo-black.png'); - width: 18px; - height: 18px; -} - .import-jobs-from-col, .import-jobs-to-col { width: 40%; diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 70a2275592b..ebc2a4651ba 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -25,7 +25,7 @@ class ApplicationController < ActionController::Base protect_from_forgery with: :exception helper_method :abilities, :can?, :current_application_settings - helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :gitorious_import_enabled?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?, :gitlab_project_import_enabled? + helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?, :gitlab_project_import_enabled? rescue_from Encoding::CompatibilityError do |exception| log_exception(exception) @@ -250,10 +250,6 @@ class ApplicationController < ActionController::Base Gitlab::OAuth::Provider.enabled?(:bitbucket) && Gitlab::BitbucketImport.public_key.present? end - def gitorious_import_enabled? - current_application_settings.import_sources.include?('gitorious') - end - def google_code_import_enabled? current_application_settings.import_sources.include?('google_code') end diff --git a/app/controllers/import/gitorious_controller.rb b/app/controllers/import/gitorious_controller.rb deleted file mode 100644 index a4c4ad23027..00000000000 --- a/app/controllers/import/gitorious_controller.rb +++ /dev/null @@ -1,47 +0,0 @@ -class Import::GitoriousController < Import::BaseController - before_action :verify_gitorious_import_enabled - - def new - redirect_to client.authorize_url(callback_import_gitorious_url) - end - - def callback - session[:gitorious_repos] = params[:repos] - redirect_to status_import_gitorious_path - end - - def status - @repos = client.repos - - @already_added_projects = current_user.created_projects.where(import_type: "gitorious") - already_added_projects_names = @already_added_projects.pluck(:import_source) - - @repos.reject! { |repo| already_added_projects_names.include? repo.full_name } - end - - def jobs - jobs = current_user.created_projects.where(import_type: "gitorious").to_json(only: [:id, :import_status]) - render json: jobs - end - - def create - @repo_id = params[:repo_id] - repo = client.repo(@repo_id) - @target_namespace = params[:new_namespace].presence || repo.namespace - @project_name = repo.name - - namespace = get_or_create_namespace || (render and return) - - @project = Gitlab::GitoriousImport::ProjectCreator.new(repo, namespace, current_user).execute - end - - private - - def client - @client ||= Gitlab::GitoriousImport::Client.new(session[:gitorious_repos]) - end - - def verify_gitorious_import_enabled - render_404 unless gitorious_import_enabled? - end -end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index f0bcb2d7cda..246477ffe88 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -146,7 +146,7 @@ class ApplicationSetting < ActiveRecord::Base default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'], default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'], domain_whitelist: Settings.gitlab['domain_whitelist'], - import_sources: %w[github bitbucket gitlab gitorious google_code fogbugz git gitlab_project], + import_sources: %w[github bitbucket gitlab google_code fogbugz git gitlab_project], shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'], max_artifacts_size: Settings.artifacts['max_size'], require_two_factor_authentication: false, diff --git a/app/views/import/gitorious/status.html.haml b/app/views/import/gitorious/status.html.haml deleted file mode 100644 index ed3afb0ce33..00000000000 --- a/app/views/import/gitorious/status.html.haml +++ /dev/null @@ -1,54 +0,0 @@ -- page_title "Gitorious import" -- header_title "Projects", root_path -%h3.page-title - %i.icon-gitorious.icon-gitorious-big - Import projects from Gitorious.org - -%p.light - Select projects you want to import. -%hr -%p - = button_tag class: "btn btn-import btn-success js-import-all" do - Import all projects - = icon("spinner spin", class: "loading-icon") - -.table-responsive - %table.table.import-jobs - %colgroup.import-jobs-from-col - %colgroup.import-jobs-to-col - %colgroup.import-jobs-status-col - %thead - %tr - %th From Gitorious.org - %th To GitLab - %th Status - %tbody - - @already_added_projects.each do |project| - %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"} - %td - = link_to project.import_source, "https://gitorious.org/#{project.import_source}", target: "_blank" - %td - = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] - %td.job-status - - if project.import_status == 'finished' - %span - %i.fa.fa-check - done - - elsif project.import_status == 'started' - %i.fa.fa-spinner.fa-spin - started - - else - = project.human_import_status_name - - - @repos.each do |repo| - %tr{id: "repo_#{repo.id}"} - %td - = link_to repo.full_name, "https://gitorious.org/#{repo.full_name}", target: "_blank" - %td.import-target - = repo.full_name - %td.import-actions.job-status - = button_tag class: "btn btn-import js-add-to-import" do - Import - = icon("spinner spin", class: "loading-icon") - -.js-importer-status{ data: { jobs_import_path: "#{jobs_import_gitorious_path}", import_path: "#{import_gitorious_path}" } } diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index ea4898f2107..0a1e2bb2cc6 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -59,11 +59,6 @@ = icon('gitlab', text: 'GitLab.com') - unless gitlab_import_configured? = render 'gitlab_import_modal' - %div - - if gitorious_import_enabled? - = link_to new_import_gitorious_path, class: 'btn import_gitorious' do - %i.icon-gitorious.icon-gitorious-small - Gitorious.org %div - if google_code_import_enabled? = link_to new_import_google_code_path, class: 'btn import_google_code' do diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 7a9376def02..4a01b9e40fb 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -212,7 +212,7 @@ Settings.gitlab.default_projects_features['builds'] = true if Settin Settings.gitlab.default_projects_features['container_registry'] = true if Settings.gitlab.default_projects_features['container_registry'].nil? Settings.gitlab.default_projects_features['visibility_level'] = Settings.send(:verify_constant, Gitlab::VisibilityLevel, Settings.gitlab.default_projects_features['visibility_level'], Gitlab::VisibilityLevel::PRIVATE) Settings.gitlab['domain_whitelist'] ||= [] -Settings.gitlab['import_sources'] ||= %w[github bitbucket gitlab gitorious google_code fogbugz git gitlab_project] +Settings.gitlab['import_sources'] ||= %w[github bitbucket gitlab google_code fogbugz git gitlab_project] Settings.gitlab['trusted_proxies'] ||= [] # diff --git a/config/routes.rb b/config/routes.rb index e93b640fbc0..24f9b44a53a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -157,12 +157,6 @@ Rails.application.routes.draw do get :jobs end - resource :gitorious, only: [:create, :new], controller: :gitorious do - get :status - get :callback - get :jobs - end - resource :google_code, only: [:create, :new], controller: :google_code do get :status post :callback diff --git a/doc/workflow/gitlab_flow.md b/doc/workflow/gitlab_flow.md index 8119324bb62..7c0eb90d540 100644 --- a/doc/workflow/gitlab_flow.md +++ b/doc/workflow/gitlab_flow.md @@ -115,7 +115,7 @@ In this flow it is not common to have a production branch (or git flow master br Merge or pull requests are created in a git management application and ask an assigned person to merge two branches. Tools such as GitHub and Bitbucket choose the name pull request since the first manual action would be to pull the feature branch. -Tools such as GitLab and Gitorious choose the name merge request since that is the final action that is requested of the assignee. +Tools such as GitLab and others choose the name merge request since that is the final action that is requested of the assignee. In this article we'll refer to them as merge requests. If you work on a feature branch for more than a few hours it is good to share the intermediate result with the rest of the team. diff --git a/features/steps/dashboard/new_project.rb b/features/steps/dashboard/new_project.rb index f0d8d498e46..2f0941e4113 100644 --- a/features/steps/dashboard/new_project.rb +++ b/features/steps/dashboard/new_project.rb @@ -18,7 +18,6 @@ class Spinach::Features::NewProject < Spinach::FeatureSteps expect(page).to have_link('GitHub') expect(page).to have_link('Bitbucket') expect(page).to have_link('GitLab.com') - expect(page).to have_link('Gitorious.org') expect(page).to have_link('Google Code') expect(page).to have_link('Repo by URL') end diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index 27acd817e51..12fbb78c53e 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -41,7 +41,7 @@ module Gitlab default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'], default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'], domain_whitelist: Settings.gitlab['domain_whitelist'], - import_sources: %w[github bitbucket gitlab gitorious google_code fogbugz git gitlab_project], + import_sources: %w[github bitbucket gitlab google_code fogbugz git gitlab_project], shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'], max_artifacts_size: Settings.artifacts['max_size'], require_two_factor_authentication: false, diff --git a/lib/gitlab/gitorious_import.rb b/lib/gitlab/gitorious_import.rb deleted file mode 100644 index 8d0132a744c..00000000000 --- a/lib/gitlab/gitorious_import.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Gitlab - module GitoriousImport - GITORIOUS_HOST = "https://gitorious.org" - end -end diff --git a/lib/gitlab/gitorious_import/client.rb b/lib/gitlab/gitorious_import/client.rb deleted file mode 100644 index 99fe5bdebfc..00000000000 --- a/lib/gitlab/gitorious_import/client.rb +++ /dev/null @@ -1,29 +0,0 @@ -module Gitlab - module GitoriousImport - class Client - attr_reader :repo_list - - def initialize(repo_list) - @repo_list = repo_list - end - - def authorize_url(redirect_uri) - "#{GITORIOUS_HOST}/gitlab-import?callback_url=#{redirect_uri}" - end - - def repos - @repos ||= repo_names.map { |full_name| GitoriousImport::Repository.new(full_name) } - end - - def repo(id) - repos.find { |repo| repo.id == id } - end - - private - - def repo_names - repo_list.to_s.split(',').map(&:strip).reject(&:blank?) - end - end - end -end diff --git a/lib/gitlab/gitorious_import/project_creator.rb b/lib/gitlab/gitorious_import/project_creator.rb deleted file mode 100644 index 8e22aa9286d..00000000000 --- a/lib/gitlab/gitorious_import/project_creator.rb +++ /dev/null @@ -1,27 +0,0 @@ -module Gitlab - module GitoriousImport - class ProjectCreator - attr_reader :repo, :namespace, :current_user - - def initialize(repo, namespace, current_user) - @repo = repo - @namespace = namespace - @current_user = current_user - end - - def execute - ::Projects::CreateService.new( - current_user, - name: repo.name, - path: repo.path, - description: repo.description, - namespace_id: namespace.id, - visibility_level: Gitlab::VisibilityLevel::PUBLIC, - import_type: "gitorious", - import_source: repo.full_name, - import_url: repo.import_url - ).execute - end - end - end -end diff --git a/lib/gitlab/gitorious_import/repository.rb b/lib/gitlab/gitorious_import/repository.rb deleted file mode 100644 index c88f1ae358d..00000000000 --- a/lib/gitlab/gitorious_import/repository.rb +++ /dev/null @@ -1,35 +0,0 @@ -module Gitlab - module GitoriousImport - Repository = Struct.new(:full_name) do - def id - Digest::SHA1.hexdigest(full_name) - end - - def namespace - segments.first - end - - def path - segments.last - end - - def name - path.titleize - end - - def description - "" - end - - def import_url - "#{GITORIOUS_HOST}/#{full_name}.git" - end - - private - - def segments - full_name.split('/') - end - end - end -end diff --git a/lib/gitlab/import_sources.rb b/lib/gitlab/import_sources.rb index 59a05411fe9..94261b7eeed 100644 --- a/lib/gitlab/import_sources.rb +++ b/lib/gitlab/import_sources.rb @@ -14,13 +14,12 @@ module Gitlab def options { - 'GitHub' => 'github', - 'Bitbucket' => 'bitbucket', - 'GitLab.com' => 'gitlab', - 'Gitorious.org' => 'gitorious', - 'Google Code' => 'google_code', - 'FogBugz' => 'fogbugz', - 'Repo by URL' => 'git', + 'GitHub' => 'github', + 'Bitbucket' => 'bitbucket', + 'GitLab.com' => 'gitlab', + 'Google Code' => 'google_code', + 'FogBugz' => 'fogbugz', + 'Repo by URL' => 'git', 'GitLab export' => 'gitlab_project' } end diff --git a/spec/controllers/import/gitorious_controller_spec.rb b/spec/controllers/import/gitorious_controller_spec.rb deleted file mode 100644 index 4ae2b78e11c..00000000000 --- a/spec/controllers/import/gitorious_controller_spec.rb +++ /dev/null @@ -1,69 +0,0 @@ -require 'spec_helper' - -describe Import::GitoriousController do - include ImportSpecHelper - - let(:user) { create(:user) } - - before do - sign_in(user) - end - - describe "GET new" do - it "redirects to import endpoint on gitorious.org" do - get :new - - expect(controller).to redirect_to("https://gitorious.org/gitlab-import?callback_url=http://test.host/import/gitorious/callback") - end - end - - describe "GET callback" do - it "stores repo list in session" do - get :callback, repos: 'foo/bar,baz/qux' - - expect(session[:gitorious_repos]).to eq('foo/bar,baz/qux') - end - end - - describe "GET status" do - before do - @repo = OpenStruct.new(full_name: 'asd/vim') - end - - it "assigns variables" do - @project = create(:project, import_type: 'gitorious', creator_id: user.id) - stub_client(repos: [@repo]) - - get :status - - expect(assigns(:already_added_projects)).to eq([@project]) - expect(assigns(:repos)).to eq([@repo]) - end - - it "does not show already added project" do - @project = create(:project, import_type: 'gitorious', creator_id: user.id, import_source: 'asd/vim') - stub_client(repos: [@repo]) - - get :status - - expect(assigns(:already_added_projects)).to eq([@project]) - expect(assigns(:repos)).to eq([]) - end - end - - describe "POST create" do - before do - @repo = Gitlab::GitoriousImport::Repository.new('asd/vim') - end - - it "takes already existing namespace" do - namespace = create(:namespace, name: "asd", owner: user) - expect(Gitlab::GitoriousImport::ProjectCreator). - to receive(:new).with(@repo, namespace, user). - and_return(double(execute: true)) - stub_client(repo: @repo) - - post :create, format: :js - end - end -end diff --git a/spec/lib/gitlab/gitorious_import/project_creator_spec.rb b/spec/lib/gitlab/gitorious_import/project_creator_spec.rb deleted file mode 100644 index 946712ca38e..00000000000 --- a/spec/lib/gitlab/gitorious_import/project_creator_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -require 'spec_helper' - -describe Gitlab::GitoriousImport::ProjectCreator, lib: true do - let(:user) { create(:user) } - let(:repo) { Gitlab::GitoriousImport::Repository.new('foo/bar-baz-qux') } - let(:namespace){ create(:group, owner: user) } - - before do - namespace.add_owner(user) - end - - it 'creates project' do - allow_any_instance_of(Project).to receive(:add_import_job) - - project_creator = Gitlab::GitoriousImport::ProjectCreator.new(repo, namespace, user) - project = project_creator.execute - - expect(project.name).to eq("Bar Baz Qux") - expect(project.path).to eq("bar-baz-qux") - expect(project.namespace).to eq(namespace) - expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC) - expect(project.import_type).to eq("gitorious") - expect(project.import_source).to eq("foo/bar-baz-qux") - expect(project.import_url).to eq("https://gitorious.org/foo/bar-baz-qux.git") - end -end -- cgit v1.2.1 From 4a3d1a5838685ff95a6c9416bb3e453ad143f50d Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Wed, 24 Aug 2016 15:20:06 +0100 Subject: Handle case where conflicts aren't on disk yet --- app/models/merge_request.rb | 2 +- lib/gitlab/conflict/file.rb | 11 +++++++++++ spec/models/merge_request_spec.rb | 7 +++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 5330a07ee35..7fa52d0b7a7 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -778,7 +778,7 @@ class MergeRequest < ActiveRecord::Base begin @conflicts_can_be_resolved_in_ui = conflicts.files.each(&:lines) - rescue Gitlab::Conflict::Parser::ParserError, Gitlab::Conflict::FileCollection::ConflictSideMissing + rescue Rugged::OdbError, Gitlab::Conflict::Parser::ParserError, Gitlab::Conflict::FileCollection::ConflictSideMissing @conflicts_can_be_resolved_in_ui = false end end diff --git a/lib/gitlab/conflict/file.rb b/lib/gitlab/conflict/file.rb index 0a1fd27ced5..dff9e29c6a5 100644 --- a/lib/gitlab/conflict/file.rb +++ b/lib/gitlab/conflict/file.rb @@ -181,6 +181,17 @@ module Gitlab sections: sections } end + + # Don't try to print merge_request or repository. + def inspect + instance_variables = [:merge_file_result, :their_path, :our_path, :our_mode].map do |instance_variable| + value = instance_variable_get("@#{instance_variable}") + + "#{instance_variable}=\"#{value}\"" + end + + "#<#{self.class} #{instance_variables.join(' ')}>" + end end end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 64c56d922ff..ae71eaeda52 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -890,6 +890,13 @@ describe MergeRequest, models: true do expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_falsey end + it 'returns a falsey value when the MR has a missing ref after a force push' do + merge_request = create_merge_request('conflict-resolvable') + allow(merge_request.conflicts).to receive(:merge_index).and_raise(Rugged::OdbError) + + expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_falsey + end + it 'returns a falsey value when the MR does not support new diff notes' do merge_request = create_merge_request('conflict-resolvable') merge_request.merge_request_diff.update_attributes(start_commit_sha: nil) -- cgit v1.2.1 From 67beaf6fb989e4f7981769b1f01bf383fc0de652 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 25 Aug 2016 12:32:35 +0100 Subject: Don't show conflicts when there are none --- app/models/merge_request.rb | 6 +++++- spec/models/merge_request_spec.rb | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 7fa52d0b7a7..19a684d1d0c 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -777,7 +777,11 @@ class MergeRequest < ActiveRecord::Base return @conflicts_can_be_resolved_in_ui = false unless has_complete_diff_refs? begin - @conflicts_can_be_resolved_in_ui = conflicts.files.each(&:lines) + # Try to parse each conflict. If the MR's mergeable status hasn't been updated, + # ensure that we don't say there are conflicts to resolve when there are no conflict + # files. + conflicts.files.each(&:lines) + @conflicts_can_be_resolved_in_ui = conflicts.files.length > 0 rescue Rugged::OdbError, Gitlab::Conflict::Parser::ParserError, Gitlab::Conflict::FileCollection::ConflictSideMissing @conflicts_can_be_resolved_in_ui = false end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index ae71eaeda52..c4138c4f3f3 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -890,6 +890,12 @@ describe MergeRequest, models: true do expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_falsey end + it 'returns a falsey value when the MR is marked as having conflicts, but has none' do + merge_request = create_merge_request('master') + + expect(merge_request.conflicts_can_be_resolved_in_ui?).to be_falsey + end + it 'returns a falsey value when the MR has a missing ref after a force push' do merge_request = create_merge_request('conflict-resolvable') allow(merge_request.conflicts).to receive(:merge_index).and_raise(Rugged::OdbError) -- cgit v1.2.1 From 0d0d46dce2a933f0060b2b05216e53197a3d449b Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 25 Aug 2016 12:36:06 +0100 Subject: Update CHANGELOG --- CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 518e80a360a..9a7753d691c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,10 @@ v 8.12.0 (unreleased) - Added tests for diff notes - Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck) +v 8.11.3 (unreleased) + - Don't show resolve conflicts link before MR status is updated + - Don't prevent viewing the MR when git refs for conflicts can't be found on disk + v 8.11.2 (unreleased) - Show "Create Merge Request" widget for push events to fork projects on the source project -- cgit v1.2.1 From 3bfb94b7593c3e14fa974701d733d6dc3c744bd2 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 24 Aug 2016 14:57:57 -0300 Subject: Label list shows all issues (opened or closed) with that label --- app/services/boards/issues/list_service.rb | 7 ++++++- spec/services/boards/issues/list_service_spec.rb | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/services/boards/issues/list_service.rb b/app/services/boards/issues/list_service.rb index 435a8c6e681..34efd09ed9f 100644 --- a/app/services/boards/issues/list_service.rb +++ b/app/services/boards/issues/list_service.rb @@ -36,7 +36,12 @@ module Boards end def set_state - params[:state] = list.done? ? 'closed' : 'opened' + params[:state] = + case list.list_type.to_sym + when :backlog then 'opened' + when :done then 'closed' + else 'all' + end end def board_label_ids diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb index f7f45983d26..cf4c5f13635 100644 --- a/spec/services/boards/issues/list_service_spec.rb +++ b/spec/services/boards/issues/list_service_spec.rb @@ -30,7 +30,7 @@ describe Boards::Issues::ListService, services: true do let!(:closed_issue1) { create(:labeled_issue, :closed, project: project, labels: [bug]) } let!(:closed_issue2) { create(:labeled_issue, :closed, project: project, labels: [p3]) } let!(:closed_issue3) { create(:issue, :closed, project: project) } - let!(:closed_issue4) { create(:labeled_issue, :closed, project: project, labels: [p1]) } + let!(:closed_issue4) { create(:labeled_issue, :closed, project: project, labels: [p1, development]) } before do project.team << [user, :developer] @@ -58,15 +58,15 @@ describe Boards::Issues::ListService, services: true do issues = described_class.new(project, user, params).execute - expect(issues).to eq [closed_issue4, closed_issue2, closed_issue3, closed_issue1] + expect(issues).to eq [closed_issue2, closed_issue3, closed_issue1] end - it 'returns opened issues that have label list applied when listing issues from a label list' do + it 'returns opened/closed issues that have label list applied when listing issues from a label list' do params = { id: list1.id } issues = described_class.new(project, user, params).execute - expect(issues).to eq [list1_issue3, list1_issue1, list1_issue2] + expect(issues).to eq [closed_issue4, list1_issue3, list1_issue1, list1_issue2] end end end -- cgit v1.2.1 From 3eb4c74f88dfb316d695dc9396b88555bf314189 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 24 Aug 2016 15:19:36 -0300 Subject: Update Issue board documentation --- doc/user/project/issue_board.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md index 9df9ed9c9da..cac926b3e28 100644 --- a/doc/user/project/issue_board.md +++ b/doc/user/project/issue_board.md @@ -31,10 +31,9 @@ Below is a table of the definitions used for GitLab's Issue Board. There are three types of lists, the ones you create based on your labels, and two default: -- **Backlog** (default): shows all issues that do not fall in one of the other - lists. Always appears on the very left. -- **Done** (default): shows all closed issues. Always appears on the very right. -- Label list: a list based on a label. It shows all issues with that label. +- **Backlog** (default): shows all opened issues that do not fall in one of the other lists. Always appears on the very left. +- **Done** (default): shows all closed issues that do not fall in one of the other lists. Always appears on the very right. +- Label list: a list based on a label. It shows all opened or closed issues with that label. ![GitLab Issue Board](img/issue_board.png) -- cgit v1.2.1 From baa73b659ae50fa82d9c4be6ab5080a9475d7041 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 25 Aug 2016 09:41:49 -0300 Subject: Update CHANGELOG --- CHANGELOG | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 518e80a360a..32d30ac8c60 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,10 +10,13 @@ v 8.12.0 (unreleased) - Added tests for diff notes - Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck) -v 8.11.2 (unreleased) +v 8.11.3 (unreleased) + - Label list shows all issues (opened or closed) with that label + +v 8.11.2 - Show "Create Merge Request" widget for push events to fork projects on the source project -v 8.11.1 (unreleased) +v 8.11.1 - Does not halt the GitHub import process when an error occurs - Fix file links on project page when default view is Files !5933 - Change using size to use count and caching it for number of group members -- cgit v1.2.1 From 6280fd3777920670ee42111fddf29576cbf85988 Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Tue, 23 Aug 2016 11:27:22 +0200 Subject: Reduce number of database queries on builds tab --- CHANGELOG | 1 + app/models/ci/build.rb | 2 +- app/models/ci/pipeline.rb | 2 +- app/models/commit_status.rb | 2 ++ app/views/projects/commit/_ci_stage.html.haml | 4 ++-- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 518e80a360a..dfa8c23fd13 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ v 8.12.0 (unreleased) v 8.11.2 (unreleased) - Show "Create Merge Request" widget for push events to fork projects on the source project + - Reduce number of database queries on builds tab v 8.11.1 (unreleased) - Does not halt the GitHub import process when an error occurs diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 096b3b801af..23c8de6f650 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -352,7 +352,7 @@ module Ci end def artifacts? - !artifacts_expired? && artifacts_file.exists? + !artifacts_expired? && self[:artifacts_file].present? end def artifacts_metadata? diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 087abe4cbb1..aff908ea16c 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -83,7 +83,7 @@ module Ci end def stages_with_latest_statuses - statuses.latest.order(:stage_idx).group_by(&:stage) + statuses.latest.includes(project: :namespace).order(:stage_idx).group_by(&:stage) end def project_id diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 84ceeac7d3e..1b403fa646d 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -25,6 +25,8 @@ class CommitStatus < ActiveRecord::Base scope :retried, -> { where.not(id: latest) } scope :ordered, -> { order(:name) } scope :ignored, -> { where(allow_failure: true, status: [:failed, :canceled]) } + scope :latest_ci_stages, -> { latest.ordered.includes(project: :namespace) } + scope :retried_ci_stages, -> { retried.ordered.includes(project: :namespace) } state_machine :status do event :enqueue do diff --git a/app/views/projects/commit/_ci_stage.html.haml b/app/views/projects/commit/_ci_stage.html.haml index 9d925cacc0d..6bb900e3fc1 100644 --- a/app/views/projects/commit/_ci_stage.html.haml +++ b/app/views/projects/commit/_ci_stage.html.haml @@ -8,8 +8,8 @@ - if stage   = stage.titleize - = render statuses.latest.ordered, coverage: @project.build_coverage_enabled?, stage: false, ref: false, allow_retry: true - = render statuses.retried.ordered, coverage: @project.build_coverage_enabled?, stage: false, ref: false, retried: true + = render statuses.latest_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, allow_retry: true + = render statuses.retried_ci_stages, coverage: @project.build_coverage_enabled?, stage: false, ref: false, retried: true %tr %td{colspan: 10}   -- cgit v1.2.1 From f16eabfc3335119015302798cb270445ddc0dc89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Rosen=C3=B6gger?= <123haynes@gmail.com> Date: Fri, 12 Aug 2016 16:29:13 +0200 Subject: Display project icon from default branch This commit makes sure that the project icon is being read from the default branch instead of 'master' --- CHANGELOG | 1 + app/controllers/projects/avatars_controller.rb | 2 +- app/models/project.rb | 1 + app/models/repository.rb | 2 +- spec/models/project_spec.rb | 31 ++++++++++++++++++++++++++ 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 518e80a360a..ab675653138 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,6 +17,7 @@ v 8.11.1 (unreleased) - Does not halt the GitHub import process when an error occurs - Fix file links on project page when default view is Files !5933 - Change using size to use count and caching it for number of group members + - Use the default branch for displaying the project icon instead of master !5792 (Hannes Rosenögger) v 8.11.0 - Use test coverage value from the latest successful pipeline in badge. !5862 diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb index 5962f74c39b..ada7db3c552 100644 --- a/app/controllers/projects/avatars_controller.rb +++ b/app/controllers/projects/avatars_controller.rb @@ -4,7 +4,7 @@ class Projects::AvatarsController < Projects::ApplicationController before_action :authorize_admin_project!, only: [:destroy] def show - @blob = @repository.blob_at_branch('master', @project.avatar_in_git) + @blob = @repository.blob_at_branch(@repository.root_ref, @project.avatar_in_git) if @blob headers['X-Content-Type-Options'] = 'nosniff' diff --git a/app/models/project.rb b/app/models/project.rb index 8cf093be4c3..0e4fb94f8eb 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1035,6 +1035,7 @@ class Project < ActiveRecord::Base "refs/heads/#{branch}", force: true) repository.copy_gitattributes(branch) + repository.expire_avatar_cache(branch) reload_default_branch end diff --git a/app/models/repository.rb b/app/models/repository.rb index bdc3b9d1c1c..91bdafdac99 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1065,7 +1065,7 @@ class Repository @avatar ||= cache.fetch(:avatar) do AVATAR_FILES.find do |file| - blob_at_branch('master', file) + blob_at_branch(root_ref, file) end end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 9a3660012f9..b2baeeb31bb 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1442,4 +1442,35 @@ describe Project, models: true do expect(shared_project.authorized_for_user?(master, Gitlab::Access::MASTER)).to be(true) end end + + describe 'change_head' do + let(:project) { create(:project) } + + it 'calls the before_change_head method' do + expect(project.repository).to receive(:before_change_head) + project.change_head(project.default_branch) + end + + it 'creates the new reference with rugged' do + expect(project.repository.rugged.references).to receive(:create).with('HEAD', + "refs/heads/#{project.default_branch}", + force: true) + project.change_head(project.default_branch) + end + + it 'copies the gitattributes' do + expect(project.repository).to receive(:copy_gitattributes).with(project.default_branch) + project.change_head(project.default_branch) + end + + it 'expires the avatar cache' do + expect(project.repository).to receive(:expire_avatar_cache).with(project.default_branch) + project.change_head(project.default_branch) + end + + it 'reloads the default branch' do + expect(project).to receive(:reload_default_branch) + project.change_head(project.default_branch) + end + end end -- cgit v1.2.1 From cb5e6fe71e95d61cead3dd7985a044b383529413 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Thu, 25 Aug 2016 15:36:56 +0200 Subject: Fix markdown link in doc_styleguide.md [ci skip] --- doc/development/doc_styleguide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/development/doc_styleguide.md b/doc/development/doc_styleguide.md index 927a1872413..dc7d832ce3a 100644 --- a/doc/development/doc_styleguide.md +++ b/doc/development/doc_styleguide.md @@ -6,7 +6,7 @@ it organized and easy to find. ## Location and naming of documents >**Note:** -These guidelines derive from the discussion taken place in issue [#3349](ce-3349). +These guidelines derive from the discussion taken place in issue [#3349][ce-3349]. The documentation hierarchy can be vastly improved by providing a better layout and organization of directories. -- cgit v1.2.1 From 5b846a5d450197e7bcb4d8cbfc65388812beae63 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 25 Aug 2016 15:53:08 +0200 Subject: Moved two 8.11 changelog entries to 8.12 [ci skip] --- CHANGELOG | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 64f4fb76bda..104f37003c9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -9,16 +9,16 @@ v 8.12.0 (unreleased) - Add Sentry logging to API calls - Added tests for diff notes - Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck) + - Reduce number of database queries on builds tab + - Use the default branch for displaying the project icon instead of master !5792 (Hannes Rosenögger) v 8.11.2 (unreleased) - Show "Create Merge Request" widget for push events to fork projects on the source project - - Reduce number of database queries on builds tab v 8.11.1 (unreleased) - Does not halt the GitHub import process when an error occurs - Fix file links on project page when default view is Files !5933 - Change using size to use count and caching it for number of group members - - Use the default branch for displaying the project icon instead of master !5792 (Hannes Rosenögger) v 8.11.0 - Use test coverage value from the latest successful pipeline in badge. !5862 -- cgit v1.2.1 From a5079f68e6aa3de4c6e430f96f7bf482bc4c492a Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Mon, 22 Aug 2016 17:56:46 +0200 Subject: Adds response mime type to transaction metric action when it's not HTML --- CHANGELOG | 1 + lib/gitlab/metrics/rack_middleware.rb | 22 ++++++++++++++++++++-- spec/lib/gitlab/metrics/rack_middleware_spec.rb | 21 +++++++++++++++++---- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 104f37003c9..ae0322a3ff9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,7 @@ v 8.12.0 (unreleased) - Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck) - Reduce number of database queries on builds tab - Use the default branch for displaying the project icon instead of master !5792 (Hannes Rosenögger) + - Adds response mime type to transaction metric action when it's not HTML v 8.11.2 (unreleased) - Show "Create Merge Request" widget for push events to fork projects on the source project diff --git a/lib/gitlab/metrics/rack_middleware.rb b/lib/gitlab/metrics/rack_middleware.rb index b4493bf44d2..01c96a6fe96 100644 --- a/lib/gitlab/metrics/rack_middleware.rb +++ b/lib/gitlab/metrics/rack_middleware.rb @@ -4,6 +4,17 @@ module Gitlab class RackMiddleware CONTROLLER_KEY = 'action_controller.instance' ENDPOINT_KEY = 'api.endpoint' + CONTENT_TYPES = { + 'text/html' => :html, + 'text/plain' => :txt, + 'application/json' => :json, + 'text/js' => :js, + 'application/atom+xml' => :atom, + 'image/png' => :png, + 'image/jpeg' => :jpeg, + 'image/gif' => :gif, + 'image/svg+xml' => :svg + } def initialize(app) @app = app @@ -46,8 +57,15 @@ module Gitlab end def tag_controller(trans, env) - controller = env[CONTROLLER_KEY] - trans.action = "#{controller.class.name}##{controller.action_name}" + controller = env[CONTROLLER_KEY] + action = "#{controller.class.name}##{controller.action_name}" + suffix = CONTENT_TYPES[controller.content_type] + + if suffix && suffix != :html + action += ".#{suffix}" + end + + trans.action = action end def tag_endpoint(trans, env) diff --git a/spec/lib/gitlab/metrics/rack_middleware_spec.rb b/spec/lib/gitlab/metrics/rack_middleware_spec.rb index a30cb2a5e38..bcaffd27909 100644 --- a/spec/lib/gitlab/metrics/rack_middleware_spec.rb +++ b/spec/lib/gitlab/metrics/rack_middleware_spec.rb @@ -19,7 +19,7 @@ describe Gitlab::Metrics::RackMiddleware do end it 'tags a transaction with the name and action of a controller' do - klass = double(:klass, name: 'TestController') + klass = double(:klass, name: 'TestController', content_type: 'text/html') controller = double(:controller, class: klass, action_name: 'show') env['action_controller.instance'] = controller @@ -32,7 +32,7 @@ describe Gitlab::Metrics::RackMiddleware do middleware.call(env) end - it 'tags a transaction with the method andpath of the route in the grape endpoint' do + it 'tags a transaction with the method and path of the route in the grape endpoint' do route = double(:route, route_method: "GET", route_path: "/:version/projects/:id/archive(.:format)") endpoint = double(:endpoint, route: route) @@ -87,17 +87,30 @@ describe Gitlab::Metrics::RackMiddleware do describe '#tag_controller' do let(:transaction) { middleware.transaction_from_env(env) } + let(:content_type) { 'text/html' } - it 'tags a transaction with the name and action of a controller' do + before do klass = double(:klass, name: 'TestController') - controller = double(:controller, class: klass, action_name: 'show') + controller = double(:controller, class: klass, action_name: 'show', content_type: content_type) env['action_controller.instance'] = controller + end + it 'tags a transaction with the name and action of a controller' do middleware.tag_controller(transaction, env) expect(transaction.action).to eq('TestController#show') end + + context 'when the response content type is not :html' do + let(:content_type) { 'application/json' } + + it 'appends the mime type to the transaction action' do + middleware.tag_controller(transaction, env) + + expect(transaction.action).to eq('TestController#show.json') + end + end end describe '#tag_endpoint' do -- cgit v1.2.1 From 5ab8977f183f15d3c638f5dfcfb2ac484c862124 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Thu, 25 Aug 2016 09:53:42 -0500 Subject: Fix inline emoji text alignment --- CHANGELOG | 1 + app/assets/stylesheets/framework/common.scss | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 104f37003c9..9b79288e1bb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,7 @@ v 8.12.0 (unreleased) - Add `wiki_page_events` to project hook APIs (Ben Boeckel) - Add Sentry logging to API calls - Added tests for diff notes + - Fix inline emoji text alignment (ClemMakesApps) - Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck) - Reduce number of database queries on builds tab - Use the default branch for displaying the project icon instead of master !5792 (Hannes Rosenögger) diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index c1e5305644b..8984bce616c 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -248,7 +248,7 @@ li.note { img.emoji { height: 20px; - vertical-align: middle; + vertical-align: top; width: 20px; } -- cgit v1.2.1 From fc3dfb61b7f0dd7975f04cc068ff3e26c3a8b947 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 25 Aug 2016 16:07:20 +0100 Subject: Use icon helper --- app/views/admin/system_info/show.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/admin/system_info/show.html.haml b/app/views/admin/system_info/show.html.haml index 7f3b95699db..bfc6142067a 100644 --- a/app/views/admin/system_info/show.html.haml +++ b/app/views/admin/system_info/show.html.haml @@ -12,7 +12,7 @@ - if @cpus %h1= "#{@cpus.length} cores" - else - %i.fa.fa-warning.text-warning + = icon('warning', class: 'text-warning') Unable to collect CPU info .col-sm-4 .light-well @@ -21,7 +21,7 @@ - if @memory %h1= "#{number_to_human_size(@memory.active_bytes)} / #{number_to_human_size(@memory.total_bytes)}" - else - %i.fa.fa-warning.text-warning + = icon('warning', class: 'text-warning') Unable to collect memory info .col-sm-4 .light-well -- cgit v1.2.1 From fa3ec9d44aa13adf170b45c882f0ad6698f7f7f0 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Tue, 23 Aug 2016 11:14:06 -0500 Subject: Fix groups sort dropdown alignment --- CHANGELOG | 1 + app/views/explore/groups/index.html.haml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 4e12f5d4f00..97bb6da6f06 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,6 +8,7 @@ v 8.12.0 (unreleased) - Add `wiki_page_events` to project hook APIs (Ben Boeckel) - Add Sentry logging to API calls - Automatically expand hidden discussions when accessed by a permalink !5585 (Mike Greiling) + - Fix groups sort dropdown alignment (ClemMakesApps) - Added tests for diff notes - Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck) - Reduce number of database queries on builds tab diff --git a/app/views/explore/groups/index.html.haml b/app/views/explore/groups/index.html.haml index 57f6e7e0612..b8248a80a27 100644 --- a/app/views/explore/groups/index.html.haml +++ b/app/views/explore/groups/index.html.haml @@ -24,7 +24,7 @@ - else = sort_title_recently_created %b.caret - %ul.dropdown-menu + %ul.dropdown-menu.dropdown-menu-align-right %li = link_to explore_groups_path(sort: sort_value_recently_created) do = sort_title_recently_created -- cgit v1.2.1 From 77abf8cccfff01fa09a4014aea0f5afc309a7ca2 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Thu, 25 Aug 2016 10:47:40 -0500 Subject: Capitalize mentioned issue timeline notes --- CHANGELOG | 1 + app/services/system_note_service.rb | 10 +++++----- features/steps/shared/issuable.rb | 2 +- spec/features/issues/new_branch_button_spec.rb | 2 +- spec/features/notes_on_merge_requests_spec.rb | 2 +- spec/models/note_spec.rb | 2 +- spec/requests/api/notes_spec.rb | 2 +- spec/services/system_note_service_spec.rb | 10 +++++----- 8 files changed, 16 insertions(+), 15 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4e12f5d4f00..f2e98a11a5b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,6 +11,7 @@ v 8.12.0 (unreleased) - Added tests for diff notes - Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck) - Reduce number of database queries on builds tab + - Capitalize mentioned issue timeline notes (ClemMakesApps) - Use the default branch for displaying the project icon instead of master !5792 (Hannes Rosenögger) v 8.11.2 (unreleased) diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 546a8f11330..0c8446e7c3d 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -269,11 +269,11 @@ module SystemNoteService # # Example Note text: # - # "mentioned in #1" + # "Mentioned in #1" # - # "mentioned in !2" + # "Mentioned in !2" # - # "mentioned in 54f7727c" + # "Mentioned in 54f7727c" # # See cross_reference_note_content. # @@ -308,7 +308,7 @@ module SystemNoteService # Check if a cross-reference is disallowed # - # This method prevents adding a "mentioned in !1" note on every single commit + # This method prevents adding a "Mentioned in !1" note on every single commit # in a merge request. Additionally, it prevents the creation of references to # external issues (which would fail). # @@ -417,7 +417,7 @@ module SystemNoteService end def cross_reference_note_prefix - 'mentioned in ' + 'Mentioned in ' end def cross_reference_note_content(gfm_reference) diff --git a/features/steps/shared/issuable.rb b/features/steps/shared/issuable.rb index aa666a954bc..df9845ba569 100644 --- a/features/steps/shared/issuable.rb +++ b/features/steps/shared/issuable.rb @@ -179,7 +179,7 @@ module SharedIssuable project = Project.find_by(name: from_project_name) expect(page).to have_content(user_name) - expect(page).to have_content("mentioned in #{issuable.class.to_s.titleize.downcase} #{issuable.to_reference(project)}") + expect(page).to have_content("Mentioned in #{issuable.class.to_s.titleize.downcase} #{issuable.to_reference(project)}") end def expect_sidebar_content(content) diff --git a/spec/features/issues/new_branch_button_spec.rb b/spec/features/issues/new_branch_button_spec.rb index e528aff4d41..fb0c4704285 100644 --- a/spec/features/issues/new_branch_button_spec.rb +++ b/spec/features/issues/new_branch_button_spec.rb @@ -20,7 +20,7 @@ feature 'Start new branch from an issue', feature: true do context "when there is a referenced merge request" do let(:note) do create(:note, :on_issue, :system, project: project, - note: "mentioned in !#{referenced_mr.iid}") + note: "Mentioned in !#{referenced_mr.iid}") end let(:referenced_mr) do create(:merge_request, :simple, source_project: project, target_project: project, diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb index 7a9edbbe339..f1c522155d3 100644 --- a/spec/features/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -141,7 +141,7 @@ describe 'Comments', feature: true do let(:project2) { create(:project, :private) } let(:issue) { create(:issue, project: project2) } let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'markdown') } - let!(:note) { create(:note_on_merge_request, :system, noteable: merge_request, project: project, note: "mentioned in #{issue.to_reference(project)}") } + let!(:note) { create(:note_on_merge_request, :system, noteable: merge_request, project: project, note: "Mentioned in #{issue.to_reference(project)}") } it 'shows the system note' do login_as :admin diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index ef2747046b9..9e8ae07e0b2 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -225,7 +225,7 @@ describe Note, models: true do let(:note) do create :note, noteable: ext_issue, project: ext_proj, - note: "mentioned in issue #{private_issue.to_reference(ext_proj)}", + note: "Mentioned in issue #{private_issue.to_reference(ext_proj)}", system: true end diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index 737fa14cbb0..223444ea39f 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -25,7 +25,7 @@ describe API::API, api: true do let!(:cross_reference_note) do create :note, noteable: ext_issue, project: ext_proj, - note: "mentioned in issue #{private_issue.to_reference(ext_proj)}", + note: "Mentioned in issue #{private_issue.to_reference(ext_proj)}", system: true end diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index 00427d6db2a..3d854a959f3 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -330,13 +330,13 @@ describe SystemNoteService, services: true do let(:mentioner) { project2.repository.commit } it 'references the mentioning commit' do - expect(subject.note).to eq "mentioned in commit #{mentioner.to_reference(project)}" + expect(subject.note).to eq "Mentioned in commit #{mentioner.to_reference(project)}" end end context 'from non-Commit' do it 'references the mentioning object' do - expect(subject.note).to eq "mentioned in issue #{mentioner.to_reference(project)}" + expect(subject.note).to eq "Mentioned in issue #{mentioner.to_reference(project)}" end end end @@ -346,13 +346,13 @@ describe SystemNoteService, services: true do let(:mentioner) { project.repository.commit } it 'references the mentioning commit' do - expect(subject.note).to eq "mentioned in commit #{mentioner.to_reference}" + expect(subject.note).to eq "Mentioned in commit #{mentioner.to_reference}" end end context 'from non-Commit' do it 'references the mentioning object' do - expect(subject.note).to eq "mentioned in issue #{mentioner.to_reference}" + expect(subject.note).to eq "Mentioned in issue #{mentioner.to_reference}" end end end @@ -362,7 +362,7 @@ describe SystemNoteService, services: true do describe '.cross_reference?' do it 'is truthy when text begins with expected text' do - expect(described_class.cross_reference?('mentioned in something')).to be_truthy + expect(described_class.cross_reference?('Mentioned in something')).to be_truthy end it 'is falsey when text does not begin with expected text' do -- cgit v1.2.1 From 9a6b7da91adce3cf8021a872e870ad828998cfb1 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Thu, 25 Aug 2016 17:56:03 +0200 Subject: Fix wrong Koding link --- doc/README.md | 1 - doc/integration/README.md | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/README.md b/doc/README.md index 047035dfb09..254394eb63e 100644 --- a/doc/README.md +++ b/doc/README.md @@ -19,7 +19,6 @@ - [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects. - [Webhooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project. - [Workflow](workflow/README.md) Using GitLab functionality and importing projects from GitHub and SVN. -- [Koding](user/project/koding.md) Learn how to use Koding, the online IDE. ## Administrator documentation diff --git a/doc/integration/README.md b/doc/integration/README.md index 70895abbcad..c2fd299db07 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -15,7 +15,7 @@ See the documentation below for details on how to configure these services. - [Gmail actions buttons](gmail_action_buttons_for_gitlab.md) Adds GitLab actions to messages - [reCAPTCHA](recaptcha.md) Configure GitLab to use Google reCAPTCHA for new users - [Akismet](akismet.md) Configure Akismet to stop spam -- [Koding](koding.md) Configure Koding to use IDE integration +- [Koding](../administration/integration/koding.md) Configure Koding to use IDE integration GitLab Enterprise Edition contains [advanced Jenkins support][jenkins]. -- cgit v1.2.1 From 82302b04fc53446a01fe1f36da261345415dca91 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Thu, 4 Aug 2016 10:53:05 -0500 Subject: Add hover color to emoji icon --- CHANGELOG | 1 + app/assets/stylesheets/pages/notes.scss | 16 +++++----------- app/views/projects/notes/_note.html.haml | 4 ++-- spec/javascripts/fixtures/awards_handler.html.haml | 2 +- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4522b268592..5d83a4b9520 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,7 @@ v 8.12.0 (unreleased) - Change merge_error column from string to text type - Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel) - Set path for all JavaScript cookies to honor GitLab's subdirectory setting !5627 (Mike Greiling) + - Add hover color to emoji icon (ClemMakesApps) - Optimistic locking for Issues and Merge Requests (title and description overriding prevention) - Add `wiki_page_events` to project hook APIs (Ben Boeckel) - Add Sentry logging to API calls diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 08d1692c888..54124a3d658 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -281,19 +281,13 @@ ul.notes { font-size: 17px; } - &.js-note-delete { - i { - &:hover { - color: $gl-text-red; - } + &:hover { + .danger-highlight { + color: $gl-text-red; } - } - &.js-note-edit { - i { - &:hover { - color: $gl-link-color; - } + .link-highlight { + color: $gl-link-color; } } } diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index d2ac1ce2b9a..7c82177f9ea 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -52,11 +52,11 @@ - if note.emoji_awardable? = link_to '#', title: 'Award Emoji', class: 'note-action-button note-emoji-button js-add-award js-note-emoji', data: { position: 'right' } do = icon('spinner spin') - = icon('smile-o') + = icon('smile-o', class: 'link-highlight') - if note_editable = link_to '#', title: 'Edit comment', class: 'note-action-button js-note-edit' do - = icon('pencil') + = icon('pencil', class: 'link-highlight') = link_to namespace_project_note_path(note.project.namespace, note.project, note), title: 'Remove comment', method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: 'note-action-button hidden-xs js-note-delete danger' do = icon('trash-o') .note-body{class: note_editable ? 'js-task-list-container' : ''} diff --git a/spec/javascripts/fixtures/awards_handler.html.haml b/spec/javascripts/fixtures/awards_handler.html.haml index d55936ee4f9..1ef2e8f8624 100644 --- a/spec/javascripts/fixtures/awards_handler.html.haml +++ b/spec/javascripts/fixtures/awards_handler.html.haml @@ -39,7 +39,7 @@ %span.note-role Reporter %a.note-action-button.note-emoji-button.js-add-award.js-note-emoji{"data-position" => "right", :href => "#", :title => "Award Emoji"} %i.fa.fa-spinner.fa-spin - %i.fa.fa-smile-o + %i.fa.fa-smile-o.link-highlight .js-task-list-container.note-body.is-task-list-enabled .note-text %p Suscipit sunt quia quisquam sed eveniet ipsam. -- cgit v1.2.1 From 7b4b4a0e557459fef2ef34361f5c231274006ab7 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 25 Aug 2016 13:53:39 -0700 Subject: Add lock_version to merge_requests table Closes #21465 It appears this column was mistakenly omitted in !5623 due to rebasing issues in earlier comments. --- db/schema.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/db/schema.rb b/db/schema.rb index 38779065225..5a105a91ad1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -620,6 +620,7 @@ ActiveRecord::Schema.define(version: 20160823081327) do t.string "merge_commit_sha" t.datetime "deleted_at" t.string "in_progress_merge_commit_sha" + t.integer "lock_version" end add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree -- cgit v1.2.1 From a15e9f02b81f26cc07536d1458a576aede861529 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Thu, 11 Aug 2016 15:47:03 -0500 Subject: Reduce contributions calendar data payload --- CHANGELOG | 1 + .../javascripts/lib/utils/datetime_utility.js | 8 ++++ app/assets/javascripts/users/calendar.js | 51 +++++++++++++--------- lib/gitlab/contributions_calendar.rb | 1 - spec/javascripts/datetime_utility_spec.js.coffee | 19 ++++++++ 5 files changed, 58 insertions(+), 22 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 69ad046dd11..adbaf5060f4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.12.0 (unreleased) - Change merge_error column from string to text type + - Reduce contributions calendar data payload (ClemMakesApps) - Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel) - Optimistic locking for Issues and Merge Requests (title and description overriding prevention) - Add `wiki_page_events` to project hook APIs (Ben Boeckel) diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js index 10afa7e4329..d4d5927d3b0 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js +++ b/app/assets/javascripts/lib/utils/datetime_utility.js @@ -67,6 +67,14 @@ $.timeago.settings.strings = tmpLocale; }; + w.gl.utils.getDayDifference = function(a, b) { + var millisecondsPerDay = 1000 * 60 * 60 * 24; + var date1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate()); + var date2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate()); + + return Math.floor((date2 - date1) / millisecondsPerDay); + } + })(window); }).call(this); diff --git a/app/assets/javascripts/users/calendar.js b/app/assets/javascripts/users/calendar.js index 8b3dbf5f5ae..74ecf4f4cf9 100644 --- a/app/assets/javascripts/users/calendar.js +++ b/app/assets/javascripts/users/calendar.js @@ -3,7 +3,6 @@ this.Calendar = (function() { function Calendar(timestamps, calendar_activities_path) { - var group, i; this.calendar_activities_path = calendar_activities_path; this.clickDay = bind(this.clickDay, this); this.currentSelectedDate = ''; @@ -13,26 +12,36 @@ this.monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; this.months = []; this.timestampsTmp = []; - i = 0; - group = 0; - _.each(timestamps, (function(_this) { - return function(count, date) { - var day, innerArray, newDate; - newDate = new Date(parseInt(date) * 1000); - day = newDate.getDay(); - if ((day === 0 && i !== 0) || i === 0) { - _this.timestampsTmp.push([]); - group++; - } - innerArray = _this.timestampsTmp[group - 1]; - innerArray.push({ - count: count, - date: newDate, - day: day - }); - return i++; - }; - })(this)); + var group = 0; + + var today = new Date() + today.setHours(0, 0, 0, 0, 0); + + var oneYearAgo = new Date(today); + oneYearAgo.setFullYear(today.getFullYear() - 1); + + var days = gl.utils.getDayDifference(oneYearAgo, today); + + for(var i = 0; i <= days; i++) { + var date = new Date(oneYearAgo); + date.setDate(date.getDate() + i); + + var day = date.getDay(); + var count = timestamps[date.getTime() * 0.001]; + + if ((day === 0 && i !== 0) || i === 0) { + this.timestampsTmp.push([]); + group++; + } + + var innerArray = this.timestampsTmp[group - 1]; + innerArray.push({ + count: count || 0, + date: date, + day: day + }); + } + this.colorKey = this.initColorKey(); this.color = this.initColor(); this.renderSvg(group); diff --git a/lib/gitlab/contributions_calendar.rb b/lib/gitlab/contributions_calendar.rb index 9dc2602867e..bd681f03173 100644 --- a/lib/gitlab/contributions_calendar.rb +++ b/lib/gitlab/contributions_calendar.rb @@ -23,7 +23,6 @@ module Gitlab dates.each do |date| date_id = date.to_time.to_i.to_s - @timestamps[date_id] = 0 day_events = events.find { |day_events| day_events["date"] == date } if day_events diff --git a/spec/javascripts/datetime_utility_spec.js.coffee b/spec/javascripts/datetime_utility_spec.js.coffee index 6b9617341fe..8bd113e7d86 100644 --- a/spec/javascripts/datetime_utility_spec.js.coffee +++ b/spec/javascripts/datetime_utility_spec.js.coffee @@ -29,3 +29,22 @@ describe 'Date time utils', -> it 'should return Saturday', -> day = gl.utils.getDayName(new Date('07/23/2016')) expect(day).toBe('Saturday') + + describe 'get day difference', -> + it 'should return 7', -> + firstDay = new Date('07/01/2016') + secondDay = new Date('07/08/2016') + difference = gl.utils.getDayDifference(firstDay, secondDay) + expect(difference).toBe(7) + + it 'should return 31', -> + firstDay = new Date('07/01/2016') + secondDay = new Date('08/01/2016') + difference = gl.utils.getDayDifference(firstDay, secondDay) + expect(difference).toBe(31) + + it 'should return 365', -> + firstDay = new Date('07/02/2015') + secondDay = new Date('07/01/2016') + difference = gl.utils.getDayDifference(firstDay, secondDay) + expect(difference).toBe(365) \ No newline at end of file -- cgit v1.2.1 From abcafc38f12e37b4475b048249741b871c54e477 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 25 Aug 2016 14:06:48 -0500 Subject: Fix changelog --- CHANGELOG | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4da8845ad09..4a335f58594 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,11 +19,7 @@ v 8.12.0 (unreleased) v 8.11.3 (unreleased) - Allow system info page to handle case where info is unavailable - -v 8.11.3 (unreleased) - Label list shows all issues (opened or closed) with that label - -v 8.11.2 - Don't show resolve conflicts link before MR status is updated - Don't prevent viewing the MR when git refs for conflicts can't be found on disk @@ -31,6 +27,7 @@ v 8.11.3 (unreleased) - Don't try to show merge conflict resolution info if a merge conflict contains non-UTF-8 characters v 8.11.2 (unreleased) +v 8.11.2 - Show "Create Merge Request" widget for push events to fork projects on the source project v 8.11.1 -- cgit v1.2.1 From 9d95dce61b073a094eccf7f9193321f8558355b7 Mon Sep 17 00:00:00 2001 From: Ruben Davila Date: Thu, 25 Aug 2016 16:12:43 -0500 Subject: Fix CHANGELOG entries related to 8.11 release. --- CHANGELOG | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 4a335f58594..b0574726126 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -11,7 +11,18 @@ v 8.12.0 (unreleased) - Add Sentry logging to API calls - Automatically expand hidden discussions when accessed by a permalink !5585 (Mike Greiling) - Added tests for diff notes - - Fix inline emoji text alignment (ClemMakesApps) + - Add delimiter to project stars and forks count (ClemMakesApps) + - Fix badge count alignment (ClemMakesApps) + - Fix branch title trailing space on hover (ClemMakesApps) + - Award emoji tooltips containing more than 10 usernames are now truncated !4780 (jlogandavison) + - Fix duplicate "me" in award emoji tooltip !5218 (jlogandavison) + - Fix spacing and vertical alignment on build status icon on commits page (ClemMakesApps) + - Update merge_requests.md with a simpler way to check out a merge request. !5944 + - Fix button missing type (ClemMakesApps) + - Move to project dropdown with infinite scroll for better performance + - Load branches asynchronously in Cherry Pick and Revert dialogs. + - Add merge request versions !5467 + - Change using size to use count and caching it for number of group members. !5935 - Added 'only_allow_merge_if_build_succeeds' project setting in the API. !5930 (Duck) - Reduce number of database queries on builds tab - Use the default branch for displaying the project icon instead of master !5792 (Hannes Rosenögger) @@ -23,29 +34,23 @@ v 8.11.3 (unreleased) - Don't show resolve conflicts link before MR status is updated - Don't prevent viewing the MR when git refs for conflicts can't be found on disk -v 8.11.3 (unreleased) - - Don't try to show merge conflict resolution info if a merge conflict contains non-UTF-8 characters - -v 8.11.2 (unreleased) v 8.11.2 - - Show "Create Merge Request" widget for push events to fork projects on the source project + - Show "Create Merge Request" widget for push events to fork projects on the source project. !5978 + - Use gitlab-workhorse 0.7.11 !5983 + - Does not halt the GitHub import process when an error occurs. !5763 + - Fix file links on project page when default view is Files !5933 + - Fixed enter key in search input not working !5888 v 8.11.1 - - Does not halt the GitHub import process when an error occurs - - Fix file links on project page when default view is Files !5933 - - Change using size to use count and caching it for number of group members + - Pulled due to packaging error. v 8.11.0 - - Add merge request versions !5467 - -v 8.11.0 (unreleased) - Use test coverage value from the latest successful pipeline in badge. !5862 - Add test coverage report badge. !5708 - Remove the http_parser.rb dependency by removing the tinder gem. !5758 (tbalthazar) - Add Koding (online IDE) integration - Ability to specify branches for Pivotal Tracker integration (Egor Lynko) - Fix don't pass a local variable called `i` to a partial. !20510 (herminiotorres) - - Add delimiter to project stars and forks count (ClemMakesApps) - Fix rename `add_users_into_project` and `projects_ids`. !20512 (herminiotorres) - Fix adding line comments on the initial commit to a repo !5900 - Fix the title of the toggle dropdown button. !5515 (herminiotorres) @@ -61,7 +66,6 @@ v 8.11.0 (unreleased) - Use long options for curl examples in documentation !5703 (winniehell) - Added tooltip listing label names to the labels value in the collapsed issuable sidebar - Remove magic comments (`# encoding: UTF-8`) from Ruby files. !5456 (winniehell) - - Fix badge count alignment (ClemMakesApps) - GitLab Performance Monitoring can now track custom events such as the number of tags pushed to a repository - Add support for relative links starting with ./ or / to RelativeLinkFilter (winniehell) - Allow naming U2F devices !5833 @@ -102,7 +106,6 @@ v 8.11.0 (unreleased) - Enforce 2FA restrictions on API authentication endpoints !5820 - Limit git rev-list output count to one in forced push check - Show deployment status on merge requests with external URLs - - Fix branch title trailing space on hover (ClemMakesApps) - Clean up unused routes (Josef Strzibny) - Fix issue on empty project to allow developers to only push to protected branches if given permission - API: Add enpoints for pipelines @@ -119,7 +122,6 @@ v 8.11.0 (unreleased) - Fix devise deprecation warnings. - Check for 2FA when using Git over HTTP and only allow PersonalAccessTokens as password in that case !5764 - Update version_sorter and use new interface for faster tag sorting - - Load branches asynchronously in Cherry Pick and Revert dialogs. - Optimize checking if a user has read access to a list of issues !5370 - Store all DB secrets in secrets.yml, under descriptive names !5274 - Fix syntax highlighting in file editor @@ -140,8 +142,6 @@ v 8.11.0 (unreleased) - Remove `search_id` of labels dropdown filter to fix 'Missleading URI for labels in Merge Requests and Issues view'. !5368 (Scott Le) - Load project invited groups and members eagerly in `ProjectTeam#fetch_members` - Add pipeline events hook - - Award emoji tooltips containing more than 10 usernames are now truncated !4780 (jlogandavison) - - Fix duplicate "me" in award emoji tooltip !5218 (jlogandavison) - Bump gitlab_git to speedup DiffCollection iterations - Rewrite description of a blocked user in admin settings. (Elias Werberich) - Make branches sortable without push permission !5462 (winniehell) @@ -153,14 +153,12 @@ v 8.11.0 (unreleased) - Fix search for notes which belongs to deleted objects - Allow Akismet to be trained by submitting issues as spam or ham !5538 - Add GitLab Workhorse version to admin dashboard (Katarzyna Kobierska Ula Budziszewska) - - Fix spacing and vertical alignment on build status icon on commits page (ClemMakesApps) - Allow branch names ending with .json for graph and network page !5579 (winniehell) - Add the `sprockets-es6` gem - Improve OAuth2 client documentation (muteor) - Fix diff comments inverted toggle bug (ClemMakesApps) - Multiple trigger variables show in separate lines (Katarzyna Kobierska Ula Budziszewska) - Profile requests when a header is passed - - Fix button missing type (ClemMakesApps) - Avoid calculation of line_code and position for _line partial when showing diff notes on discussion tab. - Speedup DiffNote#active? on discussions, preloading noteables and avoid touching git repository to return diff_refs when possible - Add commit stats in commit api. !5517 (dixpac) @@ -169,7 +167,6 @@ v 8.11.0 (unreleased) - edit_blob_link will use blob passed onto the options parameter - Make error pages responsive (Takuya Noguchi) - The performance of the project dropdown used for moving issues has been improved - - Move to project dropdown with infinite scroll for better performance - Fix skip_repo parameter being ignored when destroying a namespace - Add all builds into stage/job dropdowns on builds page - Change requests_profiles resource constraint to catch virtually any file @@ -201,7 +198,6 @@ v 8.11.0 (unreleased) - Eliminate unneeded calls to Repository#blob_at when listing commits with no path - Update gitlab_git gem to 10.4.7 - Simplify SQL queries of marking a todo as done - - Update merge_requests.md with a simpler way to check out a merge request. !5944 v 8.10.7 - Upgrade Hamlit to 2.6.1. !5873 -- cgit v1.2.1 From ace38e8397bd4c3eca11e0aafe9a8682ad81bf45 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 24 Aug 2016 20:06:16 -0700 Subject: Fix external issue tracker "Issues" link leading to 404s a70431f874 modified the behavior to link to the external issue tracker issues URL instead of the project path URL. This restores the previous behavior. Closes #21252, #21402 --- CHANGELOG | 1 + app/controllers/projects/issues_controller.rb | 2 +- spec/controllers/projects/issues_controller_spec.rb | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index abd94a0cd0c..134c89472a9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -34,6 +34,7 @@ v 8.11.3 (unreleased) - Label list shows all issues (opened or closed) with that label - Don't show resolve conflicts link before MR status is updated - Don't prevent viewing the MR when git refs for conflicts can't be found on disk + - Fix external issue tracker "Issues" link leading to 404s v 8.11.2 - Show "Create Merge Request" widget for push events to fork projects on the source project. !5978 diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 7b0189150f8..7c03dcd2e64 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -212,7 +212,7 @@ class Projects::IssuesController < Projects::ApplicationController if action_name == 'new' redirect_to external.new_issue_path else - redirect_to external.issues_url + redirect_to external.project_path end end diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 0836b71056c..16929767ddf 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -8,13 +8,13 @@ describe Projects::IssuesController do describe "GET #index" do context 'external issue tracker' do it 'redirects to the external issue tracker' do - external = double(issues_url: 'https://example.com/issues') + external = double(project_path: 'https://example.com/project') allow(project).to receive(:external_issue_tracker).and_return(external) controller.instance_variable_set(:@project, project) get :index, namespace_id: project.namespace.path, project_id: project - expect(response).to redirect_to('https://example.com/issues') + expect(response).to redirect_to('https://example.com/project') end end -- cgit v1.2.1