From b125fb4bcb637bd842db7d018d8f9c60303d9beb Mon Sep 17 00:00:00 2001 From: Matt Lee Date: Fri, 20 Jan 2017 10:55:32 -0500 Subject: WIP: This makes the default sort order for branches 'recently updated' rather than by name. --- app/controllers/projects/branches_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb index 89d84809e3a..07a0a51855b 100644 --- a/app/controllers/projects/branches_controller.rb +++ b/app/controllers/projects/branches_controller.rb @@ -7,7 +7,7 @@ class Projects::BranchesController < Projects::ApplicationController before_action :authorize_push_code!, only: [:new, :create, :destroy, :destroy_all_merged] def index - @sort = params[:sort].presence || sort_value_name + @sort = params[:sort].presence || sort_value_recently_updated @branches = BranchesFinder.new(@repository, params).execute @branches = Kaminari.paginate_array(@branches).page(params[:page]) -- cgit v1.2.1 From a5521bad4012a9eea21cb067271c8ec1810c6d8c Mon Sep 17 00:00:00 2001 From: Hiroyuki Sato Date: Sat, 4 Mar 2017 23:03:14 +0900 Subject: Prevent concurrent editing wiki --- app/controllers/projects/wikis_controller.rb | 5 ++++- app/models/wiki_page.rb | 17 ++++++++++++----- app/services/wiki_pages/update_service.rb | 2 +- app/views/projects/wikis/_form.html.haml | 2 ++ app/views/projects/wikis/edit.html.haml | 6 ++++++ .../unreleased/1827-prevent-concurrent-editing-wiki.yml | 4 ++++ .../projects/wiki/user_updates_wiki_page_spec.rb | 12 +++++++++++- spec/models/wiki_page_spec.rb | 14 ++++++++++++++ 8 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 changelogs/unreleased/1827-prevent-concurrent-editing-wiki.yml diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb index 2d8064c9878..d27af79e003 100644 --- a/app/controllers/projects/wikis_controller.rb +++ b/app/controllers/projects/wikis_controller.rb @@ -56,6 +56,9 @@ class Projects::WikisController < Projects::ApplicationController else render 'edit' end + rescue WikiPage::PageChangedError + @conflict = true + render 'edit' end def create @@ -125,6 +128,6 @@ class Projects::WikisController < Projects::ApplicationController end def wiki_params - params[:wiki].slice(:title, :content, :format, :message) + params[:wiki].slice(:title, :content, :format, :message, :last_commit_sha) end end diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 2caebb496db..4c5df6937f2 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -1,4 +1,6 @@ class WikiPage + PageChangedError = Class.new(StandardError) + include ActiveModel::Validations include ActiveModel::Conversion include StaticModel @@ -176,17 +178,22 @@ class WikiPage # Updates an existing Wiki Page, creating a new version. # - # new_content - The raw markup content to replace the existing. - # format - Optional symbol representing the content format. - # See ProjectWiki::MARKUPS Hash for available formats. - # message - Optional commit message to set on the new version. + # new_content - The raw markup content to replace the existing. + # format - Optional symbol representing the content format. + # See ProjectWiki::MARKUPS Hash for available formats. + # message - Optional commit message to set on the new version. + # last_commit_sha - Optional last commit sha to validate the page unchanged. # # Returns the String SHA1 of the newly created page # or False if the save was unsuccessful. - def update(new_content = "", format = :markdown, message = nil) + def update(new_content = "", format = :markdown, message = nil, last_commit_sha = nil) @attributes[:content] = new_content @attributes[:format] = format + if last_commit_sha && last_commit_sha != commit.sha + raise PageChangedError.new("You are attempting to update a page that has changed since you started editing it.") + end + save :update_page, @page, content, format, message end diff --git a/app/services/wiki_pages/update_service.rb b/app/services/wiki_pages/update_service.rb index 8f6a50da838..1046bb3be01 100644 --- a/app/services/wiki_pages/update_service.rb +++ b/app/services/wiki_pages/update_service.rb @@ -1,7 +1,7 @@ module WikiPages class UpdateService < WikiPages::BaseService def execute(page) - if page.update(@params[:content], @params[:format], @params[:message]) + if page.update(@params[:content], @params[:format], @params[:message], @params[:last_commit_sha]) execute_hooks(page, 'update') end diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml index c52527332bc..9313f9e9c96 100644 --- a/app/views/projects/wikis/_form.html.haml +++ b/app/views/projects/wikis/_form.html.haml @@ -2,6 +2,8 @@ = form_errors(@page) = f.hidden_field :title, value: @page.title + - if @page.persisted? + = f.hidden_field :last_commit_sha, value: @page.commit.sha .form-group = f.label :format, class: 'control-label' .col-sm-10 diff --git a/app/views/projects/wikis/edit.html.haml b/app/views/projects/wikis/edit.html.haml index 8cf018da1b7..2ec03a00db9 100644 --- a/app/views/projects/wikis/edit.html.haml +++ b/app/views/projects/wikis/edit.html.haml @@ -2,6 +2,12 @@ - page_title "Edit", @page.title.capitalize, "Wiki" %div{ class: container_class } + - if @conflict + .alert.alert-danger + Someone edited the page the same time you did. Please check out + = link_to "the page", namespace_project_wiki_path(@project.namespace, @project, @page), target: "_blank" + and make sure your changes will not unintentionally remove theirs. + .wiki-page-header.has-sidebar-toggle %button.btn.btn-default.sidebar-toggle.js-sidebar-wiki-toggle{ role: "button", type: "button" } = icon('angle-double-left') diff --git a/changelogs/unreleased/1827-prevent-concurrent-editing-wiki.yml b/changelogs/unreleased/1827-prevent-concurrent-editing-wiki.yml new file mode 100644 index 00000000000..3ef6544c013 --- /dev/null +++ b/changelogs/unreleased/1827-prevent-concurrent-editing-wiki.yml @@ -0,0 +1,4 @@ +--- +title: Prevent concurrent editing wiki +merge_request: 9707 +author: Hiroyuki Sato diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb index f842d14fa96..a15bb3ad46b 100644 --- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb @@ -8,7 +8,7 @@ feature 'Projects > Wiki > User updates wiki page', feature: true do login_as(user) visit namespace_project_path(project.namespace, project) - WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute + @wiki_page = WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute click_link 'Wiki' end @@ -25,6 +25,16 @@ feature 'Projects > Wiki > User updates wiki page', feature: true do expect(page).to have_content("Last edited by #{user.name}") expect(page).to have_content('My awesome wiki!') end + + scenario 'page has been updated since the user opened the edit page' do + click_link 'Edit' + + @wiki_page.update("Update") + + click_button 'Save changes' + + expect(page).to have_content 'Someone edited the page the same time you did.' + end end context 'in a group namespace' do diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 753dc938c52..d76d94c3186 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -208,6 +208,20 @@ describe WikiPage, models: true do expect(@page.update("more content")).to be_truthy end end + + context "with same last commit sha" do + it "returns true" do + last_commit_sha = @page.commit.sha + expect(@page.update("more content", :markdown, nil, last_commit_sha)).to be_truthy + end + end + + context "with different last commit sha" do + it "raises exception" do + last_commit_sha = "xxx" + expect { @page.update("more content", :markdown, nil, last_commit_sha) }.to raise_error(WikiPage::PageChangedError) + end + end end describe "#destroy" do -- cgit v1.2.1 From 839018d2d4e3e899b1fa06a43d093a0fdceced42 Mon Sep 17 00:00:00 2001 From: Hiroyuki Sato Date: Thu, 9 Mar 2017 13:25:15 +0900 Subject: Refactor spec --- spec/features/projects/wiki/user_updates_wiki_page_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb index a15bb3ad46b..56ce6aa8b1f 100644 --- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb @@ -2,13 +2,13 @@ require 'spec_helper' feature 'Projects > Wiki > User updates wiki page', feature: true do let(:user) { create(:user) } + let!(:wiki_page) { WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute } background do project.team << [user, :master] login_as(user) visit namespace_project_path(project.namespace, project) - @wiki_page = WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute click_link 'Wiki' end @@ -29,7 +29,7 @@ feature 'Projects > Wiki > User updates wiki page', feature: true do scenario 'page has been updated since the user opened the edit page' do click_link 'Edit' - @wiki_page.update("Update") + wiki_page.update('Update') click_button 'Save changes' -- cgit v1.2.1 From ac1667f286242a9af7709b3f6711ef08380abd3e Mon Sep 17 00:00:00 2001 From: Chad Malchow Date: Tue, 4 Apr 2017 17:39:32 +0000 Subject: added article from techbeacon on CI --- doc/university/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/university/README.md b/doc/university/README.md index c1661f0b52b..88dac143356 100644 --- a/doc/university/README.md +++ b/doc/university/README.md @@ -121,6 +121,7 @@ The curriculum is composed of GitLab videos, screencasts, presentations, project 1. [Setting up GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/) 1. [IBM: Continuous Delivery vs Continuous Deployment - Video](https://www.youtube.com/watch?v=igwFj8PPSnw) 1. [Amazon: Transition to Continuous Delivery - Video](https://www.youtube.com/watch?v=esEFaY0FDKc) +2. [TechBeacon: Doing continuous delivery? Focus first on reducing release cycle times](https://techbeacon.com/doing-continuous-delivery-focus-first-reducing-release-cycle-times) 1. See **[Integrations](#integrations)** for integrations with other CI services. #### 2.4. Workflow -- cgit v1.2.1 From 9ecb85a4f36669fa05c961eef84cf46d7bf7f39c Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Mon, 5 Jun 2017 23:38:06 +0800 Subject: Forbid creating pipeline if it's protected and cannot create the tag if it's a tag, and cannot merge the branch if it's a branch. --- app/services/ci/create_pipeline_service.rb | 10 +++++ spec/services/ci/create_pipeline_service_spec.rb | 47 +++++++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 13baa63220d..a54af4749ac 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -27,6 +27,12 @@ module Ci return error('Reference not found') end + if tag? + return error("#{ref} is protected") unless access.can_create_tag?(ref) + else + return error("#{ref} is protected") unless access.can_merge_to_branch?(ref) + end + unless commit return error('Commit not found') end @@ -94,6 +100,10 @@ module Ci @commit ||= project.commit(origin_sha || origin_ref) end + def access + @access ||= Gitlab::UserAccess.new(current_user, project: project) + end + def sha commit.try(:id) end diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 597c3947e71..13a1c6a504d 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -3,13 +3,14 @@ require 'spec_helper' describe Ci::CreatePipelineService, services: true do let(:project) { create(:project, :repository) } let(:user) { create(:admin) } + let(:ref_name) { 'refs/heads/master' } before do stub_ci_pipeline_to_return_yaml_file end describe '#execute' do - def execute_service(source: :push, after: project.commit.id, message: 'Message', ref: 'refs/heads/master') + def execute_service(source: :push, after: project.commit.id, message: 'Message', ref: ref_name) params = { ref: ref, before: '00000000', after: after, @@ -311,5 +312,49 @@ describe Ci::CreatePipelineService, services: true do end.not_to change { Environment.count } end end + + shared_examples 'when ref is protected' do + let(:user) { create(:user) } + + context 'when user is developer' do + before do + project.add_developer(user) + end + + it 'does not create a pipeline' do + expect(execute_service).not_to be_persisted + expect(Ci::Pipeline.count).to eq(0) + end + end + + context 'when user is master' do + before do + project.add_master(user) + end + + it 'creates a pipeline' do + expect(execute_service).to be_persisted + expect(Ci::Pipeline.count).to eq(1) + end + end + end + + context 'when ref is a protected branch' do + before do + create(:protected_branch, project: project, name: 'master') + end + + it_behaves_like 'when ref is protected' + end + + context 'when ref is a protected tag' do + let(:ref_name) { 'refs/tags/v1.0.0' } + + before do + create(:protected_tag, project: project, name: '*') + end + + it_behaves_like 'when ref is protected' + end end end -- cgit v1.2.1 From 4408da47b8462055612548b8d43a679c861595e8 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 6 Jun 2017 00:56:38 +0800 Subject: Move the check to Pipeline.allowed_to_create? So that we could use it for the schedule before trying to use CreatePipelineService --- app/models/ci/pipeline.rb | 14 +++++ app/models/ci/pipeline_schedule.rb | 2 +- app/services/ci/create_pipeline_service.rb | 28 +++++---- spec/models/ci/pipeline_spec.rb | 97 ++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 13 deletions(-) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 425ca9278eb..e2caeda2289 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -162,6 +162,20 @@ module Ci where.not(duration: nil).sum(:duration) end + def self.allowed_to_create?(user, project, ref) + repo = project.repository + access = Gitlab::UserAccess.new(user, project: project) + + Ability.allowed?(user, :create_pipeline, project) && + if repo.ref_exists?("#{Gitlab::Git::BRANCH_REF_PREFIX}#{ref}") + access.can_merge_to_branch?(ref) + elsif repo.ref_exists?("#{Gitlab::Git::TAG_REF_PREFIX}#{ref}") + access.can_create_tag?(ref) + else + false + end + end + def stage(name) stage = Ci::Stage.new(self, name: name) stage unless stage.statuses_count.zero? diff --git a/app/models/ci/pipeline_schedule.rb b/app/models/ci/pipeline_schedule.rb index 45d8cd34359..eaca2774bf9 100644 --- a/app/models/ci/pipeline_schedule.rb +++ b/app/models/ci/pipeline_schedule.rb @@ -37,7 +37,7 @@ module Ci end def runnable_by_owner? - Ability.allowed?(owner, :create_pipeline, project) + Ci::Pipeline.allowed_to_create?(owner, project, ref) end def set_next_run_at diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index a54af4749ac..5ed9d1aa517 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -27,10 +27,8 @@ module Ci return error('Reference not found') end - if tag? - return error("#{ref} is protected") unless access.can_create_tag?(ref) - else - return error("#{ref} is protected") unless access.can_merge_to_branch?(ref) + unless Ci::Pipeline.allowed_to_create?(current_user, project, ref) + return error("Insufficient permissions for protected #{ref}") end unless commit @@ -53,6 +51,12 @@ module Ci return error('No builds for this pipeline.') end + process! + end + + private + + def process! Ci::Pipeline.transaction do update_merge_requests_head_pipeline if pipeline.save @@ -66,8 +70,6 @@ module Ci pipeline.tap(&:process!) end - private - def update_merge_requests_head_pipeline return unless pipeline.latest? @@ -100,10 +102,6 @@ module Ci @commit ||= project.commit(origin_sha || origin_ref) end - def access - @access ||= Gitlab::UserAccess.new(current_user, project: project) - end - def sha commit.try(:id) end @@ -121,11 +119,17 @@ module Ci end def branch? - project.repository.ref_exists?(Gitlab::Git::BRANCH_REF_PREFIX + ref) + return @is_branch if defined?(@is_branch) + + @is_branch = + project.repository.ref_exists?(Gitlab::Git::BRANCH_REF_PREFIX + ref) end def tag? - project.repository.ref_exists?(Gitlab::Git::TAG_REF_PREFIX + ref) + return @is_tag if defined?(@is_tag) + + @is_tag = + project.repository.ref_exists?(Gitlab::Git::TAG_REF_PREFIX + ref) end def ref diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index ae1b01b76ab..72af8130481 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -28,6 +28,103 @@ describe Ci::Pipeline, models: true do it { is_expected.to respond_to :git_author_email } it { is_expected.to respond_to :short_sha } + describe '.allowed_to_create?' do + let(:user) { create(:user) } + let(:project) { create(:project, :repository) } + let(:ref) { 'master' } + + subject { described_class.allowed_to_create?(user, project, ref) } + + context 'when user is a developer' do + before do + project.add_developer(user) + end + + it { is_expected.to be_truthy } + + context 'when the branch is protected' do + let!(:protected_branch) do + create(:protected_branch, project: project, name: ref) + end + + it { is_expected.to be_falsey } + + context 'when developers are allowed to merge' do + let!(:protected_branch) do + create(:protected_branch, + :developers_can_merge, + project: project, + name: ref) + end + + it { is_expected.to be_truthy } + end + end + + context 'when the tag is protected' do + let(:ref) { 'v1.0.0' } + + let!(:protected_tag) do + create(:protected_tag, project: project, name: ref) + end + + it { is_expected.to be_falsey } + + context 'when developers are allowed to create the tag' do + let!(:protected_tag) do + create(:protected_tag, + :developers_can_create, + project: project, + name: ref) + end + + it { is_expected.to be_truthy } + end + end + end + + context 'when user is a master' do + before do + project.add_master(user) + end + + it { is_expected.to be_truthy } + + context 'when the branch is protected' do + let!(:protected_branch) do + create(:protected_branch, project: project, name: ref) + end + + it { is_expected.to be_truthy } + end + + context 'when the tag is protected' do + let(:ref) { 'v1.0.0' } + + let!(:protected_tag) do + create(:protected_tag, project: project, name: ref) + end + + it { is_expected.to be_truthy } + + context 'when no one can create the tag' do + let!(:protected_tag) do + create(:protected_tag, + :no_one_can_create, + project: project, + name: ref) + end + + it { is_expected.to be_falsey } + end + end + end + + context 'when owner cannot create pipeline' do + it { is_expected.to be_falsey } + end + end + describe '#source' do context 'when creating new pipeline' do let(:pipeline) do -- cgit v1.2.1 From 3c71c12b74ddc5875da2a4b53f0abd066a5a2f56 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 6 Jun 2017 00:58:58 +0800 Subject: Add changelog entry --- changelogs/unreleased/30634-protected-pipeline.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/30634-protected-pipeline.yml diff --git a/changelogs/unreleased/30634-protected-pipeline.yml b/changelogs/unreleased/30634-protected-pipeline.yml new file mode 100644 index 00000000000..e46538e5b46 --- /dev/null +++ b/changelogs/unreleased/30634-protected-pipeline.yml @@ -0,0 +1,5 @@ +--- +title: Disallow running the pipeline if ref is protected and user cannot merge the + branch or create the tag +merge_request: 11910 +author: -- cgit v1.2.1 From 47b93fd76138ce24ec78926647497e52c5101dd8 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 6 Jun 2017 02:19:47 +0800 Subject: Don't check permission, only protected ref if no user --- app/services/ci/create_pipeline_service.rb | 10 ++++- spec/services/ci/create_pipeline_service_spec.rb | 57 +++++++++++++++++++++++- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 5ed9d1aa517..7efea564ba6 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -27,7 +27,7 @@ module Ci return error('Reference not found') end - unless Ci::Pipeline.allowed_to_create?(current_user, project, ref) + unless triggering_user_allowed_for_ref?(trigger_request, ref) return error("Insufficient permissions for protected #{ref}") end @@ -56,6 +56,14 @@ module Ci private + def triggering_user_allowed_for_ref?(trigger_request, ref) + triggering_user = current_user || trigger_request.trigger.owner + + (triggering_user && + Ci::Pipeline.allowed_to_create?(triggering_user, project, ref)) || + !project.protected_for?(ref) + end + def process! Ci::Pipeline.transaction do update_merge_requests_head_pipeline if pipeline.save diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 13a1c6a504d..2616dcc6f04 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -10,13 +10,19 @@ describe Ci::CreatePipelineService, services: true do end describe '#execute' do - def execute_service(source: :push, after: project.commit.id, message: 'Message', ref: ref_name) + def execute_service( + source: :push, + after: project.commit.id, + message: 'Message', + ref: ref_name, + trigger_request: nil) params = { ref: ref, before: '00000000', after: after, commits: [{ message: message }] } - described_class.new(project, user, params).execute(source) + described_class.new(project, user, params).execute( + source, trigger_request: trigger_request) end context 'valid params' do @@ -337,6 +343,53 @@ describe Ci::CreatePipelineService, services: true do expect(Ci::Pipeline.count).to eq(1) end end + + context 'when trigger belongs to no one' do + let(:user) {} + let(:trigger_request) { create(:ci_trigger_request) } + + it 'does not create a pipeline' do + expect(execute_service(trigger_request: trigger_request)) + .not_to be_persisted + expect(Ci::Pipeline.count).to eq(0) + end + end + + context 'when trigger belongs to a developer' do + let(:user) {} + + let(:trigger_request) do + create(:ci_trigger_request).tap do |request| + user = create(:user) + project.add_developer(user) + request.trigger.update(owner: user) + end + end + + it 'does not create a pipeline' do + expect(execute_service(trigger_request: trigger_request)) + .not_to be_persisted + expect(Ci::Pipeline.count).to eq(0) + end + end + + context 'when trigger belongs to a master' do + let(:user) {} + + let(:trigger_request) do + create(:ci_trigger_request).tap do |request| + user = create(:user) + project.add_master(user) + request.trigger.update(owner: user) + end + end + + it 'does not create a pipeline' do + expect(execute_service(trigger_request: trigger_request)) + .to be_persisted + expect(Ci::Pipeline.count).to eq(1) + end + end end context 'when ref is a protected branch' do -- cgit v1.2.1 From 9984f07a28273035d6c989913cb76c9c371965d0 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 6 Jun 2017 18:00:34 +0800 Subject: Disallow legacy trigger without a owner Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11910#note_31594492 https://gitlab.com/gitlab-org/gitlab-ce/issues/30634#note_31601001 --- app/services/ci/create_pipeline_service.rb | 8 +++++--- spec/services/ci/create_pipeline_service_spec.rb | 13 +++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 7efea564ba6..a51c52b3f91 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -23,6 +23,10 @@ module Ci return error('Insufficient permissions to create a new pipeline') end + unless trigger_request && trigger_request.trigger.owner + return error('Legacy trigger without a owner is not allowed') + end + unless branch? || tag? return error('Reference not found') end @@ -59,9 +63,7 @@ module Ci def triggering_user_allowed_for_ref?(trigger_request, ref) triggering_user = current_user || trigger_request.trigger.owner - (triggering_user && - Ci::Pipeline.allowed_to_create?(triggering_user, project, ref)) || - !project.protected_for?(ref) + Ci::Pipeline.allowed_to_create?(triggering_user, project, ref) end def process! diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 2616dcc6f04..b8534a9d1aa 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -409,5 +409,18 @@ describe Ci::CreatePipelineService, services: true do it_behaves_like 'when ref is protected' end + + context 'when ref is not protected' do + context 'when trigger belongs to no one' do + let(:user) {} + let(:trigger_request) { create(:ci_trigger_request) } + + it 'does not create a pipeline' do + expect(execute_service(trigger_request: trigger_request)) + .not_to be_persisted + expect(Ci::Pipeline.count).to eq(0) + end + end + end end end -- cgit v1.2.1 From e86e1e515a7a4e4e1ee53d3d33bdfebfddd226a6 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 6 Jun 2017 20:23:19 +0800 Subject: Try to report why it's failing and fix tests --- app/services/ci/create_pipeline_service.rb | 2 +- app/services/ci/create_trigger_request_service.rb | 3 ++- lib/api/triggers.rb | 9 +++++---- lib/api/v3/triggers.rb | 7 ++++--- lib/ci/api/triggers.rb | 7 ++++--- spec/requests/ci/api/triggers_spec.rb | 14 ++++++++++++-- spec/services/ci/create_trigger_request_service_spec.rb | 12 ++++++------ spec/workers/post_receive_spec.rb | 1 + 8 files changed, 35 insertions(+), 20 deletions(-) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index a51c52b3f91..b3dbb548454 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -23,7 +23,7 @@ module Ci return error('Insufficient permissions to create a new pipeline') end - unless trigger_request && trigger_request.trigger.owner + if trigger_request && !trigger_request.trigger.owner return error('Legacy trigger without a owner is not allowed') end diff --git a/app/services/ci/create_trigger_request_service.rb b/app/services/ci/create_trigger_request_service.rb index beb27a5a597..e4f55c27f61 100644 --- a/app/services/ci/create_trigger_request_service.rb +++ b/app/services/ci/create_trigger_request_service.rb @@ -6,7 +6,8 @@ module Ci pipeline = Ci::CreatePipelineService.new(project, trigger.owner, ref: ref). execute(:trigger, ignore_skip_ci: true, trigger_request: trigger_request) - trigger_request if pipeline.persisted? + trigger_request.pipeline = pipeline + trigger_request end end end diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb index a9f2ca2608e..9e444563fdf 100644 --- a/lib/api/triggers.rb +++ b/lib/api/triggers.rb @@ -28,11 +28,12 @@ module API # create request and trigger builds trigger_request = Ci::CreateTriggerRequestService.new.execute(project, trigger, params[:ref].to_s, variables) - if trigger_request - present trigger_request.pipeline, with: Entities::Pipeline + pipeline = trigger_request.pipeline + + if pipeline.persisted? + present pipeline, with: Entities::Pipeline else - errors = 'No pipeline created' - render_api_error!(errors, 400) + render_validation_error!(pipeline) end end diff --git a/lib/api/v3/triggers.rb b/lib/api/v3/triggers.rb index a23d6b6b48c..7e75c579528 100644 --- a/lib/api/v3/triggers.rb +++ b/lib/api/v3/triggers.rb @@ -29,11 +29,12 @@ module API # create request and trigger builds trigger_request = Ci::CreateTriggerRequestService.new.execute(project, trigger, params[:ref].to_s, variables) - if trigger_request + pipeline = trigger_request.pipeline + + if pipeline.persisted? present trigger_request, with: ::API::V3::Entities::TriggerRequest else - errors = 'No builds created' - render_api_error!(errors, 400) + render_validation_error!(pipeline) end end diff --git a/lib/ci/api/triggers.rb b/lib/ci/api/triggers.rb index 6e622601680..0e5174e13ab 100644 --- a/lib/ci/api/triggers.rb +++ b/lib/ci/api/triggers.rb @@ -25,11 +25,12 @@ module Ci # create request and trigger builds trigger_request = Ci::CreateTriggerRequestService.new.execute(project, trigger, params[:ref], variables) - if trigger_request + pipeline = trigger_request.pipeline + + if pipeline.persisted? present trigger_request, with: Entities::TriggerRequest else - errors = 'No builds created' - render_api_error!(errors, 400) + render_validation_error!(pipeline) end end end diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb index 26b03c0f148..e481ca916ab 100644 --- a/spec/requests/ci/api/triggers_spec.rb +++ b/spec/requests/ci/api/triggers_spec.rb @@ -5,7 +5,14 @@ describe Ci::API::Triggers do let!(:trigger_token) { 'secure token' } let!(:project) { create(:project, :repository, ci_id: 10) } let!(:project2) { create(:empty_project, ci_id: 11) } - let!(:trigger) { create(:ci_trigger, project: project, token: trigger_token) } + + let!(:trigger) do + create(:ci_trigger, + project: project, + token: trigger_token, + owner: create(:user)) + end + let(:options) do { token: trigger_token @@ -14,6 +21,8 @@ describe Ci::API::Triggers do before do stub_ci_pipeline_to_return_yaml_file + + project.add_developer(trigger.owner) end context 'Handles errors' do @@ -47,7 +56,8 @@ describe Ci::API::Triggers do it 'returns bad request with no builds created if there\'s no commit for that ref' do post ci_api("/projects/#{project.ci_id}/refs/other-branch/trigger"), options expect(response).to have_http_status(400) - expect(json_response['message']).to eq('No builds created') + expect(json_response['message']['base']) + .to contain_exactly('Reference not found') end context 'Validates variables' do diff --git a/spec/services/ci/create_trigger_request_service_spec.rb b/spec/services/ci/create_trigger_request_service_spec.rb index f2956262f4b..8582c74e734 100644 --- a/spec/services/ci/create_trigger_request_service_spec.rb +++ b/spec/services/ci/create_trigger_request_service_spec.rb @@ -3,10 +3,13 @@ require 'spec_helper' describe Ci::CreateTriggerRequestService, services: true do let(:service) { described_class.new } let(:project) { create(:project, :repository) } - let(:trigger) { create(:ci_trigger, project: project) } + let(:trigger) { create(:ci_trigger, project: project, owner: owner) } + let(:owner) { create(:user) } before do stub_ci_pipeline_to_return_yaml_file + + project.add_developer(owner) end describe '#execute' do @@ -21,9 +24,6 @@ describe Ci::CreateTriggerRequestService, services: true do end context 'with owner' do - let(:owner) { create(:user) } - let(:trigger) { create(:ci_trigger, project: project, owner: owner) } - it { expect(subject).to be_kind_of(Ci::TriggerRequest) } it { expect(subject.pipeline).to be_kind_of(Ci::Pipeline) } it { expect(subject.pipeline).to be_trigger } @@ -36,7 +36,7 @@ describe Ci::CreateTriggerRequestService, services: true do context 'no commit for ref' do subject { service.execute(project, trigger, 'other-branch') } - it { expect(subject).to be_nil } + it { expect(subject.pipeline).not_to be_persisted } end context 'no builds created' do @@ -46,7 +46,7 @@ describe Ci::CreateTriggerRequestService, services: true do stub_ci_pipeline_yaml_file('script: { only: [develop], script: hello World }') end - it { expect(subject).to be_nil } + it { expect(subject.pipeline).not_to be_persisted } end end end diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index f4bc63bcc6a..7da48647bb5 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -82,6 +82,7 @@ describe PostReceive do OpenStruct.new(id: '123456') end allow_any_instance_of(Ci::CreatePipelineService).to receive(:branch?).and_return(true) + allow_any_instance_of(Repository).to receive(:ref_exists?).and_return(true) stub_ci_pipeline_to_return_yaml_file end -- cgit v1.2.1 From 6d17ddac5aaf6c178a13c1e371b072780e7fd049 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 6 Jun 2017 23:52:57 +0800 Subject: Still allow legacy triggers, feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11910#note_31632911 --- app/services/ci/create_pipeline_service.rb | 8 +++----- spec/services/ci/create_pipeline_service_spec.rb | 6 +++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index b3dbb548454..7efea564ba6 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -23,10 +23,6 @@ module Ci return error('Insufficient permissions to create a new pipeline') end - if trigger_request && !trigger_request.trigger.owner - return error('Legacy trigger without a owner is not allowed') - end - unless branch? || tag? return error('Reference not found') end @@ -63,7 +59,9 @@ module Ci def triggering_user_allowed_for_ref?(trigger_request, ref) triggering_user = current_user || trigger_request.trigger.owner - Ci::Pipeline.allowed_to_create?(triggering_user, project, ref) + (triggering_user && + Ci::Pipeline.allowed_to_create?(triggering_user, project, ref)) || + !project.protected_for?(ref) end def process! diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index b8534a9d1aa..348a0ab5102 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -415,10 +415,10 @@ describe Ci::CreatePipelineService, services: true do let(:user) {} let(:trigger_request) { create(:ci_trigger_request) } - it 'does not create a pipeline' do + it 'creates a pipeline' do expect(execute_service(trigger_request: trigger_request)) - .not_to be_persisted - expect(Ci::Pipeline.count).to eq(0) + .to be_persisted + expect(Ci::Pipeline.count).to eq(1) end end end -- cgit v1.2.1 From 25f930fbb34f285c2c4bde97c1e85d57a9e771d3 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 7 Jun 2017 00:25:39 +0800 Subject: Fix other tests which tested against error message --- spec/requests/api/triggers_spec.rb | 3 ++- spec/requests/api/v3/triggers_spec.rb | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index 16ddade27d9..c2636b6614e 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -61,7 +61,8 @@ describe API::Triggers do post api("/projects/#{project.id}/trigger/pipeline"), options.merge(ref: 'other-branch') expect(response).to have_http_status(400) - expect(json_response['message']).to eq('No pipeline created') + expect(json_response['message']['base']) + .to contain_exactly('Reference not found') end context 'Validates variables' do diff --git a/spec/requests/api/v3/triggers_spec.rb b/spec/requests/api/v3/triggers_spec.rb index d3de6bf13bc..60212660fb6 100644 --- a/spec/requests/api/v3/triggers_spec.rb +++ b/spec/requests/api/v3/triggers_spec.rb @@ -52,7 +52,8 @@ describe API::V3::Triggers do it 'returns bad request with no builds created if there\'s no commit for that ref' do post v3_api("/projects/#{project.id}/trigger/builds"), options.merge(ref: 'other-branch') expect(response).to have_http_status(400) - expect(json_response['message']).to eq('No builds created') + expect(json_response['message']['base']) + .to contain_exactly('Reference not found') end context 'Validates variables' do -- cgit v1.2.1 From 6e90bae1e7aa3f45089be58a2a59353a46c40493 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Mon, 13 Feb 2017 11:01:58 +0000 Subject: added .nvmrc --- .nvmrc | 1 + 1 file changed, 1 insertion(+) create mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000000..986084f369c --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +7.1 \ No newline at end of file -- cgit v1.2.1 From d39b5085043b43ca76e8e91f7d114a468a004f0f Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Thu, 22 Jun 2017 11:20:16 +0000 Subject: Update .nvmrc to 7.5 --- .nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nvmrc b/.nvmrc index 986084f369c..72906051c5c 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -7.1 \ No newline at end of file +7.5 \ No newline at end of file -- cgit v1.2.1 From 23bfd8c13c803f4efdb9eaf8e6e3c1ffd17640e8 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 4 Jul 2017 05:01:05 +0800 Subject: Consistently check permission for creating pipelines, updating builds and updating pipelines. We check against being able to merge or push if the ref is protected. --- app/models/ci/pipeline.rb | 2 +- app/policies/ci/build_policy.rb | 11 ++++--- app/policies/ci/pipeline_policy.rb | 19 +++++++++++- lib/gitlab/user_access.rb | 4 +++ spec/policies/ci/build_policy_spec.rb | 52 +++++++++++--------------------- spec/policies/ci/pipeline_policy_spec.rb | 47 +++++++++++++++++++++++++++++ 6 files changed, 93 insertions(+), 42 deletions(-) create mode 100644 spec/policies/ci/pipeline_policy_spec.rb diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index a46c1304667..06ce01095ea 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -169,7 +169,7 @@ module Ci Ability.allowed?(user, :create_pipeline, project) && if repo.ref_exists?("#{Gitlab::Git::BRANCH_REF_PREFIX}#{ref}") - access.can_merge_to_branch?(ref) + access.can_push_or_merge_to_branch?(ref) elsif repo.ref_exists?("#{Gitlab::Git::TAG_REF_PREFIX}#{ref}") access.can_create_tag?(ref) else diff --git a/app/policies/ci/build_policy.rb b/app/policies/ci/build_policy.rb index 2d7405dc240..85245528602 100644 --- a/app/policies/ci/build_policy.rb +++ b/app/policies/ci/build_policy.rb @@ -11,19 +11,20 @@ module Ci cannot! :"#{rule}_commit_status" unless can? :"#{rule}_build" end - if can?(:update_build) && protected_action? + if can?(:update_build) && !can_user_update? cannot! :update_build end end private - def protected_action? - return false unless build.action? + def can_user_update? + user_access.can_push_or_merge_to_branch?(build.ref) + end - !::Gitlab::UserAccess + def user_access + @user_access ||= ::Gitlab::UserAccess .new(user, project: build.project) - .can_merge_to_branch?(build.ref) end end end diff --git a/app/policies/ci/pipeline_policy.rb b/app/policies/ci/pipeline_policy.rb index 10aa2d3e72a..e71cc358353 100644 --- a/app/policies/ci/pipeline_policy.rb +++ b/app/policies/ci/pipeline_policy.rb @@ -1,7 +1,24 @@ module Ci class PipelinePolicy < BasePolicy + alias_method :pipeline, :subject + def rules - delegate! @subject.project + delegate! pipeline.project + + if can?(:update_pipeline) && !can_user_update? + cannot! :update_pipeline + end + end + + private + + def can_user_update? + user_access.can_push_or_merge_to_branch?(pipeline.ref) + end + + def user_access + @user_access ||= ::Gitlab::UserAccess + .new(user, project: pipeline.project) end end end diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb index 3b922da7ced..bb05c474fa2 100644 --- a/lib/gitlab/user_access.rb +++ b/lib/gitlab/user_access.rb @@ -48,6 +48,10 @@ module Gitlab end end + def can_push_or_merge_to_branch?(ref) + can_push_to_branch?(ref) || can_merge_to_branch?(ref) + end + def can_push_to_branch?(ref) return false unless can_access_git? diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb index 48a139d4b83..b4c6f3141fb 100644 --- a/spec/policies/ci/build_policy_spec.rb +++ b/spec/policies/ci/build_policy_spec.rb @@ -96,55 +96,37 @@ describe Ci::BuildPolicy, :models do end end - describe 'rules for manual actions' do + describe 'rules for protected branch' do let(:project) { create(:project) } before do project.add_developer(user) - end - - context 'when branch build is assigned to is protected' do - before do - create(:protected_branch, :no_one_can_push, - name: 'some-ref', project: project) - end - context 'when build is a manual action' do - let(:build) do - create(:ci_build, :manual, ref: 'some-ref', pipeline: pipeline) - end - - it 'does not include ability to update build' do - expect(policies).not_to include :update_build - end - end + create(:protected_branch, branch_policy, + name: build.ref, project: project) + end - context 'when build is not a manual action' do - let(:build) do - create(:ci_build, ref: 'some-ref', pipeline: pipeline) - end + context 'when no one can push or merge to the branch' do + let(:branch_policy) { :no_one_can_push } - it 'includes ability to update build' do - expect(policies).to include :update_build - end + it 'does not include ability to update build' do + expect(policies).not_to include :update_build end end - context 'when branch build is assigned to is not protected' do - context 'when build is a manual action' do - let(:build) { create(:ci_build, :manual, pipeline: pipeline) } + context 'when developers can push to the branch' do + let(:branch_policy) { :developers_can_push } - it 'includes ability to update build' do - expect(policies).to include :update_build - end + it 'includes ability to update build' do + expect(policies).to include :update_build end + end - context 'when build is not a manual action' do - let(:build) { create(:ci_build, pipeline: pipeline) } + context 'when developers can push to the branch' do + let(:branch_policy) { :developers_can_merge } - it 'includes ability to update build' do - expect(policies).to include :update_build - end + it 'includes ability to update build' do + expect(policies).to include :update_build end end end diff --git a/spec/policies/ci/pipeline_policy_spec.rb b/spec/policies/ci/pipeline_policy_spec.rb new file mode 100644 index 00000000000..4ecf07a1bf2 --- /dev/null +++ b/spec/policies/ci/pipeline_policy_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe Ci::PipelinePolicy, :models do + let(:user) { create(:user) } + let(:pipeline) { create(:ci_empty_pipeline, project: project) } + + let(:policies) do + described_class.abilities(user, pipeline).to_set + end + + describe 'rules' do + describe 'rules for protected branch' do + let(:project) { create(:project) } + + before do + project.add_developer(user) + + create(:protected_branch, branch_policy, + name: pipeline.ref, project: project) + end + + context 'when no one can push or merge to the branch' do + let(:branch_policy) { :no_one_can_push } + + it 'does not include ability to update pipeline' do + expect(policies).not_to include :update_pipeline + end + end + + context 'when developers can push to the branch' do + let(:branch_policy) { :developers_can_push } + + it 'includes ability to update pipeline' do + expect(policies).to include :update_pipeline + end + end + + context 'when developers can push to the branch' do + let(:branch_policy) { :developers_can_merge } + + it 'includes ability to update pipeline' do + expect(policies).to include :update_pipeline + end + end + end + end +end -- cgit v1.2.1 From 005870d5ce1a00b3405d0ae3a639d0c4befcb7a2 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 4 Jul 2017 05:20:44 +0800 Subject: Fix bad conflict resolution --- app/policies/ci/pipeline_policy.rb | 2 +- app/services/ci/create_pipeline_service.rb | 22 ++++++++++++---------- spec/policies/ci/build_policy_spec.rb | 6 +++--- spec/policies/ci/pipeline_policy_spec.rb | 10 +++++----- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/app/policies/ci/pipeline_policy.rb b/app/policies/ci/pipeline_policy.rb index 73b5a40c7fc..8dba28b8d97 100644 --- a/app/policies/ci/pipeline_policy.rb +++ b/app/policies/ci/pipeline_policy.rb @@ -1,6 +1,6 @@ module Ci class PipelinePolicy < BasePolicy - delegate { pipeline.project } + delegate { @subject.project } condition(:user_cannot_update) do !::Gitlab::UserAccess diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index db12116b3ae..e487b7d5f30 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -51,19 +51,13 @@ module Ci return error('No stages / jobs for this pipeline.') end - process! + process! do + pipeline_created_counter.increment(source: source) + end end private - def triggering_user_allowed_for_ref?(trigger_request, ref) - triggering_user = current_user || trigger_request.trigger.owner - - (triggering_user && - Ci::Pipeline.allowed_to_create?(triggering_user, project, ref)) || - !project.protected_for?(ref) - end - def process! Ci::Pipeline.transaction do update_merge_requests_head_pipeline if pipeline.save @@ -75,11 +69,19 @@ module Ci cancel_pending_pipelines if project.auto_cancel_pending_pipelines? - pipeline_created_counter.increment(source: source) + yield pipeline.tap(&:process!) end + def triggering_user_allowed_for_ref?(trigger_request, ref) + triggering_user = current_user || trigger_request.trigger.owner + + (triggering_user && + Ci::Pipeline.allowed_to_create?(triggering_user, project, ref)) || + !project.protected_for?(ref) + end + def update_merge_requests_head_pipeline return unless pipeline.latest? diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb index 2a8e6653eb8..9e2b0506bf3 100644 --- a/spec/policies/ci/build_policy_spec.rb +++ b/spec/policies/ci/build_policy_spec.rb @@ -110,7 +110,7 @@ describe Ci::BuildPolicy, :models do let(:branch_policy) { :no_one_can_push } it 'does not include ability to update build' do - expect(policies).to be_disallowed :update_build + expect(policy).to be_disallowed :update_build end end @@ -118,7 +118,7 @@ describe Ci::BuildPolicy, :models do let(:branch_policy) { :developers_can_push } it 'includes ability to update build' do - expect(policies).to be_allowed :update_build + expect(policy).to be_allowed :update_build end end @@ -126,7 +126,7 @@ describe Ci::BuildPolicy, :models do let(:branch_policy) { :developers_can_merge } it 'includes ability to update build' do - expect(policies).to be_allowed :update_build + expect(policy).to be_allowed :update_build end end end diff --git a/spec/policies/ci/pipeline_policy_spec.rb b/spec/policies/ci/pipeline_policy_spec.rb index db09be96875..cc04230411f 100644 --- a/spec/policies/ci/pipeline_policy_spec.rb +++ b/spec/policies/ci/pipeline_policy_spec.rb @@ -4,8 +4,8 @@ describe Ci::PipelinePolicy, :models do let(:user) { create(:user) } let(:pipeline) { create(:ci_empty_pipeline, project: project) } - let(:policies) do - described_class.abilities(user, pipeline).to_set + let(:policy) do + described_class.new(user, pipeline) end describe 'rules' do @@ -23,7 +23,7 @@ describe Ci::PipelinePolicy, :models do let(:branch_policy) { :no_one_can_push } it 'does not include ability to update pipeline' do - expect(policies).to be_disallowed :update_pipeline + expect(policy).to be_disallowed :update_pipeline end end @@ -31,7 +31,7 @@ describe Ci::PipelinePolicy, :models do let(:branch_policy) { :developers_can_push } it 'includes ability to update pipeline' do - expect(policies).to be_allowed :update_pipeline + expect(policy).to be_allowed :update_pipeline end end @@ -39,7 +39,7 @@ describe Ci::PipelinePolicy, :models do let(:branch_policy) { :developers_can_merge } it 'includes ability to update pipeline' do - expect(policies).to be_allowed :update_pipeline + expect(policy).to be_allowed :update_pipeline end end end -- cgit v1.2.1 From 28553dbc05989b698777ee085aa2a357ffe576d2 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 4 Jul 2017 05:58:28 +0800 Subject: Update tests due to permission changes --- spec/controllers/projects/jobs_controller_spec.rb | 10 ++++----- .../projects/pipelines_controller_spec.rb | 8 +++---- spec/lib/gitlab/ci/status/build/cancelable_spec.rb | 2 +- spec/lib/gitlab/ci/status/build/factory_spec.rb | 25 +++++++++++++++------- spec/lib/gitlab/ci/status/build/retryable_spec.rb | 2 +- spec/lib/gitlab/ci/status/build/stop_spec.rb | 2 +- spec/models/ci/pipeline_spec.rb | 4 ++-- spec/serializers/job_entity_spec.rb | 6 +++++- spec/serializers/pipeline_details_entity_spec.rb | 6 +++--- spec/serializers/pipeline_entity_spec.rb | 4 ++-- spec/services/ci/process_pipeline_service_spec.rb | 2 +- spec/services/ci/retry_build_service_spec.rb | 4 ++-- spec/services/ci/retry_pipeline_service_spec.rb | 20 ++++++----------- spec/services/create_deployment_service_spec.rb | 2 +- 14 files changed, 51 insertions(+), 46 deletions(-) diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index 472e5fc51a0..9ed48d98360 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -218,7 +218,7 @@ describe Projects::JobsController do describe 'POST retry' do before do - project.add_developer(user) + project.add_master(user) sign_in(user) post_retry @@ -250,7 +250,7 @@ describe Projects::JobsController do describe 'POST play' do before do - project.add_developer(user) + project.add_master(user) create(:protected_branch, :developers_can_merge, name: 'master', project: project) @@ -290,7 +290,7 @@ describe Projects::JobsController do describe 'POST cancel' do before do - project.add_developer(user) + project.add_master(user) sign_in(user) post_cancel @@ -326,7 +326,7 @@ describe Projects::JobsController do describe 'POST cancel_all' do before do - project.add_developer(user) + project.add_master(user) sign_in(user) end @@ -368,7 +368,7 @@ describe Projects::JobsController do describe 'POST erase' do before do - project.add_developer(user) + project.add_master(user) sign_in(user) post_erase diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 734532668d3..3b4d7d069c9 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -8,7 +8,7 @@ describe Projects::PipelinesController do let(:feature) { ProjectFeature::DISABLED } before do - project.add_developer(user) + project.add_master(user) project.project_feature.update( builds_access_level: feature) @@ -158,7 +158,7 @@ describe Projects::PipelinesController do context 'when builds are enabled' do let(:feature) { ProjectFeature::ENABLED } - + it 'retries a pipeline without returning any content' do expect(response).to have_http_status(:no_content) expect(build.reload).to be_retried @@ -175,7 +175,7 @@ describe Projects::PipelinesController do describe 'POST cancel.json' do let!(:pipeline) { create(:ci_pipeline, project: project) } let!(:build) { create(:ci_build, :running, pipeline: pipeline) } - + before do post :cancel, namespace_id: project.namespace, project_id: project, @@ -185,7 +185,7 @@ describe Projects::PipelinesController do context 'when builds are enabled' do let(:feature) { ProjectFeature::ENABLED } - + it 'cancels a pipeline without returning any content' do expect(response).to have_http_status(:no_content) expect(pipeline.reload).to be_canceled diff --git a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb index 114d2490490..e7b880c9b09 100644 --- a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb +++ b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb @@ -48,7 +48,7 @@ describe Gitlab::Ci::Status::Build::Cancelable do describe '#has_action?' do context 'when user is allowed to update build' do before do - build.project.team << [user, :developer] + build.project.add_master(user) end it { is_expected.to have_action } diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb index c8a97016f20..bc21b8af67c 100644 --- a/spec/lib/gitlab/ci/status/build/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb @@ -7,7 +7,7 @@ describe Gitlab::Ci::Status::Build::Factory do let(:factory) { described_class.new(build, user) } before do - project.team << [user, :developer] + project.add_master(user) end context 'when build is successful' do @@ -225,19 +225,20 @@ describe Gitlab::Ci::Status::Build::Factory do end context 'when user has ability to play action' do - before do - project.add_developer(user) - - create(:protected_branch, :developers_can_merge, - name: build.ref, project: project) - end - it 'fabricates status that has action' do expect(status).to have_action end end context 'when user does not have ability to play action' do + before do + project.team.truncate + project.add_developer(user) + + create(:protected_branch, :no_one_can_push, + name: build.ref, project: project) + end + it 'fabricates status that has no action' do expect(status).not_to have_action end @@ -262,6 +263,14 @@ describe Gitlab::Ci::Status::Build::Factory do end context 'when user is not allowed to execute manual action' do + before do + project.team.truncate + project.add_developer(user) + + create(:protected_branch, :no_one_can_push, + name: build.ref, project: project) + end + it 'fabricates status with correct details' do expect(status.text).to eq 'manual' expect(status.group).to eq 'manual' diff --git a/spec/lib/gitlab/ci/status/build/retryable_spec.rb b/spec/lib/gitlab/ci/status/build/retryable_spec.rb index 099d873fc01..ed9752b4ed6 100644 --- a/spec/lib/gitlab/ci/status/build/retryable_spec.rb +++ b/spec/lib/gitlab/ci/status/build/retryable_spec.rb @@ -48,7 +48,7 @@ describe Gitlab::Ci::Status::Build::Retryable do describe '#has_action?' do context 'when user is allowed to update build' do before do - build.project.team << [user, :developer] + build.project.add_master(user) end it { is_expected.to have_action } diff --git a/spec/lib/gitlab/ci/status/build/stop_spec.rb b/spec/lib/gitlab/ci/status/build/stop_spec.rb index 23902f26b1a..7fe3cf7ea6d 100644 --- a/spec/lib/gitlab/ci/status/build/stop_spec.rb +++ b/spec/lib/gitlab/ci/status/build/stop_spec.rb @@ -20,7 +20,7 @@ describe Gitlab::Ci::Status::Build::Stop do describe '#has_action?' do context 'when user is allowed to update build' do before do - build.project.team << [user, :developer] + build.project.add_master(user) end it { is_expected.to have_action } diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 776a674a6d9..7463fb3d379 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -832,7 +832,7 @@ describe Ci::Pipeline, models: true do context 'on failure and build retry' do before do build.drop - project.add_developer(user) + project.add_master(user) Ci::Build.retry(build, user) end @@ -1063,7 +1063,7 @@ describe Ci::Pipeline, models: true do let(:latest_status) { pipeline.statuses.latest.pluck(:status) } before do - project.add_developer(user) + project.add_master(user) end context 'when there is a failed build and failed external status' do diff --git a/spec/serializers/job_entity_spec.rb b/spec/serializers/job_entity_spec.rb index 5ca7bf2fcaf..ec30816654b 100644 --- a/spec/serializers/job_entity_spec.rb +++ b/spec/serializers/job_entity_spec.rb @@ -8,7 +8,7 @@ describe JobEntity do before do allow(request).to receive(:current_user).and_return(user) - project.add_developer(user) + project.add_master(user) end let(:entity) do @@ -90,6 +90,10 @@ describe JobEntity do end context 'when user is not allowed to trigger action' do + before do + project.team.truncate + end + it 'does not contain path to play action' do expect(subject).not_to include(:play_path) end diff --git a/spec/serializers/pipeline_details_entity_spec.rb b/spec/serializers/pipeline_details_entity_spec.rb index d28dec9592a..e9b24b47900 100644 --- a/spec/serializers/pipeline_details_entity_spec.rb +++ b/spec/serializers/pipeline_details_entity_spec.rb @@ -52,7 +52,7 @@ describe PipelineDetailsEntity do context 'user has ability to retry pipeline' do before do - project.team << [user, :developer] + project.add_master(user) end it 'retryable flag is true' do @@ -80,7 +80,7 @@ describe PipelineDetailsEntity do context 'user has ability to cancel pipeline' do before do - project.add_developer(user) + project.add_master(user) end it 'cancelable flag is true' do @@ -97,7 +97,7 @@ describe PipelineDetailsEntity do context 'when pipeline has commit statuses' do let(:pipeline) { create(:ci_empty_pipeline) } - + before do create(:generic_commit_status, pipeline: pipeline) end diff --git a/spec/serializers/pipeline_entity_spec.rb b/spec/serializers/pipeline_entity_spec.rb index 46650f3a80d..46433867b11 100644 --- a/spec/serializers/pipeline_entity_spec.rb +++ b/spec/serializers/pipeline_entity_spec.rb @@ -52,7 +52,7 @@ describe PipelineEntity do context 'user has ability to retry pipeline' do before do - project.team << [user, :developer] + project.add_master(user) end it 'contains retry path' do @@ -80,7 +80,7 @@ describe PipelineEntity do context 'user has ability to cancel pipeline' do before do - project.add_developer(user) + project.add_master(user) end it 'contains cancel path' do diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb index efcaccc254e..1e938a97f5a 100644 --- a/spec/services/ci/process_pipeline_service_spec.rb +++ b/spec/services/ci/process_pipeline_service_spec.rb @@ -9,7 +9,7 @@ describe Ci::ProcessPipelineService, '#execute', :services do end before do - project.add_developer(user) + project.add_master(user) end context 'when simple pipeline is defined' do diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index ef9927c5969..52c6a4a0bc8 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -85,7 +85,7 @@ describe Ci::RetryBuildService, :services do context 'when user has ability to execute build' do before do - project.add_developer(user) + project.add_master(user) end it_behaves_like 'build duplication' @@ -131,7 +131,7 @@ describe Ci::RetryBuildService, :services do context 'when user has ability to execute build' do before do - project.add_developer(user) + project.add_master(user) end it_behaves_like 'build duplication' diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb index 3e860203063..7798db3f3b9 100644 --- a/spec/services/ci/retry_pipeline_service_spec.rb +++ b/spec/services/ci/retry_pipeline_service_spec.rb @@ -244,13 +244,9 @@ describe Ci::RetryPipelineService, '#execute', :services do create_build('verify', :canceled, 1) end - it 'does not reprocess manual action' do - service.execute(pipeline) - - expect(build('test')).to be_pending - expect(build('deploy')).to be_failed - expect(build('verify')).to be_created - expect(pipeline.reload).to be_running + it 'raises an error' do + expect { service.execute(pipeline) } + .to raise_error Gitlab::Access::AccessDeniedError end end @@ -261,13 +257,9 @@ describe Ci::RetryPipelineService, '#execute', :services do create_build('verify', :canceled, 2) end - it 'does not reprocess manual action' do - service.execute(pipeline) - - expect(build('test')).to be_pending - expect(build('deploy')).to be_failed - expect(build('verify')).to be_created - expect(pipeline.reload).to be_running + it 'raises an error' do + expect { service.execute(pipeline) } + .to raise_error Gitlab::Access::AccessDeniedError end end end diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/create_deployment_service_spec.rb index dfab6ebf372..844d9d63428 100644 --- a/spec/services/create_deployment_service_spec.rb +++ b/spec/services/create_deployment_service_spec.rb @@ -244,7 +244,7 @@ describe CreateDeploymentService, services: true do context 'when job is retried' do it_behaves_like 'creates deployment' do before do - project.add_developer(user) + project.add_master(user) end let(:deployable) { Ci::Build.retry(job, user) } -- cgit v1.2.1 From 216bf78fd154005cbf8ec447bfa23f77f6b26775 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 4 Jul 2017 17:48:45 +0800 Subject: Introduce Gitlab::Cache::RequestStoreWrap So that we cache the result of UserAccess#can_push_or_merge_to_branch? in RequestStore, avoiding querying ProtectedBranch over and over for the list of pipelines (i.e. in PipelineSerializer) I don't think this is ideal because I don't like the idea of RequestStore in general, but this is the easiest way to cache it without changing the architecture. In the future we should cache more explicitly rather than this kind of global store. --- lib/gitlab/cache/request_store_wrap.rb | 60 ++++++++++++++++++++++++++++ lib/gitlab/user_access.rb | 10 ++++- spec/serializers/pipeline_serializer_spec.rb | 2 +- 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 lib/gitlab/cache/request_store_wrap.rb diff --git a/lib/gitlab/cache/request_store_wrap.rb b/lib/gitlab/cache/request_store_wrap.rb new file mode 100644 index 00000000000..3e0a5f06b53 --- /dev/null +++ b/lib/gitlab/cache/request_store_wrap.rb @@ -0,0 +1,60 @@ +module Gitlab + module Cache + # This module provides a simple way to cache values in RequestStore, + # and the cache key would be based on the class name, method name, + # customized instance level values, and arguments. + # + # A simple example: + # + # class UserAccess + # extend Gitlab::Cache::RequestStoreWrap + # + # request_store_wrap_key do + # [user.id, project.id] + # end + # + # request_store_wrap def can_push_to_branch?(ref) + # # ... + # end + # end + # + # This way, the result of `can_push_to_branch?` would be cached in + # `RequestStore.store` based on the cache key. + module RequestStoreWrap + def self.extended(klass) + return if klass < self + + extension = Module.new + klass.const_set(:RequestStoreWrapExtension, extension) + klass.prepend(extension) + end + + def request_store_wrap_key(&block) + if block_given? + @request_store_wrap_key = block + else + @request_store_wrap_key + end + end + + def request_store_wrap(method_name) + const_get(:RequestStoreWrapExtension) + .send(:define_method, method_name) do |*args| + return super(*args) unless RequestStore.active? + + klass = self.class + key = [klass.name, + method_name, + *instance_exec(&klass.request_store_wrap_key), + *args].join(':') + + if RequestStore.store.key?(key) + RequestStore.store[key] + else + RequestStore.store[key] = super(*args) + end + end + end + end + end +end diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb index bb05c474fa2..d8b043f5021 100644 --- a/lib/gitlab/user_access.rb +++ b/lib/gitlab/user_access.rb @@ -1,5 +1,11 @@ module Gitlab class UserAccess + extend Gitlab::Cache::RequestStoreWrap + + request_store_wrap_key do + [user&.id, project&.id] + end + attr_reader :user, :project def initialize(user, project: nil) @@ -52,7 +58,7 @@ module Gitlab can_push_to_branch?(ref) || can_merge_to_branch?(ref) end - def can_push_to_branch?(ref) + request_store_wrap def can_push_to_branch?(ref) return false unless can_access_git? if ProtectedBranch.protected?(project, ref) @@ -64,7 +70,7 @@ module Gitlab end end - def can_merge_to_branch?(ref) + request_store_wrap def can_merge_to_branch?(ref) return false unless can_access_git? if ProtectedBranch.protected?(project, ref) diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb index 44813656aff..8dc666586c7 100644 --- a/spec/serializers/pipeline_serializer_spec.rb +++ b/spec/serializers/pipeline_serializer_spec.rb @@ -110,7 +110,7 @@ describe PipelineSerializer do it 'verifies number of queries', :request_store do recorded = ActiveRecord::QueryRecorder.new { subject } - expect(recorded.count).to be_within(1).of(57) + expect(recorded.count).to be_within(1).of(59) expect(recorded.cached_count).to eq(0) end -- cgit v1.2.1 From a4dd3ea168d19d2b65b7e55ed0043c7e7dcac77c Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 4 Jul 2017 18:00:39 +0800 Subject: Make sure that retryable_builds would preload project --- app/models/ci/pipeline.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index bea2ec1e18c..7963386bdb1 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -21,7 +21,7 @@ module Ci has_many :merge_requests, foreign_key: "head_pipeline_id" has_many :pending_builds, -> { pending }, foreign_key: :commit_id, class_name: 'Ci::Build' - has_many :retryable_builds, -> { latest.failed_or_canceled }, foreign_key: :commit_id, class_name: 'Ci::Build' + has_many :retryable_builds, -> { latest.failed_or_canceled.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build' has_many :cancelable_statuses, -> { cancelable }, foreign_key: :commit_id, class_name: 'CommitStatus' has_many :manual_actions, -> { latest.manual_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build' has_many :artifacts, -> { latest.with_artifacts_not_expired.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build' -- cgit v1.2.1 From 090f034b480b8e8b6dee87765878d1746cc75bce Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 4 Jul 2017 22:31:11 +0800 Subject: Add test for RequestStoreWrap --- spec/lib/gitlab/cache/request_store_wrap_spec.rb | 99 ++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 spec/lib/gitlab/cache/request_store_wrap_spec.rb diff --git a/spec/lib/gitlab/cache/request_store_wrap_spec.rb b/spec/lib/gitlab/cache/request_store_wrap_spec.rb new file mode 100644 index 00000000000..82b47c3c7ae --- /dev/null +++ b/spec/lib/gitlab/cache/request_store_wrap_spec.rb @@ -0,0 +1,99 @@ +require 'spec_helper' + +describe Gitlab::Cache::RequestStoreWrap, :request_store do + class ExpensiveAlgorithm < Struct.new(:id, :name, :result) + extend Gitlab::Cache::RequestStoreWrap + + request_store_wrap_key do + [id, name] + end + + request_store_wrap def compute(arg) + result << arg + end + + request_store_wrap def repute(arg) + result << arg + end + end + + let(:algorithm) { ExpensiveAlgorithm.new('id', 'name', []) } + + context 'when RequestStore is active' do + it 'does not compute twice for the same argument' do + result = algorithm.compute(true) + + expect(result).to eq([true]) + expect(algorithm.compute(true)).to eq(result) + expect(algorithm.result).to eq(result) + end + + it 'computes twice for the different argument' do + algorithm.compute(true) + result = algorithm.compute(false) + + expect(result).to eq([true, false]) + expect(algorithm.result).to eq(result) + end + + it 'computes twice for the different keys, id' do + algorithm.compute(true) + algorithm.id = 'ad' + result = algorithm.compute(true) + + expect(result).to eq([true, true]) + expect(algorithm.result).to eq(result) + end + + it 'computes twice for the different keys, name' do + algorithm.compute(true) + algorithm.name = 'same' + result = algorithm.compute(true) + + expect(result).to eq([true, true]) + expect(algorithm.result).to eq(result) + end + + it 'computes twice for the different class name' do + algorithm.compute(true) + allow(ExpensiveAlgorithm).to receive(:name).and_return('CheapAlgo') + result = algorithm.compute(true) + + expect(result).to eq([true, true]) + expect(algorithm.result).to eq(result) + end + + it 'computes twice for the different method' do + algorithm.compute(true) + result = algorithm.repute(true) + + expect(result).to eq([true, true]) + expect(algorithm.result).to eq(result) + end + + it 'computes twice if RequestStore starts over' do + algorithm.compute(true) + RequestStore.end! + RequestStore.clear! + RequestStore.begin! + result = algorithm.compute(true) + + expect(result).to eq([true, true]) + expect(algorithm.result).to eq(result) + end + end + + context 'when RequestStore is inactive' do + before do + RequestStore.end! + end + + it 'computes twice even if everything is the same' do + algorithm.compute(true) + result = algorithm.compute(true) + + expect(result).to eq([true, true]) + expect(algorithm.result).to eq(result) + end + end +end -- cgit v1.2.1 From 2afa90b64a01eaefafacabb1f048835858ece15c Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 4 Jul 2017 23:28:07 +0800 Subject: Don't extend from struct as rubocop suggests --- spec/lib/gitlab/cache/request_store_wrap_spec.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/spec/lib/gitlab/cache/request_store_wrap_spec.rb b/spec/lib/gitlab/cache/request_store_wrap_spec.rb index 82b47c3c7ae..87ea26a9635 100644 --- a/spec/lib/gitlab/cache/request_store_wrap_spec.rb +++ b/spec/lib/gitlab/cache/request_store_wrap_spec.rb @@ -1,9 +1,17 @@ require 'spec_helper' describe Gitlab::Cache::RequestStoreWrap, :request_store do - class ExpensiveAlgorithm < Struct.new(:id, :name, :result) + class ExpensiveAlgorithm extend Gitlab::Cache::RequestStoreWrap + attr_accessor :id, :name, :result + + def initialize(id, name, result) + self.id = id + self.name = name + self.result = result + end + request_store_wrap_key do [id, name] end -- cgit v1.2.1 From 1843eeff0c67e3b5dd3c446de8f67eae59f0a0b4 Mon Sep 17 00:00:00 2001 From: Harish Ramachandran Date: Tue, 4 Jul 2017 18:15:18 -0400 Subject: Docs: Specify that backup restoration must be of the same type --- doc/raketasks/backup_restore.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md index 855f437cd73..ff7c5b1c89b 100644 --- a/doc/raketasks/backup_restore.md +++ b/doc/raketasks/backup_restore.md @@ -5,9 +5,9 @@ An application data backup creates an archive file that contains the database, all repositories and all attachments. -You can only restore a backup to **exactly the same version** of GitLab on which -it was created. The best way to migrate your repositories from one server to -another is through backup restore. +You can only restore a backup to **exactly the same version and type (CE/EE)** +of GitLab on which it was created. The best way to migrate your repositories +from one server to another is through backup restore. ## Backup @@ -369,8 +369,8 @@ The [restore prerequisites section](#restore-prerequisites) includes crucial information. Make sure to read and test the whole restore process at least once before attempting to perform it in a production environment. -You can only restore a backup to **exactly the same version** of GitLab that -you created it on, for example 9.1.0. +You can only restore a backup to **exactly the same version and type (CE/EE)** of +GitLab that you created it on, for example CE 9.1.0. ### Restore prerequisites @@ -441,8 +441,8 @@ Deleting tmp directories...[DONE] This procedure assumes that: -- You have installed the **exact same version** of GitLab Omnibus with which the - backup was created. +- You have installed the **exact same version and type (CE/EE)** of GitLab + Omnibus with which the backup was created. - You have run `sudo gitlab-ctl reconfigure` at least once. - GitLab is running. If not, start it using `sudo gitlab-ctl start`. -- cgit v1.2.1 From 56ea7a0cfe0fcdff33de80fd4602f463367914b2 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 5 Jul 2017 21:55:35 +0800 Subject: Merge allowed_to_create? into CreatePipelineService --- app/models/ci/pipeline.rb | 14 ---- app/models/ci/pipeline_schedule.rb | 4 - app/services/ci/create_pipeline_service.rb | 22 +++-- app/workers/pipeline_schedule_worker.rb | 13 ++- spec/models/ci/pipeline_spec.rb | 97 ---------------------- spec/services/ci/create_pipeline_service_spec.rb | 100 +++++++++++++++++++++++ 6 files changed, 122 insertions(+), 128 deletions(-) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 7963386bdb1..8d1beca9771 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -164,20 +164,6 @@ module Ci where.not(duration: nil).sum(:duration) end - def self.allowed_to_create?(user, project, ref) - repo = project.repository - access = Gitlab::UserAccess.new(user, project: project) - - Ability.allowed?(user, :create_pipeline, project) && - if repo.ref_exists?("#{Gitlab::Git::BRANCH_REF_PREFIX}#{ref}") - access.can_push_or_merge_to_branch?(ref) - elsif repo.ref_exists?("#{Gitlab::Git::TAG_REF_PREFIX}#{ref}") - access.can_create_tag?(ref) - else - false - end - end - def self.internal_sources sources.reject { |source| source == "external" }.values end diff --git a/app/models/ci/pipeline_schedule.rb b/app/models/ci/pipeline_schedule.rb index eaca2774bf9..49455e79c15 100644 --- a/app/models/ci/pipeline_schedule.rb +++ b/app/models/ci/pipeline_schedule.rb @@ -36,10 +36,6 @@ module Ci update_attribute(:active, false) end - def runnable_by_owner? - Ci::Pipeline.allowed_to_create?(owner, project, ref) - end - def set_next_run_at self.next_run_at = Gitlab::Ci::CronParser.new(cron, cron_timezone).next_time_from(Time.now) end diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index e487b7d5f30..485161e5f3f 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -27,7 +27,7 @@ module Ci return error('Reference not found') end - unless triggering_user_allowed_for_ref?(trigger_request, ref) + unless triggering_user_allowed_for_ref?(trigger_request) return error("Insufficient permissions for protected #{ref}") end @@ -74,14 +74,26 @@ module Ci pipeline.tap(&:process!) end - def triggering_user_allowed_for_ref?(trigger_request, ref) + def triggering_user_allowed_for_ref?(trigger_request) triggering_user = current_user || trigger_request.trigger.owner - (triggering_user && - Ci::Pipeline.allowed_to_create?(triggering_user, project, ref)) || + (triggering_user && allowed_to_create?(triggering_user)) || !project.protected_for?(ref) end + def allowed_to_create?(triggering_user) + access = Gitlab::UserAccess.new(triggering_user, project: project) + + Ability.allowed?(triggering_user, :create_pipeline, project) && + if branch? + access.can_push_or_merge_to_branch?(ref) + elsif tag? + access.can_create_tag?(ref) + else + false + end + end + def update_merge_requests_head_pipeline return unless pipeline.latest? @@ -145,7 +157,7 @@ module Ci end def ref - Gitlab::Git.ref_name(origin_ref) + @ref ||= Gitlab::Git.ref_name(origin_ref) end def valid_sha? diff --git a/app/workers/pipeline_schedule_worker.rb b/app/workers/pipeline_schedule_worker.rb index 7b485b3363c..d7087f20dfc 100644 --- a/app/workers/pipeline_schedule_worker.rb +++ b/app/workers/pipeline_schedule_worker.rb @@ -6,15 +6,12 @@ class PipelineScheduleWorker Ci::PipelineSchedule.active.where("next_run_at < ?", Time.now) .preload(:owner, :project).find_each do |schedule| begin - unless schedule.runnable_by_owner? - schedule.deactivate! - next - end - - Ci::CreatePipelineService.new(schedule.project, - schedule.owner, - ref: schedule.ref) + pipeline = Ci::CreatePipelineService.new(schedule.project, + schedule.owner, + ref: schedule.ref) .execute(:schedule, save_on_errors: false, schedule: schedule) + + schedule.deactivate! unless pipeline.persisted? rescue => e Rails.logger.error "#{schedule.id}: Failed to create a scheduled pipeline: #{e.message}" ensure diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 7463fb3d379..d400bdfe8f8 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -28,103 +28,6 @@ describe Ci::Pipeline, models: true do it { is_expected.to respond_to :git_author_email } it { is_expected.to respond_to :short_sha } - describe '.allowed_to_create?' do - let(:user) { create(:user) } - let(:project) { create(:project, :repository) } - let(:ref) { 'master' } - - subject { described_class.allowed_to_create?(user, project, ref) } - - context 'when user is a developer' do - before do - project.add_developer(user) - end - - it { is_expected.to be_truthy } - - context 'when the branch is protected' do - let!(:protected_branch) do - create(:protected_branch, project: project, name: ref) - end - - it { is_expected.to be_falsey } - - context 'when developers are allowed to merge' do - let!(:protected_branch) do - create(:protected_branch, - :developers_can_merge, - project: project, - name: ref) - end - - it { is_expected.to be_truthy } - end - end - - context 'when the tag is protected' do - let(:ref) { 'v1.0.0' } - - let!(:protected_tag) do - create(:protected_tag, project: project, name: ref) - end - - it { is_expected.to be_falsey } - - context 'when developers are allowed to create the tag' do - let!(:protected_tag) do - create(:protected_tag, - :developers_can_create, - project: project, - name: ref) - end - - it { is_expected.to be_truthy } - end - end - end - - context 'when user is a master' do - before do - project.add_master(user) - end - - it { is_expected.to be_truthy } - - context 'when the branch is protected' do - let!(:protected_branch) do - create(:protected_branch, project: project, name: ref) - end - - it { is_expected.to be_truthy } - end - - context 'when the tag is protected' do - let(:ref) { 'v1.0.0' } - - let!(:protected_tag) do - create(:protected_tag, project: project, name: ref) - end - - it { is_expected.to be_truthy } - - context 'when no one can create the tag' do - let!(:protected_tag) do - create(:protected_tag, - :no_one_can_create, - project: project, - name: ref) - end - - it { is_expected.to be_falsey } - end - end - end - - context 'when owner cannot create pipeline' do - it { is_expected.to be_falsey } - end - end - describe '#source' do context 'when creating new pipeline' do let(:pipeline) do diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 7d960dc411f..66218772084 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -432,4 +432,104 @@ describe Ci::CreatePipelineService, :services do end end end + + describe '#allowed_to_create?' do + let(:user) { create(:user) } + let(:project) { create(:project, :repository) } + let(:ref) { 'master' } + + subject do + described_class.new(project, user, ref: ref) + .send(:allowed_to_create?, user) + end + + context 'when user is a developer' do + before do + project.add_developer(user) + end + + it { is_expected.to be_truthy } + + context 'when the branch is protected' do + let!(:protected_branch) do + create(:protected_branch, project: project, name: ref) + end + + it { is_expected.to be_falsey } + + context 'when developers are allowed to merge' do + let!(:protected_branch) do + create(:protected_branch, + :developers_can_merge, + project: project, + name: ref) + end + + it { is_expected.to be_truthy } + end + end + + context 'when the tag is protected' do + let(:ref) { 'v1.0.0' } + + let!(:protected_tag) do + create(:protected_tag, project: project, name: ref) + end + + it { is_expected.to be_falsey } + + context 'when developers are allowed to create the tag' do + let!(:protected_tag) do + create(:protected_tag, + :developers_can_create, + project: project, + name: ref) + end + + it { is_expected.to be_truthy } + end + end + end + + context 'when user is a master' do + before do + project.add_master(user) + end + + it { is_expected.to be_truthy } + + context 'when the branch is protected' do + let!(:protected_branch) do + create(:protected_branch, project: project, name: ref) + end + + it { is_expected.to be_truthy } + end + + context 'when the tag is protected' do + let(:ref) { 'v1.0.0' } + + let!(:protected_tag) do + create(:protected_tag, project: project, name: ref) + end + + it { is_expected.to be_truthy } + + context 'when no one can create the tag' do + let!(:protected_tag) do + create(:protected_tag, + :no_one_can_create, + project: project, + name: ref) + end + + it { is_expected.to be_falsey } + end + end + end + + context 'when owner cannot create pipeline' do + it { is_expected.to be_falsey } + end + end end -- cgit v1.2.1 From 550ccf443059412a26adfcba15fbe9d05d39a5f9 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 6 Jul 2017 17:37:27 +0800 Subject: Make message and code more clear --- app/services/ci/create_pipeline_service.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 485161e5f3f..a8034e30a85 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -28,7 +28,7 @@ module Ci end unless triggering_user_allowed_for_ref?(trigger_request) - return error("Insufficient permissions for protected #{ref}") + return error("Insufficient permissions for protected ref '#{ref}'") end unless commit @@ -77,8 +77,11 @@ module Ci def triggering_user_allowed_for_ref?(trigger_request) triggering_user = current_user || trigger_request.trigger.owner - (triggering_user && allowed_to_create?(triggering_user)) || + if triggering_user + allowed_to_create?(triggering_user) + else # legacy triggers don't have a corresponding user !project.protected_for?(ref) + end end def allowed_to_create?(triggering_user) -- cgit v1.2.1 From b8f2bc749fa9bc4b0b2ad0b02b56fc39fe12cffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Thu, 13 Jul 2017 09:54:28 +0800 Subject: Add uk translation difference of Pipeline Schedules --- locale/uk/part.po | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 locale/uk/part.po diff --git a/locale/uk/part.po b/locale/uk/part.po new file mode 100644 index 00000000000..ef5864be5c9 --- /dev/null +++ b/locale/uk/part.po @@ -0,0 +1,38 @@ +# Андрей Витюк , 2017. #zanata +msgid "" +msgstr "" +"Project-Id-Version: gitlab 1.0.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-15 21:59-0500\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"PO-Revision-Date: 2017-07-12 07:29-0400\n" +"Last-Translator: Андрей Витюк \n" +"Language-Team: Ukrainian\n" +"Language: uk\n" +"X-Generator: Zanata 3.9.6\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +msgid "PipelineSchedules|Input variable key" +msgstr "Введіть ім'я змінної" + +msgid "PipelineSchedules|Input variable value" +msgstr "Вхідні значення змінних" + +msgid "PipelineSchedules|Remove variable row" +msgstr "Видалити змінні" + +msgid "PipelineSchedules|Variables" +msgstr "Змінні" + +msgid "" +"You are going to remove %{group_name}.\n" +"Removed groups CANNOT be restored!\n" +"Are you ABSOLUTELY sure?" +msgstr "" +"Ви хочете видалити %{group_name}.\n" +"Видалені групи НЕ МОЖНА буду відновити!\n" +"Ви АБСОЛЮТНО впевнені?" + -- cgit v1.2.1 From 67f444471e67e2e9420424f1a79386df13bf3157 Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Mon, 17 Jul 2017 22:26:48 +0900 Subject: Add link to doc/api/ci/lint.md --- changelogs/unreleased/35204-doc-api-ci-lint-typo.yml | 4 ++++ doc/api/ci/lint.md | 2 ++ 2 files changed, 6 insertions(+) create mode 100644 changelogs/unreleased/35204-doc-api-ci-lint-typo.yml diff --git a/changelogs/unreleased/35204-doc-api-ci-lint-typo.yml b/changelogs/unreleased/35204-doc-api-ci-lint-typo.yml new file mode 100644 index 00000000000..45b6c57579b --- /dev/null +++ b/changelogs/unreleased/35204-doc-api-ci-lint-typo.yml @@ -0,0 +1,4 @@ +--- +title: Add link to doc/api/ci/lint.md +merge_request: 12914 +author: Takuya Noguchi diff --git a/doc/api/ci/lint.md b/doc/api/ci/lint.md index 6a4dca92cfe..e4a6dc809b1 100644 --- a/doc/api/ci/lint.md +++ b/doc/api/ci/lint.md @@ -47,3 +47,5 @@ Example responses: "error": "content is missing" } ``` + +[ce-5953]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5953 -- cgit v1.2.1 From 3c34a0b99be2cf858831043403ba2268ac270c77 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 18 Jul 2017 20:17:24 +0800 Subject: Remove old request store wrap --- lib/gitlab/cache/request_store_wrap.rb | 60 ------------- spec/lib/gitlab/cache/request_store_wrap_spec.rb | 107 ----------------------- 2 files changed, 167 deletions(-) delete mode 100644 lib/gitlab/cache/request_store_wrap.rb delete mode 100644 spec/lib/gitlab/cache/request_store_wrap_spec.rb diff --git a/lib/gitlab/cache/request_store_wrap.rb b/lib/gitlab/cache/request_store_wrap.rb deleted file mode 100644 index 3e0a5f06b53..00000000000 --- a/lib/gitlab/cache/request_store_wrap.rb +++ /dev/null @@ -1,60 +0,0 @@ -module Gitlab - module Cache - # This module provides a simple way to cache values in RequestStore, - # and the cache key would be based on the class name, method name, - # customized instance level values, and arguments. - # - # A simple example: - # - # class UserAccess - # extend Gitlab::Cache::RequestStoreWrap - # - # request_store_wrap_key do - # [user.id, project.id] - # end - # - # request_store_wrap def can_push_to_branch?(ref) - # # ... - # end - # end - # - # This way, the result of `can_push_to_branch?` would be cached in - # `RequestStore.store` based on the cache key. - module RequestStoreWrap - def self.extended(klass) - return if klass < self - - extension = Module.new - klass.const_set(:RequestStoreWrapExtension, extension) - klass.prepend(extension) - end - - def request_store_wrap_key(&block) - if block_given? - @request_store_wrap_key = block - else - @request_store_wrap_key - end - end - - def request_store_wrap(method_name) - const_get(:RequestStoreWrapExtension) - .send(:define_method, method_name) do |*args| - return super(*args) unless RequestStore.active? - - klass = self.class - key = [klass.name, - method_name, - *instance_exec(&klass.request_store_wrap_key), - *args].join(':') - - if RequestStore.store.key?(key) - RequestStore.store[key] - else - RequestStore.store[key] = super(*args) - end - end - end - end - end -end diff --git a/spec/lib/gitlab/cache/request_store_wrap_spec.rb b/spec/lib/gitlab/cache/request_store_wrap_spec.rb deleted file mode 100644 index 87ea26a9635..00000000000 --- a/spec/lib/gitlab/cache/request_store_wrap_spec.rb +++ /dev/null @@ -1,107 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Cache::RequestStoreWrap, :request_store do - class ExpensiveAlgorithm - extend Gitlab::Cache::RequestStoreWrap - - attr_accessor :id, :name, :result - - def initialize(id, name, result) - self.id = id - self.name = name - self.result = result - end - - request_store_wrap_key do - [id, name] - end - - request_store_wrap def compute(arg) - result << arg - end - - request_store_wrap def repute(arg) - result << arg - end - end - - let(:algorithm) { ExpensiveAlgorithm.new('id', 'name', []) } - - context 'when RequestStore is active' do - it 'does not compute twice for the same argument' do - result = algorithm.compute(true) - - expect(result).to eq([true]) - expect(algorithm.compute(true)).to eq(result) - expect(algorithm.result).to eq(result) - end - - it 'computes twice for the different argument' do - algorithm.compute(true) - result = algorithm.compute(false) - - expect(result).to eq([true, false]) - expect(algorithm.result).to eq(result) - end - - it 'computes twice for the different keys, id' do - algorithm.compute(true) - algorithm.id = 'ad' - result = algorithm.compute(true) - - expect(result).to eq([true, true]) - expect(algorithm.result).to eq(result) - end - - it 'computes twice for the different keys, name' do - algorithm.compute(true) - algorithm.name = 'same' - result = algorithm.compute(true) - - expect(result).to eq([true, true]) - expect(algorithm.result).to eq(result) - end - - it 'computes twice for the different class name' do - algorithm.compute(true) - allow(ExpensiveAlgorithm).to receive(:name).and_return('CheapAlgo') - result = algorithm.compute(true) - - expect(result).to eq([true, true]) - expect(algorithm.result).to eq(result) - end - - it 'computes twice for the different method' do - algorithm.compute(true) - result = algorithm.repute(true) - - expect(result).to eq([true, true]) - expect(algorithm.result).to eq(result) - end - - it 'computes twice if RequestStore starts over' do - algorithm.compute(true) - RequestStore.end! - RequestStore.clear! - RequestStore.begin! - result = algorithm.compute(true) - - expect(result).to eq([true, true]) - expect(algorithm.result).to eq(result) - end - end - - context 'when RequestStore is inactive' do - before do - RequestStore.end! - end - - it 'computes twice even if everything is the same' do - algorithm.compute(true) - result = algorithm.compute(true) - - expect(result).to eq([true, true]) - expect(algorithm.result).to eq(result) - end - end -end -- cgit v1.2.1 From c86e74b284826e2f53bbcba763edd113a7022ffc Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 18 Jul 2017 21:08:48 +0800 Subject: Restore some tests from master --- spec/policies/ci/build_policy_spec.rb | 38 ++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb index 86e57fdf607..9041460ea91 100644 --- a/spec/policies/ci/build_policy_spec.rb +++ b/spec/policies/ci/build_policy_spec.rb @@ -98,16 +98,17 @@ describe Ci::BuildPolicy, :models do describe 'rules for protected branch' do let(:project) { create(:project) } + let(:build) { create(:ci_build, ref: 'some-ref', pipeline: pipeline) } before do project.add_developer(user) - - create(:protected_branch, branch_policy, - name: build.ref, project: project) end context 'when no one can push or merge to the branch' do - let(:branch_policy) { :no_one_can_push } + before do + create(:protected_branch, :no_one_can_push, + name: 'some-ref', project: project) + end it 'does not include ability to update build' do expect(policy).to be_disallowed :update_build @@ -115,7 +116,34 @@ describe Ci::BuildPolicy, :models do end context 'when developers can push to the branch' do - let(:branch_policy) { :developers_can_merge } + before do + create(:protected_branch, :developers_can_merge, + name: 'some-ref', project: project) + end + + it 'includes ability to update build' do + expect(policy).to be_allowed :update_build + end + end + + context 'when no one can create the tag' do + before do + create(:protected_tag, :no_one_can_create, + name: 'some-ref', project: project) + + build.update(tag: true) + end + + it 'does not include ability to update build' do + expect(policy).to be_disallowed :update_build + end + end + + context 'when no one can create the tag but it is not a tag' do + before do + create(:protected_tag, :no_one_can_create, + name: 'some-ref', project: project) + end it 'includes ability to update build' do expect(policy).to be_allowed :update_build -- cgit v1.2.1 From 679789ee93b0e5db3863bfcd539e20074c140984 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 18 Jul 2017 21:56:28 +0800 Subject: Rename can_push_or_merge_to_branch? to can_update_branch? Also make sure pipeline would also check against tag as well --- app/policies/ci/build_policy.rb | 2 +- app/policies/ci/pipeline_policy.rb | 10 +++++++--- app/services/ci/create_pipeline_service.rb | 2 +- lib/gitlab/user_access.rb | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/policies/ci/build_policy.rb b/app/policies/ci/build_policy.rb index 00adb51e7de..00f18d0155b 100644 --- a/app/policies/ci/build_policy.rb +++ b/app/policies/ci/build_policy.rb @@ -6,7 +6,7 @@ module Ci if @subject.tag? !access.can_create_tag?(@subject.ref) else - !access.can_push_or_merge_to_branch?(@subject.ref) + !access.can_update_branch?(@subject.ref) end end diff --git a/app/policies/ci/pipeline_policy.rb b/app/policies/ci/pipeline_policy.rb index 8dba28b8d97..07d724c9cfd 100644 --- a/app/policies/ci/pipeline_policy.rb +++ b/app/policies/ci/pipeline_policy.rb @@ -3,9 +3,13 @@ module Ci delegate { @subject.project } condition(:user_cannot_update) do - !::Gitlab::UserAccess - .new(@user, project: @subject.project) - .can_push_or_merge_to_branch?(@subject.ref) + access = ::Gitlab::UserAccess.new(@user, project: @subject.project) + + if @subject.tag? + !access.can_create_tag?(@subject.ref) + else + !access.can_update_branch?(@subject.ref) + end end rule { user_cannot_update }.prevent :update_pipeline diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 8e2184a1f19..8b689968895 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -89,7 +89,7 @@ module Ci Ability.allowed?(triggering_user, :create_pipeline, project) && if branch? - access.can_push_or_merge_to_branch?(ref) + access.can_update_branch?(ref) elsif tag? access.can_create_tag?(ref) else diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb index c63b98500ee..25698bb8e99 100644 --- a/lib/gitlab/user_access.rb +++ b/lib/gitlab/user_access.rb @@ -54,7 +54,7 @@ module Gitlab end end - def can_push_or_merge_to_branch?(ref) + def can_update_branch?(ref) can_push_to_branch?(ref) || can_merge_to_branch?(ref) end -- cgit v1.2.1 From a27cf281b17641f3f33712633099369867415309 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 18 Jul 2017 22:04:22 +0800 Subject: Unify build policy tests and pipeline policy tests --- spec/policies/ci/build_policy_spec.rb | 10 ++++----- spec/policies/ci/pipeline_policy_spec.rb | 35 ++++++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb index 9041460ea91..e3ea3c960a4 100644 --- a/spec/policies/ci/build_policy_spec.rb +++ b/spec/policies/ci/build_policy_spec.rb @@ -96,7 +96,7 @@ describe Ci::BuildPolicy, :models do end end - describe 'rules for protected branch' do + describe 'rules for protected ref' do let(:project) { create(:project) } let(:build) { create(:ci_build, ref: 'some-ref', pipeline: pipeline) } @@ -107,7 +107,7 @@ describe Ci::BuildPolicy, :models do context 'when no one can push or merge to the branch' do before do create(:protected_branch, :no_one_can_push, - name: 'some-ref', project: project) + name: build.ref, project: project) end it 'does not include ability to update build' do @@ -118,7 +118,7 @@ describe Ci::BuildPolicy, :models do context 'when developers can push to the branch' do before do create(:protected_branch, :developers_can_merge, - name: 'some-ref', project: project) + name: build.ref, project: project) end it 'includes ability to update build' do @@ -129,7 +129,7 @@ describe Ci::BuildPolicy, :models do context 'when no one can create the tag' do before do create(:protected_tag, :no_one_can_create, - name: 'some-ref', project: project) + name: build.ref, project: project) build.update(tag: true) end @@ -142,7 +142,7 @@ describe Ci::BuildPolicy, :models do context 'when no one can create the tag but it is not a tag' do before do create(:protected_tag, :no_one_can_create, - name: 'some-ref', project: project) + name: build.ref, project: project) end it 'includes ability to update build' do diff --git a/spec/policies/ci/pipeline_policy_spec.rb b/spec/policies/ci/pipeline_policy_spec.rb index cc04230411f..b11b06d301f 100644 --- a/spec/policies/ci/pipeline_policy_spec.rb +++ b/spec/policies/ci/pipeline_policy_spec.rb @@ -9,18 +9,18 @@ describe Ci::PipelinePolicy, :models do end describe 'rules' do - describe 'rules for protected branch' do + describe 'rules for protected ref' do let(:project) { create(:project) } before do project.add_developer(user) - - create(:protected_branch, branch_policy, - name: pipeline.ref, project: project) end context 'when no one can push or merge to the branch' do - let(:branch_policy) { :no_one_can_push } + before do + create(:protected_branch, :no_one_can_push, + name: pipeline.ref, project: project) + end it 'does not include ability to update pipeline' do expect(policy).to be_disallowed :update_pipeline @@ -28,15 +28,34 @@ describe Ci::PipelinePolicy, :models do end context 'when developers can push to the branch' do - let(:branch_policy) { :developers_can_push } + before do + create(:protected_branch, :developers_can_merge, + name: pipeline.ref, project: project) + end it 'includes ability to update pipeline' do expect(policy).to be_allowed :update_pipeline end end - context 'when developers can push to the branch' do - let(:branch_policy) { :developers_can_merge } + context 'when no one can create the tag' do + before do + create(:protected_tag, :no_one_can_create, + name: pipeline.ref, project: project) + + pipeline.update(tag: true) + end + + it 'does not include ability to update pipeline' do + expect(policy).to be_disallowed :update_pipeline + end + end + + context 'when no one can create the tag but it is not a tag' do + before do + create(:protected_tag, :no_one_can_create, + name: pipeline.ref, project: project) + end it 'includes ability to update pipeline' do expect(policy).to be_allowed :update_pipeline -- cgit v1.2.1 From 1ed6d1541c7973c08cdd4c1906ddcc0c3db893e3 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 18 Jul 2017 22:13:57 +0800 Subject: Rename :user_cannot_update to :protected_ref --- app/policies/ci/build_policy.rb | 4 ++-- app/policies/ci/pipeline_policy.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/policies/ci/build_policy.rb b/app/policies/ci/build_policy.rb index 00f18d0155b..984e5482288 100644 --- a/app/policies/ci/build_policy.rb +++ b/app/policies/ci/build_policy.rb @@ -1,6 +1,6 @@ module Ci class BuildPolicy < CommitStatusPolicy - condition(:user_cannot_update) do + condition(:protected_ref) do access = ::Gitlab::UserAccess.new(@user, project: @subject.project) if @subject.tag? @@ -10,6 +10,6 @@ module Ci end end - rule { user_cannot_update }.prevent :update_build + rule { protected_ref }.prevent :update_build end end diff --git a/app/policies/ci/pipeline_policy.rb b/app/policies/ci/pipeline_policy.rb index 07d724c9cfd..4e689a9efd5 100644 --- a/app/policies/ci/pipeline_policy.rb +++ b/app/policies/ci/pipeline_policy.rb @@ -2,7 +2,7 @@ module Ci class PipelinePolicy < BasePolicy delegate { @subject.project } - condition(:user_cannot_update) do + condition(:protected_ref) do access = ::Gitlab::UserAccess.new(@user, project: @subject.project) if @subject.tag? @@ -12,6 +12,6 @@ module Ci end end - rule { user_cannot_update }.prevent :update_pipeline + rule { protected_ref }.prevent :update_pipeline end end -- cgit v1.2.1 From 7bd5e571256aff6de132b118f04224e56abf3228 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 18 Jul 2017 22:32:34 +0800 Subject: Instead of adding master, stub_not_protect_default_branch --- spec/controllers/projects/jobs_controller_spec.rb | 14 +++++++++----- spec/controllers/projects/pipelines_controller_spec.rb | 3 ++- spec/lib/gitlab/ci/status/build/cancelable_spec.rb | 4 +++- spec/lib/gitlab/ci/status/build/factory_spec.rb | 14 +++++++------- spec/lib/gitlab/ci/status/build/retryable_spec.rb | 4 +++- spec/lib/gitlab/ci/status/build/stop_spec.rb | 4 +++- spec/models/ci/pipeline_spec.rb | 8 ++++++-- spec/serializers/job_entity_spec.rb | 11 ++++++++--- spec/serializers/pipeline_details_entity_spec.rb | 6 ++++-- spec/serializers/pipeline_entity_spec.rb | 6 ++++-- spec/services/ci/process_pipeline_service_spec.rb | 4 +++- spec/services/ci/retry_build_service_spec.rb | 8 ++++++-- spec/services/create_deployment_service_spec.rb | 4 +++- spec/support/stub_configuration.rb | 5 +++++ 14 files changed, 66 insertions(+), 29 deletions(-) diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index 9ed48d98360..5a295ae47a6 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -7,6 +7,10 @@ describe Projects::JobsController do let(:pipeline) { create(:ci_pipeline, project: project) } let(:user) { create(:user) } + before do + stub_not_protect_default_branch + end + describe 'GET index' do context 'when scope is pending' do before do @@ -218,7 +222,7 @@ describe Projects::JobsController do describe 'POST retry' do before do - project.add_master(user) + project.add_developer(user) sign_in(user) post_retry @@ -250,7 +254,7 @@ describe Projects::JobsController do describe 'POST play' do before do - project.add_master(user) + project.add_developer(user) create(:protected_branch, :developers_can_merge, name: 'master', project: project) @@ -290,7 +294,7 @@ describe Projects::JobsController do describe 'POST cancel' do before do - project.add_master(user) + project.add_developer(user) sign_in(user) post_cancel @@ -326,7 +330,7 @@ describe Projects::JobsController do describe 'POST cancel_all' do before do - project.add_master(user) + project.add_developer(user) sign_in(user) end @@ -368,7 +372,7 @@ describe Projects::JobsController do describe 'POST erase' do before do - project.add_master(user) + project.add_developer(user) sign_in(user) post_erase diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 3b4d7d069c9..c8de275ca3e 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -8,7 +8,8 @@ describe Projects::PipelinesController do let(:feature) { ProjectFeature::DISABLED } before do - project.add_master(user) + stub_not_protect_default_branch + project.add_developer(user) project.project_feature.update( builds_access_level: feature) diff --git a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb index e7b880c9b09..5a7a42d84c0 100644 --- a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb +++ b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb @@ -48,7 +48,9 @@ describe Gitlab::Ci::Status::Build::Cancelable do describe '#has_action?' do context 'when user is allowed to update build' do before do - build.project.add_master(user) + stub_not_protect_default_branch + + build.project.add_developer(user) end it { is_expected.to have_action } diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb index bc21b8af67c..8768302eda1 100644 --- a/spec/lib/gitlab/ci/status/build/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb @@ -7,7 +7,9 @@ describe Gitlab::Ci::Status::Build::Factory do let(:factory) { described_class.new(build, user) } before do - project.add_master(user) + stub_not_protect_default_branch + + project.add_developer(user) end context 'when build is successful' do @@ -232,11 +234,10 @@ describe Gitlab::Ci::Status::Build::Factory do context 'when user does not have ability to play action' do before do - project.team.truncate - project.add_developer(user) + allow(build.project).to receive(:empty_repo?).and_return(false) create(:protected_branch, :no_one_can_push, - name: build.ref, project: project) + name: build.ref, project: build.project) end it 'fabricates status that has no action' do @@ -264,11 +265,10 @@ describe Gitlab::Ci::Status::Build::Factory do context 'when user is not allowed to execute manual action' do before do - project.team.truncate - project.add_developer(user) + allow(build.project).to receive(:empty_repo?).and_return(false) create(:protected_branch, :no_one_can_push, - name: build.ref, project: project) + name: build.ref, project: build.project) end it 'fabricates status with correct details' do diff --git a/spec/lib/gitlab/ci/status/build/retryable_spec.rb b/spec/lib/gitlab/ci/status/build/retryable_spec.rb index ed9752b4ed6..21026f2c968 100644 --- a/spec/lib/gitlab/ci/status/build/retryable_spec.rb +++ b/spec/lib/gitlab/ci/status/build/retryable_spec.rb @@ -48,7 +48,9 @@ describe Gitlab::Ci::Status::Build::Retryable do describe '#has_action?' do context 'when user is allowed to update build' do before do - build.project.add_master(user) + stub_not_protect_default_branch + + build.project.add_developer(user) end it { is_expected.to have_action } diff --git a/spec/lib/gitlab/ci/status/build/stop_spec.rb b/spec/lib/gitlab/ci/status/build/stop_spec.rb index 7fe3cf7ea6d..e0425103f41 100644 --- a/spec/lib/gitlab/ci/status/build/stop_spec.rb +++ b/spec/lib/gitlab/ci/status/build/stop_spec.rb @@ -20,7 +20,9 @@ describe Gitlab::Ci::Status::Build::Stop do describe '#has_action?' do context 'when user is allowed to update build' do before do - build.project.add_master(user) + stub_not_protect_default_branch + + build.project.add_developer(user) end it { is_expected.to have_action } diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index bdfe8706b5e..bbd45f10b1b 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -734,8 +734,10 @@ describe Ci::Pipeline, models: true do context 'on failure and build retry' do before do + stub_not_protect_default_branch + build.drop - project.add_master(user) + project.add_developer(user) Ci::Build.retry(build, user) end @@ -999,7 +1001,9 @@ describe Ci::Pipeline, models: true do let(:latest_status) { pipeline.statuses.latest.pluck(:status) } before do - project.add_master(user) + stub_not_protect_default_branch + + project.add_developer(user) end context 'when there is a failed build and failed external status' do diff --git a/spec/serializers/job_entity_spec.rb b/spec/serializers/job_entity_spec.rb index ec30816654b..026360e91a3 100644 --- a/spec/serializers/job_entity_spec.rb +++ b/spec/serializers/job_entity_spec.rb @@ -7,8 +7,10 @@ describe JobEntity do let(:request) { double('request') } before do + stub_not_protect_default_branch allow(request).to receive(:current_user).and_return(user) - project.add_master(user) + + project.add_developer(user) end let(:entity) do @@ -77,7 +79,7 @@ describe JobEntity do project.add_developer(user) create(:protected_branch, :developers_can_merge, - name: 'master', project: project) + name: job.ref, project: job.project) end it 'contains path to play action' do @@ -91,7 +93,10 @@ describe JobEntity do context 'when user is not allowed to trigger action' do before do - project.team.truncate + allow(job.project).to receive(:empty_repo?).and_return(false) + + create(:protected_branch, :no_one_can_push, + name: job.ref, project: job.project) end it 'does not contain path to play action' do diff --git a/spec/serializers/pipeline_details_entity_spec.rb b/spec/serializers/pipeline_details_entity_spec.rb index e9b24b47900..b990370a271 100644 --- a/spec/serializers/pipeline_details_entity_spec.rb +++ b/spec/serializers/pipeline_details_entity_spec.rb @@ -9,6 +9,8 @@ describe PipelineDetailsEntity do end before do + stub_not_protect_default_branch + allow(request).to receive(:current_user).and_return(user) end @@ -52,7 +54,7 @@ describe PipelineDetailsEntity do context 'user has ability to retry pipeline' do before do - project.add_master(user) + project.add_developer(user) end it 'retryable flag is true' do @@ -80,7 +82,7 @@ describe PipelineDetailsEntity do context 'user has ability to cancel pipeline' do before do - project.add_master(user) + project.add_developer(user) end it 'cancelable flag is true' do diff --git a/spec/serializers/pipeline_entity_spec.rb b/spec/serializers/pipeline_entity_spec.rb index 46433867b11..5b01cc4fc9e 100644 --- a/spec/serializers/pipeline_entity_spec.rb +++ b/spec/serializers/pipeline_entity_spec.rb @@ -5,6 +5,8 @@ describe PipelineEntity do let(:request) { double('request') } before do + stub_not_protect_default_branch + allow(request).to receive(:current_user).and_return(user) end @@ -52,7 +54,7 @@ describe PipelineEntity do context 'user has ability to retry pipeline' do before do - project.add_master(user) + project.add_developer(user) end it 'contains retry path' do @@ -80,7 +82,7 @@ describe PipelineEntity do context 'user has ability to cancel pipeline' do before do - project.add_master(user) + project.add_developer(user) end it 'contains cancel path' do diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb index 1e938a97f5a..5a34ec12c8f 100644 --- a/spec/services/ci/process_pipeline_service_spec.rb +++ b/spec/services/ci/process_pipeline_service_spec.rb @@ -9,7 +9,9 @@ describe Ci::ProcessPipelineService, '#execute', :services do end before do - project.add_master(user) + stub_not_protect_default_branch + + project.add_developer(user) end context 'when simple pipeline is defined' do diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 52c6a4a0bc8..2cf62b54666 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -85,7 +85,9 @@ describe Ci::RetryBuildService, :services do context 'when user has ability to execute build' do before do - project.add_master(user) + stub_not_protect_default_branch + + project.add_developer(user) end it_behaves_like 'build duplication' @@ -131,7 +133,9 @@ describe Ci::RetryBuildService, :services do context 'when user has ability to execute build' do before do - project.add_master(user) + stub_not_protect_default_branch + + project.add_developer(user) end it_behaves_like 'build duplication' diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/create_deployment_service_spec.rb index 844d9d63428..2794721e157 100644 --- a/spec/services/create_deployment_service_spec.rb +++ b/spec/services/create_deployment_service_spec.rb @@ -244,7 +244,9 @@ describe CreateDeploymentService, services: true do context 'when job is retried' do it_behaves_like 'creates deployment' do before do - project.add_master(user) + stub_not_protect_default_branch + + project.add_developer(user) end let(:deployable) { Ci::Build.retry(job, user) } diff --git a/spec/support/stub_configuration.rb b/spec/support/stub_configuration.rb index 48f454c7187..80ecce92dc1 100644 --- a/spec/support/stub_configuration.rb +++ b/spec/support/stub_configuration.rb @@ -9,6 +9,11 @@ module StubConfiguration .to receive_messages(messages) end + def stub_not_protect_default_branch + stub_application_setting( + default_branch_protection: Gitlab::Access::PROTECTION_NONE) + end + def stub_config_setting(messages) allow(Gitlab.config.gitlab).to receive_messages(messages) end -- cgit v1.2.1 From 339baf8f5d7716baa1a6924c94f1896cf8f6805f Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Tue, 18 Jul 2017 17:05:41 -0500 Subject: refactor async calendar data --- app/assets/javascripts/users/index.js | 2 -- app/assets/javascripts/users/user_tabs.js | 27 +++++++++++++++++++++++++-- app/controllers/users_controller.rb | 5 +---- app/views/users/calendar.html.haml | 9 --------- app/views/users/show.html.haml | 2 +- 5 files changed, 27 insertions(+), 18 deletions(-) delete mode 100644 app/views/users/calendar.html.haml diff --git a/app/assets/javascripts/users/index.js b/app/assets/javascripts/users/index.js index ecd8e09161e..c9d5da5c5f9 100644 --- a/app/assets/javascripts/users/index.js +++ b/app/assets/javascripts/users/index.js @@ -1,7 +1,5 @@ -import ActivityCalendar from './activity_calendar'; import User from './user'; // use legacy exports until embedded javascript is refactored -window.Calendar = ActivityCalendar; window.gl = window.gl || {}; window.gl.User = User; diff --git a/app/assets/javascripts/users/user_tabs.js b/app/assets/javascripts/users/user_tabs.js index f8e23c8624d..c499c403e28 100644 --- a/app/assets/javascripts/users/user_tabs.js +++ b/app/assets/javascripts/users/user_tabs.js @@ -1,5 +1,7 @@ /* eslint-disable max-len, space-before-function-paren, no-underscore-dangle, consistent-return, comma-dangle, no-unused-vars, dot-notation, no-new, no-return-assign, camelcase, no-param-reassign, class-methods-use-this */ +import ActivityCalendar from './activity_calendar'; + /* UserTabs @@ -60,6 +62,15 @@ content on the Users#show page. */ +const CALENDAR_TEMPLATE = ` +
+
+
+ Summary of issues, merge requests, push events, and comments +
+
+`; + export default class UserTabs { constructor ({ defaultAction, action, parentEl }) { this.loaded = {}; @@ -147,9 +158,21 @@ export default class UserTabs { return; } const $calendarWrap = this.$parentEl.find('.user-calendar'); - $calendarWrap.load($calendarWrap.data('href')); + const calendarPath = $calendarWrap.data('calendarPath'); + const calendarActivitiesPath = $calendarWrap.data('calendarActivitiesPath'); + + $.ajax({ + dataType: 'json', + type: 'GET', + url: calendarPath, + success: (activityData) => { + $calendarWrap.html(CALENDAR_TEMPLATE); + new ActivityCalendar(activityData, calendarActivitiesPath); + } + }); + new gl.Activities(); - return this.loaded['activity'] = true; + this.loaded['activity'] = true; } toggleLoading(status) { diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 8131eba6a2f..4ee855806ab 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -73,10 +73,7 @@ class UsersController < ApplicationController end def calendar - calendar = contributions_calendar - @activity_dates = calendar.activity_dates - - render 'calendar', layout: false + render json: contributions_calendar.activity_dates end def calendar_activities diff --git a/app/views/users/calendar.html.haml b/app/views/users/calendar.html.haml deleted file mode 100644 index 57b8845c55d..00000000000 --- a/app/views/users/calendar.html.haml +++ /dev/null @@ -1,9 +0,0 @@ -.clearfix.calendar - .js-contrib-calendar - .calendar-hint - Summary of issues, merge requests, push events, and comments -:javascript - new Calendar( - #{@activity_dates.to_json}, - '#{user_calendar_activities_path}' - ); diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index f246bd7a586..863fec842f5 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -105,7 +105,7 @@ .tab-content #activity.tab-pane .row-content-block.calender-block.white.second-block.hidden-xs - .user-calendar{ data: { href: user_calendar_path } } + .user-calendar{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path } } %h4.center.light %i.fa.fa-spinner.fa-spin .user-calendar-activities -- cgit v1.2.1 From f2c0ab398eb71ba9549ebd6d70b7fa7c8707b380 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Tue, 18 Jul 2017 17:27:01 -0500 Subject: refactor users bundle, remove inline javascript, and transform into an async chunk --- app/assets/javascripts/dispatcher.js | 7 +++++++ app/assets/javascripts/users/index.js | 22 ++++++++++++++++++---- app/assets/javascripts/users/user.js | 34 ---------------------------------- app/views/users/show.html.haml | 10 ---------- config/webpack.config.js | 2 -- 5 files changed, 25 insertions(+), 50 deletions(-) delete mode 100644 app/assets/javascripts/users/user.js diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index ae19592ecbe..f114dec4e60 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -516,6 +516,13 @@ import PerformanceBar from './performance_bar'; case 'protected_branches': shortcut_handler = new ShortcutsNavigation(); } + break; + case 'users': + const action = path[1]; + import(/* webpackChunkName: 'user_profile' */ './users') + .then(user => user.default(action)) + .catch(() => {}); + break; } // If we haven't installed a custom shortcut handler, install the default one if (!shortcut_handler) { diff --git a/app/assets/javascripts/users/index.js b/app/assets/javascripts/users/index.js index c9d5da5c5f9..33a83f8dae5 100644 --- a/app/assets/javascripts/users/index.js +++ b/app/assets/javascripts/users/index.js @@ -1,5 +1,19 @@ -import User from './user'; +import Cookies from 'js-cookie'; +import UserTabs from './user_tabs'; -// use legacy exports until embedded javascript is refactored -window.gl = window.gl || {}; -window.gl.User = User; +export default function initUserProfile(action) { + // place profile avatars to top + $('.profile-groups-avatars').tooltip({ + placement: 'top', + }); + + // eslint-disable-next-line no-new + new UserTabs({ parentEl: '.user-profile', action }); + + // hide project limit message + $('.hide-project-limit-message').on('click', (e) => { + e.preventDefault(); + Cookies.set('hide_project_limit_message', 'false'); + $(this).parents('.project-limit-message').remove(); + }); +} diff --git a/app/assets/javascripts/users/user.js b/app/assets/javascripts/users/user.js deleted file mode 100644 index 0b0a3e1afb4..00000000000 --- a/app/assets/javascripts/users/user.js +++ /dev/null @@ -1,34 +0,0 @@ -/* eslint-disable class-methods-use-this */ - -import Cookies from 'js-cookie'; -import UserTabs from './user_tabs'; - -export default class User { - constructor({ action }) { - this.action = action; - this.placeProfileAvatarsToTop(); - this.initTabs(); - this.hideProjectLimitMessage(); - } - - placeProfileAvatarsToTop() { - $('.profile-groups-avatars').tooltip({ - placement: 'top', - }); - } - - initTabs() { - return new UserTabs({ - parentEl: '.user-profile', - action: this.action, - }); - } - - hideProjectLimitMessage() { - $('.hide-project-limit-message').on('click', (e) => { - e.preventDefault(); - Cookies.set('hide_project_limit_message', 'false'); - $(this).parents('.project-limit-message').remove(); - }); - } -} diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 863fec842f5..7107c1b2d81 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -1,8 +1,5 @@ - page_title @user.name - page_description @user.bio -- content_for :page_specific_javascripts do - = page_specific_javascript_bundle_tag('common_d3') - = page_specific_javascript_bundle_tag('users') - header_title @user.name, user_path(@user) - @no_container = true @@ -129,10 +126,3 @@ .loading-status = spinner - -:javascript - var userProfile; - - userProfile = new gl.User({ - action: "#{controller.action_name}" - }); diff --git a/config/webpack.config.js b/config/webpack.config.js index 1113241e402..98626d9fe73 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -66,7 +66,6 @@ var config = { stl_viewer: './blob/stl_viewer.js', terminal: './terminal/terminal_bundle.js', u2f: ['vendor/u2f'], - users: './users/index.js', raven: './raven/index.js', vue_merge_request_widget: './vue_merge_request_widget/index.js', test: './test.js', @@ -184,7 +183,6 @@ var config = { name: 'common_d3', chunks: [ 'graphs', - 'users', 'monitoring', ], }), -- cgit v1.2.1 From b74b2d8e867c0b3d58c636df205060f9434cb0c7 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 19 Jul 2017 01:44:38 -0500 Subject: fix broken tests --- spec/controllers/users_controller_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 842d82cdbe9..7aeb6efd86d 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -80,9 +80,9 @@ describe UsersController do it 'renders calendar' do sign_in(user) - get :calendar, username: user.username + get :calendar, username: user.username, format: :json - expect(response).to render_template('calendar') + expect(response).to have_http_status(200) end context 'forked project' do -- cgit v1.2.1 From b84eb3434d0493cd594eade68d344a9675d72b8a Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 19 Jul 2017 16:42:47 +0800 Subject: Try to merge permission checks into one --- app/services/ci/create_pipeline_service.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 8b689968895..f331f86e622 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -19,18 +19,20 @@ module Ci return error('Pipeline is disabled') end - unless trigger_request || can?(current_user, :create_pipeline, project) - return error('Insufficient permissions to create a new pipeline') + triggering_user = current_user || trigger_request.trigger.owner + + unless allowed_to_trigger_pipeline?(triggering_user) + if can?(triggering_user, :create_pipeline, project) + return error("Insufficient permissions for protected ref '#{ref}'") + else + return error('Insufficient permissions to create a new pipeline') + end end unless branch? || tag? return error('Reference not found') end - unless triggering_user_allowed_for_ref?(trigger_request) - return error("Insufficient permissions for protected ref '#{ref}'") - end - unless commit return error('Commit not found') end @@ -74,9 +76,7 @@ module Ci pipeline.tap(&:process!) end - def triggering_user_allowed_for_ref?(trigger_request) - triggering_user = current_user || trigger_request.trigger.owner - + def allowed_to_trigger_pipeline?(triggering_user) if triggering_user allowed_to_create?(triggering_user) else # legacy triggers don't have a corresponding user @@ -87,7 +87,7 @@ module Ci def allowed_to_create?(triggering_user) access = Gitlab::UserAccess.new(triggering_user, project: project) - Ability.allowed?(triggering_user, :create_pipeline, project) && + can?(triggering_user, :create_pipeline, project) && if branch? access.can_update_branch?(ref) elsif tag? -- cgit v1.2.1 From 561bc570dea970328e0c33972fcf1ed90427f2f2 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 19 Jul 2017 17:53:56 +0800 Subject: Add a test for checking queries with different ref --- spec/serializers/pipeline_serializer_spec.rb | 33 +++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb index 8dc666586c7..262bc4acb69 100644 --- a/spec/serializers/pipeline_serializer_spec.rb +++ b/spec/serializers/pipeline_serializer_spec.rb @@ -108,14 +108,35 @@ describe PipelineSerializer do end end - it 'verifies number of queries', :request_store do - recorded = ActiveRecord::QueryRecorder.new { subject } - expect(recorded.count).to be_within(1).of(59) - expect(recorded.cached_count).to eq(0) + shared_examples 'no N+1 queries' do + it 'verifies number of queries', :request_store do + recorded = ActiveRecord::QueryRecorder.new { subject } + expect(recorded.count).to be_within(1).of(59) + expect(recorded.cached_count).to eq(0) + end + end + + context 'with the same ref' do + let(:ref) { 'feature' } + + it_behaves_like 'no N+1 queries' + end + + context 'with different refs' do + def ref + @sequence ||= 0 + @sequence += 1 + "feature-#{@sequence}" + end + + it_behaves_like 'no N+1 queries' end def create_pipeline(status) - create(:ci_empty_pipeline, project: project, status: status).tap do |pipeline| + create(:ci_empty_pipeline, + project: project, + status: status, + ref: ref).tap do |pipeline| Ci::Build::AVAILABLE_STATUSES.each do |status| create_build(pipeline, status, status) end @@ -125,7 +146,7 @@ describe PipelineSerializer do def create_build(pipeline, stage, status) create(:ci_build, :tags, :triggered, :artifacts, pipeline: pipeline, stage: stage, - name: stage, status: status) + name: stage, status: status, ref: pipeline.ref) end end end -- cgit v1.2.1 From bab44bd99433a77fa45802647d767f0ca94a4a5e Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 19 Jul 2017 13:11:39 +0200 Subject: Fix job merge request link to a forked source project --- app/serializers/build_details_entity.rb | 2 +- spec/serializers/build_details_entity_spec.rb | 83 +++++++++++++++++++++------ 2 files changed, 67 insertions(+), 18 deletions(-) diff --git a/app/serializers/build_details_entity.rb b/app/serializers/build_details_entity.rb index 20f9938f038..8ad5af1987c 100644 --- a/app/serializers/build_details_entity.rb +++ b/app/serializers/build_details_entity.rb @@ -16,7 +16,7 @@ class BuildDetailsEntity < JobEntity end expose :path do |build| - project_merge_request_path(project, build.merge_request) + project_merge_request_path(build.project, build.merge_request) end end diff --git a/spec/serializers/build_details_entity_spec.rb b/spec/serializers/build_details_entity_spec.rb index b92c1c28ba8..e688035cecc 100644 --- a/spec/serializers/build_details_entity_spec.rb +++ b/spec/serializers/build_details_entity_spec.rb @@ -9,37 +9,86 @@ describe BuildDetailsEntity do describe '#as_json' do let(:project) { create(:project, :repository) } - let!(:build) { create(:ci_build, :failed, project: project) } + let(:pipeline) { create(:ci_pipeline, project: project) } + let(:build) { create(:ci_build, :failed, pipeline: pipeline) } let(:request) { double('request') } - let(:entity) { described_class.new(build, request: request, current_user: user, project: project) } + + let(:entity) do + described_class.new(build, request: request, + current_user: user, + project: project) + end + subject { entity.as_json } before do allow(request).to receive(:current_user).and_return(user) end + it 'contains the needed key value pairs' do + expect(subject).to include(:coverage, :erased_at, :duration) + expect(subject).to include(:runner, :pipeline) + expect(subject).to include(:raw_path, :new_issue_path) + end + context 'when the user has access to issues and merge requests' do - let!(:merge_request) do - create(:merge_request, source_project: project, source_branch: build.ref) - end + context 'when merge request orginates from the same project' do + let(:merge_request) do + create(:merge_request, source_project: project, source_branch: build.ref) + end - before do - allow(build).to receive(:merge_request).and_return(merge_request) - end + before do + allow(build).to receive(:merge_request).and_return(merge_request) + end + + it 'contains the needed key value pairs' do + expect(subject).to include(:merge_request) + expect(subject).to include(:new_issue_path) + end + + it 'exposes details of the merge request' do + expect(subject[:merge_request]).to include(:iid, :path) + end - it 'contains the needed key value pairs' do - expect(subject).to include(:coverage, :erased_at, :duration) - expect(subject).to include(:runner, :pipeline) - expect(subject).to include(:raw_path, :merge_request) - expect(subject).to include(:new_issue_path) + it 'has a correct merge request path' do + expect(subject[:merge_request][:path]).to include project.full_path + end end - it 'exposes details of the merge request' do - expect(subject[:merge_request]).to include(:iid, :path) + context 'when merge request is from a fork' do + let(:fork_project) do + create(:empty_project, forked_from_project: project) + end + + let(:pipeline) { create(:ci_pipeline, project: fork_project) } + + before do + allow(build).to receive(:merge_request).and_return(merge_request) + end + + let(:merge_request) do + create(:merge_request, source_project: fork_project, + target_project: project, + source_branch: build.ref) + end + + it 'contains the needed key value pairs' do + expect(subject).to include(:merge_request) + expect(subject).to include(:new_issue_path) + end + + it 'exposes details of the merge request' do + expect(subject[:merge_request]).to include(:iid, :path) + end + + it 'has a correct merge request path' do + expect(subject[:merge_request][:path]) + .to include fork_project.full_path + end end context 'when the build has been erased' do - let!(:build) { create(:ci_build, :erasable, project: project) } + let(:build) { create(:ci_build, :erasable, project: project) } it 'exposes the user whom erased the build' do expect(subject).to include(:erase_path) @@ -47,7 +96,7 @@ describe BuildDetailsEntity do end context 'when the build has been erased' do - let!(:build) { create(:ci_build, erased_at: Time.now, project: project, erased_by: user) } + let(:build) { create(:ci_build, erased_at: Time.now, project: project, erased_by: user) } it 'exposes the user whom erased the build' do expect(subject).to include(:erased_by) -- cgit v1.2.1 From a397a0eb1a4c34c27175e2c4e68e7ceb43a81f02 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 19 Jul 2017 19:12:11 +0800 Subject: Eliminate N+1 queries on checking different protected refs I realized where the N+1 queries were actually coming from project.protected_branches, but how come we cannot preload this, or cache this at all? Then I found that this is somehow a Rails limitation. What we're doing before, eventually come to: project.protected_branches.matching But why it's not cached? (project.protected_branches.loaded? is always false) It's because matching is a class method, which is called on the proxy. In this case, Rails cannot cache the result. I don't know if this is possible to implement or not, because clearly this would require some tricks to implement class methods on associations. So instead, we could just pass project.protected_branches to ProtectedRef.matching, then it would work regularly. With this change, there's no more N+1 queries. --- app/models/concerns/protected_ref.rb | 9 +++++---- lib/gitlab/user_access.rb | 30 +++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/app/models/concerns/protected_ref.rb b/app/models/concerns/protected_ref.rb index fc6b840f7a8..ca9ef2b9375 100644 --- a/app/models/concerns/protected_ref.rb +++ b/app/models/concerns/protected_ref.rb @@ -25,8 +25,8 @@ module ProtectedRef end end - def protected_ref_accessible_to?(ref, user, action:) - access_levels_for_ref(ref, action: action).any? do |access_level| + def protected_ref_accessible_to?(ref, user, action:, protected_refs: nil) + access_levels_for_ref(ref, action: action, protected_refs: protected_refs).any? do |access_level| access_level.check_access(user) end end @@ -37,8 +37,9 @@ module ProtectedRef end end - def access_levels_for_ref(ref, action:) - self.matching(ref).map(&:"#{action}_access_levels").flatten + def access_levels_for_ref(ref, action:, protected_refs: nil) + self.matching(ref, protected_refs: protected_refs) + .map(&:"#{action}_access_levels").flatten end def matching(ref_name, protected_refs: nil) diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb index 25698bb8e99..6c6111006b6 100644 --- a/lib/gitlab/user_access.rb +++ b/lib/gitlab/user_access.rb @@ -37,8 +37,8 @@ module Gitlab request_cache def can_create_tag?(ref) return false unless can_access_git? - if ProtectedTag.protected?(project, ref) - project.protected_tags.protected_ref_accessible_to?(ref, user, action: :create) + if protected?(ProtectedTag, project, ref) + protected_tag_accessible_to?(ref, action: :create) else user.can?(:push_code, project) end @@ -47,7 +47,7 @@ module Gitlab request_cache def can_delete_branch?(ref) return false unless can_access_git? - if ProtectedBranch.protected?(project, ref) + if protected?(ProtectedBranch, project, ref) user.can?(:delete_protected_branch, project) else user.can?(:push_code, project) @@ -61,10 +61,10 @@ module Gitlab request_cache def can_push_to_branch?(ref) return false unless can_access_git? - if ProtectedBranch.protected?(project, ref) + if protected?(ProtectedBranch, project, ref) return true if project.empty_repo? && project.user_can_push_to_empty_repo?(user) - project.protected_branches.protected_ref_accessible_to?(ref, user, action: :push) + protected_branch_accessible_to?(ref, action: :push) else user.can?(:push_code, project) end @@ -73,8 +73,8 @@ module Gitlab request_cache def can_merge_to_branch?(ref) return false unless can_access_git? - if ProtectedBranch.protected?(project, ref) - project.protected_branches.protected_ref_accessible_to?(ref, user, action: :merge) + if protected?(ProtectedBranch, project, ref) + protected_branch_accessible_to?(ref, action: :merge) else user.can?(:push_code, project) end @@ -91,5 +91,21 @@ module Gitlab def can_access_git? user && user.can?(:access_git) end + + def protected_branch_accessible_to?(ref, action:) + ProtectedBranch.protected_ref_accessible_to?( + ref, user, action: action, + protected_refs: project.protected_branches) + end + + def protected_tag_accessible_to?(ref, action:) + ProtectedTag.protected_ref_accessible_to?( + ref, user, action: action, + protected_refs: project.protected_tags) + end + + request_cache def protected?(kind, project, ref) + kind.protected?(project, ref) + end end end -- cgit v1.2.1 From 0275914919551de1ffd5819bd9da7bf05d6a7668 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 19 Jul 2017 13:15:16 +0200 Subject: Add changelog entry for build merge request link fix --- .../fix-gb-fix-build-merge-request-link-to-fork-project.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/fix-gb-fix-build-merge-request-link-to-fork-project.yml diff --git a/changelogs/unreleased/fix-gb-fix-build-merge-request-link-to-fork-project.yml b/changelogs/unreleased/fix-gb-fix-build-merge-request-link-to-fork-project.yml new file mode 100644 index 00000000000..7a68e91c6d3 --- /dev/null +++ b/changelogs/unreleased/fix-gb-fix-build-merge-request-link-to-fork-project.yml @@ -0,0 +1,4 @@ +--- +title: Fix job merge request link to a forked source project +merge_request: 12965 +author: -- cgit v1.2.1 From b5399517687edbe854f3bb51a89c30c13a3f12b4 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Tue, 18 Jul 2017 21:40:35 +0900 Subject: Ini --- lib/api/api.rb | 1 + lib/api/group_variables.rb | 95 +++++++++++++ lib/api/helpers.rb | 4 + spec/requests/api/group_variables_spec.rb | 221 ++++++++++++++++++++++++++++++ 4 files changed, 321 insertions(+) create mode 100644 lib/api/group_variables.rb create mode 100644 spec/requests/api/group_variables_spec.rb diff --git a/lib/api/api.rb b/lib/api/api.rb index efcf0976a81..f6a310841e4 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -134,6 +134,7 @@ module API mount ::API::Triggers mount ::API::Users mount ::API::Variables + mount ::API::GroupVariables mount ::API::Version route :any, '*path' do diff --git a/lib/api/group_variables.rb b/lib/api/group_variables.rb new file mode 100644 index 00000000000..0dd418887e0 --- /dev/null +++ b/lib/api/group_variables.rb @@ -0,0 +1,95 @@ +module API + class GroupVariables < Grape::API + include PaginationParams + + before { authenticate! } + before { authorize! :admin_build, user_group } + + params do + requires :id, type: String, desc: 'The ID of a group' + end + + resource :groups, requirements: { id: %r{[^/]+} } do + desc 'Get group-level variables' do + success Entities::Variable + end + params do + use :pagination + end + get ':id/variables' do + variables = user_group.variables + present paginate(variables), with: Entities::Variable + end + + desc 'Get a specific variable from a group' do + success Entities::Variable + end + params do + requires :key, type: String, desc: 'The key of the variable' + end + get ':id/variables/:key' do + key = params[:key] + variable = user_group.variables.find_by(key: key) + + return not_found!('GroupVariable') unless variable + + present variable, with: Entities::Variable + end + + desc 'Create a new variable in a group' do + success Entities::Variable + end + params do + requires :key, type: String, desc: 'The key of the variable' + requires :value, type: String, desc: 'The value of the variable' + optional :protected, type: String, desc: 'Whether the variable is protected' + end + post ':id/variables' do + variable_params = declared_params(include_missing: false) + + variable = user_group.variables.create(variable_params) + + if variable.valid? + present variable, with: Entities::Variable + else + render_validation_error!(variable) + end + end + + desc 'Update an existing variable from a group' do + success Entities::Variable + end + params do + optional :key, type: String, desc: 'The key of the variable' + optional :value, type: String, desc: 'The value of the variable' + optional :protected, type: String, desc: 'Whether the variable is protected' + end + put ':id/variables/:key' do + variable = user_group.variables.find_by(key: params[:key]) + + return not_found!('GroupVariable') unless variable + + variable_params = declared_params(include_missing: false).except(:key) + + if variable.update(variable_params) + present variable, with: Entities::Variable + else + render_validation_error!(variable) + end + end + + desc 'Delete an existing variable from a group' do + success Entities::Variable + end + params do + requires :key, type: String, desc: 'The key of the variable' + end + delete ':id/variables/:key' do + variable = user_group.variables.find_by(key: params[:key]) + not_found!('GroupVariable') unless variable + + variable.destroy + end + end + end +end diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 0f4791841d2..56cd1f3df5a 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -29,6 +29,10 @@ module API @project ||= find_project!(params[:id]) end + def user_group + @group ||= find_group!(params[:id]) + end + def available_labels @available_labels ||= LabelsFinder.new(current_user, project_id: user_project.id).execute end diff --git a/spec/requests/api/group_variables_spec.rb b/spec/requests/api/group_variables_spec.rb new file mode 100644 index 00000000000..402ea057cc5 --- /dev/null +++ b/spec/requests/api/group_variables_spec.rb @@ -0,0 +1,221 @@ +require 'spec_helper' + +describe API::GroupVariables do + let(:group) { create(:group) } + let(:user) { create(:user) } + + describe 'GET /groups/:id/variables' do + let!(:variable) { create(:ci_group_variable, group: group) } + + context 'authorized user with proper permissions' do + before do + group.add_master(user) + end + + it 'returns group variables' do + get api("/groups/#{group.id}/variables", user) + + expect(response).to have_http_status(200) + expect(json_response).to be_a(Array) + end + end + + context 'authorized user with invalid permissions' do + it 'does not return group variables' do + get api("/groups/#{group.id}/variables", user) + + expect(response).to have_http_status(403) + end + end + + context 'unauthorized user' do + it 'does not return group variables' do + get api("/groups/#{group.id}/variables") + + expect(response).to have_http_status(401) + end + end + end + + describe 'GET /groups/:id/variables/:key' do + let!(:variable) { create(:ci_group_variable, group: group) } + + context 'authorized user with proper permissions' do + before do + group.add_master(user) + end + + it 'returns group variable details' do + get api("/groups/#{group.id}/variables/#{variable.key}", user) + + expect(response).to have_http_status(200) + expect(json_response['value']).to eq(variable.value) + expect(json_response['protected']).to eq(variable.protected?) + end + + it 'responds with 404 Not Found if requesting non-existing variable' do + get api("/groups/#{group.id}/variables/non_existing_variable", user) + + expect(response).to have_http_status(404) + end + end + + context 'authorized user with invalid permissions' do + it 'does not return group variable details' do + get api("/groups/#{group.id}/variables/#{variable.key}", user) + + expect(response).to have_http_status(403) + end + end + + context 'unauthorized user' do + it 'does not return group variable details' do + get api("/groups/#{group.id}/variables/#{variable.key}") + + expect(response).to have_http_status(401) + end + end + end + + describe 'POST /groups/:id/variables' do + context 'authorized user with proper permissions' do + let!(:variable) { create(:ci_group_variable, group: group) } + + before do + group.add_master(user) + end + + it 'creates variable' do + expect do + post api("/groups/#{group.id}/variables", user), key: 'TEST_VARIABLE_2', value: 'VALUE_2', protected: true + end.to change{group.variables.count}.by(1) + + expect(response).to have_http_status(201) + expect(json_response['key']).to eq('TEST_VARIABLE_2') + expect(json_response['value']).to eq('VALUE_2') + expect(json_response['protected']).to be_truthy + end + + it 'creates variable with optional attributes' do + expect do + post api("/groups/#{group.id}/variables", user), key: 'TEST_VARIABLE_2', value: 'VALUE_2' + end.to change{group.variables.count}.by(1) + + expect(response).to have_http_status(201) + expect(json_response['key']).to eq('TEST_VARIABLE_2') + expect(json_response['value']).to eq('VALUE_2') + expect(json_response['protected']).to be_falsey + end + + it 'does not allow to duplicate variable key' do + expect do + post api("/groups/#{group.id}/variables", user), key: variable.key, value: 'VALUE_2' + end.to change{group.variables.count}.by(0) + + expect(response).to have_http_status(400) + end + end + + context 'authorized user with invalid permissions' do + it 'does not create variable' do + post api("/groups/#{group.id}/variables", user) + + expect(response).to have_http_status(403) + end + end + + context 'unauthorized user' do + it 'does not create variable' do + post api("/groups/#{group.id}/variables") + + expect(response).to have_http_status(401) + end + end + end + + describe 'PUT /groups/:id/variables/:key' do + let!(:variable) { create(:ci_group_variable, group: group) } + + context 'authorized user with proper permissions' do + before do + group.add_master(user) + end + + it 'updates variable data' do + initial_variable = group.variables.first + value_before = initial_variable.value + + put api("/groups/#{group.id}/variables/#{variable.key}", user), value: 'VALUE_1_UP', protected: true + + updated_variable = group.variables.first + + expect(response).to have_http_status(200) + expect(value_before).to eq(variable.value) + expect(updated_variable.value).to eq('VALUE_1_UP') + expect(updated_variable).to be_protected + end + + it 'responds with 404 Not Found if requesting non-existing variable' do + put api("/groups/#{group.id}/variables/non_existing_variable", user) + + expect(response).to have_http_status(404) + end + end + + context 'authorized user with invalid permissions' do + it 'does not update variable' do + put api("/groups/#{group.id}/variables/#{variable.key}", user) + + expect(response).to have_http_status(403) + end + end + + context 'unauthorized user' do + it 'does not update variable' do + put api("/groups/#{group.id}/variables/#{variable.key}") + + expect(response).to have_http_status(401) + end + end + end + + describe 'DELETE /groups/:id/variables/:key' do + let!(:variable) { create(:ci_group_variable, group: group) } + + context 'authorized user with proper permissions' do + before do + group.add_master(user) + end + + it 'deletes variable' do + expect do + delete api("/groups/#{group.id}/variables/#{variable.key}", user) + + expect(response).to have_http_status(204) + end.to change{group.variables.count}.by(-1) + end + + it 'responds with 404 Not Found if requesting non-existing variable' do + delete api("/groups/#{group.id}/variables/non_existing_variable", user) + + expect(response).to have_http_status(404) + end + end + + context 'authorized user with invalid permissions' do + it 'does not delete variable' do + delete api("/groups/#{group.id}/variables/#{variable.key}", user) + + expect(response).to have_http_status(403) + end + end + + context 'unauthorized user' do + it 'does not delete variable' do + delete api("/groups/#{group.id}/variables/#{variable.key}") + + expect(response).to have_http_status(401) + end + end + end +end -- cgit v1.2.1 From 280cfc6152986debbd909261210d12be0a70c810 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Tue, 18 Jul 2017 21:53:16 +0900 Subject: Add changelog --- changelogs/unreleased/34519-extend-api-group-secret-variable.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/34519-extend-api-group-secret-variable.yml diff --git a/changelogs/unreleased/34519-extend-api-group-secret-variable.yml b/changelogs/unreleased/34519-extend-api-group-secret-variable.yml new file mode 100644 index 00000000000..e0b625c392f --- /dev/null +++ b/changelogs/unreleased/34519-extend-api-group-secret-variable.yml @@ -0,0 +1,4 @@ +--- +title: Extend API for Group Secret Variable +merge_request: 12936 +author: -- cgit v1.2.1 From 862e2c80be2963009c74d01e502e7ac9777c3a86 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 19 Jul 2017 20:57:27 +0900 Subject: Document update --- doc/api/README.md | 3 +- doc/api/build_variables.md | 125 ------------------------------------- doc/api/group_level_variables.md | 125 +++++++++++++++++++++++++++++++++++++ doc/api/project_level_variables.md | 125 +++++++++++++++++++++++++++++++++++++ 4 files changed, 252 insertions(+), 126 deletions(-) delete mode 100644 doc/api/build_variables.md create mode 100644 doc/api/group_level_variables.md create mode 100644 doc/api/project_level_variables.md diff --git a/doc/api/README.md b/doc/api/README.md index 95e7a457848..9c308254ab2 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -11,7 +11,8 @@ following locations: - [Award Emoji](award_emoji.md) - [Branches](branches.md) - [Broadcast Messages](broadcast_messages.md) -- [Build Variables](build_variables.md) +- [Project-level Variables](project_level_variables.md) +- [Group-level Variables](group_level_variables.md) - [Commits](commits.md) - [Deployments](deployments.md) - [Deploy Keys](deploy_keys.md) diff --git a/doc/api/build_variables.md b/doc/api/build_variables.md deleted file mode 100644 index d4f00256ed3..00000000000 --- a/doc/api/build_variables.md +++ /dev/null @@ -1,125 +0,0 @@ -# Build Variables API - -## List project variables - -Get list of a project's build variables. - -``` -GET /projects/:id/variables -``` - -| Attribute | Type | required | Description | -|-----------|---------|----------|---------------------| -| `id` | integer/string | yes | The ID of a project or [urlencoded NAMESPACE/PROJECT_NAME of the project](README.md#namespaced-path-encoding) owned by the authenticated user | - -``` -curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables" -``` - -```json -[ - { - "key": "TEST_VARIABLE_1", - "value": "TEST_1" - }, - { - "key": "TEST_VARIABLE_2", - "value": "TEST_2" - } -] -``` - -## Show variable details - -Get the details of a project's specific build variable. - -``` -GET /projects/:id/variables/:key -``` - -| Attribute | Type | required | Description | -|-----------|---------|----------|-----------------------| -| `id` | integer/string | yes | The ID of a project or [urlencoded NAMESPACE/PROJECT_NAME of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `key` | string | yes | The `key` of a variable | - -``` -curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables/TEST_VARIABLE_1" -``` - -```json -{ - "key": "TEST_VARIABLE_1", - "value": "TEST_1" -} -``` - -## Create variable - -Create a new build variable. - -``` -POST /projects/:id/variables -``` - -| Attribute | Type | required | Description | -|-------------|---------|----------|-----------------------| -| `id` | integer/string | yes | The ID of a project or [urlencoded NAMESPACE/PROJECT_NAME of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `key` | string | yes | The `key` of a variable; must have no more than 255 characters; only `A-Z`, `a-z`, `0-9`, and `_` are allowed | -| `value` | string | yes | The `value` of a variable | -| `protected` | boolean | no | Whether the variable is protected | - -``` -curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables" --form "key=NEW_VARIABLE" --form "value=new value" -``` - -```json -{ - "key": "NEW_VARIABLE", - "value": "new value", - "protected": false -} -``` - -## Update variable - -Update a project's build variable. - -``` -PUT /projects/:id/variables/:key -``` - -| Attribute | Type | required | Description | -|-------------|---------|----------|-------------------------| -| `id` | integer/string | yes | The ID of a project or [urlencoded NAMESPACE/PROJECT_NAME of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `key` | string | yes | The `key` of a variable | -| `value` | string | yes | The `value` of a variable | -| `protected` | boolean | no | Whether the variable is protected | - -``` -curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables/NEW_VARIABLE" --form "value=updated value" -``` - -```json -{ - "key": "NEW_VARIABLE", - "value": "updated value", - "protected": true -} -``` - -## Remove variable - -Remove a project's build variable. - -``` -DELETE /projects/:id/variables/:key -``` - -| Attribute | Type | required | Description | -|-----------|---------|----------|-------------------------| -| `id` | integer/string | yes | The ID of a project or [urlencoded NAMESPACE/PROJECT_NAME of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `key` | string | yes | The `key` of a variable | - -``` -curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables/VARIABLE_1" -``` diff --git a/doc/api/group_level_variables.md b/doc/api/group_level_variables.md new file mode 100644 index 00000000000..e19be7b35c4 --- /dev/null +++ b/doc/api/group_level_variables.md @@ -0,0 +1,125 @@ +# Group-level Variables API + +## List group variables + +Get list of a group's variables. + +``` +GET /groups/:id/variables +``` + +| Attribute | Type | required | Description | +|-----------|---------|----------|---------------------| +| `id` | integer/string | yes | The ID of a group or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user | + +``` +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/1/variables" +``` + +```json +[ + { + "key": "TEST_VARIABLE_1", + "value": "TEST_1" + }, + { + "key": "TEST_VARIABLE_2", + "value": "TEST_2" + } +] +``` + +## Show variable details + +Get the details of a group's specific variable. + +``` +GET /groups/:id/variables/:key +``` + +| Attribute | Type | required | Description | +|-----------|---------|----------|-----------------------| +| `id` | integer/string | yes | The ID of a group or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user | +| `key` | string | yes | The `key` of a variable | + +``` +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/1/variables/TEST_VARIABLE_1" +``` + +```json +{ + "key": "TEST_VARIABLE_1", + "value": "TEST_1" +} +``` + +## Create variable + +Create a new variable. + +``` +POST /groups/:id/variables +``` + +| Attribute | Type | required | Description | +|-------------|---------|----------|-----------------------| +| `id` | integer/string | yes | The ID of a group or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user | +| `key` | string | yes | The `key` of a variable; must have no more than 255 characters; only `A-Z`, `a-z`, `0-9`, and `_` are allowed | +| `value` | string | yes | The `value` of a variable | +| `protected` | boolean | no | Whether the variable is protected | + +``` +curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/1/variables" --form "key=NEW_VARIABLE" --form "value=new value" +``` + +```json +{ + "key": "NEW_VARIABLE", + "value": "new value", + "protected": false +} +``` + +## Update variable + +Update a group's variable. + +``` +PUT /groups/:id/variables/:key +``` + +| Attribute | Type | required | Description | +|-------------|---------|----------|-------------------------| +| `id` | integer/string | yes | The ID of a group or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user | +| `key` | string | yes | The `key` of a variable | +| `value` | string | yes | The `value` of a variable | +| `protected` | boolean | no | Whether the variable is protected | + +``` +curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/1/variables/NEW_VARIABLE" --form "value=updated value" +``` + +```json +{ + "key": "NEW_VARIABLE", + "value": "updated value", + "protected": true +} +``` + +## Remove variable + +Remove a group's variable. + +``` +DELETE /groups/:id/variables/:key +``` + +| Attribute | Type | required | Description | +|-----------|---------|----------|-------------------------| +| `id` | integer/string | yes | The ID of a group or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user | +| `key` | string | yes | The `key` of a variable | + +``` +curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/groups/1/variables/VARIABLE_1" +``` diff --git a/doc/api/project_level_variables.md b/doc/api/project_level_variables.md new file mode 100644 index 00000000000..82ac0b09027 --- /dev/null +++ b/doc/api/project_level_variables.md @@ -0,0 +1,125 @@ +# Project-level Variables API + +## List project variables + +Get list of a project's variables. + +``` +GET /projects/:id/variables +``` + +| Attribute | Type | required | Description | +|-----------|---------|----------|---------------------| +| `id` | integer/string | yes | The ID of a project or [urlencoded NAMESPACE/PROJECT_NAME of the project](README.md#namespaced-path-encoding) owned by the authenticated user | + +``` +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables" +``` + +```json +[ + { + "key": "TEST_VARIABLE_1", + "value": "TEST_1" + }, + { + "key": "TEST_VARIABLE_2", + "value": "TEST_2" + } +] +``` + +## Show variable details + +Get the details of a project's specific variable. + +``` +GET /projects/:id/variables/:key +``` + +| Attribute | Type | required | Description | +|-----------|---------|----------|-----------------------| +| `id` | integer/string | yes | The ID of a project or [urlencoded NAMESPACE/PROJECT_NAME of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `key` | string | yes | The `key` of a variable | + +``` +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables/TEST_VARIABLE_1" +``` + +```json +{ + "key": "TEST_VARIABLE_1", + "value": "TEST_1" +} +``` + +## Create variable + +Create a new variable. + +``` +POST /projects/:id/variables +``` + +| Attribute | Type | required | Description | +|-------------|---------|----------|-----------------------| +| `id` | integer/string | yes | The ID of a project or [urlencoded NAMESPACE/PROJECT_NAME of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `key` | string | yes | The `key` of a variable; must have no more than 255 characters; only `A-Z`, `a-z`, `0-9`, and `_` are allowed | +| `value` | string | yes | The `value` of a variable | +| `protected` | boolean | no | Whether the variable is protected | + +``` +curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables" --form "key=NEW_VARIABLE" --form "value=new value" +``` + +```json +{ + "key": "NEW_VARIABLE", + "value": "new value", + "protected": false +} +``` + +## Update variable + +Update a project's variable. + +``` +PUT /projects/:id/variables/:key +``` + +| Attribute | Type | required | Description | +|-------------|---------|----------|-------------------------| +| `id` | integer/string | yes | The ID of a project or [urlencoded NAMESPACE/PROJECT_NAME of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `key` | string | yes | The `key` of a variable | +| `value` | string | yes | The `value` of a variable | +| `protected` | boolean | no | Whether the variable is protected | + +``` +curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables/NEW_VARIABLE" --form "value=updated value" +``` + +```json +{ + "key": "NEW_VARIABLE", + "value": "updated value", + "protected": true +} +``` + +## Remove variable + +Remove a project's variable. + +``` +DELETE /projects/:id/variables/:key +``` + +| Attribute | Type | required | Description | +|-----------|---------|----------|-------------------------| +| `id` | integer/string | yes | The ID of a project or [urlencoded NAMESPACE/PROJECT_NAME of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `key` | string | yes | The `key` of a variable | + +``` +curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables/VARIABLE_1" +``` -- cgit v1.2.1 From d035d735242a47bee7cd5973c9daa7d984800700 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 19 Jul 2017 22:37:38 +0800 Subject: Fix tests and fine tweak permission error message --- app/services/ci/create_pipeline_service.rb | 10 +++++----- lib/gitlab/user_access.rb | 6 ++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index f331f86e622..700ac42d56e 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -23,16 +23,16 @@ module Ci unless allowed_to_trigger_pipeline?(triggering_user) if can?(triggering_user, :create_pipeline, project) - return error("Insufficient permissions for protected ref '#{ref}'") + if branch? || tag? + return error("Insufficient permissions for protected ref '#{ref}'") + else + return error('Reference not found') + end else return error('Insufficient permissions to create a new pipeline') end end - unless branch? || tag? - return error('Reference not found') - end - unless commit return error('Commit not found') end diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb index 6c6111006b6..d9a5af09f08 100644 --- a/lib/gitlab/user_access.rb +++ b/lib/gitlab/user_access.rb @@ -94,13 +94,15 @@ module Gitlab def protected_branch_accessible_to?(ref, action:) ProtectedBranch.protected_ref_accessible_to?( - ref, user, action: action, + ref, user, + action: action, protected_refs: project.protected_branches) end def protected_tag_accessible_to?(ref, action:) ProtectedTag.protected_ref_accessible_to?( - ref, user, action: action, + ref, user, + action: action, protected_refs: project.protected_tags) end -- cgit v1.2.1 From a05bc477b99500fa919295e1086f7a8de903e3c4 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 20 Jul 2017 00:08:34 +0800 Subject: Use hash to return multiple objects --- app/services/ci/create_trigger_request_service.rb | 8 +++---- lib/api/triggers.rb | 4 ++-- lib/api/v3/triggers.rb | 6 ++--- lib/ci/api/triggers.rb | 6 ++--- .../ci/create_trigger_request_service_spec.rb | 26 +++++++++++----------- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/app/services/ci/create_trigger_request_service.rb b/app/services/ci/create_trigger_request_service.rb index 90f75606ddf..1674830a41a 100644 --- a/app/services/ci/create_trigger_request_service.rb +++ b/app/services/ci/create_trigger_request_service.rb @@ -1,13 +1,13 @@ module Ci - class CreateTriggerRequestService - def execute(project, trigger, ref, variables = nil) + module CreateTriggerRequestService + def self.execute(project, trigger, ref, variables = nil) trigger_request = trigger.trigger_requests.create(variables: variables) pipeline = Ci::CreatePipelineService.new(project, trigger.owner, ref: ref) .execute(:trigger, ignore_skip_ci: true, trigger_request: trigger_request) - trigger_request.pipeline = pipeline - trigger_request + { trigger_request: trigger_request, + pipeline: pipeline } end end end diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb index 9e444563fdf..55528101f15 100644 --- a/lib/api/triggers.rb +++ b/lib/api/triggers.rb @@ -27,8 +27,8 @@ module API end # create request and trigger builds - trigger_request = Ci::CreateTriggerRequestService.new.execute(project, trigger, params[:ref].to_s, variables) - pipeline = trigger_request.pipeline + result = Ci::CreateTriggerRequestService.execute(project, trigger, params[:ref].to_s, variables) + pipeline = result[:pipeline] if pipeline.persisted? present pipeline, with: Entities::Pipeline diff --git a/lib/api/v3/triggers.rb b/lib/api/v3/triggers.rb index 7e75c579528..0e236423b8c 100644 --- a/lib/api/v3/triggers.rb +++ b/lib/api/v3/triggers.rb @@ -28,11 +28,11 @@ module API end # create request and trigger builds - trigger_request = Ci::CreateTriggerRequestService.new.execute(project, trigger, params[:ref].to_s, variables) - pipeline = trigger_request.pipeline + result = Ci::CreateTriggerRequestService.execute(project, trigger, params[:ref].to_s, variables) + pipeline = result[:pipeline] if pipeline.persisted? - present trigger_request, with: ::API::V3::Entities::TriggerRequest + present result[:trigger_request], with: ::API::V3::Entities::TriggerRequest else render_validation_error!(pipeline) end diff --git a/lib/ci/api/triggers.rb b/lib/ci/api/triggers.rb index 0e5174e13ab..ce0ef95b186 100644 --- a/lib/ci/api/triggers.rb +++ b/lib/ci/api/triggers.rb @@ -24,11 +24,11 @@ module Ci end # create request and trigger builds - trigger_request = Ci::CreateTriggerRequestService.new.execute(project, trigger, params[:ref], variables) - pipeline = trigger_request.pipeline + result = Ci::CreateTriggerRequestService.execute(project, trigger, params[:ref], variables) + pipeline = result[:pipeline] if pipeline.persisted? - present trigger_request, with: Entities::TriggerRequest + present result[:trigger_request], with: Entities::TriggerRequest else render_validation_error!(pipeline) end diff --git a/spec/services/ci/create_trigger_request_service_spec.rb b/spec/services/ci/create_trigger_request_service_spec.rb index 8582c74e734..48d9b0844f1 100644 --- a/spec/services/ci/create_trigger_request_service_spec.rb +++ b/spec/services/ci/create_trigger_request_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Ci::CreateTriggerRequestService, services: true do - let(:service) { described_class.new } + let(:service) { described_class } let(:project) { create(:project, :repository) } let(:trigger) { create(:ci_trigger, project: project, owner: owner) } let(:owner) { create(:user) } @@ -17,26 +17,26 @@ describe Ci::CreateTriggerRequestService, services: true do subject { service.execute(project, trigger, 'master') } context 'without owner' do - it { expect(subject).to be_kind_of(Ci::TriggerRequest) } - it { expect(subject.pipeline).to be_kind_of(Ci::Pipeline) } - it { expect(subject.pipeline).to be_trigger } - it { expect(subject.builds.first).to be_kind_of(Ci::Build) } + it { expect(subject[:trigger_request]).to be_kind_of(Ci::TriggerRequest) } + it { expect(subject[:trigger_request].builds.first).to be_kind_of(Ci::Build) } + it { expect(subject[:pipeline]).to be_kind_of(Ci::Pipeline) } + it { expect(subject[:pipeline]).to be_trigger } end context 'with owner' do - it { expect(subject).to be_kind_of(Ci::TriggerRequest) } - it { expect(subject.pipeline).to be_kind_of(Ci::Pipeline) } - it { expect(subject.pipeline).to be_trigger } - it { expect(subject.pipeline.user).to eq(owner) } - it { expect(subject.builds.first).to be_kind_of(Ci::Build) } - it { expect(subject.builds.first.user).to eq(owner) } + it { expect(subject[:trigger_request]).to be_kind_of(Ci::TriggerRequest) } + it { expect(subject[:trigger_request].builds.first).to be_kind_of(Ci::Build) } + it { expect(subject[:trigger_request].builds.first.user).to eq(owner) } + it { expect(subject[:pipeline]).to be_kind_of(Ci::Pipeline) } + it { expect(subject[:pipeline]).to be_trigger } + it { expect(subject[:pipeline].user).to eq(owner) } end end context 'no commit for ref' do subject { service.execute(project, trigger, 'other-branch') } - it { expect(subject.pipeline).not_to be_persisted } + it { expect(subject[:pipeline]).not_to be_persisted } end context 'no builds created' do @@ -46,7 +46,7 @@ describe Ci::CreateTriggerRequestService, services: true do stub_ci_pipeline_yaml_file('script: { only: [develop], script: hello World }') end - it { expect(subject.pipeline).not_to be_persisted } + it { expect(subject[:pipeline]).not_to be_persisted } end end end -- cgit v1.2.1 From c9c715cd5510456d83da5272f28b7ce7f248c77f Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 20 Jul 2017 01:31:20 +0800 Subject: Make permission checks easier to understand --- app/services/ci/create_pipeline_service.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 700ac42d56e..5da70ba87e9 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -23,16 +23,16 @@ module Ci unless allowed_to_trigger_pipeline?(triggering_user) if can?(triggering_user, :create_pipeline, project) - if branch? || tag? - return error("Insufficient permissions for protected ref '#{ref}'") - else - return error('Reference not found') - end + return error("Insufficient permissions for protected ref '#{ref}'") else return error('Insufficient permissions to create a new pipeline') end end + unless branch? || tag? + return error('Reference not found') + end + unless commit return error('Commit not found') end @@ -93,7 +93,7 @@ module Ci elsif tag? access.can_create_tag?(ref) else - false + true # Allow it for now and we'll reject when we check ref existence end end -- cgit v1.2.1 From e9a25242a16c0b8092fcc94dfb117ac214be8205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Thu, 13 Jul 2017 09:54:28 +0800 Subject: Add uk translation difference of Pipeline Schedules --- locale/uk/part.po | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 locale/uk/part.po diff --git a/locale/uk/part.po b/locale/uk/part.po new file mode 100644 index 00000000000..ef5864be5c9 --- /dev/null +++ b/locale/uk/part.po @@ -0,0 +1,38 @@ +# Андрей Витюк , 2017. #zanata +msgid "" +msgstr "" +"Project-Id-Version: gitlab 1.0.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-15 21:59-0500\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"PO-Revision-Date: 2017-07-12 07:29-0400\n" +"Last-Translator: Андрей Витюк \n" +"Language-Team: Ukrainian\n" +"Language: uk\n" +"X-Generator: Zanata 3.9.6\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +msgid "PipelineSchedules|Input variable key" +msgstr "Введіть ім'я змінної" + +msgid "PipelineSchedules|Input variable value" +msgstr "Вхідні значення змінних" + +msgid "PipelineSchedules|Remove variable row" +msgstr "Видалити змінні" + +msgid "PipelineSchedules|Variables" +msgstr "Змінні" + +msgid "" +"You are going to remove %{group_name}.\n" +"Removed groups CANNOT be restored!\n" +"Are you ABSOLUTELY sure?" +msgstr "" +"Ви хочете видалити %{group_name}.\n" +"Видалені групи НЕ МОЖНА буду відновити!\n" +"Ви АБСОЛЮТНО впевнені?" + -- cgit v1.2.1 From 77c14bee90cb61c09fcae0515688c5ebb8781892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Thu, 20 Jul 2017 10:08:51 +0800 Subject: merge uk part.po to gitlab.po --- locale/uk/gitlab.po | 29 +++++++++++++++++++++++++---- locale/uk/part.po | 38 -------------------------------------- 2 files changed, 25 insertions(+), 42 deletions(-) delete mode 100644 locale/uk/part.po diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po index 59a7eb6e1b3..56498f3c901 100644 --- a/locale/uk/gitlab.po +++ b/locale/uk/gitlab.po @@ -1,16 +1,16 @@ -# Андрей Витюк , 2017. #zanata # Huang Tao , 2017. #zanata +# Андрей Витюк , 2017. #zanata msgid "" msgstr "" "Project-Id-Version: gitlab 1.0.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-06-28 13:32+0200\n" +"POT-Creation-Date: 2017-07-05 08:50-0500\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2017-07-12 09:05-0400\n" -"Last-Translator: Андрей Витюк \n" "Language-Team: Ukrainian (https://translate.zanata.org/project/view/GitLab)\n" +"PO-Revision-Date: 2017-07-14 01:22-0400\n" +"Last-Translator: Huang Tao \n" "Language: uk\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " @@ -654,6 +654,12 @@ msgstr "Всі" msgid "PipelineSchedules|Inactive" msgstr "Неактивні" +msgid "PipelineSchedules|Input variable key" +msgstr "Введіть ім'я змінної" + +msgid "PipelineSchedules|Input variable value" +msgstr "Вхідні значення змінних" + msgid "PipelineSchedules|Next Run" msgstr "Наступний запуск" @@ -663,12 +669,18 @@ msgstr "Немає" msgid "PipelineSchedules|Provide a short description for this pipeline" msgstr "Задайте короткий опис для цього Конвеєру" +msgid "PipelineSchedules|Remove variable row" +msgstr "Видалити змінні" + msgid "PipelineSchedules|Take ownership" msgstr "Стати власником" msgid "PipelineSchedules|Target" msgstr "Ціль" +msgid "PipelineSchedules|Variables" +msgstr "Змінні" + msgid "PipelineSheduleIntervalPattern|Custom" msgstr "Власні" @@ -1140,6 +1152,15 @@ msgstr "Ми не маємо достатньо даних для показу msgid "Withdraw Access Request" msgstr "Скасувати запит доступу" +msgid "" +"You are going to remove %{group_name}.\n" +"Removed groups CANNOT be restored!\n" +"Are you ABSOLUTELY sure?" +msgstr "" +"Ви хочете видалити %{group_name}.\n" +"Видалені групи НЕ МОЖНА буду відновити!\n" +"Ви АБСОЛЮТНО впевнені?" + msgid "" "You are going to remove %{project_name_with_namespace}.\n" "Removed project CANNOT be restored!\n" diff --git a/locale/uk/part.po b/locale/uk/part.po deleted file mode 100644 index ef5864be5c9..00000000000 --- a/locale/uk/part.po +++ /dev/null @@ -1,38 +0,0 @@ -# Андрей Витюк , 2017. #zanata -msgid "" -msgstr "" -"Project-Id-Version: gitlab 1.0.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-06-15 21:59-0500\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2017-07-12 07:29-0400\n" -"Last-Translator: Андрей Витюк \n" -"Language-Team: Ukrainian\n" -"Language: uk\n" -"X-Generator: Zanata 3.9.6\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " -"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -msgid "PipelineSchedules|Input variable key" -msgstr "Введіть ім'я змінної" - -msgid "PipelineSchedules|Input variable value" -msgstr "Вхідні значення змінних" - -msgid "PipelineSchedules|Remove variable row" -msgstr "Видалити змінні" - -msgid "PipelineSchedules|Variables" -msgstr "Змінні" - -msgid "" -"You are going to remove %{group_name}.\n" -"Removed groups CANNOT be restored!\n" -"Are you ABSOLUTELY sure?" -msgstr "" -"Ви хочете видалити %{group_name}.\n" -"Видалені групи НЕ МОЖНА буду відновити!\n" -"Ви АБСОЛЮТНО впевнені?" - -- cgit v1.2.1 From c9749e22383661c0772addfcf4274ec3a81bd229 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 20 Jul 2017 09:18:45 +0200 Subject: Improve build details serializable entity specs --- spec/factories/ci/builds.rb | 1 + spec/serializers/build_details_entity_spec.rb | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index a77f01ecb00..863c82ece6a 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -140,6 +140,7 @@ FactoryGirl.define do end trait :erased do + erasable erased_at Time.now erased_by factory: :user end diff --git a/spec/serializers/build_details_entity_spec.rb b/spec/serializers/build_details_entity_spec.rb index e688035cecc..2c981154f0d 100644 --- a/spec/serializers/build_details_entity_spec.rb +++ b/spec/serializers/build_details_entity_spec.rb @@ -46,8 +46,8 @@ describe BuildDetailsEntity do expect(subject).to include(:new_issue_path) end - it 'exposes details of the merge request' do - expect(subject[:merge_request]).to include(:iid, :path) + it 'exposes correct details of the merge request' do + expect(subject[:merge_request][:iid]).to eq merge_request.iid end it 'has a correct merge request path' do @@ -78,7 +78,7 @@ describe BuildDetailsEntity do end it 'exposes details of the merge request' do - expect(subject[:merge_request]).to include(:iid, :path) + expect(subject[:merge_request][:iid]).to eq merge_request.iid end it 'has a correct merge request path' do @@ -88,7 +88,7 @@ describe BuildDetailsEntity do end context 'when the build has been erased' do - let(:build) { create(:ci_build, :erasable, project: project) } + let(:build) { create(:ci_build, :erased, project: project) } it 'exposes the user whom erased the build' do expect(subject).to include(:erase_path) @@ -96,7 +96,7 @@ describe BuildDetailsEntity do end context 'when the build has been erased' do - let(:build) { create(:ci_build, erased_at: Time.now, project: project, erased_by: user) } + let(:build) { create(:ci_build, :erased, project: project, erased_by: user) } it 'exposes the user whom erased the build' do expect(subject).to include(:erased_by) -- cgit v1.2.1 From 72a85ae9ac2468b099a565d3848bf8e0dcdf4499 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Fri, 28 Apr 2017 06:46:15 +0000 Subject: Handle errors while a project is being deleted asynchronously. 1. Rescue all errors that `Projects::DestroyService` might throw, to prevent the worker from leaving things in an inconsistent state 2. Unmark the project as `pending_delete` 3. Add a `delete_error` text column to `projects`, and save the error message in there, to be shown to the project masters/owners. --- app/services/projects/destroy_service.rb | 9 ++-- app/workers/project_destroy_worker.rb | 3 ++ ...28064307_add_column_delete_error_to_projects.rb | 31 +++++++++++ db/schema.rb | 1 + .../gitlab/import_export/safe_model_attributes.yml | 1 + spec/services/projects/destroy_service_spec.rb | 63 ++++++++++++++++++++++ 6 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20170428064307_add_column_delete_error_to_projects.rb diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index e2b2660ea71..682407ac896 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -26,9 +26,6 @@ module Projects Projects::UnlinkForkService.new(project, current_user).execute Project.transaction do - project.team.truncate - project.destroy! - unless remove_legacy_registry_tags raise_error('Failed to remove some tags in project container registry. Please try again or contact administrator.') end @@ -40,10 +37,14 @@ module Projects unless remove_repository(wiki_path) raise_error('Failed to remove wiki repository. Please try again or contact administrator.') end + + project.team.truncate + project.destroy! end - log_info("Project \"#{project.path_with_namespace}\" was removed") system_hook_service.execute_hooks_for(project, :destroy) + + log_info("Project \"#{project.path_with_namespace}\" was removed") true end diff --git a/app/workers/project_destroy_worker.rb b/app/workers/project_destroy_worker.rb index b462327490e..482e1e38cd1 100644 --- a/app/workers/project_destroy_worker.rb +++ b/app/workers/project_destroy_worker.rb @@ -12,5 +12,8 @@ class ProjectDestroyWorker user = User.find(user_id) ::Projects::DestroyService.new(project, user, params.symbolize_keys).execute + rescue StandardError => error + project.assign_attributes(delete_error: error.message, pending_delete: false) + project.save!(validate: false) end end diff --git a/db/migrate/20170428064307_add_column_delete_error_to_projects.rb b/db/migrate/20170428064307_add_column_delete_error_to_projects.rb new file mode 100644 index 00000000000..ef5fc2cdea5 --- /dev/null +++ b/db/migrate/20170428064307_add_column_delete_error_to_projects.rb @@ -0,0 +1,31 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddColumnDeleteErrorToProjects < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + # When a migration requires downtime you **must** uncomment the following + # constant and define a short and easy to understand explanation as to why the + # migration requires downtime. + # DOWNTIME_REASON = '' + + # When using the methods "add_concurrent_index", "remove_concurrent_index" or + # "add_column_with_default" you must disable the use of transactions + # as these methods can not run in an existing transaction. + # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure + # that either of them is the _only_ method called in the migration, + # any other changes should go in a separate migration. + # This ensures that upon failure _only_ the index creation or removing fails + # and can be retried or reverted easily. + # + # To disable transactions uncomment the following line and remove these + # comments: + # disable_ddl_transaction! + + def change + add_column :projects, :delete_error, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 284b2068166..0ba2bd31517 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1134,6 +1134,7 @@ ActiveRecord::Schema.define(version: 20170717150329) do t.integer "cached_markdown_version" t.datetime "last_repository_updated_at" t.string "ci_config_path" + t.text "delete_error" end add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 4ef3db3721f..0f2db3380a7 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -396,6 +396,7 @@ Project: - build_allow_git_fetch - last_repository_updated_at - ci_config_path +- delete_error Author: - name ProjectFeature: diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index b399d3402fd..a629afe723d 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -36,6 +36,27 @@ describe Projects::DestroyService, services: true do end end + shared_examples 'handles errors thrown during async destroy' do |error_message| + it 'does not allow the error to bubble up' do + expect do + Sidekiq::Testing.inline! { destroy_project(project, user, {}) } + end.not_to raise_error + end + + it 'unmarks the project as "pending deletion"' do + Sidekiq::Testing.inline! { destroy_project(project, user, {}) } + + expect(project.reload.pending_delete).to be(false) + end + + it 'stores an error message in `projects.delete_error`' do + Sidekiq::Testing.inline! { destroy_project(project, user, {}) } + + expect(project.reload.delete_error).to be_present + expect(project.delete_error).to include(error_message) + end + end + context 'Sidekiq inline' do before do # Run sidekiq immediatly to check that renamed repository will be removed @@ -89,10 +110,52 @@ describe Projects::DestroyService, services: true do end it_behaves_like 'deleting the project with pipeline and build' + + context 'errors' do + context 'when `remove_legacy_registry_tags` fails' do + before do + expect_any_instance_of(Projects::DestroyService) + .to receive(:remove_legacy_registry_tags).and_return(false) + end + + it_behaves_like 'handles errors thrown during async destroy', "Failed to remove some tags" + end + + context 'when `remove_repository` fails' do + before do + expect_any_instance_of(Projects::DestroyService) + .to receive(:remove_repository).and_return(false) + end + + it_behaves_like 'handles errors thrown during async destroy', "Failed to remove project repository" + end + + context 'when `execute` raises any other error' do + before do + expect_any_instance_of(Projects::DestroyService) + .to receive(:execute).and_raise(ArgumentError.new("Other error message")) + end + + it_behaves_like 'handles errors thrown during async destroy', "Other error message" + end + end end context 'with execute' do it_behaves_like 'deleting the project with pipeline and build' + + context 'when `execute` raises an error' do + before do + expect_any_instance_of(Projects::DestroyService) + .to receive(:execute).and_raise(ArgumentError) + end + + it 'allows the error to bubble up' do + expect do + Sidekiq::Testing.inline! { Projects::DestroyService.new(project, user, {}).execute } + end.to raise_error(ArgumentError) + end + end end describe 'container registry' do -- cgit v1.2.1 From f0e4e3993b1f5a21ab61aaff95f73ac4e5b88ad3 Mon Sep 17 00:00:00 2001 From: Timothy Andrew Date: Thu, 4 May 2017 10:50:05 +0000 Subject: WIP: Display a project's `delete_error` on the project homepage. --- app/views/projects/_deletion_failed.html.haml | 9 +++++++++ app/views/projects/show.html.haml | 1 + 2 files changed, 10 insertions(+) create mode 100644 app/views/projects/_deletion_failed.html.haml diff --git a/app/views/projects/_deletion_failed.html.haml b/app/views/projects/_deletion_failed.html.haml new file mode 100644 index 00000000000..cd717760432 --- /dev/null +++ b/app/views/projects/_deletion_failed.html.haml @@ -0,0 +1,9 @@ +- if @project.delete_error.present? + .project-deletion-failed-message.alert.alert-warning + This project was scheduled for deletion, but failed with the message: + = @project.delete_error + + .alert-link-group + = link_to "Don't show again", profile_path(user: {hide_no_ssh_key: true}), method: :put, class: 'alert-link' + | + = link_to 'Remind later', '#', class: 'hide-no-ssh-message alert-link' diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 49d0a6828fe..336bc694ffc 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -7,6 +7,7 @@ = auto_discovery_link_tag(:atom, project_path(@project, rss_url_options), title: "#{@project.name} activity") = content_for flash_message_container do + = render 'deletion_failed' - if current_user && can?(current_user, :download_code, @project) = render 'shared/no_ssh' = render 'shared/no_password' -- cgit v1.2.1 From 3491b19a4e67a9f439c12afac45ef38f3fce0ef5 Mon Sep 17 00:00:00 2001 From: Tiago Botelho Date: Thu, 29 Jun 2017 12:43:01 +0100 Subject: Add specs for ProjectDestroyWorker --- app/services/projects/destroy_service.rb | 2 +- app/views/projects/_deletion_failed.html.haml | 4 +-- app/views/projects/_flash_messages.html.haml | 5 ++++ app/views/projects/empty.html.haml | 5 +--- app/views/projects/show.html.haml | 6 +---- app/workers/project_destroy_worker.rb | 15 +++++------ ...28064307_add_column_delete_error_to_projects.rb | 24 ----------------- spec/features/projects/show_project_spec.rb | 30 ++++++++++++++++++++++ spec/workers/project_destroy_worker_spec.rb | 21 ++++++++++++--- 9 files changed, 63 insertions(+), 49 deletions(-) create mode 100644 app/views/projects/_flash_messages.html.haml create mode 100644 spec/features/projects/show_project_spec.rb diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index 682407ac896..7b0a08af290 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -44,7 +44,7 @@ module Projects system_hook_service.execute_hooks_for(project, :destroy) - log_info("Project \"#{project.path_with_namespace}\" was removed") + log_info("Project \"#{project.full_path}\" was removed") true end diff --git a/app/views/projects/_deletion_failed.html.haml b/app/views/projects/_deletion_failed.html.haml index cd717760432..028510b5671 100644 --- a/app/views/projects/_deletion_failed.html.haml +++ b/app/views/projects/_deletion_failed.html.haml @@ -1,9 +1,9 @@ - if @project.delete_error.present? .project-deletion-failed-message.alert.alert-warning - This project was scheduled for deletion, but failed with the message: + This project was scheduled for deletion, but failed with the following message: = @project.delete_error .alert-link-group - = link_to "Don't show again", profile_path(user: {hide_no_ssh_key: true}), method: :put, class: 'alert-link' + = link_to "Don't show again", profile_path(user: { hide_no_ssh_key: true }), method: :put, class: 'alert-link' | = link_to 'Remind later', '#', class: 'hide-no-ssh-message alert-link' diff --git a/app/views/projects/_flash_messages.html.haml b/app/views/projects/_flash_messages.html.haml new file mode 100644 index 00000000000..6c9d466c761 --- /dev/null +++ b/app/views/projects/_flash_messages.html.haml @@ -0,0 +1,5 @@ += content_for flash_message_container do + = render 'deletion_failed' + - if current_user && can?(current_user, :download_code, project) + = render 'shared/no_ssh' + = render 'shared/no_password' diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml index 0f132a68ce1..3d7c72ae61a 100644 --- a/app/views/projects/empty.html.haml +++ b/app/views/projects/empty.html.haml @@ -1,10 +1,7 @@ - @no_container = true - flash_message_container = show_new_nav? ? :new_global_flash : :flash_message -= content_for flash_message_container do - - if current_user && can?(current_user, :download_code, @project) - = render 'shared/no_ssh' - = render 'shared/no_password' += render partial: 'flash_messages', locals: { project: @project } = render "projects/head" = render "home_panel" diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 336bc694ffc..3926149e790 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -6,11 +6,7 @@ = content_for :meta_tags do = auto_discovery_link_tag(:atom, project_path(@project, rss_url_options), title: "#{@project.name} activity") -= content_for flash_message_container do - = render 'deletion_failed' - - if current_user && can?(current_user, :download_code, @project) - = render 'shared/no_ssh' - = render 'shared/no_password' += render partial: 'flash_messages', locals: { project: @project } = render "projects/head" = render "projects/last_push" diff --git a/app/workers/project_destroy_worker.rb b/app/workers/project_destroy_worker.rb index 482e1e38cd1..209cf11e893 100644 --- a/app/workers/project_destroy_worker.rb +++ b/app/workers/project_destroy_worker.rb @@ -3,17 +3,14 @@ class ProjectDestroyWorker include DedicatedSidekiqQueue def perform(project_id, user_id, params) - begin - project = Project.unscoped.find(project_id) - rescue ActiveRecord::RecordNotFound - return - end - + project = Project.find(project_id) user = User.find(user_id) ::Projects::DestroyService.new(project, user, params.symbolize_keys).execute - rescue StandardError => error - project.assign_attributes(delete_error: error.message, pending_delete: false) - project.save!(validate: false) + rescue Exception => error # rubocop:disable Lint/RescueException + project&.update_attributes(delete_error: error.message, pending_delete: false) + Rails.logger.error("Deletion failed on #{project&.full_path} with the following message: #{error.message}") + + raise end end diff --git a/db/migrate/20170428064307_add_column_delete_error_to_projects.rb b/db/migrate/20170428064307_add_column_delete_error_to_projects.rb index ef5fc2cdea5..09f9d9b5b7a 100644 --- a/db/migrate/20170428064307_add_column_delete_error_to_projects.rb +++ b/db/migrate/20170428064307_add_column_delete_error_to_projects.rb @@ -1,30 +1,6 @@ -# See http://doc.gitlab.com/ce/development/migration_style_guide.html -# for more information on how to write migrations for GitLab. - class AddColumnDeleteErrorToProjects < ActiveRecord::Migration - include Gitlab::Database::MigrationHelpers - - # Set this constant to true if this migration requires downtime. DOWNTIME = false - # When a migration requires downtime you **must** uncomment the following - # constant and define a short and easy to understand explanation as to why the - # migration requires downtime. - # DOWNTIME_REASON = '' - - # When using the methods "add_concurrent_index", "remove_concurrent_index" or - # "add_column_with_default" you must disable the use of transactions - # as these methods can not run in an existing transaction. - # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure - # that either of them is the _only_ method called in the migration, - # any other changes should go in a separate migration. - # This ensures that upon failure _only_ the index creation or removing fails - # and can be retried or reverted easily. - # - # To disable transactions uncomment the following line and remove these - # comments: - # disable_ddl_transaction! - def change add_column :projects, :delete_error, :text end diff --git a/spec/features/projects/show_project_spec.rb b/spec/features/projects/show_project_spec.rb new file mode 100644 index 00000000000..5aa0d8f0026 --- /dev/null +++ b/spec/features/projects/show_project_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +describe 'Project show page', feature: true do + context 'when project pending delete' do + let(:project) { create(:project, :empty_repo, pending_delete: true) } + let(:worker) { ProjectDestroyWorker.new } + + before do + sign_in(project.owner) + end + + it 'shows flash error if deletion for project fails' do + error_message = "some error message" + project.update_attributes(delete_error: error_message, pending_delete: false) + + visit namespace_project_path(project.namespace, project) + + expect(page).to have_selector('.project-deletion-failed-message') + expect(page).to have_content("This project was scheduled for deletion, but failed with the following message: #{error_message}") + end + + it 'renders 404 if project was successfully deleted' do + worker.perform(project.id, project.owner.id, {}) + + visit namespace_project_path(project.namespace, project) + + expect(page).to have_http_status(404) + end + end +end diff --git a/spec/workers/project_destroy_worker_spec.rb b/spec/workers/project_destroy_worker_spec.rb index 3d135f40c1f..29f0295de42 100644 --- a/spec/workers/project_destroy_worker_spec.rb +++ b/spec/workers/project_destroy_worker_spec.rb @@ -1,24 +1,37 @@ require 'spec_helper' describe ProjectDestroyWorker do - let(:project) { create(:project, :repository) } + let(:project) { create(:project, :repository, pending_delete: true) } let(:path) { project.repository.path_to_repo } subject { described_class.new } - describe "#perform" do - it "deletes the project" do + describe '#perform' do + it 'deletes the project' do subject.perform(project.id, project.owner.id, {}) expect(Project.all).not_to include(project) expect(Dir.exist?(path)).to be_falsey end - it "deletes the project but skips repo deletion" do + it 'deletes the project but skips repo deletion' do subject.perform(project.id, project.owner.id, { "skip_repo" => true }) expect(Project.all).not_to include(project) expect(Dir.exist?(path)).to be_truthy end + + describe 'when StandardError is raised' do + it 'reverts pending_delete attribute with a error message' do + allow_any_instance_of(::Projects::DestroyService).to receive(:execute).and_raise(StandardError, "some error message") + + expect do + subject.perform(project.id, project.owner.id, {}) + end.to change { project.reload.pending_delete }.from(true).to(false) + + expect(Project.all).to include(project) + expect(project.delete_error).to eq("some error message") + end + end end end -- cgit v1.2.1 From 0aa8249e484ca97cfc28c7301d69077919032c08 Mon Sep 17 00:00:00 2001 From: Tiago Botelho Date: Thu, 6 Jul 2017 14:43:07 +0100 Subject: Refactors Project Destroy service and worker code --- app/services/projects/destroy_service.rb | 42 ++++++++++++++++++++------------ app/workers/project_destroy_worker.rb | 7 ++---- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index 7b0a08af290..7e38aacc91a 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -25,27 +25,15 @@ module Projects Projects::UnlinkForkService.new(project, current_user).execute - Project.transaction do - unless remove_legacy_registry_tags - raise_error('Failed to remove some tags in project container registry. Please try again or contact administrator.') - end - - unless remove_repository(repo_path) - raise_error('Failed to remove project repository. Please try again or contact administrator.') - end - - unless remove_repository(wiki_path) - raise_error('Failed to remove wiki repository. Please try again or contact administrator.') - end - - project.team.truncate - project.destroy! - end + attempt_destroy_transaction(project, repo_path, wiki_path) system_hook_service.execute_hooks_for(project, :destroy) log_info("Project \"#{project.full_path}\" was removed") true + rescue Projects::DestroyService::DestroyError => error + Rails.logger.error("Deletion failed on #{project.full_path} with the following message: #{error.message}") + false end private @@ -71,6 +59,28 @@ module Projects end end + def attempt_destroy_transaction(project, repo_path, wiki_path) + Project.transaction do + unless remove_legacy_registry_tags + raise_error('Failed to remove some tags in project container registry. Please try again or contact administrator.') + end + + unless remove_repository(repo_path) + raise_error('Failed to remove project repository. Please try again or contact administrator.') + end + + unless remove_repository(wiki_path) + raise_error('Failed to remove wiki repository. Please try again or contact administrator.') + end + + project.team.truncate + project.destroy! + end + rescue Exception => error # rubocop:disable Lint/RescueException + project.update_attributes(delete_error: error.message, pending_delete: false) + raise + end + ## # This method makes sure that we correctly remove registry tags # for legacy image repository (when repository path equals project path). diff --git a/app/workers/project_destroy_worker.rb b/app/workers/project_destroy_worker.rb index 209cf11e893..e695ec060f0 100644 --- a/app/workers/project_destroy_worker.rb +++ b/app/workers/project_destroy_worker.rb @@ -7,10 +7,7 @@ class ProjectDestroyWorker user = User.find(user_id) ::Projects::DestroyService.new(project, user, params.symbolize_keys).execute - rescue Exception => error # rubocop:disable Lint/RescueException - project&.update_attributes(delete_error: error.message, pending_delete: false) - Rails.logger.error("Deletion failed on #{project&.full_path} with the following message: #{error.message}") - - raise + rescue ActiveRecord::RecordNotFound => error + logger.error("Failed to delete project #{project.path_with_namespace} (#{project.id}): #{error.message}") end end -- cgit v1.2.1 From 70489d08b7e8b4bd0ba566da2ed0e417bef3ed3e Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 20 Jul 2017 11:42:13 +0200 Subject: Fix invalid assertions in build details entity specs --- spec/factories/ci/builds.rb | 1 - spec/serializers/build_details_entity_spec.rb | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index 863c82ece6a..a77f01ecb00 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -140,7 +140,6 @@ FactoryGirl.define do end trait :erased do - erasable erased_at Time.now erased_by factory: :user end diff --git a/spec/serializers/build_details_entity_spec.rb b/spec/serializers/build_details_entity_spec.rb index 2c981154f0d..446a2451956 100644 --- a/spec/serializers/build_details_entity_spec.rb +++ b/spec/serializers/build_details_entity_spec.rb @@ -87,18 +87,18 @@ describe BuildDetailsEntity do end end - context 'when the build has been erased' do - let(:build) { create(:ci_build, :erased, project: project) } + context 'when the build has not been erased' do + let(:build) { create(:ci_build, :erasable, project: project) } - it 'exposes the user whom erased the build' do + it 'exposes a build erase path' do expect(subject).to include(:erase_path) end end context 'when the build has been erased' do - let(:build) { create(:ci_build, :erased, project: project, erased_by: user) } + let(:build) { create(:ci_build, :erased, project: project) } - it 'exposes the user whom erased the build' do + it 'exposes the user who erased the build' do expect(subject).to include(:erased_by) end end -- cgit v1.2.1 From e9862a9900c6269a41b65ca543035e57b49fede3 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 20 Jul 2017 20:17:42 +0800 Subject: Use struct instead of hash --- app/services/ci/create_trigger_request_service.rb | 5 +++-- lib/api/triggers.rb | 2 +- lib/api/v3/triggers.rb | 4 ++-- lib/ci/api/triggers.rb | 4 ++-- .../ci/create_trigger_request_service_spec.rb | 24 +++++++++++----------- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/app/services/ci/create_trigger_request_service.rb b/app/services/ci/create_trigger_request_service.rb index 1674830a41a..a43d0e4593c 100644 --- a/app/services/ci/create_trigger_request_service.rb +++ b/app/services/ci/create_trigger_request_service.rb @@ -1,13 +1,14 @@ module Ci module CreateTriggerRequestService + Result = Struct.new(:trigger_request, :pipeline) + def self.execute(project, trigger, ref, variables = nil) trigger_request = trigger.trigger_requests.create(variables: variables) pipeline = Ci::CreatePipelineService.new(project, trigger.owner, ref: ref) .execute(:trigger, ignore_skip_ci: true, trigger_request: trigger_request) - { trigger_request: trigger_request, - pipeline: pipeline } + Result.new(trigger_request, pipeline) end end end diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb index 55528101f15..280fe72ae47 100644 --- a/lib/api/triggers.rb +++ b/lib/api/triggers.rb @@ -28,7 +28,7 @@ module API # create request and trigger builds result = Ci::CreateTriggerRequestService.execute(project, trigger, params[:ref].to_s, variables) - pipeline = result[:pipeline] + pipeline = result.pipeline if pipeline.persisted? present pipeline, with: Entities::Pipeline diff --git a/lib/api/v3/triggers.rb b/lib/api/v3/triggers.rb index 0e236423b8c..e9d4c35307b 100644 --- a/lib/api/v3/triggers.rb +++ b/lib/api/v3/triggers.rb @@ -29,10 +29,10 @@ module API # create request and trigger builds result = Ci::CreateTriggerRequestService.execute(project, trigger, params[:ref].to_s, variables) - pipeline = result[:pipeline] + pipeline = result.pipeline if pipeline.persisted? - present result[:trigger_request], with: ::API::V3::Entities::TriggerRequest + present result.trigger_request, with: ::API::V3::Entities::TriggerRequest else render_validation_error!(pipeline) end diff --git a/lib/ci/api/triggers.rb b/lib/ci/api/triggers.rb index ce0ef95b186..6225203f223 100644 --- a/lib/ci/api/triggers.rb +++ b/lib/ci/api/triggers.rb @@ -25,10 +25,10 @@ module Ci # create request and trigger builds result = Ci::CreateTriggerRequestService.execute(project, trigger, params[:ref], variables) - pipeline = result[:pipeline] + pipeline = result.pipeline if pipeline.persisted? - present result[:trigger_request], with: Entities::TriggerRequest + present result.trigger_request, with: Entities::TriggerRequest else render_validation_error!(pipeline) end diff --git a/spec/services/ci/create_trigger_request_service_spec.rb b/spec/services/ci/create_trigger_request_service_spec.rb index 48d9b0844f1..37ca9804f56 100644 --- a/spec/services/ci/create_trigger_request_service_spec.rb +++ b/spec/services/ci/create_trigger_request_service_spec.rb @@ -17,26 +17,26 @@ describe Ci::CreateTriggerRequestService, services: true do subject { service.execute(project, trigger, 'master') } context 'without owner' do - it { expect(subject[:trigger_request]).to be_kind_of(Ci::TriggerRequest) } - it { expect(subject[:trigger_request].builds.first).to be_kind_of(Ci::Build) } - it { expect(subject[:pipeline]).to be_kind_of(Ci::Pipeline) } - it { expect(subject[:pipeline]).to be_trigger } + it { expect(subject.trigger_request).to be_kind_of(Ci::TriggerRequest) } + it { expect(subject.trigger_request.builds.first).to be_kind_of(Ci::Build) } + it { expect(subject.pipeline).to be_kind_of(Ci::Pipeline) } + it { expect(subject.pipeline).to be_trigger } end context 'with owner' do - it { expect(subject[:trigger_request]).to be_kind_of(Ci::TriggerRequest) } - it { expect(subject[:trigger_request].builds.first).to be_kind_of(Ci::Build) } - it { expect(subject[:trigger_request].builds.first.user).to eq(owner) } - it { expect(subject[:pipeline]).to be_kind_of(Ci::Pipeline) } - it { expect(subject[:pipeline]).to be_trigger } - it { expect(subject[:pipeline].user).to eq(owner) } + it { expect(subject.trigger_request).to be_kind_of(Ci::TriggerRequest) } + it { expect(subject.trigger_request.builds.first).to be_kind_of(Ci::Build) } + it { expect(subject.trigger_request.builds.first.user).to eq(owner) } + it { expect(subject.pipeline).to be_kind_of(Ci::Pipeline) } + it { expect(subject.pipeline).to be_trigger } + it { expect(subject.pipeline.user).to eq(owner) } end end context 'no commit for ref' do subject { service.execute(project, trigger, 'other-branch') } - it { expect(subject[:pipeline]).not_to be_persisted } + it { expect(subject.pipeline).not_to be_persisted } end context 'no builds created' do @@ -46,7 +46,7 @@ describe Ci::CreateTriggerRequestService, services: true do stub_ci_pipeline_yaml_file('script: { only: [develop], script: hello World }') end - it { expect(subject[:pipeline]).not_to be_persisted } + it { expect(subject.pipeline).not_to be_persisted } end end end -- cgit v1.2.1 From fd045bbee94faba08dee2e017fcf3718e9752d1b Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 20 Jul 2017 14:34:39 +0100 Subject: Fixed issue boards sidebar close button with new navigation Closes #35296 --- app/assets/stylesheets/pages/boards.scss | 5 ++++- changelogs/unreleased/issue-boards-close-icon-size.yml | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/issue-boards-close-icon-size.yml diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss index df858cffe09..6039cda96d8 100644 --- a/app/assets/stylesheets/pages/boards.scss +++ b/app/assets/stylesheets/pages/boards.scss @@ -431,7 +431,10 @@ margin: 5px; } -.page-with-layout-nav.page-with-sub-nav .issue-boards-sidebar { +.page-with-layout-nav.page-with-sub-nav .issue-boards-sidebar, +.page-with-new-sidebar.page-with-sidebar .issue-boards-sidebar { + position: absolute; + &.right-sidebar { top: 0; bottom: 0; diff --git a/changelogs/unreleased/issue-boards-close-icon-size.yml b/changelogs/unreleased/issue-boards-close-icon-size.yml new file mode 100644 index 00000000000..bc6bda0e50d --- /dev/null +++ b/changelogs/unreleased/issue-boards-close-icon-size.yml @@ -0,0 +1,4 @@ +--- +title: Fixed issue boards sidebar close icon size +merge_request: +author: -- cgit v1.2.1 From 01c9488f4a559063eba77074ba2d369de87b8018 Mon Sep 17 00:00:00 2001 From: Ryan Scott Date: Thu, 30 Mar 2017 10:39:06 +0900 Subject: Added slash command to close an issue as a duplicate. Closes #26372 --- app/models/system_note_metadata.rb | 2 +- app/services/issuable_base_service.rb | 22 +++++++++ app/services/quick_actions/interpret_service.rb | 14 ++++++ app/services/system_note_service.rb | 19 ++++++++ .../26372-duplicate-issue-slash-command.yml | 4 ++ doc/user/project/quick_actions.md | 1 + .../issues/user_uses_slash_commands_spec.rb | 41 ++++++++++++++++ spec/services/issues/update_service_spec.rb | 56 ++++++++++++++++++++++ .../quick_actions/interpret_service_spec.rb | 36 ++++++++++++++ spec/services/system_note_service_spec.rb | 25 ++++++++++ 10 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/26372-duplicate-issue-slash-command.yml diff --git a/app/models/system_note_metadata.rb b/app/models/system_note_metadata.rb index 414c95f7705..1ffdd285b91 100644 --- a/app/models/system_note_metadata.rb +++ b/app/models/system_note_metadata.rb @@ -2,7 +2,7 @@ class SystemNoteMetadata < ActiveRecord::Base ICON_TYPES = %w[ commit description merge confidential visible label assignee cross_reference title time_tracking branch milestone discussion task moved opened closed merged - outdated + outdated duplicate ].freeze validates :note, presence: true diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb index 9078b1f0983..c7e646222bb 100644 --- a/app/services/issuable_base_service.rb +++ b/app/services/issuable_base_service.rb @@ -46,6 +46,14 @@ class IssuableBaseService < BaseService SystemNoteService.change_time_spent(issuable, issuable.project, current_user) end + def create_issue_duplicate_note(issuable, original_issue) + SystemNoteService.mark_duplicate_issue(issuable, issuable.project, current_user, original_issue) + end + + def create_cross_reference_note(noteable, mentioner) + SystemNoteService.cross_reference(noteable, mentioner, current_user) + end + def filter_params(issuable) ability_name = :"admin_#{issuable.to_ability_name}" @@ -58,6 +66,7 @@ class IssuableBaseService < BaseService params.delete(:assignee_ids) params.delete(:assignee_id) params.delete(:due_date) + params.delete(:original_issue_id) end filter_assignee(issuable) @@ -209,6 +218,7 @@ class IssuableBaseService < BaseService change_state(issuable) change_subscription(issuable) change_todo(issuable) + change_issue_duplicate(issuable) toggle_award(issuable) filter_params(issuable) old_labels = issuable.labels.to_a @@ -291,6 +301,18 @@ class IssuableBaseService < BaseService end end + def change_issue_duplicate(issuable) + original_issue_id = params.delete(:original_issue_id) + return if original_issue_id.nil? + + original_issue = IssuesFinder.new(current_user).find(original_issue_id) + if original_issue.present? + create_issue_duplicate_note(issuable, original_issue) + close_service.new(project, current_user, {}).execute(issuable) + create_cross_reference_note(original_issue, issuable) + end + end + def toggle_award(issuable) award = params.delete(:emoji_award) if award diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index 6f82159e6c7..3eecf0b5545 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -471,6 +471,20 @@ module QuickActions end end + desc 'Mark this issue as a duplicate of another issue' + params '#issue' + condition do + issuable.is_a?(Issue) && + issuable.persisted? && + current_user.can?(:"update_#{issuable.to_ability_name}", issuable) + end + command :duplicate do |duplicate_param| + original_issue = extract_references(duplicate_param, :issue).first + if original_issue.present? && original_issue != issuable + @updates[:original_issue_id] = original_issue.id + end + end + def extract_users(params) return [] if params.nil? diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index da0f21d449a..2e5e904c43d 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -552,6 +552,25 @@ module SystemNoteService create_note(NoteSummary.new(noteable, project, author, body, action: 'moved')) end + # Called when a Notable has been marked as a duplicate of another Issue + # + # noteable - Noteable object + # project - Project owning noteable + # author - User performing the change + # original_issue - Issue that this is a duplicate of + # + # Example Note text: + # + # "marked this issue as a duplicate of #1234" + # + # "marked this issue as a duplicate of other_project#5678" + # + # Returns the created Note object + def mark_duplicate_issue(noteable, project, author, original_issue) + body = "marked this issue as a duplicate of #{original_issue.to_reference(project)}" + create_note(NoteSummary.new(noteable, project, author, body, action: 'duplicate')) + end + private def notes_for_mentioner(mentioner, noteable, notes) diff --git a/changelogs/unreleased/26372-duplicate-issue-slash-command.yml b/changelogs/unreleased/26372-duplicate-issue-slash-command.yml new file mode 100644 index 00000000000..079ebe59f98 --- /dev/null +++ b/changelogs/unreleased/26372-duplicate-issue-slash-command.yml @@ -0,0 +1,4 @@ +--- +title: Added /duplicate slash command to close a duplicate issue +merge_request: +author: Ryan Scott diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md index 19b51c83222..ce4dd4e99d5 100644 --- a/doc/user/project/quick_actions.md +++ b/doc/user/project/quick_actions.md @@ -37,3 +37,4 @@ do. | `/target_branch ` | Set target branch for current merge request | | `/award :emoji:` | Toggle award for :emoji: | | `/board_move ~column` | Move issue to column on the board | +| `/duplicate #issue` | Closes this issue and marks it as a duplicate of another issue | diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb index 1cd1f016674..d5de060b033 100644 --- a/spec/features/issues/user_uses_slash_commands_spec.rb +++ b/spec/features/issues/user_uses_slash_commands_spec.rb @@ -134,5 +134,46 @@ feature 'Issues > User uses quick actions', feature: true, js: true do expect(page).not_to have_content '/wip' end end + + describe 'mark issue as duplicate' do + let(:issue) { create(:issue, project: project) } + let(:original_issue) { create(:issue, project: project) } + + context 'when the current user can update issues' do + it 'does not create a note, and marks the issue as a duplicate' do + write_note("/duplicate ##{original_issue.to_reference}") + + expect(page).not_to have_content "/duplicate #{original_issue.to_reference}" + expect(page).to have_content 'Commands applied' + expect(page).to have_content "marked this issue as a duplicate of #{original_issue.to_reference}" + + issue.reload + + expect(issue.closed?).to be_truthy + end + end + + context 'when the current user cannot update the issue' do + let(:guest) { create(:user) } + before do + project.team << [guest, :guest] + logout + login_with(guest) + visit namespace_project_issue_path(project.namespace, project, issue) + end + + it 'does not create a note, and does not mark the issue as a duplicate' do + write_note("/duplicate ##{original_issue.to_reference}") + + expect(page).to have_content "/duplicate ##{original_issue.to_reference}" + expect(page).not_to have_content 'Commands applied' + expect(page).not_to have_content "marked this issue as a duplicate of #{original_issue.to_reference}" + + issue.reload + + expect(issue.closed?).to be_falsey + end + end + end end end diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index d0b991f19ab..3e7abf85106 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -491,6 +491,62 @@ describe Issues::UpdateService, services: true do include_examples 'updating mentions', Issues::UpdateService end + context 'duplicate issue' do + let(:issues_finder) { spy(:issues_finder) } + let(:close_service) { spy(:close_service) } + + before do + allow(IssuesFinder).to receive(:new).and_return(issues_finder) + allow(Issues::CloseService).to receive(:new).and_return(close_service) + allow(SystemNoteService).to receive(:cross_reference) + allow(SystemNoteService).to receive(:mark_duplicate_issue) + end + + context 'invalid original_issue_id' do + let(:original_issue_id) { double } + before { update_issue({ original_issue_id: original_issue_id }) } + + it 'finds the root issue' do + expect(issues_finder).to have_received(:find).with(original_issue_id) + end + + it 'does not close the issue' do + expect(close_service).not_to have_received(:execute) + end + + it 'does not create system notes' do + expect(SystemNoteService).not_to have_received(:cross_reference) + expect(SystemNoteService).not_to have_received(:mark_duplicate_issue) + end + end + + context 'valid original_issue_id' do + let(:original_issue) { create(:issue, project: project) } + let(:original_issue_id) { double } + + before do + allow(issues_finder).to receive(:find).and_return(original_issue) + update_issue({ original_issue_id: original_issue_id }) + end + + it 'finds the root issue' do + expect(issues_finder).to have_received(:find).with(original_issue_id) + end + + it 'closes the issue' do + expect(close_service).to have_received(:execute).with(issue) + end + + it 'creates a system note that this issue is a duplicate' do + expect(SystemNoteService).to have_received(:mark_duplicate_issue).with(issue, project, user, original_issue) + end + + it 'creates a cross reference system note in the other issue' do + expect(SystemNoteService).to have_received(:cross_reference).with(original_issue, issue, user) + end + end + end + include_examples 'issuable update service' do let(:open_issuable) { issue } let(:closed_issuable) { create(:closed_issue, project: project) } diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index a2db3f68ff7..3e4aa66756c 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -261,6 +261,17 @@ describe QuickActions::InterpretService, services: true do end end + shared_examples 'duplicate command' do + let(:issue_duplicate) { create(:issue, project: project) } + + it 'fetches issue and populates original_issue_id if content contains /duplicate issue_reference' do + issue_duplicate # populate the issue + _, updates = service.execute(content, issuable) + + expect(updates).to eq(original_issue_id: issue_duplicate.id) + end + end + it_behaves_like 'reopen command' do let(:content) { '/reopen' } let(:issuable) { issue } @@ -644,6 +655,26 @@ describe QuickActions::InterpretService, services: true do let(:issuable) { issue } end + it_behaves_like 'duplicate command' do + let(:content) { "/duplicate #{issue_duplicate.to_reference}" } + let(:issuable) { issue } + end + + it_behaves_like 'empty command' do + let(:content) { '/duplicate #{issue.to_reference}' } + let(:issuable) { issue } + end + + it_behaves_like 'empty command' do + let(:content) { '/duplicate' } + let(:issuable) { issue } + end + + it_behaves_like 'empty command' do + let(:content) { '/duplicate imaginary#1234' } + let(:issuable) { issue } + end + context 'when current_user cannot :admin_issue' do let(:visitor) { create(:user) } let(:issue) { create(:issue, project: project, author: visitor) } @@ -693,6 +724,11 @@ describe QuickActions::InterpretService, services: true do let(:content) { '/remove_due_date' } let(:issuable) { issue } end + + it_behaves_like 'empty command' do + let(:content) { '/duplicate #{issue.to_reference}' } + let(:issuable) { issue } + end end context '/award command' do diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index 60477b8e9ba..db120889119 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -1101,4 +1101,29 @@ describe SystemNoteService, services: true do expect(subject.note).to include(diffs_project_merge_request_url(project, merge_request, diff_id: diff_id, anchor: line_code)) end end + + describe '.mark_duplicate_issue' do + subject { described_class.mark_duplicate_issue(noteable, project, author, original_issue) } + + context 'within the same project' do + let(:original_issue) { create(:issue, project: project) } + + it_behaves_like 'a system note' do + let(:action) { 'duplicate' } + end + + it { expect(subject.note).to eq "marked this issue as a duplicate of #{original_issue.to_reference}" } + end + + context 'across different projects' do + let(:other_project) { create(:empty_project) } + let(:original_issue) { create(:issue, project: other_project) } + + it_behaves_like 'a system note' do + let(:action) { 'duplicate' } + end + + it { expect(subject.note).to eq "marked this issue as a duplicate of #{original_issue.to_reference(project)}" } + end + end end -- cgit v1.2.1 From 7e3d34595c3e090fe505b4fbd49cde2a303b1b6f Mon Sep 17 00:00:00 2001 From: Ryan Scott Date: Wed, 5 Apr 2017 11:31:48 +0900 Subject: Changes based on MR feedback. Marking an issue as a duplicate will now also add an upvote on behalf of the author on the original issue. --- app/models/system_note_metadata.rb | 5 ++- app/services/issuable_base_service.rb | 20 ++++----- app/services/system_note_service.rb | 8 ++-- .../issues/user_uses_slash_commands_spec.rb | 8 +--- spec/services/issues/update_service_spec.rb | 48 +++++++------------- .../quick_actions/interpret_service_spec.rb | 52 +++++++++++++++------- 6 files changed, 71 insertions(+), 70 deletions(-) diff --git a/app/models/system_note_metadata.rb b/app/models/system_note_metadata.rb index 1ffdd285b91..0b33e45473b 100644 --- a/app/models/system_note_metadata.rb +++ b/app/models/system_note_metadata.rb @@ -1,8 +1,9 @@ class SystemNoteMetadata < ActiveRecord::Base ICON_TYPES = %w[ commit description merge confidential visible label assignee cross_reference - title time_tracking branch milestone discussion task moved opened closed merged - outdated duplicate + title time_tracking branch milestone discussion task moved + opened closed merged duplicate + outdated ].freeze validates :note, presence: true diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb index c7e646222bb..f57fbaca836 100644 --- a/app/services/issuable_base_service.rb +++ b/app/services/issuable_base_service.rb @@ -50,10 +50,6 @@ class IssuableBaseService < BaseService SystemNoteService.mark_duplicate_issue(issuable, issuable.project, current_user, original_issue) end - def create_cross_reference_note(noteable, mentioner) - SystemNoteService.cross_reference(noteable, mentioner, current_user) - end - def filter_params(issuable) ability_name = :"admin_#{issuable.to_ability_name}" @@ -303,14 +299,18 @@ class IssuableBaseService < BaseService def change_issue_duplicate(issuable) original_issue_id = params.delete(:original_issue_id) - return if original_issue_id.nil? + return unless original_issue_id - original_issue = IssuesFinder.new(current_user).find(original_issue_id) - if original_issue.present? - create_issue_duplicate_note(issuable, original_issue) - close_service.new(project, current_user, {}).execute(issuable) - create_cross_reference_note(original_issue, issuable) + begin + original_issue = IssuesFinder.new(current_user).find(original_issue_id) + rescue ActiveRecord::RecordNotFound + return end + + note = create_issue_duplicate_note(issuable, original_issue) + note.create_cross_references! + close_service.new(project, current_user, {}).execute(issuable) + original_issue.create_award_emoji(AwardEmoji::UPVOTE_NAME, issuable.author) end def toggle_award(issuable) diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 2e5e904c43d..ed079f0e495 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -552,11 +552,11 @@ module SystemNoteService create_note(NoteSummary.new(noteable, project, author, body, action: 'moved')) end - # Called when a Notable has been marked as a duplicate of another Issue + # Called when a Noteable has been marked as a duplicate of another Issue # - # noteable - Noteable object - # project - Project owning noteable - # author - User performing the change + # noteable - Noteable object + # project - Project owning noteable + # author - User performing the change # original_issue - Issue that this is a duplicate of # # Example Note text: diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb index d5de060b033..28f27c76e35 100644 --- a/spec/features/issues/user_uses_slash_commands_spec.rb +++ b/spec/features/issues/user_uses_slash_commands_spec.rb @@ -147,9 +147,7 @@ feature 'Issues > User uses quick actions', feature: true, js: true do expect(page).to have_content 'Commands applied' expect(page).to have_content "marked this issue as a duplicate of #{original_issue.to_reference}" - issue.reload - - expect(issue.closed?).to be_truthy + expect(issue.reload).to be_closed end end @@ -169,9 +167,7 @@ feature 'Issues > User uses quick actions', feature: true, js: true do expect(page).not_to have_content 'Commands applied' expect(page).not_to have_content "marked this issue as a duplicate of #{original_issue.to_reference}" - issue.reload - - expect(issue.closed?).to be_falsey + expect(issue.reload).to be_open end end end diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index 3e7abf85106..e7f3ab93395 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -492,57 +492,43 @@ describe Issues::UpdateService, services: true do end context 'duplicate issue' do - let(:issues_finder) { spy(:issues_finder) } - let(:close_service) { spy(:close_service) } - - before do - allow(IssuesFinder).to receive(:new).and_return(issues_finder) - allow(Issues::CloseService).to receive(:new).and_return(close_service) - allow(SystemNoteService).to receive(:cross_reference) - allow(SystemNoteService).to receive(:mark_duplicate_issue) - end + let(:original_issue) { create(:issue, project: project) } context 'invalid original_issue_id' do - let(:original_issue_id) { double } - before { update_issue({ original_issue_id: original_issue_id }) } - - it 'finds the root issue' do - expect(issues_finder).to have_received(:find).with(original_issue_id) + before do + update_issue(original_issue_id: 123456789) end it 'does not close the issue' do - expect(close_service).not_to have_received(:execute) + expect(issue.reload).not_to be_closed end - it 'does not create system notes' do - expect(SystemNoteService).not_to have_received(:cross_reference) - expect(SystemNoteService).not_to have_received(:mark_duplicate_issue) + it 'does not create a system note' do + note = find_note("marked this issue as a duplicate of #{original_issue.to_reference}") + expect(note).to be_nil + end + + it 'does not upvote the issue on behalf of the author' do + expect(original_issue).not_to be_awarded_emoji(AwardEmoji::UPVOTE_NAME, issue.author) end end context 'valid original_issue_id' do - let(:original_issue) { create(:issue, project: project) } - let(:original_issue_id) { double } - before do - allow(issues_finder).to receive(:find).and_return(original_issue) - update_issue({ original_issue_id: original_issue_id }) - end - - it 'finds the root issue' do - expect(issues_finder).to have_received(:find).with(original_issue_id) + update_issue(original_issue_id: original_issue.id) end it 'closes the issue' do - expect(close_service).to have_received(:execute).with(issue) + expect(issue.reload).to be_closed end it 'creates a system note that this issue is a duplicate' do - expect(SystemNoteService).to have_received(:mark_duplicate_issue).with(issue, project, user, original_issue) + note = find_note("marked this issue as a duplicate of #{original_issue.to_reference}") + expect(note).not_to be_nil end - it 'creates a cross reference system note in the other issue' do - expect(SystemNoteService).to have_received(:cross_reference).with(original_issue, issue, user) + it 'upvotes the issue on behalf of the author' do + expect(original_issue).to be_awarded_emoji(AwardEmoji::UPVOTE_NAME, issue.author) end end end diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index 3e4aa66756c..1d60b74e566 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -262,8 +262,6 @@ describe QuickActions::InterpretService, services: true do end shared_examples 'duplicate command' do - let(:issue_duplicate) { create(:issue, project: project) } - it 'fetches issue and populates original_issue_id if content contains /duplicate issue_reference' do issue_duplicate # populate the issue _, updates = service.execute(content, issuable) @@ -655,24 +653,44 @@ describe QuickActions::InterpretService, services: true do let(:issuable) { issue } end - it_behaves_like 'duplicate command' do - let(:content) { "/duplicate #{issue_duplicate.to_reference}" } - let(:issuable) { issue } - end + context '/duplicate command' do + it_behaves_like 'duplicate command' do + let(:issue_duplicate) { create(:issue, project: project) } + let(:content) { "/duplicate #{issue_duplicate.to_reference}" } + let(:issuable) { issue } + end - it_behaves_like 'empty command' do - let(:content) { '/duplicate #{issue.to_reference}' } - let(:issuable) { issue } - end + it_behaves_like 'empty command' do + let(:content) { "/duplicate #{issue.to_reference}" } + let(:issuable) { issue } + end - it_behaves_like 'empty command' do - let(:content) { '/duplicate' } - let(:issuable) { issue } - end + it_behaves_like 'empty command' do + let(:content) { '/duplicate' } + let(:issuable) { issue } + end - it_behaves_like 'empty command' do - let(:content) { '/duplicate imaginary#1234' } - let(:issuable) { issue } + context 'cross project references' do + it_behaves_like 'duplicate command' do + let(:other_project) { create(:empty_project, :public) } + let(:issue_duplicate) { create(:issue, project: other_project) } + let(:content) { "/duplicate #{issue_duplicate.to_reference(project)}" } + let(:issuable) { issue } + end + + it_behaves_like 'empty command' do + let(:content) { '/duplicate imaginary#1234' } + let(:issuable) { issue } + end + + it_behaves_like 'empty command' do + let(:other_project) { create(:empty_project, :private) } + let(:issue_duplicate) { create(:issue, project: other_project) } + + let(:content) { "/duplicate #{issue_duplicate.to_reference(project)}" } + let(:issuable) { issue } + end + end end context 'when current_user cannot :admin_issue' do -- cgit v1.2.1 From 3498e825d08adb0311d0431d9d15e450f95bfc86 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Tue, 18 Jul 2017 15:27:00 +0100 Subject: Fix feature specs --- spec/features/issues/user_uses_slash_commands_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb index 28f27c76e35..60b787fdd61 100644 --- a/spec/features/issues/user_uses_slash_commands_spec.rb +++ b/spec/features/issues/user_uses_slash_commands_spec.rb @@ -155,9 +155,9 @@ feature 'Issues > User uses quick actions', feature: true, js: true do let(:guest) { create(:user) } before do project.team << [guest, :guest] - logout - login_with(guest) - visit namespace_project_issue_path(project.namespace, project, issue) + gitlab_sign_out + sign_in(guest) + visit project_issue_path(project, issue) end it 'does not create a note, and does not mark the issue as a duplicate' do -- cgit v1.2.1 From de01b862254be634a0602c6a8875cdda0538354f Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Fri, 21 Jul 2017 03:10:26 +0800 Subject: Add a note that schedules could be deactivated when lacking permissions too. --- doc/user/project/pipelines/schedules.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/user/project/pipelines/schedules.md b/doc/user/project/pipelines/schedules.md index 258b3a2f955..9ad15a12c3c 100644 --- a/doc/user/project/pipelines/schedules.md +++ b/doc/user/project/pipelines/schedules.md @@ -71,9 +71,10 @@ The next time a pipeline is scheduled, your credentials will be used. >**Note:** When the owner of the schedule doesn't have the ability to create pipelines -anymore, due to e.g., being blocked or removed from the project, the schedule -is deactivated. Another user can take ownership and activate it, so the -schedule can be run again. +anymore, due to e.g., being blocked or removed from the project, or lacking +the permission to run on protected branches or tags. When this happened, the +schedule is deactivated. Another user can take ownership and activate it, so +the schedule can be run again. ## Advanced admin configuration -- cgit v1.2.1 From 8a444484345806dcbc0312d770b185edde1edb67 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Fri, 21 Jul 2017 17:49:32 +0800 Subject: Extract validations --- app/services/ci/create_pipeline_service.rb | 48 +++++++++++++++--------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 3ff698b6437..21e2ef153de 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -15,12 +15,34 @@ module Ci pipeline_schedule: schedule ) + result = validate(current_user || trigger_request.trigger.owner, + ignore_skip_ci: ignore_skip_ci, + save_on_errors: save_on_errors) + + return result if result + + Ci::Pipeline.transaction do + update_merge_requests_head_pipeline if pipeline.save + + Ci::CreatePipelineStagesService + .new(project, current_user) + .execute(pipeline) + end + + cancel_pending_pipelines if project.auto_cancel_pending_pipelines? + + pipeline_created_counter.increment(source: source) + + pipeline.tap(&:process!) + end + + private + + def validate(triggering_user, ignore_skip_ci:, save_on_errors:) unless project.builds_enabled? return error('Pipeline is disabled') end - triggering_user = current_user || trigger_request.trigger.owner - unless allowed_to_trigger_pipeline?(triggering_user) if can?(triggering_user, :create_pipeline, project) return error("Insufficient permissions for protected ref '#{ref}'") @@ -52,28 +74,6 @@ module Ci unless pipeline.has_stage_seeds? return error('No stages / jobs for this pipeline.') end - - process! do - pipeline_created_counter.increment(source: source) - end - end - - private - - def process! - Ci::Pipeline.transaction do - update_merge_requests_head_pipeline if pipeline.save - - Ci::CreatePipelineStagesService - .new(project, current_user) - .execute(pipeline) - end - - cancel_pending_pipelines if project.auto_cancel_pending_pipelines? - - yield - - pipeline.tap(&:process!) end def allowed_to_trigger_pipeline?(triggering_user) -- cgit v1.2.1 From 53c5b6717ccfb4c9bc1f4faf008d084dd4f0cd96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 21 Jul 2017 12:43:04 +0200 Subject: Fix translations for Star/Unstar in JS file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- app/assets/javascripts/star.js | 6 ++++-- app/views/projects/buttons/_star.html.haml | 2 +- changelogs/unreleased/35391-fix-star-i18n-in-js.yml | 4 ++++ 3 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/35391-fix-star-i18n-in-js.yml diff --git a/app/assets/javascripts/star.js b/app/assets/javascripts/star.js index 6d38124f1c1..3a06b477d7c 100644 --- a/app/assets/javascripts/star.js +++ b/app/assets/javascripts/star.js @@ -1,6 +1,8 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-unused-vars, one-var, no-var, one-var-declaration-per-line, prefer-arrow-callback, no-new, max-len */ /* global Flash */ +import { __, s__ } from './locale'; + export default class Star { constructor() { $('.project-home-panel .toggle-star').on('ajax:success', function(e, data, status, xhr) { @@ -11,10 +13,10 @@ export default class Star { toggleStar = function(isStarred) { $this.parent().find('.star-count').text(data.star_count); if (isStarred) { - $starSpan.removeClass('starred').text('Star'); + $starSpan.removeClass('starred').text(s__('StarProject|Star')); $starIcon.removeClass('fa-star').addClass('fa-star-o'); } else { - $starSpan.addClass('starred').text('Unstar'); + $starSpan.addClass('starred').text(__('Unstar')); $starIcon.removeClass('fa-star-o').addClass('fa-star'); } }; diff --git a/app/views/projects/buttons/_star.html.haml b/app/views/projects/buttons/_star.html.haml index e248676be0d..c82ae35a685 100644 --- a/app/views/projects/buttons/_star.html.haml +++ b/app/views/projects/buttons/_star.html.haml @@ -2,7 +2,7 @@ = link_to toggle_star_project_path(@project), { class: 'btn star-btn toggle-star', method: :post, remote: true } do - if current_user.starred?(@project) = icon('star') - %span.starred= _('Unstar') + %span.starred= _('Unstar') - else = icon('star-o') %span= s_('StarProject|Star') diff --git a/changelogs/unreleased/35391-fix-star-i18n-in-js.yml b/changelogs/unreleased/35391-fix-star-i18n-in-js.yml new file mode 100644 index 00000000000..a6fd4dc89fd --- /dev/null +++ b/changelogs/unreleased/35391-fix-star-i18n-in-js.yml @@ -0,0 +1,4 @@ +--- +title: Fix translations for Star/Unstar in JS file +merge_request: +author: -- cgit v1.2.1 From eaa935d77b824510a141ab10e9471107c516f902 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 21 Jul 2017 13:09:13 +0200 Subject: Fix target project merge request link on build page --- app/serializers/build_details_entity.rb | 3 ++- spec/serializers/build_details_entity_spec.rb | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/serializers/build_details_entity.rb b/app/serializers/build_details_entity.rb index 8ad5af1987c..743a08acefe 100644 --- a/app/serializers/build_details_entity.rb +++ b/app/serializers/build_details_entity.rb @@ -16,7 +16,8 @@ class BuildDetailsEntity < JobEntity end expose :path do |build| - project_merge_request_path(build.project, build.merge_request) + project_merge_request_path(build.merge_request.project, + build.merge_request) end end diff --git a/spec/serializers/build_details_entity_spec.rb b/spec/serializers/build_details_entity_spec.rb index 446a2451956..1332572fffc 100644 --- a/spec/serializers/build_details_entity_spec.rb +++ b/spec/serializers/build_details_entity_spec.rb @@ -81,9 +81,9 @@ describe BuildDetailsEntity do expect(subject[:merge_request][:iid]).to eq merge_request.iid end - it 'has a correct merge request path' do + it 'has a merge request path to a target project' do expect(subject[:merge_request][:path]) - .to include fork_project.full_path + .to include project.full_path end end -- cgit v1.2.1 From 1df696f5a6836e03a6bf8d5139c2c7ce6d96e727 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 20 Jul 2017 15:42:33 +0100 Subject: Move duplicate issue management to a service --- app/helpers/system_note_helper.rb | 3 +- app/services/issuable_base_service.rb | 23 +------ app/services/issues/base_service.rb | 8 +++ app/services/issues/duplicate_service.rb | 24 +++++++ app/services/issues/update_service.rb | 18 ++--- app/services/quick_actions/interpret_service.rb | 10 ++- app/services/system_note_service.rb | 31 +++++++-- app/views/shared/icons/_icon_clone.svg | 3 + .../26372-duplicate-issue-slash-command.yml | 4 +- spec/services/issues/duplicate_service_spec.rb | 80 ++++++++++++++++++++++ spec/services/issues/update_service_spec.rb | 41 +++-------- .../quick_actions/interpret_service_spec.rb | 11 +-- spec/services/system_note_service_spec.rb | 35 ++++++++-- 13 files changed, 205 insertions(+), 86 deletions(-) create mode 100644 app/services/issues/duplicate_service.rb create mode 100644 app/views/shared/icons/_icon_clone.svg create mode 100644 spec/services/issues/duplicate_service_spec.rb diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb index 209bd56b78a..08fd97cd048 100644 --- a/app/helpers/system_note_helper.rb +++ b/app/helpers/system_note_helper.rb @@ -18,7 +18,8 @@ module SystemNoteHelper 'milestone' => 'icon_clock_o', 'discussion' => 'icon_comment_o', 'moved' => 'icon_arrow_circle_o_right', - 'outdated' => 'icon_edit' + 'outdated' => 'icon_edit', + 'duplicate' => 'icon_clone' }.freeze def icon_for_system_note(note) diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb index f57fbaca836..ea497729115 100644 --- a/app/services/issuable_base_service.rb +++ b/app/services/issuable_base_service.rb @@ -46,10 +46,6 @@ class IssuableBaseService < BaseService SystemNoteService.change_time_spent(issuable, issuable.project, current_user) end - def create_issue_duplicate_note(issuable, original_issue) - SystemNoteService.mark_duplicate_issue(issuable, issuable.project, current_user, original_issue) - end - def filter_params(issuable) ability_name = :"admin_#{issuable.to_ability_name}" @@ -62,7 +58,7 @@ class IssuableBaseService < BaseService params.delete(:assignee_ids) params.delete(:assignee_id) params.delete(:due_date) - params.delete(:original_issue_id) + params.delete(:canonical_issue_id) end filter_assignee(issuable) @@ -214,7 +210,6 @@ class IssuableBaseService < BaseService change_state(issuable) change_subscription(issuable) change_todo(issuable) - change_issue_duplicate(issuable) toggle_award(issuable) filter_params(issuable) old_labels = issuable.labels.to_a @@ -297,22 +292,6 @@ class IssuableBaseService < BaseService end end - def change_issue_duplicate(issuable) - original_issue_id = params.delete(:original_issue_id) - return unless original_issue_id - - begin - original_issue = IssuesFinder.new(current_user).find(original_issue_id) - rescue ActiveRecord::RecordNotFound - return - end - - note = create_issue_duplicate_note(issuable, original_issue) - note.create_cross_references! - close_service.new(project, current_user, {}).execute(issuable) - original_issue.create_award_emoji(AwardEmoji::UPVOTE_NAME, issuable.author) - end - def toggle_award(issuable) award = params.delete(:emoji_award) if award diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb index 34199eb5d13..4c198fc96ea 100644 --- a/app/services/issues/base_service.rb +++ b/app/services/issues/base_service.rb @@ -7,6 +7,14 @@ module Issues issue_data end + def reopen_service + Issues::ReopenService + end + + def close_service + Issues::CloseService + end + private def create_assignee_note(issue, old_assignees) diff --git a/app/services/issues/duplicate_service.rb b/app/services/issues/duplicate_service.rb new file mode 100644 index 00000000000..5c0854e664d --- /dev/null +++ b/app/services/issues/duplicate_service.rb @@ -0,0 +1,24 @@ +module Issues + class DuplicateService < Issues::BaseService + def execute(duplicate_issue, canonical_issue) + return if canonical_issue == duplicate_issue + return unless can?(current_user, :update_issue, duplicate_issue) + return unless can?(current_user, :create_note, canonical_issue) + + create_issue_duplicate_note(duplicate_issue, canonical_issue) + create_issue_canonical_note(canonical_issue, duplicate_issue) + + close_service.new(project, current_user, {}).execute(duplicate_issue) + end + + private + + def create_issue_duplicate_note(duplicate_issue, canonical_issue) + SystemNoteService.mark_duplicate_issue(duplicate_issue, duplicate_issue.project, current_user, canonical_issue) + end + + def create_issue_canonical_note(canonical_issue, duplicate_issue) + SystemNoteService.mark_canonical_issue_of_duplicate(canonical_issue, canonical_issue.project, current_user, duplicate_issue) + end + end +end diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb index cd9f9a4a16e..8d918ccc635 100644 --- a/app/services/issues/update_service.rb +++ b/app/services/issues/update_service.rb @@ -5,6 +5,7 @@ module Issues def execute(issue) handle_move_between_iids(issue) filter_spam_check_params + change_issue_duplicate(issue) update(issue) end @@ -53,14 +54,6 @@ module Issues end end - def reopen_service - Issues::ReopenService - end - - def close_service - Issues::CloseService - end - def handle_move_between_iids(issue) return unless params[:move_between_iids] @@ -72,6 +65,15 @@ module Issues issue.move_between(issue_before, issue_after) end + def change_issue_duplicate(issue) + canonical_issue_id = params.delete(:canonical_issue_id) + canonical_issue = IssuesFinder.new(current_user).find_by(id: canonical_issue_id) + + if canonical_issue + Issues::DuplicateService.new(project, current_user).execute(issue, canonical_issue) + end + end + private def get_issue_if_allowed(project, iid) diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index 3eecf0b5545..5dc1b91d2c0 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -472,6 +472,9 @@ module QuickActions end desc 'Mark this issue as a duplicate of another issue' + explanation do |duplicate_reference| + "Marks this issue as a duplicate of #{duplicate_reference}." + end params '#issue' condition do issuable.is_a?(Issue) && @@ -479,9 +482,10 @@ module QuickActions current_user.can?(:"update_#{issuable.to_ability_name}", issuable) end command :duplicate do |duplicate_param| - original_issue = extract_references(duplicate_param, :issue).first - if original_issue.present? && original_issue != issuable - @updates[:original_issue_id] = original_issue.id + canonical_issue = extract_references(duplicate_param, :issue).first + + if canonical_issue.present? + @updates[:canonical_issue_id] = canonical_issue.id end end diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index ed079f0e495..2dbee9c246e 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -554,10 +554,10 @@ module SystemNoteService # Called when a Noteable has been marked as a duplicate of another Issue # - # noteable - Noteable object - # project - Project owning noteable - # author - User performing the change - # original_issue - Issue that this is a duplicate of + # noteable - Noteable object + # project - Project owning noteable + # author - User performing the change + # canonical_issue - Issue that this is a duplicate of # # Example Note text: # @@ -566,8 +566,27 @@ module SystemNoteService # "marked this issue as a duplicate of other_project#5678" # # Returns the created Note object - def mark_duplicate_issue(noteable, project, author, original_issue) - body = "marked this issue as a duplicate of #{original_issue.to_reference(project)}" + def mark_duplicate_issue(noteable, project, author, canonical_issue) + body = "marked this issue as a duplicate of #{canonical_issue.to_reference(project)}" + create_note(NoteSummary.new(noteable, project, author, body, action: 'duplicate')) + end + + # Called when a Noteable has been marked as the canonical Issue of a duplicate + # + # noteable - Noteable object + # project - Project owning noteable + # author - User performing the change + # duplicate_issue - Issue that was a duplicate of this + # + # Example Note text: + # + # "marked #1234 as a duplicate of this issue" + # + # "marked other_project#5678 as a duplicate of this issue" + # + # Returns the created Note object + def mark_canonical_issue_of_duplicate(noteable, project, author, duplicate_issue) + body = "marked #{duplicate_issue.to_reference(project)} as a duplicate of this issue" create_note(NoteSummary.new(noteable, project, author, body, action: 'duplicate')) end diff --git a/app/views/shared/icons/_icon_clone.svg b/app/views/shared/icons/_icon_clone.svg new file mode 100644 index 00000000000..ccc897aa98f --- /dev/null +++ b/app/views/shared/icons/_icon_clone.svg @@ -0,0 +1,3 @@ + + + diff --git a/changelogs/unreleased/26372-duplicate-issue-slash-command.yml b/changelogs/unreleased/26372-duplicate-issue-slash-command.yml index 079ebe59f98..3108344e0bf 100644 --- a/changelogs/unreleased/26372-duplicate-issue-slash-command.yml +++ b/changelogs/unreleased/26372-duplicate-issue-slash-command.yml @@ -1,4 +1,4 @@ --- -title: Added /duplicate slash command to close a duplicate issue -merge_request: +title: Added /duplicate quick action to close a duplicate issue +merge_request: 12845 author: Ryan Scott diff --git a/spec/services/issues/duplicate_service_spec.rb b/spec/services/issues/duplicate_service_spec.rb new file mode 100644 index 00000000000..82daf53b173 --- /dev/null +++ b/spec/services/issues/duplicate_service_spec.rb @@ -0,0 +1,80 @@ +require 'spec_helper' + +describe Issues::DuplicateService, services: true do + let(:user) { create(:user) } + let(:canonical_project) { create(:empty_project) } + let(:duplicate_project) { create(:empty_project) } + + let(:canonical_issue) { create(:issue, project: canonical_project) } + let(:duplicate_issue) { create(:issue, project: duplicate_project) } + + subject { described_class.new(duplicate_project, user, {}) } + + describe '#execute' do + context 'when the issues passed are the same' do + it 'does nothing' do + expect(subject).not_to receive(:close_service) + expect(SystemNoteService).not_to receive(:mark_duplicate_issue) + expect(SystemNoteService).not_to receive(:mark_canonical_issue_of_duplicate) + + subject.execute(duplicate_issue, duplicate_issue) + end + end + + context 'when the user cannot update the duplicate issue' do + before do + canonical_project.add_reporter(user) + end + + it 'does nothing' do + expect(subject).not_to receive(:close_service) + expect(SystemNoteService).not_to receive(:mark_duplicate_issue) + expect(SystemNoteService).not_to receive(:mark_canonical_issue_of_duplicate) + + subject.execute(duplicate_issue, canonical_issue) + end + end + + context 'when the user cannot comment on the canonical issue' do + before do + duplicate_project.add_reporter(user) + end + + it 'does nothing' do + expect(subject).not_to receive(:close_service) + expect(SystemNoteService).not_to receive(:mark_duplicate_issue) + expect(SystemNoteService).not_to receive(:mark_canonical_issue_of_duplicate) + + subject.execute(duplicate_issue, canonical_issue) + end + end + + context 'when the user can mark the issue as a duplicate' do + before do + canonical_project.add_reporter(user) + duplicate_project.add_reporter(user) + end + + it 'closes the duplicate issue' do + subject.execute(duplicate_issue, canonical_issue) + + expect(duplicate_issue.reload).to be_closed + expect(canonical_issue.reload).to be_open + end + + it 'adds a system note to the duplicate issue' do + expect(SystemNoteService) + .to receive(:mark_duplicate_issue).with(duplicate_issue, duplicate_project, user, canonical_issue) + + subject.execute(duplicate_issue, canonical_issue) + end + + it 'adds a system note to the canonical issue' do + expect(SystemNoteService) + .to receive(:mark_canonical_issue_of_duplicate).with(canonical_issue, canonical_project, user, duplicate_issue) + + subject.execute(duplicate_issue, canonical_issue) + end + end + end +end diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index e7f3ab93395..064be940a1c 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -492,43 +492,22 @@ describe Issues::UpdateService, services: true do end context 'duplicate issue' do - let(:original_issue) { create(:issue, project: project) } + let(:canonical_issue) { create(:issue, project: project) } - context 'invalid original_issue_id' do - before do - update_issue(original_issue_id: 123456789) - end - - it 'does not close the issue' do - expect(issue.reload).not_to be_closed - end + context 'invalid canonical_issue_id' do + it 'does not call the duplicate service' do + expect(Issues::DuplicateService).not_to receive(:new) - it 'does not create a system note' do - note = find_note("marked this issue as a duplicate of #{original_issue.to_reference}") - expect(note).to be_nil - end - - it 'does not upvote the issue on behalf of the author' do - expect(original_issue).not_to be_awarded_emoji(AwardEmoji::UPVOTE_NAME, issue.author) + update_issue(canonical_issue_id: 123456789) end end - context 'valid original_issue_id' do - before do - update_issue(original_issue_id: original_issue.id) - end - - it 'closes the issue' do - expect(issue.reload).to be_closed - end - - it 'creates a system note that this issue is a duplicate' do - note = find_note("marked this issue as a duplicate of #{original_issue.to_reference}") - expect(note).not_to be_nil - end + context 'valid canonical_issue_id' do + it 'calls the duplicate service with both issues' do + expect_any_instance_of(Issues::DuplicateService) + .to receive(:execute).with(issue, canonical_issue) - it 'upvotes the issue on behalf of the author' do - expect(original_issue).to be_awarded_emoji(AwardEmoji::UPVOTE_NAME, issue.author) + update_issue(canonical_issue_id: canonical_issue.id) end end end diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index 1d60b74e566..2a2a5c38e4b 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -262,11 +262,11 @@ describe QuickActions::InterpretService, services: true do end shared_examples 'duplicate command' do - it 'fetches issue and populates original_issue_id if content contains /duplicate issue_reference' do + it 'fetches issue and populates canonical_issue_id if content contains /duplicate issue_reference' do issue_duplicate # populate the issue _, updates = service.execute(content, issuable) - expect(updates).to eq(original_issue_id: issue_duplicate.id) + expect(updates).to eq(canonical_issue_id: issue_duplicate.id) end end @@ -660,11 +660,6 @@ describe QuickActions::InterpretService, services: true do let(:issuable) { issue } end - it_behaves_like 'empty command' do - let(:content) { "/duplicate #{issue.to_reference}" } - let(:issuable) { issue } - end - it_behaves_like 'empty command' do let(:content) { '/duplicate' } let(:issuable) { issue } @@ -679,7 +674,7 @@ describe QuickActions::InterpretService, services: true do end it_behaves_like 'empty command' do - let(:content) { '/duplicate imaginary#1234' } + let(:content) { "/duplicate imaginary#1234" } let(:issuable) { issue } end diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index db120889119..681b419aedf 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -1103,27 +1103,52 @@ describe SystemNoteService, services: true do end describe '.mark_duplicate_issue' do - subject { described_class.mark_duplicate_issue(noteable, project, author, original_issue) } + subject { described_class.mark_duplicate_issue(noteable, project, author, canonical_issue) } context 'within the same project' do - let(:original_issue) { create(:issue, project: project) } + let(:canonical_issue) { create(:issue, project: project) } it_behaves_like 'a system note' do let(:action) { 'duplicate' } end - it { expect(subject.note).to eq "marked this issue as a duplicate of #{original_issue.to_reference}" } + it { expect(subject.note).to eq "marked this issue as a duplicate of #{canonical_issue.to_reference}" } end context 'across different projects' do let(:other_project) { create(:empty_project) } - let(:original_issue) { create(:issue, project: other_project) } + let(:canonical_issue) { create(:issue, project: other_project) } it_behaves_like 'a system note' do let(:action) { 'duplicate' } end - it { expect(subject.note).to eq "marked this issue as a duplicate of #{original_issue.to_reference(project)}" } + it { expect(subject.note).to eq "marked this issue as a duplicate of #{canonical_issue.to_reference(project)}" } + end + end + + describe '.mark_canonical_issue_of_duplicate' do + subject { described_class.mark_canonical_issue_of_duplicate(noteable, project, author, duplicate_issue) } + + context 'within the same project' do + let(:duplicate_issue) { create(:issue, project: project) } + + it_behaves_like 'a system note' do + let(:action) { 'duplicate' } + end + + it { expect(subject.note).to eq "marked #{duplicate_issue.to_reference} as a duplicate of this issue" } + end + + context 'across different projects' do + let(:other_project) { create(:empty_project) } + let(:duplicate_issue) { create(:issue, project: other_project) } + + it_behaves_like 'a system note' do + let(:action) { 'duplicate' } + end + + it { expect(subject.note).to eq "marked #{duplicate_issue.to_reference(project)} as a duplicate of this issue" } end end end -- cgit v1.2.1 From c5c9dce270516adf3a2e4a549d1c32b6a3223335 Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Wed, 12 Jul 2017 16:58:48 -0300 Subject: Add group milestones API endpoint --- app/finders/issuable_finder.rb | 2 +- doc/api/README.md | 3 +- doc/api/group_milestones.md | 120 ++++++++ lib/api/api.rb | 3 +- lib/api/entities.rb | 4 +- lib/api/group_milestones.rb | 85 ++++++ lib/api/helpers.rb | 4 + lib/api/milestone_responses.rb | 98 +++++++ lib/api/milestones.rb | 154 ---------- lib/api/project_milestones.rb | 91 ++++++ spec/requests/api/group_milestones_spec.rb | 21 ++ spec/requests/api/milestones_spec.rb | 385 ------------------------- spec/requests/api/project_milestones_spec.rb | 25 ++ spec/support/api/milestones_shared_examples.rb | 383 ++++++++++++++++++++++++ 14 files changed, 834 insertions(+), 544 deletions(-) create mode 100644 doc/api/group_milestones.md create mode 100644 lib/api/group_milestones.rb create mode 100644 lib/api/milestone_responses.rb delete mode 100644 lib/api/milestones.rb create mode 100644 lib/api/project_milestones.rb create mode 100644 spec/requests/api/group_milestones_spec.rb delete mode 100644 spec/requests/api/milestones_spec.rb create mode 100644 spec/requests/api/project_milestones_spec.rb create mode 100644 spec/support/api/milestones_shared_examples.rb diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index 2e5a6493134..762c0861cd2 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -20,7 +20,7 @@ # class IssuableFinder include CreatedAtFilter - + NONE = '0'.freeze IRRELEVANT_PARAMS_FOR_CACHE_KEY = %i[utf8 sort page].freeze diff --git a/doc/api/README.md b/doc/api/README.md index 95e7a457848..a888c0ebb4e 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -29,7 +29,8 @@ following locations: - [Keys](keys.md) - [Labels](labels.md) - [Merge Requests](merge_requests.md) -- [Milestones](milestones.md) +- [Project milestones](milestones.md) +- [Group milestones](group_milestones.md) - [Namespaces](namespaces.md) - [Notes](notes.md) (comments) - [Notification settings](notification_settings.md) diff --git a/doc/api/group_milestones.md b/doc/api/group_milestones.md new file mode 100644 index 00000000000..086fba7e91d --- /dev/null +++ b/doc/api/group_milestones.md @@ -0,0 +1,120 @@ +# Group milestones API + +## List group milestones + +Returns a list of group milestones. + +``` +GET /groups/:id/milestones +GET /groups/:id/milestones?iids=42 +GET /groups/:id/milestones?iids[]=42&iids[]=43 +GET /groups/:id/milestones?state=active +GET /groups/:id/milestones?state=closed +GET /groups/:id/milestones?search=version +``` + +Parameters: + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user | +| `iids` | Array[integer] | optional | Return only the milestones having the given `iids` | +| `state` | string | optional | Return only `active` or `closed` milestones` | +| `search` | string | optional | Return only milestones with a title or description matching the provided string | + +```bash +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/milestones +``` + +Example Response: + +```json +[ + { + "id": 12, + "iid": 3, + "group_id": 16, + "title": "10.0", + "description": "Version", + "due_date": "2013-11-29", + "start_date": "2013-11-10", + "state": "active", + "updated_at": "2013-10-02T09:24:18Z", + "created_at": "2013-10-02T09:24:18Z" + } +] +``` + + +## Get single milestone + +Gets a single group milestone. + +``` +GET /groups/:id/milestones/:milestone_id +``` + +Parameters: + +- `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user +- `milestone_id` (required) - The ID of the group milestone + +## Create new milestone + +Creates a new group milestone. + +``` +POST /groups/:id/milestones +``` + +Parameters: + +- `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user +- `title` (required) - The title of an milestone +- `description` (optional) - The description of the milestone +- `due_date` (optional) - The due date of the milestone +- `start_date` (optional) - The start date of the milestone + +## Edit milestone + +Updates an existing group milestone. + +``` +PUT /groups/:id/milestones/:milestone_id +``` + +Parameters: + +- `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user +- `milestone_id` (required) - The ID of a group milestone +- `title` (optional) - The title of a milestone +- `description` (optional) - The description of a milestone +- `due_date` (optional) - The due date of the milestone +- `start_date` (optional) - The start date of the milestone +- `state_event` (optional) - The state event of the milestone (close|activate) + +## Get all issues assigned to a single milestone + +Gets all issues assigned to a single group milestone. + +``` +GET /groups/:id/milestones/:milestone_id/issues +``` + +Parameters: + +- `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user +- `milestone_id` (required) - The ID of a group milestone + +## Get all merge requests assigned to a single milestone + +Gets all merge requests assigned to a single group milestone. + +``` +GET /groups/:id/milestones/:milestone_id/merge_requests +``` + +Parameters: + +- `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user +- `milestone_id` (required) - The ID of a group milestone diff --git a/lib/api/api.rb b/lib/api/api.rb index efcf0976a81..7e45c34731f 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -109,7 +109,8 @@ module API mount ::API::Members mount ::API::MergeRequestDiffs mount ::API::MergeRequests - mount ::API::Milestones + mount ::API::ProjectMilestones + mount ::API::GroupMilestones mount ::API::Namespaces mount ::API::Notes mount ::API::NotificationSettings diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 09a88869063..586325ddb0c 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -269,8 +269,8 @@ module API class Milestone < Grape::Entity expose :id, :iid - expose(:project_id) { |entity| entity&.project_id } - expose(:group_id) { |entity| entity&.group_id } + expose :project_id, if: -> (entity, options) { entity&.project_id } + expose :group_id, if: -> (entity, options) { entity&.group_id } expose :title, :description expose :state, :created_at, :updated_at expose :due_date diff --git a/lib/api/group_milestones.rb b/lib/api/group_milestones.rb new file mode 100644 index 00000000000..b85eb59dc0a --- /dev/null +++ b/lib/api/group_milestones.rb @@ -0,0 +1,85 @@ +module API + class GroupMilestones < Grape::API + include MilestoneResponses + include PaginationParams + + before do + authenticate! + end + + params do + requires :id, type: String, desc: 'The ID of a group' + end + resource :groups, requirements: { id: %r{[^/]+} } do + desc 'Get a list of group milestones' do + success Entities::Milestone + end + params do + use :list_params + end + get ":id/milestones" do + list_milestones_for(user_group) + end + + desc 'Get a single group milestone' do + success Entities::Milestone + end + params do + requires :milestone_id, type: Integer, desc: 'The ID of a group milestone' + end + get ":id/milestones/:milestone_id" do + authorize! :read_group, user_group + + get_milestone_for(user_group) + end + + desc 'Create a new group milestone' do + success Entities::Milestone + end + params do + requires :title, type: String, desc: 'The title of the milestone' + use :optional_params + end + post ":id/milestones" do + authorize! :admin_milestones, user_group + + create_milestone_for(user_group) + end + + desc 'Update an existing group milestone' do + success Entities::Milestone + end + params do + use :update_params + end + put ":id/milestones/:milestone_id" do + authorize! :admin_milestones, user_group + + update_milestone_for(user_group) + end + + desc 'Get all issues for a single group milestone' do + success Entities::IssueBasic + end + params do + requires :milestone_id, type: Integer, desc: 'The ID of a group milestone' + use :pagination + end + get ":id/milestones/:milestone_id/issues" do + milestone_issuables_for(user_group, :issue) + end + + desc 'Get all merge requests for a single group milestone' do + detail 'This feature was introduced in GitLab 9.' + success Entities::MergeRequestBasic + end + params do + requires :milestone_id, type: Integer, desc: 'The ID of a group milestone' + use :pagination + end + get ':id/milestones/:milestone_id/merge_requests' do + milestone_issuables_for(user_group, :merge_request) + end + end + end +end diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 0f4791841d2..57e3e93500f 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -25,6 +25,10 @@ module API initial_current_user != current_user end + def user_group + @group ||= find_group!(params[:id]) + end + def user_project @project ||= find_project!(params[:id]) end diff --git a/lib/api/milestone_responses.rb b/lib/api/milestone_responses.rb new file mode 100644 index 00000000000..ef09d9505d2 --- /dev/null +++ b/lib/api/milestone_responses.rb @@ -0,0 +1,98 @@ +module API + module MilestoneResponses + extend ActiveSupport::Concern + + included do + helpers do + params :optional_params do + optional :description, type: String, desc: 'The description of the milestone' + optional :due_date, type: String, desc: 'The due date of the milestone. The ISO 8601 date format (%Y-%m-%d)' + optional :start_date, type: String, desc: 'The start date of the milestone. The ISO 8601 date format (%Y-%m-%d)' + end + + params :list_params do + optional :state, type: String, values: %w[active closed all], default: 'all', + desc: 'Return "active", "closed", or "all" milestones' + optional :iids, type: Array[Integer], desc: 'The IIDs of the milestones' + optional :search, type: String, desc: 'The search criteria for the title or description of the milestone' + use :pagination + end + + params :update_params do + requires :milestone_id, type: Integer, desc: 'The milestone ID number' + optional :title, type: String, desc: 'The title of the milestone' + optional :state_event, type: String, values: %w[close activate], + desc: 'The state event of the milestone ' + use :optional_params + at_least_one_of :title, :description, :due_date, :state_event + end + + def list_milestones_for(parent) + milestones = parent.milestones + milestones = Milestone.filter_by_state(milestones, params[:state]) + milestones = filter_by_iid(milestones, params[:iids]) if params[:iids].present? + milestones = filter_by_search(milestones, params[:search]) if params[:search] + + present paginate(milestones), with: Entities::Milestone + end + + def get_milestone_for(parent) + milestone = parent.milestones.find(params[:milestone_id]) + present milestone, with: Entities::Milestone + end + + def create_milestone_for(parent) + milestone = ::Milestones::CreateService.new(parent, current_user, declared_params).execute + + if milestone.valid? + present milestone, with: Entities::Milestone + else + render_api_error!("Failed to create milestone #{milestone.errors.messages}", 400) + end + end + + def update_milestone_for(parent) + milestone = parent.milestones.find(params.delete(:milestone_id)) + + milestone_params = declared_params(include_missing: false) + milestone = ::Milestones::UpdateService.new(parent, current_user, milestone_params).execute(milestone) + + if milestone.valid? + present milestone, with: Entities::Milestone + else + render_api_error!("Failed to update milestone #{milestone.errors.messages}", 400) + end + end + + def milestone_issuables_for(parent, type) + milestone = parent.milestones.find(params[:milestone_id]) + + finder_klass, entity = get_finder_and_entity(type) + + params = build_finder_params(milestone, parent) + + issuables = finder_klass.new(current_user, params).execute + present paginate(issuables), with: entity, current_user: current_user + end + + def build_finder_params(milestone, parent) + finder_params = { milestone_title: milestone.title, sort: 'label_priority' } + + if parent.is_a?(Group) + finder_params.merge(group_id: parent.id) + else + finder_params.merge(project_id: parent.id) + end + end + + def get_finder_and_entity(type) + if type == :issue + [IssuesFinder, Entities::IssueBasic] + else + [MergeRequestsFinder, Entities::MergeRequestBasic] + end + end + end + end + end +end diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb deleted file mode 100644 index 3541d3c95fb..00000000000 --- a/lib/api/milestones.rb +++ /dev/null @@ -1,154 +0,0 @@ -module API - class Milestones < Grape::API - include PaginationParams - - before { authenticate! } - - helpers do - def filter_milestones_state(milestones, state) - case state - when 'active' then milestones.active - when 'closed' then milestones.closed - else milestones - end - end - - params :optional_params do - optional :description, type: String, desc: 'The description of the milestone' - optional :due_date, type: String, desc: 'The due date of the milestone. The ISO 8601 date format (%Y-%m-%d)' - optional :start_date, type: String, desc: 'The start date of the milestone. The ISO 8601 date format (%Y-%m-%d)' - end - end - - params do - requires :id, type: String, desc: 'The ID of a project' - end - resource :projects, requirements: { id: %r{[^/]+} } do - desc 'Get a list of project milestones' do - success Entities::Milestone - end - params do - optional :state, type: String, values: %w[active closed all], default: 'all', - desc: 'Return "active", "closed", or "all" milestones' - optional :iids, type: Array[Integer], desc: 'The IIDs of the milestones' - optional :search, type: String, desc: 'The search criteria for the title or description of the milestone' - use :pagination - end - get ":id/milestones" do - authorize! :read_milestone, user_project - - milestones = user_project.milestones - milestones = filter_milestones_state(milestones, params[:state]) - milestones = filter_by_iid(milestones, params[:iids]) if params[:iids].present? - milestones = filter_by_search(milestones, params[:search]) if params[:search] - - present paginate(milestones), with: Entities::Milestone - end - - desc 'Get a single project milestone' do - success Entities::Milestone - end - params do - requires :milestone_id, type: Integer, desc: 'The ID of a project milestone' - end - get ":id/milestones/:milestone_id" do - authorize! :read_milestone, user_project - - milestone = user_project.milestones.find(params[:milestone_id]) - present milestone, with: Entities::Milestone - end - - desc 'Create a new project milestone' do - success Entities::Milestone - end - params do - requires :title, type: String, desc: 'The title of the milestone' - use :optional_params - end - post ":id/milestones" do - authorize! :admin_milestone, user_project - - milestone = ::Milestones::CreateService.new(user_project, current_user, declared_params).execute - - if milestone.valid? - present milestone, with: Entities::Milestone - else - render_api_error!("Failed to create milestone #{milestone.errors.messages}", 400) - end - end - - desc 'Update an existing project milestone' do - success Entities::Milestone - end - params do - requires :milestone_id, type: Integer, desc: 'The ID of a project milestone' - optional :title, type: String, desc: 'The title of the milestone' - optional :state_event, type: String, values: %w[close activate], - desc: 'The state event of the milestone ' - use :optional_params - at_least_one_of :title, :description, :due_date, :state_event - end - put ":id/milestones/:milestone_id" do - authorize! :admin_milestone, user_project - milestone = user_project.milestones.find(params.delete(:milestone_id)) - - milestone_params = declared_params(include_missing: false) - milestone = ::Milestones::UpdateService.new(user_project, current_user, milestone_params).execute(milestone) - - if milestone.valid? - present milestone, with: Entities::Milestone - else - render_api_error!("Failed to update milestone #{milestone.errors.messages}", 400) - end - end - - desc 'Get all issues for a single project milestone' do - success Entities::IssueBasic - end - params do - requires :milestone_id, type: Integer, desc: 'The ID of a project milestone' - use :pagination - end - get ":id/milestones/:milestone_id/issues" do - authorize! :read_milestone, user_project - - milestone = user_project.milestones.find(params[:milestone_id]) - - finder_params = { - project_id: user_project.id, - milestone_title: milestone.title, - sort: 'label_priority' - } - - issues = IssuesFinder.new(current_user, finder_params).execute - present paginate(issues), with: Entities::IssueBasic, current_user: current_user, project: user_project - end - - desc 'Get all merge requests for a single project milestone' do - detail 'This feature was introduced in GitLab 9.' - success Entities::MergeRequestBasic - end - params do - requires :milestone_id, type: Integer, desc: 'The ID of a project milestone' - use :pagination - end - get ':id/milestones/:milestone_id/merge_requests' do - authorize! :read_milestone, user_project - - milestone = user_project.milestones.find(params[:milestone_id]) - - finder_params = { - project_id: user_project.id, - milestone_title: milestone.title, - sort: 'label_priority' - } - - merge_requests = MergeRequestsFinder.new(current_user, finder_params).execute - present paginate(merge_requests), - with: Entities::MergeRequestBasic, - current_user: current_user, - project: user_project - end - end - end -end diff --git a/lib/api/project_milestones.rb b/lib/api/project_milestones.rb new file mode 100644 index 00000000000..451998c726a --- /dev/null +++ b/lib/api/project_milestones.rb @@ -0,0 +1,91 @@ +module API + class ProjectMilestones < Grape::API + include PaginationParams + include MilestoneResponses + + before do + authenticate! + end + + params do + requires :id, type: String, desc: 'The ID of a project' + end + resource :projects, requirements: { id: %r{[^/]+} } do + desc 'Get a list of project milestones' do + success Entities::Milestone + end + params do + use :list_params + end + get ":id/milestones" do + authorize! :read_milestone, user_project + + list_milestones_for(user_project) + end + + desc 'Get a single project milestone' do + success Entities::Milestone + end + params do + requires :milestone_id, type: Integer, desc: 'The ID of a project milestone' + end + get ":id/milestones/:milestone_id" do + authorize! :read_milestone, user_project + + get_milestone_for(user_project) + end + + desc 'Create a new project milestone' do + success Entities::Milestone + end + params do + requires :title, type: String, desc: 'The title of the milestone' + use :optional_params + end + post ":id/milestones" do + authorize! :admin_milestone, user_project + + create_milestone_for(user_project) + end + + desc 'Update an existing project milestone' do + success Entities::Milestone + end + params do + use :update_params + end + put ":id/milestones/:milestone_id" do + authorize! :admin_milestone, user_project + + update_milestone_for(user_project) + end + + desc 'Get all issues for a single project milestone' do + success Entities::IssueBasic + end + params do + requires :milestone_id, type: Integer, desc: 'The ID of a project milestone' + use :pagination + end + get ":id/milestones/:milestone_id/issues" do + authorize! :read_milestone, user_project + + milestone_issuables_for(user_project, :issue) + end + + desc 'Get all merge requests for a single project milestone' do + detail 'This feature was introduced in GitLab 9.' + success Entities::MergeRequestBasic + end + params do + requires :milestone_id, type: Integer, desc: 'The ID of a project milestone' + use :pagination + end + get ':id/milestones/:milestone_id/merge_requests' do + authorize! :read_milestone, user_project + + milestone_issuables_for(user_project, :merge_request) + end + end + end +end diff --git a/spec/requests/api/group_milestones_spec.rb b/spec/requests/api/group_milestones_spec.rb new file mode 100644 index 00000000000..9b24658771f --- /dev/null +++ b/spec/requests/api/group_milestones_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe API::GroupMilestones do + let(:user) { create(:user) } + let(:group) { create(:group, :private) } + let(:project) { create(:empty_project, namespace: group) } + let!(:group_member) { create(:group_member, group: group, user: user) } + let!(:closed_milestone) { create(:closed_milestone, group: group, title: 'version1', description: 'closed milestone') } + let!(:milestone) { create(:milestone, group: group, title: 'version2', description: 'open milestone') } + + it_behaves_like 'group and project milestones', "/groups/:id/milestones" do + let(:route) { "/groups/#{group.id}/milestones" } + end + + def setup_for_group + context_group.update(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + context_group.add_developer(user) + public_project.update(namespace: context_group) + context_group.reload + end +end diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb deleted file mode 100644 index ab5ea3e8f2c..00000000000 --- a/spec/requests/api/milestones_spec.rb +++ /dev/null @@ -1,385 +0,0 @@ -require 'spec_helper' - -describe API::Milestones do - let(:user) { create(:user) } - let!(:project) { create(:empty_project, namespace: user.namespace ) } - let!(:closed_milestone) { create(:closed_milestone, project: project, title: 'version1', description: 'closed milestone') } - let!(:milestone) { create(:milestone, project: project, title: 'version2', description: 'open milestone') } - let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) } - let(:label_2) { create(:label, title: 'label_2', project: project, priority: 2) } - let(:label_3) { create(:label, title: 'label_3', project: project) } - - before do - project.team << [user, :developer] - end - - describe 'GET /projects/:id/milestones' do - it 'returns project milestones' do - get api("/projects/#{project.id}/milestones", user) - - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.first['title']).to eq(milestone.title) - end - - it 'returns a 401 error if user not authenticated' do - get api("/projects/#{project.id}/milestones") - - expect(response).to have_http_status(401) - end - - it 'returns an array of active milestones' do - get api("/projects/#{project.id}/milestones?state=active", user) - - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) - expect(json_response.first['id']).to eq(milestone.id) - end - - it 'returns an array of closed milestones' do - get api("/projects/#{project.id}/milestones?state=closed", user) - - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(1) - expect(json_response.first['id']).to eq(closed_milestone.id) - end - - it 'returns an array of milestones specified by iids' do - other_milestone = create(:milestone, project: project) - - get api("/projects/#{project.id}/milestones", user), iids: [closed_milestone.iid, other_milestone.iid] - - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) - expect(json_response.map{ |m| m['id'] }).to match_array([closed_milestone.id, other_milestone.id]) - end - - it 'does not return any milestone if none found' do - get api("/projects/#{project.id}/milestones", user), iids: [Milestone.maximum(:iid).succ] - - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.length).to eq(0) - end - end - - describe 'GET /projects/:id/milestones/:milestone_id' do - it 'returns a project milestone by id' do - get api("/projects/#{project.id}/milestones/#{milestone.id}", user) - - expect(response).to have_http_status(200) - expect(json_response['title']).to eq(milestone.title) - expect(json_response['iid']).to eq(milestone.iid) - end - - it 'returns a project milestone by iids array' do - get api("/projects/#{project.id}/milestones?iids=#{closed_milestone.iid}", user) - - expect(response.status).to eq 200 - expect(response).to include_pagination_headers - expect(json_response.size).to eq(1) - expect(json_response.size).to eq(1) - expect(json_response.first['title']).to eq closed_milestone.title - expect(json_response.first['id']).to eq closed_milestone.id - end - - it 'returns a project milestone by searching for title' do - get api("/projects/#{project.id}/milestones", user), search: 'version2' - - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response.size).to eq(1) - expect(json_response.first['title']).to eq milestone.title - expect(json_response.first['id']).to eq milestone.id - end - - it 'returns a project milestones by searching for description' do - get api("/projects/#{project.id}/milestones", user), search: 'open' - - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response.size).to eq(1) - expect(json_response.first['title']).to eq milestone.title - expect(json_response.first['id']).to eq milestone.id - end - end - - describe 'GET /projects/:id/milestones/:milestone_id' do - it 'returns a project milestone by id' do - get api("/projects/#{project.id}/milestones/#{milestone.id}", user) - - expect(response).to have_http_status(200) - expect(json_response['title']).to eq(milestone.title) - expect(json_response['iid']).to eq(milestone.iid) - end - - it 'returns 401 error if user not authenticated' do - get api("/projects/#{project.id}/milestones/#{milestone.id}") - - expect(response).to have_http_status(401) - end - - it 'returns a 404 error if milestone id not found' do - get api("/projects/#{project.id}/milestones/1234", user) - - expect(response).to have_http_status(404) - end - end - - describe 'POST /projects/:id/milestones' do - it 'creates a new project milestone' do - post api("/projects/#{project.id}/milestones", user), title: 'new milestone' - - expect(response).to have_http_status(201) - expect(json_response['title']).to eq('new milestone') - expect(json_response['description']).to be_nil - end - - it 'creates a new project milestone with description and dates' do - post api("/projects/#{project.id}/milestones", user), - title: 'new milestone', description: 'release', due_date: '2013-03-02', start_date: '2013-02-02' - - expect(response).to have_http_status(201) - expect(json_response['description']).to eq('release') - expect(json_response['due_date']).to eq('2013-03-02') - expect(json_response['start_date']).to eq('2013-02-02') - end - - it 'returns a 400 error if title is missing' do - post api("/projects/#{project.id}/milestones", user) - - expect(response).to have_http_status(400) - end - - it 'returns a 400 error if params are invalid (duplicate title)' do - post api("/projects/#{project.id}/milestones", user), - title: milestone.title, description: 'release', due_date: '2013-03-02' - - expect(response).to have_http_status(400) - end - - it 'creates a new project with reserved html characters' do - post api("/projects/#{project.id}/milestones", user), title: 'foo & bar 1.1 -> 2.2' - - expect(response).to have_http_status(201) - expect(json_response['title']).to eq('foo & bar 1.1 -> 2.2') - expect(json_response['description']).to be_nil - end - end - - describe 'PUT /projects/:id/milestones/:milestone_id' do - it 'updates a project milestone' do - put api("/projects/#{project.id}/milestones/#{milestone.id}", user), - title: 'updated title' - - expect(response).to have_http_status(200) - expect(json_response['title']).to eq('updated title') - end - - it 'removes a due date if nil is passed' do - milestone.update!(due_date: "2016-08-05") - - put api("/projects/#{project.id}/milestones/#{milestone.id}", user), due_date: nil - - expect(response).to have_http_status(200) - expect(json_response['due_date']).to be_nil - end - - it 'returns a 404 error if milestone id not found' do - put api("/projects/#{project.id}/milestones/1234", user), - title: 'updated title' - - expect(response).to have_http_status(404) - end - end - - describe 'PUT /projects/:id/milestones/:milestone_id to close milestone' do - it 'updates a project milestone' do - put api("/projects/#{project.id}/milestones/#{milestone.id}", user), - state_event: 'close' - expect(response).to have_http_status(200) - - expect(json_response['state']).to eq('closed') - end - end - - describe 'PUT /projects/:id/milestones/:milestone_id to test observer on close' do - it 'creates an activity event when an milestone is closed' do - expect(Event).to receive(:create) - - put api("/projects/#{project.id}/milestones/#{milestone.id}", user), - state_event: 'close' - end - end - - describe 'GET /projects/:id/milestones/:milestone_id/issues' do - before do - milestone.issues << create(:issue, project: project) - end - it 'returns project issues for a particular milestone' do - get api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user) - - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.first['milestone']['title']).to eq(milestone.title) - end - - it 'returns project issues sorted by label priority' do - issue_1 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_3]) - issue_2 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_1]) - issue_3 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_2]) - - get api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user) - - expect(json_response.first['id']).to eq(issue_2.id) - expect(json_response.second['id']).to eq(issue_3.id) - expect(json_response.third['id']).to eq(issue_1.id) - end - - it 'matches V4 response schema for a list of issues' do - get api("/projects/#{project.id}/milestones/#{milestone.id}/issues", user) - - expect(response).to have_http_status(200) - expect(response).to match_response_schema('public_api/v4/issues') - end - - it 'returns a 401 error if user not authenticated' do - get api("/projects/#{project.id}/milestones/#{milestone.id}/issues") - - expect(response).to have_http_status(401) - end - - describe 'confidential issues' do - let(:public_project) { create(:empty_project, :public) } - let(:milestone) { create(:milestone, project: public_project) } - let(:issue) { create(:issue, project: public_project) } - let(:confidential_issue) { create(:issue, confidential: true, project: public_project) } - - before do - public_project.team << [user, :developer] - milestone.issues << issue << confidential_issue - end - - it 'returns confidential issues to team members' do - get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", user) - - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.size).to eq(2) - expect(json_response.map { |issue| issue['id'] }).to include(issue.id, confidential_issue.id) - end - - it 'does not return confidential issues to team members with guest role' do - member = create(:user) - project.team << [member, :guest] - - get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", member) - - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.size).to eq(1) - expect(json_response.map { |issue| issue['id'] }).to include(issue.id) - end - - it 'does not return confidential issues to regular users' do - get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", create(:user)) - - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.size).to eq(1) - expect(json_response.map { |issue| issue['id'] }).to include(issue.id) - end - - it 'returns issues ordered by label priority' do - issue.labels << label_2 - confidential_issue.labels << label_1 - - get api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", user) - - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.size).to eq(2) - expect(json_response.first['id']).to eq(confidential_issue.id) - expect(json_response.second['id']).to eq(issue.id) - end - end - end - - describe 'GET /projects/:id/milestones/:milestone_id/merge_requests' do - let(:merge_request) { create(:merge_request, source_project: project) } - let(:another_merge_request) { create(:merge_request, :simple, source_project: project) } - - before do - milestone.merge_requests << merge_request - end - - it 'returns project merge_requests for a particular milestone' do - # eager-load another_merge_request - another_merge_request - get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", user) - - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.size).to eq(1) - expect(json_response.first['title']).to eq(merge_request.title) - expect(json_response.first['milestone']['title']).to eq(milestone.title) - end - - it 'returns project merge_requests sorted by label priority' do - merge_request_1 = create(:labeled_merge_request, source_branch: 'branch_1', source_project: project, milestone: milestone, labels: [label_2]) - merge_request_2 = create(:labeled_merge_request, source_branch: 'branch_2', source_project: project, milestone: milestone, labels: [label_1]) - merge_request_3 = create(:labeled_merge_request, source_branch: 'branch_3', source_project: project, milestone: milestone, labels: [label_3]) - - get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", user) - - expect(json_response.first['id']).to eq(merge_request_2.id) - expect(json_response.second['id']).to eq(merge_request_1.id) - expect(json_response.third['id']).to eq(merge_request_3.id) - end - - it 'returns a 404 error if milestone id not found' do - get api("/projects/#{project.id}/milestones/1234/merge_requests", user) - - expect(response).to have_http_status(404) - end - - it 'returns a 404 if the user has no access to the milestone' do - new_user = create :user - get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", new_user) - - expect(response).to have_http_status(404) - end - - it 'returns a 401 error if user not authenticated' do - get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests") - - expect(response).to have_http_status(401) - end - - it 'returns merge_requests ordered by position asc' do - milestone.merge_requests << another_merge_request - another_merge_request.labels << label_1 - merge_request.labels << label_2 - - get api("/projects/#{project.id}/milestones/#{milestone.id}/merge_requests", user) - - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.size).to eq(2) - expect(json_response.first['id']).to eq(another_merge_request.id) - expect(json_response.second['id']).to eq(merge_request.id) - end - end -end diff --git a/spec/requests/api/project_milestones_spec.rb b/spec/requests/api/project_milestones_spec.rb new file mode 100644 index 00000000000..fe8fdbfd7e4 --- /dev/null +++ b/spec/requests/api/project_milestones_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +describe API::ProjectMilestones do + let(:user) { create(:user) } + let!(:project) { create(:empty_project, namespace: user.namespace ) } + let!(:closed_milestone) { create(:closed_milestone, project: project, title: 'version1', description: 'closed milestone') } + let!(:milestone) { create(:milestone, project: project, title: 'version2', description: 'open milestone') } + + before do + project.team << [user, :developer] + end + + it_behaves_like 'group and project milestones', "/projects/:id/milestones" do + let(:route) { "/projects/#{project.id}/milestones" } + end + + describe 'PUT /projects/:id/milestones/:milestone_id to test observer on close' do + it 'creates an activity event when an milestone is closed' do + expect(Event).to receive(:create) + + put api("/projects/#{project.id}/milestones/#{milestone.id}", user), + state_event: 'close' + end + end +end diff --git a/spec/support/api/milestones_shared_examples.rb b/spec/support/api/milestones_shared_examples.rb new file mode 100644 index 00000000000..480e7d5151f --- /dev/null +++ b/spec/support/api/milestones_shared_examples.rb @@ -0,0 +1,383 @@ +shared_examples_for 'group and project milestones' do |route_definition| + let(:resource_route) { "#{route}/#{milestone.id}" } + let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) } + let(:label_2) { create(:label, title: 'label_2', project: project, priority: 2) } + let(:label_3) { create(:label, title: 'label_3', project: project) } + let(:merge_request) { create(:merge_request, source_project: project) } + let(:another_merge_request) { create(:merge_request, :simple, source_project: project) } + + describe "GET #{route_definition}" do + it 'returns milestones list' do + get api(route, user) + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.first['title']).to eq(milestone.title) + end + + it 'returns a 401 error if user not authenticated' do + get api(route) + + expect(response).to have_http_status(401) + end + + it 'returns an array of active milestones' do + get api("#{route}/?state=active", user) + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + expect(json_response.first['id']).to eq(milestone.id) + end + + it 'returns an array of closed milestones' do + get api("#{route}/?state=closed", user) + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + expect(json_response.first['id']).to eq(closed_milestone.id) + end + + it 'returns an array of milestones specified by iids' do + other_milestone = create(:milestone, project: try(:project), group: try(:group)) + + get api(route, user), iids: [closed_milestone.iid, other_milestone.iid] + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(2) + expect(json_response.map{ |m| m['id'] }).to match_array([closed_milestone.id, other_milestone.id]) + end + + it 'does not return any milestone if none found' do + get api(route, user), iids: [Milestone.maximum(:iid).succ] + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(0) + end + + it 'returns a milestone by iids array' do + get api("#{route}?iids=#{closed_milestone.iid}", user) + + expect(response.status).to eq 200 + expect(response).to include_pagination_headers + expect(json_response.size).to eq(1) + expect(json_response.size).to eq(1) + expect(json_response.first['title']).to eq closed_milestone.title + expect(json_response.first['id']).to eq closed_milestone.id + end + + it 'returns a milestone by searching for title' do + get api(route, user), search: 'version2' + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response.size).to eq(1) + expect(json_response.first['title']).to eq milestone.title + expect(json_response.first['id']).to eq milestone.id + end + + it 'returns a milestones by searching for description' do + get api(route, user), search: 'open' + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response.size).to eq(1) + expect(json_response.first['title']).to eq milestone.title + expect(json_response.first['id']).to eq milestone.id + end + end + + describe "GET #{route_definition}/:milestone_id" do + it 'returns a milestone by id' do + get api(resource_route, user) + + expect(response).to have_http_status(200) + expect(json_response['title']).to eq(milestone.title) + expect(json_response['iid']).to eq(milestone.iid) + end + + it 'returns a milestone by id' do + get api(resource_route, user) + + expect(response).to have_http_status(200) + expect(json_response['title']).to eq(milestone.title) + expect(json_response['iid']).to eq(milestone.iid) + end + + it 'returns 401 error if user not authenticated' do + get api(resource_route) + + expect(response).to have_http_status(401) + end + + it 'returns a 404 error if milestone id not found' do + get api("#{route}/1234", user) + + expect(response).to have_http_status(404) + end + end + + describe "POST #{route_definition}" do + it 'creates a new milestone' do + post api(route, user), title: 'new milestone' + + expect(response).to have_http_status(201) + expect(json_response['title']).to eq('new milestone') + expect(json_response['description']).to be_nil + end + + it 'creates a new milestone with description and dates' do + post api(route, user), + title: 'new milestone', description: 'release', due_date: '2013-03-02', start_date: '2013-02-02' + + expect(response).to have_http_status(201) + expect(json_response['description']).to eq('release') + expect(json_response['due_date']).to eq('2013-03-02') + expect(json_response['start_date']).to eq('2013-02-02') + end + + it 'returns a 400 error if title is missing' do + post api(route, user) + + expect(response).to have_http_status(400) + end + + it 'returns a 400 error if params are invalid (duplicate title)' do + post api(route, user), + title: milestone.title, description: 'release', due_date: '2013-03-02' + + expect(response).to have_http_status(400) + end + + it 'creates a new milestone with reserved html characters' do + post api(route, user), title: 'foo & bar 1.1 -> 2.2' + + expect(response).to have_http_status(201) + expect(json_response['title']).to eq('foo & bar 1.1 -> 2.2') + expect(json_response['description']).to be_nil + end + end + + describe "PUT #{route_definition}/:milestone_id" do + it 'updates a milestone' do + put api(resource_route, user), + title: 'updated title' + + expect(response).to have_http_status(200) + expect(json_response['title']).to eq('updated title') + end + + it 'removes a due date if nil is passed' do + milestone.update!(due_date: "2016-08-05") + + put api(resource_route, user), due_date: nil + + expect(response).to have_http_status(200) + expect(json_response['due_date']).to be_nil + end + + it 'returns a 404 error if milestone id not found' do + put api("#{route}/1234", user), + title: 'updated title' + + expect(response).to have_http_status(404) + end + + it 'closes milestone' do + put api(resource_route, user), + state_event: 'close' + expect(response).to have_http_status(200) + + expect(json_response['state']).to eq('closed') + end + end + + describe "GET #{route_definition}/:milestone_id/issues" do + let(:issues_route) { "#{route}/#{milestone.id}/issues" } + + before do + milestone.issues << create(:issue, project: project) + end + it 'returns issues for a particular milestone' do + get api(issues_route, user) + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.first['milestone']['title']).to eq(milestone.title) + end + + it 'returns issues sorted by label priority' do + issue_1 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_3]) + issue_2 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_1]) + issue_3 = create(:labeled_issue, project: project, milestone: milestone, labels: [label_2]) + + get api(issues_route, user) + + expect(json_response.first['id']).to eq(issue_2.id) + expect(json_response.second['id']).to eq(issue_3.id) + expect(json_response.third['id']).to eq(issue_1.id) + end + + it 'matches V4 response schema for a list of issues' do + get api(issues_route, user) + + expect(response).to have_http_status(200) + expect(response).to match_response_schema('public_api/v4/issues') + end + + it 'returns a 401 error if user not authenticated' do + get api(issues_route) + + expect(response).to have_http_status(401) + end + + describe 'confidential issues' do + let!(:public_project) { create(:empty_project, :public) } + let!(:context_group) { try(:group) } + let!(:milestone) do + context_group ? create(:milestone, group: context_group) : create(:milestone, project: public_project) + end + let!(:issue) { create(:issue, project: public_project) } + let!(:confidential_issue) { create(:issue, confidential: true, project: public_project) } + let!(:issues_route) do + if context_group + "#{route}/#{milestone.id}/issues" + else + "/projects/#{public_project.id}/milestones/#{milestone.id}/issues" + end + end + + before do + # Add public project to the group in context + setup_for_group if context_group + + public_project.team << [user, :developer] + milestone.issues << issue << confidential_issue + end + + it 'returns confidential issues to team members' do + get api(issues_route, user) + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + # 2 for projects, 3 for group(which has another project with an issue) + expect(json_response.size).to be_between(2, 3) + expect(json_response.map { |issue| issue['id'] }).to include(issue.id, confidential_issue.id) + end + + it 'does not return confidential issues to team members with guest role' do + member = create(:user) + public_project.team << [member, :guest] + + get api(issues_route, member) + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.size).to eq(1) + expect(json_response.map { |issue| issue['id'] }).to include(issue.id) + end + + it 'does not return confidential issues to regular users' do + get api(issues_route, create(:user)) + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.size).to eq(1) + expect(json_response.map { |issue| issue['id'] }).to include(issue.id) + end + + it 'returns issues ordered by label priority' do + issue.labels << label_2 + confidential_issue.labels << label_1 + + get api(issues_route, user) + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + # 2 for projects, 3 for group(which has another project with an issue) + expect(json_response.size).to be_between(2, 3) + expect(json_response.first['id']).to eq(confidential_issue.id) + expect(json_response.second['id']).to eq(issue.id) + end + end + end + + describe "GET #{route_definition}/:milestone_id/merge_requests" do + let(:merge_requests_route) { "#{route}/#{milestone.id}/merge_requests" } + + before do + milestone.merge_requests << merge_request + end + + it 'returns merge_requests for a particular milestone' do + # eager-load another_merge_request + another_merge_request + get api(merge_requests_route, user) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq(1) + expect(json_response.first['title']).to eq(merge_request.title) + expect(json_response.first['milestone']['title']).to eq(milestone.title) + end + + it 'returns merge_requests sorted by label priority' do + merge_request_1 = create(:labeled_merge_request, source_branch: 'branch_1', source_project: project, milestone: milestone, labels: [label_2]) + merge_request_2 = create(:labeled_merge_request, source_branch: 'branch_2', source_project: project, milestone: milestone, labels: [label_1]) + merge_request_3 = create(:labeled_merge_request, source_branch: 'branch_3', source_project: project, milestone: milestone, labels: [label_3]) + + get api(merge_requests_route, user) + + expect(json_response.first['id']).to eq(merge_request_2.id) + expect(json_response.second['id']).to eq(merge_request_1.id) + expect(json_response.third['id']).to eq(merge_request_3.id) + end + + it 'returns a 404 error if milestone id not found' do + not_found_route = "#{route}/1234/merge_requests" + + get api(not_found_route, user) + + expect(response).to have_http_status(404) + end + + it 'returns a 404 if the user has no access to the milestone' do + new_user = create :user + get api(merge_requests_route, new_user) + + expect(response).to have_http_status(404) + end + + it 'returns a 401 error if user not authenticated' do + get api(merge_requests_route) + + expect(response).to have_http_status(401) + end + + it 'returns merge_requests ordered by position asc' do + milestone.merge_requests << another_merge_request + another_merge_request.labels << label_1 + merge_request.labels << label_2 + + get api(merge_requests_route, user) + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.size).to eq(2) + expect(json_response.first['id']).to eq(another_merge_request.id) + expect(json_response.second['id']).to eq(merge_request.id) + end + end +end -- cgit v1.2.1 From e4391c7190fcebd37e49db447b22b1081dca9741 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Fri, 21 Jul 2017 18:45:12 +0100 Subject: Backport changes from https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2328 --- app/controllers/admin/application_settings_controller.rb | 4 ++-- app/controllers/projects/application_controller.rb | 1 + app/controllers/projects_controller.rb | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index c1bc4c0d675..4c0f7556894 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -76,11 +76,11 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController params.delete(:domain_blacklist_raw) if params[:domain_blacklist_file] params.require(:application_setting).permit( - application_setting_params_ce + application_setting_params_attributes ) end - def application_setting_params_ce + def application_setting_params_attributes [ :admin_notification_email, :after_sign_out_path, diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb index 95de3a44641..221e01b415a 100644 --- a/app/controllers/projects/application_controller.rb +++ b/app/controllers/projects/application_controller.rb @@ -22,6 +22,7 @@ class Projects::ApplicationController < ApplicationController def project return @project if @project + return nil unless params[:project_id] || params[:id] path = File.join(params[:namespace_id], params[:project_id] || params[:id]) auth_proc = ->(project) { !project.pending_delete? } diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index c769693255c..2d7cbd4614e 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -296,10 +296,10 @@ class ProjectsController < Projects::ApplicationController def project_params params.require(:project) - .permit(project_params_ce) + .permit(project_params_attributes) end - def project_params_ce + def project_params_attributes [ :avatar, :build_allow_git_fetch, -- cgit v1.2.1 From c10943d9cc1c00c3464f0863203289ce7a608f40 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 21 Jul 2017 17:07:59 -0400 Subject: Create guest users only when necessary rather than for every spec These are two examples of a top-level `before` block doing too much. Only specific specs cared about these guest users, but we were creating them and their `ProjectMember` records for every single spec that ran. --- spec/features/explore/new_menu_spec.rb | 17 +++++++++-------- .../issuable_slash_commands_shared_examples.rb | 19 +++++++++++++++---- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/spec/features/explore/new_menu_spec.rb b/spec/features/explore/new_menu_spec.rb index 7dd69f550ac..e51d527bdf9 100644 --- a/spec/features/explore/new_menu_spec.rb +++ b/spec/features/explore/new_menu_spec.rb @@ -1,17 +1,13 @@ require 'spec_helper' feature 'Top Plus Menu', feature: true, js: true do - let(:user) { create :user } - let(:guest_user) { create :user} + let(:user) { create(:user) } let(:group) { create(:group) } let(:project) { create(:project, :repository, creator: user, namespace: user.namespace) } let(:public_project) { create(:project, :public) } before do group.add_owner(user) - group.add_guest(guest_user) - - project.add_guest(guest_user) end context 'used by full user' do @@ -39,7 +35,7 @@ feature 'Top Plus Menu', feature: true, js: true do scenario 'click on New snippet shows new snippet page' do visit root_dashboard_path - + click_topmenuitem("New snippet") expect(page).to have_content('New Snippet') @@ -102,7 +98,12 @@ feature 'Top Plus Menu', feature: true, js: true do end context 'used by guest user' do + let(:guest_user) { create(:user) } + before do + group.add_guest(guest_user) + project.add_guest(guest_user) + sign_in(guest_user) end @@ -153,7 +154,7 @@ feature 'Top Plus Menu', feature: true, js: true do scenario 'has no New project for group menu item' do visit group_path(group) - + expect(find('.header-new.dropdown')).not_to have_selector('.header-new-group-project') end end @@ -168,5 +169,5 @@ feature 'Top Plus Menu', feature: true, js: true do def hasnot_topmenuitem(item_name) expect(find('.header-new.dropdown')).not_to have_content(item_name) - end + end end diff --git a/spec/support/features/issuable_slash_commands_shared_examples.rb b/spec/support/features/issuable_slash_commands_shared_examples.rb index 033e338fe61..035428a7d9b 100644 --- a/spec/support/features/issuable_slash_commands_shared_examples.rb +++ b/spec/support/features/issuable_slash_commands_shared_examples.rb @@ -5,8 +5,6 @@ shared_examples 'issuable record that supports quick actions in its description include QuickActionsHelpers let(:master) { create(:user) } - let(:assignee) { create(:user, username: 'bob') } - let(:guest) { create(:user) } let(:project) { create(:project, :public) } let!(:milestone) { create(:milestone, project: project, title: 'ASAP') } let!(:label_bug) { create(:label, project: project, title: 'bug') } @@ -15,8 +13,6 @@ shared_examples 'issuable record that supports quick actions in its description before do project.team << [master, :master] - project.team << [assignee, :developer] - project.team << [guest, :guest] sign_in(master) end @@ -57,6 +53,7 @@ shared_examples 'issuable record that supports quick actions in its description context 'with a note containing commands' do it 'creates a note without the commands and interpret the commands accordingly' do + assignee = create(:user, username: 'bob') write_note("Awesome!\n/assign @bob\n/label ~bug\n/milestone %\"ASAP\"") expect(page).to have_content 'Awesome!' @@ -77,6 +74,7 @@ shared_examples 'issuable record that supports quick actions in its description context 'with a note containing only commands' do it 'does not create a note but interpret the commands accordingly' do + assignee = create(:user, username: 'bob') write_note("/assign @bob\n/label ~bug\n/milestone %\"ASAP\"") expect(page).not_to have_content '/assign @bob' @@ -111,8 +109,12 @@ shared_examples 'issuable record that supports quick actions in its description context "when current user cannot close #{issuable_type}" do before do + guest = create(:user) + project.add_guest(guest) + sign_out(:user) sign_in(guest) + visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) end @@ -146,8 +148,12 @@ shared_examples 'issuable record that supports quick actions in its description context "when current user cannot reopen #{issuable_type}" do before do + guest = create(:user) + project.add_guest(guest) + sign_out(:user) sign_in(guest) + visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) end @@ -176,6 +182,9 @@ shared_examples 'issuable record that supports quick actions in its description context "when current user cannot change title of #{issuable_type}" do before do + guest = create(:user) + project.add_guest(guest) + sign_out(:user) sign_in(guest) visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) @@ -267,6 +276,8 @@ shared_examples 'issuable record that supports quick actions in its description describe "preview of note on #{issuable_type}" do it 'removes quick actions from note and explains them' do + create(:user, username: 'bob') + visit public_send("namespace_project_#{issuable_type}_path", project.namespace, project, issuable) page.within('.js-main-target-form') do -- cgit v1.2.1 From 9408ed7f5a3750dcf589c071a008afce9af56dc6 Mon Sep 17 00:00:00 2001 From: Simon Knox Date: Mon, 17 Jul 2017 15:05:22 +1000 Subject: fix resize bug for title and collapsible nav menus --- app/assets/javascripts/main.js | 8 +------- app/assets/stylesheets/framework/header.scss | 29 ++++++++++++++++++++++++++++ app/views/layouts/header/_new.html.haml | 2 +- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 26c67fb721c..5704625ed2b 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -284,13 +284,7 @@ $(function () { return $container.remove(); // Commit show suppressed diff }); - $('.navbar-toggle').on('click', function () { - $('.header-content .title, .header-content .navbar-sub-nav').toggle(); - $('.header-content .header-logo').toggle(); - $('.header-content .navbar-collapse').toggle(); - $('.js-navbar-toggle-left, .js-navbar-toggle-right, .title-container').toggle(); - return $('.navbar-toggle').toggleClass('active'); - }); + $('.navbar-toggle').on('click', () => $('.header-content').toggleClass('menu-expanded')); // Show/hide comments on diff $body.on('click', '.js-toggle-diff-comments', function (e) { var $this = $(this); diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index 20fb10c28d4..605f4284bb5 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -132,6 +132,22 @@ header { } } + &.navbar-gitlab-new { + .fa-times { + display: none; + } + + .menu-expanded { + .fa-ellipsis-v { + display: none; + } + + .fa-times { + display: block; + } + } + } + .global-dropdown { position: absolute; left: -10px; @@ -171,6 +187,19 @@ header { min-height: $header-height; padding-left: 30px; + &.menu-expanded { + @media (max-width: $screen-xs-max) { + .header-logo, + .title-container { + display: none; + } + + .navbar-collapse { + display: block; + } + } + } + .dropdown-menu { margin-top: -5px; } diff --git a/app/views/layouts/header/_new.html.haml b/app/views/layouts/header/_new.html.haml index 4697d91724b..c0d35c73063 100644 --- a/app/views/layouts/header/_new.html.haml +++ b/app/views/layouts/header/_new.html.haml @@ -81,6 +81,6 @@ %button.navbar-toggle.hidden-sm.hidden-md.hidden-lg{ type: 'button' } %span.sr-only Toggle navigation = icon('ellipsis-v', class: 'js-navbar-toggle-right') - = icon('times', class: 'js-navbar-toggle-left', style: 'display: none;') + = icon('times', class: 'js-navbar-toggle-left') = render 'shared/outdated_browser' -- cgit v1.2.1 From 630254012dbab1cdac178872bae92c609539f782 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Fri, 21 Jul 2017 16:50:39 -0500 Subject: Compress gitlab svg logo --- app/views/shared/_logo_type.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/_logo_type.svg b/app/views/shared/_logo_type.svg index 7e9276a0a83..cb07e2634a9 100644 --- a/app/views/shared/_logo_type.svg +++ b/app/views/shared/_logo_type.svg @@ -1 +1 @@ - + -- cgit v1.2.1 From 7ff9008f3e533f2e0442c7a07ef1c67c119822ea Mon Sep 17 00:00:00 2001 From: Hiroyuki Sato Date: Sun, 23 Jul 2017 21:30:10 +0900 Subject: Change double quotes to single quotes --- spec/models/wiki_page_spec.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 4f462044532..220b70503f0 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -209,17 +209,17 @@ describe WikiPage, models: true do end end - context "with same last commit sha" do - it "returns true" do + context 'with same last commit sha' do + it 'returns true' do last_commit_sha = @page.commit.sha - expect(@page.update("more content", :markdown, nil, last_commit_sha)).to be_truthy + expect(@page.update('more content', :markdown, nil, last_commit_sha)).to be_truthy end end - context "with different last commit sha" do - it "raises exception" do - last_commit_sha = "xxx" - expect { @page.update("more content", :markdown, nil, last_commit_sha) }.to raise_error(WikiPage::PageChangedError) + context 'with different last commit sha' do + it 'raises exception' do + last_commit_sha = 'xxx' + expect { @page.update('more content', :markdown, nil, last_commit_sha) }.to raise_error(WikiPage::PageChangedError) end end end -- cgit v1.2.1 From df65334ecadbc426a535237211a4d8eec53f52c0 Mon Sep 17 00:00:00 2001 From: Hiroyuki Sato Date: Sun, 23 Jul 2017 21:43:32 +0900 Subject: Refactor: use keyword arguments for optional parameters --- app/models/wiki_page.rb | 2 +- app/services/wiki_pages/update_service.rb | 2 +- spec/models/wiki_page_spec.rb | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index fa70b69f02f..12f12674e56 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -192,7 +192,7 @@ class WikiPage # # Returns the String SHA1 of the newly created page # or False if the save was unsuccessful. - def update(new_content = "", format = :markdown, message = nil, last_commit_sha = nil) + def update(new_content, format: :markdown, message: nil, last_commit_sha: nil) @attributes[:content] = new_content @attributes[:format] = format diff --git a/app/services/wiki_pages/update_service.rb b/app/services/wiki_pages/update_service.rb index 1046bb3be01..c628e6781af 100644 --- a/app/services/wiki_pages/update_service.rb +++ b/app/services/wiki_pages/update_service.rb @@ -1,7 +1,7 @@ module WikiPages class UpdateService < WikiPages::BaseService def execute(page) - if page.update(@params[:content], @params[:format], @params[:message], @params[:last_commit_sha]) + if page.update(@params[:content], format: @params[:format], message: @params[:message], last_commit_sha: @params[:last_commit_sha]) execute_hooks(page, 'update') end diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 220b70503f0..732a32684e8 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -212,14 +212,14 @@ describe WikiPage, models: true do context 'with same last commit sha' do it 'returns true' do last_commit_sha = @page.commit.sha - expect(@page.update('more content', :markdown, nil, last_commit_sha)).to be_truthy + expect(@page.update('more content', last_commit_sha: last_commit_sha)).to be_truthy end end context 'with different last commit sha' do it 'raises exception' do last_commit_sha = 'xxx' - expect { @page.update('more content', :markdown, nil, last_commit_sha) }.to raise_error(WikiPage::PageChangedError) + expect { @page.update('more content', last_commit_sha: last_commit_sha) }.to raise_error(WikiPage::PageChangedError) end end end -- cgit v1.2.1 From 3acf790f7cb982e27b70322106b636a2b80490e8 Mon Sep 17 00:00:00 2001 From: Hiroyuki Sato Date: Sun, 23 Jul 2017 22:27:20 +0900 Subject: Fix error of spinach test --- features/steps/project/wiki.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/project/wiki.rb b/features/steps/project/wiki.rb index a2f5d2e1515..85e1b8441a3 100644 --- a/features/steps/project/wiki.rb +++ b/features/steps/project/wiki.rb @@ -63,7 +63,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps end step 'That page has two revisions' do - @page.update("new content", :markdown, "second commit") + @page.update("new content", message: "second commit") end step 'I click the History button' do -- cgit v1.2.1 From 1300736850c0a2246b346c31680aae8e2c6baa4c Mon Sep 17 00:00:00 2001 From: Ahmad Sherif Date: Mon, 24 Jul 2017 07:07:20 +0200 Subject: Use a unique feature name for Workhorse send blob migration --- lib/gitlab/workhorse.rb | 2 +- spec/lib/gitlab/workhorse_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb index 916ef365d78..5dd8a38fea2 100644 --- a/lib/gitlab/workhorse.rb +++ b/lib/gitlab/workhorse.rb @@ -62,7 +62,7 @@ module Gitlab end def send_git_blob(repository, blob) - params = if Gitlab::GitalyClient.feature_enabled?(:project_raw_show) + params = if Gitlab::GitalyClient.feature_enabled?(:workhorse_raw_show) { 'GitalyServer' => gitaly_server_hash(repository), 'GetBlobRequest' => { diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb index 124f66a6e0e..7b39441e76e 100644 --- a/spec/lib/gitlab/workhorse_spec.rb +++ b/spec/lib/gitlab/workhorse_spec.rb @@ -325,7 +325,7 @@ describe Gitlab::Workhorse, lib: true do subject { described_class.send_git_blob(repository, blob) } - context 'when Gitaly project_raw_show feature is enabled' do + context 'when Gitaly workhorse_raw_show feature is enabled' do it 'sets the header correctly' do key, command, params = decode_workhorse_header(subject) @@ -345,7 +345,7 @@ describe Gitlab::Workhorse, lib: true do end end - context 'when Gitaly project_raw_show feature is disabled', skip_gitaly_mock: true do + context 'when Gitaly workhorse_raw_show feature is disabled', skip_gitaly_mock: true do it 'sets the header correctly' do key, command, params = decode_workhorse_header(subject) -- cgit v1.2.1 From 2fa22a07296223c1239bfab94654487cca222097 Mon Sep 17 00:00:00 2001 From: Jarka Kadlecova Date: Tue, 13 Jun 2017 10:25:25 +0200 Subject: Associate Issues tab only with internal issues tracker --- app/controllers/projects/issues_controller.rb | 13 +++-- app/policies/project_policy.rb | 3 -- changelogs/unreleased/33097-issue-tracker.yml | 4 ++ .../controllers/projects/issues_controller_spec.rb | 59 +++++++++++++++------- spec/features/projects/features_visibility_spec.rb | 19 +++++-- spec/policies/project_policy_spec.rb | 24 +++++++++ 6 files changed, 91 insertions(+), 31 deletions(-) create mode 100644 changelogs/unreleased/33097-issue-tracker.yml diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 0ac9da2ff0f..5b0eeac2477 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -8,7 +8,6 @@ class Projects::IssuesController < Projects::ApplicationController prepend_before_action :authenticate_user!, only: [:new] - before_action :redirect_to_external_issue_tracker, only: [:index, :new] before_action :check_issues_available! before_action :issue, except: [:index, :new, :create, :bulk_update] @@ -243,19 +242,19 @@ class Projects::IssuesController < Projects::ApplicationController end def authorize_update_issue! - return render_404 unless can?(current_user, :update_issue, @issue) + render_404 unless can?(current_user, :update_issue, @issue) end def authorize_admin_issues! - return render_404 unless can?(current_user, :admin_issue, @project) + render_404 unless can?(current_user, :admin_issue, @project) end def authorize_create_merge_request! - return render_404 unless can?(current_user, :push_code, @project) && @issue.can_be_worked_on?(current_user) + render_404 unless can?(current_user, :push_code, @project) && @issue.can_be_worked_on?(current_user) end def check_issues_available! - return render_404 unless @project.feature_available?(:issues, current_user) && @project.default_issues_tracker? + return render_404 unless @project.feature_available?(:issues, current_user) end def redirect_to_external_issue_tracker @@ -270,6 +269,10 @@ class Projects::IssuesController < Projects::ApplicationController end end + def module_enabled + render_404 unless @project.feature_available?(:issues, current_user) + end + def issue_params params.require(:issue).permit(*issue_params_attributes) end diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index 323131c0f7e..d27bbf2948c 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -287,9 +287,6 @@ class ProjectPolicy < BasePolicy prevent :create_issue prevent :update_issue prevent :admin_issue - end - - rule { issues_disabled & default_issues_tracker }.policy do prevent :read_issue end diff --git a/changelogs/unreleased/33097-issue-tracker.yml b/changelogs/unreleased/33097-issue-tracker.yml new file mode 100644 index 00000000000..0b13f7165db --- /dev/null +++ b/changelogs/unreleased/33097-issue-tracker.yml @@ -0,0 +1,4 @@ +--- +title: Associate Issues tab only with internal issues tracker +merge_request: +author: diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 18d0be3c103..e56f5d11daf 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -7,16 +7,30 @@ describe Projects::IssuesController do describe "GET #index" do context 'external issue tracker' do - let!(:service) do - create(:custom_issue_tracker_service, project: project, title: 'Custom Issue Tracker', project_url: 'http://test.com') + before do + sign_in(user) + project.add_developer(user) + create(:jira_service, project: project) end - it 'redirects to the external issue tracker' do - controller.instance_variable_set(:@project, project) + context 'when GitLab issues disabled' do + it 'returns 404 status' do + project.issues_enabled = false + project.save! - get :index, namespace_id: project.namespace, project_id: project + get :index, namespace_id: project.namespace, project_id: project + + expect(response).to have_http_status(404) + end + end + + context 'when GitLab issues enabled' do + it 'renders the "index" template' do + get :index, namespace_id: project.namespace, project_id: project - expect(response).to redirect_to(service.issue_tracker_path) + expect(response).to have_http_status(200) + expect(response).to render_template(:index) + end end end @@ -42,15 +56,7 @@ describe Projects::IssuesController do it "returns 404 when issues are disabled" do project.issues_enabled = false - project.save - - get :index, namespace_id: project.namespace, project_id: project - expect(response).to have_http_status(404) - end - - it "returns 404 when external issue tracker is enabled" do - controller.instance_variable_set(:@project, project) - allow(project).to receive(:default_issues_tracker?).and_return(false) + project.save! get :index, namespace_id: project.namespace, project_id: project expect(response).to have_http_status(404) @@ -148,14 +154,29 @@ describe Projects::IssuesController do before do sign_in(user) project.team << [user, :developer] + + external = double + allow(project).to receive(:external_issue_tracker).and_return(external) end - it 'redirects to the external issue tracker' do - controller.instance_variable_set(:@project, project) + context 'when GitLab issues disabled' do + it 'returns 404 status' do + project.issues_enabled = false + project.save! - get :new, namespace_id: project.namespace, project_id: project + get :new, namespace_id: project.namespace, project_id: project - expect(response).to redirect_to('http://test.com') + expect(response).to have_http_status(404) + end + end + + context 'when GitLab issues enabled' do + it 'renders the "new" template' do + get :new, namespace_id: project.namespace, project_id: project + + expect(response).to have_http_status(200) + expect(response).to render_template(:new) + end end end end diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb index 827e02a58d0..2091c7b79d3 100644 --- a/spec/features/projects/features_visibility_spec.rb +++ b/spec/features/projects/features_visibility_spec.rb @@ -39,14 +39,25 @@ describe 'Edit Project Settings', feature: true do end end - context "When external issue tracker is enabled" do - it "does not hide issues tab" do - project.project_feature.update(issues_access_level: ProjectFeature::DISABLED) + context 'When external issue tracker is enabled and issues enabled on project settings' do + it 'does not hide issues tab' do allow_any_instance_of(Project).to receive(:external_issue_tracker).and_return(JiraService.new) visit project_path(project) - expect(page).to have_selector(".shortcuts-issues") + expect(page).to have_selector('.shortcuts-issues') + end + end + + context 'When external issue tracker is enabled and issues disabled on project settings' do + it 'hides issues tab' do + project.issues_enabled = false + project.save! + allow_any_instance_of(Project).to receive(:external_issue_tracker).and_return(JiraService.new) + + visit namespace_project_path(project.namespace, project) + + expect(page).not_to have_selector('.shortcuts-issues') end end diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index ca435dd0218..4ed788af811 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -103,6 +103,30 @@ describe ProjectPolicy, models: true do end end + context 'issues feature' do + subject { described_class.new(owner, project) } + + context 'when the feature is disabled' do + it 'does not include the issues permissions' do + project.issues_enabled = false + project.save! + + expect_disallowed :read_issue, :create_issue, :update_issue, :admin_issue + end + end + + context 'when the feature is disabled and external tracker configured' do + it 'does not include the issues permissions' do + create(:jira_service, project: project) + + project.issues_enabled = false + project.save! + + expect_disallowed :read_issue, :create_issue, :update_issue, :admin_issue + end + end + end + context 'abilities for non-public projects' do let(:project) { create(:empty_project, namespace: owner.namespace) } -- cgit v1.2.1 From 7bee7b848aab883a6869e1fd2fbb9e66182d2023 Mon Sep 17 00:00:00 2001 From: Jarka Kadlecova Date: Mon, 10 Jul 2017 09:38:42 +0200 Subject: Support both internal and external issue trackers --- app/controllers/projects/issues_controller.rb | 4 - app/helpers/issues_helper.rb | 26 ++- app/models/merge_request.rb | 2 +- app/models/project.rb | 10 +- .../project_services/issue_tracker_service.rb | 8 +- app/models/project_services/jira_service.rb | 2 +- app/services/issues/close_service.rb | 4 +- .../layouts/nav/_new_project_sidebar.html.haml | 6 +- app/views/layouts/nav/_project.html.haml | 6 +- app/views/projects/merge_requests/index.html.haml | 2 +- app/views/shared/_mr_head.html.haml | 2 +- lib/api/entities.rb | 2 +- lib/api/merge_requests.rb | 17 +- lib/banzai/filter/issue_reference_filter.rb | 2 +- .../reference_parser/external_issue_parser.rb | 10 +- lib/gitlab/reference_extractor.rb | 7 +- lib/gitlab/slash_commands/issue_command.rb | 2 +- .../features/issuables/markdown_references_spec.rb | 193 +++++++++++++++++++++ spec/features/projects/features_visibility_spec.rb | 2 +- spec/helpers/issues_helper_spec.rb | 8 +- .../filter/external_issue_reference_filter_spec.rb | 5 + spec/lib/banzai/pipeline/gfm_pipeline_spec.rb | 89 ++++++++-- spec/lib/gitlab/reference_extractor_spec.rb | 31 +++- spec/models/concerns/mentionable_spec.rb | 18 +- spec/models/merge_request_spec.rb | 52 +++++- spec/models/project_spec.rb | 45 ++++- spec/requests/api/merge_requests_spec.rb | 14 +- spec/requests/api/projects_spec.rb | 25 +++ spec/services/git_push_service_spec.rb | 58 +++++-- spec/services/issues/close_service_spec.rb | 8 +- spec/services/merge_requests/build_service_spec.rb | 2 +- 31 files changed, 563 insertions(+), 99 deletions(-) create mode 100644 spec/features/issuables/markdown_references_spec.rb diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 5b0eeac2477..e2ccabb22db 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -269,10 +269,6 @@ class Projects::IssuesController < Projects::ApplicationController end end - def module_enabled - render_404 unless @project.feature_available?(:issues, current_user) - end - def issue_params params.require(:issue).permit(*issue_params_attributes) end diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 42b6cfdf02f..7e1ccb23e9e 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -17,10 +17,10 @@ module IssuesHelper return '' if project.nil? url = - if options[:only_path] - project.issues_tracker.issue_path(issue_iid) + if options[:internal] + url_for_internal_issue(issue_iid, project, options) else - project.issues_tracker.issue_url(issue_iid) + url_for_tracker_issue(issue_iid, project, options) end # Ensure we return a valid URL to prevent possible XSS. @@ -29,6 +29,24 @@ module IssuesHelper '' end + def url_for_tracker_issue(issue_iid, project, options) + if options[:only_path] + project.issues_tracker.issue_path(issue_iid) + else + project.issues_tracker.issue_url(issue_iid) + end + end + + def url_for_internal_issue(issue_iid, project = @project, options = {}) + helpers = Gitlab::Routing.url_helpers + + if options[:only_path] + helpers.namespace_project_issue_path(namespace_id: project.namespace, project_id: project, id: issue_iid) + else + helpers.namespace_project_issue_url(namespace_id: project.namespace, project_id: project, id: issue_iid) + end + end + def bulk_update_milestone_options milestones = @project.milestones.active.reorder(due_date: :asc, title: :asc).to_a milestones.unshift(Milestone::None) @@ -158,4 +176,6 @@ module IssuesHelper # Required for Banzai::Filter::IssueReferenceFilter module_function :url_for_issue + module_function :url_for_internal_issue + module_function :url_for_tracker_issue end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index e4e7999d0f2..a910099b4c1 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -596,7 +596,7 @@ class MergeRequest < ActiveRecord::Base # running `ReferenceExtractor` on each of them separately. # This optimization does not apply to issues from external sources. def cache_merge_request_closes_issues!(current_user) - return if project.has_external_issue_tracker? + return unless project.issues_enabled? transaction do self.merge_requests_closing_issues.delete_all diff --git a/app/models/project.rb b/app/models/project.rb index 0b357d5d003..d827bfaa806 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -734,9 +734,11 @@ class Project < ActiveRecord::Base end def get_issue(issue_id, current_user) - if default_issues_tracker? - IssuesFinder.new(current_user, project_id: id).find_by(iid: issue_id) - else + issue = IssuesFinder.new(current_user, project_id: id).find_by(iid: issue_id) if issues_enabled? + + if issue + issue + elsif external_issue_tracker ExternalIssue.new(issue_id, self) end end @@ -758,7 +760,7 @@ class Project < ActiveRecord::Base end def external_issue_reference_pattern - external_issue_tracker.class.reference_pattern + external_issue_tracker.class.reference_pattern(only_long: issues_enabled?) end def default_issues_tracker? diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb index 6d6a3ae3647..31984c5d7ed 100644 --- a/app/models/project_services/issue_tracker_service.rb +++ b/app/models/project_services/issue_tracker_service.rb @@ -8,8 +8,12 @@ class IssueTrackerService < Service # This pattern does not support cross-project references # The other code assumes that this pattern is a superset of all # overriden patterns. See ReferenceRegexes::EXTERNAL_PATTERN - def self.reference_pattern - @reference_pattern ||= %r{(\b[A-Z][A-Z0-9_]+-|#{Issue.reference_prefix})(?\d+)} + def self.reference_pattern(only_long: false) + if only_long + %r{(\b[A-Z][A-Z0-9_]+-)(?\d+)} + else + %r{(\b[A-Z][A-Z0-9_]+-|#{Issue.reference_prefix})(?\d+)} + end end def default? diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 5498a2e17b2..450027c2e57 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -18,7 +18,7 @@ class JiraService < IssueTrackerService end # {PROJECT-KEY}-{NUMBER} Examples: JIRA-1, PROJECT-1 - def self.reference_pattern + def self.reference_pattern(only_long: true) @reference_pattern ||= %r{(?\b([A-Z][A-Z0-9_]+-)\d+)} end diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb index ddef5281498..74459c3342c 100644 --- a/app/services/issues/close_service.rb +++ b/app/services/issues/close_service.rb @@ -16,13 +16,13 @@ module Issues # The code calling this method is responsible for ensuring that a user is # allowed to close the given issue. def close_issue(issue, commit: nil, notifications: true, system_note: true) - if project.jira_tracker? && project.jira_service.active + if project.jira_tracker? && project.jira_service.active && issue.is_a?(ExternalIssue) project.jira_service.close_issue(commit, issue) todo_service.close_issue(issue, current_user) return issue end - if project.default_issues_tracker? && issue.close + if project.issues_enabled? && issue.close event_service.close_issue(issue, current_user) create_note(issue, commit) if system_note notification_service.close_issue(issue, current_user) if notifications diff --git a/app/views/layouts/nav/_new_project_sidebar.html.haml b/app/views/layouts/nav/_new_project_sidebar.html.haml index 21f175291fa..00395b222e4 100644 --- a/app/views/layouts/nav/_new_project_sidebar.html.haml +++ b/app/views/layouts/nav/_new_project_sidebar.html.haml @@ -75,10 +75,10 @@ Registry - if project_nav_tab? :issues - = nav_link(controller: @project.default_issues_tracker? ? [:issues, :labels, :milestones, :boards] : :issues) do + = nav_link(controller: @project.issues_enabled? ? [:issues, :labels, :milestones, :boards] : :issues) do = link_to project_issues_path(@project), title: 'Issues', class: 'shortcuts-issues' do %span - - if @project.default_issues_tracker? + - if @project.issues_enabled? %span.badge.count.issue_counter= number_with_delimiter(IssuesFinder.new(current_user, project_id: @project.id).execute.opened.count) Issues @@ -113,7 +113,7 @@ Milestones - if project_nav_tab? :merge_requests - = nav_link(controller: @project.default_issues_tracker? ? :merge_requests : [:merge_requests, :labels, :milestones]) do + = nav_link(controller: @project.issues_enabled? ? :merge_requests : [:merge_requests, :labels, :milestones]) do = link_to project_merge_requests_path(@project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do %span %span.badge.count.merge_counter.js-merge-counter= number_with_delimiter(MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened.count) diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index fb90bb4b472..924cd2e9681 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -23,16 +23,16 @@ Registry - if project_nav_tab? :issues - = nav_link(controller: @project.default_issues_tracker? ? [:issues, :labels, :milestones, :boards] : :issues) do + = nav_link(controller: @project.issues_enabled? ? [:issues, :labels, :milestones, :boards] : :issues) do = link_to project_issues_path(@project), title: 'Issues', class: 'shortcuts-issues' do %span Issues - - if @project.default_issues_tracker? + - if @project.issues_enabled? %span.badge.count.issue_counter= number_with_delimiter(issuables_count_for_state(:issues, :opened, finder: IssuesFinder.new(current_user, project_id: @project.id))) - if project_nav_tab? :merge_requests - controllers = [:merge_requests, 'projects/merge_requests/conflicts'] - - controllers.push(:merge_requests, :labels, :milestones) unless @project.default_issues_tracker? + - controllers.push(:merge_requests, :labels, :milestones) unless @project.issues_enabled? = nav_link(controller: controllers) do = link_to project_merge_requests_path(@project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do %span diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml index bfeb746ee83..c020e7db380 100644 --- a/app/views/projects/merge_requests/index.html.haml +++ b/app/views/projects/merge_requests/index.html.haml @@ -4,7 +4,7 @@ - new_merge_request_path = project_new_merge_request_path(merge_project) if merge_project - page_title "Merge Requests" -- unless @project.default_issues_tracker? +- unless @project.issues_enabled? = content_for :sub_nav do = render "projects/merge_requests/head" diff --git a/app/views/shared/_mr_head.html.haml b/app/views/shared/_mr_head.html.haml index 4211ec6351d..e7355ae2eea 100644 --- a/app/views/shared/_mr_head.html.haml +++ b/app/views/shared/_mr_head.html.haml @@ -1,4 +1,4 @@ -- if @project.default_issues_tracker? +- if @project.issues_enabled? = render "projects/issues/head" - else = render "projects/merge_requests/head" diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 09a88869063..1719e9f7205 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -109,7 +109,7 @@ module API user.avatar_url(only_path: false) end expose :star_count, :forks_count - expose :open_issues_count, if: lambda { |project, options| project.feature_available?(:issues, options[:current_user]) && project.default_issues_tracker? } + expose :open_issues_count, if: lambda { |project, options| project.feature_available?(:issues, options[:current_user]) } expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] } expose :public_builds, as: :public_jobs expose :ci_config_path diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 6e2e13e0a24..f64ac659413 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -29,14 +29,6 @@ module API render_api_error!(errors, 400) end - def issue_entity(project) - if project.has_external_issue_tracker? - Entities::ExternalIssue - else - Entities::IssueBasic - end - end - def find_merge_requests(args = {}) args = params.merge(args) @@ -278,7 +270,14 @@ module API get ':id/merge_requests/:merge_request_iid/closes_issues' do merge_request = find_merge_request_with_access(params[:merge_request_iid]) issues = ::Kaminari.paginate_array(merge_request.closes_issues(current_user)) - present paginate(issues), with: issue_entity(user_project), current_user: current_user + issues = paginate(issues) + + external_issues, internal_issues = issues.partition { |issue| issue.is_a?(ExternalIssue) } + + data = Entities::IssueBasic.represent(internal_issues, current_user: current_user) + data += Entities::ExternalIssue.represent(external_issues, current_user: current_user) + + data.as_json end end end diff --git a/lib/banzai/filter/issue_reference_filter.rb b/lib/banzai/filter/issue_reference_filter.rb index ba1a5ac84b3..ce1ab977d3b 100644 --- a/lib/banzai/filter/issue_reference_filter.rb +++ b/lib/banzai/filter/issue_reference_filter.rb @@ -20,7 +20,7 @@ module Banzai end def url_for_object(issue, project) - IssuesHelper.url_for_issue(issue.iid, project, only_path: context[:only_path]) + IssuesHelper.url_for_issue(issue.iid, project, only_path: context[:only_path], internal: true) end def project_from_ref(ref) diff --git a/lib/banzai/reference_parser/external_issue_parser.rb b/lib/banzai/reference_parser/external_issue_parser.rb index 6307c1b571a..1802cd04854 100644 --- a/lib/banzai/reference_parser/external_issue_parser.rb +++ b/lib/banzai/reference_parser/external_issue_parser.rb @@ -21,10 +21,14 @@ module Banzai gather_attributes_per_project(nodes, self.class.data_attribute) end - private - + # we extract only external issue trackers references here, we don't extract cross-project references, + # so we don't need to do anything here. def can_read_reference?(user, ref_project, node) - can?(user, :read_issue, ref_project) + true + end + + def nodes_visible_to_user(user, nodes) + nodes end end end diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index 7668ecacc4b..f5b757ace77 100644 --- a/lib/gitlab/reference_extractor.rb +++ b/lib/gitlab/reference_extractor.rb @@ -33,7 +33,12 @@ module Gitlab def issues if project && project.jira_tracker? - @references[:external_issue] ||= references(:external_issue) + if project.issues_enabled? + @references[:all_issues] ||= references(:external_issue) + references(:issue) + else + @references[:external_issue] ||= references(:external_issue) + + references(:issue).select { |i| i.project_id != project.id } + end else @references[:issue] ||= references(:issue) end diff --git a/lib/gitlab/slash_commands/issue_command.rb b/lib/gitlab/slash_commands/issue_command.rb index 87ea19b8806..3d96982b820 100644 --- a/lib/gitlab/slash_commands/issue_command.rb +++ b/lib/gitlab/slash_commands/issue_command.rb @@ -2,7 +2,7 @@ module Gitlab module SlashCommands class IssueCommand < BaseCommand def self.available?(project) - project.issues_enabled? && project.default_issues_tracker? + project.issues_enabled? end def collection diff --git a/spec/features/issuables/markdown_references_spec.rb b/spec/features/issuables/markdown_references_spec.rb new file mode 100644 index 00000000000..f51b2e4001a --- /dev/null +++ b/spec/features/issuables/markdown_references_spec.rb @@ -0,0 +1,193 @@ +require 'rails_helper' + +describe 'Markdown References', :feature, :js do + let(:user) { create(:user) } + let(:actual_project) { create(:project, :public) } + let(:merge_request) { create(:merge_request, target_project: actual_project, source_project: actual_project)} + let(:issue_actual_project) { create(:issue, project: actual_project) } + let!(:other_project) { create(:empty_project, :public) } + let!(:issue_other_project) { create(:issue, project: other_project) } + let(:issues) { [issue_actual_project, issue_other_project] } + + def build_note + markdown = "Referencing internal issue #{issue_actual_project.to_reference}, " + + "cross-project #{issue_other_project.to_reference(actual_project)} external JIRA-5 " + + "and non existing #999" + + page.within('#diff-notes-app') do + fill_in 'note_note', with: markdown + end + end + + shared_examples 'correct references' do + before do + remotelink = double(:remotelink, all: [], build: double(save!: true)) + + stub_request(:get, "https://jira.example.com/rest/api/2/issue/JIRA-5") + stub_request(:post, "https://jira.example.com/rest/api/2/issue/JIRA-5/comment") + allow_any_instance_of(JIRA::Resource::Issue).to receive(:remotelink).and_return(remotelink) + + sign_in(user) + visit merge_request_path(merge_request) + build_note + end + + def links_expectations + issues.each do |issue| + if referenced_issues.include?(issue) + expect(page).to have_link(issue.to_reference, href: issue_path(issue)) + else + expect(page).not_to have_link(issue.to_reference, href: issue_path(issue)) + end + end + + if jira_referenced + expect(page).to have_link('JIRA-5', href: 'https://jira.example.com/browse/JIRA-5') + else + expect(page).not_to have_link('JIRA-5', href: 'https://jira.example.com/browse/JIRA-5') + end + + expect(page).not_to have_link('#999') + end + + it 'creates a link to the referenced issue on the preview' do + find('.js-md-preview-button').click + wait_for_requests + + page.within('.md-preview-holder') do + links_expectations + end + end + + it 'creates a link to the referenced issue after submit' do + click_button 'Comment' + wait_for_requests + + page.within('#diff-notes-app') do + links_expectations + end + end + + it 'creates a note on the referenced issues' do + click_button 'Comment' + wait_for_requests + + if referenced_issues.include?(issue_actual_project) + visit issue_path(issue_actual_project) + + page.within('#notes') do + expect(page).to have_content( + "#{user.to_reference} mentioned in merge request #{merge_request.to_reference}" + ) + end + end + + if referenced_issues.include?(issue_other_project) + visit issue_path(issue_other_project) + + page.within('#notes') do + expect(page).to have_content( + "#{user.to_reference} mentioned in merge request #{merge_request.to_reference(other_project)}" + ) + end + end + end + end + + context 'when internal issues tracker is enabled for the other project' do + context 'when only internal issues tracker is enabled for the actual project' do + include_examples 'correct references' do + let(:referenced_issues) { [issue_actual_project, issue_other_project] } + let(:jira_referenced) { false } + end + end + + context 'when both external and internal issues trackers are enabled for the actual project' do + before do + create(:jira_service, project: actual_project) + end + + include_examples 'correct references' do + let(:referenced_issues) { [issue_actual_project, issue_other_project] } + let(:jira_referenced) { true } + end + end + + context 'when only external issues tracker is enabled for the actual project' do + before do + create(:jira_service, project: actual_project) + + actual_project.issues_enabled = false + actual_project.save! + end + + include_examples 'correct references' do + let(:referenced_issues) { [issue_other_project] } + let(:jira_referenced) { true } + end + end + + context 'when no tracker is enabled for the actual project' do + before do + actual_project.issues_enabled = false + actual_project.save! + end + + include_examples 'correct references' do + let(:referenced_issues) { [issue_other_project] } + let(:jira_referenced) { false } + end + end + end + + context 'when internal issues tracker is disabled for the other project' do + before do + other_project.issues_enabled = false + other_project.save! + end + + context 'when only internal issues tracker is enabled for the actual project' do + include_examples 'correct references' do + let(:referenced_issues) { [issue_actual_project] } + let(:jira_referenced) { false } + end + end + + context 'when both external and internal issues trackers are enabled for the actual project' do + before do + create(:jira_service, project: actual_project) + end + + include_examples 'correct references' do + let(:referenced_issues) { [issue_actual_project] } + let(:jira_referenced) { true } + end + end + + context 'when only external issues tracker is enabled for the actual project' do + before do + create(:jira_service, project: actual_project) + + actual_project.issues_enabled = false + actual_project.save! + end + + include_examples 'correct references' do + let(:referenced_issues) { [] } + let(:jira_referenced) { true } + end + end + + context 'when no issues tracker is enabled for the actual project' do + before do + actual_project.issues_enabled = false + actual_project.save! + end + + include_examples 'correct references' do + let(:referenced_issues) { [] } + let(:jira_referenced) { false } + end + end + end +end diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb index 2091c7b79d3..1588f8a828a 100644 --- a/spec/features/projects/features_visibility_spec.rb +++ b/spec/features/projects/features_visibility_spec.rb @@ -55,7 +55,7 @@ describe 'Edit Project Settings', feature: true do project.save! allow_any_instance_of(Project).to receive(:external_issue_tracker).and_return(JiraService.new) - visit namespace_project_path(project.namespace, project) + visit project_path(project) expect(page).not_to have_selector('.shortcuts-issues') end diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb index 8f7f17a484f..9524a101e74 100644 --- a/spec/helpers/issues_helper_spec.rb +++ b/spec/helpers/issues_helper_spec.rb @@ -8,7 +8,7 @@ describe IssuesHelper do describe "url_for_issue" do let(:issues_url) { ext_project.external_issue_tracker.issues_url} let(:ext_expected) { issues_url.gsub(':id', issue.iid.to_s).gsub(':project_id', ext_project.id.to_s) } - let(:int_expected) { polymorphic_path([@project.namespace, project, issue]) } + let(:int_expected) { polymorphic_path([@project.namespace, @project, issue]) } it "returns internal path if used internal tracker" do @project = project @@ -22,6 +22,12 @@ describe IssuesHelper do expect(url_for_issue(issue.iid)).to match(ext_expected) end + it "returns path to internal issue when internal option passed" do + @project = ext_project + + expect(url_for_issue(issue.iid, ext_project, internal: true)).to match(int_expected) + end + it "returns empty string if project nil" do @project = nil diff --git a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb index b7d82c36ddd..fb320e0148a 100644 --- a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb @@ -108,6 +108,11 @@ describe Banzai::Filter::ExternalIssueReferenceFilter, lib: true do let(:issue) { ExternalIssue.new("#123", project) } let(:reference) { issue.to_reference } + before do + project.issues_enabled = false + project.save! + end + it_behaves_like "external issue tracker" end diff --git a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb index 1eb90dc1847..601ffbb5456 100644 --- a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb +++ b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb @@ -4,26 +4,87 @@ describe Banzai::Pipeline::GfmPipeline do describe 'integration between parsing regular and external issue references' do let(:project) { create(:redmine_project, :public) } - it 'allows to use shorthand external reference syntax for Redmine' do - markdown = '#12' + context 'when internal issue tracker is enabled' do + context 'when shorthand pattern #ISSUE_ID is used' do + it 'links an internal issue if it exists' do + issue = create(:issue, project: project) + markdown = issue.to_reference(project, full: true) - result = described_class.call(markdown, project: project)[:output] - link = result.css('a').first + result = described_class.call(markdown, project: project)[:output] + link = result.css('a').first - expect(link['href']).to eq 'http://redmine/projects/project_name_in_redmine/issues/12' + expect(link['href']).to eq( + Gitlab::Routing.url_helpers.project_issue_path(project, issue) + ) + end + + it 'does not link any issue if it does not exist on GitLab' do + markdown = '#12' + + result = described_class.call(markdown, project: project)[:output] + expect(result.css('a')).to be_empty + end + end + + it 'allows to use long external reference syntax for Redmine' do + markdown = 'API_32-12' + + result = described_class.call(markdown, project: project)[:output] + link = result.css('a').first + + expect(link['href']).to eq 'http://redmine/projects/project_name_in_redmine/issues/12' + end + + it 'parses cross-project references to regular issues' do + other_project = create(:empty_project, :public) + issue = create(:issue, project: other_project) + markdown = issue.to_reference(project, full: true) + + result = described_class.call(markdown, project: project)[:output] + link = result.css('a').first + + expect(link['href']).to eq( + Gitlab::Routing.url_helpers.project_issue_path(other_project, issue) + ) + end end - it 'parses cross-project references to regular issues' do - other_project = create(:empty_project, :public) - issue = create(:issue, project: other_project) - markdown = issue.to_reference(project, full: true) + context 'when internal issue tracker is disabled' do + before do + project.issues_enabled = false + project.save! + end + + it 'allows to use shorthand external reference syntax for Redmine' do + markdown = '#12' + + result = described_class.call(markdown, project: project)[:output] + link = result.css('a').first + + expect(link['href']).to eq 'http://redmine/projects/project_name_in_redmine/issues/12' + end + + it 'allows to use long external reference syntax for Redmine' do + markdown = 'API_32-12' + + result = described_class.call(markdown, project: project)[:output] + link = result.css('a').first + + expect(link['href']).to eq 'http://redmine/projects/project_name_in_redmine/issues/12' + end + + it 'parses cross-project references to regular issues' do + other_project = create(:empty_project, :public) + issue = create(:issue, project: other_project) + markdown = issue.to_reference(project, full: true) - result = described_class.call(markdown, project: project)[:output] - link = result.css('a').first + result = described_class.call(markdown, project: project)[:output] + link = result.css('a').first - expect(link['href']).to eq( - Gitlab::Routing.url_helpers.project_issue_path(other_project, issue) - ) + expect(link['href']).to eq( + Gitlab::Routing.url_helpers.project_issue_path(other_project, issue) + ) + end end end end diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb index 84cfd934fa0..917692e9c6c 100644 --- a/spec/lib/gitlab/reference_extractor_spec.rb +++ b/spec/lib/gitlab/reference_extractor_spec.rb @@ -183,11 +183,34 @@ describe Gitlab::ReferenceExtractor, lib: true do context 'with an external issue tracker' do let(:project) { create(:jira_project) } + let(:issue) { create(:issue, project: project) } + + context 'when GitLab issues are enabled' do + it 'returns both JIRA and internal issues' do + subject.analyze("JIRA-123 and FOOBAR-4567 and #{issue.to_reference}") + expect(subject.issues).to eq [ExternalIssue.new('JIRA-123', project), + ExternalIssue.new('FOOBAR-4567', project), + issue] + end + + it 'returns only JIRA issues if the internal one does not exists' do + subject.analyze("JIRA-123 and FOOBAR-4567 and #999") + expect(subject.issues).to eq [ExternalIssue.new('JIRA-123', project), + ExternalIssue.new('FOOBAR-4567', project)] + end + end - it 'returns JIRA issues for a JIRA-integrated project' do - subject.analyze('JIRA-123 and FOOBAR-4567') - expect(subject.issues).to eq [ExternalIssue.new('JIRA-123', project), - ExternalIssue.new('FOOBAR-4567', project)] + context 'when GitLab issues are disabled' do + before do + project.issues_enabled = false + project.save! + end + + it 'returns only JIRA issues' do + subject.analyze("JIRA-123 and FOOBAR-4567 and #{issue.to_reference}") + expect(subject.issues).to eq [ExternalIssue.new('JIRA-123', project), + ExternalIssue.new('FOOBAR-4567', project)] + end end end diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb index e2a29e0ae70..1ad811736af 100644 --- a/spec/models/concerns/mentionable_spec.rb +++ b/spec/models/concerns/mentionable_spec.rb @@ -174,25 +174,25 @@ describe Commit, 'Mentionable' do it "is false when message doesn't reference anything" do allow(commit.raw).to receive(:message).and_return "WIP: Do something" - expect(commit.matches_cross_reference_regex?).to be false + expect(commit.matches_cross_reference_regex?).to be_falsey end it 'is true if issue #number mentioned in title' do allow(commit.raw).to receive(:message).and_return "#1" - expect(commit.matches_cross_reference_regex?).to be true + expect(commit.matches_cross_reference_regex?).to be_truthy end it 'is true if references an MR' do allow(commit.raw).to receive(:message).and_return "See merge request !12" - expect(commit.matches_cross_reference_regex?).to be true + expect(commit.matches_cross_reference_regex?).to be_truthy end it 'is true if references a commit' do allow(commit.raw).to receive(:message).and_return "a1b2c3d4" - expect(commit.matches_cross_reference_regex?).to be true + expect(commit.matches_cross_reference_regex?).to be_truthy end it 'is true if issue referenced by url' do @@ -200,7 +200,7 @@ describe Commit, 'Mentionable' do allow(commit.raw).to receive(:message).and_return Gitlab::UrlBuilder.build(issue) - expect(commit.matches_cross_reference_regex?).to be true + expect(commit.matches_cross_reference_regex?).to be_truthy end context 'with external issue tracker' do @@ -209,7 +209,13 @@ describe Commit, 'Mentionable' do it 'is true if external issues referenced' do allow(commit.raw).to receive(:message).and_return 'JIRA-123' - expect(commit.matches_cross_reference_regex?).to be true + expect(commit.matches_cross_reference_regex?).to be_truthy + end + + it 'is true if internal issues referenced' do + allow(commit.raw).to receive(:message).and_return '#123' + + expect(commit.matches_cross_reference_regex?).to be_truthy end end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 1eadc28869f..6f6a8ac91b8 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -155,13 +155,53 @@ describe MergeRequest, models: true do expect { subject.cache_merge_request_closes_issues!(subject.author) }.to change(subject.merge_requests_closing_issues, :count).by(1) end - it 'does not cache issues from external trackers' do - subject.project.update_attribute(:has_external_issue_tracker, true) - issue = ExternalIssue.new('JIRA-123', subject.project) - commit = double('commit1', safe_message: "Fixes #{issue.to_reference}") - allow(subject).to receive(:commits).and_return([commit]) + context 'when both internal and external issue trackers are enabled' do + before do + subject.project.has_external_issue_tracker = true + subject.project.save! + end + + it 'does not cache issues from external trackers' do + issue = ExternalIssue.new('JIRA-123', subject.project) + commit = double('commit1', safe_message: "Fixes #{issue.to_reference}") + allow(subject).to receive(:commits).and_return([commit]) - expect { subject.cache_merge_request_closes_issues!(subject.author) }.not_to change(subject.merge_requests_closing_issues, :count) + expect { subject.cache_merge_request_closes_issues!(subject.author) }.not_to change(subject.merge_requests_closing_issues, :count) + end + + it 'caches an internal issue' do + issue = create(:issue, project: subject.project) + commit = double('commit1', safe_message: "Fixes #{issue.to_reference}") + allow(subject).to receive(:commits).and_return([commit]) + + expect { subject.cache_merge_request_closes_issues!(subject.author) } + .to change(subject.merge_requests_closing_issues, :count).by(1) + end + end + + context 'when only external issue tracker enabled' do + before do + subject.project.has_external_issue_tracker = true + subject.project.issues_enabled = false + subject.project.save! + end + + it 'does not cache issues from external trackers' do + issue = ExternalIssue.new('JIRA-123', subject.project) + commit = double('commit1', safe_message: "Fixes #{issue.to_reference}") + allow(subject).to receive(:commits).and_return([commit]) + + expect { subject.cache_merge_request_closes_issues!(subject.author) }.not_to change(subject.merge_requests_closing_issues, :count) + end + + it 'does not cache an internal issue' do + issue = create(:issue, project: subject.project) + commit = double('commit1', safe_message: "Fixes #{issue.to_reference}") + allow(subject).to receive(:commits).and_return([commit]) + + expect { subject.cache_merge_request_closes_issues!(subject.author) } + .not_to change(subject.merge_requests_closing_issues, :count) + end end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index fdcb011d685..8d916b79b13 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -533,15 +533,48 @@ describe Project, models: true do end context 'with external issues tracker' do + let!(:internal_issue) { create(:issue, project: project) } before do - allow(project).to receive(:default_issues_tracker?).and_return(false) + allow(project).to receive(:external_issue_tracker).and_return(true) end - it 'returns an ExternalIssue' do - issue = project.get_issue('FOO-1234', user) - expect(issue).to be_kind_of(ExternalIssue) - expect(issue.iid).to eq 'FOO-1234' - expect(issue.project).to eq project + context 'when internal issues are enabled' do + it 'returns interlan issue' do + issue = project.get_issue(internal_issue.iid, user) + + expect(issue).to be_kind_of(Issue) + expect(issue.iid).to eq(internal_issue.iid) + expect(issue.project).to eq(project) + end + + it 'returns an ExternalIssue when internal issue does not exists' do + issue = project.get_issue('FOO-1234', user) + + expect(issue).to be_kind_of(ExternalIssue) + expect(issue.iid).to eq('FOO-1234') + expect(issue.project).to eq(project) + end + end + + context 'when internal issues are disabled' do + before do + project.issues_enabled = false + project.save! + end + + it 'returns always an External issues' do + issue = project.get_issue(internal_issue.iid, user) + expect(issue).to be_kind_of(ExternalIssue) + expect(issue.iid).to eq(internal_issue.iid.to_s) + expect(issue.project).to eq(project) + end + + it 'returns an ExternalIssue when internal issue does not exists' do + issue = project.get_issue('FOO-1234', user) + expect(issue).to be_kind_of(ExternalIssue) + expect(issue.iid).to eq('FOO-1234') + expect(issue.project).to eq(project) + end end end end diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 9098ae6bcda..35b6522ea98 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -794,18 +794,24 @@ describe API::MergeRequests do it 'handles external issues' do jira_project = create(:jira_project, :public, name: 'JIR_EXT1') - issue = ExternalIssue.new("#{jira_project.name}-123", jira_project) - merge_request = create(:merge_request, :simple, author: user, assignee: user, source_project: jira_project) - merge_request.update_attribute(:description, "Closes #{issue.to_reference(jira_project)}") + ext_issue = ExternalIssue.new("#{jira_project.name}-123", jira_project) + issue = create(:issue, project: jira_project) + description = "Closes #{ext_issue.to_reference(jira_project)}\ncloses #{issue.to_reference}" + merge_request = create(:merge_request, + :simple, author: user, assignee: user, source_project: jira_project, description: description) get api("/projects/#{jira_project.id}/merge_requests/#{merge_request.iid}/closes_issues", user) expect(response).to have_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(json_response.length).to eq(1) + expect(json_response.length).to eq(2) + expect(json_response.second['title']).to eq(ext_issue.title) + expect(json_response.second['id']).to eq(ext_issue.id) + expect(json_response.second['confidential']).to be_nil expect(json_response.first['title']).to eq(issue.title) expect(json_response.first['id']).to eq(issue.id) + expect(json_response.first['confidential']).not_to be_nil end it 'returns 403 if the user has no access to the merge request' do diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 6dbde8bad31..457f64cc88c 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -159,6 +159,31 @@ describe API::Projects do expect(json_response.first).to include 'statistics' end + context 'when external issue tracker is enabled' do + let!(:jira_service) { create(:jira_service, project: project) } + + it 'includes open_issues_count' do + get api('/projects', user) + + expect(response.status).to eq 200 + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.first.keys).to include('open_issues_count') + expect(json_response.find { |hash| hash['id'] == project.id }.keys).to include('open_issues_count') + end + + it 'does not include open_issues_count if issues are disabled' do + project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED) + + get api('/projects', user) + + expect(response.status).to eq 200 + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.find { |hash| hash['id'] == project.id }.keys).not_to include('open_issues_count') + end + end + context 'and with simple=true' do it 'returns a simplified version of all the projects' do expected_keys = %w(id http_url_to_repo web_url name name_with_namespace path path_with_namespace) diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index c493c08a7ae..f801506f1b6 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -488,21 +488,57 @@ describe GitPushService, services: true do end end - context "using wrong markdown" do - let(:message) { "this is some work.\n\ncloses #1" } + context "using internal issue reference" do + context 'when internal issues are disabled' do + before do + project.issues_enabled = false + project.save! + end + let(:message) { "this is some work.\n\ncloses #1" } + + it "does not initiates one api call to jira server to close the issue" do + execute_service(project, commit_author, @oldrev, @newrev, @ref ) + + expect(WebMock).not_to have_requested(:post, jira_api_transition_url('JIRA-1')) + end + + it "does not initiates one api call to jira server to comment on the issue" do + execute_service(project, commit_author, @oldrev, @newrev, @ref ) + + expect(WebMock).not_to have_requested(:post, jira_api_comment_url('JIRA-1')).with( + body: comment_body + ).once + end + end - it "does not initiates one api call to jira server to close the issue" do - execute_service(project, commit_author, @oldrev, @newrev, @ref ) + context 'when internal issues are enabled' do + let(:issue) { create(:issue, project: project) } + let(:message) { "this is some work.\n\ncloses JIRA-1 \n\n closes #{issue.to_reference}" } - expect(WebMock).not_to have_requested(:post, jira_api_transition_url('JIRA-1')) - end + it "initiates one api call to jira server to close the jira issue" do + execute_service(project, commit_author, @oldrev, @newrev, @ref ) - it "does not initiates one api call to jira server to comment on the issue" do - execute_service(project, commit_author, @oldrev, @newrev, @ref ) + expect(WebMock).to have_requested(:post, jira_api_transition_url('JIRA-1')).once + end - expect(WebMock).not_to have_requested(:post, jira_api_comment_url('JIRA-1')).with( - body: comment_body - ).once + it "initiates one api call to jira server to comment on the jira issue" do + execute_service(project, commit_author, @oldrev, @newrev, @ref ) + + expect(WebMock).to have_requested(:post, jira_api_comment_url('JIRA-1')).with( + body: comment_body + ).once + end + + it "closes the internal issue" do + execute_service(project, commit_author, @oldrev, @newrev, @ref ) + expect(issue.reload).to be_closed + end + + it "adds a note indicating that the issue is now closed" do + expect(SystemNoteService).to receive(:change_status) + .with(issue, project, commit_author, "closed", closing_commit) + execute_service(project, commit_author, @oldrev, @newrev, @ref ) + end end end end diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb index d6f4c694069..da8b60f1337 100644 --- a/spec/services/issues/close_service_spec.rb +++ b/spec/services/issues/close_service_spec.rb @@ -98,13 +98,13 @@ describe Issues::CloseService, services: true do end end - context 'external issue tracker' do + context 'internal issues disabled' do before do - allow(project).to receive(:default_issues_tracker?).and_return(false) - described_class.new(project, user).close_issue(issue) + project.issues_enabled = false + project.save! end - it 'closes the issue' do + it 'does not close the issue' do expect(issue).to be_valid expect(issue).to be_opened expect(todo.reload).to be_pending diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb index 01ef52396d7..a40d4c877bc 100644 --- a/spec/services/merge_requests/build_service_spec.rb +++ b/spec/services/merge_requests/build_service_spec.rb @@ -207,7 +207,7 @@ describe MergeRequests::BuildService, services: true do let(:source_branch) { '12345-fix-issue' } before do - allow(project).to receive(:default_issues_tracker?).and_return(false) + allow(project).to receive(:external_issue_tracker).and_return(true) end it 'sets the title to: Resolves External Issue $issue-iid' do -- cgit v1.2.1 From 6774a0378d624fafbd287ce4adcee3787106f1b9 Mon Sep 17 00:00:00 2001 From: Jarka Kadlecova Date: Mon, 24 Jul 2017 08:14:06 +0200 Subject: Change docs to support paralel external and internal issue trackers --- doc/integration/external-issue-tracker.md | 6 ++---- doc/user/project/integrations/bugzilla.md | 4 +++- doc/user/project/integrations/redmine.md | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md index 2dd9b33273c..372e1909330 100644 --- a/doc/integration/external-issue-tracker.md +++ b/doc/integration/external-issue-tracker.md @@ -4,14 +4,12 @@ GitLab has a great issue tracker but you can also use an external one such as Jira, Redmine, or Bugzilla. Issue trackers are configurable per GitLab project and allow you to do the following: -- the **Issues** link on the GitLab project pages takes you to the appropriate - issue index of the external tracker -- clicking **New issue** on the project dashboard creates a new issue on the - external tracker - you can reference these external issues inside GitLab interface (merge requests, commits, comments) and they will be automatically converted into links +You can have enabled both external and internal GitLab issue trackers in parallel. The **Issues** link always opens the internal issue tracker and in case the internal issue tracker is disabled the link is not visible in the menu. + ## Configuration The configuration is done via a project's **Services**. diff --git a/doc/user/project/integrations/bugzilla.md b/doc/user/project/integrations/bugzilla.md index 6a040516231..ba2adc1afda 100644 --- a/doc/user/project/integrations/bugzilla.md +++ b/doc/user/project/integrations/bugzilla.md @@ -20,10 +20,12 @@ Once you have configured and enabled Bugzilla: ## Referencing issues in Bugzilla Issues in Bugzilla can be referenced in two alternative ways: -1. `#` where `` is a number (example `#143`) +1. `#` where `` is a number (example `#143`). 2. `-` where `` starts with a capital letter which is then followed by capital letters, numbers or underscores, and `` is a number (example `API_32-143`). +We suggest using the longer format if you have both internal and external issue trackers enabled. If you use the shorter format and an issue with the same ID exists in the internal issue tracker the internal issue will be linked. + Please note that `` part is ignored and links always point to the address specified in `issues_url`. diff --git a/doc/user/project/integrations/redmine.md b/doc/user/project/integrations/redmine.md index 8026f1f57bc..cf92465da53 100644 --- a/doc/user/project/integrations/redmine.md +++ b/doc/user/project/integrations/redmine.md @@ -30,5 +30,7 @@ Issues in Redmine can be referenced in two alternative ways: then followed by capital letters, numbers or underscores, and `` is a number (example `API_32-143`). +We suggest using the longer format if you have both internal and external issue trackers enabled. If you use the shorter format and an issue with the same ID exists in the internal issue tracker the internal issue will be linked. + Please note that `` part is ignored and links always point to the address specified in `issues_url`. -- cgit v1.2.1 From 632f360d0cf5a37f1047452b8fc25fd58c6f4e14 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Thu, 20 Jul 2017 22:30:12 +0200 Subject: Fix currently invalid po files --- changelogs/unreleased/bvl-fix-invalid-po-files.yml | 4 ++++ locale/ja/gitlab.po | 7 +++---- locale/uk/gitlab.po | 3 +-- locale/zh_CN/gitlab.po | 10 ++++------ locale/zh_HK/gitlab.po | 8 +++----- locale/zh_TW/gitlab.po | 4 ++-- 6 files changed, 17 insertions(+), 19 deletions(-) create mode 100644 changelogs/unreleased/bvl-fix-invalid-po-files.yml diff --git a/changelogs/unreleased/bvl-fix-invalid-po-files.yml b/changelogs/unreleased/bvl-fix-invalid-po-files.yml new file mode 100644 index 00000000000..b8a22a9e6df --- /dev/null +++ b/changelogs/unreleased/bvl-fix-invalid-po-files.yml @@ -0,0 +1,4 @@ +--- +title: Fix some invalid entries in PO files +merge_request: 13032 +author: diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po index cf74abf81bc..04c61906c73 100644 --- a/locale/ja/gitlab.po +++ b/locale/ja/gitlab.po @@ -33,7 +33,8 @@ msgstr "%{commit_author_link}は%{commit_timeago}前、コミットしました msgid "1 pipeline" msgid_plural "%d pipelines" -msgstr[0] "%d 個のパイプライン" +msgstr[0] "1 個のパイプライン" +msgstr[1] "%d 個のパイプライン" msgid "A collection of graphs regarding Continuous Integration" msgstr "CIについてのグラフ" @@ -1135,8 +1136,7 @@ msgstr "" msgid "" "You are going to remove the fork relationship to source project " "%{forked_from_project}. Are you ABSOLUTELY sure?" -msgstr "元のプロジェクト (%{forked_from_project}) とのリレーションを削除しようとしています。\n" -"本当によろしいですか?" +msgstr "元のプロジェクト (%{forked_from_project}) とのリレーションを削除しようとしています。本当によろしいですか?" msgid "" "You are going to transfer %{project_name_with_namespace} to another owner. " @@ -1201,4 +1201,3 @@ msgstr "メール通知" msgid "parent" msgid_plural "parents" msgstr[0] "親" - diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po index 59a7eb6e1b3..f198fff8dce 100644 --- a/locale/uk/gitlab.po +++ b/locale/uk/gitlab.po @@ -379,7 +379,7 @@ msgid "Edit" msgstr "Редагувати" msgid "Edit Pipeline Schedule %{id}" -msgstr "Редагувати Розклад Конвеєра % {id}" +msgstr "Редагувати Розклад Конвеєра %{id}" msgid "Every day (at 4:00am)" msgstr "Кожен день (в 4:00 ранку)" @@ -1231,4 +1231,3 @@ msgid_plural "parents" msgstr[0] "джерело" msgstr[1] "джерела" msgstr[2] "джерел" - diff --git a/locale/zh_CN/gitlab.po b/locale/zh_CN/gitlab.po index 47b72d7be1a..f471e7def25 100644 --- a/locale/zh_CN/gitlab.po +++ b/locale/zh_CN/gitlab.po @@ -29,7 +29,8 @@ msgstr "由 %{commit_author_link} 提交于 %{commit_timeago}" msgid "1 pipeline" msgid_plural "%d pipelines" -msgstr[0] "%d 条流水线" +msgstr[0] "1 条流水线" +msgstr[1] "%d 条流水线" msgid "A collection of graphs regarding Continuous Integration" msgstr "持续集成数据图" @@ -236,7 +237,7 @@ msgstr "创建新目录" msgid "" "Create a personal access token on your account to pull or push via " "%{protocol}." -msgstr "在帐户上创建个人访问令牌,以通过%{protocol}来拉取或推送。" +msgstr "在帐户上创建个人访问令牌,以通过 %{protocol} 来拉取或推送。" msgid "Create directory" msgstr "创建目录" @@ -1109,9 +1110,7 @@ msgid "" "You are going to remove %{project_name_with_namespace}.\n" "Removed project CANNOT be restored!\n" "Are you ABSOLUTELY sure?" -msgstr "即将要删除 %{project_name_with_namespace}。\n" -"已删除的项目无法恢复!\n" -"确定继续吗?" +msgstr "即将要删除 %{project_name_with_namespace}。已删除的项目无法恢复!确定继续吗?" msgid "" "You are going to remove the fork relationship to source project " @@ -1179,4 +1178,3 @@ msgstr "通知邮件" msgid "parent" msgid_plural "parents" msgstr[0] "父级" - diff --git a/locale/zh_HK/gitlab.po b/locale/zh_HK/gitlab.po index 8a4e6da4ea9..1b7c39f8f62 100644 --- a/locale/zh_HK/gitlab.po +++ b/locale/zh_HK/gitlab.po @@ -28,7 +28,8 @@ msgstr "由 %{commit_author_link} 提交於 %{commit_timeago}" msgid "1 pipeline" msgid_plural "%d pipelines" -msgstr[0] "%d 條流水線" +msgstr[0] "1 條流水線" +msgstr[1] "%d 條流水線" msgid "A collection of graphs regarding Continuous Integration" msgstr "相關持續集成的圖像集合" @@ -1108,9 +1109,7 @@ msgid "" "You are going to remove %{project_name_with_namespace}.\n" "Removed project CANNOT be restored!\n" "Are you ABSOLUTELY sure?" -msgstr "即將要刪除 %{project_name_with_namespace}。\n" -"已刪除的項目無法恢複!\n" -"確定繼續嗎?" +msgstr "即將要刪除 %{project_name_with_namespace}。已刪除的項目無法恢複!確定繼續嗎?" msgid "" "You are going to remove the fork relationship to source project " @@ -1178,4 +1177,3 @@ msgstr "通知郵件" msgid "parent" msgid_plural "parents" msgstr[0] "父級" - diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po index 05173ed12c0..8d30a78145d 100644 --- a/locale/zh_TW/gitlab.po +++ b/locale/zh_TW/gitlab.po @@ -32,7 +32,8 @@ msgstr "%{commit_author_link} 在 %{commit_timeago} 送交" msgid "1 pipeline" msgid_plural "%d pipelines" -msgstr[0] "%d 條流水線" +msgstr[0] "1 條流水線" +msgstr[1] "%d 條流水線" msgid "A collection of graphs regarding Continuous Integration" msgstr "持續整合 (CI) 相關的圖表" @@ -1193,4 +1194,3 @@ msgstr "通知信" msgid "parent" msgid_plural "parents" msgstr[0] "上層" - -- cgit v1.2.1 From fee65beb70bb9f995fe701a9deb0fabdc7a0e142 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 24 Jul 2017 09:20:22 +0100 Subject: Fixed custom logo sizing in new navigation header Closes #35439 --- app/assets/stylesheets/new_nav.scss | 5 +++++ changelogs/unreleased/new-navigation-custom-logo.yml | 4 ++++ 2 files changed, 9 insertions(+) create mode 100644 changelogs/unreleased/new-navigation-custom-logo.yml diff --git a/app/assets/stylesheets/new_nav.scss b/app/assets/stylesheets/new_nav.scss index 9f3e278ebfc..360ffda8d71 100644 --- a/app/assets/stylesheets/new_nav.scss +++ b/app/assets/stylesheets/new_nav.scss @@ -21,6 +21,11 @@ header.navbar-gitlab-new { padding-right: 0; color: currentColor; + img { + height: 28px; + margin-right: 10px; + } + > a { display: flex; align-items: center; diff --git a/changelogs/unreleased/new-navigation-custom-logo.yml b/changelogs/unreleased/new-navigation-custom-logo.yml new file mode 100644 index 00000000000..22e6c5dc7e5 --- /dev/null +++ b/changelogs/unreleased/new-navigation-custom-logo.yml @@ -0,0 +1,4 @@ +--- +title: Fix sizing of custom header logo in new navigation +merge_request: +author: -- cgit v1.2.1 From 6b0608cb8573fe8450332aa3a675848fa1adfd89 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Mon, 24 Jul 2017 11:46:33 +0200 Subject: Fix bug with truncation of file containing metrics bump prometheus gem version --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index b0b437ae342..b295cf8cdf4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -591,7 +591,7 @@ GEM premailer-rails (1.9.7) actionmailer (>= 3, < 6) premailer (~> 1.7, >= 1.7.9) - prometheus-client-mmap (0.7.0.beta9) + prometheus-client-mmap (0.7.0.beta10) mmap2 (~> 2.2, >= 2.2.7) pry (0.10.4) coderay (~> 1.1.0) -- cgit v1.2.1 From 61f948baed18788c2bb34dd6d5da452a19f58e52 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Mon, 24 Jul 2017 10:53:57 +0100 Subject: Upgrade the re2 gem to 1.1.0 --- Gemfile | 2 +- Gemfile.lock | 4 ++-- lib/gitlab/untrusted_regexp.rb | 30 +++--------------------------- spec/lib/gitlab/ci/trace/stream_spec.rb | 14 ++++++++++++++ spec/lib/gitlab/untrusted_regexp_spec.rb | 8 ++++---- 5 files changed, 24 insertions(+), 34 deletions(-) diff --git a/Gemfile b/Gemfile index 1ee44680774..5758b1b554e 100644 --- a/Gemfile +++ b/Gemfile @@ -164,7 +164,7 @@ gem 'rainbow', '~> 2.2' gem 'settingslogic', '~> 2.0.9' # Linear-time regex library for untrusted regular expressions -gem 're2', '~> 1.0.0' +gem 're2', '~> 1.1.0' # Misc diff --git a/Gemfile.lock b/Gemfile.lock index b0b437ae342..f8aaba57998 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -656,7 +656,7 @@ GEM debugger-ruby_core_source (~> 1.3) rdoc (4.2.2) json (~> 1.4) - re2 (1.0.0) + re2 (1.1.0) recaptcha (3.0.0) json recursive-open-struct (1.0.0) @@ -1055,7 +1055,7 @@ DEPENDENCIES raindrops (~> 0.18) rblineprof (~> 0.3.6) rdoc (~> 4.2) - re2 (~> 1.0.0) + re2 (~> 1.1.0) recaptcha (~> 3.0) redcarpet (~> 3.4) redis (~> 3.2) diff --git a/lib/gitlab/untrusted_regexp.rb b/lib/gitlab/untrusted_regexp.rb index 187a9e1145f..7ce2e9d636e 100644 --- a/lib/gitlab/untrusted_regexp.rb +++ b/lib/gitlab/untrusted_regexp.rb @@ -22,33 +22,9 @@ module Gitlab end def scan(text) - text = text.dup # modified in-place - results = [] - - loop do - match = scan_regexp.match(text) - break unless match - - # Ruby scan returns empty strings, not nil - groups = match.to_a.map(&:to_s) - - results << - if regexp.number_of_capturing_groups.zero? - groups[0] - else - groups[1..-1] - end - - matchsize = match.end(0) - - # No further matches - break unless matchsize.present? - - text.slice!(0, matchsize) - break unless text.present? - end - - results + matches = scan_regexp.scan(text).to_a + matches.map!(&:first) if regexp.number_of_capturing_groups.zero? + matches end def replace(text, rewrite) diff --git a/spec/lib/gitlab/ci/trace/stream_spec.rb b/spec/lib/gitlab/ci/trace/stream_spec.rb index 8b925fd4e22..ebe5af56160 100644 --- a/spec/lib/gitlab/ci/trace/stream_spec.rb +++ b/spec/lib/gitlab/ci/trace/stream_spec.rb @@ -308,6 +308,20 @@ describe Gitlab::Ci::Trace::Stream do it { is_expected.to eq('65') } end + context 'long line' do + let(:data) { 'a' * 80000 + '100%' + 'a' * 80000 } + let(:regex) { '\d+\%' } + + it { is_expected.to eq('100') } + end + + context 'many lines' do + let(:data) { "foo\n" * 80000 + "100%\n" + "foo\n" * 80000 } + let(:regex) { '\d+\%' } + + it { is_expected.to eq('100') } + end + context 'empty regex' do let(:data) { 'foo' } let(:regex) { '' } diff --git a/spec/lib/gitlab/untrusted_regexp_spec.rb b/spec/lib/gitlab/untrusted_regexp_spec.rb index 21d47b7897a..bed58d407ef 100644 --- a/spec/lib/gitlab/untrusted_regexp_spec.rb +++ b/spec/lib/gitlab/untrusted_regexp_spec.rb @@ -54,8 +54,8 @@ describe Gitlab::UntrustedRegexp do let(:regexp) { '' } let(:text) { 'foo' } - it 'returns an array of empty matches' do - is_expected.to eq(['']) + it 'returns an array of nil matches' do + is_expected.to eq([nil, nil, nil, nil]) end end @@ -63,8 +63,8 @@ describe Gitlab::UntrustedRegexp do let(:regexp) { '()' } let(:text) { 'foo' } - it 'returns an array of empty matches in an array' do - is_expected.to eq([['']]) + it 'returns an array of nil matches in an array' do + is_expected.to eq([[nil], [nil], [nil], [nil]]) end end -- cgit v1.2.1 From 32c47aa348049a2714ab34f0040e516b7921b746 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 24 Jul 2017 08:55:39 +0100 Subject: Fixed duplicate new milestone buttons in new navigation Closes #35454 --- app/assets/stylesheets/framework/nav.scss | 6 ++++++ app/views/projects/milestones/index.html.haml | 6 +++--- changelogs/unreleased/new-nav-duplicated-new-milestone-buttons.yml | 4 ++++ 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/new-nav-duplicated-new-milestone-buttons.yml diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss index 99eea97377c..35b4d77a5ab 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -182,6 +182,12 @@ } } + &.nav-controls-new-nav { + > .dropdown { + margin-right: 0; + } + } + > .btn-grouped { float: none; } diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml index a89387bc8f1..e0b29b0c2e1 100644 --- a/app/views/projects/milestones/index.html.haml +++ b/app/views/projects/milestones/index.html.haml @@ -1,7 +1,7 @@ - @no_container = true - page_title 'Milestones' -- if show_new_nav? +- if show_new_nav? && can?(current_user, :admin_milestone, @project) - content_for :breadcrumbs_extra do = link_to "New milestone", new_namespace_project_milestone_path(@project.namespace, @project), class: 'btn btn-new', title: 'New milestone' @@ -11,10 +11,10 @@ .top-area = render 'shared/milestones_filter', counts: milestone_counts(@project.milestones) - .nav-controls + .nav-controls{ class: ("nav-controls-new-nav" if show_new_nav?) } = render 'shared/milestones_sort_dropdown' - if can?(current_user, :admin_milestone, @project) - = link_to new_project_milestone_path(@project), class: 'btn btn-new', title: 'New milestone' do + = link_to new_project_milestone_path(@project), class: "btn btn-new #{("visible-xs" if show_new_nav?)}", title: 'New milestone' do New milestone .milestones diff --git a/changelogs/unreleased/new-nav-duplicated-new-milestone-buttons.yml b/changelogs/unreleased/new-nav-duplicated-new-milestone-buttons.yml new file mode 100644 index 00000000000..fcf7d8e63d6 --- /dev/null +++ b/changelogs/unreleased/new-nav-duplicated-new-milestone-buttons.yml @@ -0,0 +1,4 @@ +--- +title: Fixed duplicate new milestone buttons when new navigation is turned on +merge_request: +author: -- cgit v1.2.1 From 4ad8f12e44b81bb5a07a5365ec0fc5fdba19094e Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 24 Jul 2017 10:47:33 +0000 Subject: Fix editing project with container images present --- app/services/projects/update_service.rb | 9 ++++++++- .../unreleased/fix-gb-project-update-with-registry-images.yml | 4 ++++ spec/services/projects/update_service_spec.rb | 9 ++++++++- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/fix-gb-project-update-with-registry-images.yml diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb index 30ca95eef7a..d81035e4eba 100644 --- a/app/services/projects/update_service.rb +++ b/app/services/projects/update_service.rb @@ -5,7 +5,7 @@ module Projects return error('New visibility level not allowed!') end - if project.has_container_registry_tags? + if renaming_project_with_container_registry_tags? return error('Cannot rename project because it contains container registry tags!') end @@ -44,6 +44,13 @@ module Projects true end + def renaming_project_with_container_registry_tags? + new_path = params[:path] + + new_path && new_path != project.path && + project.has_container_registry_tags? + end + def changing_default_branch? new_branch = params[:default_branch] diff --git a/changelogs/unreleased/fix-gb-project-update-with-registry-images.yml b/changelogs/unreleased/fix-gb-project-update-with-registry-images.yml new file mode 100644 index 00000000000..a54a34c71d4 --- /dev/null +++ b/changelogs/unreleased/fix-gb-project-update-with-registry-images.yml @@ -0,0 +1,4 @@ +--- +title: Fix editing project with container images present +merge_request: 13028 +author: diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb index fd4011ad606..3ee834748df 100644 --- a/spec/services/projects/update_service_spec.rb +++ b/spec/services/projects/update_service_spec.rb @@ -103,7 +103,7 @@ describe Projects::UpdateService, '#execute', :services do end end - context 'when renaming project that contains container images' do + context 'when updating a project that contains container images' do before do stub_container_registry_config(enabled: true) stub_container_registry_tags(repository: /image/, tags: %w[rc1]) @@ -116,6 +116,13 @@ describe Projects::UpdateService, '#execute', :services do expect(result).to include(status: :error) expect(result[:message]).to match(/contains container registry tags/) end + + it 'allows to update other settings' do + result = update_project(project, admin, public_builds: true) + + expect(result[:status]).to eq :success + expect(project.reload.public_builds).to be true + end end context 'when passing invalid parameters' do -- cgit v1.2.1 From c1cb6e103d1e34ca4bcc9bcf694508b989c725ce Mon Sep 17 00:00:00 2001 From: Huang Tao Date: Mon, 24 Jul 2017 10:51:03 +0000 Subject: Add Portuguese Brazil translations of Pipeline Schedules --- locale/pt_BR/gitlab.po | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po index c4918a4c920..78cf6d2dacc 100644 --- a/locale/pt_BR/gitlab.po +++ b/locale/pt_BR/gitlab.po @@ -6,13 +6,13 @@ msgid "" msgstr "" "Project-Id-Version: gitlab 1.0.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-06-28 13:32+0200\n" +"POT-Creation-Date: 2017-07-05 08:50-0500\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2017-07-12 09:05-0400\n" -"Last-Translator: Leandro Nunes dos Santos \n" "Language-Team: Portuguese (Brazil) (https://translate.zanata.org/project/view/GitLab)\n" +"PO-Revision-Date: 2017-07-14 01:17-0400\n" +"Last-Translator: Huang Tao \n" "Language: pt-BR\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" @@ -644,6 +644,12 @@ msgstr "Todos" msgid "PipelineSchedules|Inactive" msgstr "Inativo" +msgid "PipelineSchedules|Input variable key" +msgstr "PipelineSchedules|Chave da variável de entrada" + +msgid "PipelineSchedules|Input variable value" +msgstr "PipelineSchedules|Valor da variável de entrada" + msgid "PipelineSchedules|Next Run" msgstr "Próxima Execução" @@ -653,12 +659,18 @@ msgstr "Nenhum" msgid "PipelineSchedules|Provide a short description for this pipeline" msgstr "Digite uma descrição curta para esta pipeline" +msgid "PipelineSchedules|Remove variable row" +msgstr "PipelineSchedules|Remova a linha da variável" + msgid "PipelineSchedules|Take ownership" msgstr "Tornar-se proprietário" msgid "PipelineSchedules|Target" msgstr "Destino" +msgid "PipelineSchedules|Variables" +msgstr "PipelineSchedules|Variáveis" + msgid "PipelineSheduleIntervalPattern|Custom" msgstr "Personalizado" @@ -1150,6 +1162,15 @@ msgstr "Esta etapa não possui dados suficientes para exibição." msgid "Withdraw Access Request" msgstr "Remover Requisição de Acesso" +msgid "" +"You are going to remove %{group_name}.\n" +"Removed groups CANNOT be restored!\n" +"Are you ABSOLUTELY sure?" +msgstr "" +"Você vai remover %{group_name}.\n" +"Grupos removidos NÃO PODEM ser restaurados!\n" +"Você está ABSOLUTAMENTE certo?" + msgid "" "You are going to remove %{project_name_with_namespace}.\n" "Removed project CANNOT be restored!\n" -- cgit v1.2.1 From fab1b0f1d189094ade6be5c35f03a53eeff99872 Mon Sep 17 00:00:00 2001 From: Maxim Rydkin Date: Mon, 24 Jul 2017 10:54:16 +0000 Subject: Decrease ABC threshold to 56.96 --- .rubocop.yml | 2 +- app/controllers/admin/projects_controller.rb | 15 +-- app/finders/admin/projects_finder.rb | 33 +++++ .../28202_decrease_abc_threshold_step2.yml | 4 + spec/finders/admin/projects_finder_spec.rb | 136 +++++++++++++++++++++ 5 files changed, 177 insertions(+), 13 deletions(-) create mode 100644 app/finders/admin/projects_finder.rb create mode 100644 changelogs/unreleased/28202_decrease_abc_threshold_step2.yml create mode 100644 spec/finders/admin/projects_finder_spec.rb diff --git a/.rubocop.yml b/.rubocop.yml index 9785e7626f9..f661a29d9d1 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -563,7 +563,7 @@ Style/Proc: # branches, and conditions. Metrics/AbcSize: Enabled: true - Max: 57.08 + Max: 56.96 # This cop checks if the length of a block exceeds some maximum value. Metrics/BlockLength: diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index 984d5398708..0b6cd71e651 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -3,18 +3,9 @@ class Admin::ProjectsController < Admin::ApplicationController before_action :group, only: [:show, :transfer] def index - params[:sort] ||= 'latest_activity_desc' - @projects = Project.with_statistics - @projects = @projects.in_namespace(params[:namespace_id]) if params[:namespace_id].present? - @projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present? - @projects = @projects.with_push if params[:with_push].present? - @projects = @projects.abandoned if params[:abandoned].present? - @projects = @projects.where(last_repository_check_failed: true) if params[:last_repository_check_failed].present? - @projects = @projects.non_archived unless params[:archived].present? - @projects = @projects.personal(current_user) if params[:personal].present? - @projects = @projects.search(params[:name]) if params[:name].present? - @projects = @projects.sort(@sort = params[:sort]) - @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]) + finder = Admin::ProjectsFinder.new(params: params, current_user: current_user) + @projects = finder.execute + @sort = finder.sort respond_to do |format| format.html diff --git a/app/finders/admin/projects_finder.rb b/app/finders/admin/projects_finder.rb new file mode 100644 index 00000000000..a5ba791a513 --- /dev/null +++ b/app/finders/admin/projects_finder.rb @@ -0,0 +1,33 @@ +class Admin::ProjectsFinder + attr_reader :sort, :namespace_id, :visibility_level, :with_push, + :abandoned, :last_repository_check_failed, :archived, + :personal, :name, :page, :current_user + + def initialize(params:, current_user:) + @current_user = current_user + @sort = params.fetch(:sort) { 'latest_activity_desc' } + @namespace_id = params[:namespace_id] + @visibility_level = params[:visibility_level] + @with_push = params[:with_push] + @abandoned = params[:abandoned] + @last_repository_check_failed = params[:last_repository_check_failed] + @archived = params[:archived] + @personal = params[:personal] + @name = params[:name] + @page = params[:page] + end + + def execute + items = Project.with_statistics + items = items.in_namespace(namespace_id) if namespace_id.present? + items = items.where(visibility_level: visibility_level) if visibility_level.present? + items = items.with_push if with_push.present? + items = items.abandoned if abandoned.present? + items = items.where(last_repository_check_failed: true) if last_repository_check_failed.present? + items = items.non_archived unless archived.present? + items = items.personal(current_user) if personal.present? + items = items.search(name) if name.present? + items = items.sort(sort) + items.includes(:namespace).order("namespaces.path, projects.name ASC").page(page) + end +end diff --git a/changelogs/unreleased/28202_decrease_abc_threshold_step2.yml b/changelogs/unreleased/28202_decrease_abc_threshold_step2.yml new file mode 100644 index 00000000000..b8f30b52b18 --- /dev/null +++ b/changelogs/unreleased/28202_decrease_abc_threshold_step2.yml @@ -0,0 +1,4 @@ +--- +title: Decrease ABC threshold to 56.96 +merge_request: 11227 +author: Maxim Rydkin diff --git a/spec/finders/admin/projects_finder_spec.rb b/spec/finders/admin/projects_finder_spec.rb new file mode 100644 index 00000000000..73038a4c8d6 --- /dev/null +++ b/spec/finders/admin/projects_finder_spec.rb @@ -0,0 +1,136 @@ +require 'spec_helper' + +describe Admin::ProjectsFinder do + describe '#execute' do + let(:user) { create(:user) } + let(:group) { create(:group, :public) } + + let!(:private_project) do + create(:empty_project, :private, name: 'A', path: 'A') + end + + let!(:internal_project) do + create(:empty_project, :internal, group: group, name: 'B', path: 'B') + end + + let!(:public_project) do + create(:empty_project, :public, group: group, name: 'C', path: 'C') + end + + let!(:shared_project) do + create(:empty_project, :private, name: 'D', path: 'D') + end + + let(:params) { {} } + let(:current_user) { user } + let(:project_ids_relation) { nil } + let(:finder) { described_class.new(params: params, current_user: current_user) } + + subject { finder.execute.to_a } + + context 'without a user' do + let(:current_user) { nil } + + it { is_expected.to eq([shared_project, public_project, internal_project, private_project]) } + end + + context 'with a user' do + it { is_expected.to eq([shared_project, public_project, internal_project, private_project]) } + end + + context 'filter by namespace_id' do + let(:namespace) { create(:namespace) } + let!(:project_in_namespace) { create(:empty_project, namespace: namespace) } + let(:params) { { namespace_id: namespace.id } } + + it { is_expected.to eq([project_in_namespace]) } + end + + context 'filter by visibility_level' do + before do + private_project.add_master(user) + end + + context 'private' do + let(:params) { { visibility_level: Gitlab::VisibilityLevel::PRIVATE } } + + it { is_expected.to eq([shared_project, private_project]) } + end + + context 'internal' do + let(:params) { { visibility_level: Gitlab::VisibilityLevel::INTERNAL } } + + it { is_expected.to eq([internal_project]) } + end + + context 'public' do + let(:params) { { visibility_level: Gitlab::VisibilityLevel::PUBLIC } } + + it { is_expected.to eq([public_project]) } + end + end + + context 'filter by push' do + let(:pushed_event) { create(:event, :pushed) } + let!(:project_with_push) { pushed_event.project } + let(:params) { { with_push: true } } + + it { is_expected.to eq([project_with_push]) } + end + + context 'filter by abandoned' do + before do + private_project.update(last_activity_at: Time.zone.now - 6.months - 1.minute) + end + + let(:params) { { abandoned: true } } + + it { is_expected.to eq([private_project]) } + end + + context 'filter by last_repository_check_failed' do + before do + private_project.update(last_repository_check_failed: true) + end + + let(:params) { { last_repository_check_failed: true } } + + it { is_expected.to eq([private_project]) } + end + + context 'filter by archived' do + let!(:archived_project) { create(:empty_project, :public, :archived, name: 'E', path: 'E') } + + context 'archived=false' do + let(:params) { { archived: false } } + + it { is_expected.to match_array([shared_project, public_project, internal_project, private_project]) } + end + + context 'archived=true' do + let(:params) { { archived: true } } + + it { is_expected.to match_array([archived_project, shared_project, public_project, internal_project, private_project]) } + end + end + + context 'filter by personal' do + let!(:personal_project) { create(:empty_project, namespace: user.namespace) } + let(:params) { { personal: true } } + + it { is_expected.to eq([personal_project]) } + end + + context 'filter by name' do + let(:params) { { name: 'C' } } + + it { is_expected.to eq([shared_project, public_project, private_project]) } + end + + context 'sorting' do + let(:params) { { sort: 'name_asc' } } + + it { is_expected.to eq([private_project, internal_project, public_project, shared_project]) } + end + end +end -- cgit v1.2.1 From 124ef7dd60f481ccbc8217571e1790f9fc56abe9 Mon Sep 17 00:00:00 2001 From: Jarka Kadlecova Date: Wed, 19 Jul 2017 16:45:28 +0200 Subject: Add Slack and JIRA services counts to Usage Data --- .../unreleased/31533-usage-data-projects-stats.yml | 4 +++ lib/gitlab/usage_data.rb | 15 +++++++++-- spec/lib/gitlab/usage_data_spec.rb | 29 +++++++++++++++++++--- 3 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 changelogs/unreleased/31533-usage-data-projects-stats.yml diff --git a/changelogs/unreleased/31533-usage-data-projects-stats.yml b/changelogs/unreleased/31533-usage-data-projects-stats.yml new file mode 100644 index 00000000000..11bb6118337 --- /dev/null +++ b/changelogs/unreleased/31533-usage-data-projects-stats.yml @@ -0,0 +1,4 @@ +--- +title: Add Slack and JIRA services counts to Usage Data +merge_request: +author: diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index dba071d7e47..e0ac21305a5 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -40,14 +40,13 @@ module Gitlab pages_domains: PagesDomain.count, projects: Project.count, projects_imported_from_github: Project.where(import_type: 'github').count, - projects_prometheus_active: PrometheusService.active.count, protected_branches: ProtectedBranch.count, releases: Release.count, snippets: Snippet.count, todos: Todo.count, uploads: Upload.count, web_hooks: WebHook.count - } + }.merge(services_usage) } end @@ -64,6 +63,18 @@ module Gitlab usage_data end + + def services_usage + types = { + JiraService: :projects_jira_active, + SlackService: :projects_slack_notifications_active, + SlackSlashCommandsService: :projects_slack_slash_active, + PrometheusService: :projects_prometheus_active + } + + results = Service.unscoped.where(type: types.keys, active: true).group(:type).count + results.each_with_object({}) { |(key, value), response| response[types[key.to_sym]] = value } + end end end end diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index daf097f8d51..68429d792f2 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -1,11 +1,19 @@ require 'spec_helper' describe Gitlab::UsageData do - let!(:project) { create(:empty_project) } - let!(:project2) { create(:empty_project) } - let!(:board) { create(:board, project: project) } + let(:projects) { create_list(:project, 3) } + let!(:board) { create(:board, project: projects[0]) } describe '#data' do + before do + create(:jira_service, project: projects[0]) + create(:jira_service, project: projects[1]) + create(:prometheus_service, project: projects[1]) + create(:service, project: projects[0], type: 'SlackSlashCommandsService', active: true) + create(:service, project: projects[1], type: 'SlackService', active: true) + create(:service, project: projects[2], type: 'SlackService', active: true) + end + subject { described_class.data } it "gathers usage data" do @@ -25,7 +33,7 @@ describe Gitlab::UsageData do count_data = subject[:counts] expect(count_data[:boards]).to eq(1) - expect(count_data[:projects]).to eq(2) + expect(count_data[:projects]).to eq(3) expect(count_data.keys).to match_array(%i( boards @@ -49,6 +57,9 @@ describe Gitlab::UsageData do notes projects projects_imported_from_github + projects_jira_active + projects_slack_notifications_active + projects_slack_slash_active projects_prometheus_active pages_domains protected_branches @@ -59,6 +70,16 @@ describe Gitlab::UsageData do web_hooks )) end + + it 'gathers projects data correctly' do + count_data = subject[:counts] + + expect(count_data[:projects]).to eq(3) + expect(count_data[:projects_prometheus_active]).to eq(1) + expect(count_data[:projects_jira_active]).to eq(2) + expect(count_data[:projects_slack_notifications_active]).to eq(2) + expect(count_data[:projects_slack_slash_active]).to eq(1) + end end describe '#license_usage_data' do -- cgit v1.2.1 From 8f0eef8b0023129b2e7848fe9ba62d3aaf717cc9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 24 Jul 2017 14:19:09 +0300 Subject: Update shoulda-matchers gem to 3.1.2 Signed-off-by: Dmitriy Zaporozhets --- Gemfile | 2 +- Gemfile.lock | 6 +++--- spec/spec_helper.rb | 7 +++++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 1ee44680774..df720c60bab 100644 --- a/Gemfile +++ b/Gemfile @@ -353,7 +353,7 @@ group :development, :test do end group :test do - gem 'shoulda-matchers', '~> 2.8.0', require: false + gem 'shoulda-matchers', '~> 3.1.2', require: false gem 'email_spec', '~> 1.6.0' gem 'json-schema', '~> 2.6.2' gem 'webmock', '~> 2.3.2' diff --git a/Gemfile.lock b/Gemfile.lock index b0b437ae342..6f555c830de 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -774,8 +774,8 @@ GEM sexp_processor (4.9.0) sham_rack (1.3.6) rack - shoulda-matchers (2.8.0) - activesupport (>= 3.0.0) + shoulda-matchers (3.1.2) + activesupport (>= 4.0.0) sidekiq (5.0.4) concurrent-ruby (~> 1.0) connection_pool (~> 2.2, >= 2.2.0) @@ -1084,7 +1084,7 @@ DEPENDENCIES sentry-raven (~> 2.5.3) settingslogic (~> 2.0.9) sham_rack (~> 1.3.6) - shoulda-matchers (~> 2.8.0) + shoulda-matchers (~> 3.1.2) sidekiq (~> 5.0) sidekiq-cron (~> 0.6.0) sidekiq-limit_fetch (~> 3.4) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 5d5715b10ff..e7329210896 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -148,3 +148,10 @@ FactoryGirl::SyntaxRunner.class_eval do end ActiveRecord::Migration.maintain_test_schema! + +Shoulda::Matchers.configure do |config| + config.integrate do |with| + with.test_framework :rspec + with.library :rails + end +end -- cgit v1.2.1 From 87308484fa60bfdbd5a03674cd0c619a225aa95c Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Mon, 24 Jul 2017 13:22:59 +0200 Subject: [ci skip] Add Changelog entry metrics files handling --- changelogs/unreleased/pawel-fix-metrics-files-handling.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/pawel-fix-metrics-files-handling.yml diff --git a/changelogs/unreleased/pawel-fix-metrics-files-handling.yml b/changelogs/unreleased/pawel-fix-metrics-files-handling.yml new file mode 100644 index 00000000000..cfdb4246af9 --- /dev/null +++ b/changelogs/unreleased/pawel-fix-metrics-files-handling.yml @@ -0,0 +1,4 @@ +--- +title: Fix bug causing metrics files to be truncated +merge_request: 35420 +author: -- cgit v1.2.1 From ce498df8f4a7ad55b92d17781ff60c574a901866 Mon Sep 17 00:00:00 2001 From: Pedro Moreira da Silva Date: Mon, 24 Jul 2017 13:20:17 +0100 Subject: Add UX debt label to the contribution guidelines gitlab-design#29 --- CONTRIBUTING.md | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 89e505709a3..a8499c126aa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,7 +31,7 @@ _This notice should stay as the first item in the CONTRIBUTING.MD file._ - [Issue tracker guidelines](#issue-tracker-guidelines) - [Issue weight](#issue-weight) - [Regression issues](#regression-issues) - - [Technical debt](#technical-debt) + - [Technical and UX debt](#technical-and-ux-debt) - [Stewardship](#stewardship) - [Merge requests](#merge-requests) - [Merge request guidelines](#merge-request-guidelines) @@ -344,27 +344,29 @@ addressed. [8.3 Regressions]: https://gitlab.com/gitlab-org/gitlab-ce/issues/4127 [update the notes]: https://gitlab.com/gitlab-org/release-tools/blob/master/doc/pro-tips.md#update-the-regression-issue -### Technical debt +### Technical and UX debt -In order to track things that can be improved in GitLab's codebase, we created -the ~"technical debt" label in [GitLab's issue tracker][ce-tracker]. +In order to track things that can be improved in GitLab's codebase, +we use the ~"technical debt" label in [GitLab's issue tracker][ce-tracker]. +For user experience improvements, we use the ~"UX debt" label. -This label should be added to issues that describe things that can be improved, -shortcuts that have been taken, code that needs refactoring, features that need -additional attention, and all other things that have been left behind due to -high velocity of development. +These labels should be added to issues that describe things that can be improved, +shortcuts that have been taken, features that need additional attention, and all +other things that have been left behind due to high velocity of development. +For example, code that needs refactoring should use the ~"technical debt" label, +user experience refinements should use the ~"UX debt" label. Everyone can create an issue, though you may need to ask for adding a specific label, if you do not have permissions to do it by yourself. Additional labels -can be combined with the `technical debt` label, to make it easier to schedule +can be combined with these labels, to make it easier to schedule the improvements for a release. -Issues tagged with the `technical debt` label have the same priority like issues +Issues tagged with these labels have the same priority like issues that describe a new feature to be introduced in GitLab, and should be scheduled for a release by the appropriate person. -Make sure to mention the merge request that the `technical debt` issue is -associated with in the description of the issue. +Make sure to mention the merge request that the ~"technical debt" issue or +~"UX debt" issue is associated with in the description of the issue. ### Stewardship -- cgit v1.2.1 From eafb03cfd5904893c3f05cd6a596997ccee09963 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 24 Jul 2017 15:21:16 +0300 Subject: Remove unnecessary set_flash.now from controller specs Signed-off-by: Dmitriy Zaporozhets --- spec/controllers/projects/issues_controller_spec.rb | 2 +- spec/controllers/projects/merge_requests_controller_spec.rb | 2 +- spec/controllers/sent_notifications_controller_spec.rb | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 18d0be3c103..13a39b1b260 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -806,7 +806,7 @@ describe Projects::IssuesController do delete :destroy, namespace_id: project.namespace, project_id: project, id: issue.iid expect(response).to have_http_status(302) - expect(controller).to set_flash[:notice].to(/The issue was successfully deleted\./).now + expect(controller).to set_flash[:notice].to(/The issue was successfully deleted\./) end it 'delegates the update of the todos count cache to TodoService' do diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index c193babead0..2fce4b7a85f 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -439,7 +439,7 @@ describe Projects::MergeRequestsController do delete :destroy, namespace_id: project.namespace, project_id: project, id: merge_request.iid expect(response).to have_http_status(302) - expect(controller).to set_flash[:notice].to(/The merge request was successfully deleted\./).now + expect(controller).to set_flash[:notice].to(/The merge request was successfully deleted\./) end it 'delegates the update of the todos count cache to TodoService' do diff --git a/spec/controllers/sent_notifications_controller_spec.rb b/spec/controllers/sent_notifications_controller_spec.rb index 7340a4e16c0..c8771eda313 100644 --- a/spec/controllers/sent_notifications_controller_spec.rb +++ b/spec/controllers/sent_notifications_controller_spec.rb @@ -23,7 +23,7 @@ describe SentNotificationsController, type: :controller do end it 'sets the flash message' do - expect(controller).to set_flash[:notice].to(/unsubscribed/).now + expect(controller).to set_flash[:notice].to(/unsubscribed/) end it 'redirects to the login page' do @@ -83,7 +83,7 @@ describe SentNotificationsController, type: :controller do end it 'sets the flash message' do - expect(controller).to set_flash[:notice].to(/unsubscribed/).now + expect(controller).to set_flash[:notice].to(/unsubscribed/) end it 'redirects to the issue page' do @@ -109,7 +109,7 @@ describe SentNotificationsController, type: :controller do end it 'sets the flash message' do - expect(controller).to set_flash[:notice].to(/unsubscribed/).now + expect(controller).to set_flash[:notice].to(/unsubscribed/) end it 'redirects to the merge request page' do -- cgit v1.2.1 From cc577b89706686063d4ff0d86a11c63b6570231c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 24 Jul 2017 15:33:14 +0300 Subject: Update tests for new version of shoulda-matchers Signed-off-by: Dmitriy Zaporozhets --- spec/models/notification_setting_spec.rb | 7 ++++++- spec/models/pages_domain_spec.rb | 2 +- spec/models/redirect_route_spec.rb | 2 +- spec/models/route_spec.rb | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb index cc235ad467e..74fa1c1f926 100644 --- a/spec/models/notification_setting_spec.rb +++ b/spec/models/notification_setting_spec.rb @@ -11,7 +11,12 @@ RSpec.describe NotificationSetting, type: :model do it { is_expected.to validate_presence_of(:user) } it { is_expected.to validate_presence_of(:level) } - it { is_expected.to validate_uniqueness_of(:user_id).scoped_to([:source_id, :source_type]).with_message(/already exists in source/) } + + describe 'user_id' do + before { subject.user = create(:user) } + + it { is_expected.to validate_uniqueness_of(:user_id).scoped_to([:source_type, :source_id]).with_message(/already exists in source/) } + end context "events" do let(:user) { create(:user) } diff --git a/spec/models/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb index f9d060d4e0e..d4a777a9bd9 100644 --- a/spec/models/pages_domain_spec.rb +++ b/spec/models/pages_domain_spec.rb @@ -11,7 +11,7 @@ describe PagesDomain, models: true do context 'is unique' do let(:domain) { 'my.domain.com' } - it { is_expected.to validate_uniqueness_of(:domain) } + it { is_expected.to validate_uniqueness_of(:domain).case_insensitive } end { diff --git a/spec/models/redirect_route_spec.rb b/spec/models/redirect_route_spec.rb index 71827421dd7..a97af28cb8e 100644 --- a/spec/models/redirect_route_spec.rb +++ b/spec/models/redirect_route_spec.rb @@ -11,7 +11,7 @@ describe RedirectRoute, models: true do describe 'validations' do it { is_expected.to validate_presence_of(:source) } it { is_expected.to validate_presence_of(:path) } - it { is_expected.to validate_uniqueness_of(:path) } + it { is_expected.to validate_uniqueness_of(:path).case_insensitive } end describe '.matching_path_and_descendants' do diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb index 1754253e0f2..12f7611fb28 100644 --- a/spec/models/route_spec.rb +++ b/spec/models/route_spec.rb @@ -15,7 +15,7 @@ describe Route, models: true do it { is_expected.to validate_presence_of(:source) } it { is_expected.to validate_presence_of(:path) } - it { is_expected.to validate_uniqueness_of(:path) } + it { is_expected.to validate_uniqueness_of(:path).case_insensitive } end describe 'callbacks' do -- cgit v1.2.1 From ff3d3ccb3ff00b7801c8a506453ca3f9d8ccf2ec Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 24 Jul 2017 15:45:56 +0300 Subject: Fix today day highlight in calendar Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/calendar.scss | 2 +- changelogs/unreleased/dz-fix-calendar-today.yml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/dz-fix-calendar-today.yml diff --git a/app/assets/stylesheets/framework/calendar.scss b/app/assets/stylesheets/framework/calendar.scss index 759401a7806..0ac095f7d8f 100644 --- a/app/assets/stylesheets/framework/calendar.scss +++ b/app/assets/stylesheets/framework/calendar.scss @@ -93,7 +93,7 @@ .is-selected .pika-day, .pika-day:hover, - .is-today .pika-day:hover { + .is-today .pika-day { background: $gl-primary; color: $white-light; box-shadow: none; diff --git a/changelogs/unreleased/dz-fix-calendar-today.yml b/changelogs/unreleased/dz-fix-calendar-today.yml new file mode 100644 index 00000000000..5320d8b26b5 --- /dev/null +++ b/changelogs/unreleased/dz-fix-calendar-today.yml @@ -0,0 +1,4 @@ +--- +title: Fix today day highlight in calendar +merge_request: 13048 +author: -- cgit v1.2.1 From e597fa613d4c68857f73e07533fadee66df5d012 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 20 Jul 2017 16:35:28 +0100 Subject: Add GitLab-specific concerns to code review guide --- doc/development/code_review.md | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/doc/development/code_review.md b/doc/development/code_review.md index 4ed89146072..e3f37616757 100644 --- a/doc/development/code_review.md +++ b/doc/development/code_review.md @@ -133,6 +133,55 @@ reviewee. tomorrow. When you are not able to find the right balance, ask other people about their opinion. +### GitLab-specific concerns + +GitLab is used in a lot of places. Many users use +our [Omnibus packages](https://about.gitlab.com/installation/), but some use +the [Docker images](https://docs.gitlab.com/omnibus/docker/), some are +[installed from source](https://docs.gitlab.com/ce/install/installation.html), +and there are other installation methods available. GitLab.com itself is a large +Enterprise Edition instance. This has some implications: + +1. **Query changes** should be tested to ensure that they don't result in worse + performance at the scale of GitLab.com: + 1. Generating large quantities of data locally can help. + 2. Asking for query plans from GitLab.com is the most reliable way to validate + these. +2. **Database migrations** must be: + 1. Reversible. + 2. Performant at the scale of GitLab.com - ask a maintainer to test the + migration on the staging environment if you aren't sure. + 3. Categorised correctly: + - Regular migrations run before the new code is running on the instance. + - [Post-deployment migrations](post_deployment_migrations.md) run _after_ + the new code is deployed, when the instance is configured to do that. + - [Background migrations](background_migrations.md) run in Sidekiq, and + should only be done for migrations that would take an extreme amount of + time at GitLab.com scale. +3. **Sidekiq workers** + [cannot change in a backwards-incompatible way](sidekiq_style_guide.md#removing-or-renaming-queues): + 1. Sidekiq queues are not drained before a deploy happens, so there will be + workers in the queue from the previous version of GitLab. + 2. If you need to change a method signature, try to do so across two releases, + and accept both the old and new arguments in the first of those. + 3. Similarly, if you need to remove a worker, stop it from being scheduled in + one release, then remove it in the next. This will allow existing jobs to + execute. + 4. Don't forget, not every instance will upgrade to every intermediate version + (some people may go from X.1.0 to X.10.0, or even try bigger upgrades!), so + try to be liberal in accepting the old format if it is cheap to do so. +4. **Cached values** may persist across releases. If you are changing the type a + cached value returns (say, from a string or nil to an array), change the + cache key at the same time. +5. **Settings** should be added as a + [last resort](https://about.gitlab.com/handbook/product/#convention-over-configuration). + If you're adding a new setting in `gitlab.yml`: + 1. Try to avoid that, and add to `ApplicationSetting` instead. + 2. Ensure that it is also + [added to Omnibus](https://docs.gitlab.com/omnibus/settings/gitlab.yml.html#adding-a-new-setting-to-gitlab-yml). +6. **Filesystem access** can be slow, so try to avoid + [shared files](shared_files.md) when an alternative solution is available. + ### Credits Largely based on the [thoughtbot code review guide]. -- cgit v1.2.1 From a8b33d7b5db99f47000316a8dc167106214ca4f8 Mon Sep 17 00:00:00 2001 From: Emilien Mottet Date: Mon, 24 Jul 2017 17:04:54 +0200 Subject: fix conflict pluralized --- app/assets/javascripts/merge_conflicts/merge_conflict_store.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js index c4e379a4a0b..8be7314ded8 100644 --- a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js +++ b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js @@ -175,7 +175,7 @@ import Cookies from 'js-cookie'; getConflictsCountText() { const count = this.getConflictsCount(); - const text = count ? 'conflicts' : 'conflict'; + const text = count > 1 ? 'conflicts' : 'conflict'; return `${count} ${text}`; }, -- cgit v1.2.1 From f9bb6ccea87cf9420a524da53bb11c8a6b119154 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 24 Jul 2017 11:20:52 -0400 Subject: Use `match_array` rather than `eq` in ProjectsFinder spec --- spec/finders/admin/projects_finder_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/finders/admin/projects_finder_spec.rb b/spec/finders/admin/projects_finder_spec.rb index 73038a4c8d6..296d6c51d04 100644 --- a/spec/finders/admin/projects_finder_spec.rb +++ b/spec/finders/admin/projects_finder_spec.rb @@ -31,11 +31,11 @@ describe Admin::ProjectsFinder do context 'without a user' do let(:current_user) { nil } - it { is_expected.to eq([shared_project, public_project, internal_project, private_project]) } + it { is_expected.to match_array([shared_project, public_project, internal_project, private_project]) } end context 'with a user' do - it { is_expected.to eq([shared_project, public_project, internal_project, private_project]) } + it { is_expected.to match_array([shared_project, public_project, internal_project, private_project]) } end context 'filter by namespace_id' do @@ -54,7 +54,7 @@ describe Admin::ProjectsFinder do context 'private' do let(:params) { { visibility_level: Gitlab::VisibilityLevel::PRIVATE } } - it { is_expected.to eq([shared_project, private_project]) } + it { is_expected.to match_array([shared_project, private_project]) } end context 'internal' do @@ -124,7 +124,7 @@ describe Admin::ProjectsFinder do context 'filter by name' do let(:params) { { name: 'C' } } - it { is_expected.to eq([shared_project, public_project, private_project]) } + it { is_expected.to match_array([shared_project, public_project, private_project]) } end context 'sorting' do -- cgit v1.2.1 From fef5a4fddd6ba0d152c553ab2b1667497400c062 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Mon, 24 Jul 2017 17:21:05 +0200 Subject: How to Merge to external File --- app/assets/javascripts/how_to_merge.js | 12 ++++++++++++ app/views/projects/merge_requests/_how_to_merge.html.haml | 14 +++----------- config/webpack.config.js | 1 + 3 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 app/assets/javascripts/how_to_merge.js diff --git a/app/assets/javascripts/how_to_merge.js b/app/assets/javascripts/how_to_merge.js new file mode 100644 index 00000000000..f739db751a6 --- /dev/null +++ b/app/assets/javascripts/how_to_merge.js @@ -0,0 +1,12 @@ +document.addEventListener('DOMContentLoaded', () => { + const modal = $('#modal_merge_info').modal({ + modal: true, + show: false, + }); + $('.how_to_merge_link').bind('click', () => { + modal.show(); + }); + $('.modal-header .close').bind('click', () => { + modal.hide(); + }); +}); diff --git a/app/views/projects/merge_requests/_how_to_merge.html.haml b/app/views/projects/merge_requests/_how_to_merge.html.haml index 766cb272bec..917ec7fdbda 100644 --- a/app/views/projects/merge_requests/_how_to_merge.html.haml +++ b/app/views/projects/merge_requests/_how_to_merge.html.haml @@ -1,3 +1,6 @@ +- content_for :page_specific_javascripts do + = webpack_bundle_tag('how_to_merge') + #modal_merge_info.modal .modal-dialog .modal-content @@ -50,14 +53,3 @@ = succeed '.' do You can also checkout merge requests locally by = link_to 'following these guidelines', help_page_path('user/project/merge_requests/index.md', anchor: "checkout-merge-requests-locally"), target: '_blank', rel: 'noopener noreferrer' - -:javascript - $(function(){ - var modal = $('#modal_merge_info').modal({modal: true, show:false}); - $('.how_to_merge_link').bind("click", function(){ - modal.show(); - }); - $('.modal-header .close').bind("click", function(){ - modal.hide(); - }) - }) diff --git a/config/webpack.config.js b/config/webpack.config.js index a7d92bc53b7..f08daa2fddb 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -42,6 +42,7 @@ var config = { group: './group.js', groups: './groups/index.js', groups_list: './groups_list.js', + how_to_merge: './how_to_merge.js', issue_show: './issue_show/index.js', integrations: './integrations', job_details: './jobs/job_details_bundle.js', -- cgit v1.2.1 From ccac2abeba419f16029c40f29063f1812c9e159c Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Mon, 24 Jul 2017 11:35:54 +0100 Subject: Don't treat anonymous users as owners when group has pending invites The `members` table can have entries where `user_id: nil`, because people can invite group members by email. We never want to include those as members, because it might cause confusion with the anonymous (logged out) user. --- app/models/group.rb | 6 +++++- app/policies/project_policy.rb | 3 ++- ...444-error-500-viewing-notes-with-anonymous-user.yml | 4 ++++ spec/models/ability_spec.rb | 8 ++++---- spec/models/group_spec.rb | 4 ++++ spec/policies/project_policy_spec.rb | 18 ++++++++++++++++++ 6 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 changelogs/unreleased/35444-error-500-viewing-notes-with-anonymous-user.yml diff --git a/app/models/group.rb b/app/models/group.rb index dfa4e8adedd..bd5735ed82e 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -167,10 +167,14 @@ class Group < Namespace end def has_owner?(user) + return false unless user + members_with_parents.owners.where(user_id: user).any? end def has_master?(user) + return false unless user + members_with_parents.masters.where(user_id: user).any? end @@ -212,7 +216,7 @@ class Group < Namespace end def members_with_parents - GroupMember.non_request.where(source_id: ancestors.pluck(:id).push(id)) + GroupMember.active.where(source_id: ancestors.pluck(:id).push(id)).where.not(user_id: nil) end def users_with_parents diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index d27bbf2948c..0133091db57 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -10,7 +10,8 @@ class ProjectPolicy < BasePolicy desc "User is a project owner" condition :owner do - @user && project.owner == @user || (project.group && project.group.has_owner?(@user)) + (project.owner.present? && project.owner == @user) || + project.group&.has_owner?(@user) end desc "Project has public builds enabled" diff --git a/changelogs/unreleased/35444-error-500-viewing-notes-with-anonymous-user.yml b/changelogs/unreleased/35444-error-500-viewing-notes-with-anonymous-user.yml new file mode 100644 index 00000000000..9b8bc1d0d99 --- /dev/null +++ b/changelogs/unreleased/35444-error-500-viewing-notes-with-anonymous-user.yml @@ -0,0 +1,4 @@ +--- +title: Fix anonymous access to public projects in groups with pending invites +merge_request: +author: diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index dc7a0d80752..58f1a620ab4 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -98,7 +98,7 @@ describe Ability, lib: true do user2 = build(:user, external: true) users = [user1, user2] - expect(project).to receive(:owner).twice.and_return(user1) + expect(project).to receive(:owner).at_least(:once).and_return(user1) expect(described_class.users_that_can_read_project(users, project)) .to eq([user1]) @@ -109,7 +109,7 @@ describe Ability, lib: true do user2 = build(:user, external: true) users = [user1, user2] - expect(project.team).to receive(:members).twice.and_return([user1]) + expect(project.team).to receive(:members).at_least(:once).and_return([user1]) expect(described_class.users_that_can_read_project(users, project)) .to eq([user1]) @@ -140,7 +140,7 @@ describe Ability, lib: true do user2 = build(:user, external: true) users = [user1, user2] - expect(project).to receive(:owner).twice.and_return(user1) + expect(project).to receive(:owner).at_least(:once).and_return(user1) expect(described_class.users_that_can_read_project(users, project)) .to eq([user1]) @@ -151,7 +151,7 @@ describe Ability, lib: true do user2 = build(:user, external: true) users = [user1, user2] - expect(project.team).to receive(:members).twice.and_return([user1]) + expect(project.team).to receive(:members).at_least(:once).and_return([user1]) expect(described_class.users_that_can_read_project(users, project)) .to eq([user1]) diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 770176451fe..d8e868265ed 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -236,6 +236,7 @@ describe Group, models: true do describe '#has_owner?' do before do @members = setup_group_members(group) + create(:group_member, :invited, :owner, group: group) end it { expect(group.has_owner?(@members[:owner])).to be_truthy } @@ -244,11 +245,13 @@ describe Group, models: true do it { expect(group.has_owner?(@members[:reporter])).to be_falsey } it { expect(group.has_owner?(@members[:guest])).to be_falsey } it { expect(group.has_owner?(@members[:requester])).to be_falsey } + it { expect(group.has_owner?(nil)).to be_falsey } end describe '#has_master?' do before do @members = setup_group_members(group) + create(:group_member, :invited, :master, group: group) end it { expect(group.has_master?(@members[:owner])).to be_falsey } @@ -257,6 +260,7 @@ describe Group, models: true do it { expect(group.has_master?(@members[:reporter])).to be_falsey } it { expect(group.has_master?(@members[:guest])).to be_falsey } it { expect(group.has_master?(@members[:requester])).to be_falsey } + it { expect(group.has_master?(nil)).to be_falsey } end describe '#lfs_enabled?' do diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index 4ed788af811..f244975e597 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -127,6 +127,24 @@ describe ProjectPolicy, models: true do end end + context 'when a project has pending invites, and the current user is anonymous' do + let(:group) { create(:group, :public) } + let(:project) { create(:empty_project, :public, namespace: group) } + let(:user_permissions) { [:create_project, :create_issue, :create_note, :upload_file] } + let(:anonymous_permissions) { guest_permissions - user_permissions } + + subject { described_class.new(nil, project) } + + before do + create(:group_member, :invited, group: group) + end + + it 'does not grant owner access' do + expect_allowed(*anonymous_permissions) + expect_disallowed(*user_permissions) + end + end + context 'abilities for non-public projects' do let(:project) { create(:empty_project, namespace: owner.namespace) } -- cgit v1.2.1 From 6039fa610c43fea950a96628ae26158c475d42b2 Mon Sep 17 00:00:00 2001 From: Chenjerai Katanda Date: Mon, 24 Jul 2017 16:20:49 +0000 Subject: Add instructions for enabling the `pg_trgm` extension in the production db. As a workaround to [a fault during HA setup](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/2501). --- doc/administration/high_availability/database.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/administration/high_availability/database.md b/doc/administration/high_availability/database.md index da9687aa849..ca6d8d2de67 100644 --- a/doc/administration/high_availability/database.md +++ b/doc/administration/high_availability/database.md @@ -97,9 +97,12 @@ If you use a cloud-managed service, or provide your own PostgreSQL: Enter new password: Enter it again: ``` - -1. Enable the `pg_trgm` extension: +1. Exit from editing `template1` prompt by typing `\q` and Enter. +1. Enable the `pg_trgm` extension within the `gitlabhq_production` database: + ``` + gitlab-psql -d gitlabhq_production + CREATE EXTENSION pg_trgm; # Output: -- cgit v1.2.1 From 3a0b9e06e1dd5f6141a6f04dd2b39dbb803c07f1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 24 Jul 2017 19:26:15 +0300 Subject: Adjust tests to work with latest shoulda gem Signed-off-by: Dmitriy Zaporozhets --- spec/models/list_spec.rb | 6 ------ spec/models/notification_setting_spec.rb | 4 +++- spec/models/user_spec.rb | 4 +++- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/spec/models/list_spec.rb b/spec/models/list_spec.rb index db2c2619968..a6cc01bea5f 100644 --- a/spec/models/list_spec.rb +++ b/spec/models/list_spec.rb @@ -13,12 +13,6 @@ describe List do it { is_expected.to validate_presence_of(:position) } it { is_expected.to validate_numericality_of(:position).only_integer.is_greater_than_or_equal_to(0) } - it 'validates uniqueness of label scoped to board_id' do - create(:list) - - expect(subject).to validate_uniqueness_of(:label_id).scoped_to(:board_id) - end - context 'when list_type is set to closed' do subject { described_class.new(list_type: :closed) } diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb index 74fa1c1f926..76a7b07949f 100644 --- a/spec/models/notification_setting_spec.rb +++ b/spec/models/notification_setting_spec.rb @@ -13,7 +13,9 @@ RSpec.describe NotificationSetting, type: :model do it { is_expected.to validate_presence_of(:level) } describe 'user_id' do - before { subject.user = create(:user) } + before do + subject.user = create(:user) + end it { is_expected.to validate_uniqueness_of(:user_id).scoped_to([:source_type, :source_id]).with_message(/already exists in source/) } end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index a1d6d7e6e0b..20bdb7e37da 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -114,7 +114,9 @@ describe User, models: true do end it 'validates uniqueness' do - expect(subject).to validate_uniqueness_of(:username).case_insensitive + user = build(:user) + + expect(user).to validate_uniqueness_of(:username).case_insensitive end end -- cgit v1.2.1 From 52b8a0db689c2df968776a1f369ea6a6db245d39 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Mon, 24 Jul 2017 17:36:52 +0000 Subject: Resolve "Lazy load images on the Frontend" --- app/assets/javascripts/copy_as_gfm.js | 10 ++- app/assets/javascripts/lazy_loader.js | 76 ++++++++++++++++++++++ app/assets/javascripts/main.js | 6 ++ app/assets/stylesheets/framework/avatar.scss | 2 + app/assets/stylesheets/framework/typography.scss | 11 +++- app/assets/stylesheets/framework/variables.scss | 4 +- app/helpers/avatars_helper.rb | 9 +-- app/helpers/emails_helper.rb | 4 +- app/helpers/lazy_image_tag_helper.rb | 24 +++++++ app/helpers/version_check_helper.rb | 2 +- app/models/concerns/cache_markdown_field.rb | 2 +- app/views/projects/blob/viewers/_image.html.haml | 2 +- app/views/projects/diffs/viewers/_image.html.haml | 14 ++-- .../34361-lazy-load-images-on-the-frontend.yml | 4 ++ doc/development/fe_guide/performance.md | 12 ++++ features/steps/project/wiki.rb | 2 +- lib/banzai/filter/gollum_tags_filter.rb | 2 +- lib/banzai/filter/image_lazy_load_filter.rb | 16 +++++ lib/banzai/filter/image_link_filter.rb | 2 +- lib/banzai/filter/relative_link_filter.rb | 1 + lib/banzai/pipeline/gfm_pipeline.rb | 1 + spec/features/admin/admin_appearance_spec.rb | 4 +- spec/features/markdown_spec.rb | 2 +- .../uploads/user_uploads_avatar_to_group_spec.rb | 2 +- .../uploads/user_uploads_avatar_to_profile_spec.rb | 2 +- spec/helpers/application_helper_spec.rb | 7 +- spec/helpers/avatars_helper_spec.rb | 48 +++++--------- spec/javascripts/lazy_loader_spec.js | 57 ++++++++++++++++ spec/lib/banzai/filter/gollum_tags_filter_spec.rb | 4 +- .../banzai/filter/image_lazy_load_filter_spec.rb | 19 ++++++ spec/support/matchers/markdown_matchers.rb | 4 +- 31 files changed, 287 insertions(+), 68 deletions(-) create mode 100644 app/assets/javascripts/lazy_loader.js create mode 100644 app/helpers/lazy_image_tag_helper.rb create mode 100644 changelogs/unreleased/34361-lazy-load-images-on-the-frontend.yml create mode 100644 lib/banzai/filter/image_lazy_load_filter.rb create mode 100644 spec/javascripts/lazy_loader_spec.js create mode 100644 spec/lib/banzai/filter/image_lazy_load_filter_spec.rb diff --git a/app/assets/javascripts/copy_as_gfm.js b/app/assets/javascripts/copy_as_gfm.js index ba9d9a3e1f7..54257531284 100644 --- a/app/assets/javascripts/copy_as_gfm.js +++ b/app/assets/javascripts/copy_as_gfm.js @@ -1,6 +1,7 @@ /* eslint-disable class-methods-use-this, object-shorthand, no-unused-vars, no-use-before-define, no-new, max-len, no-restricted-syntax, guard-for-in, no-continue */ import './lib/utils/common_utils'; +import { placeholderImage } from './lazy_loader'; const gfmRules = { // The filters referenced in lib/banzai/pipeline/gfm_pipeline.rb convert @@ -56,6 +57,11 @@ const gfmRules = { return text; }, }, + ImageLazyLoadFilter: { + 'img'(el, text) { + return `![${el.getAttribute('alt')}](${el.getAttribute('src')})`; + }, + }, VideoLinkFilter: { '.video-container'(el) { const videoEl = el.querySelector('video'); @@ -163,7 +169,9 @@ const gfmRules = { return text.trim().split('\n').map(s => `> ${s}`.trim()).join('\n'); }, 'img'(el) { - return `![${el.getAttribute('alt')}](${el.getAttribute('src')})`; + const imageSrc = el.src; + const imageUrl = imageSrc && imageSrc !== placeholderImage ? imageSrc : (el.dataset.src || ''); + return `![${el.getAttribute('alt')}](${imageUrl})`; }, 'a.anchor'(el, text) { // Don't render a Markdown link for the anchor link inside a heading diff --git a/app/assets/javascripts/lazy_loader.js b/app/assets/javascripts/lazy_loader.js new file mode 100644 index 00000000000..3d64b121fa7 --- /dev/null +++ b/app/assets/javascripts/lazy_loader.js @@ -0,0 +1,76 @@ +/* eslint-disable one-export, one-var, one-var-declaration-per-line */ + +import _ from 'underscore'; + +export const placeholderImage = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=='; +const SCROLL_THRESHOLD = 300; + +export default class LazyLoader { + constructor(options = {}) { + this.lazyImages = []; + this.observerNode = options.observerNode || '#content-body'; + + const throttledScrollCheck = _.throttle(() => this.scrollCheck(), 300); + const debouncedElementsInView = _.debounce(() => this.checkElementsInView(), 300); + + window.addEventListener('scroll', throttledScrollCheck); + window.addEventListener('resize', debouncedElementsInView); + + const scrollContainer = options.scrollContainer || window; + scrollContainer.addEventListener('load', () => this.loadCheck()); + } + searchLazyImages() { + this.lazyImages = [].slice.call(document.querySelectorAll('.lazy')); + this.checkElementsInView(); + } + startContentObserver() { + const contentNode = document.querySelector(this.observerNode) || document.querySelector('body'); + + if (contentNode) { + const observer = new MutationObserver(() => this.searchLazyImages()); + + observer.observe(contentNode, { + childList: true, + subtree: true, + }); + } + } + loadCheck() { + this.searchLazyImages(); + this.startContentObserver(); + } + scrollCheck() { + requestAnimationFrame(() => this.checkElementsInView()); + } + checkElementsInView() { + const scrollTop = pageYOffset; + const visHeight = scrollTop + innerHeight + SCROLL_THRESHOLD; + let imgBoundRect, imgTop, imgBound; + + // Loading Images which are in the current viewport or close to them + this.lazyImages = this.lazyImages.filter((selectedImage) => { + if (selectedImage.getAttribute('data-src')) { + imgBoundRect = selectedImage.getBoundingClientRect(); + + imgTop = scrollTop + imgBoundRect.top; + imgBound = imgTop + imgBoundRect.height; + + if (scrollTop < imgBound && visHeight > imgTop) { + LazyLoader.loadImage(selectedImage); + return false; + } + + return true; + } + return false; + }); + } + static loadImage(img) { + if (img.getAttribute('data-src')) { + img.setAttribute('src', img.getAttribute('data-src')); + img.removeAttribute('data-src'); + img.classList.remove('lazy'); + img.classList.add('js-lazy-loaded'); + } + } +} diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 26c67fb721c..44b502cdab3 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -109,6 +109,7 @@ import './label_manager'; import './labels'; import './labels_select'; import './layout_nav'; +import LazyLoader from './lazy_loader'; import './line_highlighter'; import './logo'; import './member_expiration_date'; @@ -166,6 +167,11 @@ window.addEventListener('load', function onLoad() { gl.utils.handleLocationHash(); }, false); +gl.lazyLoader = new LazyLoader({ + scrollContainer: window, + observerNode: '#content-body' +}); + $(function () { var $body = $('body'); var $document = $(document); diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss index 06f7af33f94..0dfa7a31d31 100644 --- a/app/assets/stylesheets/framework/avatar.scss +++ b/app/assets/stylesheets/framework/avatar.scss @@ -35,6 +35,8 @@ width: 40px; height: 40px; padding: 0; + background: $avatar-background; + overflow: hidden; &.avatar-inline { float: none; diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index 8a58c1ed567..befd8133be0 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -11,8 +11,17 @@ } img { - max-width: 100%; + /*max-width: 100%;*/ margin: 0 0 8px; + min-width: 200px; + min-height: 100px; + background-color: $gray-lightest; + } + + img.js-lazy-loaded { + min-width: none; + min-height: none; + background-color: none; } p a:not(.no-attachment-icon) img { diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 7016208f624..cf0a1ad57d0 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -379,7 +379,9 @@ $issue-boards-card-shadow: rgba(186, 186, 186, 0.5); * Avatar */ $avatar_radius: 50%; -$avatar-border: $border-color; +$avatar-border: $gray-normal; +$avatar-border-hover: $gray-darker; +$avatar-background: $gray-lightest; $gl-avatar-size: 40px; /* diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb index bbe7f3c8fb4..0e068d4b51c 100644 --- a/app/helpers/avatars_helper.rb +++ b/app/helpers/avatars_helper.rb @@ -11,17 +11,12 @@ module AvatarsHelper def user_avatar_without_link(options = {}) avatar_size = options[:size] || 16 user_name = options[:user].try(:name) || options[:user_name] - css_class = options[:css_class] || '' avatar_url = options[:url] || avatar_icon(options[:user] || options[:user_email], avatar_size) data_attributes = { container: 'body' } - if options[:lazy] - data_attributes[:src] = avatar_url - end - image_tag( - options[:lazy] ? '' : avatar_url, - class: "avatar has-tooltip s#{avatar_size} #{css_class}", + avatar_url, + class: %W[avatar has-tooltip s#{avatar_size}].push(*options[:css_class]), alt: "#{user_name}'s avatar", title: user_name, data: data_attributes diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb index fdbca789d21..5f11fe62030 100644 --- a/app/helpers/emails_helper.rb +++ b/app/helpers/emails_helper.rb @@ -61,8 +61,8 @@ module EmailsHelper else image_tag( image_url('mailers/gitlab_header_logo.gif'), - size: "55x50", - alt: "GitLab" + size: '55x50', + alt: 'GitLab' ) end end diff --git a/app/helpers/lazy_image_tag_helper.rb b/app/helpers/lazy_image_tag_helper.rb new file mode 100644 index 00000000000..2c5619ac41b --- /dev/null +++ b/app/helpers/lazy_image_tag_helper.rb @@ -0,0 +1,24 @@ +module LazyImageTagHelper + def placeholder_image + "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" + end + + # Override the default ActionView `image_tag` helper to support lazy-loading + def image_tag(source, options = {}) + options = options.symbolize_keys + + unless options.delete(:lazy) == false + options[:data] ||= {} + options[:data][:src] = path_to_image(source) + options[:class] ||= "" + options[:class] << " lazy" + + source = placeholder_image + end + + super(source, options) + end + + # Required for Banzai::Filter::ImageLazyLoadFilter + module_function :placeholder_image +end diff --git a/app/helpers/version_check_helper.rb b/app/helpers/version_check_helper.rb index 456598b4c28..3b175251446 100644 --- a/app/helpers/version_check_helper.rb +++ b/app/helpers/version_check_helper.rb @@ -2,7 +2,7 @@ module VersionCheckHelper def version_status_badge if Rails.env.production? && current_application_settings.version_check_enabled image_url = VersionCheck.new.url - image_tag image_url, class: 'js-version-status-badge' + image_tag image_url, class: 'js-version-status-badge', lazy: false end end end diff --git a/app/models/concerns/cache_markdown_field.rb b/app/models/concerns/cache_markdown_field.rb index 95152dcd68c..48547a938fc 100644 --- a/app/models/concerns/cache_markdown_field.rb +++ b/app/models/concerns/cache_markdown_field.rb @@ -11,7 +11,7 @@ module CacheMarkdownField extend ActiveSupport::Concern # Increment this number every time the renderer changes its output - CACHE_VERSION = 1 + CACHE_VERSION = 2 # changes to these attributes cause the cache to be invalidates INVALIDATED_BY = %w[author project].freeze diff --git a/app/views/projects/blob/viewers/_image.html.haml b/app/views/projects/blob/viewers/_image.html.haml index 640d59b3174..1650aa8197f 100644 --- a/app/views/projects/blob/viewers/_image.html.haml +++ b/app/views/projects/blob/viewers/_image.html.haml @@ -1,2 +1,2 @@ .file-content.image_file - %img{ src: blob_raw_url, alt: viewer.blob.name } + %img{ 'data-src': blob_raw_url, alt: viewer.blob.name } diff --git a/app/views/projects/diffs/viewers/_image.html.haml b/app/views/projects/diffs/viewers/_image.html.haml index 33d3dcbeafa..05877ceed3d 100644 --- a/app/views/projects/diffs/viewers/_image.html.haml +++ b/app/views/projects/diffs/viewers/_image.html.haml @@ -8,7 +8,7 @@ .image %span.wrap .frame{ class: (diff_file.deleted_file? ? 'deleted' : 'added') } - %img{ src: blob_raw_path, alt: diff_file.file_path } + %img{ 'data-src': blob_raw_path, alt: diff_file.file_path } %p.image-info= number_to_human_size(blob.size) - else .image @@ -16,7 +16,7 @@ %span.wrap .frame.deleted %a{ href: project_blob_path(@project, tree_join(diff_file.old_content_sha, diff_file.old_path)) } - %img{ src: old_blob_raw_path, alt: diff_file.old_path } + %img{ 'data-src': old_blob_raw_path, alt: diff_file.old_path } %p.image-info.hide %span.meta-filesize= number_to_human_size(old_blob.size) | @@ -28,7 +28,7 @@ %span.wrap .frame.added %a{ href: project_blob_path(@project, tree_join(diff_file.content_sha, diff_file.new_path)) } - %img{ src: blob_raw_path, alt: diff_file.new_path } + %img{ 'data-src': blob_raw_path, alt: diff_file.new_path } %p.image-info.hide %span.meta-filesize= number_to_human_size(blob.size) | @@ -41,10 +41,10 @@ .swipe.view.hide .swipe-frame .frame.deleted - %img{ src: old_blob_raw_path, alt: diff_file.old_path } + %img{ 'data-src': old_blob_raw_path, alt: diff_file.old_path } .swipe-wrap .frame.added - %img{ src: blob_raw_path, alt: diff_file.new_path } + %img{ 'data-src': blob_raw_path, alt: diff_file.new_path } %span.swipe-bar %span.top-handle %span.bottom-handle @@ -52,9 +52,9 @@ .onion-skin.view.hide .onion-skin-frame .frame.deleted - %img{ src: old_blob_raw_path, alt: diff_file.old_path } + %img{ 'data-src': old_blob_raw_path, alt: diff_file.old_path } .frame.added - %img{ src: blob_raw_path, alt: diff_file.new_path } + %img{ 'data-src': blob_raw_path, alt: diff_file.new_path } .controls .transparent .drag-track diff --git a/changelogs/unreleased/34361-lazy-load-images-on-the-frontend.yml b/changelogs/unreleased/34361-lazy-load-images-on-the-frontend.yml new file mode 100644 index 00000000000..d188a558d38 --- /dev/null +++ b/changelogs/unreleased/34361-lazy-load-images-on-the-frontend.yml @@ -0,0 +1,4 @@ +--- +title: Lazy load images for better Frontend performance +merge_request: 12503 +author: diff --git a/doc/development/fe_guide/performance.md b/doc/development/fe_guide/performance.md index 2ddcbe13afa..f25313d6cff 100644 --- a/doc/development/fe_guide/performance.md +++ b/doc/development/fe_guide/performance.md @@ -23,6 +23,18 @@ controlled by the server. 1. The backend code will most likely be using etags. You do not and should not check for status `304 Not Modified`. The browser will transform it for you. +### Lazy Loading + +To improve the time to first render we are using lazy loading for images. This works by setting +the actual image source on the `data-src` attribute. After the HTML is rendered and JavaScript is loaded, +the value of `data-src` will be moved to `src` automatically if the image is in the current viewport. + +* Prepare images in HTML for lazy loading by renaming the `src` attribute to `data-src` +* If you are using the Rails `image_tag` helper, all images will be lazy-loaded by default unless `lazy: false` is provided. + +If you are asynchronously adding content which contains lazy images then you need to call the function +`gl.lazyLoader.searchLazyImages()` which will search for lazy images and load them if needed. + ## Reducing Asset Footprint ### Page-specific JavaScript diff --git a/features/steps/project/wiki.rb b/features/steps/project/wiki.rb index a2f5d2e1515..9d38939378d 100644 --- a/features/steps/project/wiki.rb +++ b/features/steps/project/wiki.rb @@ -114,7 +114,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps end step 'Image should be shown on the page' do - expect(page).to have_xpath("//img[@src=\"image.jpg\"]") + expect(page).to have_xpath("//img[@data-src=\"image.jpg\"]") end step 'I click on image link' do diff --git a/lib/banzai/filter/gollum_tags_filter.rb b/lib/banzai/filter/gollum_tags_filter.rb index 0ea4eeaed5b..2e259904673 100644 --- a/lib/banzai/filter/gollum_tags_filter.rb +++ b/lib/banzai/filter/gollum_tags_filter.rb @@ -118,7 +118,7 @@ module Banzai end if path - content_tag(:img, nil, src: path, class: 'gfm') + content_tag(:img, nil, data: { src: path }, class: 'gfm') end end diff --git a/lib/banzai/filter/image_lazy_load_filter.rb b/lib/banzai/filter/image_lazy_load_filter.rb new file mode 100644 index 00000000000..7a81d583b82 --- /dev/null +++ b/lib/banzai/filter/image_lazy_load_filter.rb @@ -0,0 +1,16 @@ +module Banzai + module Filter + # HTML filter that moves the value of the src attribute to the data-src attribute so it can be lazy loaded + class ImageLazyLoadFilter < HTML::Pipeline::Filter + def call + doc.xpath('descendant-or-self::img').each do |img| + img['class'] ||= '' << 'lazy' + img['data-src'] = img['src'] + img['src'] = LazyImageTagHelper.placeholder_image + end + + doc + end + end + end +end diff --git a/lib/banzai/filter/image_link_filter.rb b/lib/banzai/filter/image_link_filter.rb index 123c92fd250..f318c425962 100644 --- a/lib/banzai/filter/image_link_filter.rb +++ b/lib/banzai/filter/image_link_filter.rb @@ -10,7 +10,7 @@ module Banzai link = doc.document.create_element( 'a', class: 'no-attachment-icon', - href: img['src'], + href: img['data-src'] || img['src'], target: '_blank', rel: 'noopener noreferrer' ) diff --git a/lib/banzai/filter/relative_link_filter.rb b/lib/banzai/filter/relative_link_filter.rb index 9e23c8f8c55..c2fed57a0d8 100644 --- a/lib/banzai/filter/relative_link_filter.rb +++ b/lib/banzai/filter/relative_link_filter.rb @@ -22,6 +22,7 @@ module Banzai doc.css('img, video').each do |el| process_link_attr el.attribute('src') + process_link_attr el.attribute('data-src') end doc diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb index bd4d1aa9ff8..3208abfc538 100644 --- a/lib/banzai/pipeline/gfm_pipeline.rb +++ b/lib/banzai/pipeline/gfm_pipeline.rb @@ -16,6 +16,7 @@ module Banzai Filter::MathFilter, Filter::UploadLinkFilter, Filter::VideoLinkFilter, + Filter::ImageLazyLoadFilter, Filter::ImageLinkFilter, Filter::EmojiFilter, Filter::TableOfContentsFilter, diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb index b9e361328df..2f90f668e89 100644 --- a/spec/features/admin/admin_appearance_spec.rb +++ b/spec/features/admin/admin_appearance_spec.rb @@ -63,11 +63,11 @@ feature 'Admin Appearance', feature: true do end def logo_selector - '//img[@src^="/uploads/-/system/appearance/logo"]' + '//img[data-src^="/uploads/-/system/appearance/logo"]' end def header_logo_selector - '//img[@src^="/uploads/-/system/appearance/header_logo"]' + '//img[data-src^="/uploads/-/system/appearance/header_logo"]' end def logo_fixture diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb index 534be3ab5a7..1aca3e3a9fd 100644 --- a/spec/features/markdown_spec.rb +++ b/spec/features/markdown_spec.rb @@ -100,7 +100,7 @@ describe 'GitLab Markdown', feature: true do end it 'permits img elements' do - expect(doc).to have_selector('img[src*="smile.png"]') + expect(doc).to have_selector('img[data-src*="smile.png"]') end it 'permits br elements' do diff --git a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb index 5843f18d89f..8188d4c79f4 100644 --- a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb +++ b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb @@ -18,7 +18,7 @@ feature 'User uploads avatar to group', feature: true do visit group_path(group) - expect(page).to have_selector(%Q(img[src$="/uploads/-/system/group/avatar/#{group.id}/dk.png"])) + expect(page).to have_selector(%Q(img[data-src$="/uploads/-/system/group/avatar/#{group.id}/dk.png"])) # Cheating here to verify something that isn't user-facing, but is important expect(group.reload.avatar.file).to exist diff --git a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb index e8171dcaeb0..2628508afe8 100644 --- a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb +++ b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb @@ -16,7 +16,7 @@ feature 'User uploads avatar to profile', feature: true do visit user_path(user) - expect(page).to have_selector(%Q(img[src$="/uploads/-/system/user/avatar/#{user.id}/dk.png"])) + expect(page).to have_selector(%Q(img[data-src$="/uploads/-/system/user/avatar/#{user.id}/dk.png"])) # Cheating here to verify something that isn't user-facing, but is important expect(user.reload.avatar.file).to exist diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index f5e139685e8..ac5a58ac189 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -62,13 +62,13 @@ describe ApplicationHelper do avatar_url = "/uploads/-/system/project/avatar/#{project.id}/banana_sample.gif" expect(helper.project_icon(project.full_path).to_s) - .to eq "\"Banana" + .to eq "" allow(ActionController::Base).to receive(:asset_host).and_return(gitlab_host) avatar_url = "#{gitlab_host}/uploads/-/system/project/avatar/#{project.id}/banana_sample.gif" expect(helper.project_icon(project.full_path).to_s) - .to eq "\"Banana" + .to eq "" end it 'gives uploaded icon when present' do @@ -77,7 +77,8 @@ describe ApplicationHelper do allow_any_instance_of(Project).to receive(:avatar_in_git).and_return(true) avatar_url = "#{gitlab_host}#{project_avatar_path(project)}" - expect(helper.project_icon(project.full_path).to_s).to match(image_tag(avatar_url)) + expect(helper.project_icon(project.full_path).to_s) + .to eq "" end end diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb index 049475a5408..d16fcf21e45 100644 --- a/spec/helpers/avatars_helper_spec.rb +++ b/spec/helpers/avatars_helper_spec.rb @@ -27,11 +27,11 @@ describe AvatarsHelper do it 'displays user avatar' do is_expected.to eq image_tag( - avatar_icon(user, 16), - class: 'avatar has-tooltip s16 ', + LazyImageTagHelper.placeholder_image, + class: 'avatar has-tooltip s16 lazy', alt: "#{user.name}'s avatar", title: user.name, - data: { container: 'body' } + data: { container: 'body', src: avatar_icon(user, 16) } ) end @@ -40,22 +40,8 @@ describe AvatarsHelper do it 'uses provided css_class' do is_expected.to eq image_tag( - avatar_icon(user, 16), - class: "avatar has-tooltip s16 #{options[:css_class]}", - alt: "#{user.name}'s avatar", - title: user.name, - data: { container: 'body' } - ) - end - end - - context 'with lazy parameter' do - let(:options) { { user: user, lazy: true } } - - it 'uses data-src instead of src' do - is_expected.to eq image_tag( - '', - class: 'avatar has-tooltip s16 ', + LazyImageTagHelper.placeholder_image, + class: "avatar has-tooltip s16 #{options[:css_class]} lazy", alt: "#{user.name}'s avatar", title: user.name, data: { container: 'body', src: avatar_icon(user, 16) } @@ -68,11 +54,11 @@ describe AvatarsHelper do it 'uses provided size' do is_expected.to eq image_tag( - avatar_icon(user, options[:size]), - class: "avatar has-tooltip s#{options[:size]} ", + LazyImageTagHelper.placeholder_image, + class: "avatar has-tooltip s#{options[:size]} lazy", alt: "#{user.name}'s avatar", title: user.name, - data: { container: 'body' } + data: { container: 'body', src: avatar_icon(user, options[:size]) } ) end end @@ -82,11 +68,11 @@ describe AvatarsHelper do it 'uses provided url' do is_expected.to eq image_tag( - options[:url], - class: 'avatar has-tooltip s16 ', + LazyImageTagHelper.placeholder_image, + class: 'avatar has-tooltip s16 lazy', alt: "#{user.name}'s avatar", title: user.name, - data: { container: 'body' } + data: { container: 'body', src: options[:url] } ) end end @@ -99,22 +85,22 @@ describe AvatarsHelper do it 'prefers user parameter' do is_expected.to eq image_tag( - avatar_icon(user, 16), - class: 'avatar has-tooltip s16 ', + LazyImageTagHelper.placeholder_image, + class: 'avatar has-tooltip s16 lazy', alt: "#{user.name}'s avatar", title: user.name, - data: { container: 'body' } + data: { container: 'body', src: avatar_icon(user, 16) } ) end end it 'uses user_name and user_email parameter if user is not present' do is_expected.to eq image_tag( - avatar_icon(options[:user_email], 16), - class: 'avatar has-tooltip s16 ', + LazyImageTagHelper.placeholder_image, + class: 'avatar has-tooltip s16 lazy', alt: "#{options[:user_name]}'s avatar", title: options[:user_name], - data: { container: 'body' } + data: { container: 'body', src: avatar_icon(options[:user_email], 16) } ) end end diff --git a/spec/javascripts/lazy_loader_spec.js b/spec/javascripts/lazy_loader_spec.js new file mode 100644 index 00000000000..1d81e4e2d1a --- /dev/null +++ b/spec/javascripts/lazy_loader_spec.js @@ -0,0 +1,57 @@ +import LazyLoader from '~/lazy_loader'; + +let lazyLoader = null; + +describe('LazyLoader', function () { + preloadFixtures('issues/issue_with_comment.html.raw'); + + beforeEach(function () { + loadFixtures('issues/issue_with_comment.html.raw'); + lazyLoader = new LazyLoader({ + observerNode: 'body', + }); + // Doing everything that happens normally in onload + lazyLoader.loadCheck(); + }); + describe('behavior', function () { + it('should copy value from data-src to src for img 1', function (done) { + const img = document.querySelectorAll('img[data-src]')[0]; + const originalDataSrc = img.getAttribute('data-src'); + img.scrollIntoView(); + + setTimeout(() => { + expect(img.getAttribute('src')).toBe(originalDataSrc); + expect(document.getElementsByClassName('js-lazy-loaded').length).toBeGreaterThan(0); + done(); + }, 100); + }); + + it('should lazy load dynamically added data-src images', function (done) { + const newImg = document.createElement('img'); + const testPath = '/img/testimg.png'; + newImg.className = 'lazy'; + newImg.setAttribute('data-src', testPath); + document.body.appendChild(newImg); + newImg.scrollIntoView(); + + setTimeout(() => { + expect(newImg.getAttribute('src')).toBe(testPath); + expect(document.getElementsByClassName('js-lazy-loaded').length).toBeGreaterThan(0); + done(); + }, 100); + }); + + it('should not alter normal images', function (done) { + const newImg = document.createElement('img'); + const testPath = '/img/testimg.png'; + newImg.setAttribute('src', testPath); + document.body.appendChild(newImg); + newImg.scrollIntoView(); + + setTimeout(() => { + expect(newImg).not.toHaveClass('js-lazy-loaded'); + done(); + }, 100); + }); + }); +}); diff --git a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb index 082c0d4dd0d..cbb2808c6bb 100644 --- a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb +++ b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb @@ -22,7 +22,7 @@ describe Banzai::Filter::GollumTagsFilter, lib: true do tag = '[[images/image.jpg]]' doc = filter("See #{tag}", project_wiki: project_wiki) - expect(doc.at_css('img')['src']).to eq "#{project_wiki.wiki_base_path}/images/image.jpg" + expect(doc.at_css('img')['data-src']).to eq "#{project_wiki.wiki_base_path}/images/image.jpg" end it 'does not creates img tag if image does not exist' do @@ -40,7 +40,7 @@ describe Banzai::Filter::GollumTagsFilter, lib: true do tag = '[[http://example.com/image.jpg]]' doc = filter("See #{tag}", project_wiki: project_wiki) - expect(doc.at_css('img')['src']).to eq "http://example.com/image.jpg" + expect(doc.at_css('img')['data-src']).to eq "http://example.com/image.jpg" end it 'does not creates img tag for invalid URL' do diff --git a/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb b/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb new file mode 100644 index 00000000000..c19de7b784a --- /dev/null +++ b/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe Banzai::Filter::ImageLazyLoadFilter, lib: true do + include FilterSpecHelper + + def image(path) + %() + end + + it 'transforms the image src to a data-src' do + doc = filter(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) + expect(doc.at_css('img')['data-src']).to eq '/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg' + end + + it 'works with external images' do + doc = filter(image('https://i.imgur.com/DfssX9C.jpg')) + expect(doc.at_css('img')['data-src']).to eq 'https://i.imgur.com/DfssX9C.jpg' + end +end diff --git a/spec/support/matchers/markdown_matchers.rb b/spec/support/matchers/markdown_matchers.rb index bbbbaf4c5e8..7afa57fb76b 100644 --- a/spec/support/matchers/markdown_matchers.rb +++ b/spec/support/matchers/markdown_matchers.rb @@ -17,7 +17,7 @@ module MarkdownMatchers image = actual.at_css('img[alt="Relative Image"]') expect(link['href']).to end_with('master/doc/README.md') - expect(image['src']).to end_with('master/app/assets/images/touch-icon-ipad.png') + expect(image['data-src']).to end_with('master/app/assets/images/touch-icon-ipad.png') end end @@ -70,7 +70,7 @@ module MarkdownMatchers # GollumTagsFilter matcher :parse_gollum_tags do def have_image(src) - have_css("img[src$='#{src}']") + have_css("img[data-src$='#{src}']") end prefix = '/namespace1/gitlabhq/wikis' -- cgit v1.2.1 From 8bf89cb4aba188cd9abc41bb9eefb92458cfb75b Mon Sep 17 00:00:00 2001 From: Toon Claes Date: Thu, 20 Jul 2017 22:44:48 +0200 Subject: Add author_id & assignee_id param to /issues API Allow issues filtering on `author_id` and `assignee_id`. --- app/finders/issuable_finder.rb | 1 + changelogs/unreleased/tc-issue-api-assignee.yml | 4 ++++ doc/api/issues.md | 13 +++++++++++- lib/api/issues.rb | 5 +++++ spec/requests/api/issues_spec.rb | 27 +++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/tc-issue-api-assignee.yml diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index fc63e30c8fb..6fe17a2b99d 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -11,6 +11,7 @@ # group_id: integer # project_id: integer # milestone_title: string +# author_id: integer # assignee_id: integer # search: string # label_name: string diff --git a/changelogs/unreleased/tc-issue-api-assignee.yml b/changelogs/unreleased/tc-issue-api-assignee.yml new file mode 100644 index 00000000000..8d6360d5baf --- /dev/null +++ b/changelogs/unreleased/tc-issue-api-assignee.yml @@ -0,0 +1,4 @@ +--- +title: Add author_id & assignee_id param to /issues API +merge_request: 13004 +author: diff --git a/doc/api/issues.md b/doc/api/issues.md index a00a63bad4b..82c19c8c40a 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -26,7 +26,8 @@ GET /issues?labels=foo,bar&state=opened GET /issues?milestone=1.0.0 GET /issues?milestone=1.0.0&state=opened GET /issues?iids[]=42&iids[]=43 -GET /issues?search=issue+title+or+description +GET /issues?author_id=5 +GET /issues?assignee_id=5 ``` | Attribute | Type | Required | Description | @@ -34,6 +35,8 @@ GET /issues?search=issue+title+or+description | `state` | string | no | Return all issues or just those that are `opened` or `closed` | | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels | | `milestone` | string | no | The milestone title | +| `author_id` | integer | no | Returns issues created by the given user `id` (not limited to issues created by the authenticated user) | +| `assignee_id` | integer | no | Returns issues assigned to the given user `id` (not limited to issues created by the authenticated user) | | `iids` | Array[integer] | no | Return only the issues having the given `iid` | | `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | | `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | @@ -117,6 +120,8 @@ GET /groups/:id/issues?milestone=1.0.0 GET /groups/:id/issues?milestone=1.0.0&state=opened GET /groups/:id/issues?iids[]=42&iids[]=43 GET /groups/:id/issues?search=issue+title+or+description +GET /groups/:id/issues?author_id=5 +GET /groups/:id/issues?assignee_id=5 ``` | Attribute | Type | Required | Description | @@ -126,6 +131,8 @@ GET /groups/:id/issues?search=issue+title+or+description | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels | | `iids` | Array[integer] | no | Return only the issues having the given `iid` | | `milestone` | string | no | The milestone title | +| `author_id` | integer | no | Returns issues created by the given user `id` (not limited to issues created by the authenticated user) | +| `assignee_id` | integer | no | Returns issues assigned to the given user `id` (not limited to issues created by the authenticated user) | | `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | | `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | | `search` | string | no | Search group issues against their `title` and `description` | @@ -209,6 +216,8 @@ GET /projects/:id/issues?milestone=1.0.0 GET /projects/:id/issues?milestone=1.0.0&state=opened GET /projects/:id/issues?iids[]=42&iids[]=43 GET /projects/:id/issues?search=issue+title+or+description +GET /projects/:id/issues?author_id=5 +GET /projects/:id/issues?assignee_id=5 ``` | Attribute | Type | Required | Description | @@ -218,6 +227,8 @@ GET /projects/:id/issues?search=issue+title+or+description | `state` | string | no | Return all issues or just those that are `opened` or `closed` | | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels | | `milestone` | string | no | The milestone title | +| `author_id` | integer | no | Returns issues created by the given user `id` (not limited to issues created by the authenticated user) | +| `assignee_id` | integer | no | Returns issues assigned to the given user `id` (not limited to issues created by the authenticated user) | | `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | | `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | | `search` | string | no | Search project issues against their `title` and `description` | diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 14b26f28ebf..621539afeaf 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -8,6 +8,9 @@ module API def find_issues(args = {}) args = params.merge(args) + # Do not scope to "authored" when author or assignee id is given + args.delete(:scope) if args[:author_id] || args[:assignee_id] + args.delete(:id) args[:milestone_title] = args.delete(:milestone) args[:label_name] = args.delete(:labels) @@ -29,6 +32,8 @@ module API optional :search, type: String, desc: 'Search issues for text present in the title or description' optional :created_after, type: DateTime, desc: 'Return issues created after the specified time' optional :created_before, type: DateTime, desc: 'Return issues created before the specified time' + optional :author_id, type: Integer, desc: 'Return issues which are authored by the user with the given ID' + optional :assignee_id, type: Integer, desc: 'Return issues which are assigned to the user with the given ID' use :pagination end diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 9837fedb522..dac88ce0b07 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -105,6 +105,33 @@ describe API::Issues do expect(json_response.second['id']).to eq(closed_issue.id) end + it 'returns issues authored by the given author id' do + issue2 = create(:issue, author: user2, project: project) + + get api('/issues', user), author_id: user2.id + + expect_paginated_array_response(size: 1) + expect(first_issue['id']).to eq(issue2.id) + end + + it 'returns issues assigned to the given assignee id' do + issue2 = create(:issue, assignees: [user2], project: project) + + get api('/issues', user), assignee_id: user2.id + + expect_paginated_array_response(size: 1) + expect(first_issue['id']).to eq(issue2.id) + end + + it 'returns issues authored by the given author id and assigned to the given assignee id' do + issue2 = create(:issue, author: user2, assignees: [user2], project: project) + + get api('/issues', user), author_id: user2.id, assignee_id: user2.id + + expect_paginated_array_response(size: 1) + expect(first_issue['id']).to eq(issue2.id) + end + it 'returns issues matching given search string for title' do get api("/issues", user), search: issue.title -- cgit v1.2.1 From d8798c907dfb960856423422a91eb1e6dc8db090 Mon Sep 17 00:00:00 2001 From: Toon Claes Date: Mon, 24 Jul 2017 22:41:33 +0200 Subject: Allow query param scope for /issues API endpoint --- doc/api/issues.md | 15 +++++++++------ lib/api/issues.rb | 9 +++++---- spec/requests/api/issues_spec.rb | 16 ++++++++++++---- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/doc/api/issues.md b/doc/api/issues.md index 82c19c8c40a..466fea651af 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -35,8 +35,9 @@ GET /issues?assignee_id=5 | `state` | string | no | Return all issues or just those that are `opened` or `closed` | | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels | | `milestone` | string | no | The milestone title | -| `author_id` | integer | no | Returns issues created by the given user `id` (not limited to issues created by the authenticated user) | -| `assignee_id` | integer | no | Returns issues assigned to the given user `id` (not limited to issues created by the authenticated user) | +| `scope` | string | no | Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all` | +| `author_id` | integer | no | Return issues created by the given user `id`. Combine with `scope=all` or `scope=assigned-to-me`. | +| `assignee_id` | integer | no | Return issues assigned to the given user `id` | | `iids` | Array[integer] | no | Return only the issues having the given `iid` | | `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | | `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | @@ -131,8 +132,9 @@ GET /groups/:id/issues?assignee_id=5 | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels | | `iids` | Array[integer] | no | Return only the issues having the given `iid` | | `milestone` | string | no | The milestone title | -| `author_id` | integer | no | Returns issues created by the given user `id` (not limited to issues created by the authenticated user) | -| `assignee_id` | integer | no | Returns issues assigned to the given user `id` (not limited to issues created by the authenticated user) | +| `scope` | string | no | Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all` | +| `author_id` | integer | no | Return issues created by the given user `id`. Combine with `scope=all` or `scope=assigned-to-me`. | +| `assignee_id` | integer | no | Return issues assigned to the given user `id` | | `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | | `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | | `search` | string | no | Search group issues against their `title` and `description` | @@ -227,8 +229,9 @@ GET /projects/:id/issues?assignee_id=5 | `state` | string | no | Return all issues or just those that are `opened` or `closed` | | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels | | `milestone` | string | no | The milestone title | -| `author_id` | integer | no | Returns issues created by the given user `id` (not limited to issues created by the authenticated user) | -| `assignee_id` | integer | no | Returns issues assigned to the given user `id` (not limited to issues created by the authenticated user) | +| `scope` | string | no | Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all` | +| `author_id` | integer | no | Return issues created by the given user `id`. Combine with `scope=all` or `scope=assigned-to-me`. | +| `assignee_id` | integer | no | Return issues assigned to the given user `id` | | `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | | `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | | `search` | string | no | Search project issues against their `title` and `description` | diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 621539afeaf..8f8d622fd34 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -8,9 +8,6 @@ module API def find_issues(args = {}) args = params.merge(args) - # Do not scope to "authored" when author or assignee id is given - args.delete(:scope) if args[:author_id] || args[:assignee_id] - args.delete(:id) args[:milestone_title] = args.delete(:milestone) args[:label_name] = args.delete(:labels) @@ -34,6 +31,8 @@ module API optional :created_before, type: DateTime, desc: 'Return issues created before the specified time' optional :author_id, type: Integer, desc: 'Return issues which are authored by the user with the given ID' optional :assignee_id, type: Integer, desc: 'Return issues which are assigned to the user with the given ID' + optional :scope, type: String, values: %w[created-by-me assigned-to-me all], + desc: 'Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all`' use :pagination end @@ -60,9 +59,11 @@ module API optional :state, type: String, values: %w[opened closed all], default: 'all', desc: 'Return opened, closed, or all issues' use :issues_params + optional :scope, type: String, values: %w[created-by-me assigned-to-me all], default: 'created-by-me', + desc: 'Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all`' end get do - issues = find_issues(scope: 'authored') + issues = find_issues present paginate(issues), with: Entities::IssueBasic, current_user: current_user end diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index dac88ce0b07..c8f3267907a 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -71,7 +71,6 @@ describe API::Issues do expect(response).to have_http_status(401) end end - context "when authenticated" do let(:first_issue) { json_response.first } @@ -105,10 +104,19 @@ describe API::Issues do expect(json_response.second['id']).to eq(closed_issue.id) end + it 'returns issues assigned to me' do + issue2 = create(:issue, assignees: [user2], project: project) + + get api('/issues', user2), scope: 'assigned-to-me' + + expect_paginated_array_response(size: 1) + expect(first_issue['id']).to eq(issue2.id) + end + it 'returns issues authored by the given author id' do issue2 = create(:issue, author: user2, project: project) - get api('/issues', user), author_id: user2.id + get api('/issues', user), author_id: user2.id, scope: 'all' expect_paginated_array_response(size: 1) expect(first_issue['id']).to eq(issue2.id) @@ -117,7 +125,7 @@ describe API::Issues do it 'returns issues assigned to the given assignee id' do issue2 = create(:issue, assignees: [user2], project: project) - get api('/issues', user), assignee_id: user2.id + get api('/issues', user), assignee_id: user2.id, scope: 'all' expect_paginated_array_response(size: 1) expect(first_issue['id']).to eq(issue2.id) @@ -126,7 +134,7 @@ describe API::Issues do it 'returns issues authored by the given author id and assigned to the given assignee id' do issue2 = create(:issue, author: user2, assignees: [user2], project: project) - get api('/issues', user), author_id: user2.id, assignee_id: user2.id + get api('/issues', user), author_id: user2.id, assignee_id: user2.id, scope: 'all' expect_paginated_array_response(size: 1) expect(first_issue['id']).to eq(issue2.id) -- cgit v1.2.1 From fa9adb6599ae20c8522c92c9a0d670633fe3d5b0 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Mon, 24 Jul 2017 14:53:30 +0200 Subject: Explicitly add `protect_from_forgery` action Otherwise the token might be cleared before authentication is done, causing the authentication itself to fail --- app/controllers/sessions_controller.rb | 8 ++++++++ changelogs/unreleased/bvl-fix-login-issue-with-ldap-enabled.yml | 5 +++++ 2 files changed, 13 insertions(+) create mode 100644 changelogs/unreleased/bvl-fix-login-issue-with-ldap-enabled.yml diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 0e8a57f8e03..69513f4dadc 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -5,6 +5,14 @@ class SessionsController < Devise::SessionsController skip_before_action :check_two_factor_requirement, only: [:destroy] + # Explicitly call protect from forgery before anything else. Otherwise the + # CSFR-token might be cleared before authentication is done. This was the case + # when LDAP was enabled and the `OmniauthCallbacksController` is loaded + # + # *Note:* `prepend: true` is the default for rails4, but this will be changed + # to `prepend: false` in rails5. + protect_from_forgery prepend: true, with: :exception + prepend_before_action :check_initial_setup, only: [:new] prepend_before_action :authenticate_with_two_factor, if: :two_factor_enabled?, only: [:create] diff --git a/changelogs/unreleased/bvl-fix-login-issue-with-ldap-enabled.yml b/changelogs/unreleased/bvl-fix-login-issue-with-ldap-enabled.yml new file mode 100644 index 00000000000..a98455d0916 --- /dev/null +++ b/changelogs/unreleased/bvl-fix-login-issue-with-ldap-enabled.yml @@ -0,0 +1,5 @@ +--- +title: Fix cross site request protection when logging in as a regular user when LDAP + is enabled +merge_request: 13049 +author: -- cgit v1.2.1 From 3951eb62705046fb2de6c836a82c1cad043d3036 Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Mon, 17 Jul 2017 00:11:32 +0900 Subject: Use only CSS to truncate commit message in blame --- app/assets/stylesheets/framework/files.scss | 10 ++++++++++ app/views/projects/blame/show.html.haml | 4 ++-- .../35163-url-in-commit-message-can-be-broken-in-blame.yml | 4 ++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/35163-url-in-commit-message-can-be-broken-in-blame.yml diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index c7c2684d548..8ad082f7a65 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -163,8 +163,18 @@ td.blame-commit { padding: 5px 10px; min-width: 400px; + max-width: 400px; background: $gray-light; border-left: 3px solid; + + .commit-row-title { + display: flex; + } + + .item-title { + flex: 1; + margin-right: 0.5em; + } } @for $i from 0 through 5 { diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml index f11afe8fc22..c7359d873d9 100644 --- a/app/views/projects/blame/show.html.haml +++ b/app/views/projects/blame/show.html.haml @@ -21,8 +21,8 @@ .commit = author_avatar(commit, size: 36) .commit-row-title - %strong - = link_to_gfm truncate(commit.title, length: 35), project_commit_path(@project, commit.id), class: "cdark" + %span.item-title.str-truncated-100 + = link_to_gfm commit.title, project_commit_path(@project, commit.id), class: "cdark", title: commit.title .pull-right = link_to commit.short_id, project_commit_path(@project, commit), class: "commit-sha"   diff --git a/changelogs/unreleased/35163-url-in-commit-message-can-be-broken-in-blame.yml b/changelogs/unreleased/35163-url-in-commit-message-can-be-broken-in-blame.yml new file mode 100644 index 00000000000..4fd60a79782 --- /dev/null +++ b/changelogs/unreleased/35163-url-in-commit-message-can-be-broken-in-blame.yml @@ -0,0 +1,4 @@ +--- +title: Use only CSS to truncate commit message in blame +merge_request: 12900 +author: Takuya Noguchi -- cgit v1.2.1 From 837e3e7c280897ba166704203775f7ff71e378d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 25 Jul 2017 14:25:59 +0800 Subject: synchronize ukrainian translation in zanata --- locale/uk/gitlab.po | 80 +++++++++++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po index 56498f3c901..b81f566309c 100644 --- a/locale/uk/gitlab.po +++ b/locale/uk/gitlab.po @@ -9,8 +9,8 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language-Team: Ukrainian (https://translate.zanata.org/project/view/GitLab)\n" -"PO-Revision-Date: 2017-07-14 01:22-0400\n" -"Last-Translator: Huang Tao \n" +"PO-Revision-Date: 2017-07-24 06:16-0400\n" +"Last-Translator: Андрей Витюк \n" "Language: uk\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " @@ -57,7 +57,7 @@ msgid "Add Changelog" msgstr "Додати список змін (Changelog)" msgid "Add Contribution guide" -msgstr "Додати керівництво для контрибуторів" +msgstr "Додати керівництво для контриб’юторів" msgid "Add License" msgstr "Додати ліцензію" @@ -209,7 +209,9 @@ msgstr[1] "Комміта" msgstr[2] "Коммітів" msgid "Commit duration in minutes for last 30 commits" -msgstr "Комміт тривалість у хвилинах за останні 30 коммітів" +msgstr "" +"Тривалість коммітів протягом декількох хвилин на протязі 30 останніх " +"коммітів" msgid "Commit message" msgstr "Комміт повідомлення" @@ -236,10 +238,10 @@ msgid "Compare" msgstr "Порівняти" msgid "Contribution guide" -msgstr "Керівництво контрибуторів" +msgstr "Керівництво контриб’юторів" msgid "Contributors" -msgstr "Контрибутори" +msgstr "Контриб’ютори" msgid "Copy URL to clipboard" msgstr "Скопіювати URL в буфер обміну" @@ -352,16 +354,16 @@ msgid "Download" msgstr "Завантажити" msgid "Download tar" -msgstr "Завантажити в форматі tar" +msgstr "Завантажити tar" msgid "Download tar.bz2" -msgstr "Завантажити в форматі tar.bz2" +msgstr "Завантажити tar.bz2" msgid "Download tar.gz" -msgstr "Завантажити в форматі tar.gz" +msgstr "Завантажити tar.gz" msgid "Download zip" -msgstr "Завантажити в форматі zip" +msgstr "Завантажити zip" msgid "DownloadArtifacts|Download" msgstr "Завантажити" @@ -397,7 +399,7 @@ msgid "Failed to remove the pipeline schedule" msgstr "Не вдалося видалити розклад Конвеєра" msgid "Files" -msgstr "Файли" +msgstr "Файлів" msgid "Filter by commit message" msgstr "Фільтрувати повідомлення коммітів" @@ -436,7 +438,7 @@ msgid "GoToYourFork|Fork" msgstr "Форк" msgid "Home" -msgstr "Початок" +msgstr "Головна" msgid "Housekeeping successfully started" msgstr "Очищення успішно розпочато" @@ -451,13 +453,13 @@ msgid "Introducing Cycle Analytics" msgstr "Представляємо аналітику циклу" msgid "Jobs for last month" -msgstr "Завдання за останній місяць" +msgstr "Кількість завдань за останній місяць" msgid "Jobs for last week" -msgstr "Завдання за останній тиждень" +msgstr "Кількість завдань за останній тиждень" msgid "Jobs for last year" -msgstr "Завдання за останній рік" +msgstr "Кількість завдань за останній рік" msgid "LFSStatus|Disabled" msgstr "Вимкнено" @@ -508,7 +510,7 @@ msgid "New Issue" msgid_plural "New Issues" msgstr[0] "Нова проблема" msgstr[1] "Нові проблеми" -msgstr[2] "Новах проблем" +msgstr[2] "Нових проблем" msgid "New Pipeline Schedule" msgstr "Новий розклад Конвеєра" @@ -757,7 +759,7 @@ msgid "ProjectLifecycle|Stage" msgstr "Етап" msgid "ProjectNetworkGraph|Graph" -msgstr "Графік" +msgstr "Історія" msgid "Read more" msgstr "Докладніше" @@ -852,7 +854,7 @@ msgid "Source code" msgstr "Код" msgid "StarProject|Star" -msgstr "Старт" +msgstr "Підписатися" msgid "Start a %{new_merge_request} with these changes" msgstr "Почати %{new_merge_request} з цих змін" @@ -988,19 +990,19 @@ msgid "Timeago|%s minutes remaining" msgstr "%s хвилини залишитися" msgid "Timeago|%s months ago" -msgstr "%s місяців тому" +msgstr "%s місяці(в) тому" msgid "Timeago|%s months remaining" -msgstr "%s місяці, що залишилися" +msgstr "%s місяці(в), що залишилися" msgid "Timeago|%s seconds remaining" msgstr "%s секунд, що залишаються" msgid "Timeago|%s weeks ago" -msgstr "%s тижнів тому" +msgstr "%s тижні(в) тому" msgid "Timeago|%s weeks remaining" -msgstr "%s тижнів залишилися" +msgstr "%s тижні(в) залишилися" msgid "Timeago|%s years ago" msgstr "%s років тому" @@ -1030,7 +1032,7 @@ msgid "Timeago|Past due" msgstr "Прострочені" msgid "Timeago|a day ago" -msgstr "годин тому" +msgstr "День тому" msgid "Timeago|a month ago" msgstr "місяць тому" @@ -1054,28 +1056,28 @@ msgid "Timeago|about an hour ago" msgstr "Близько години тому" msgid "Timeago|in %s days" -msgstr "через %s днїв" +msgstr "через %s дні(в)" msgid "Timeago|in %s hours" -msgstr "через %s години" +msgstr "через %s годин(и)" msgid "Timeago|in %s minutes" -msgstr "через %s хвилини" +msgstr "через %s хвилин(и)" msgid "Timeago|in %s months" -msgstr "через %s місяців" +msgstr "через %s місяці(в)" msgid "Timeago|in %s seconds" -msgstr "через %s секунд" +msgstr "через %s секунд(и)" msgid "Timeago|in %s weeks" -msgstr "через %s тижні" +msgstr "через %s тижні(в)" msgid "Timeago|in %s years" -msgstr "через %s років" +msgstr "через %s роки(ів)" msgid "Timeago|in 1 day" -msgstr "через день" +msgstr "через 1 день" msgid "Timeago|in 1 hour" msgstr "через годину" @@ -1093,22 +1095,22 @@ msgid "Timeago|in 1 year" msgstr "через рік" msgid "Timeago|less than a minute ago" -msgstr "менш хвилини тому" +msgstr "менше хвилини тому" msgid "Time|hr" msgid_plural "Time|hrs" -msgstr[0] "Година" -msgstr[1] "Годині" -msgstr[2] "Годин" +msgstr[0] "година" +msgstr[1] "години" +msgstr[2] "годин" msgid "Time|min" msgid_plural "Time|mins" msgstr[0] "хвилина" -msgstr[1] "хвилині" +msgstr[1] "хвилини" msgstr[2] "хвилин" msgid "Time|s" -msgstr "секунда" +msgstr "секунд(а)" msgid "Total Time" msgstr "Загальний час" @@ -1117,7 +1119,7 @@ msgid "Total test time for all commits/merges" msgstr "Загальний час, щоб перевірити всі фіксації/злиття" msgid "Unstar" -msgstr "Зняти позначку" +msgstr "Відписатись" msgid "Upload New File" msgstr "Завантажити новий файл" @@ -1129,7 +1131,7 @@ msgid "UploadLink|click to upload" msgstr "Натисніть, щоб завантажити" msgid "Use your global notification setting" -msgstr "Використовуються глобальний налаштування повідомлень" +msgstr "Використовуються глобальні налаштування повідомлень" msgid "View open merge request" msgstr "Перегляд відкритих запитів на злиття" -- cgit v1.2.1 From 2f0a4243d5e7d848172a8adfa72084eb4d07c60b Mon Sep 17 00:00:00 2001 From: Frank Groeneveld Date: Tue, 25 Jul 2017 08:29:04 +0200 Subject: Upgrade re2 to support seperate CXX and CC passing --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 5758b1b554e..8b32a60818a 100644 --- a/Gemfile +++ b/Gemfile @@ -164,7 +164,7 @@ gem 'rainbow', '~> 2.2' gem 'settingslogic', '~> 2.0.9' # Linear-time regex library for untrusted regular expressions -gem 're2', '~> 1.1.0' +gem 're2', '~> 1.1.1' # Misc diff --git a/Gemfile.lock b/Gemfile.lock index 6ffff0d8735..a64805ad6bf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -656,7 +656,7 @@ GEM debugger-ruby_core_source (~> 1.3) rdoc (4.2.2) json (~> 1.4) - re2 (1.1.0) + re2 (1.1.1) recaptcha (3.0.0) json recursive-open-struct (1.0.0) @@ -1055,7 +1055,7 @@ DEPENDENCIES raindrops (~> 0.18) rblineprof (~> 0.3.6) rdoc (~> 4.2) - re2 (~> 1.1.0) + re2 (~> 1.1.1) recaptcha (~> 3.0) redcarpet (~> 3.4) redis (~> 3.2) -- cgit v1.2.1 From 2b0a85c100423adf648c99ae3f528c46e5d474c7 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Tue, 18 Jul 2017 09:21:09 +0200 Subject: Adjust `PathRegex` to validate files in the `public` directory And reports when too many words are rejected. --- spec/lib/gitlab/path_regex_spec.rb | 46 ++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/spec/lib/gitlab/path_regex_spec.rb b/spec/lib/gitlab/path_regex_spec.rb index 1eea710c80b..37c67db8217 100644 --- a/spec/lib/gitlab/path_regex_spec.rb +++ b/spec/lib/gitlab/path_regex_spec.rb @@ -36,9 +36,10 @@ describe Gitlab::PathRegex, lib: true do described_class::PROJECT_WILDCARD_ROUTES.include?(path.split('/').first) end - def failure_message(missing_words, constant_name, migration_helper) + def failure_message(constant_name, migration_helper, missing_words:, additional_words: []) missing_words = Array(missing_words) - <<-MSG + additional_words = Array(additional_words) + message = <<-MSG Found new routes that could cause conflicts with existing namespaced routes for groups or projects. @@ -52,6 +53,18 @@ describe Gitlab::PathRegex, lib: true do Make sure to make a note of the renamed records in the release blog post. MSG + + if additional_words.any? + additional_message = <<-ADDITIONAL + Why are <#{additional_words.join(', ')}> in `#{constant_name}`? + If they are really required, update these specs to reflect that. + + ADDITIONAL + + message = [message, additional_message].join + end + + message end let(:all_routes) do @@ -68,9 +81,26 @@ describe Gitlab::PathRegex, lib: true do let(:routes_not_starting_in_wildcard) { routes_without_format.select { |p| p !~ %r{^/[:*]} } } let(:top_level_words) do - routes_not_starting_in_wildcard.map do |route| + words = routes_not_starting_in_wildcard.map do |route| route.split('/')[1] end.compact.uniq + + words += files_in_public + words + additional_top_level_words + end + + let(:additional_top_level_words) do + # Required to keep the uploads safe, remove after + # https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12917 gets merged + ['system'] + end + + let(:files_in_public) do + git = Gitlab.config.git.bin_path + `cd #{Rails.root} && #{git} ls-files public` + .split("\n") + .map { |entry| entry.gsub('public/', '') } + .uniq end # All routes that start with a namespaced path, that have 1 or more @@ -122,11 +152,13 @@ describe Gitlab::PathRegex, lib: true do it 'includes all the top level namespaces' do failure_block = lambda do missing_words = top_level_words - described_class::TOP_LEVEL_ROUTES - failure_message(missing_words, 'TOP_LEVEL_ROUTES', 'rename_root_paths') + additional_words = described_class::TOP_LEVEL_ROUTES - top_level_words + failure_message('TOP_LEVEL_ROUTES', 'rename_root_paths', + missing_words: missing_words, additional_words: additional_words) end expect(described_class::TOP_LEVEL_ROUTES) - .to include(*top_level_words), failure_block + .to contain_exactly(*top_level_words), failure_block end end @@ -134,7 +166,7 @@ describe Gitlab::PathRegex, lib: true do it "don't contain a second wildcard" do failure_block = lambda do missing_words = paths_after_group_id - described_class::GROUP_ROUTES - failure_message(missing_words, 'GROUP_ROUTES', 'rename_child_paths') + failure_message('GROUP_ROUTES', 'rename_child_paths', missing_words: missing_words) end expect(described_class::GROUP_ROUTES) @@ -147,7 +179,7 @@ describe Gitlab::PathRegex, lib: true do aggregate_failures do all_wildcard_paths.each do |path| expect(wildcards_include?(path)) - .to be(true), failure_message(path, 'PROJECT_WILDCARD_ROUTES', 'rename_wildcard_paths') + .to be(true), failure_message('PROJECT_WILDCARD_ROUTES', 'rename_wildcard_paths', missing_words: path) end end end -- cgit v1.2.1 From 1dcf799c76c5f2218ed7b1997389cd1e4ac81a17 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Tue, 18 Jul 2017 09:25:27 +0200 Subject: Remove a bunch of reserved top level routes These don't seem to be used anywhere, so can be removed. --- lib/gitlab/path_regex.rb | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/lib/gitlab/path_regex.rb b/lib/gitlab/path_regex.rb index 60a32d5d5ea..c8b1b762940 100644 --- a/lib/gitlab/path_regex.rb +++ b/lib/gitlab/path_regex.rb @@ -16,7 +16,6 @@ module Gitlab .well-known abuse_reports admin - all api assets autocomplete @@ -27,29 +26,20 @@ module Gitlab groups health_check help - hooks import invites - issues jwt koding - member - merge_requests - new - notes notification_settings oauth profile projects public - repository robots.txt s search sent_notifications - services snippets - teams u unicorn_test unsubscribes -- cgit v1.2.1 From bf114b31114e860e746f248661addcdde0133077 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Tue, 18 Jul 2017 09:37:38 +0200 Subject: Add contents of `public` as forbidden top-level routes --- lib/gitlab/path_regex.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/gitlab/path_regex.rb b/lib/gitlab/path_regex.rb index c8b1b762940..894bd5efae5 100644 --- a/lib/gitlab/path_regex.rb +++ b/lib/gitlab/path_regex.rb @@ -14,14 +14,23 @@ module Gitlab TOP_LEVEL_ROUTES = %w[ - .well-known + 404.html + 422.html + 500.html + 502.html + 503.html abuse_reports admin api + apple-touch-icon-precomposed.png + apple-touch-icon.png assets autocomplete ci dashboard + deploy.html explore + favicon.ico files groups health_check @@ -39,6 +48,7 @@ module Gitlab s search sent_notifications + slash-command-logo.png snippets u unicorn_test -- cgit v1.2.1 From d22fe96b58b104830f99fa77cba2d4fe7d7aaaff Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Tue, 18 Jul 2017 15:28:20 +0200 Subject: Take ee words into account We need to reserve these words in EE to support the upgrade path from CE to EE. --- changelogs/unreleased/bvl-free-unused-names.yml | 5 ++++ spec/lib/gitlab/path_regex_spec.rb | 39 +++++++++++++++---------- 2 files changed, 29 insertions(+), 15 deletions(-) create mode 100644 changelogs/unreleased/bvl-free-unused-names.yml diff --git a/changelogs/unreleased/bvl-free-unused-names.yml b/changelogs/unreleased/bvl-free-unused-names.yml new file mode 100644 index 00000000000..53acb95e5bb --- /dev/null +++ b/changelogs/unreleased/bvl-free-unused-names.yml @@ -0,0 +1,5 @@ +--- +title: Free up some top level words, reject top level groups named like files in the + public folder +merge_request: 12932 +author: diff --git a/spec/lib/gitlab/path_regex_spec.rb b/spec/lib/gitlab/path_regex_spec.rb index 37c67db8217..c38bbb64fc3 100644 --- a/spec/lib/gitlab/path_regex_spec.rb +++ b/spec/lib/gitlab/path_regex_spec.rb @@ -36,10 +36,12 @@ describe Gitlab::PathRegex, lib: true do described_class::PROJECT_WILDCARD_ROUTES.include?(path.split('/').first) end - def failure_message(constant_name, migration_helper, missing_words:, additional_words: []) + def failure_message(constant_name, migration_helper, missing_words: [], additional_words: []) missing_words = Array(missing_words) additional_words = Array(additional_words) - message = <<-MSG + message = "" + if missing_words.any? + message += <<-MISSING Found new routes that could cause conflicts with existing namespaced routes for groups or projects. @@ -52,16 +54,15 @@ describe Gitlab::PathRegex, lib: true do Make sure to make a note of the renamed records in the release blog post. - MSG + MISSING + end if additional_words.any? - additional_message = <<-ADDITIONAL + message += <<-ADDITIONAL Why are <#{additional_words.join(', ')}> in `#{constant_name}`? If they are really required, update these specs to reflect that. ADDITIONAL - - message = [message, additional_message].join end message @@ -85,14 +86,11 @@ describe Gitlab::PathRegex, lib: true do route.split('/')[1] end.compact.uniq - words += files_in_public - words + additional_top_level_words + words + ee_top_level_words + files_in_public end - let(:additional_top_level_words) do - # Required to keep the uploads safe, remove after - # https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12917 gets merged - ['system'] + let(:ee_top_level_words) do + ['unsubscribes'] end let(:files_in_public) do @@ -145,7 +143,16 @@ describe Gitlab::PathRegex, lib: true do let(:paths_after_group_id) do group_routes.map do |route| route.gsub(STARTING_WITH_GROUP, '').split('/').first - end.uniq + end.uniq + ee_paths_after_group_id + end + + let(:ee_paths_after_group_id) do + %w(analytics + ldap + ldap_group_links + notification_setting + audit_events + pipeline_quota hooks) end describe 'TOP_LEVEL_ROUTES' do @@ -166,11 +173,13 @@ describe Gitlab::PathRegex, lib: true do it "don't contain a second wildcard" do failure_block = lambda do missing_words = paths_after_group_id - described_class::GROUP_ROUTES - failure_message('GROUP_ROUTES', 'rename_child_paths', missing_words: missing_words) + additional_words = described_class::GROUP_ROUTES - paths_after_group_id + failure_message('GROUP_ROUTES', 'rename_child_paths', + missing_words: missing_words, additional_words: additional_words) end expect(described_class::GROUP_ROUTES) - .to include(*paths_after_group_id), failure_block + .to contain_exactly(*paths_after_group_id), failure_block end end -- cgit v1.2.1 From 02987e17c7af928fb85f80d1039eb938c366d8d3 Mon Sep 17 00:00:00 2001 From: Balasankar C Date: Tue, 25 Jul 2017 08:19:34 +0000 Subject: Update docs on using external registry with gitlab --- doc/administration/container_registry.md | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/doc/administration/container_registry.md b/doc/administration/container_registry.md index afafb6bf1f5..8cb0e5b1562 100644 --- a/doc/administration/container_registry.md +++ b/doc/administration/container_registry.md @@ -465,23 +465,42 @@ on how to achieve that. ## Disable Container Registry but use GitLab as an auth endpoint -You can disable the embedded Container Registry to use an external one, but -still use GitLab as an auth endpoint. - **Omnibus GitLab** + +You can use GitLab as an auth endpoint and use a non-bundled Container Registry. + 1. Open `/etc/gitlab/gitlab.rb` and set necessary configurations: ```ruby - registry['enable'] = false gitlab_rails['registry_enabled'] = true gitlab_rails['registry_host'] = "registry.gitlab.example.com" gitlab_rails['registry_port'] = "5005" gitlab_rails['registry_api_url'] = "http://localhost:5000" - gitlab_rails['registry_key_path'] = "/var/opt/gitlab/gitlab-rails/certificate.key" gitlab_rails['registry_path'] = "/var/opt/gitlab/gitlab-rails/shared/registry" gitlab_rails['registry_issuer'] = "omnibus-gitlab-issuer" ``` +1. A certificate keypair is required for GitLab and the Container Registry to + communicate securely. By default omnibus-gitlab will generate one keypair, + which is saved to `/var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key`. + When using an non-bundled Container Registry, you will need to supply a + custom certificate key. To do that, add the following to + `/etc/gitlab/gitlab.rb` + + ```ruby + gitlab_rails['registry_key_path'] = "/custom/path/to/registry-key.key" + # registry['internal_key'] should contain the contents of the custom key + # file. Line breaks in the key file should be marked using `\n` character + # Example: + registry['internal_key'] = "---BEGIN RSA PRIVATE KEY---\nMIIEpQIBAA\n" + ``` + + **Note:** The file specified at `registry_key_path` gets populated with the + content specified by `internal_key`, each time reconfigure is executed. If + no file is specified, omnibus-gitlab will default it to + `/var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key` and will populate + it. + 1. Save the file and [reconfigure GitLab][] for the changes to take effect. **Installations from source** -- cgit v1.2.1 From 25e44edc30b5ca61267487248db9330da3e48a6c Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 25 Jul 2017 16:44:02 +0800 Subject: Allow admin to read_users_list even if it's restricted --- app/policies/global_policy.rb | 2 +- .../35478-allow-admin-to-read-user-list.yml | 4 ++++ spec/policies/global_policy_spec.rb | 20 ++++++++++++++++++++ spec/requests/api/users_spec.rb | 19 ++++++++++++------- 4 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 changelogs/unreleased/35478-allow-admin-to-read-user-list.yml diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb index 55eefa76d3f..1c91425f589 100644 --- a/app/policies/global_policy.rb +++ b/app/policies/global_policy.rb @@ -44,7 +44,7 @@ class GlobalPolicy < BasePolicy prevent :log_in end - rule { ~restricted_public_level }.policy do + rule { admin | ~restricted_public_level }.policy do enable :read_users_list end end diff --git a/changelogs/unreleased/35478-allow-admin-to-read-user-list.yml b/changelogs/unreleased/35478-allow-admin-to-read-user-list.yml new file mode 100644 index 00000000000..da4b730f0ca --- /dev/null +++ b/changelogs/unreleased/35478-allow-admin-to-read-user-list.yml @@ -0,0 +1,4 @@ +--- +title: Allow admin to read_users_list even if it's restricted +merge_request: 13066 +author: diff --git a/spec/policies/global_policy_spec.rb b/spec/policies/global_policy_spec.rb index bb0fa0c0e9c..c3e2b603c4b 100644 --- a/spec/policies/global_policy_spec.rb +++ b/spec/policies/global_policy_spec.rb @@ -30,5 +30,25 @@ describe GlobalPolicy, models: true do it { is_expected.to be_allowed(:read_users_list) } end end + + context "for an admin" do + let(:current_user) { create(:admin) } + + context "when the public level is restricted" do + before do + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + end + + it { is_expected.to be_allowed(:read_users_list) } + end + + context "when the public level is not restricted" do + before do + stub_application_setting(restricted_visibility_levels: []) + end + + it { is_expected.to be_allowed(:read_users_list) } + end + end end end diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 877bde3b9a6..66b165b438b 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -55,17 +55,22 @@ describe API::Users do context "when public level is restricted" do before do stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) - allow_any_instance_of(API::Helpers).to receive(:authenticate!).and_return(true) end - it "renders 403" do - get api("/users") - expect(response).to have_http_status(403) + context 'when authenticate as a regular user' do + it "renders 403" do + get api("/users", user) + + expect(response).to have_gitlab_http_status(403) + end end - it "renders 404" do - get api("/users/#{user.id}") - expect(response).to have_http_status(404) + context 'when authenticate as an admin' do + it "renders 200" do + get api("/users", admin) + + expect(response).to have_gitlab_http_status(200) + end end end -- cgit v1.2.1 From 7e165327712e24efa94673cfd180ebb361eaa7bd Mon Sep 17 00:00:00 2001 From: Simon Knox Date: Tue, 25 Jul 2017 19:02:13 +1000 Subject: fix :focus styles for selected filter dropdown items --- app/assets/stylesheets/framework/filters.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss index 41184907abb..2b2afdb0e3e 100644 --- a/app/assets/stylesheets/framework/filters.scss +++ b/app/assets/stylesheets/framework/filters.scss @@ -413,13 +413,16 @@ background-color: $dropdown-hover-color; color: $white-light; text-decoration: none; + outline: 0; .avatar { border-color: $white-light; } } -.filter-dropdown-item { +.droplab-dropdown .dropdown-menu .filter-dropdown-item { + padding: 0; + .btn { border: none; width: 100%; @@ -454,14 +457,11 @@ } .dropdown-user { - display: -webkit-flex; display: flex; } .dropdown-user-details { - display: -webkit-flex; display: flex; - -webkit-flex-direction: column; flex-direction: column; > span { -- cgit v1.2.1 From e13d75c38a09fca98dfbb52ef94119770b7a445a Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Sun, 2 Jul 2017 17:02:59 +0200 Subject: Explicitly define inverse of acces_level relations --- app/models/concerns/protected_ref.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/models/concerns/protected_ref.rb b/app/models/concerns/protected_ref.rb index fc6b840f7a8..5dd43c36222 100644 --- a/app/models/concerns/protected_ref.rb +++ b/app/models/concerns/protected_ref.rb @@ -17,7 +17,13 @@ module ProtectedRef class_methods do def protected_ref_access_levels(*types) types.each do |type| - has_many :"#{type}_access_levels", dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent + # We need to set `inverse_of` to make sure the `belongs_to`-object is set + # when creating children using `accepts_nested_attributes_for`. + # + # If we don't `protected_branch` or `protected_tag` would be empty and + # `project` cannot be delegated to it, which in turn would cause validations + # to fail. + has_many :"#{type}_access_levels", dependent: :destroy, inverse_of: self.model_name.singular # rubocop:disable Cop/ActiveRecordDependent validates :"#{type}_access_levels", length: { is: 1, message: "are restricted to a single instance per #{self.model_name.human}." } -- cgit v1.2.1 From 33dc5171e5885bbc1de1db7b9be58453edfa9453 Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Tue, 25 Jul 2017 09:35:45 +0000 Subject: Resolve "More RESTful API: include resource URLs in responses" --- Gemfile | 1 + Gemfile.lock | 5 ++ ...d-resources-uris-using-grape-source-helpers.yml | 4 + config/initializers/grape_route_helpers_fix.rb | 35 +++++++++ config/routes/api.rb | 2 +- doc/api/issues.md | 40 ++++++++-- doc/api/projects.md | 91 ++++++++++++++++++++-- lib/api/api.rb | 1 + lib/api/entities.rb | 52 +++++++++++++ lib/api/helpers/related_resources_helpers.rb | 28 +++++++ lib/api/issues.rb | 2 +- lib/api/v3/entities.rb | 31 +++++++- spec/requests/api/issues_spec.rb | 13 ++++ spec/requests/api/projects_spec.rb | 32 ++++++++ 14 files changed, 324 insertions(+), 13 deletions(-) create mode 100644 changelogs/unreleased/22600-related-resources-uris-using-grape-source-helpers.yml create mode 100644 config/initializers/grape_route_helpers_fix.rb create mode 100644 lib/api/helpers/related_resources_helpers.rb diff --git a/Gemfile b/Gemfile index 210ac78fac3..d24d10e7496 100644 --- a/Gemfile +++ b/Gemfile @@ -16,6 +16,7 @@ gem 'mysql2', '~> 0.4.5', group: :mysql gem 'pg', '~> 0.18.2', group: :postgres gem 'rugged', '~> 0.25.1.1' +gem 'grape-route-helpers', '~> 2.0.0' gem 'faraday', '~> 0.12' diff --git a/Gemfile.lock b/Gemfile.lock index f6c1636dfaf..1f3d6d2d618 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -345,6 +345,10 @@ GEM grape-entity (0.6.0) activesupport multi_json (>= 1.3.2) + grape-route-helpers (2.0.0) + activesupport + grape (~> 0.16, >= 0.16.0) + rake grpc (1.4.0) google-protobuf (~> 3.1) googleauth (~> 0.5.1) @@ -981,6 +985,7 @@ DEPENDENCIES google-api-client (~> 0.8.6) grape (~> 0.19.2) grape-entity (~> 0.6.0) + grape-route-helpers (~> 2.0.0) haml_lint (~> 0.21.0) hamlit (~> 2.6.1) hashie-forbidden_attributes diff --git a/changelogs/unreleased/22600-related-resources-uris-using-grape-source-helpers.yml b/changelogs/unreleased/22600-related-resources-uris-using-grape-source-helpers.yml new file mode 100644 index 00000000000..837a34bd067 --- /dev/null +++ b/changelogs/unreleased/22600-related-resources-uris-using-grape-source-helpers.yml @@ -0,0 +1,4 @@ +--- +title: Declare related resources into V4 API entities +merge_request: +author: diff --git a/config/initializers/grape_route_helpers_fix.rb b/config/initializers/grape_route_helpers_fix.rb new file mode 100644 index 00000000000..d3cf9e453d0 --- /dev/null +++ b/config/initializers/grape_route_helpers_fix.rb @@ -0,0 +1,35 @@ +if defined?(GrapeRouteHelpers) + module GrapeRouteHelpers + class DecoratedRoute + # GrapeRouteHelpers gem tries to parse the versions + # from a string, not supporting Grape `version` array definition. + # + # Without the following fix, we get this on route helpers generation: + # + # => undefined method `scan' for ["v3", "v4"] + # + # 2.0.0 implementation of this method: + # + # ``` + # def route_versions + # version_pattern = /[^\[",\]\s]+/ + # if route_version + # route_version.scan(version_pattern) + # else + # [nil] + # end + # end + # ``` + def route_versions + return [nil] if route_version.nil? || route_version.empty? + + if route_version.is_a?(String) + version_pattern = /[^\[",\]\s]+/ + route_version.scan(version_pattern) + else + route_version + end + end + end + end +end diff --git a/config/routes/api.rb b/config/routes/api.rb index 69c8efc151c..ce7a7c88900 100644 --- a/config/routes/api.rb +++ b/config/routes/api.rb @@ -1,2 +1,2 @@ API::API.logger Rails.logger -mount API::API => '/api' +mount API::API => '/' diff --git a/doc/api/issues.md b/doc/api/issues.md index a00a63bad4b..0e391c75cd3 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -356,7 +356,13 @@ Example response: "user_notes_count": 1, "due_date": null, "web_url": "http://example.com/example/example/issues/1", - "confidential": false + "confidential": false, + "_links": { + "self": "http://example.com/api/v4/projects/1/issues/2", + "notes": "http://example.com/api/v4/projects/1/issues/2/notes", + "award_emoji": "http://example.com/api/v4/projects/1/issues/2/award_emoji", + "project": "http://example.com/api/v4/projects/1" + } } ``` @@ -418,7 +424,13 @@ Example response: "user_notes_count": 0, "due_date": null, "web_url": "http://example.com/example/example/issues/14", - "confidential": false + "confidential": false, + "_links": { + "self": "http://example.com/api/v4/projects/1/issues/2", + "notes": "http://example.com/api/v4/projects/1/issues/2/notes", + "award_emoji": "http://example.com/api/v4/projects/1/issues/2/award_emoji", + "project": "http://example.com/api/v4/projects/1" + } } ``` @@ -481,7 +493,13 @@ Example response: "user_notes_count": 0, "due_date": "2016-07-22", "web_url": "http://example.com/example/example/issues/15", - "confidential": false + "confidential": false, + "_links": { + "self": "http://example.com/api/v4/projects/1/issues/2", + "notes": "http://example.com/api/v4/projects/1/issues/2/notes", + "award_emoji": "http://example.com/api/v4/projects/1/issues/2/award_emoji", + "project": "http://example.com/api/v4/projects/1" + } } ``` @@ -567,7 +585,13 @@ Example response: }, "due_date": null, "web_url": "http://example.com/example/example/issues/11", - "confidential": false + "confidential": false, + "_links": { + "self": "http://example.com/api/v4/projects/1/issues/2", + "notes": "http://example.com/api/v4/projects/1/issues/2/notes", + "award_emoji": "http://example.com/api/v4/projects/1/issues/2/award_emoji", + "project": "http://example.com/api/v4/projects/1" + } } ``` @@ -632,7 +656,13 @@ Example response: }, "due_date": null, "web_url": "http://example.com/example/example/issues/11", - "confidential": false + "confidential": false, + "_links": { + "self": "http://example.com/api/v4/projects/1/issues/2", + "notes": "http://example.com/api/v4/projects/1/issues/2/notes", + "award_emoji": "http://example.com/api/v4/projects/1/issues/2/award_emoji", + "project": "http://example.com/api/v4/projects/1" + } } ``` diff --git a/doc/api/projects.md b/doc/api/projects.md index 61ae89a64c0..d3f8e509612 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -99,7 +99,16 @@ Parameters: "repository_size": 1038090, "lfs_objects_size": 0, "job_artifacts_size": 0 - } + }, + "_links": { + "self": "http://example.com/api/v4/projects", + "issues": "http://example.com/api/v4/projects/1/issues", + "merge_requests": "http://example.com/api/v4/projects/1/merge_requests", + "repo_branches": "http://example.com/api/v4/projects/1/repository_branches", + "labels": "http://example.com/api/v4/projects/1/labels", + "events": "http://example.com/api/v4/projects/1/events", + "members": "http://example.com/api/v4/projects/1/members" + }, }, { "id": 6, @@ -168,6 +177,15 @@ Parameters: "repository_size": 2066080, "lfs_objects_size": 0, "job_artifacts_size": 0 + }, + "_links": { + "self": "http://example.com/api/v4/projects", + "issues": "http://example.com/api/v4/projects/1/issues", + "merge_requests": "http://example.com/api/v4/projects/1/merge_requests", + "repo_branches": "http://example.com/api/v4/projects/1/repository_branches", + "labels": "http://example.com/api/v4/projects/1/labels", + "events": "http://example.com/api/v4/projects/1/events", + "members": "http://example.com/api/v4/projects/1/members" } } ] @@ -257,6 +275,15 @@ Parameters: "repository_size": 1038090, "lfs_objects_size": 0, "job_artifacts_size": 0 + }, + "_links": { + "self": "http://example.com/api/v4/projects", + "issues": "http://example.com/api/v4/projects/1/issues", + "merge_requests": "http://example.com/api/v4/projects/1/merge_requests", + "repo_branches": "http://example.com/api/v4/projects/1/repository_branches", + "labels": "http://example.com/api/v4/projects/1/labels", + "events": "http://example.com/api/v4/projects/1/events", + "members": "http://example.com/api/v4/projects/1/members" } }, { @@ -326,6 +353,15 @@ Parameters: "repository_size": 2066080, "lfs_objects_size": 0, "job_artifacts_size": 0 + }, + "_links": { + "self": "http://example.com/api/v4/projects", + "issues": "http://example.com/api/v4/projects/1/issues", + "merge_requests": "http://example.com/api/v4/projects/1/merge_requests", + "repo_branches": "http://example.com/api/v4/projects/1/repository_branches", + "labels": "http://example.com/api/v4/projects/1/labels", + "events": "http://example.com/api/v4/projects/1/events", + "members": "http://example.com/api/v4/projects/1/members" } } ] @@ -427,6 +463,15 @@ Parameters: "repository_size": 1038090, "lfs_objects_size": 0, "job_artifacts_size": 0 + }, + "_links": { + "self": "http://example.com/api/v4/projects", + "issues": "http://example.com/api/v4/projects/1/issues", + "merge_requests": "http://example.com/api/v4/projects/1/merge_requests", + "repo_branches": "http://example.com/api/v4/projects/1/repository_branches", + "labels": "http://example.com/api/v4/projects/1/labels", + "events": "http://example.com/api/v4/projects/1/events", + "members": "http://example.com/api/v4/projects/1/members" } } ``` @@ -659,7 +704,16 @@ Example response: "shared_with_groups": [], "only_allow_merge_if_pipeline_succeeds": false, "only_allow_merge_if_all_discussions_are_resolved": false, - "request_access_enabled": false + "request_access_enabled": false, + "_links": { + "self": "http://example.com/api/v4/projects", + "issues": "http://example.com/api/v4/projects/1/issues", + "merge_requests": "http://example.com/api/v4/projects/1/merge_requests", + "repo_branches": "http://example.com/api/v4/projects/1/repository_branches", + "labels": "http://example.com/api/v4/projects/1/labels", + "events": "http://example.com/api/v4/projects/1/events", + "members": "http://example.com/api/v4/projects/1/members" + } } ``` @@ -725,7 +779,16 @@ Example response: "shared_with_groups": [], "only_allow_merge_if_pipeline_succeeds": false, "only_allow_merge_if_all_discussions_are_resolved": false, - "request_access_enabled": false + "request_access_enabled": false, + "_links": { + "self": "http://example.com/api/v4/projects", + "issues": "http://example.com/api/v4/projects/1/issues", + "merge_requests": "http://example.com/api/v4/projects/1/merge_requests", + "repo_branches": "http://example.com/api/v4/projects/1/repository_branches", + "labels": "http://example.com/api/v4/projects/1/labels", + "events": "http://example.com/api/v4/projects/1/events", + "members": "http://example.com/api/v4/projects/1/members" + } } ``` @@ -809,7 +872,16 @@ Example response: "shared_with_groups": [], "only_allow_merge_if_pipeline_succeeds": false, "only_allow_merge_if_all_discussions_are_resolved": false, - "request_access_enabled": false + "request_access_enabled": false, + "_links": { + "self": "http://example.com/api/v4/projects", + "issues": "http://example.com/api/v4/projects/1/issues", + "merge_requests": "http://example.com/api/v4/projects/1/merge_requests", + "repo_branches": "http://example.com/api/v4/projects/1/repository_branches", + "labels": "http://example.com/api/v4/projects/1/labels", + "events": "http://example.com/api/v4/projects/1/events", + "members": "http://example.com/api/v4/projects/1/members" + } } ``` @@ -893,7 +965,16 @@ Example response: "shared_with_groups": [], "only_allow_merge_if_pipeline_succeeds": false, "only_allow_merge_if_all_discussions_are_resolved": false, - "request_access_enabled": false + "request_access_enabled": false, + "_links": { + "self": "http://example.com/api/v4/projects", + "issues": "http://example.com/api/v4/projects/1/issues", + "merge_requests": "http://example.com/api/v4/projects/1/merge_requests", + "repo_branches": "http://example.com/api/v4/projects/1/repository_branches", + "labels": "http://example.com/api/v4/projects/1/labels", + "events": "http://example.com/api/v4/projects/1/events", + "members": "http://example.com/api/v4/projects/1/members" + } } ``` diff --git a/lib/api/api.rb b/lib/api/api.rb index efcf0976a81..9a983d31ac6 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -3,6 +3,7 @@ module API include APIGuard allow_access_with_scope :api + prefix :api version %w(v3 v4), using: :path diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 1719e9f7205..c165236105f 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -82,6 +82,38 @@ module API end class Project < Grape::Entity + include ::API::Helpers::RelatedResourcesHelpers + + expose :_links do + expose :self do |project| + expose_url(api_v4_projects_path(id: project.id)) + end + + expose :issues, if: -> (*args) { issues_available?(*args) } do |project| + expose_url(api_v4_projects_issues_path(id: project.id)) + end + + expose :merge_requests, if: -> (*args) { mrs_available?(*args) } do |project| + expose_url(api_v4_projects_merge_requests_path(id: project.id)) + end + + expose :repo_branches do |project| + expose_url(api_v4_projects_repository_branches_path(id: project.id)) + end + + expose :labels do |project| + expose_url(api_v4_projects_labels_path(id: project.id)) + end + + expose :events do |project| + expose_url(api_v4_projects_events_path(id: project.id)) + end + + expose :members do |project| + expose_url(api_v4_projects_members_path(id: project.id)) + end + end + expose :id, :description, :default_branch, :tag_list expose :archived?, as: :archived expose :visibility, :ssh_url_to_repo, :http_url_to_repo, :web_url @@ -297,6 +329,26 @@ module API end class Issue < IssueBasic + include ::API::Helpers::RelatedResourcesHelpers + + expose :_links do + expose :self do |issue| + expose_url(api_v4_project_issue_path(id: issue.project_id, issue_iid: issue.iid)) + end + + expose :notes do |issue| + expose_url(api_v4_projects_issues_notes_path(id: issue.project_id, noteable_id: issue.iid)) + end + + expose :award_emoji do |issue| + expose_url(api_v4_projects_issues_award_emoji_path(id: issue.project_id, issue_iid: issue.iid)) + end + + expose :project do |issue| + expose_url(api_v4_projects_path(id: issue.project_id)) + end + end + expose :subscribed do |issue, options| issue.subscribed?(options[:current_user], options[:project] || issue.project) end diff --git a/lib/api/helpers/related_resources_helpers.rb b/lib/api/helpers/related_resources_helpers.rb new file mode 100644 index 00000000000..769cc1457fc --- /dev/null +++ b/lib/api/helpers/related_resources_helpers.rb @@ -0,0 +1,28 @@ +module API + module Helpers + module RelatedResourcesHelpers + include GrapeRouteHelpers::NamedRouteMatcher + + def issues_available?(project, options) + available?(:issues, project, options[:current_user]) + end + + def mrs_available?(project, options) + available?(:merge_requests, project, options[:current_user]) + end + + def expose_url(path) + url_options = Rails.application.routes.default_url_options + protocol, host, port = url_options.slice(:protocol, :host, :port).values + + URI::HTTP.build(scheme: protocol, host: host, port: port, path: path).to_s + end + + private + + def available?(feature, project, current_user) + project.feature_available?(feature, current_user) + end + end + end +end diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 14b26f28ebf..93ebe18508d 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -112,7 +112,7 @@ module API params do requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue' end - get ":id/issues/:issue_iid" do + get ":id/issues/:issue_iid", as: :api_v4_project_issue do issue = find_project_issue(params[:issue_iid]) present issue, with: Entities::Issue, current_user: current_user, project: user_project end diff --git a/lib/api/v3/entities.rb b/lib/api/v3/entities.rb index 3759250f7f6..773f667abe0 100644 --- a/lib/api/v3/entities.rb +++ b/lib/api/v3/entities.rb @@ -259,11 +259,40 @@ module API expose :job_events, as: :build_events end - class Issue < ::API::Entities::Issue + class ProjectEntity < Grape::Entity + expose :id, :iid + expose(:project_id) { |entity| entity&.project.try(:id) } + expose :title, :description + expose :state, :created_at, :updated_at + end + + class IssueBasic < ProjectEntity + expose :label_names, as: :labels + expose :milestone, using: ::API::Entities::Milestone + expose :assignees, :author, using: ::API::Entities::UserBasic + + expose :assignee, using: ::API::Entities::UserBasic do |issue, options| + issue.assignees.first + end + + expose :user_notes_count + expose :upvotes, :downvotes + expose :due_date + expose :confidential + + expose :web_url do |issue, options| + Gitlab::UrlBuilder.build(issue) + end + end + + class Issue < IssueBasic unexpose :assignees expose :assignee do |issue, options| ::API::Entities::UserBasic.represent(issue.assignees.first, options) end + expose :subscribed do |issue, options| + issue.subscribed?(options[:current_user], options[:project] || issue.project) + end end end end diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 9837fedb522..ff4fc802176 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -693,6 +693,19 @@ describe API::Issues do expect(json_response['confidential']).to be_falsy end + context 'links exposure' do + it 'exposes related resources full URIs' do + get api("/projects/#{project.id}/issues/#{issue.iid}", user) + + links = json_response['_links'] + + expect(links['self']).to end_with("/api/v4/projects/#{project.id}/issues/#{issue.iid}") + expect(links['notes']).to end_with("/api/v4/projects/#{project.id}/issues/#{issue.iid}/notes") + expect(links['award_emoji']).to end_with("/api/v4/projects/#{project.id}/issues/#{issue.iid}/award_emoji") + expect(links['project']).to end_with("/api/v4/projects/#{project.id}") + end + end + it "returns a project issue by internal id" do get api("/projects/#{project.id}/issues/#{issue.iid}", user) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 457f64cc88c..79e7e1a95df 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -815,6 +815,38 @@ describe API::Projects do expect(json_response).not_to include("import_error") end + context 'links exposure' do + it 'exposes related resources full URIs' do + get api("/projects/#{project.id}", user) + + links = json_response['_links'] + + expect(links['self']).to end_with("/api/v4/projects/#{project.id}") + expect(links['issues']).to end_with("/api/v4/projects/#{project.id}/issues") + expect(links['merge_requests']).to end_with("/api/v4/projects/#{project.id}/merge_requests") + expect(links['repo_branches']).to end_with("/api/v4/projects/#{project.id}/repository/branches") + expect(links['labels']).to end_with("/api/v4/projects/#{project.id}/labels") + expect(links['events']).to end_with("/api/v4/projects/#{project.id}/events") + expect(links['members']).to end_with("/api/v4/projects/#{project.id}/members") + end + + it 'filters related URIs when their feature is not enabled' do + project = create(:empty_project, :public, + :merge_requests_disabled, + :issues_disabled, + creator_id: user.id, + namespace: user.namespace) + + get api("/projects/#{project.id}", user) + + links = json_response['_links'] + + expect(links.has_key?('merge_requests')).to be_falsy + expect(links.has_key?('issues')).to be_falsy + expect(links['self']).to end_with("/api/v4/projects/#{project.id}") + end + end + describe 'permissions' do context 'all projects' do before do -- cgit v1.2.1 From 4236c2f055000ae9eadc165eea6355cf4825d595 Mon Sep 17 00:00:00 2001 From: Tiago Botelho Date: Tue, 25 Jul 2017 10:46:01 +0100 Subject: Adds link_to_gfm method instrumentation --- changelogs/unreleased/add-instrumentation-to-link-to-gfm.yml | 4 ++++ config/initializers/8_metrics.rb | 3 +++ 2 files changed, 7 insertions(+) create mode 100644 changelogs/unreleased/add-instrumentation-to-link-to-gfm.yml diff --git a/changelogs/unreleased/add-instrumentation-to-link-to-gfm.yml b/changelogs/unreleased/add-instrumentation-to-link-to-gfm.yml new file mode 100644 index 00000000000..b5cf521561a --- /dev/null +++ b/changelogs/unreleased/add-instrumentation-to-link-to-gfm.yml @@ -0,0 +1,4 @@ +--- +title: Add instrumentation to MarkupHelper#link_to_gfm +merge_request: 13069 +author: diff --git a/config/initializers/8_metrics.rb b/config/initializers/8_metrics.rb index 25630b298ce..2aeb94d47cd 100644 --- a/config/initializers/8_metrics.rb +++ b/config/initializers/8_metrics.rb @@ -114,6 +114,9 @@ def instrument_classes(instrumentation) # This is a Rails scope so we have to instrument it manually. instrumentation.instrument_method(Project, :visible_to_user) + # Needed for https://gitlab.com/gitlab-org/gitlab-ce/issues/34509 + instrumentation.instrument_method(MarkupHelper, :link_to_gfm) + # Needed for https://gitlab.com/gitlab-org/gitlab-ce/issues/30224#note_32306159 instrumentation.instrument_instance_method(MergeRequestDiff, :load_commits) end -- cgit v1.2.1 From 33193155c7188209a168ceeb8ec4d3170dabbbaa Mon Sep 17 00:00:00 2001 From: winh Date: Mon, 24 Jul 2017 14:21:34 +0200 Subject: Make issuable searchbar full height --- app/assets/stylesheets/pages/issuable.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index aa04e490649..eb269df46fe 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -211,6 +211,10 @@ -webkit-overflow-scrolling: touch; } + &.affix-top .issuable-sidebar { + height: 100%; + } + &.right-sidebar-expanded { width: $gutter_width; -- cgit v1.2.1 From 531681c11d9e542fbd0d5ae5db8bc9a17cc0aefd Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 25 Jul 2017 11:28:30 +0100 Subject: Fix vertical alignment in firefox and safari for pipeline mini graph --- app/assets/stylesheets/pages/pipelines.scss | 3 ++- changelogs/unreleased/2971-multiproject-grah-ce-port.yml | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/2971-multiproject-grah-ce-port.yml diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 9637d26e56d..d3862df20d3 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -597,7 +597,7 @@ } // Dropdown button in mini pipeline graph -.mini-pipeline-graph-dropdown-toggle { +button.mini-pipeline-graph-dropdown-toggle { border-radius: 100px; background-color: $white-light; border-width: 1px; @@ -608,6 +608,7 @@ padding: 0; transition: all 0.2s linear; position: relative; + vertical-align: middle; > .fa.fa-caret-down { position: absolute; diff --git a/changelogs/unreleased/2971-multiproject-grah-ce-port.yml b/changelogs/unreleased/2971-multiproject-grah-ce-port.yml new file mode 100644 index 00000000000..37584cac6ab --- /dev/null +++ b/changelogs/unreleased/2971-multiproject-grah-ce-port.yml @@ -0,0 +1,4 @@ +--- +title: Fix vertical alignment in firefox and safari for pipeline mini graph +merge_request: +author: -- cgit v1.2.1 From 77a6ec22ba9057154925a6484c05ae204423aacd Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 25 Jul 2017 12:45:17 +0200 Subject: Handle maximum pages artifacts size correctly --- app/services/projects/update_pages_service.rb | 4 +- .../services/projects/update_pages_service_spec.rb | 72 ++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/app/services/projects/update_pages_service.rb b/app/services/projects/update_pages_service.rb index e60b854f916..a819b799ff8 100644 --- a/app/services/projects/update_pages_service.rb +++ b/app/services/projects/update_pages_service.rb @@ -130,7 +130,9 @@ module Projects end def max_size - current_application_settings.max_pages_size.megabytes || MAX_SIZE + current_application_settings.max_pages_size.megabytes.tap do |maximum| + return MAX_SIZE if maximum.zero? || maximum > MAX_SIZE + end end def tmp_path diff --git a/spec/services/projects/update_pages_service_spec.rb b/spec/services/projects/update_pages_service_spec.rb index fc0a17296f3..8210f8a9608 100644 --- a/spec/services/projects/update_pages_service_spec.rb +++ b/spec/services/projects/update_pages_service_spec.rb @@ -96,6 +96,78 @@ describe Projects::UpdatePagesService do expect(execute).not_to eq(:success) end + describe 'maximum pages artifacts size' do + let(:metadata) { spy('metadata') } + + before do + file = fixture_file_upload(Rails.root + 'spec/fixtures/pages.zip') + metafile = fixture_file_upload(Rails.root + 'spec/fixtures/pages.zip.meta') + + build.update_attributes(artifacts_file: file) + build.update_attributes(artifacts_metadata: metafile) + + allow(build).to receive(:artifacts_metadata_entry) + .and_return(metadata) + end + + shared_examples 'pages size limit exceeded' do + it 'limits the maximum size of gitlab pages' do + subject.execute + + expect(deploy_status.description) + .to match(/artifacts for pages are too large/) + end + end + + context 'when maximum pages size is set to zero' do + before do + stub_application_setting(max_pages_size: 0) + end + + context 'when page size does not exceed internal maximum' do + before do + allow(metadata).to receive(:total_size).and_return(200.megabytes) + end + + it 'updates pages correctly' do + subject.execute + + expect(deploy_status.description).not_to be_present + end + end + + context 'when pages size does exceed internal maximum' do + before do + allow(metadata).to receive(:total_size).and_return(2.terabytes) + end + + it_behaves_like 'pages size limit exceeded' + end + end + + context 'when pages size is greater than max size setting' do + before do + stub_application_setting(max_pages_size: 200) + allow(metadata).to receive(:total_size).and_return(201.megabytes) + end + + it_behaves_like 'pages size limit exceeded' + end + + context 'when max size setting is greater than internal max size' do + before do + stub_application_setting(max_pages_size: 3.terabytes / 1.megabyte) + allow(metadata).to receive(:total_size).and_return(2.terabytes) + end + + it_behaves_like 'pages size limit exceeded' + end + end + + def deploy_status + GenericCommitStatus.find_by(name: 'pages:deploy'); + end + def execute subject.execute[:status] end -- cgit v1.2.1 From 8758c10886c5a5dfc140a33142c3a0e15dc2b42b Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Tue, 25 Jul 2017 11:50:09 +0100 Subject: v3 API is unsupported after 9.5, but may not be removed That is, it may not _necessarily_ be removed. We do not provide guarantees for when API v3 will be available until beyond 9.5. --- doc/api/v3_to_v4.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/api/v3_to_v4.md b/doc/api/v3_to_v4.md index 9db8e0351cf..9835fab7c98 100644 --- a/doc/api/v3_to_v4.md +++ b/doc/api/v3_to_v4.md @@ -2,9 +2,11 @@ Since GitLab 9.0, API V4 is the preferred version to be used. -API V3 will be removed in GitLab 9.5, to be released on August 22, 2017. In the -meantime, we advise you to make any necessary changes to applications that use -V3. The V3 API documentation is still [available](https://gitlab.com/gitlab-org/gitlab-ce/blob/8-16-stable/doc/api/README.md). +API V3 will be unsupported from GitLab 9.5, to be released on August +22, 2017. It will be removed in GitLab 9.5 or later. In the meantime, we advise +you to make any necessary changes to applications that use V3. The V3 API +documentation is still +[available](https://gitlab.com/gitlab-org/gitlab-ce/blob/8-16-stable/doc/api/README.md). Below are the changes made between V3 and V4. -- cgit v1.2.1 From 205090fcfb741884215723281dfb0afb56efbbfb Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 25 Jul 2017 11:56:41 +0100 Subject: Removed inline JS in shared HAML files --- app/assets/javascripts/dispatcher.js | 65 ++++++++++++++++++++-- app/assets/javascripts/issuable_context.js | 4 +- app/assets/javascripts/main.js | 1 - app/assets/javascripts/milestone_select.js | 2 +- app/assets/javascripts/project.js | 29 +++++----- app/assets/javascripts/snippets_list.js | 9 --- app/helpers/notes_helper.rb | 10 ++++ app/views/shared/_clone_panel.html.haml | 8 --- app/views/shared/_label.html.haml | 8 --- .../shared/_personal_access_tokens_form.html.haml | 15 ----- app/views/shared/issuable/_filter.html.haml | 10 ---- app/views/shared/issuable/_participants.html.haml | 2 - app/views/shared/issuable/_search_bar.html.haml | 9 --- app/views/shared/issuable/_sidebar.html.haml | 10 +--- app/views/shared/notes/_notes_with_form.html.haml | 3 +- app/views/snippets/_snippets.html.haml | 6 +- 16 files changed, 90 insertions(+), 101 deletions(-) delete mode 100644 app/assets/javascripts/snippets_list.js diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index ffe97c071ba..8a142e49b72 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -27,6 +27,10 @@ /* global Shortcuts */ /* global Sidebar */ /* global ShortcutsWiki */ +/* global IssuableContext */ +/* global IssueStatusSelect */ +/* global SubscriptionSelect */ +/* global Notes */ import Issue from './issue'; import BindInOut from './behaviors/bind_in_out'; @@ -126,6 +130,42 @@ import PerformanceBar from './performance_bar'; .init(); } + function initIssuableSidebar() { + new MilestoneSelect({ + full_path: gl.sidebarOptions.fullPath, + }); + new LabelsSelect(); + new IssuableContext(gl.sidebarOptions.currentUser); + gl.Subscription.bindAll('.subscription'); + new gl.DueDateSelectors(); + window.sidebar = new Sidebar(); + } + + function initLegacyFilters() { + new UsersSelect(); + new LabelsSelect(); + new MilestoneSelect(); + new IssueStatusSelect(); + new SubscriptionSelect(); + $('form.filter-form').on('submit', function (event) { + event.preventDefault(); + gl.utils.visitUrl(`${this.action}&${$(this).serialize()}`); + }); + } + + function initNotes() { + const dataEl = document.querySelector('.js-notes-data'); + const { + notesUrl, + notesIds, + now, + diffView, + autocomplete, + } = JSON.parse(dataEl.innerHTML); + + window.notes = new Notes(notesUrl, notesIds, now, diffView, autocomplete); + } + switch (page) { case 'profiles:preferences:show': initExperimentalFlags(); @@ -156,6 +196,8 @@ import PerformanceBar from './performance_bar'; new Issue(); shortcut_handler = new ShortcutsIssuable(); new ZenMode(); + initIssuableSidebar(); + initNotes(); break; case 'dashboard:milestones:index': new ProjectSelect(); @@ -166,10 +208,12 @@ import PerformanceBar from './performance_bar'; new Milestone(); new Sidebar(); break; + case 'dashboard:issues': + case 'dashboard:merge_requests': case 'groups:issues': case 'groups:merge_requests': - new UsersSelect(); new ProjectSelect(); + initLegacyFilters(); break; case 'dashboard:todos:index': new Todos(); @@ -237,6 +281,9 @@ import PerformanceBar from './performance_bar'; new gl.GLForm($('.tag-form'), true); new RefSelectDropdown($('.js-branch-select'), window.gl.availableRefs); break; + case 'projects:snippets:show': + initNotes(); + break; case 'projects:snippets:new': case 'projects:snippets:edit': case 'projects:snippets:create': @@ -253,19 +300,17 @@ import PerformanceBar from './performance_bar'; new ZenMode(); new gl.GLForm($('.release-form'), true); break; + case 'projects:merge_requests:conflicts:show': case 'projects:merge_requests:show': new gl.Diff(); shortcut_handler = new ShortcutsIssuable(true); new ZenMode(); + initIssuableSidebar(); + initNotes(); break; case 'dashboard:activity': new gl.Activities(); break; - case 'dashboard:issues': - case 'dashboard:merge_requests': - new ProjectSelect(); - new UsersSelect(); - break; case 'projects:commit:show': new Commit(); new gl.Diff(); @@ -274,6 +319,7 @@ import PerformanceBar from './performance_bar'; new MiniPipelineGraph({ container: '.js-commit-pipeline-graph', }).bindEvents(); + initNotes(); break; case 'projects:commit:pipelines': new MiniPipelineGraph({ @@ -367,10 +413,12 @@ import PerformanceBar from './performance_bar'; case 'projects:labels:edit': new Labels(); break; + case 'groups:labels:index': case 'projects:labels:index': if ($('.prioritized-labels').length) { new gl.LabelManager(); } + new gl.ProjectLabelSubscription('.label-subscription'); break; case 'projects:network:show': // Ensure we don't create a particular shortcut handler here. This is @@ -415,10 +463,15 @@ import PerformanceBar from './performance_bar'; case 'snippets:show': new LineHighlighter(); new BlobViewer(); + initNotes(); break; case 'import:fogbugz:new_user_map': new UsersSelect(); break; + case 'profiles:personal_access_tokens:index': + case 'admin:impersonation_tokens:index': + new gl.DueDateSelectors(); + break; } switch (path.first()) { case 'sessions': diff --git a/app/assets/javascripts/issuable_context.js b/app/assets/javascripts/issuable_context.js index a4d7bf096ef..a45ff3fc43e 100644 --- a/app/assets/javascripts/issuable_context.js +++ b/app/assets/javascripts/issuable_context.js @@ -50,11 +50,9 @@ import UsersSelect from './users_select'; } IssuableContext.prototype.initParticipants = function() { - var _this; - _this = this; $(document).on("click", ".js-participants-more", this.toggleHiddenParticipants); return $(".js-participants-author").each(function(i) { - if (i >= _this.PARTICIPANTS_ROW_COUNT) { + if (i >= 7) { return $(this).addClass("js-participants-hidden").hide(); } }); diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index e96d51de838..6d3f5390cf6 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -145,7 +145,6 @@ import './right_sidebar'; import './search'; import './search_autocomplete'; import './smart_interval'; -import './snippets_list'; import './star'; import './subscription'; import './subscription_select'; diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js index 9d481d7c003..6756ab0b3aa 100644 --- a/app/assets/javascripts/milestone_select.js +++ b/app/assets/javascripts/milestone_select.js @@ -8,7 +8,7 @@ var _this, $els; if (currentProject != null) { _this = this; - this.currentProject = JSON.parse(currentProject); + this.currentProject = typeof currentProject === 'string' ? JSON.parse(currentProject) : currentProject; } $els = $(els); diff --git a/app/assets/javascripts/project.js b/app/assets/javascripts/project.js index 738e710deb9..a3f7d69b98d 100644 --- a/app/assets/javascripts/project.js +++ b/app/assets/javascripts/project.js @@ -6,21 +6,22 @@ import Cookies from 'js-cookie'; (function() { this.Project = (function() { function Project() { - $('ul.clone-options-dropdown a').click(function() { - var url; - if ($(this).hasClass('active')) { - return; - } - $('.active').not($(this)).removeClass('active'); - $(this).toggleClass('active'); - url = $("#project_clone").val(); - $('#project_clone').val(url); + const $cloneOptions = $('ul.clone-options-dropdown'); + const $projectCloneField = $('#project_clone'); + const $cloneBtnText = $('a.clone-dropdown-btn span'); + + $('a', $cloneOptions).on('click', (e) => { + const $this = $(e.currentTarget); + const url = $this.attr('href'); + + e.preventDefault(); + + $('.active', $cloneOptions).not($this).removeClass('active'); + $this.toggleClass('active'); + $projectCloneField.val(url); + $cloneBtnText.text($this.text()); + return $('.clone').text(url); - // Git protocol switcher - // Remove the active class for all buttons (ssh, http, kerberos if shown) - // Add the active class for the clicked button - // Update the input field - // Update the command line instructions }); // Ref switcher this.initRefSwitcher(); diff --git a/app/assets/javascripts/snippets_list.js b/app/assets/javascripts/snippets_list.js deleted file mode 100644 index 3b6d999b1c3..00000000000 --- a/app/assets/javascripts/snippets_list.js +++ /dev/null @@ -1,9 +0,0 @@ -function SnippetsList() { - const $holder = $('.snippets-list-holder'); - - $holder.find('.pagination').on('ajax:success', (e, data) => { - $holder.replaceWith(data.html); - }); -} - -window.gl.SnippetsList = SnippetsList; diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 0a0881d95cf..505579674c9 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -130,4 +130,14 @@ module NotesHelper can?(current_user, :create_note, @project) end end + + def initial_notes_data(autocomplete) + { + notesUrl: notes_url, + notesIds: @notes.map(&:id), + now: Time.now.to_i, + diffView: diff_view, + autocomplete: autocomplete + } + end end diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml index 75704eda361..b4843eafdb7 100644 --- a/app/views/shared/_clone_panel.html.haml +++ b/app/views/shared/_clone_panel.html.haml @@ -20,11 +20,3 @@ = text_field_tag :project_clone, default_url_to_repo(project), class: "js-select-on-focus form-control", readonly: true, aria: { label: 'Project clone URL' } .input-group-btn = clipboard_button(target: '#project_clone', title: _("Copy URL to clipboard"), class: "btn-default btn-clipboard") - -:javascript - $('ul.clone-options-dropdown a').on('click',function(e){ - e.preventDefault(); - var $this = $(this); - $('a.clone-dropdown-btn span').text($this.text()); - $('#project_clone').val($this.attr('href')); - }); diff --git a/app/views/shared/_label.html.haml b/app/views/shared/_label.html.haml index 2f776a17f45..8ded7440de3 100644 --- a/app/views/shared/_label.html.haml +++ b/app/views/shared/_label.html.haml @@ -76,11 +76,3 @@ = link_to destroy_label_path(label), title: "Delete", class: 'btn btn-transparent btn-action remove-row', method: :delete, data: {confirm: label_deletion_confirm_text(label), toggle: "tooltip"} do %span.sr-only Delete = icon('trash-o') - - - if current_user - - if can_subscribe_to_label_in_different_levels?(label) - :javascript - new gl.GroupLabelSubscription('##{dom_id(label)} .label-subscription'); - - else - :javascript - new gl.ProjectLabelSubscription('##{dom_id(label)} .label-subscription'); diff --git a/app/views/shared/_personal_access_tokens_form.html.haml b/app/views/shared/_personal_access_tokens_form.html.haml index b20055a564e..e415ec64c38 100644 --- a/app/views/shared/_personal_access_tokens_form.html.haml +++ b/app/views/shared/_personal_access_tokens_form.html.haml @@ -23,18 +23,3 @@ .prepend-top-default = f.submit "Create #{type} token", class: "btn btn-create" - -:javascript - var $dateField = $('.datepicker'); - var date = $dateField.val(); - - new Pikaday({ - field: $dateField.get(0), - theme: 'gitlab-theme animate-picker', - format: 'yyyy-mm-dd', - minDate: new Date(), - container: $dateField.parent().get(0), - onSelect: function(dateText) { - $dateField.val(dateFormat(new Date(dateText), 'yyyy-mm-dd')); - } - }); diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml index 2cabbc8c560..c4ed7f6e750 100644 --- a/app/views/shared/issuable/_filter.html.haml +++ b/app/views/shared/issuable/_filter.html.haml @@ -36,13 +36,3 @@ .row-content-block.second-block.filtered-labels{ class: ("hidden" unless has_labels) } - if has_labels = render 'shared/labels_row', labels: @labels - -:javascript - new LabelsSelect(); - new MilestoneSelect(); - new IssueStatusSelect(); - new SubscriptionSelect(); - $('form.filter-form').on('submit', function (event) { - event.preventDefault(); - gl.utils.visitUrl(this.action + '&' + $(this).serialize()); - }); diff --git a/app/views/shared/issuable/_participants.html.haml b/app/views/shared/issuable/_participants.html.haml index db407363a09..8a71819aa8e 100644 --- a/app/views/shared/issuable/_participants.html.haml +++ b/app/views/shared/issuable/_participants.html.haml @@ -16,5 +16,3 @@ .hide-collapsed.participants-more %a.js-participants-more{ href: "#", data: { original_text: "+ #{participants_size - 7} more", less_text: "- show less" } } + #{participants_extra} more -:javascript - IssuableContext.prototype.PARTICIPANTS_ROW_COUNT = #{participants_row}; diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml index 6f0b7600698..3428d6e0445 100644 --- a/app/views/shared/issuable/_search_bar.html.haml +++ b/app/views/shared/issuable/_search_bar.html.haml @@ -108,12 +108,3 @@ #js-add-issues-btn.prepend-left-10 - elsif type != :boards_modal = render 'shared/sort_dropdown' - -- unless type === :boards_modal - :javascript - $(document).off('page:restore').on('page:restore', function (event) { - if (gl.FilteredSearchManager) { - const filteredSearchManager = new gl.FilteredSearchManager(); - filteredSearchManager.setup(); - } - }); diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index ecbaa901792..094f2472693 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -143,12 +143,6 @@ endpoint: "#{issuable_json_path(issuable)}?basic=true", editable: #{can_edit_issuable ? true : false}, currentUser: #{current_user.to_json(only: [:username, :id, :name], methods: :avatar_url)}, - rootPath: "#{root_path}" + rootPath: "#{root_path}", + fullPath: "#{@project.full_path}", }; - - new MilestoneSelect('{"full_path":"#{@project.full_path}"}'); - new LabelsSelect(); - new IssuableContext('#{escape_javascript(current_user.to_json(only: [:username, :id, :name]))}'); - gl.Subscription.bindAll('.subscription'); - new gl.DueDateSelectors(); - window.sidebar = new Sidebar(); diff --git a/app/views/shared/notes/_notes_with_form.html.haml b/app/views/shared/notes/_notes_with_form.html.haml index f0fcc414756..eae04c9bbb8 100644 --- a/app/views/shared/notes/_notes_with_form.html.haml +++ b/app/views/shared/notes/_notes_with_form.html.haml @@ -22,5 +22,4 @@ = link_to "sign in", new_session_path(:user, redirect_to_referer: 'yes') to comment -:javascript - var notes = new Notes("#{notes_url}", #{@notes.map(&:id).to_json}, #{Time.now.to_i}, "#{diff_view}", #{autocomplete}) +%script.js-notes-data{ type: "application/json" }= initial_notes_data(autocomplete).to_json.html_safe diff --git a/app/views/snippets/_snippets.html.haml b/app/views/snippets/_snippets.html.haml index ac3701233ad..dfea8b40bd8 100644 --- a/app/views/snippets/_snippets.html.haml +++ b/app/views/snippets/_snippets.html.haml @@ -1,4 +1,3 @@ -- remote = local_assigns.fetch(:remote, false) - link_project = local_assigns.fetch(:link_project, false) .snippets-list-holder @@ -8,7 +7,4 @@ %li .nothing-here-block Nothing here. - = paginate @snippets, theme: 'gitlab', remote: remote - -:javascript - gl.SnippetsList(); + = paginate @snippets, theme: 'gitlab' -- cgit v1.2.1 From 8a50e5fb0c02e37c3eef80c88edfcb902571769c Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 25 Jul 2017 13:04:22 +0200 Subject: Add changelog for max pages artifacts size fix --- .../unreleased/fix-gb-handle-max-pages-artifacts-size-correctly.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/fix-gb-handle-max-pages-artifacts-size-correctly.yml diff --git a/changelogs/unreleased/fix-gb-handle-max-pages-artifacts-size-correctly.yml b/changelogs/unreleased/fix-gb-handle-max-pages-artifacts-size-correctly.yml new file mode 100644 index 00000000000..3d9592bbf2a --- /dev/null +++ b/changelogs/unreleased/fix-gb-handle-max-pages-artifacts-size-correctly.yml @@ -0,0 +1,4 @@ +--- +title: Handle maximum pages artifacts size correctly +merge_request: 13072 +author: -- cgit v1.2.1 From b915a46758aa02bc5fa61fec02b1e80196a1b6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Tue, 25 Jul 2017 19:08:51 +0800 Subject: synchronize ukrainian translation in zanata again --- locale/uk/gitlab.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po index b81f566309c..c259ca253bc 100644 --- a/locale/uk/gitlab.po +++ b/locale/uk/gitlab.po @@ -9,7 +9,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language-Team: Ukrainian (https://translate.zanata.org/project/view/GitLab)\n" -"PO-Revision-Date: 2017-07-24 06:16-0400\n" +"PO-Revision-Date: 2017-07-25 03:27-0400\n" "Last-Translator: Андрей Витюк \n" "Language: uk\n" "X-Generator: Zanata 3.9.6\n" @@ -381,7 +381,7 @@ msgid "Edit" msgstr "Редагувати" msgid "Edit Pipeline Schedule %{id}" -msgstr "Редагувати Розклад Конвеєра % {id}" +msgstr "Редагувати Розклад Конвеєра %{id}" msgid "Every day (at 4:00am)" msgstr "Кожен день (в 4:00 ранку)" -- cgit v1.2.1 From 7151fb754b82888e022bfced02f2fdfd9000a1ff Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 25 Jul 2017 13:47:03 +0200 Subject: Fix rubocop offense in update pages service specs --- spec/services/projects/update_pages_service_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/services/projects/update_pages_service_spec.rb b/spec/services/projects/update_pages_service_spec.rb index 8210f8a9608..aa6ad6340f5 100644 --- a/spec/services/projects/update_pages_service_spec.rb +++ b/spec/services/projects/update_pages_service_spec.rb @@ -165,7 +165,7 @@ describe Projects::UpdatePagesService do end def deploy_status - GenericCommitStatus.find_by(name: 'pages:deploy'); + GenericCommitStatus.find_by(name: 'pages:deploy') end def execute -- cgit v1.2.1 From 069a4a02e075548267266be2dcceb4002ba7be81 Mon Sep 17 00:00:00 2001 From: Simon Knox Date: Tue, 25 Jul 2017 06:33:00 +0000 Subject: Add directives to Vue component ordering --- doc/development/fe_guide/style_guide_js.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/development/fe_guide/style_guide_js.md b/doc/development/fe_guide/style_guide_js.md index ae844fa1051..149a0159680 100644 --- a/doc/development/fe_guide/style_guide_js.md +++ b/doc/development/fe_guide/style_guide_js.md @@ -447,6 +447,7 @@ A forEach will cause side effects, it will be mutating the array being iterated. 1. `name` 1. `props` 1. `mixins` + 1. `directives` 1. `data` 1. `components` 1. `computedProps` -- cgit v1.2.1 From a872c3e886528016d5383ef9260277b8120e2cc4 Mon Sep 17 00:00:00 2001 From: Tiago Botelho Date: Mon, 24 Jul 2017 19:27:29 +0100 Subject: Bumps Gitlab Omniauth LDAP version --- Gemfile | 2 +- Gemfile.lock | 16 ++++++++-------- changelogs/unreleased/bump-omniauth-ldap-gem-version.yml | 4 ++++ 3 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 changelogs/unreleased/bump-omniauth-ldap-gem-version.yml diff --git a/Gemfile b/Gemfile index 5758b1b554e..d45c15fd650 100644 --- a/Gemfile +++ b/Gemfile @@ -60,7 +60,7 @@ gem 'browser', '~> 2.2' # LDAP Auth # GitLab fork with several improvements to original library. For full list of changes # see https://github.com/intridea/omniauth-ldap/compare/master...gitlabhq:master -gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: 'omniauth-ldap' +gem 'gitlab_omniauth-ldap', '~> 2.0.3', require: 'omniauth-ldap' # Git Wiki # Required manually in config/initializers/gollum.rb to control load order diff --git a/Gemfile.lock b/Gemfile.lock index 6ffff0d8735..7b1d5dfdc6e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -288,11 +288,11 @@ GEM mime-types (>= 1.16, < 3) posix-spawn (~> 0.3) gitlab-markup (1.5.1) - gitlab_omniauth-ldap (1.2.1) - net-ldap (~> 0.9) - omniauth (~> 1.0) - pyu-ruby-sasl (~> 0.0.3.1) - rubyntlm (~> 0.3) + gitlab_omniauth-ldap (2.0.3) + net-ldap (~> 0.16) + omniauth (~> 1.3) + pyu-ruby-sasl (>= 0.0.3.3, < 0.1) + rubyntlm (~> 0.5) globalid (0.3.7) activesupport (>= 4.1.0) gollum-grit_adapter (1.0.1) @@ -467,7 +467,7 @@ GEM mustermann-grape (1.0.0) mustermann (~> 1.0.0) mysql2 (0.4.5) - net-ldap (0.12.1) + net-ldap (0.16.0) netrc (0.11.0) nokogiri (1.6.8.1) mini_portile2 (~> 2.1.0) @@ -740,7 +740,7 @@ GEM nokogiri (>= 1.5.10) ruby_parser (3.9.0) sexp_processor (~> 4.1) - rubyntlm (0.5.2) + rubyntlm (0.6.2) rubypants (0.2.0) rubyzip (1.2.1) rufus-scheduler (3.4.0) @@ -974,7 +974,7 @@ DEPENDENCIES github-linguist (~> 4.7.0) gitlab-flowdock-git-hook (~> 1.0.1) gitlab-markup (~> 1.5.1) - gitlab_omniauth-ldap (~> 1.2.1) + gitlab_omniauth-ldap (~> 2.0.3) gollum-lib (~> 4.2) gollum-rugged_adapter (~> 0.4.4) gon (~> 6.1.0) diff --git a/changelogs/unreleased/bump-omniauth-ldap-gem-version.yml b/changelogs/unreleased/bump-omniauth-ldap-gem-version.yml new file mode 100644 index 00000000000..42e1c9e8f83 --- /dev/null +++ b/changelogs/unreleased/bump-omniauth-ldap-gem-version.yml @@ -0,0 +1,4 @@ +--- +title: Prevent LDAP login callback from being called with a GET request +merge_request: 13059 +author: -- cgit v1.2.1 From 5fdef68f2bb35dc7a217c55cd6f1ed01ec3adff2 Mon Sep 17 00:00:00 2001 From: Jarka Kadlecova Date: Tue, 25 Jul 2017 14:14:28 +0200 Subject: Move relative_path to the element that is being clicked --- app/views/shared/_new_project_item_select.html.haml | 4 ++-- spec/features/dashboard/issues_spec.rb | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/views/shared/_new_project_item_select.html.haml b/app/views/shared/_new_project_item_select.html.haml index c1acee1a211..5f3cdaefd54 100644 --- a/app/views/shared/_new_project_item_select.html.haml +++ b/app/views/shared/_new_project_item_select.html.haml @@ -1,6 +1,6 @@ - if @projects.any? .project-item-select-holder - = project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at' }, with_feature_enabled: local_assigns[:with_feature_enabled] - %a.btn.btn-new.new-project-item-select-button{ data: { relative_path: local_assigns[:path] } } + = project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at', relative_path: local_assigns[:path] }, with_feature_enabled: local_assigns[:with_feature_enabled] + %a.btn.btn-new.new-project-item-select-button = local_assigns[:label] = icon('caret-down') diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb index 69c1a2ed89a..2a5ef08da60 100644 --- a/spec/features/dashboard/issues_spec.rb +++ b/spec/features/dashboard/issues_spec.rb @@ -78,5 +78,23 @@ RSpec.describe 'Dashboard Issues', feature: true do expect(page).not_to have_content(project_with_issues_disabled.name_with_namespace) end end + + it 'shows the new issue page', js: true do + Gitlab::Application.routes.default_url_options = { + host: Capybara.current_session.server.host, + port: Capybara.current_session.server.port, + protocol: 'http' + } + + find('.new-project-item-select-button').trigger('click') + wait_for_requests + find('.select2-results li').click + + expect(page).to have_current_path("/#{project.path_with_namespace}/issues/new") + + page.within('#content-body') do + expect(page).to have_selector('.issue-form') + end + end end end -- cgit v1.2.1 From 2286879583580861109207c05aa4fae1729a02b6 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Tue, 25 Jul 2017 14:19:09 +0200 Subject: Ensure test files are deleted after tests --- config/initializers/7_prometheus_metrics.rb | 2 +- lib/gitlab/health_checks/base_abstract_check.rb | 6 +- lib/gitlab/health_checks/fs_shards_check.rb | 67 ++++++++++++++-------- .../gitlab/health_checks/fs_shards_check_spec.rb | 6 ++ 4 files changed, 52 insertions(+), 29 deletions(-) diff --git a/config/initializers/7_prometheus_metrics.rb b/config/initializers/7_prometheus_metrics.rb index 987324a86c9..a2f8421f5d7 100644 --- a/config/initializers/7_prometheus_metrics.rb +++ b/config/initializers/7_prometheus_metrics.rb @@ -6,7 +6,7 @@ Prometheus::Client.configure do |config| config.initial_mmap_file_size = 4 * 1024 config.multiprocess_files_dir = ENV['prometheus_multiproc_dir'] - if Rails.env.development? && Rails.env.test? + if Rails.env.development? || Rails.env.test? config.multiprocess_files_dir ||= Rails.root.join('tmp/prometheus_multiproc_dir') end end diff --git a/lib/gitlab/health_checks/base_abstract_check.rb b/lib/gitlab/health_checks/base_abstract_check.rb index 7de6d4d9367..8b365dab185 100644 --- a/lib/gitlab/health_checks/base_abstract_check.rb +++ b/lib/gitlab/health_checks/base_abstract_check.rb @@ -27,10 +27,10 @@ module Gitlab Metric.new(name, value, labels) end - def with_timing(proc) + def with_timing start = Time.now - result = proc.call - yield result, Time.now.to_f - start.to_f + result = yield + [result, Time.now.to_f - start.to_f] end def catch_timeout(seconds, &block) diff --git a/lib/gitlab/health_checks/fs_shards_check.rb b/lib/gitlab/health_checks/fs_shards_check.rb index bebde857b16..45cd8f7eefc 100644 --- a/lib/gitlab/health_checks/fs_shards_check.rb +++ b/lib/gitlab/health_checks/fs_shards_check.rb @@ -10,52 +10,64 @@ module Gitlab def readiness repository_storages.map do |storage_name| begin - tmp_file_path = tmp_file_path(storage_name) - if !storage_stat_test(storage_name) HealthChecks::Result.new(false, 'cannot stat storage', shard: storage_name) - elsif !storage_write_test(tmp_file_path) - HealthChecks::Result.new(false, 'cannot write to storage', shard: storage_name) - elsif !storage_read_test(tmp_file_path) - HealthChecks::Result.new(false, 'cannot read from storage', shard: storage_name) else - HealthChecks::Result.new(true, nil, shard: storage_name) + with_temp_file(storage_name) do |tmp_file_path| + if !storage_write_test(tmp_file_path) + HealthChecks::Result.new(false, 'cannot write to storage', shard: storage_name) + elsif !storage_read_test(tmp_file_path) + HealthChecks::Result.new(false, 'cannot read from storage', shard: storage_name) + else + HealthChecks::Result.new(true, nil, shard: storage_name) + end + end end rescue RuntimeError => ex message = "unexpected error #{ex} when checking storage #{storage_name}" Rails.logger.error(message) HealthChecks::Result.new(false, message, shard: storage_name) - ensure - delete_test_file(tmp_file_path) end end end def metrics - repository_storages.flat_map do |storage_name| - tmp_file_path = tmp_file_path(storage_name) - [ - operation_metrics(:filesystem_accessible, :filesystem_access_latency_seconds, -> { storage_stat_test(storage_name) }, shard: storage_name), - operation_metrics(:filesystem_writable, :filesystem_write_latency_seconds, -> { storage_write_test(tmp_file_path) }, shard: storage_name), - operation_metrics(:filesystem_readable, :filesystem_read_latency_seconds, -> { storage_read_test(tmp_file_path) }, shard: storage_name) - ].flatten + res = [] + repository_storages.each do |storage_name| + res << operation_metrics(:filesystem_accessible, :filesystem_access_latency_seconds, shard: storage_name) do + with_timing { storage_stat_test(storage_name) } + end + + res << operation_metrics(:filesystem_writable, :filesystem_write_latency_seconds, shard: storage_name) do + with_temp_file(storage_name) do |tmp_file_path| + with_timing { storage_write_test(tmp_file_path) } + end + end + + res << operation_metrics(:filesystem_readable, :filesystem_read_latency_seconds, shard: storage_name) do + with_temp_file(storage_name) do |tmp_file_path| + storage_write_test(tmp_file_path) # writes data used by read test + with_timing { storage_read_test(tmp_file_path) } + end + end end + res.flatten end private - def operation_metrics(ok_metric, latency_metric, operation, **labels) - with_timing operation do |result, elapsed| - [ - metric(latency_metric, elapsed, **labels), - metric(ok_metric, result ? 1 : 0, **labels) - ] - end + def operation_metrics(ok_metric, latency_metric, **labels) + result, elapsed = yield + [ + metric(latency_metric, elapsed, **labels), + metric(ok_metric, result ? 1 : 0, **labels) + ] rescue RuntimeError => ex Rails.logger.error("unexpected error #{ex} when checking #{ok_metric}") [metric(ok_metric, 0, **labels)] end + def repository_storages @repository_storage ||= Gitlab::CurrentSettings.current_application_settings.repository_storages end @@ -68,8 +80,13 @@ module Gitlab Gitlab::Popen.popen([TIMEOUT_EXECUTABLE, COMMAND_TIMEOUT].concat(cmd_args), *args, &block) end - def tmp_file_path(storage_name) - Dir::Tmpname.create(%w(fs_shards_check +deleted), path(storage_name)) { |path| path } + def with_temp_file(storage_name) + begin + temp_file_path = Dir::Tmpname.create(%w(fs_shards_check +deleted), path(storage_name)) { |path| path } + yield temp_file_path + ensure + delete_test_file(temp_file_path) + end end def path(storage_name) diff --git a/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb b/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb index 3de73a9ff65..947fb1b64d0 100644 --- a/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb +++ b/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb @@ -131,6 +131,12 @@ describe Gitlab::HealthChecks::FsShardsCheck do expect(subject).to include(an_object_having_attributes(name: :filesystem_read_latency_seconds, value: be >= 0)) expect(subject).to include(an_object_having_attributes(name: :filesystem_write_latency_seconds, value: be >= 0)) end + + it 'cleans up files used for metrics' do + subject + + expect(Dir.entries(tmp_dir).count).to eq(2) + end end end end -- cgit v1.2.1 From b1d6670d049c9645ddf4def369de0b12521692b5 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Tue, 25 Jul 2017 14:30:27 +0200 Subject: Add Changelog about temp file removal fix + remove whitespace --- .../pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml | 4 ++++ lib/gitlab/health_checks/fs_shards_check.rb | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml diff --git a/changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml b/changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml new file mode 100644 index 00000000000..4906232237f --- /dev/null +++ b/changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml @@ -0,0 +1,4 @@ +--- +title: Ensure fs metrics test files are deleted +merge_request: +author: diff --git a/lib/gitlab/health_checks/fs_shards_check.rb b/lib/gitlab/health_checks/fs_shards_check.rb index 45cd8f7eefc..ab18701b3bf 100644 --- a/lib/gitlab/health_checks/fs_shards_check.rb +++ b/lib/gitlab/health_checks/fs_shards_check.rb @@ -67,7 +67,6 @@ module Gitlab [metric(ok_metric, 0, **labels)] end - def repository_storages @repository_storage ||= Gitlab::CurrentSettings.current_application_settings.repository_storages end -- cgit v1.2.1 From ad46c8878b3102f74e211ef72ff5347b89aee14c Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Tue, 25 Jul 2017 13:48:30 +0200 Subject: Add `api` prefix as a top level route in the spec. Now that it has been removed from the rails routes. But it still needs to be a reserved top-level word, so the tests should know about this. --- spec/lib/gitlab/path_regex_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/gitlab/path_regex_spec.rb b/spec/lib/gitlab/path_regex_spec.rb index c38bbb64fc3..20be743d224 100644 --- a/spec/lib/gitlab/path_regex_spec.rb +++ b/spec/lib/gitlab/path_regex_spec.rb @@ -86,7 +86,7 @@ describe Gitlab::PathRegex, lib: true do route.split('/')[1] end.compact.uniq - words + ee_top_level_words + files_in_public + words + ee_top_level_words + files_in_public + Array(API::API.prefix.to_s) end let(:ee_top_level_words) do -- cgit v1.2.1 From 37f27079fe16ffb6f8dbb888593335a361f5964a Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Tue, 25 Jul 2017 15:17:05 +0200 Subject: Fix redis check with_timing method usage --- lib/gitlab/health_checks/simple_abstract_check.rb | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/gitlab/health_checks/simple_abstract_check.rb b/lib/gitlab/health_checks/simple_abstract_check.rb index 3dcb28a193c..f5026171ba4 100644 --- a/lib/gitlab/health_checks/simple_abstract_check.rb +++ b/lib/gitlab/health_checks/simple_abstract_check.rb @@ -15,14 +15,13 @@ module Gitlab end def metrics - with_timing method(:check) do |result, elapsed| - Rails.logger.error("#{human_name} check returned unexpected result #{result}") unless is_successful?(result) - [ - metric("#{metric_prefix}_timeout", result.is_a?(Timeout::Error) ? 1 : 0), - metric("#{metric_prefix}_success", is_successful?(result) ? 1 : 0), - metric("#{metric_prefix}_latency_seconds", elapsed) - ] - end + result, elapsed = with_timing(&method(:check)) + Rails.logger.error("#{human_name} check returned unexpected result #{result}") unless is_successful?(result) + [ + metric("#{metric_prefix}_timeout", result.is_a?(Timeout::Error) ? 1 : 0), + metric("#{metric_prefix}_success", is_successful?(result) ? 1 : 0), + metric("#{metric_prefix}_latency_seconds", elapsed) + ] end private -- cgit v1.2.1 From a78306e7fa0e815a5586a81ee9c2fcf095793de4 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 25 Jul 2017 13:59:50 +0200 Subject: Enable gitaly_post_upload_pack by default --- changelogs/unreleased/post-upload-pack-opt-out.yml | 4 ++++ lib/gitlab/workhorse.rb | 5 ++++- spec/lib/gitlab/workhorse_spec.rb | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/post-upload-pack-opt-out.yml diff --git a/changelogs/unreleased/post-upload-pack-opt-out.yml b/changelogs/unreleased/post-upload-pack-opt-out.yml new file mode 100644 index 00000000000..302a99795a0 --- /dev/null +++ b/changelogs/unreleased/post-upload-pack-opt-out.yml @@ -0,0 +1,4 @@ +--- +title: Enable gitaly_post_upload_pack by default +merge_request: 13078 +author: diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb index 5dd8a38fea2..3f25e463412 100644 --- a/lib/gitlab/workhorse.rb +++ b/lib/gitlab/workhorse.rb @@ -35,7 +35,10 @@ module Gitlab when 'git_receive_pack' Gitlab::GitalyClient.feature_enabled?(:post_receive_pack) when 'git_upload_pack' - Gitlab::GitalyClient.feature_enabled?(:post_upload_pack) + Gitlab::GitalyClient.feature_enabled?( + :post_upload_pack, + status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT + ) when 'info_refs' true else diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb index 7b39441e76e..6ca1edb01b9 100644 --- a/spec/lib/gitlab/workhorse_spec.rb +++ b/spec/lib/gitlab/workhorse_spec.rb @@ -237,7 +237,8 @@ describe Gitlab::Workhorse, lib: true do context 'when action is not enabled by feature flag' do it 'does not include Gitaly params in the returned value' do - allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(feature_flag).and_return(false) + status_opt_out = Gitlab::GitalyClient::MigrationStatus::OPT_OUT + allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(feature_flag, status: status_opt_out).and_return(false) expect(subject).not_to include(gitaly_params) end -- cgit v1.2.1 From 3f59e354a7324e9bf332a34661743d85e82b987c Mon Sep 17 00:00:00 2001 From: James Edwards-Jones Date: Tue, 25 Jul 2017 15:28:13 +0100 Subject: Update CHANGELOG.md for 9.4.1 [ci skip] --- CHANGELOG.md | 12 ++++++++++++ changelogs/unreleased/35399-mini-graph-commits-box.yml | 4 ---- .../35444-error-500-viewing-notes-with-anonymous-user.yml | 4 ---- changelogs/unreleased/bvl-fix-invalid-po-files.yml | 4 ---- .../unreleased/bvl-fix-login-issue-with-ldap-enabled.yml | 5 ----- .../fix-gb-project-update-with-registry-images.yml | 4 ---- ...-sm-32790-pipeline_schedules-pages-throwing-error-500.yml | 4 ---- changelogs/unreleased/issue-boards-close-icon-size.yml | 4 ---- .../unreleased/new-nav-duplicated-new-milestone-buttons.yml | 4 ---- changelogs/unreleased/pawel-fix-metrics-files-handling.yml | 4 ---- 10 files changed, 12 insertions(+), 37 deletions(-) delete mode 100644 changelogs/unreleased/35399-mini-graph-commits-box.yml delete mode 100644 changelogs/unreleased/35444-error-500-viewing-notes-with-anonymous-user.yml delete mode 100644 changelogs/unreleased/bvl-fix-invalid-po-files.yml delete mode 100644 changelogs/unreleased/bvl-fix-login-issue-with-ldap-enabled.yml delete mode 100644 changelogs/unreleased/fix-gb-project-update-with-registry-images.yml delete mode 100644 changelogs/unreleased/fix-sm-32790-pipeline_schedules-pages-throwing-error-500.yml delete mode 100644 changelogs/unreleased/issue-boards-close-icon-size.yml delete mode 100644 changelogs/unreleased/new-nav-duplicated-new-milestone-buttons.yml delete mode 100644 changelogs/unreleased/pawel-fix-metrics-files-handling.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index daf154eeb07..580d2357512 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 9.4.1 (2017-07-25) + +- Fix pipeline_schedules pages throwing error 500 (when ref is empty). !12983 +- Fix editing project with container images present. !13028 +- Fix some invalid entries in PO files. !13032 +- Fix cross site request protection when logging in as a regular user when LDAP is enabled. !13049 +- Fix bug causing metrics files to be truncated. !35420 +- Fix anonymous access to public projects in groups with pending invites. +- Fixed issue boards sidebar close icon size. +- Fixed duplicate new milestone buttons when new navigation is turned on. +- Fix margins in the mini graph for pipeline in commits box. + ## 9.4.0 (2017-07-22) - Add blame view age mapping. !7198 (Jeff Stubler) diff --git a/changelogs/unreleased/35399-mini-graph-commits-box.yml b/changelogs/unreleased/35399-mini-graph-commits-box.yml deleted file mode 100644 index ed080ed86b4..00000000000 --- a/changelogs/unreleased/35399-mini-graph-commits-box.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix margins in the mini graph for pipeline in commits box -merge_request: -author: diff --git a/changelogs/unreleased/35444-error-500-viewing-notes-with-anonymous-user.yml b/changelogs/unreleased/35444-error-500-viewing-notes-with-anonymous-user.yml deleted file mode 100644 index 9b8bc1d0d99..00000000000 --- a/changelogs/unreleased/35444-error-500-viewing-notes-with-anonymous-user.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix anonymous access to public projects in groups with pending invites -merge_request: -author: diff --git a/changelogs/unreleased/bvl-fix-invalid-po-files.yml b/changelogs/unreleased/bvl-fix-invalid-po-files.yml deleted file mode 100644 index b8a22a9e6df..00000000000 --- a/changelogs/unreleased/bvl-fix-invalid-po-files.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix some invalid entries in PO files -merge_request: 13032 -author: diff --git a/changelogs/unreleased/bvl-fix-login-issue-with-ldap-enabled.yml b/changelogs/unreleased/bvl-fix-login-issue-with-ldap-enabled.yml deleted file mode 100644 index a98455d0916..00000000000 --- a/changelogs/unreleased/bvl-fix-login-issue-with-ldap-enabled.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix cross site request protection when logging in as a regular user when LDAP - is enabled -merge_request: 13049 -author: diff --git a/changelogs/unreleased/fix-gb-project-update-with-registry-images.yml b/changelogs/unreleased/fix-gb-project-update-with-registry-images.yml deleted file mode 100644 index a54a34c71d4..00000000000 --- a/changelogs/unreleased/fix-gb-project-update-with-registry-images.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix editing project with container images present -merge_request: 13028 -author: diff --git a/changelogs/unreleased/fix-sm-32790-pipeline_schedules-pages-throwing-error-500.yml b/changelogs/unreleased/fix-sm-32790-pipeline_schedules-pages-throwing-error-500.yml deleted file mode 100644 index 334d8ca4d9e..00000000000 --- a/changelogs/unreleased/fix-sm-32790-pipeline_schedules-pages-throwing-error-500.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix pipeline_schedules pages throwing error 500 (when ref is empty) -merge_request: 12983 -author: diff --git a/changelogs/unreleased/issue-boards-close-icon-size.yml b/changelogs/unreleased/issue-boards-close-icon-size.yml deleted file mode 100644 index bc6bda0e50d..00000000000 --- a/changelogs/unreleased/issue-boards-close-icon-size.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixed issue boards sidebar close icon size -merge_request: -author: diff --git a/changelogs/unreleased/new-nav-duplicated-new-milestone-buttons.yml b/changelogs/unreleased/new-nav-duplicated-new-milestone-buttons.yml deleted file mode 100644 index fcf7d8e63d6..00000000000 --- a/changelogs/unreleased/new-nav-duplicated-new-milestone-buttons.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixed duplicate new milestone buttons when new navigation is turned on -merge_request: -author: diff --git a/changelogs/unreleased/pawel-fix-metrics-files-handling.yml b/changelogs/unreleased/pawel-fix-metrics-files-handling.yml deleted file mode 100644 index cfdb4246af9..00000000000 --- a/changelogs/unreleased/pawel-fix-metrics-files-handling.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix bug causing metrics files to be truncated -merge_request: 35420 -author: -- cgit v1.2.1 From 1c572994004acbd442c05537cb5062cd2e5d29e6 Mon Sep 17 00:00:00 2001 From: Jarka Kadlecova Date: Tue, 25 Jul 2017 17:25:41 +0200 Subject: Remove project_key from the Jira configuration --- app/models/project_services/jira_service.rb | 18 +++--------------- .../unreleased/31129-jira-project-key-elim.yml | 4 ++++ doc/user/project/integrations/jira.md | 4 ++-- features/steps/project/services.rb | 1 - lib/api/services.rb | 6 ------ .../features/projects/services/jira_service_spec.rb | 21 +++++++-------------- spec/models/project_services/jira_service_spec.rb | 10 +++------- spec/support/jira_service_helper.rb | 2 +- 8 files changed, 20 insertions(+), 46 deletions(-) create mode 100644 changelogs/unreleased/31129-jira-project-key-elim.yml diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 450027c2e57..37f2c96a22f 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -3,10 +3,8 @@ class JiraService < IssueTrackerService validates :url, url: true, presence: true, if: :activated? validates :api_url, url: true, allow_blank: true - validates :project_key, presence: true, if: :activated? - prop_accessor :username, :password, :url, :api_url, :project_key, - :jira_issue_transition_id, :title, :description + prop_accessor :username, :password, :url, :api_url, :jira_issue_transition_id, :title, :description before_update :reset_password @@ -54,10 +52,6 @@ class JiraService < IssueTrackerService @client ||= JIRA::Client.new(options) end - def jira_project - @jira_project ||= jira_request { client.Project.find(project_key) } - end - def help "You need to configure JIRA before enabling this service. For more details read the @@ -88,18 +82,12 @@ class JiraService < IssueTrackerService [ { type: 'text', name: 'url', title: 'Web URL', placeholder: 'https://jira.example.com', required: true }, { type: 'text', name: 'api_url', title: 'JIRA API URL', placeholder: 'If different from Web URL' }, - { type: 'text', name: 'project_key', placeholder: 'Project Key', required: true }, { type: 'text', name: 'username', placeholder: '', required: true }, { type: 'password', name: 'password', placeholder: '', required: true }, - { type: 'text', name: 'jira_issue_transition_id', placeholder: '' } + { type: 'text', name: 'jira_issue_transition_id', title: 'Transition ID', placeholder: '' } ] end - # URLs to redirect from Gitlab issues pages to jira issue tracker - def project_url - "#{url}/issues/?jql=project=#{project_key}" - end - def issues_url "#{url}/browse/:id" end @@ -184,7 +172,7 @@ class JiraService < IssueTrackerService def test_settings return unless client_url.present? # Test settings by getting the project - jira_request { jira_project.present? } + jira_request { client.ServerInfo.all.attrs } end private diff --git a/changelogs/unreleased/31129-jira-project-key-elim.yml b/changelogs/unreleased/31129-jira-project-key-elim.yml new file mode 100644 index 00000000000..bfa0e99f250 --- /dev/null +++ b/changelogs/unreleased/31129-jira-project-key-elim.yml @@ -0,0 +1,4 @@ +--- +title: Remove project_key from the Jira configuration +merge_request: 12050 +author: diff --git a/doc/user/project/integrations/jira.md b/doc/user/project/integrations/jira.md index cf03f2a9033..cfa4c8a93f8 100644 --- a/doc/user/project/integrations/jira.md +++ b/doc/user/project/integrations/jira.md @@ -98,11 +98,11 @@ in the table below. | Field | Description | | ----- | ----------- | | `Web URL` | The base URL to the JIRA instance web interface which is being linked to this GitLab project. E.g., `https://jira.example.com`. | -| `JIRA API URL` | The base URL to the JIRA instance API. E.g., `https://jira-api.example.com`. This is optional. If not entered, the Web URL value be used. | +| `JIRA API URL` | The base URL to the JIRA instance API. Web URL value will be used if not set. E.g., `https://jira-api.example.com`. | | `Project key` | Put a JIRA project key (in uppercase), e.g. `MARS` in this field. This is only for testing the configuration settings. JIRA integration in GitLab works with _all_ JIRA projects in your JIRA instance. This field will be removed in a future release. | | `Username` | The user name created in [configuring JIRA step](#configuring-jira). | | `Password` |The password of the user created in [configuring JIRA step](#configuring-jira). | -| `JIRA issue transition` | This is the ID of a transition that moves issues to a closed state. You can find this number under JIRA workflow administration ([see screenshot](img/jira_workflow_screenshot.png)). **Closing JIRA issues via commits or Merge Requests won't work if you don't set the ID correctly.** | +| `Transition ID` | This is the ID of a transition that moves issues to a closed state. You can find this number under JIRA workflow administration ([see screenshot](img/jira_workflow_screenshot.png)). **Closing JIRA issues via commits or Merge Requests won't work if you don't set the ID correctly.** | After saving the configuration, your GitLab project will be able to interact with all JIRA projects in your JIRA instance. diff --git a/features/steps/project/services.rb b/features/steps/project/services.rb index 906a81b29b3..7e2a357f6b2 100644 --- a/features/steps/project/services.rb +++ b/features/steps/project/services.rb @@ -175,7 +175,6 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps fill_in 'JIRA API URL', with: 'http://jira.example/api' fill_in 'Username', with: 'gitlab' fill_in 'Password', with: 'gitlab' - fill_in 'Project Key', with: 'GITLAB' click_button 'Save' end diff --git a/lib/api/services.rb b/lib/api/services.rb index 7488f95a9b7..843c05ae32e 100644 --- a/lib/api/services.rb +++ b/lib/api/services.rb @@ -312,12 +312,6 @@ module API type: String, desc: 'The base URL to the JIRA instance API. Web URL value will be used if not set. E.g., https://jira-api.example.com' }, - { - required: true, - name: :project_key, - type: String, - desc: 'The short identifier for your JIRA project, all uppercase, e.g., PROJ' - }, { required: false, name: :username, diff --git a/spec/features/projects/services/jira_service_spec.rb b/spec/features/projects/services/jira_service_spec.rb index 7c29af247d6..b71eec0ecfd 100644 --- a/spec/features/projects/services/jira_service_spec.rb +++ b/spec/features/projects/services/jira_service_spec.rb @@ -6,17 +6,12 @@ feature 'Setup Jira service', :feature, :js do let(:service) { project.create_jira_service } let(:url) { 'http://jira.example.com' } - - def stub_project_url - WebMock.stub_request(:get, 'http://jira.example.com/rest/api/2/project/GitLabProject') - .with(basic_auth: %w(username password)) - end + let(:test_url) { 'http://jira.example.com/rest/api/2/serverInfo' } def fill_form(active = true) check 'Active' if active fill_in 'service_url', with: url - fill_in 'service_project_key', with: 'GitLabProject' fill_in 'service_username', with: 'username' fill_in 'service_password', with: 'password' fill_in 'service_jira_issue_transition_id', with: '25' @@ -31,11 +26,10 @@ feature 'Setup Jira service', :feature, :js do describe 'user sets and activates Jira Service' do context 'when Jira connection test succeeds' do - before do - stub_project_url - end - it 'activates the JIRA service' do + server_info = { key: 'value' }.to_json + WebMock.stub_request(:get, test_url).with(basic_auth: %w(username password)).to_return(body: server_info) + click_link('JIRA') fill_form click_button('Test settings and save changes') @@ -47,10 +41,6 @@ feature 'Setup Jira service', :feature, :js do end context 'when Jira connection test fails' do - before do - stub_project_url.to_return(status: 401) - end - it 'shows errors when some required fields are not filled in' do click_link('JIRA') @@ -64,6 +54,9 @@ feature 'Setup Jira service', :feature, :js do end it 'activates the JIRA service' do + WebMock.stub_request(:get, test_url).with(basic_auth: %w(username password)) + .to_raise(JIRA::HTTPError.new(double(message: 'message'))) + click_link('JIRA') fill_form click_button('Test settings and save changes') diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 105afed1337..d7d09808a98 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -15,7 +15,6 @@ describe JiraService, models: true do end it { is_expected.to validate_presence_of(:url) } - it { is_expected.to validate_presence_of(:project_key) } it_behaves_like 'issue tracker service URL attribute', :url end @@ -34,7 +33,6 @@ describe JiraService, models: true do active: true, username: 'username', password: 'test', - project_key: 'TEST', jira_issue_transition_id: 24, url: 'http://jira.test.com' ) @@ -88,7 +86,6 @@ describe JiraService, models: true do url: 'http://jira.example.com', username: 'gitlab_jira_username', password: 'gitlab_jira_password', - project_key: 'GitLabProject', jira_issue_transition_id: "custom-id" ) @@ -196,15 +193,14 @@ describe JiraService, models: true do project: create(:project), url: 'http://jira.example.com', username: 'jira_username', - password: 'jira_password', - project_key: 'GitLabProject' + password: 'jira_password' ) end def test_settings(api_url) - project_url = "http://#{api_url}/rest/api/2/project/GitLabProject" + test_url = "http://#{api_url}/rest/api/2/serverInfo" - WebMock.stub_request(:get, project_url).with(basic_auth: %w(jira_username jira_password)) + WebMock.stub_request(:get, test_url).with(basic_auth: %w(jira_username jira_password)).to_return(body: { url: 'http://url' }.to_json ) jira_service.test_settings end diff --git a/spec/support/jira_service_helper.rb b/spec/support/jira_service_helper.rb index 97ae0b6afc5..0b5f66597fd 100644 --- a/spec/support/jira_service_helper.rb +++ b/spec/support/jira_service_helper.rb @@ -51,7 +51,7 @@ module JiraServiceHelper end def jira_project_url - JIRA_API + "/project/#{jira_tracker.project_key}" + JIRA_API + "/project" end def jira_api_comment_url(issue_id) -- cgit v1.2.1 From fe27de8bf124d65013da1d82618a1ab45584ff68 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 25 Jul 2017 16:27:51 +0100 Subject: moved some code into new files fixed duplication of code --- app/assets/javascripts/dispatcher.js | 40 ++----------------------- app/assets/javascripts/init_issuable_sidebar.js | 16 ++++++++++ app/assets/javascripts/init_legacy_filters.js | 14 +++++++++ app/assets/javascripts/init_notes.js | 14 +++++++++ app/assets/javascripts/main.js | 5 ++++ app/assets/javascripts/todos.js | 4 --- 6 files changed, 52 insertions(+), 41 deletions(-) create mode 100644 app/assets/javascripts/init_issuable_sidebar.js create mode 100644 app/assets/javascripts/init_legacy_filters.js create mode 100644 app/assets/javascripts/init_notes.js diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 8a142e49b72..2802c3a375a 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -30,7 +30,6 @@ /* global IssuableContext */ /* global IssueStatusSelect */ /* global SubscriptionSelect */ -/* global Notes */ import Issue from './issue'; import BindInOut from './behaviors/bind_in_out'; @@ -66,6 +65,9 @@ import initSettingsPanels from './settings_panels'; import initExperimentalFlags from './experimental_flags'; import OAuthRememberMe from './oauth_remember_me'; import PerformanceBar from './performance_bar'; +import initNotes from './init_notes'; +import initLegacyFilters from './init_legacy_filters'; +import initIssuableSidebar from './init_issuable_sidebar'; (function() { var Dispatcher; @@ -130,42 +132,6 @@ import PerformanceBar from './performance_bar'; .init(); } - function initIssuableSidebar() { - new MilestoneSelect({ - full_path: gl.sidebarOptions.fullPath, - }); - new LabelsSelect(); - new IssuableContext(gl.sidebarOptions.currentUser); - gl.Subscription.bindAll('.subscription'); - new gl.DueDateSelectors(); - window.sidebar = new Sidebar(); - } - - function initLegacyFilters() { - new UsersSelect(); - new LabelsSelect(); - new MilestoneSelect(); - new IssueStatusSelect(); - new SubscriptionSelect(); - $('form.filter-form').on('submit', function (event) { - event.preventDefault(); - gl.utils.visitUrl(`${this.action}&${$(this).serialize()}`); - }); - } - - function initNotes() { - const dataEl = document.querySelector('.js-notes-data'); - const { - notesUrl, - notesIds, - now, - diffView, - autocomplete, - } = JSON.parse(dataEl.innerHTML); - - window.notes = new Notes(notesUrl, notesIds, now, diffView, autocomplete); - } - switch (page) { case 'profiles:preferences:show': initExperimentalFlags(); diff --git a/app/assets/javascripts/init_issuable_sidebar.js b/app/assets/javascripts/init_issuable_sidebar.js new file mode 100644 index 00000000000..82071348d99 --- /dev/null +++ b/app/assets/javascripts/init_issuable_sidebar.js @@ -0,0 +1,16 @@ +/* eslint-disable no-new */ +/* global MilestoneSelect */ +/* global LabelsSelect */ +/* global IssuableContext */ +/* global Sidebar */ + +export default () => { + new MilestoneSelect({ + full_path: gl.sidebarOptions.fullPath, + }); + new LabelsSelect(); + new IssuableContext(gl.sidebarOptions.currentUser); + gl.Subscription.bindAll('.subscription'); + new gl.DueDateSelectors(); + window.sidebar = new Sidebar(); +}; diff --git a/app/assets/javascripts/init_legacy_filters.js b/app/assets/javascripts/init_legacy_filters.js new file mode 100644 index 00000000000..aa25f295bbc --- /dev/null +++ b/app/assets/javascripts/init_legacy_filters.js @@ -0,0 +1,14 @@ +/* eslint-disable no-new */ +/* global UsersSelect */ +/* global LabelsSelect */ +/* global MilestoneSelect */ +/* global IssueStatusSelect */ +/* global SubscriptionSelect */ + +export default () => { + new UsersSelect(); + new LabelsSelect(); + new MilestoneSelect(); + new IssueStatusSelect(); + new SubscriptionSelect(); +}; diff --git a/app/assets/javascripts/init_notes.js b/app/assets/javascripts/init_notes.js new file mode 100644 index 00000000000..3a8b4360cb6 --- /dev/null +++ b/app/assets/javascripts/init_notes.js @@ -0,0 +1,14 @@ +/* global Notes */ + +export default () => { + const dataEl = document.querySelector('.js-notes-data'); + const { + notesUrl, + notesIds, + now, + diffView, + autocomplete, + } = JSON.parse(dataEl.innerHTML); + + window.notes = new Notes(notesUrl, notesIds, now, diffView, autocomplete); +}; diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 6d3f5390cf6..3afc420140d 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -346,4 +346,9 @@ $(function () { gl.utils.renderTimeago(); $(document).trigger('init.scrolling-tabs'); + + $('form.filter-form').on('submit', function (event) { + event.preventDefault(); + gl.utils.visitUrl(`${this.action}&${$(this).serialize()}`); + }); }); diff --git a/app/assets/javascripts/todos.js b/app/assets/javascripts/todos.js index cd305631c10..bba8b5abbb4 100644 --- a/app/assets/javascripts/todos.js +++ b/app/assets/javascripts/todos.js @@ -37,10 +37,6 @@ export default class Todos { this.initFilterDropdown($('.js-type-search'), 'type'); this.initFilterDropdown($('.js-action-search'), 'action_id'); - $('form.filter-form').on('submit', function applyFilters(event) { - event.preventDefault(); - gl.utils.visitUrl(`${this.action}&${$(this).serialize()}`); - }); return new UsersSelect(); } -- cgit v1.2.1 From 887227e0371858d5d048f61bfe0700e4b7ebab58 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 25 Jul 2017 16:46:15 +0100 Subject: moved some more inline code removed some global variable comments --- app/assets/javascripts/dispatcher.js | 3 --- app/assets/javascripts/init_issuable_sidebar.js | 6 ++++-- app/assets/javascripts/issuable_context.js | 4 +++- app/assets/javascripts/sidebar/sidebar_bundle.js | 3 ++- app/helpers/issuables_helper.rb | 10 ++++++++++ app/views/shared/issuable/_sidebar.html.haml | 9 +-------- 6 files changed, 20 insertions(+), 15 deletions(-) diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 2802c3a375a..0b2c7e434f0 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -27,9 +27,6 @@ /* global Shortcuts */ /* global Sidebar */ /* global ShortcutsWiki */ -/* global IssuableContext */ -/* global IssueStatusSelect */ -/* global SubscriptionSelect */ import Issue from './issue'; import BindInOut from './behaviors/bind_in_out'; diff --git a/app/assets/javascripts/init_issuable_sidebar.js b/app/assets/javascripts/init_issuable_sidebar.js index 82071348d99..29e3d2ea94e 100644 --- a/app/assets/javascripts/init_issuable_sidebar.js +++ b/app/assets/javascripts/init_issuable_sidebar.js @@ -5,11 +5,13 @@ /* global Sidebar */ export default () => { + const sidebarOptions = JSON.parse(document.querySelector('.js-sidebar-options').innerHTML); + new MilestoneSelect({ - full_path: gl.sidebarOptions.fullPath, + full_path: sidebarOptions.fullPath, }); new LabelsSelect(); - new IssuableContext(gl.sidebarOptions.currentUser); + new IssuableContext(sidebarOptions.currentUser); gl.Subscription.bindAll('.subscription'); new gl.DueDateSelectors(); window.sidebar = new Sidebar(); diff --git a/app/assets/javascripts/issuable_context.js b/app/assets/javascripts/issuable_context.js index a45ff3fc43e..26392db4b5b 100644 --- a/app/assets/javascripts/issuable_context.js +++ b/app/assets/javascripts/issuable_context.js @@ -4,6 +4,8 @@ import Cookies from 'js-cookie'; import UsersSelect from './users_select'; +const PARTICIPANTS_ROW_COUNT = 7; + (function() { this.IssuableContext = (function() { function IssuableContext(currentUser) { @@ -52,7 +54,7 @@ import UsersSelect from './users_select'; IssuableContext.prototype.initParticipants = function() { $(document).on("click", ".js-participants-more", this.toggleHiddenParticipants); return $(".js-participants-author").each(function(i) { - if (i >= 7) { + if (i >= PARTICIPANTS_ROW_COUNT) { return $(this).addClass("js-participants-hidden").hide(); } }); diff --git a/app/assets/javascripts/sidebar/sidebar_bundle.js b/app/assets/javascripts/sidebar/sidebar_bundle.js index 2b02af87d8a..a9df66748c5 100644 --- a/app/assets/javascripts/sidebar/sidebar_bundle.js +++ b/app/assets/javascripts/sidebar/sidebar_bundle.js @@ -5,7 +5,8 @@ import sidebarAssignees from './components/assignees/sidebar_assignees'; import Mediator from './sidebar_mediator'; function domContentLoaded() { - const mediator = new Mediator(gl.sidebarOptions); + const sidebarOptions = JSON.parse(document.querySelector('.js-sidebar-options').innerHTML); + const mediator = new Mediator(sidebarOptions); mediator.fetch(); const sidebarAssigneesEl = document.querySelector('#js-vue-sidebar-assignees'); diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 425af547330..f4fad7150e8 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -354,4 +354,14 @@ module IssuablesHelper params[:format] = :json if issuable.is_a?(Issue) end end + + def issuable_sidebar_options(issuable, can_edit_issuable) + { + endpoint: "#{issuable_json_path(issuable)}?basic=true", + editable: can_edit_issuable, + currentUser: current_user.as_json(only: [:username, :id, :name], methods: :avatar_url), + rootPath: root_path, + fullPath: @project.full_path + } + end end diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index 094f2472693..b08267357e5 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -138,11 +138,4 @@ = project_ref = clipboard_button(text: project_ref, title: "Copy reference to clipboard", placement: "left") - :javascript - gl.sidebarOptions = { - endpoint: "#{issuable_json_path(issuable)}?basic=true", - editable: #{can_edit_issuable ? true : false}, - currentUser: #{current_user.to_json(only: [:username, :id, :name], methods: :avatar_url)}, - rootPath: "#{root_path}", - fullPath: "#{@project.full_path}", - }; + %script.js-sidebar-options{ type: "application/json" }= issuable_sidebar_options(issuable, can_edit_issuable).to_json.html_safe -- cgit v1.2.1 From 6263ecd3a42312a62957674665e35d3590192123 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Mon, 24 Jul 2017 15:09:55 -0700 Subject: Add lower path index to redirect_routes --- .../mk-add-lower-path-index-to-redirect-routes.yml | 4 +++ ...4302_add_lower_path_index_to_redirect_routes.rb | 34 ++++++++++++++++++++++ db/schema.rb | 2 +- lib/tasks/migrate/setup_postgresql.rake | 2 ++ 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/mk-add-lower-path-index-to-redirect-routes.yml create mode 100644 db/migrate/20170724214302_add_lower_path_index_to_redirect_routes.rb diff --git a/changelogs/unreleased/mk-add-lower-path-index-to-redirect-routes.yml b/changelogs/unreleased/mk-add-lower-path-index-to-redirect-routes.yml new file mode 100644 index 00000000000..37a5fa66d13 --- /dev/null +++ b/changelogs/unreleased/mk-add-lower-path-index-to-redirect-routes.yml @@ -0,0 +1,4 @@ +--- +title: Improve redirect route query performance +merge_request: 13062 +author: diff --git a/db/migrate/20170724214302_add_lower_path_index_to_redirect_routes.rb b/db/migrate/20170724214302_add_lower_path_index_to_redirect_routes.rb new file mode 100644 index 00000000000..db60c2087b9 --- /dev/null +++ b/db/migrate/20170724214302_add_lower_path_index_to_redirect_routes.rb @@ -0,0 +1,34 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddLowerPathIndexToRedirectRoutes < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + INDEX_NAME = 'index_on_redirect_routes_lower_path' + + disable_ddl_transaction! + + def up + return unless Gitlab::Database.postgresql? + + execute "CREATE INDEX CONCURRENTLY #{INDEX_NAME} ON redirect_routes (LOWER(path));" + end + + def down + return unless Gitlab::Database.postgresql? + + # Why not use remove_concurrent_index_by_name? + # + # `index_exists?` doesn't work on this index. Perhaps this is related to the + # fact that the index doesn't show up in the schema. And apparently it isn't + # trivial to write a query that checks for an index. BUT there is a + # convenient `IF EXISTS` parameter for `DROP INDEX`. + if supports_drop_index_concurrently? + disable_statement_timeout + execute "DROP INDEX CONCURRENTLY IF EXISTS #{INDEX_NAME};" + else + execute "DROP INDEX IF EXISTS #{INDEX_NAME};" + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 284b2068166..7724af5b610 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: 20170717150329) do +ActiveRecord::Schema.define(version: 20170724214302) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" diff --git a/lib/tasks/migrate/setup_postgresql.rake b/lib/tasks/migrate/setup_postgresql.rake index 4108cee08b4..9cc986535e1 100644 --- a/lib/tasks/migrate/setup_postgresql.rake +++ b/lib/tasks/migrate/setup_postgresql.rake @@ -4,6 +4,7 @@ require Rails.root.join('db/migrate/20151007120511_namespaces_projects_path_lowe require Rails.root.join('db/migrate/20151008110232_add_users_lower_username_email_indexes') require Rails.root.join('db/migrate/20161212142807_add_lower_path_index_to_routes') require Rails.root.join('db/migrate/20170317203554_index_routes_path_for_like') +require Rails.root.join('db/migrate/20170724214302_add_lower_path_index_to_redirect_routes') require Rails.root.join('db/migrate/20170503185032_index_redirect_routes_path_for_like') desc 'GitLab | Sets up PostgreSQL' @@ -12,5 +13,6 @@ task setup_postgresql: :environment do AddUsersLowerUsernameEmailIndexes.new.up AddLowerPathIndexToRoutes.new.up IndexRoutesPathForLike.new.up + AddLowerPathIndexToRedirectRoutes.new.up IndexRedirectRoutesPathForLike.new.up end -- cgit v1.2.1 From 22d53f06076e52165af3ba04d0b703bed20cfb97 Mon Sep 17 00:00:00 2001 From: Tiago Botelho Date: Tue, 25 Jul 2017 10:09:21 +0100 Subject: Fixes 500 error caused by pending delete projects in admin dashboard --- app/controllers/admin/dashboard_controller.rb | 2 +- ...delete-projects-error-in-admin-dashboard-fix.yml | 4 ++++ spec/controllers/admin/dashboard_controller_spec.rb | 21 +++++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/35453-pending-delete-projects-error-in-admin-dashboard-fix.yml create mode 100644 spec/controllers/admin/dashboard_controller_spec.rb diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb index 8360ce08bdc..05e749c00c0 100644 --- a/app/controllers/admin/dashboard_controller.rb +++ b/app/controllers/admin/dashboard_controller.rb @@ -1,6 +1,6 @@ class Admin::DashboardController < Admin::ApplicationController def index - @projects = Project.with_route.limit(10) + @projects = Project.without_deleted.with_route.limit(10) @users = User.limit(10) @groups = Group.with_route.limit(10) end diff --git a/changelogs/unreleased/35453-pending-delete-projects-error-in-admin-dashboard-fix.yml b/changelogs/unreleased/35453-pending-delete-projects-error-in-admin-dashboard-fix.yml new file mode 100644 index 00000000000..fa906accbb8 --- /dev/null +++ b/changelogs/unreleased/35453-pending-delete-projects-error-in-admin-dashboard-fix.yml @@ -0,0 +1,4 @@ +--- +title: Fixes 500 error caused by pending delete projects in admin dashboard +merge_request: 13067 +author: diff --git a/spec/controllers/admin/dashboard_controller_spec.rb b/spec/controllers/admin/dashboard_controller_spec.rb new file mode 100644 index 00000000000..6eb9f7867d5 --- /dev/null +++ b/spec/controllers/admin/dashboard_controller_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe Admin::DashboardController do + describe '#index' do + context 'with pending_delete projects' do + render_views + + it 'does not retrieve projects that are pending deletion' do + sign_in(create(:admin)) + + project = create(:project) + pending_delete_project = create(:project, pending_delete: true) + + get :index + + expect(response.body).to match(project.name) + expect(response.body).not_to match(pending_delete_project.name) + end + end + end +end -- cgit v1.2.1 From 96479cba5ac7d9b6a4b3364a29037e4e83fec25d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 25 Jul 2017 19:00:49 +0200 Subject: Remove outdated ~Frontend label in CONTRIBUTING.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a8499c126aa..12fb34b24be 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -114,8 +114,8 @@ scheduling into milestones. Labelling is a task for everyone. Most issues will have labels for at least one of the following: - Type: ~"feature proposal", ~bug, ~customer, etc. -- Subject: ~wiki, ~"container registry", ~ldap, ~api, etc. -- Team: ~CI, ~Discussion, ~Edge, ~Frontend, ~Platform, etc. +- Subject: ~wiki, ~"container registry", ~ldap, ~api, ~frontend, etc. +- Team: ~CI, ~Discussion, ~Edge, ~Platform, etc. - Priority: ~Deliverable, ~Stretch All labels, their meaning and priority are defined on the @@ -278,7 +278,7 @@ For feature proposals for EE, open an issue on the In order to help track the feature proposals, we have created a [`feature proposal`][fpl] label. For the time being, users that are not members of the project cannot add labels. You can instead ask one of the [core team] -members to add the label `feature proposal` to the issue or add the following +members to add the label ~"feature proposal" to the issue or add the following code snippet right after your description in a new line: `~"feature proposal"`. Please keep feature proposals as small and simple as possible, complex ones -- cgit v1.2.1 From e4028988b4f8428609abca36c92bfeca747bbefd Mon Sep 17 00:00:00 2001 From: Chenjerai Katanda Date: Tue, 25 Jul 2017 17:23:39 +0000 Subject: Add note on external url setting for HA clusters. --- doc/administration/high_availability/gitlab.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/administration/high_availability/gitlab.md b/doc/administration/high_availability/gitlab.md index 137fed35a73..e2cf281bc49 100644 --- a/doc/administration/high_availability/gitlab.md +++ b/doc/administration/high_availability/gitlab.md @@ -70,6 +70,12 @@ for each GitLab application server in your environment. gitlab_rails['redis_host'] = '10.1.0.6' # IP/hostname of Redis server gitlab_rails['redis_password'] = 'Redis Password' ``` + + > **Note:** To maintain uniformity of links across HA clusters, the `external_url` + on the master as well as all secondary application servers should point to the + eventual url that users will use to access GitLab. In a typical HA setup, + this will be the url of the load balancer which will route traffic to all + GitLab application servers in the HA cluster. 1. Run `sudo gitlab-ctl reconfigure` to compile the configuration. -- cgit v1.2.1 From 250dbecd28473ce256e46f7233c14acb8c02a29d Mon Sep 17 00:00:00 2001 From: Tiago Botelho Date: Tue, 25 Jul 2017 18:15:45 +0100 Subject: Pending delete projects should not show in deploy keys --- app/serializers/deploy_key_entity.rb | 2 +- .../35338-deploy-keys-should-not-show-pending-delete-projects.yml | 4 ++++ spec/serializers/deploy_key_entity_spec.rb | 4 +++- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/35338-deploy-keys-should-not-show-pending-delete-projects.yml diff --git a/app/serializers/deploy_key_entity.rb b/app/serializers/deploy_key_entity.rb index 068013c8829..c75431a79ae 100644 --- a/app/serializers/deploy_key_entity.rb +++ b/app/serializers/deploy_key_entity.rb @@ -9,7 +9,7 @@ class DeployKeyEntity < Grape::Entity expose :created_at expose :updated_at expose :projects, using: ProjectEntity do |deploy_key| - deploy_key.projects.select { |project| options[:user].can?(:read_project, project) } + deploy_key.projects.without_deleted.select { |project| options[:user].can?(:read_project, project) } end expose :can_edit diff --git a/changelogs/unreleased/35338-deploy-keys-should-not-show-pending-delete-projects.yml b/changelogs/unreleased/35338-deploy-keys-should-not-show-pending-delete-projects.yml new file mode 100644 index 00000000000..73808030f4c --- /dev/null +++ b/changelogs/unreleased/35338-deploy-keys-should-not-show-pending-delete-projects.yml @@ -0,0 +1,4 @@ +--- +title: Pending delete projects should not show in deploy keys. +merge_request: 13088 +author: diff --git a/spec/serializers/deploy_key_entity_spec.rb b/spec/serializers/deploy_key_entity_spec.rb index 9620f9665cf..8149de869f1 100644 --- a/spec/serializers/deploy_key_entity_spec.rb +++ b/spec/serializers/deploy_key_entity_spec.rb @@ -2,13 +2,15 @@ require 'spec_helper' describe DeployKeyEntity do include RequestAwareEntity - + let(:user) { create(:user) } let(:project) { create(:empty_project, :internal)} let(:project_private) { create(:empty_project, :private)} + let!(:project_pending_delete) { create(:empty_project, :internal, pending_delete: true) } let(:deploy_key) { create(:deploy_key) } let!(:deploy_key_internal) { create(:deploy_keys_project, project: project, deploy_key: deploy_key) } let!(:deploy_key_private) { create(:deploy_keys_project, project: project_private, deploy_key: deploy_key) } + let!(:deploy_key_pending_delete) { create(:deploy_keys_project, project: project_pending_delete, deploy_key: deploy_key) } let(:entity) { described_class.new(deploy_key, user: user) } -- cgit v1.2.1 From 3a90f6a418857d342427c3c7e1b6689c5e97bbee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=AAnis=20Volpato=20Martins?= Date: Tue, 25 Jul 2017 18:12:33 -0300 Subject: Docs: fix HAProxy name and exporter's link --- doc/user/project/integrations/prometheus_library/haproxy.md | 8 ++++---- doc/user/project/integrations/prometheus_library/metrics.md | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/user/project/integrations/prometheus_library/haproxy.md b/doc/user/project/integrations/prometheus_library/haproxy.md index 309da610cc0..f2939f047a3 100644 --- a/doc/user/project/integrations/prometheus_library/haproxy.md +++ b/doc/user/project/integrations/prometheus_library/haproxy.md @@ -1,7 +1,7 @@ -# Monitoring HA Proxy +# Monitoring HAProxy > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12621) in GitLab 9.4 -GitLab has support for automatically detecting and monitoring HA Proxy. This is provided by leveraging the [HA Proxy Exporter](https://github.com/hnlq715/nginx-vts-exporter), which translates HA Proxy statistics into a Prometheus readable form. +GitLab has support for automatically detecting and monitoring HAProxy. This is provided by leveraging the [HAProxy Exporter](https://github.com/prometheus/haproxy_exporter), which translates HAProxy statistics into a Prometheus readable form. ## Metrics supported @@ -10,9 +10,9 @@ GitLab has support for automatically detecting and monitoring HA Proxy. This is | Throughput (req/sec) | sum(rate(haproxy_frontend_http_requests_total{%{environment_filter}}[2m])) | | HTTP Error Rate (%) | sum(rate(haproxy_frontend_http_requests_total{code="5xx",%{environment_filter}}[2m])) / sum(rate(haproxy_frontend_http_requests_total{%{environment_filter}}[2m])) | -## Configuring Prometheus to monitor for HA Proxy metrics +## Configuring Prometheus to monitor for HAProxy metrics -To get started with NGINX monitoring, you should install and configure the [HA Proxy exporter](https://github.com/prometheus/haproxy_exporter) which parses these statistics and translates them into a Prometheus monitoring endpoint. +To get started with NGINX monitoring, you should install and configure the [HAProxy exporter](https://github.com/prometheus/haproxy_exporter) which parses these statistics and translates them into a Prometheus monitoring endpoint. ## Specifying the Environment label diff --git a/doc/user/project/integrations/prometheus_library/metrics.md b/doc/user/project/integrations/prometheus_library/metrics.md index 546e1f51df5..6bdffce9c55 100644 --- a/doc/user/project/integrations/prometheus_library/metrics.md +++ b/doc/user/project/integrations/prometheus_library/metrics.md @@ -4,7 +4,7 @@ GitLab offers automatic detection of select [Prometheus exporters](https://prometheus.io/docs/instrumenting/exporters/). Currently supported exporters are: * [Kubernetes](kubernetes.md) * [NGINX](nginx.md) -* [HA Proxy](haproxy.md) +* [HAProxy](haproxy.md) * [Amazon Cloud Watch](cloudwatch.md) We have tried to surface the most important metrics for each exporter, and will be continuing to add support for additional exporters in future releases. If you would like to add support for other official exporters, [contributions](#adding-to-the-library) are welcome. -- cgit v1.2.1 From af8667bc7218a7c84773d661d0eafda00c0d1d82 Mon Sep 17 00:00:00 2001 From: Paulo Bezerra Date: Tue, 25 Jul 2017 18:30:23 -0300 Subject: Enhance pt-BR translation in Project and Repository pages --- locale/pt_BR/gitlab.po | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po index 78cf6d2dacc..ee00b816b84 100644 --- a/locale/pt_BR/gitlab.po +++ b/locale/pt_BR/gitlab.po @@ -413,14 +413,14 @@ msgstr[0] "Fork" msgstr[1] "Forks" msgid "ForkedFromProjectPath|Forked from" -msgstr "Forked de" +msgstr "Fork criado a partir de" msgid "From issue creation until deploy to production" msgstr "Da abertura de tarefas até a implantação para a produção" msgid "From merge request merge until deploy to production" msgstr "" -"Da aceitação da solicitação de incorporação até a implantação em produção" +"Do merge request até a implantação em produção" msgid "Go to your fork" msgstr "Ir para seu fork" @@ -576,7 +576,7 @@ msgid "NotificationEvent|Successful pipeline" msgstr "Pipeline bem sucedido" msgid "NotificationLevel|Custom" -msgstr "Personalizar" +msgstr "Personalizado" msgid "NotificationLevel|Disabled" msgstr "Desabilitado" @@ -881,9 +881,9 @@ msgid "" "the issue to a milestone, or add the issue to a list on your Issue Board. " "Begin creating issues to see data for this stage." msgstr "" -"A etapa de relatos mostra o tempo que leva desde a criação de uma issue até " -"sua atribuição a um marco, ou sua adição a uma lista no seu Issue Board. " -"Comece a criar issues para ver dados para esta etapa." +"A etapa de planejamento mostra o tempo que se leva desde a criação de uma " +"issue até sua atribuição à um milestone, ou sua adição a uma lista no seu " +"Issue Board. Comece a criar issues para ver dados para esta etapa." msgid "The phase of the development lifecycle." msgstr "A fase do ciclo de vida do desenvolvimento." @@ -974,7 +974,7 @@ msgid "Time before an issue gets scheduled" msgstr "Tempo até que uma issue seja agendada" msgid "Time before an issue starts implementation" -msgstr "Tempo até que uma issue comece a ser implementado" +msgstr "Tempo até que uma issue comece a ser implementada" msgid "Time between merge request creation and merge/close" msgstr "" -- cgit v1.2.1 From 895e1b3ed1de5f94414b0e042b0053fab794a1f6 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Wed, 26 Jul 2017 00:28:13 +0200 Subject: Stop abusing subject to store results, + add helper methods to cleanup fs_shards metrics --- ..._temp_files_are_deleted_in_fs_metrics-35457.yml | 2 +- lib/gitlab/health_checks/fs_shards_check.rb | 64 ++++++++++++--------- .../gitlab/health_checks/fs_shards_check_spec.rb | 65 ++++++++++------------ 3 files changed, 67 insertions(+), 64 deletions(-) diff --git a/changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml b/changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml index 4906232237f..1186dc59dc7 100644 --- a/changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml +++ b/changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml @@ -1,4 +1,4 @@ --- -title: Ensure fs metrics test files are deleted +title: Ensure filesystem metrics test files are deleted merge_request: author: diff --git a/lib/gitlab/health_checks/fs_shards_check.rb b/lib/gitlab/health_checks/fs_shards_check.rb index ab18701b3bf..ddd1aaa7043 100644 --- a/lib/gitlab/health_checks/fs_shards_check.rb +++ b/lib/gitlab/health_checks/fs_shards_check.rb @@ -32,26 +32,13 @@ module Gitlab end def metrics - res = [] - repository_storages.each do |storage_name| - res << operation_metrics(:filesystem_accessible, :filesystem_access_latency_seconds, shard: storage_name) do - with_timing { storage_stat_test(storage_name) } - end - - res << operation_metrics(:filesystem_writable, :filesystem_write_latency_seconds, shard: storage_name) do - with_temp_file(storage_name) do |tmp_file_path| - with_timing { storage_write_test(tmp_file_path) } - end - end - - res << operation_metrics(:filesystem_readable, :filesystem_read_latency_seconds, shard: storage_name) do - with_temp_file(storage_name) do |tmp_file_path| - storage_write_test(tmp_file_path) # writes data used by read test - with_timing { storage_read_test(tmp_file_path) } - end - end + repository_storages.flat_map do |storage_name| + [ + storage_stat_metrics(storage_name), + storage_write_metrics(storage_name), + storage_read_metrics(storage_name) + ].flatten end - res.flatten end private @@ -81,19 +68,26 @@ module Gitlab def with_temp_file(storage_name) begin - temp_file_path = Dir::Tmpname.create(%w(fs_shards_check +deleted), path(storage_name)) { |path| path } + temp_file_path = Dir::Tmpname.create(%w(fs_shards_check +deleted), storage_path(storage_name)) { |path| path } yield temp_file_path ensure delete_test_file(temp_file_path) end end - def path(storage_name) + def storage_path(storage_name) storages_paths&.dig(storage_name, 'path') end + def delete_test_file(tmp_path) + _, status = exec_with_timeout(%W{ rm -f #{tmp_path} }) + status == 0 + rescue Errno::ENOENT + File.delete(tmp_path) rescue Errno::ENOENT + end + def storage_stat_test(storage_name) - stat_path = File.join(path(storage_name), '.') + stat_path = File.join(storage_path(storage_name), '.') begin _, status = exec_with_timeout(%W{ stat #{stat_path} }) status == 0 @@ -122,11 +116,27 @@ module Gitlab file_contents == RANDOM_STRING end - def delete_test_file(tmp_path) - _, status = exec_with_timeout(%W{ rm -f #{tmp_path} }) - status == 0 - rescue Errno::ENOENT - File.delete(tmp_path) rescue Errno::ENOENT + def storage_stat_metrics(storage_name) + operation_metrics(:filesystem_accessible, :filesystem_access_latency_seconds, shard: storage_name) do + with_timing { storage_stat_test(storage_name) } + end + end + + def storage_write_metrics(storage_name) + operation_metrics(:filesystem_writable, :filesystem_write_latency_seconds, shard: storage_name) do + with_temp_file(storage_name) do |tmp_file_path| + with_timing { storage_write_test(tmp_file_path) } + end + end + end + + def storage_read_metrics(storage_name) + operation_metrics(:filesystem_readable, :filesystem_read_latency_seconds, shard: storage_name) do + with_temp_file(storage_name) do |tmp_file_path| + storage_write_test(tmp_file_path) # writes data used by read test + with_timing { storage_read_test(tmp_file_path) } + end + end end end end diff --git a/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb b/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb index 947fb1b64d0..0a8dfa3bbdd 100644 --- a/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb +++ b/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb @@ -64,9 +64,7 @@ describe Gitlab::HealthChecks::FsShardsCheck do it 'cleans up files used for testing' do expect(described_class).to receive(:storage_write_test).with(any_args).and_call_original - subject - - expect(Dir.entries(tmp_dir).count).to eq(2) + expect { subject }.not_to change(Dir.entries(tmp_dir), :count) end context 'read test fails' do @@ -88,8 +86,6 @@ describe Gitlab::HealthChecks::FsShardsCheck do end describe '#metrics' do - subject { described_class.metrics } - context 'storage points to not existing folder' do let(:storages_paths) do { @@ -104,14 +100,15 @@ describe Gitlab::HealthChecks::FsShardsCheck do end it 'provides metrics' do - expect(subject).to all(have_attributes(labels: { shard: :default })) - expect(subject).to include(an_object_having_attributes(name: :filesystem_accessible, value: 0)) - expect(subject).to include(an_object_having_attributes(name: :filesystem_readable, value: 0)) - expect(subject).to include(an_object_having_attributes(name: :filesystem_writable, value: 0)) - - expect(subject).to include(an_object_having_attributes(name: :filesystem_access_latency_seconds, value: be >= 0)) - expect(subject).to include(an_object_having_attributes(name: :filesystem_read_latency_seconds, value: be >= 0)) - expect(subject).to include(an_object_having_attributes(name: :filesystem_write_latency_seconds, value: be >= 0)) + metrics = described_class.metrics + + expect(metrics).to all(have_attributes(labels: { shard: :default })) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_accessible, value: 0)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_readable, value: 0)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_writable, value: 0)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_access_latency_seconds, value: be >= 0)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_read_latency_seconds, value: be >= 0)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_write_latency_seconds, value: be >= 0)) end end @@ -121,21 +118,19 @@ describe Gitlab::HealthChecks::FsShardsCheck do end it 'provides metrics' do - expect(subject).to all(have_attributes(labels: { shard: :default })) - - expect(subject).to include(an_object_having_attributes(name: :filesystem_accessible, value: 1)) - expect(subject).to include(an_object_having_attributes(name: :filesystem_readable, value: 1)) - expect(subject).to include(an_object_having_attributes(name: :filesystem_writable, value: 1)) - - expect(subject).to include(an_object_having_attributes(name: :filesystem_access_latency_seconds, value: be >= 0)) - expect(subject).to include(an_object_having_attributes(name: :filesystem_read_latency_seconds, value: be >= 0)) - expect(subject).to include(an_object_having_attributes(name: :filesystem_write_latency_seconds, value: be >= 0)) + metrics = described_class.metrics + + expect(metrics).to all(have_attributes(labels: { shard: :default })) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_accessible, value: 1)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_readable, value: 1)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_writable, value: 1)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_access_latency_seconds, value: be >= 0)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_read_latency_seconds, value: be >= 0)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_write_latency_seconds, value: be >= 0)) end it 'cleans up files used for metrics' do - subject - - expect(Dir.entries(tmp_dir).count).to eq(2) + expect { described_class.metrics }.not_to change(Dir.entries(tmp_dir), :count) end end end @@ -156,18 +151,16 @@ describe Gitlab::HealthChecks::FsShardsCheck do end describe '#metrics' do - subject { described_class.metrics } - it 'provides metrics' do - expect(subject).to all(have_attributes(labels: { shard: :default })) - - expect(subject).to include(an_object_having_attributes(name: :filesystem_accessible, value: 0)) - expect(subject).to include(an_object_having_attributes(name: :filesystem_readable, value: 0)) - expect(subject).to include(an_object_having_attributes(name: :filesystem_writable, value: 0)) - - expect(subject).to include(an_object_having_attributes(name: :filesystem_access_latency_seconds, value: be >= 0)) - expect(subject).to include(an_object_having_attributes(name: :filesystem_read_latency_seconds, value: be >= 0)) - expect(subject).to include(an_object_having_attributes(name: :filesystem_write_latency_seconds, value: be >= 0)) + metrics = described_class.metrics + + expect(metrics).to all(have_attributes(labels: { shard: :default })) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_accessible, value: 0)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_readable, value: 0)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_writable, value: 0)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_access_latency_seconds, value: be >= 0)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_read_latency_seconds, value: be >= 0)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_write_latency_seconds, value: be >= 0)) end end end -- cgit v1.2.1 From acf4a36b3ed81c952d3f2edbfb054118b1d9dfff Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Fri, 21 Jul 2017 09:36:31 +0200 Subject: Implement GRPC call to RepositoryService --- app/models/repository.rb | 13 ++++++++++--- lib/gitlab/git/repository.rb | 10 ++++++---- lib/gitlab/gitaly_client.rb | 2 +- lib/gitlab/gitaly_client/repository_service.rb | 16 ++++++++++++++++ .../gitlab/gitaly_client/repository_service_spec.rb | 19 +++++++++++++++++++ spec/models/repository_spec.rb | 16 ++++++++++------ 6 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 lib/gitlab/gitaly_client/repository_service.rb create mode 100644 spec/lib/gitlab/gitaly_client/repository_service_spec.rb diff --git a/app/models/repository.rb b/app/models/repository.rb index 8663cf5e602..d27eeff9fb4 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -471,8 +471,17 @@ class Repository end cache_method :root_ref + # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/314 def exists? - refs_directory_exists? + return false unless path_with_namespace + + Gitlab::GitalyClient.migrate(:repository_exists) do |enabled| + if enabled + raw_repository.exists? + else + refs_directory_exists? + end + end end cache_method :exists? @@ -1095,8 +1104,6 @@ class Repository end def refs_directory_exists? - return false unless path_with_namespace - File.exist?(File.join(path_to_repo, 'refs')) end diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 63eebadff2e..3e27fd7b682 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -45,6 +45,8 @@ module Gitlab :bare?, to: :rugged + delegate :exists?, to: :gitaly_repository_client + # Default branch in the repository def root_ref @root_ref ||= gitaly_migrate(:root_ref) do |is_enabled| @@ -208,10 +210,6 @@ module Gitlab !empty? end - def repo_exists? - !!rugged - end - # Discovers the default branch based on the repository's available branches # # - If no branches are present, returns nil @@ -815,6 +813,10 @@ module Gitlab @gitaly_commit_client ||= Gitlab::GitalyClient::CommitService.new(self) end + def gitaly_repository_client + @gitaly_repository_client ||= Gitlab::GitalyClient::RepositoryService.new(self) + end + private # Gitaly note: JV: Trying to get rid of the 'filter' option so we can implement this with 'git'. diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb index 435e41e36fb..c90ef282fdd 100644 --- a/lib/gitlab/gitaly_client.rb +++ b/lib/gitlab/gitaly_client.rb @@ -57,7 +57,7 @@ module Gitlab metadata = yield(metadata) if block_given? stub(service, storage).send(rpc, request, metadata) end - + def self.request_metadata(storage) encoded_token = Base64.strict_encode64(token(storage).to_s) { metadata: { 'authorization' => "Bearer #{encoded_token}" } } diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb new file mode 100644 index 00000000000..f5d84ea8762 --- /dev/null +++ b/lib/gitlab/gitaly_client/repository_service.rb @@ -0,0 +1,16 @@ +module Gitlab + module GitalyClient + class RepositoryService + def initialize(repository) + @repository = repository + @gitaly_repo = repository.gitaly_repository + end + + def exists? + request = Gitaly::RepositoryExistsRequest.new(repository: @gitaly_repo) + + GitalyClient.call(@repository.storage, :repository_service, :exists, request).exists + end + end + end +end diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb new file mode 100644 index 00000000000..5a9f3fc130c --- /dev/null +++ b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe Gitlab::GitalyClient::RepositoryService do + set(:project) { create(:empty_project) } + let(:storage_name) { project.repository_storage } + let(:relative_path) { project.path_with_namespace + '.git' } + let(:client) { described_class.new(project.repository) } + + describe '#exists?' do + it 'sends an exists message' do + expect_any_instance_of(Gitaly::RepositoryService::Stub) + .to receive(:exists) + .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash)) + .and_call_original + + client.exists? + end + end +end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 7635b0868e7..fcda4248446 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -956,21 +956,25 @@ describe Repository, models: true do end end - describe '#exists?' do + shared_examples 'repo exists check' do it 'returns true when a repository exists' do expect(repository.exists?).to eq(true) end - it 'returns false when a repository does not exist' do - allow(repository).to receive(:refs_directory_exists?).and_return(false) + it 'returns false if no full path can be constructed' do + allow(repository).to receive(:path_with_namespace).and_return(nil) expect(repository.exists?).to eq(false) end + end - it 'returns false when there is no namespace' do - allow(repository).to receive(:path_with_namespace).and_return(nil) + describe '#exists?' do + context 'when repository_exists is disabled' do + it_behaves_like 'repo exists check' + end - expect(repository.exists?).to eq(false) + context 'when repository_exists is enabled', skip_gitaly_mock: true do + it_behaves_like 'repo exists check' end end -- cgit v1.2.1 From 2dc2538d740bcb1293808463b06f295522e8ce87 Mon Sep 17 00:00:00 2001 From: Marcia Ramos Date: Wed, 26 Jul 2017 08:02:11 +0000 Subject: Docs new topic "user/index" --- doc/README.md | 7 +- doc/articles/index.md | 21 ++++++ doc/integration/README.md | 20 +++--- doc/user/index.md | 175 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 210 insertions(+), 13 deletions(-) create mode 100644 doc/user/index.md diff --git a/doc/README.md b/doc/README.md index 2b3b0998fcc..ac7311a8c13 100644 --- a/doc/README.md +++ b/doc/README.md @@ -11,15 +11,11 @@ self-hosted, free to use. Every feature available in GitLab CE is also available self-hosted, fully featured solution of GitLab, available under distinct [subscriptions](https://about.gitlab.com/products/): **GitLab Enterprise Edition Starter (EES)** and **GitLab Enterprise Edition Premium (EEP)**. - **GitLab.com**: SaaS GitLab solution, with [free and paid subscriptions](https://about.gitlab.com/gitlab-com/). GitLab.com is hosted by GitLab, Inc., and administrated by GitLab (users don't have access to admin settings). -**GitLab EE** contains all features available in **GitLab CE**, +> **GitLab EE** contains all features available in **GitLab CE**, plus premium features available in each version: **Enterprise Edition Starter** (**EES**) and **Enterprise Edition Premium** (**EEP**). Everything available in **EES** is also available in **EEP**. -**Note:** _We are unifying the documentation for CE and EE. To check if certain feature is -available in CE or EE, look for a note right below the page title containing the GitLab -version which introduced that feature._ - ---- Shortcuts to GitLab's most visited docs: @@ -40,6 +36,7 @@ Shortcuts to GitLab's most visited docs: ### User account +- [User documentation](user/index.md) - [Authentication](topics/authentication/index.md): Account security with two-factor authentication, setup your ssh keys and deploy keys for secure access to your projects. - [Profile settings](profile/README.md): Manage your profile settings, two factor authentication and more. - [User permissions](user/permissions.md): Learn what each role in a project (external/guest/reporter/developer/master/owner) can do. diff --git a/doc/articles/index.md b/doc/articles/index.md index 342fa88e80f..a4e41517d83 100644 --- a/doc/articles/index.md +++ b/doc/articles/index.md @@ -11,6 +11,7 @@ They are written by members of the GitLab Team and by - **LDAP** - [How to configure LDAP with GitLab CE](how_to_configure_ldap_gitlab_ce/index.md) + - [How to configure LDAP with GitLab EE](https://docs.gitlab.com/ee/articles/how_to_configure_ldap_gitlab_ee/) ## Git @@ -23,3 +24,23 @@ They are written by members of the GitLab Team and by - [Part 2: Quick start guide - Setting up GitLab Pages](../user/project/pages/getting_started_part_two.md) - [Part 3: Setting Up Custom Domains - DNS Records and SSL/TLS Certificates](../user/project/pages/getting_started_part_three.md) - [Part 4: Creating and tweaking `.gitlab-ci.yml` for GitLab Pages](../user/project/pages/getting_started_part_four.md) +- [Building a new GitLab Docs site with Nanoc, GitLab CI, and GitLab Pages](https://about.gitlab.com/2016/12/07/building-a-new-gitlab-docs-site-with-nanoc-gitlab-ci-and-gitlab-pages/) +- [GitLab CI: Deployment & Environments](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/) + +## Sofware development + +- [In 13 minutes from Kubernetes to a complete application development tool](https://about.gitlab.com/2016/11/14/idea-to-production/) +- [Making CI Easier with GitLab](https://about.gitlab.com/2017/07/13/making-ci-easier-with-gitlab/) +- [Fast and Natural Continuous Integration with GitLab CI](https://about.gitlab.com/2017/05/22/fast-and-natural-continuous-integration-with-gitlab-ci/) +- [GitLab Workflow, an Overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/) +- [Continuous Integration, Delivery, and Deployment with GitLab](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) + +## Build, test, and deploy with GitLab CI/CD + +**Build, test, and deploy** the software you develop with **[GitLab CI/CD](../ci/README.md)** + +- [Continuous Delivery of a Spring Boot application with GitLab CI and Kubernetes](https://about.gitlab.com/2016/12/14/continuous-delivery-of-a-spring-boot-application-with-gitlab-ci-and-kubernetes/) +- [Automated Debian Package Build with GitLab CI](https://about.gitlab.com/2016/10/12/automated-debian-package-build-with-gitlab-ci/) +- [Building an Elixir Release into a Docker image using GitLab CI](https://about.gitlab.com/2016/08/11/building-an-elixir-release-into-docker-image-using-gitlab-ci-part-1/) +- [Setting up GitLab CI for Android projects](https://about.gitlab.com/2016/11/30/setting-up-gitlab-ci-for-android-projects/) +- [How to use GitLab CI and MacStadium to build your macOS or iOS projects](https://about.gitlab.com/2017/05/15/how-to-use-macstadium-and-gitlab-ci-to-build-your-macos-or-ios-projects/) diff --git a/doc/integration/README.md b/doc/integration/README.md index e56e58498a6..d70b9a7f54b 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -5,19 +5,23 @@ trackers and external authentication. See the documentation below for details on how to configure these services. -- [JIRA](../user/project/integrations/jira.md) Integrate with the JIRA issue tracker +- [Akismet](akismet.md) Configure Akismet to stop spam +- [Auth0 OmniAuth](auth0.md) Enable the Auth0 OmniAuth provider +- [Bitbucket](bitbucket.md) Import projects from Bitbucket.org and login to your GitLab instance with your +Bitbucket.org account +- [CAS](cas.md) Configure GitLab to sign in using CAS - [External issue tracker](external-issue-tracker.md) Redmine, JIRA, etc. +- [Gmail actions buttons](gmail_action_buttons_for_gitlab.md) Adds GitLab actions to messages +- [JIRA](../user/project/integrations/jira.md) Integrate with the JIRA issue tracker +- [Koding](../administration/integration/koding.md) Configure Koding to use IDE integration - [LDAP](ldap.md) Set up sign in via LDAP -- [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab.com, Google, Bitbucket, Facebook, Shibboleth, SAML, Crowd, Azure and Authentiq ID -- [SAML](saml.md) Configure GitLab as a SAML 2.0 Service Provider -- [CAS](cas.md) Configure GitLab to sign in using CAS - [OAuth2 provider](oauth_provider.md) OAuth2 application creation +- [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab.com, Google, Bitbucket, Facebook, Shibboleth, SAML, Crowd, Azure and Authentiq ID - [OpenID Connect](openid_connect_provider.md) Use GitLab as an identity provider -- [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](../administration/integration/koding.md) Configure Koding to use IDE integration - [PlantUML](../administration/integration/plantuml.md) Configure PlantUML to use diagrams in AsciiDoc documents. +- [reCAPTCHA](recaptcha.md) Configure GitLab to use Google reCAPTCHA for new users +- [SAML](saml.md) Configure GitLab as a SAML 2.0 Service Provider +- [Trello](trello_power_up.md) Integrate Trello with GitLab > GitLab Enterprise Edition contains [advanced Jenkins support][jenkins]. diff --git a/doc/user/index.md b/doc/user/index.md new file mode 100644 index 00000000000..f545dbffde3 --- /dev/null +++ b/doc/user/index.md @@ -0,0 +1,175 @@ +# User documentation + +Welcome to GitLab! We're glad to have you here! + +As a GitLab user you'll have access to all the features +your [subscription](https://about.gitlab.com/products/) +includes, except [GitLab administrator](../README.md#administrator-documentation) +settings, unless you have admin privileges to install, configure, +and upgrade your GitLab instance. + +For GitLab.com, admin privileges are restricted to the GitLab team. + +If you run your own GitLab instance and are looking for the administration settings, +please refer to the [administration](../README.md#administrator-documentation) +documentation. + +## Overview + +GitLab is a fully integrated software development platform that enables you +and your team to work cohesively, faster, transparently, and effectively, +since the discussion of a new idea until taking that idea to production all +all the way through, from within the same platform. + +Please check this page for an overview on [GitLab's features](https://about.gitlab.com/features/). + +## Use cases + +GitLab is a git-based platforms that integrates a great number of essential tools for software development and deployment, and project management: + +- Code hosting in repositories with version control +- Track proposals for new implementations, bug reports, and feedback with a +fully featured [Issue Tracker](project/issues/index.md#issue-tracker) +- Organize and prioritize with [Issue Boards](project/issues/index.md#issue-boards) +- Code review in [Merge Requests](project/merge_requests/index.md) with live-preview changes per +branch with [Review Apps](../ci/review_apps/index.md) +- Build, test and deploy with built-in [Continuous Integration](../ci/README.md) +- Deploy your personal and professional static websites with [GitLab Pages](project/pages/index.md) +- Integrate with Docker with [GitLab Container Registry](project/container_registry.md) +- Track the development lifecycle with [GitLab Cycle Analytics](project/cycle_analytics.md) + +With GitLab Enterprise Edition, you can also: + +- Provide support with [Service Desk](https://docs.gitlab.com/ee/user/project/service_desk.html) +- Improve collaboration with +[Merge Request Approvals](https://docs.gitlab.com/ee/user/project/merge_requests/index.html#merge-request-approvals), +[Multiple Assignees for Issues](https://docs.gitlab.com/ee/user/project/issues/multiple_assignees_for_issues.html), +and [Multiple Issue Boards](https://docs.gitlab.com/ee/user/project/issue_board.html#multiple-issue-boards) +- Create formal relashionships between issues with [Related Issues](https://docs.gitlab.com/ee/user/project/issues/related_issues.html) +- Use [Burndown Charts](https://docs.gitlab.com/ee/user/project/milestones/burndown_charts.html) to track progress during a sprint or while working on a new version of their software. +- Leverage [Elasticsearch](https://docs.gitlab.com/ee/integration/elasticsearch.html) with [Advanced Global Search](https://docs.gitlab.com/ee/user/search/advanced_global_search.html) and [Advanced Syntax Search](https://docs.gitlab.com/ee/user/search/advanced_search_syntax.html) for faster, more advanced code search across your entire GitLab instance +- [Authenticate users with Kerberos](https://docs.gitlab.com/ee/integration/kerberos.html) +- [Mirror a repository](https://docs.gitlab.com/ee/workflow/repository_mirroring.html) from elsewhere on your local server. +- [Export issues as CSV](https://docs.gitlab.com/ee/user/project/issues/csv_export.html) +- View your entire CI/CD pipeline involving more than one project with [Multiple-Project Pipeline Graphs](https://docs.gitlab.com/ee/ci/multi_project_pipeline_graphs.html) +- [Lock files](https://docs.gitlab.com/ee/user/project/file_lock.html) to prevent conflicts +- View of the current health and status of each CI environment running on Kubernetes with [Deploy Boards](https://docs.gitlab.com/ee/user/project/deploy_boards.html) +- Leverage your continuous delivery method with [Canary Deployments](https://docs.gitlab.com/ee/user/project/canary_deployments.html) + +You can also [integrate](project/integrations/project_services.md) GitLab with numerous third-party applications, such as Mattermost, Microsoft Teams, HipChat, Trello, Slack, Bamboo CI, JIRA, and a lot more. + +### Articles + +For a complete workflow use case please check [GitLab Workflow, an Overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/#gitlab-workflow-use-case-scenario). + +For more use cases please check our [Technical Articles](../articles/index.md). + +## Projects + +In GitLab, you can create projects for numerous reasons, such as, host +your code, use it as an issue tracker, collaborate on code, and continuously +build, test, and deploy your app with built-in GitLab CI/CD. Or, you can do +it all at once, from one single project. + +### Issues + +Explore the best of GitLab [Issues](project/issues/index.md). + +### Merge Requests + +Collanorate on code, gather reviews, live preview changes per branch, and +request approvals with [Merge Requests](project/merge_requests/index.md). + +### Milestones + +Work on multiple issues and merge requests towards the same target date +with [Milestones](project/milestones/index.md). + +### GitLab Pages + +Publish your static site directly from GitLab with [GitLab Pages](project/pages/index.md). You +can [build, test, and deploy any Static Site Generator](https://about.gitlab.com/2016/06/17/ssg-overview-gitlab-pages-part-3-examples-ci/) with Pages. + +### Container Registry + +Build and deploy Docker images with [GitLab Container Registry](project/container_registry.md). + +## GitLab CI/CD + +Use built-in [GitLab CI/CD](../ci/README.md) to test, build, and deploy your applications +directly from GitLab. No third-party integrations needed. + +### Auto Deploy + +Deploy your application out-of-the-box with [GitLab Auto Deploy](../ci/autodeploy/index.md). + +### Review Apps + +Live-preview the changes introduced by a merge request with [Review Apps](../ci/review_apps/index.md). + +## Groups + +With GitLab [Groups](group/index.md) you can assemble related projects together +and grant members access to several projects at once. + +### Subgroups + +Groups can also be nested in [subgroups](group/subgroups/index.md). + +## Account + +There is a lot you can customize and configure +to enjoy the best of GitLab. + +Manage your user settings to change your personal info, +personal access tokens, authorized applications, integrations, etc. + +### Authentication + +Read through the [authentication](../topics/authentication/index.md) methods available in GitLab. + +### Permissions + +Learn the different set of [permissions](permissions.md) for user type (guest, reporter, developer, master, owner). + +## Integrations + +[Integrate GitLab](../integration/README.md) with your preferred tool, +such as Trello, JIRA, etc. + +## Git and GitLab + +Learn what is [Git](../topics/git/index.md) and its best practices. + +## Discussions + +In GitLab, you can comment and mention collaborators in issues, +merge requests, code snippets, and commits. + +When performing inline reviews to implementations +to your codebase through merge requests you can +gather feedback through [resolvable discussions](discussions/index.md#resolvable-discussions). + +## Todos + +Never forget to reply to your collaborators. [GitLab Todos](../workflow/todos.md) +are a tool for working faster and more effectively with your team, +by listing all user or group mentions, as well as issues and merge +requests you're assigned to. + +## Snippets + +[Snippets](snippets.md) are code blocks that you want to store in GitLab, from which +you have quick access to. You can also gather feedback on them through +[discussions](#discussions). + +## Webhooks + +Configure [webhooks](project/integrations/webhooks.html) to listen for +specific events like pushes, issues or merge requests. GitLab will send a +POST request with data to the webhook URL. + +## API + +Automate GitLab via [API](../api/README.html). + -- cgit v1.2.1 From 29022350999ab3ddc4518f7a7647939ec2de8e09 Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Fri, 16 Jun 2017 11:04:24 +1100 Subject: Add CSRF token verification to API --- .../33601-add-csrf-token-verification-to-api.yml | 4 +++ lib/api/helpers.rb | 38 +++++++++++++++++--- spec/lib/api/helpers/csrf_tokens_spec.rb | 42 ++++++++++++++++++++++ 3 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 changelogs/unreleased/33601-add-csrf-token-verification-to-api.yml create mode 100644 spec/lib/api/helpers/csrf_tokens_spec.rb diff --git a/changelogs/unreleased/33601-add-csrf-token-verification-to-api.yml b/changelogs/unreleased/33601-add-csrf-token-verification-to-api.yml new file mode 100644 index 00000000000..fa1a77ebcc1 --- /dev/null +++ b/changelogs/unreleased/33601-add-csrf-token-verification-to-api.yml @@ -0,0 +1,4 @@ +--- +title: Add CSRF token verification to API +merge_request: 12154 +author: @blackst0ne diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 57e3e93500f..ab5f4c865e0 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -328,6 +328,33 @@ module API private + def xor_byte_strings(s1, s2) + s2_bytes = s2.bytes + s1.each_byte.with_index { |c1, i| s2_bytes[i] ^= c1 } + s2_bytes.pack('C*') + end + + # Check if CSRF tokens are equal. + # The header token is masked. + # So, before the comparison it must be unmasked. + def csrf_tokens_valid?(request) + session_token = request.session['_csrf_token'] + header_token = request.headers['X-Csrf-Token'] + + session_token = Base64.strict_decode64(session_token) + header_token = Base64.strict_decode64(header_token) + + # Decoded CSRF token passed from the frontend has to be 64 symbols long. + return false if header_token.size != 64 + + header_token = xor_byte_strings(header_token[0...32], header_token[32..-1]) + + ActiveSupport::SecurityUtils.secure_compare(session_token, header_token) + + rescue + false + end + def private_token params[APIGuard::PRIVATE_TOKEN_PARAM] || env[APIGuard::PRIVATE_TOKEN_HEADER] end @@ -336,12 +363,15 @@ module API env['warden'] end + def verified_request? + request = Grape::Request.new(env) + + request.head? || request.get? || csrf_tokens_valid?(request) + end + # Check the Rails session for valid authentication details - # - # Until CSRF protection is added to the API, disallow this method for - # state-changing endpoints def find_user_from_warden - warden.try(:authenticate) if %w[GET HEAD].include?(env['REQUEST_METHOD']) + warden.try(:authenticate) if verified_request? end def initial_current_user diff --git a/spec/lib/api/helpers/csrf_tokens_spec.rb b/spec/lib/api/helpers/csrf_tokens_spec.rb new file mode 100644 index 00000000000..d16db6c9064 --- /dev/null +++ b/spec/lib/api/helpers/csrf_tokens_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe API::Helpers do + subject do + Class.new.include(described_class).new + end + + let(:header_token) { 'WblCcheb1qQLHFVhlMtwOhxJr5613vUT05vCvToRvfJ68UPT7+eV5xpaY9CjubnF3VGbTfIhQYkZWmWTfvZAWQ==' } + let(:session_token) { 'I0gBofh8Q0MRRjaxN3LJ/8EYNNNH/7SaysGnLkTn/as=' } + + before do + class Request + attr_reader :headers + attr_reader :session + + def initialize(header_token = nil, session_token = nil) + @headers = { 'X-Csrf-Token' => header_token } + @session = { '_csrf_token' => session_token } + end + end + end + + it 'should return false if header token is invalid' do + request = Request.new(nil, session_token) + expect(subject.send(:csrf_tokens_valid?, request)).to be false + end + + it 'should return false if session_token token is invalid' do + request = Request.new(header_token, nil) + expect(subject.send(:csrf_tokens_valid?, request)).to be false + end + + it 'should return false if header_token is not 64 symbols long' do + request = Request.new(header_token[0..16], session_token) + expect(subject.send(:csrf_tokens_valid?, request)).to be false + end + + it 'should return true if both header_token and session_token are correct' do + request = Request.new(header_token, session_token) + expect(subject.send(:csrf_tokens_valid?, request)).to be true + end +end -- cgit v1.2.1 From 8ce8b21f675709c884148d050663b9f2374cdc61 Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Wed, 21 Jun 2017 17:52:54 +1100 Subject: Refactor CSRF protection --- .../33601-add-csrf-token-verification-to-api.yml | 2 +- config/initializers/omniauth.rb | 2 +- lib/api/helpers.rb | 32 ++-------------------- lib/gitlab/request_forgery_protection.rb | 23 ++++++++++++++++ lib/omni_auth/request_forgery_protection.rb | 21 -------------- 5 files changed, 27 insertions(+), 53 deletions(-) create mode 100644 lib/gitlab/request_forgery_protection.rb delete mode 100644 lib/omni_auth/request_forgery_protection.rb diff --git a/changelogs/unreleased/33601-add-csrf-token-verification-to-api.yml b/changelogs/unreleased/33601-add-csrf-token-verification-to-api.yml index fa1a77ebcc1..88cfb99a73e 100644 --- a/changelogs/unreleased/33601-add-csrf-token-verification-to-api.yml +++ b/changelogs/unreleased/33601-add-csrf-token-verification-to-api.yml @@ -1,4 +1,4 @@ --- title: Add CSRF token verification to API merge_request: 12154 -author: @blackst0ne +author: Vitaliy @blackst0ne Klachkov diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index f7fa6d1c2de..24ff3b924b5 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -16,7 +16,7 @@ OmniAuth.config.allowed_request_methods = [:post] # In case of auto sign-in, the GET method is used (users don't get to click on a button) OmniAuth.config.allowed_request_methods << :get if Gitlab.config.omniauth.auto_sign_in_with_provider.present? OmniAuth.config.before_request_phase do |env| - OmniAuth::RequestForgeryProtection.call(env) + GitLab::RequestForgeryProtection.call(env) end if Gitlab.config.omniauth.enabled diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index ab5f4c865e0..b81ce75ef4f 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -328,33 +328,6 @@ module API private - def xor_byte_strings(s1, s2) - s2_bytes = s2.bytes - s1.each_byte.with_index { |c1, i| s2_bytes[i] ^= c1 } - s2_bytes.pack('C*') - end - - # Check if CSRF tokens are equal. - # The header token is masked. - # So, before the comparison it must be unmasked. - def csrf_tokens_valid?(request) - session_token = request.session['_csrf_token'] - header_token = request.headers['X-Csrf-Token'] - - session_token = Base64.strict_decode64(session_token) - header_token = Base64.strict_decode64(header_token) - - # Decoded CSRF token passed from the frontend has to be 64 symbols long. - return false if header_token.size != 64 - - header_token = xor_byte_strings(header_token[0...32], header_token[32..-1]) - - ActiveSupport::SecurityUtils.secure_compare(session_token, header_token) - - rescue - false - end - def private_token params[APIGuard::PRIVATE_TOKEN_PARAM] || env[APIGuard::PRIVATE_TOKEN_HEADER] end @@ -363,10 +336,9 @@ module API env['warden'] end + # Check if CSRF tokens are valid. def verified_request? - request = Grape::Request.new(env) - - request.head? || request.get? || csrf_tokens_valid?(request) + GitLab::RequestForgeryProtection.call(env) end # Check the Rails session for valid authentication details diff --git a/lib/gitlab/request_forgery_protection.rb b/lib/gitlab/request_forgery_protection.rb new file mode 100644 index 00000000000..071a72a1f8b --- /dev/null +++ b/lib/gitlab/request_forgery_protection.rb @@ -0,0 +1,23 @@ +# A module to check CSRF tokens in requests. +# It's used in API helpers and OmniAuth. +# Usage: GitLab::RequestForgeryProtection.call(env) + +module GitLab + module RequestForgeryProtection + class Controller < ActionController::Base + protect_from_forgery with: :exception + + def index + head :ok + end + end + + def self.app + @app ||= Controller.action(:index) + end + + def self.call(env) + app.call(env) + end + end +end diff --git a/lib/omni_auth/request_forgery_protection.rb b/lib/omni_auth/request_forgery_protection.rb deleted file mode 100644 index 69155131d8d..00000000000 --- a/lib/omni_auth/request_forgery_protection.rb +++ /dev/null @@ -1,21 +0,0 @@ -# Protects OmniAuth request phase against CSRF. - -module OmniAuth - module RequestForgeryProtection - class Controller < ActionController::Base - protect_from_forgery with: :exception - - def index - head :ok - end - end - - def self.app - @app ||= Controller.action(:index) - end - - def self.call(env) - app.call(env) - end - end -end -- cgit v1.2.1 From cc3a82bc8bf0af9a8b7deb1b289aee621c91f7da Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Thu, 22 Jun 2017 16:19:14 +1100 Subject: Add `rescue false`. --- config/initializers/omniauth.rb | 2 +- lib/api/helpers.rb | 2 +- lib/gitlab/request_forgery_protection.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 24ff3b924b5..a36e59c941a 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -16,7 +16,7 @@ OmniAuth.config.allowed_request_methods = [:post] # In case of auto sign-in, the GET method is used (users don't get to click on a button) OmniAuth.config.allowed_request_methods << :get if Gitlab.config.omniauth.auto_sign_in_with_provider.present? OmniAuth.config.before_request_phase do |env| - GitLab::RequestForgeryProtection.call(env) + Gitlab::RequestForgeryProtection.call(env) end if Gitlab.config.omniauth.enabled diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index b81ce75ef4f..9a589828221 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -338,7 +338,7 @@ module API # Check if CSRF tokens are valid. def verified_request? - GitLab::RequestForgeryProtection.call(env) + Gitlab::RequestForgeryProtection.call(env) rescue false end # Check the Rails session for valid authentication details diff --git a/lib/gitlab/request_forgery_protection.rb b/lib/gitlab/request_forgery_protection.rb index 071a72a1f8b..b0e15e2b655 100644 --- a/lib/gitlab/request_forgery_protection.rb +++ b/lib/gitlab/request_forgery_protection.rb @@ -2,7 +2,7 @@ # It's used in API helpers and OmniAuth. # Usage: GitLab::RequestForgeryProtection.call(env) -module GitLab +module Gitlab module RequestForgeryProtection class Controller < ActionController::Base protect_from_forgery with: :exception -- cgit v1.2.1 From 5a1f3df3b82361b613dbf718c4f7af26332297a1 Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Thu, 22 Jun 2017 16:20:50 +1100 Subject: Remove spec/lib/api/helpers/csrf_tokens_spec.rb --- spec/lib/api/helpers/csrf_tokens_spec.rb | 42 -------------------------------- 1 file changed, 42 deletions(-) delete mode 100644 spec/lib/api/helpers/csrf_tokens_spec.rb diff --git a/spec/lib/api/helpers/csrf_tokens_spec.rb b/spec/lib/api/helpers/csrf_tokens_spec.rb deleted file mode 100644 index d16db6c9064..00000000000 --- a/spec/lib/api/helpers/csrf_tokens_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'spec_helper' - -describe API::Helpers do - subject do - Class.new.include(described_class).new - end - - let(:header_token) { 'WblCcheb1qQLHFVhlMtwOhxJr5613vUT05vCvToRvfJ68UPT7+eV5xpaY9CjubnF3VGbTfIhQYkZWmWTfvZAWQ==' } - let(:session_token) { 'I0gBofh8Q0MRRjaxN3LJ/8EYNNNH/7SaysGnLkTn/as=' } - - before do - class Request - attr_reader :headers - attr_reader :session - - def initialize(header_token = nil, session_token = nil) - @headers = { 'X-Csrf-Token' => header_token } - @session = { '_csrf_token' => session_token } - end - end - end - - it 'should return false if header token is invalid' do - request = Request.new(nil, session_token) - expect(subject.send(:csrf_tokens_valid?, request)).to be false - end - - it 'should return false if session_token token is invalid' do - request = Request.new(header_token, nil) - expect(subject.send(:csrf_tokens_valid?, request)).to be false - end - - it 'should return false if header_token is not 64 symbols long' do - request = Request.new(header_token[0..16], session_token) - expect(subject.send(:csrf_tokens_valid?, request)).to be false - end - - it 'should return true if both header_token and session_token are correct' do - request = Request.new(header_token, session_token) - expect(subject.send(:csrf_tokens_valid?, request)).to be true - end -end -- cgit v1.2.1 From cb405aa45dd5acf766797a7375043b6608d394f8 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 26 Jul 2017 11:19:57 +0200 Subject: Refactor max_size method in update pages service As per review feedback https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/13072#note_35853177 --- app/services/projects/update_pages_service.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/services/projects/update_pages_service.rb b/app/services/projects/update_pages_service.rb index a819b799ff8..749a1cc56d8 100644 --- a/app/services/projects/update_pages_service.rb +++ b/app/services/projects/update_pages_service.rb @@ -130,9 +130,11 @@ module Projects end def max_size - current_application_settings.max_pages_size.megabytes.tap do |maximum| - return MAX_SIZE if maximum.zero? || maximum > MAX_SIZE - end + max_pages_size = current_application_settings.max_pages_size.megabytes + + return MAX_SIZE if max_pages_size.zero? + + [max_pages_size, MAX_SIZE].min end def tmp_path -- cgit v1.2.1 From dcf4a2e83c69d1be0915f9c4c4f023abee2e7dea Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 26 Jul 2017 11:25:10 +0200 Subject: Rescue only from ActionController::InvalidAuthenticityToken --- lib/api/helpers.rb | 4 ++-- lib/gitlab/request_forgery_protection.rb | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 9a589828221..234825480f2 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -336,9 +336,9 @@ module API env['warden'] end - # Check if CSRF tokens are valid. + # Check if the request is GET/HEAD, or if CSRF token is valid. def verified_request? - Gitlab::RequestForgeryProtection.call(env) rescue false + Gitlab::RequestForgeryProtection.verified?(env) end # Check the Rails session for valid authentication details diff --git a/lib/gitlab/request_forgery_protection.rb b/lib/gitlab/request_forgery_protection.rb index b0e15e2b655..48dd0487790 100644 --- a/lib/gitlab/request_forgery_protection.rb +++ b/lib/gitlab/request_forgery_protection.rb @@ -19,5 +19,13 @@ module Gitlab def self.call(env) app.call(env) end + + def self.verified?(env) + call(env) + + true + rescue ActionController::InvalidAuthenticityToken + false + end end end -- cgit v1.2.1 From 9aa2205a15c72394234892ef3babe94ce7eb1828 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Wed, 26 Jul 2017 09:31:17 +0000 Subject: Resolve "Memory usage notice doesn't link anywhere" --- .../components/mr_widget_deployment.js | 3 ++- .../components/mr_widget_memory_usage.js | 11 +++++++++-- app/controllers/projects/merge_requests_controller.rb | 6 ++++++ .../34110-memory-usage-notice-doesn-t-link-anywhere.yml | 4 ++++ .../vue_mr_widget/components/mr_widget_deployment_spec.js | 1 + .../vue_mr_widget/components/mr_widget_memory_usage_spec.js | 2 ++ 6 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/34110-memory-usage-notice-doesn-t-link-anywhere.yml diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js index e8e22ad93a5..744a1cd24fa 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_deployment.js @@ -108,7 +108,8 @@ export default { diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js index 76cb71b6c12..534e2a88eff 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_memory_usage.js @@ -7,7 +7,14 @@ import MRWidgetService from '../services/mr_widget_service'; export default { name: 'MemoryUsage', props: { - metricsUrl: { type: String, required: true }, + metricsUrl: { + type: String, + required: true, + }, + metricsMonitoringUrl: { + type: String, + required: true, + }, }, data() { return { @@ -124,7 +131,7 @@ export default {

- Memory usage {{memoryChangeType}} from {{memoryFrom}}MB to {{memoryTo}}MB + Memory usage {{memoryChangeType}} from {{memoryFrom}}MB to {{memoryTo}}MB

{ el: document.createElement('div'), propsData: { metricsUrl: url, + metricsMonitoringUrl: monitoringUrl, memoryMetrics: [], deploymentTime: 0, hasMetrics: false, -- cgit v1.2.1 From 8ab29d569e8c0019bbe458dea6f05a9894f0711a Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Fri, 9 Jun 2017 08:27:39 -0700 Subject: Upgrade omniauth-ldap gem (and some dependencies) Most notably, the net-ldap gem. --- Gemfile | 2 +- Gemfile.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Gemfile b/Gemfile index 7c7122a39ea..276893d0ff4 100644 --- a/Gemfile +++ b/Gemfile @@ -61,7 +61,7 @@ gem 'browser', '~> 2.2' # LDAP Auth # GitLab fork with several improvements to original library. For full list of changes # see https://github.com/intridea/omniauth-ldap/compare/master...gitlabhq:master -gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: 'omniauth-ldap' +gem 'gitlab_omniauth-ldap', '~> 2.0.1', require: 'omniauth-ldap' # Git Wiki # Required manually in config/initializers/gollum.rb to control load order diff --git a/Gemfile.lock b/Gemfile.lock index 901e5334994..2b2df1b6bcc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -288,11 +288,11 @@ GEM mime-types (>= 1.16, < 3) posix-spawn (~> 0.3) gitlab-markup (1.5.1) - gitlab_omniauth-ldap (1.2.1) - net-ldap (~> 0.9) - omniauth (~> 1.0) - pyu-ruby-sasl (~> 0.0.3.1) - rubyntlm (~> 0.3) + gitlab_omniauth-ldap (2.0.1) + net-ldap (~> 0.16) + omniauth (~> 1.3) + pyu-ruby-sasl (>= 0.0.3.3, < 0.1) + rubyntlm (~> 0.5) globalid (0.3.7) activesupport (>= 4.1.0) gollum-grit_adapter (1.0.1) @@ -471,7 +471,7 @@ GEM mustermann-grape (1.0.0) mustermann (~> 1.0.0) mysql2 (0.4.5) - net-ldap (0.12.1) + net-ldap (0.16.0) netrc (0.11.0) nokogiri (1.6.8.1) mini_portile2 (~> 2.1.0) @@ -744,7 +744,7 @@ GEM nokogiri (>= 1.5.10) ruby_parser (3.9.0) sexp_processor (~> 4.1) - rubyntlm (0.5.2) + rubyntlm (0.6.2) rubypants (0.2.0) rubyzip (1.2.1) rufus-scheduler (3.4.0) @@ -978,7 +978,7 @@ DEPENDENCIES github-linguist (~> 4.7.0) gitlab-flowdock-git-hook (~> 1.0.1) gitlab-markup (~> 1.5.1) - gitlab_omniauth-ldap (~> 1.2.1) + gitlab_omniauth-ldap (~> 2.0.1) gollum-lib (~> 4.2) gollum-rugged_adapter (~> 0.4.4) gon (~> 6.1.0) -- cgit v1.2.1 From 6dbff9663de072279bd027e8e3e453b732f75977 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Tue, 6 Jun 2017 11:16:17 -0700 Subject: Add LDAP config options --- config/gitlab.yml.example | 30 +++++++++++++++++++++++++++++- config/initializers/1_settings.rb | 5 +++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index cb007813b65..8ddd9bab4e6 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -254,10 +254,38 @@ production: &base host: '_your_ldap_server' port: 389 uid: 'sAMAccountName' - method: 'plain' # "tls" or "ssl" or "plain" bind_dn: '_the_full_dn_of_the_user_you_will_bind_with' password: '_the_password_of_the_bind_user' + # Encryption method. The "method" key is deprecated in favor of + # "encryption". + # + # Examples: "start_tls" or "simple_tls" or "plain" + # + # Deprecated values: "tls" was replaced with "start_tls" and "ssl" was + # replaced with "simple_tls". + # + encryption: 'plain' + + # Enables SSL certificate verification if encryption method is + # "start_tls" or "simple_tls". (Defaults to false for backward- + # compatibility) + verify_certificates: false + + # Specifies the path to a file containing a PEM-format CA certificate, + # e.g. if you need to use an internal CA. + # + # Example: '/etc/ca.pem' + # + ca_cert: '' + + # Specifies the SSL version for OpenSSL to use, if the OpenSSL default + # is not appropriate. + # + # Example: 'TLSv1_1' + # + ssl_version: '' + # Set a timeout, in seconds, for LDAP queries. This helps avoid blocking # a request if the LDAP server becomes unresponsive. # A value of 0 means there is no timeout. diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index ec7ce51b542..9344a42540b 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -145,6 +145,11 @@ if Settings.ldap['enabled'] || Rails.env.test? server['attributes'] = {} if server['attributes'].nil? server['provider_name'] ||= "ldap#{key}".downcase server['provider_class'] = OmniAuth::Utils.camelize(server['provider_name']) + server['encryption'] ||= server['method'] # for backwards compatibility + + # Certificates are not verified for backwards compatibility. + # This default should be flipped to true in 9.5. + server['verify_certificates'] = false if server['verify_certificates'].nil? end end -- cgit v1.2.1 From 94b4c9f34f576bbeddc2a22098f33c6ae656d7ab Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Thu, 8 Jun 2017 15:46:06 -0700 Subject: Use encryption instead of method The method key is deprecated in the `gitlab_omniauth-ldap` gem. --- lib/gitlab/ldap/config.rb | 4 ++-- spec/lib/gitlab/ldap/config_spec.rb | 28 ++++++++++++++-------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb index 6fdf68641e2..c531100fbc4 100644 --- a/lib/gitlab/ldap/config.rb +++ b/lib/gitlab/ldap/config.rb @@ -50,7 +50,7 @@ module Gitlab def omniauth_options opts = base_options.merge( base: base, - method: options['method'], + encryption: options['encryption'], filter: omniauth_user_filter, name_proc: name_proc ) @@ -158,7 +158,7 @@ module Gitlab end def encryption - case options['method'].to_s + case options['encryption'].to_s when 'ssl' :simple_tls when 'tls' diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb index cab2e9908ff..e75e1e3ea2f 100644 --- a/spec/lib/gitlab/ldap/config_spec.rb +++ b/spec/lib/gitlab/ldap/config_spec.rb @@ -23,9 +23,9 @@ describe Gitlab::LDAP::Config, lib: true do it 'constructs basic options' do stub_ldap_config( options: { - 'host' => 'ldap.example.com', - 'port' => 386, - 'method' => 'plain' + 'host' => 'ldap.example.com', + 'port' => 386, + 'encryption' => 'plain' } ) @@ -39,11 +39,11 @@ describe Gitlab::LDAP::Config, lib: true do it 'includes authentication options when auth is configured' do stub_ldap_config( options: { - 'host' => 'ldap.example.com', - 'port' => 686, - 'method' => 'ssl', - 'bind_dn' => 'uid=admin,dc=example,dc=com', - 'password' => 'super_secret' + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'ssl', + 'bind_dn' => 'uid=admin,dc=example,dc=com', + 'password' => 'super_secret' } ) @@ -64,11 +64,11 @@ describe Gitlab::LDAP::Config, lib: true do it 'constructs basic options' do stub_ldap_config( options: { - 'host' => 'ldap.example.com', - 'port' => 386, - 'base' => 'ou=users,dc=example,dc=com', - 'method' => 'plain', - 'uid' => 'uid' + 'host' => 'ldap.example.com', + 'port' => 386, + 'base' => 'ou=users,dc=example,dc=com', + 'encryption' => 'plain', + 'uid' => 'uid' } ) @@ -76,7 +76,7 @@ describe Gitlab::LDAP::Config, lib: true do host: 'ldap.example.com', port: 386, base: 'ou=users,dc=example,dc=com', - method: 'plain', + encryption: 'plain', filter: '(uid=%{username})' ) expect(config.omniauth_options.keys).not_to include(:bind_dn, :password) -- cgit v1.2.1 From b67c007842ba42d2ed1cf1d8879a220a1b9906f9 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Thu, 8 Jun 2017 16:30:54 -0700 Subject: Set `Net::LDAP` encryption properly --- lib/gitlab/ldap/config.rb | 34 +++++++++--- spec/lib/gitlab/ldap/config_spec.rb | 102 ++++++++++++++++++++++++++++++++---- 2 files changed, 117 insertions(+), 19 deletions(-) diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb index c531100fbc4..383e0a09e42 100644 --- a/lib/gitlab/ldap/config.rb +++ b/lib/gitlab/ldap/config.rb @@ -2,6 +2,16 @@ module Gitlab module LDAP class Config + NET_LDAP_ENCRYPTION_METHOD = { + :simple_tls => :simple_tls, + :start_tls => :start_tls, + :plain => nil, + + # Deprecated. Better to pass-through the actual `Net::LDAP` encryption type. + :ssl => :simple_tls, + :tls => :start_tls, + } + attr_accessor :provider, :options def self.enabled? @@ -39,7 +49,7 @@ module Gitlab def adapter_options opts = base_options.merge( - encryption: encryption + encryption: encryption_options ) opts.merge!(auth_options) if has_auth? @@ -157,14 +167,22 @@ module Gitlab base_config.servers.values.find { |server| server['provider_name'] == provider } end - def encryption - case options['encryption'].to_s - when 'ssl' - :simple_tls - when 'tls' - :start_tls + def encryption_options + method = translate_method(options['encryption']) + options = { method: method } + options.merge!(tls_options: tls_options(method)) if method + options + end + + def translate_method(method_from_config) + NET_LDAP_ENCRYPTION_METHOD[method_from_config.to_sym] + end + + def tls_options(method) + if method && options['verify_certificates'] + OpenSSL::SSL::SSLContext::DEFAULT_PARAMS else - nil + { verify_mode: OpenSSL::SSL::VERIFY_NONE } end end diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb index e75e1e3ea2f..bbd4da58252 100644 --- a/spec/lib/gitlab/ldap/config_spec.rb +++ b/spec/lib/gitlab/ldap/config_spec.rb @@ -5,7 +5,7 @@ describe Gitlab::LDAP::Config, lib: true do let(:config) { Gitlab::LDAP::Config.new('ldapmain') } - describe '#initalize' do + describe '#initialize' do it 'requires a provider' do expect{ Gitlab::LDAP::Config.new }.to raise_error ArgumentError end @@ -32,31 +32,111 @@ describe Gitlab::LDAP::Config, lib: true do expect(config.adapter_options).to eq( host: 'ldap.example.com', port: 386, - encryption: nil + encryption: { method: nil } ) end it 'includes authentication options when auth is configured' do stub_ldap_config( options: { - 'host' => 'ldap.example.com', - 'port' => 686, - 'encryption' => 'ssl', - 'bind_dn' => 'uid=admin,dc=example,dc=com', - 'password' => 'super_secret' + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'simple_tls', + 'verify_certificates' => true, + 'bind_dn' => 'uid=admin,dc=example,dc=com', + 'password' => 'super_secret' } ) - expect(config.adapter_options).to eq( - host: 'ldap.example.com', - port: 686, - encryption: :simple_tls, + expect(config.adapter_options).to include({ auth: { method: :simple, username: 'uid=admin,dc=example,dc=com', password: 'super_secret' } + }) + end + + it 'sets encryption method to simple_tls when configured as simple_tls' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'simple_tls' + } + ) + + expect(config.adapter_options[:encryption]).to include({ method: :simple_tls }) + end + + it 'sets encryption method to simple_tls when configured as ssl, for backwards compatibility' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'ssl' + } + ) + + expect(config.adapter_options[:encryption]).to include({ method: :simple_tls }) + end + + it 'sets encryption method to start_tls when configured as start_tls' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'start_tls' + } + ) + + expect(config.adapter_options[:encryption]).to include({ method: :start_tls }) + end + + it 'sets encryption method to start_tls when configured as tls, for backwards compatibility' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'tls' + } ) + + expect(config.adapter_options[:encryption]).to include({ method: :start_tls }) + end + + context 'when verify_certificates is enabled' do + it 'sets tls_options to OpenSSL defaults' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'simple_tls', + 'verify_certificates' => true + } + ) + + expect(config.adapter_options[:encryption]).to include({ tls_options: OpenSSL::SSL::SSLContext::DEFAULT_PARAMS }) + end + end + + context 'when verify_certificates is disabled' do + it 'sets verify_mode to OpenSSL VERIFY_NONE' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'simple_tls', + 'verify_certificates' => false + } + ) + + expect(config.adapter_options[:encryption]).to include({ + tls_options: { + verify_mode: OpenSSL::SSL::VERIFY_NONE + } + }) + end end end -- cgit v1.2.1 From dcc12505aa121f809f6cf64fa7a68cc5457aca31 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Thu, 8 Jun 2017 16:57:13 -0700 Subject: Set `Net::LDAP` `ca_file` option --- lib/gitlab/ldap/config.rb | 20 +++++++++++++++----- spec/lib/gitlab/ldap/config_spec.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb index 383e0a09e42..983c79a6364 100644 --- a/lib/gitlab/ldap/config.rb +++ b/lib/gitlab/ldap/config.rb @@ -179,11 +179,21 @@ module Gitlab end def tls_options(method) - if method && options['verify_certificates'] - OpenSSL::SSL::SSLContext::DEFAULT_PARAMS - else - { verify_mode: OpenSSL::SSL::VERIFY_NONE } - end + return { verify_mode: OpenSSL::SSL::VERIFY_NONE } unless method + + opts = if options['verify_certificates'] + OpenSSL::SSL::SSLContext::DEFAULT_PARAMS + else + # It is important to explicitly set verify_mode for two reasons: + # 1. The behavior of OpenSSL is undefined when verify_mode is not set. + # 2. The net-ldap gem implementation verifies the certificate hostname + # unless verify_mode is set to VERIFY_NONE. + { verify_mode: OpenSSL::SSL::VERIFY_NONE } + end + + opts[:ca_file] = options['ca_file'] if options['ca_file'].present? + + opts end def auth_options diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb index bbd4da58252..4544a38876c 100644 --- a/spec/lib/gitlab/ldap/config_spec.rb +++ b/spec/lib/gitlab/ldap/config_spec.rb @@ -138,6 +138,36 @@ describe Gitlab::LDAP::Config, lib: true do }) end end + + context 'when ca_file is specified' do + it 'passes it through in tls_options' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'simple_tls', + 'ca_file' => '/etc/ca.pem' + } + ) + + expect(config.adapter_options[:encryption][:tls_options]).to include({ ca_file: '/etc/ca.pem' }) + end + end + + context 'when ca_file is a blank string' do + it 'does not add the ca_file key to tls_options' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'simple_tls', + 'ca_file' => ' ' + } + ) + + expect(config.adapter_options[:encryption][:tls_options]).not_to have_key(:ca_file) + end + end end describe '#omniauth_options' do -- cgit v1.2.1 From 612b3864505a9e7445d09a80efa263cca9d8758d Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Thu, 8 Jun 2017 17:03:57 -0700 Subject: Set `Net::LDAP` `ssl_version` option --- lib/gitlab/ldap/config.rb | 1 + spec/lib/gitlab/ldap/config_spec.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb index 983c79a6364..a48a485dffd 100644 --- a/lib/gitlab/ldap/config.rb +++ b/lib/gitlab/ldap/config.rb @@ -192,6 +192,7 @@ module Gitlab end opts[:ca_file] = options['ca_file'] if options['ca_file'].present? + opts[:ssl_version] = options['ssl_version'] if options['ssl_version'].present? opts end diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb index 4544a38876c..e24c7d6b9a2 100644 --- a/spec/lib/gitlab/ldap/config_spec.rb +++ b/spec/lib/gitlab/ldap/config_spec.rb @@ -168,6 +168,36 @@ describe Gitlab::LDAP::Config, lib: true do expect(config.adapter_options[:encryption][:tls_options]).not_to have_key(:ca_file) end end + + context 'when ssl_version is specified' do + it 'passes it through in tls_options' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'simple_tls', + 'ssl_version' => 'TLSv1_2' + } + ) + + expect(config.adapter_options[:encryption][:tls_options]).to include({ ssl_version: 'TLSv1_2' }) + end + end + + context 'when ssl_version is a blank string' do + it 'does not add the ssl_version key to tls_options' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'simple_tls', + 'ssl_version' => ' ' + } + ) + + expect(config.adapter_options[:encryption][:tls_options]).not_to have_key(:ssl_version) + end + end end describe '#omniauth_options' do -- cgit v1.2.1 From cd13e4ae734f6a5ff2d02986138bda54267425ae Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Fri, 9 Jun 2017 10:29:19 -0700 Subject: Verify certificates in `omniauth-ldap` --- lib/gitlab/ldap/config.rb | 3 ++- spec/lib/gitlab/ldap/config_spec.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb index a48a485dffd..9ed88330900 100644 --- a/lib/gitlab/ldap/config.rb +++ b/lib/gitlab/ldap/config.rb @@ -62,7 +62,8 @@ module Gitlab base: base, encryption: options['encryption'], filter: omniauth_user_filter, - name_proc: name_proc + name_proc: name_proc, + disable_verify_certificates: !options['verify_certificates'] ) if has_auth? diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb index e24c7d6b9a2..0cebbab5c24 100644 --- a/spec/lib/gitlab/ldap/config_spec.rb +++ b/spec/lib/gitlab/ldap/config_spec.rb @@ -238,6 +238,36 @@ describe Gitlab::LDAP::Config, lib: true do password: 'super_secret' ) end + + context 'when verify_certificates is enabled' do + it 'specifies disable_verify_certificates as false' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'simple_tls', + 'verify_certificates' => true + } + ) + + expect(config.omniauth_options).to include({ disable_verify_certificates: false }) + end + end + + context 'when verify_certificates is disabled' do + it 'specifies disable_verify_certificates as true' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'simple_tls', + 'verify_certificates' => false + } + ) + + expect(config.omniauth_options).to include({ disable_verify_certificates: true }) + end + end end describe '#has_auth?' do -- cgit v1.2.1 From c8dd77de81f42c593dcbf0b373afd0ab33f18071 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Fri, 9 Jun 2017 10:30:17 -0700 Subject: Pass configured `ca_file` to `omniauth-ldap` --- lib/gitlab/ldap/config.rb | 1 + spec/lib/gitlab/ldap/config_spec.rb | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb index 9ed88330900..3f88e20bbec 100644 --- a/lib/gitlab/ldap/config.rb +++ b/lib/gitlab/ldap/config.rb @@ -73,6 +73,7 @@ module Gitlab ) end + opts[:ca_file] = options['ca_file'] if options['ca_file'].present? opts end diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb index 0cebbab5c24..107084519f9 100644 --- a/spec/lib/gitlab/ldap/config_spec.rb +++ b/spec/lib/gitlab/ldap/config_spec.rb @@ -268,6 +268,39 @@ describe Gitlab::LDAP::Config, lib: true do expect(config.omniauth_options).to include({ disable_verify_certificates: true }) end end + + context 'when ca_file is present' do + it 'passes it through' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'simple_tls', + 'verify_certificates' => true, + 'ca_file' => '/etc/ca.pem' + } + ) + + expect(config.omniauth_options).to include({ ca_file: '/etc/ca.pem' }) + end + end + + context 'when ca_file is blank' do + it 'does not include the ca_file option' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'simple_tls', + 'verify_certificates' => true, + 'ca_file' => ' ' + } + ) + + expect(config.omniauth_options).not_to have_key(:ca_file) + end + end + end describe '#has_auth?' do -- cgit v1.2.1 From 2d7d1fa69db2b5e0056d5ab8884684886229f852 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Fri, 9 Jun 2017 10:30:38 -0700 Subject: Pass configured `ssl_version` to `omniauth-ldap` --- lib/gitlab/ldap/config.rb | 2 ++ spec/lib/gitlab/ldap/config_spec.rb | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb index 3f88e20bbec..efc3c50e038 100644 --- a/lib/gitlab/ldap/config.rb +++ b/lib/gitlab/ldap/config.rb @@ -74,6 +74,8 @@ module Gitlab end opts[:ca_file] = options['ca_file'] if options['ca_file'].present? + opts[:ssl_version] = options['ssl_version'] if options['ssl_version'].present? + opts end diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb index 107084519f9..7679c9ea913 100644 --- a/spec/lib/gitlab/ldap/config_spec.rb +++ b/spec/lib/gitlab/ldap/config_spec.rb @@ -301,6 +301,37 @@ describe Gitlab::LDAP::Config, lib: true do end end + context 'when ssl_version is present' do + it 'passes it through' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'simple_tls', + 'verify_certificates' => true, + 'ssl_version' => 'TLSv1_2' + } + ) + + expect(config.omniauth_options).to include({ ssl_version: 'TLSv1_2' }) + end + end + + context 'when ssl_version is blank' do + it 'does not include the ssl_version option' do + stub_ldap_config( + options: { + 'host' => 'ldap.example.com', + 'port' => 686, + 'encryption' => 'simple_tls', + 'verify_certificates' => true, + 'ssl_version' => ' ' + } + ) + + expect(config.omniauth_options).not_to have_key(:ssl_version) + end + end end describe '#has_auth?' do -- cgit v1.2.1 From 72d8b1e40aa96f575aac9a8c9dada09e66cd7a9d Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Fri, 9 Jun 2017 10:39:29 -0700 Subject: Move backwards compatibility logic out of the code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And closer to the configuration setup. The code doesn’t need to know about this. --- config/initializers/1_settings.rb | 6 +++++- lib/gitlab/ldap/config.rb | 6 +----- spec/lib/gitlab/ldap/config_spec.rb | 24 ------------------------ 3 files changed, 6 insertions(+), 30 deletions(-) diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 9344a42540b..20fe92dd6b3 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -145,7 +145,11 @@ if Settings.ldap['enabled'] || Rails.env.test? server['attributes'] = {} if server['attributes'].nil? server['provider_name'] ||= "ldap#{key}".downcase server['provider_class'] = OmniAuth::Utils.camelize(server['provider_name']) - server['encryption'] ||= server['method'] # for backwards compatibility + + # For backwards compatibility + server['encryption'] ||= server['method'] + server['encryption'] = 'simple_tls' if server['encryption'] == 'ssl' + server['encryption'] = 'start_tls' if server['encryption'] == 'tls' # Certificates are not verified for backwards compatibility. # This default should be flipped to true in 9.5. diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb index efc3c50e038..db76ee098c5 100644 --- a/lib/gitlab/ldap/config.rb +++ b/lib/gitlab/ldap/config.rb @@ -5,11 +5,7 @@ module Gitlab NET_LDAP_ENCRYPTION_METHOD = { :simple_tls => :simple_tls, :start_tls => :start_tls, - :plain => nil, - - # Deprecated. Better to pass-through the actual `Net::LDAP` encryption type. - :ssl => :simple_tls, - :tls => :start_tls, + :plain => nil } attr_accessor :provider, :options diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb index 7679c9ea913..e3a9505531d 100644 --- a/spec/lib/gitlab/ldap/config_spec.rb +++ b/spec/lib/gitlab/ldap/config_spec.rb @@ -69,18 +69,6 @@ describe Gitlab::LDAP::Config, lib: true do expect(config.adapter_options[:encryption]).to include({ method: :simple_tls }) end - it 'sets encryption method to simple_tls when configured as ssl, for backwards compatibility' do - stub_ldap_config( - options: { - 'host' => 'ldap.example.com', - 'port' => 686, - 'encryption' => 'ssl' - } - ) - - expect(config.adapter_options[:encryption]).to include({ method: :simple_tls }) - end - it 'sets encryption method to start_tls when configured as start_tls' do stub_ldap_config( options: { @@ -93,18 +81,6 @@ describe Gitlab::LDAP::Config, lib: true do expect(config.adapter_options[:encryption]).to include({ method: :start_tls }) end - it 'sets encryption method to start_tls when configured as tls, for backwards compatibility' do - stub_ldap_config( - options: { - 'host' => 'ldap.example.com', - 'port' => 686, - 'encryption' => 'tls' - } - ) - - expect(config.adapter_options[:encryption]).to include({ method: :start_tls }) - end - context 'when verify_certificates is enabled' do it 'sets tls_options to OpenSSL defaults' do stub_ldap_config( -- cgit v1.2.1 From 71c36c5bb48ad70ec6f079bbedd6114b769805fa Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Fri, 9 Jun 2017 11:43:07 -0700 Subject: Add warning about certificate verification on load --- config/initializers/1_settings.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 20fe92dd6b3..201a1d062b9 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -153,7 +153,16 @@ if Settings.ldap['enabled'] || Rails.env.test? # Certificates are not verified for backwards compatibility. # This default should be flipped to true in 9.5. - server['verify_certificates'] = false if server['verify_certificates'].nil? + if server['verify_certificates'].nil? + server['verify_certificates'] = false + + message = <<-MSG.strip_heredoc + LDAP SSL certificate verification is disabled for backwards-compatibility. + Please add the "verify_certificates" option to gitlab.yml for each LDAP + server. Certificate verification will be enabled by default in GitLab 9.5. + MSG + Rails.logger.warn(message) + end end end -- cgit v1.2.1 From 0b4eb7f21851b478d7fe179a1213d090d8ce4c57 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Fri, 9 Jun 2017 11:47:20 -0700 Subject: Fix code style --- lib/gitlab/ldap/config.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb index db76ee098c5..163e49ecc1c 100644 --- a/lib/gitlab/ldap/config.rb +++ b/lib/gitlab/ldap/config.rb @@ -3,10 +3,10 @@ module Gitlab module LDAP class Config NET_LDAP_ENCRYPTION_METHOD = { - :simple_tls => :simple_tls, - :start_tls => :start_tls, - :plain => nil - } + simple_tls: :simple_tls, + start_tls: :start_tls, + plain: nil + }.freeze attr_accessor :provider, :options @@ -170,7 +170,7 @@ module Gitlab def encryption_options method = translate_method(options['encryption']) options = { method: method } - options.merge!(tls_options: tls_options(method)) if method + options[:tls_options] = tls_options(method) if method options end -- cgit v1.2.1 From fdaa49ca29c458a99cdae207784ecf10f0d208c0 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Fri, 9 Jun 2017 15:35:41 -0700 Subject: Update LDAP SSL config options --- doc/administration/auth/ldap.md | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/doc/administration/auth/ldap.md b/doc/administration/auth/ldap.md index 3449f9e15ce..90dd9d6a51b 100644 --- a/doc/administration/auth/ldap.md +++ b/doc/administration/auth/ldap.md @@ -69,14 +69,42 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server # Example: 'ldap.mydomain.com' host: '_your_ldap_server' # This port is an example, it is sometimes different but it is always an integer and not a string - port: 389 + port: 389 # usually 636 for SSL uid: 'sAMAccountName' # This should be the attribute, not the value that maps to uid. - method: 'plain' # "tls" or "ssl" or "plain" # Examples: 'america\\momo' or 'CN=Gitlab Git,CN=Users,DC=mydomain,DC=com' bind_dn: '_the_full_dn_of_the_user_you_will_bind_with' password: '_the_password_of_the_bind_user' + # Encryption method. The "method" key is deprecated in favor of + # "encryption". + # + # Examples: "start_tls" or "simple_tls" or "plain" + # + # Deprecated values: "tls" was replaced with "start_tls" and "ssl" was + # replaced with "simple_tls". + # + encryption: 'plain' + + # Enables SSL certificate verification if encryption method is + # "start_tls" or "simple_tls". (Defaults to false for backward- + # compatibility) + verify_certificates: false + + # Specifies the path to a file containing a PEM-format CA certificate, + # e.g. if you need to use an internal CA. + # + # Example: '/etc/ca.pem' + # + ca_cert: '' + + # Specifies the SSL version for OpenSSL to use, if the OpenSSL default + # is not appropriate. + # + # Example: 'TLSv1_1' + # + ssl_version: '' + # Set a timeout, in seconds, for LDAP queries. This helps avoid blocking # a request if the LDAP server becomes unresponsive. # A value of 0 means there is no timeout. @@ -116,8 +144,8 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server # # Note: GitLab does not support omniauth-ldap's custom filter syntax. # - # Below an example for get only specific users - # Example: '(&(objectclass=user)(|(samaccountname=momo)(samaccountname=toto)))' + # Example for getting only specific users: + # '(&(objectclass=user)(|(samaccountname=momo)(samaccountname=toto)))' # user_filter: '' -- cgit v1.2.1 From e0fe34778d4705111db0b553925be7da5ee3c66d Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Fri, 9 Jun 2017 15:37:23 -0700 Subject: Copy comment improvements from documentation --- config/gitlab.yml.example | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 8ddd9bab4e6..f702e812955 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -251,9 +251,13 @@ production: &base # Example: 'Paris' or 'Acme, Ltd.' label: 'LDAP' + # Example: 'ldap.mydomain.com' host: '_your_ldap_server' - port: 389 - uid: 'sAMAccountName' + # This port is an example, it is sometimes different but it is always an integer and not a string + port: 389 # usually 636 for SSL + uid: 'sAMAccountName' # This should be the attribute, not the value that maps to uid. + + # Examples: 'america\\momo' or 'CN=Gitlab Git,CN=Users,DC=mydomain,DC=com' bind_dn: '_the_full_dn_of_the_user_you_will_bind_with' password: '_the_password_of_the_bind_user' @@ -314,17 +318,20 @@ production: &base # Base where we can search for users # - # Ex. ou=People,dc=gitlab,dc=example + # Ex. 'ou=People,dc=gitlab,dc=example' or 'DC=mydomain,DC=com' # base: '' # Filter LDAP users # - # Format: RFC 4515 http://tools.ietf.org/search/rfc4515 + # Format: RFC 4515 https://tools.ietf.org/search/rfc4515 # Ex. (employeeType=developer) # # Note: GitLab does not support omniauth-ldap's custom filter syntax. # + # Example for getting only specific users: + # '(&(objectclass=user)(|(samaccountname=momo)(samaccountname=toto)))' + # user_filter: '' # LDAP attributes that GitLab will use to create an account for the LDAP user. -- cgit v1.2.1 From 857dcd6c76d5219aecb15c391b3ee7994f1dbb25 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Fri, 9 Jun 2017 16:01:59 -0700 Subject: Change encryption description --- doc/administration/auth/ldap.md | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/doc/administration/auth/ldap.md b/doc/administration/auth/ldap.md index 90dd9d6a51b..a7395e03d1c 100644 --- a/doc/administration/auth/ldap.md +++ b/doc/administration/auth/ldap.md @@ -278,6 +278,19 @@ In other words, if an existing GitLab user wants to enable LDAP sign-in for themselves, they should check that their GitLab email address matches their LDAP email address, and then sign into GitLab via their LDAP credentials. +## Encryption + +### TLS Server Authentication + +There are two encryption methods, `simple_tls` and `start_tls`. + +For either encryption method, if setting `validate_certificates: false`, TLS +encryption is established with the LDAP server before any LDAP-protocol data is +exchanged but no validation of the LDAP server's SSL certificate is performed. + +>**Note**: Before GitLab 9.5, `validate_certificates: false` is the default if +unspecified. + ## Limitations ### TLS Client Authentication @@ -287,14 +300,6 @@ You should disable anonymous LDAP authentication and enable simple or SASL authentication. The TLS client authentication setting in your LDAP server cannot be mandatory and clients cannot be authenticated with the TLS protocol. -### TLS Server Authentication - -Not supported by GitLab's configuration options. -When setting `method: ssl`, the underlying authentication method used by -`omniauth-ldap` is `simple_tls`. This method establishes TLS encryption with -the LDAP server before any LDAP-protocol data is exchanged but no validation of -the LDAP server's SSL certificate is performed. - ## Troubleshooting ### Debug LDAP user filter with ldapsearch @@ -334,9 +339,9 @@ tree and traverse it. ### Connection Refused If you are getting 'Connection Refused' errors when trying to connect to the -LDAP server please double-check the LDAP `port` and `method` settings used by -GitLab. Common combinations are `method: 'plain'` and `port: 389`, OR -`method: 'ssl'` and `port: 636`. +LDAP server please double-check the LDAP `port` and `encryption` settings used by +GitLab. Common combinations are `encryption: 'plain'` and `port: 389`, OR +`encryption: 'simple_tls'` and `port: 636`. ### Troubleshooting -- cgit v1.2.1 From 8bc20a8e00111a1453e51d88fcf7520091b47d02 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Fri, 9 Jun 2017 16:09:52 -0700 Subject: Add changelog entry --- changelogs/unreleased/mk-add-ldap-ssl-certificate-verification.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/mk-add-ldap-ssl-certificate-verification.yml diff --git a/changelogs/unreleased/mk-add-ldap-ssl-certificate-verification.yml b/changelogs/unreleased/mk-add-ldap-ssl-certificate-verification.yml new file mode 100644 index 00000000000..80e6c50d5b3 --- /dev/null +++ b/changelogs/unreleased/mk-add-ldap-ssl-certificate-verification.yml @@ -0,0 +1,4 @@ +--- +title: Add LDAP SSL certificate verification option +merge_request: +author: -- cgit v1.2.1 From 951bd2a43161206dbafe2a6099098e5fb48a6005 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Mon, 12 Jun 2017 10:17:49 -0700 Subject: Update more examples --- config/gitlab.yml.example | 2 +- doc/articles/how_to_configure_ldap_gitlab_ce/index.md | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index f702e812955..106658ad12b 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -709,7 +709,7 @@ test: host: 127.0.0.1 port: 3890 uid: 'uid' - method: 'plain' # "tls" or "ssl" or "plain" + encryption: 'plain' # "start_tls" or "simple_tls" or "plain" base: 'dc=example,dc=com' user_filter: '' group_base: 'ou=groups,dc=example,dc=com' diff --git a/doc/articles/how_to_configure_ldap_gitlab_ce/index.md b/doc/articles/how_to_configure_ldap_gitlab_ce/index.md index 6892905dd94..130e8f542b4 100644 --- a/doc/articles/how_to_configure_ldap_gitlab_ce/index.md +++ b/doc/articles/how_to_configure_ldap_gitlab_ce/index.md @@ -120,7 +120,8 @@ gitlab_rails['ldap_servers'] = { 'host' => 'ad.example.org', 'port' => 636, 'uid' => 'sAMAccountName', - 'method' => 'ssl', + 'encryption' => 'simple_tls', + 'verify_certificates' => true, 'bind_dn' => 'CN=GitLabSRV,CN=Users,DC=GitLab,DC=org', 'password' => 'Password1', 'active_directory' => true, @@ -255,7 +256,7 @@ If `allow_username_or_email_login` is enabled in the LDAP configuration, GitLab ## LDAP extended features on GitLab EE -With [GitLab Enterprise Edition (EE)](https://about.gitlab.com/giltab-ee/), besides everything we just described, you'll +With [GitLab Enterprise Edition (EE)](https://about.gitlab.com/gitlab-ee/), besides everything we just described, you'll have extended functionalities with LDAP, such as: - Group sync -- cgit v1.2.1 From 7f92a36a36ab8183c843982bf91bdabb45861154 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Tue, 13 Jun 2017 14:01:28 -0700 Subject: Fix plain LDAP (no encryption) --- Gemfile | 2 +- Gemfile.lock | 4 ++-- lib/gitlab/ldap/config.rb | 9 ++++++--- spec/lib/gitlab/ldap/config_spec.rb | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Gemfile b/Gemfile index 276893d0ff4..7bb912571f4 100644 --- a/Gemfile +++ b/Gemfile @@ -61,7 +61,7 @@ gem 'browser', '~> 2.2' # LDAP Auth # GitLab fork with several improvements to original library. For full list of changes # see https://github.com/intridea/omniauth-ldap/compare/master...gitlabhq:master -gem 'gitlab_omniauth-ldap', '~> 2.0.1', require: 'omniauth-ldap' +gem 'gitlab_omniauth-ldap', '~> 2.0.2', require: 'omniauth-ldap' # Git Wiki # Required manually in config/initializers/gollum.rb to control load order diff --git a/Gemfile.lock b/Gemfile.lock index 2b2df1b6bcc..661f0294646 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -288,7 +288,7 @@ GEM mime-types (>= 1.16, < 3) posix-spawn (~> 0.3) gitlab-markup (1.5.1) - gitlab_omniauth-ldap (2.0.1) + gitlab_omniauth-ldap (2.0.2) net-ldap (~> 0.16) omniauth (~> 1.3) pyu-ruby-sasl (>= 0.0.3.3, < 0.1) @@ -978,7 +978,7 @@ DEPENDENCIES github-linguist (~> 4.7.0) gitlab-flowdock-git-hook (~> 1.0.1) gitlab-markup (~> 1.5.1) - gitlab_omniauth-ldap (~> 2.0.1) + gitlab_omniauth-ldap (~> 2.0.2) gollum-lib (~> 4.2) gollum-rugged_adapter (~> 0.4.4) gon (~> 6.1.0) diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb index 163e49ecc1c..8eda3ea03f9 100644 --- a/lib/gitlab/ldap/config.rb +++ b/lib/gitlab/ldap/config.rb @@ -169,9 +169,12 @@ module Gitlab def encryption_options method = translate_method(options['encryption']) - options = { method: method } - options[:tls_options] = tls_options(method) if method - options + return nil unless method + + { + method: method, + tls_options: tls_options(method) + } end def translate_method(method_from_config) diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb index e3a9505531d..3a56797d68b 100644 --- a/spec/lib/gitlab/ldap/config_spec.rb +++ b/spec/lib/gitlab/ldap/config_spec.rb @@ -32,7 +32,7 @@ describe Gitlab::LDAP::Config, lib: true do expect(config.adapter_options).to eq( host: 'ldap.example.com', port: 386, - encryption: { method: nil } + encryption: nil ) end -- cgit v1.2.1 From 26ee3a28029597f6813e652a09288504e9a2291d Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Tue, 13 Jun 2017 14:03:25 -0700 Subject: Mention how to test LDAP connections --- config/gitlab.yml.example | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 106658ad12b..e9bf2df490f 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -228,7 +228,8 @@ production: &base # ========================== ## LDAP settings - # You can inspect a sample of the LDAP users with login access by running: + # You can test connections and inspect a sample of the LDAP users with login + # access by running: # bundle exec rake gitlab:ldap:check RAILS_ENV=production ldap: enabled: false -- cgit v1.2.1 From 6f5f80592499dace8900961e0c596771d46d588c Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Tue, 13 Jun 2017 15:25:06 -0700 Subject: Add net-ldap explicitly since we use it directly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And this has already been done on EE, so it’ll match now. --- Gemfile | 1 + Gemfile.lock | 1 + 2 files changed, 2 insertions(+) diff --git a/Gemfile b/Gemfile index 7bb912571f4..b9d206c2500 100644 --- a/Gemfile +++ b/Gemfile @@ -62,6 +62,7 @@ gem 'browser', '~> 2.2' # GitLab fork with several improvements to original library. For full list of changes # see https://github.com/intridea/omniauth-ldap/compare/master...gitlabhq:master gem 'gitlab_omniauth-ldap', '~> 2.0.2', require: 'omniauth-ldap' +gem 'net-ldap' # Git Wiki # Required manually in config/initializers/gollum.rb to control load order diff --git a/Gemfile.lock b/Gemfile.lock index 661f0294646..c21b8d43b32 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1013,6 +1013,7 @@ DEPENDENCIES minitest (~> 5.7.0) mousetrap-rails (~> 1.4.6) mysql2 (~> 0.4.5) + net-ldap nokogiri (~> 1.6.7, >= 1.6.7.2) oauth2 (~> 1.4) octokit (~> 4.6.2) -- cgit v1.2.1 From 425dbdd222244bc00cab8c2dbd6bb94233d11a15 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 26 Jul 2017 11:13:35 +0100 Subject: fixed label subscription & merge conflicts --- app/assets/javascripts/dispatcher.js | 11 +++++++++-- app/assets/javascripts/init_legacy_filters.js | 3 ++- .../javascripts/merge_conflicts/merge_conflicts_bundle.js | 3 +++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 0b2c7e434f0..bab2d59e67f 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -263,7 +263,6 @@ import initIssuableSidebar from './init_issuable_sidebar'; new ZenMode(); new gl.GLForm($('.release-form'), true); break; - case 'projects:merge_requests:conflicts:show': case 'projects:merge_requests:show': new gl.Diff(); shortcut_handler = new ShortcutsIssuable(true); @@ -381,7 +380,15 @@ import initIssuableSidebar from './init_issuable_sidebar'; if ($('.prioritized-labels').length) { new gl.LabelManager(); } - new gl.ProjectLabelSubscription('.label-subscription'); + $('.label-subscription').each((i, el) => { + const $el = $(el); + + if ($el.find('.dropdown-group-label').length) { + new gl.GroupLabelSubscription($el); + } else { + new gl.ProjectLabelSubscription($el); + } + }); break; case 'projects:network:show': // Ensure we don't create a particular shortcut handler here. This is diff --git a/app/assets/javascripts/init_legacy_filters.js b/app/assets/javascripts/init_legacy_filters.js index aa25f295bbc..1211c2c802c 100644 --- a/app/assets/javascripts/init_legacy_filters.js +++ b/app/assets/javascripts/init_legacy_filters.js @@ -1,10 +1,11 @@ /* eslint-disable no-new */ -/* global UsersSelect */ /* global LabelsSelect */ /* global MilestoneSelect */ /* global IssueStatusSelect */ /* global SubscriptionSelect */ +import UsersSelect from './users_select'; + export default () => { new UsersSelect(); new LabelsSelect(); diff --git a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js index 17030c3e4d3..d74cf5328ad 100644 --- a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js +++ b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js @@ -2,6 +2,7 @@ /* global Flash */ import Vue from 'vue'; +import initIssuableSidebar from '../init_issuable_sidebar'; import './merge_conflict_store'; import './merge_conflict_service'; import './mixins/line_conflict_utils'; @@ -19,6 +20,8 @@ $(() => { resolveConflictsPath: conflictsEl.dataset.resolveConflictsPath }); + initIssuableSidebar(); + gl.MergeConflictsResolverApp = new Vue({ el: '#conflicts', data: mergeConflictsStore.state, -- cgit v1.2.1 From 02b2cf63fb0dd2a16e24704c0f9b38ae941a039a Mon Sep 17 00:00:00 2001 From: Hiroyuki Sato Date: Wed, 26 Jul 2017 19:35:18 +0900 Subject: Update changelog appropriately --- changelogs/unreleased/1827-prevent-concurrent-editing-wiki.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/unreleased/1827-prevent-concurrent-editing-wiki.yml b/changelogs/unreleased/1827-prevent-concurrent-editing-wiki.yml index 3ef6544c013..c8c2bb3eb4c 100644 --- a/changelogs/unreleased/1827-prevent-concurrent-editing-wiki.yml +++ b/changelogs/unreleased/1827-prevent-concurrent-editing-wiki.yml @@ -1,4 +1,4 @@ --- -title: Prevent concurrent editing wiki +title: Alert the user if a Wiki page changed while they were editing it in order to prevent overwriting changes. merge_request: 9707 author: Hiroyuki Sato -- cgit v1.2.1 From a7d49c39276955f9accc6bf79b71abd350a0f161 Mon Sep 17 00:00:00 2001 From: Hiroyuki Sato Date: Wed, 26 Jul 2017 19:53:33 +0900 Subject: Remove unnecessary code --- spec/features/projects/wiki/user_updates_wiki_page_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb index fcedf27225e..cb44f37e29f 100644 --- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb @@ -6,7 +6,6 @@ feature 'Projects > Wiki > User updates wiki page', feature: true do background do project.team << [user, :master] - WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute sign_in(user) visit project_wikis_path(project) -- cgit v1.2.1 From c4854426654949feef4085fd3026d5862f00aa7c Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Wed, 26 Jul 2017 03:20:02 -0700 Subject: Fix project wiki web_url spec --- spec/models/project_wiki_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index 1f314791479..79ab50c1234 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -21,7 +21,7 @@ describe ProjectWiki, models: true do describe '#web_url' do it 'returns the full web URL to the wiki' do - expect(subject.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/wikis/home") + expect(subject.web_url).to match("https?://[^\/]+/#{project.path_with_namespace}/wikis/home") end end -- cgit v1.2.1 From f8cd9aeb26c290eb92274b63426eb3b809693e9d Mon Sep 17 00:00:00 2001 From: Max Raab Date: Wed, 26 Jul 2017 07:22:57 +0000 Subject: Add missing colon --- app/views/admin/dashboard/index.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml index 128b5dc01ab..8e94e68bc11 100644 --- a/app/views/admin/dashboard/index.html.haml +++ b/app/views/admin/dashboard/index.html.haml @@ -150,7 +150,7 @@ .well-segment.well-centered = link_to admin_groups_path do %h3.text-center - Groups + Groups: = number_with_delimiter(Group.count) %hr = link_to 'New group', new_admin_group_path, class: "btn btn-new" -- cgit v1.2.1 From 7ce0a61a993f36f30692f93c477f671f82dbef51 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Wed, 26 Jul 2017 13:23:27 +0200 Subject: use `.zero?` instead of `== 0` --- lib/gitlab/health_checks/fs_shards_check.rb | 8 ++++---- spec/lib/gitlab/health_checks/fs_shards_check_spec.rb | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/gitlab/health_checks/fs_shards_check.rb b/lib/gitlab/health_checks/fs_shards_check.rb index ddd1aaa7043..928fb014ef4 100644 --- a/lib/gitlab/health_checks/fs_shards_check.rb +++ b/lib/gitlab/health_checks/fs_shards_check.rb @@ -81,7 +81,7 @@ module Gitlab def delete_test_file(tmp_path) _, status = exec_with_timeout(%W{ rm -f #{tmp_path} }) - status == 0 + status.zero? rescue Errno::ENOENT File.delete(tmp_path) rescue Errno::ENOENT end @@ -90,7 +90,7 @@ module Gitlab stat_path = File.join(storage_path(storage_name), '.') begin _, status = exec_with_timeout(%W{ stat #{stat_path} }) - status == 0 + status.zero? rescue Errno::ENOENT File.exist?(stat_path) && File::Stat.new(stat_path).readable? end @@ -100,7 +100,7 @@ module Gitlab _, status = exec_with_timeout(%W{ tee #{tmp_path} }) do |stdin| stdin.write(RANDOM_STRING) end - status == 0 + status.zero? rescue Errno::ENOENT written_bytes = File.write(tmp_path, RANDOM_STRING) rescue Errno::ENOENT written_bytes == RANDOM_STRING.length @@ -110,7 +110,7 @@ module Gitlab _, status = exec_with_timeout(%W{ diff #{tmp_path} - }) do |stdin| stdin.write(RANDOM_STRING) end - status == 0 + status.zero? rescue Errno::ENOENT file_contents = File.read(tmp_path) rescue Errno::ENOENT file_contents == RANDOM_STRING diff --git a/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb b/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb index 0a8dfa3bbdd..8abc4320c59 100644 --- a/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb +++ b/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::HealthChecks::FsShardsCheck do def command_exists?(command) _, status = Gitlab::Popen.popen(%W{ #{command} 1 echo }) - status == 0 + status.zero? rescue Errno::ENOENT false end -- cgit v1.2.1 From b5bdc55d239f3e19f8fe1e59b118da05ac81a0dd Mon Sep 17 00:00:00 2001 From: Tiago Botelho Date: Tue, 18 Jul 2017 16:09:14 +0100 Subject: Move exception handling to execute --- app/services/projects/destroy_service.rb | 57 ++++++++++++++-------- app/views/projects/_deletion_failed.html.haml | 13 ++--- app/views/projects/_flash_messages.html.haml | 5 +- app/views/projects/empty.html.haml | 1 - app/views/projects/show.html.haml | 1 - app/workers/project_destroy_worker.rb | 2 +- ...9289-project-destroy-clean-up-after-failure.yml | 4 ++ spec/features/projects/show_project_spec.rb | 18 ++----- spec/services/projects/destroy_service_spec.rb | 37 +++++++------- spec/workers/project_destroy_worker_spec.rb | 19 ++++---- 10 files changed, 81 insertions(+), 76 deletions(-) create mode 100644 changelogs/unreleased/29289-project-destroy-clean-up-after-failure.yml diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index 7e38aacc91a..f6e8b6655f2 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -15,29 +15,48 @@ module Projects def execute return false unless can?(current_user, :remove_project, project) - repo_path = project.path_with_namespace - wiki_path = repo_path + '.wiki' - # Flush the cache for both repositories. This has to be done _before_ # removing the physical repositories as some expiration code depends on # Git data (e.g. a list of branch names). - flush_caches(project, wiki_path) + flush_caches(project) Projects::UnlinkForkService.new(project, current_user).execute - attempt_destroy_transaction(project, repo_path, wiki_path) + attempt_destroy_transaction(project) system_hook_service.execute_hooks_for(project, :destroy) - log_info("Project \"#{project.full_path}\" was removed") + true - rescue Projects::DestroyService::DestroyError => error - Rails.logger.error("Deletion failed on #{project.full_path} with the following message: #{error.message}") + rescue => error + attempt_rollback(project, error.message) false + rescue Exception => error # rubocop:disable Lint/RescueException + # Project.transaction can raise Exception + attempt_rollback(project, error.message) + raise end private + def repo_path + project.path_with_namespace + end + + def wiki_path + repo_path + '.wiki' + end + + def trash_repositories! + unless remove_repository(repo_path) + raise_error('Failed to remove project repository. Please try again or contact administrator.') + end + + unless remove_repository(wiki_path) + raise_error('Failed to remove wiki repository. Please try again or contact administrator.') + end + end + def remove_repository(path) # Skip repository removal. We use this flag when remove user or group return true if params[:skip_repo] == true @@ -59,26 +78,24 @@ module Projects end end - def attempt_destroy_transaction(project, repo_path, wiki_path) + def attempt_rollback(project, message) + return unless project + + project.update_attributes(delete_error: message, pending_delete: false) + log_error("Deletion failed on #{project.full_path} with the following message: #{message}") + end + + def attempt_destroy_transaction(project) Project.transaction do unless remove_legacy_registry_tags raise_error('Failed to remove some tags in project container registry. Please try again or contact administrator.') end - unless remove_repository(repo_path) - raise_error('Failed to remove project repository. Please try again or contact administrator.') - end - - unless remove_repository(wiki_path) - raise_error('Failed to remove wiki repository. Please try again or contact administrator.') - end + trash_repositories! project.team.truncate project.destroy! end - rescue Exception => error # rubocop:disable Lint/RescueException - project.update_attributes(delete_error: error.message, pending_delete: false) - raise end ## @@ -107,7 +124,7 @@ module Projects "#{path}+#{project.id}#{DELETED_FLAG}" end - def flush_caches(project, wiki_path) + def flush_caches(project) project.repository.before_delete Repository.new(wiki_path, project).before_delete diff --git a/app/views/projects/_deletion_failed.html.haml b/app/views/projects/_deletion_failed.html.haml index 028510b5671..4f3698f91e6 100644 --- a/app/views/projects/_deletion_failed.html.haml +++ b/app/views/projects/_deletion_failed.html.haml @@ -1,9 +1,6 @@ -- if @project.delete_error.present? - .project-deletion-failed-message.alert.alert-warning - This project was scheduled for deletion, but failed with the following message: - = @project.delete_error +- project = local_assigns.fetch(:project) +- return unless project.delete_error.present? - .alert-link-group - = link_to "Don't show again", profile_path(user: { hide_no_ssh_key: true }), method: :put, class: 'alert-link' - | - = link_to 'Remind later', '#', class: 'hide-no-ssh-message alert-link' +.project-deletion-failed-message.alert.alert-warning + This project was scheduled for deletion, but failed with the following message: + = project.delete_error diff --git a/app/views/projects/_flash_messages.html.haml b/app/views/projects/_flash_messages.html.haml index 6c9d466c761..f47d84ef755 100644 --- a/app/views/projects/_flash_messages.html.haml +++ b/app/views/projects/_flash_messages.html.haml @@ -1,5 +1,8 @@ +- project = local_assigns.fetch(:project) +- flash_message_container = show_new_nav? ? :new_global_flash : :flash_message + = content_for flash_message_container do - = render 'deletion_failed' + = render partial: 'deletion_failed', locals: { project: project } - if current_user && can?(current_user, :download_code, project) = render 'shared/no_ssh' = render 'shared/no_password' diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml index 3d7c72ae61a..d17709380d5 100644 --- a/app/views/projects/empty.html.haml +++ b/app/views/projects/empty.html.haml @@ -1,5 +1,4 @@ - @no_container = true -- flash_message_container = show_new_nav? ? :new_global_flash : :flash_message = render partial: 'flash_messages', locals: { project: @project } diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 3926149e790..a9b39cedb1d 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -1,7 +1,6 @@ - @no_container = true - breadcrumb_title "Project" - @content_class = "limit-container-width" unless fluid_layout -- flash_message_container = show_new_nav? ? :new_global_flash : :flash_message = content_for :meta_tags do = auto_discovery_link_tag(:atom, project_path(@project, rss_url_options), title: "#{@project.name} activity") diff --git a/app/workers/project_destroy_worker.rb b/app/workers/project_destroy_worker.rb index e695ec060f0..a9188b78460 100644 --- a/app/workers/project_destroy_worker.rb +++ b/app/workers/project_destroy_worker.rb @@ -8,6 +8,6 @@ class ProjectDestroyWorker ::Projects::DestroyService.new(project, user, params.symbolize_keys).execute rescue ActiveRecord::RecordNotFound => error - logger.error("Failed to delete project #{project.path_with_namespace} (#{project.id}): #{error.message}") + logger.error("Failed to delete project (#{project_id}): #{error.message}") end end diff --git a/changelogs/unreleased/29289-project-destroy-clean-up-after-failure.yml b/changelogs/unreleased/29289-project-destroy-clean-up-after-failure.yml new file mode 100644 index 00000000000..488b37ac37f --- /dev/null +++ b/changelogs/unreleased/29289-project-destroy-clean-up-after-failure.yml @@ -0,0 +1,4 @@ +--- +title: Handle errors while a project is being deleted asynchronously. +merge_request: 11088 +author: diff --git a/spec/features/projects/show_project_spec.rb b/spec/features/projects/show_project_spec.rb index 5aa0d8f0026..1bc6fae9e7f 100644 --- a/spec/features/projects/show_project_spec.rb +++ b/spec/features/projects/show_project_spec.rb @@ -3,28 +3,18 @@ require 'spec_helper' describe 'Project show page', feature: true do context 'when project pending delete' do let(:project) { create(:project, :empty_repo, pending_delete: true) } - let(:worker) { ProjectDestroyWorker.new } before do sign_in(project.owner) end - it 'shows flash error if deletion for project fails' do - error_message = "some error message" - project.update_attributes(delete_error: error_message, pending_delete: false) + it 'shows error message if deletion for project fails' do + project.update_attributes(delete_error: "Something went wrong", pending_delete: false) - visit namespace_project_path(project.namespace, project) + visit project_path(project) expect(page).to have_selector('.project-deletion-failed-message') - expect(page).to have_content("This project was scheduled for deletion, but failed with the following message: #{error_message}") - end - - it 'renders 404 if project was successfully deleted' do - worker.perform(project.id, project.owner.id, {}) - - visit namespace_project_path(project.namespace, project) - - expect(page).to have_http_status(404) + expect(page).to have_content("This project was scheduled for deletion, but failed with the following message: #{project.delete_error}") end end end diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index a629afe723d..357e09bee95 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -130,30 +130,29 @@ describe Projects::DestroyService, services: true do it_behaves_like 'handles errors thrown during async destroy', "Failed to remove project repository" end - context 'when `execute` raises any other error' do + context 'when `execute` raises expected error' do before do - expect_any_instance_of(Projects::DestroyService) - .to receive(:execute).and_raise(ArgumentError.new("Other error message")) + expect_any_instance_of(Project) + .to receive(:destroy!).and_raise(StandardError.new("Other error message")) end it_behaves_like 'handles errors thrown during async destroy', "Other error message" end - end - end - context 'with execute' do - it_behaves_like 'deleting the project with pipeline and build' + context 'when `execute` raises unexpected error' do + before do + expect_any_instance_of(Project) + .to receive(:destroy!).and_raise(Exception.new("Other error message")) + end - context 'when `execute` raises an error' do - before do - expect_any_instance_of(Projects::DestroyService) - .to receive(:execute).and_raise(ArgumentError) - end + it 'allows error to bubble up and rolls back project deletion' do + expect do + Sidekiq::Testing.inline! { destroy_project(project, user, {}) } + end.to raise_error - it 'allows the error to bubble up' do - expect do - Sidekiq::Testing.inline! { Projects::DestroyService.new(project, user, {}).execute } - end.to raise_error(ArgumentError) + expect(project.reload.pending_delete).to be(false) + expect(project.delete_error).to include("Other error message") + end end end end @@ -182,8 +181,7 @@ describe Projects::DestroyService, services: true do expect_any_instance_of(ContainerRepository) .to receive(:delete_tags!).and_return(false) - expect{ destroy_project(project, user) } - .to raise_error(ActiveRecord::RecordNotDestroyed) + expect(destroy_project(project, user)).to be false end end end @@ -208,8 +206,7 @@ describe Projects::DestroyService, services: true do expect_any_instance_of(ContainerRepository) .to receive(:delete_tags!).and_return(false) - expect { destroy_project(project, user) } - .to raise_error(Projects::DestroyService::DestroyError) + expect(destroy_project(project, user)).to be false end end end diff --git a/spec/workers/project_destroy_worker_spec.rb b/spec/workers/project_destroy_worker_spec.rb index 29f0295de42..f19c9dff941 100644 --- a/spec/workers/project_destroy_worker_spec.rb +++ b/spec/workers/project_destroy_worker_spec.rb @@ -21,17 +21,16 @@ describe ProjectDestroyWorker do expect(Dir.exist?(path)).to be_truthy end - describe 'when StandardError is raised' do - it 'reverts pending_delete attribute with a error message' do - allow_any_instance_of(::Projects::DestroyService).to receive(:execute).and_raise(StandardError, "some error message") - - expect do - subject.perform(project.id, project.owner.id, {}) - end.to change { project.reload.pending_delete }.from(true).to(false) + it 'does not raise error when project could not be found' do + expect do + subject.perform(-1, project.owner.id, {}) + end.not_to raise_error + end - expect(Project.all).to include(project) - expect(project.delete_error).to eq("some error message") - end + it 'does not raise error when user could not be found' do + expect do + subject.perform(project.id, -1, {}) + end.not_to raise_error end end end -- cgit v1.2.1 From d596c731459140dd49ecf05475e62861874e97a1 Mon Sep 17 00:00:00 2001 From: Andrew Newdigate Date: Wed, 26 Jul 2017 15:06:52 +0100 Subject: Removed `Repository#blob_by_oid` unused method --- app/models/repository.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index d27eeff9fb4..50b7a477904 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -457,10 +457,6 @@ class Repository nil end - def blob_by_oid(oid) - Gitlab::Git::Blob.raw(self, oid) - end - def root_ref if raw_repository raw_repository.root_ref -- cgit v1.2.1 From 869d728dfb64db47b5c019fb233ad9d6af9a9d17 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Tue, 25 Jul 2017 13:20:12 -0500 Subject: Test remove potentially unused file --- app/views/groups/_shared_projects.html.haml | 1 - 1 file changed, 1 deletion(-) delete mode 100644 app/views/groups/_shared_projects.html.haml diff --git a/app/views/groups/_shared_projects.html.haml b/app/views/groups/_shared_projects.html.haml deleted file mode 100644 index b1694c919d0..00000000000 --- a/app/views/groups/_shared_projects.html.haml +++ /dev/null @@ -1 +0,0 @@ -= render 'shared/projects/list', projects: projects, stars: false, skip_namespace: false -- cgit v1.2.1 From 396b8f91ec47ffb5a02ebf6d713ef4cbf04f1f94 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Tue, 25 Jul 2017 17:57:02 +0100 Subject: Fix saving diffs that are not valid UTF-8 Previously, we used Psych, which would: 1. Check if a string was encoded as binary, and not ASCII-compatible. 2. Add the !binary tag in that case. 3. Convert to base64. We need to do the same thing, using a new column in place of the tag. --- app/models/merge_request_diff.rb | 17 ++++++++++---- app/models/merge_request_diff_file.rb | 10 ++++++++ ...ing-a-binary-file-with-non-utf-8-characters.yml | 5 ++++ ...45659_add_binary_to_merge_request_diff_files.rb | 9 ++++++++ db/schema.rb | 3 ++- spec/features/projects/ref_switcher_spec.rb | 4 ++-- .../gitlab/import_export/safe_model_attributes.yml | 1 + spec/models/merge_request_diff_file_spec.rb | 27 +++++++++++++++++++++- spec/models/merge_request_diff_spec.rb | 9 ++++++++ spec/support/test_env.rb | 3 ++- 10 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 changelogs/unreleased/35539-can-t-create-a-merge-request-containing-a-binary-file-with-non-utf-8-characters.yml create mode 100644 db/migrate/20170725145659_add_binary_to_merge_request_diff_files.rb diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 4b141945ab4..ec87aee9310 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -236,10 +236,21 @@ class MergeRequestDiff < ActiveRecord::Base def create_merge_request_diff_files(diffs) rows = diffs.map.with_index do |diff, index| - diff.to_hash.merge( + diff_hash = diff.to_hash.merge( + binary: false, merge_request_diff_id: self.id, relative_order: index ) + + # Compatibility with old diffs created with Psych. + diff_hash.tap do |hash| + diff_text = hash[:diff] + + if diff_text.encoding == Encoding::BINARY && !diff_text.ascii_only? + hash[:binary] = true + hash[:diff] = [diff_text].pack('m0') + end + end end Gitlab::Database.bulk_insert('merge_request_diff_files', rows) @@ -268,9 +279,7 @@ class MergeRequestDiff < ActiveRecord::Base st_diffs end elsif merge_request_diff_files.present? - merge_request_diff_files - .as_json(only: Gitlab::Git::Diff::SERIALIZE_KEYS) - .map(&:with_indifferent_access) + merge_request_diff_files.map(&:to_hash) end end diff --git a/app/models/merge_request_diff_file.rb b/app/models/merge_request_diff_file.rb index 598ebd4d829..1199ff5af22 100644 --- a/app/models/merge_request_diff_file.rb +++ b/app/models/merge_request_diff_file.rb @@ -8,4 +8,14 @@ class MergeRequestDiffFile < ActiveRecord::Base encode_utf8(diff) if diff.respond_to?(:encoding) end + + def diff + binary? ? super.unpack('m0').first : super + end + + def to_hash + keys = Gitlab::Git::Diff::SERIALIZE_KEYS - [:diff] + + as_json(only: keys).merge(diff: diff).with_indifferent_access + end end diff --git a/changelogs/unreleased/35539-can-t-create-a-merge-request-containing-a-binary-file-with-non-utf-8-characters.yml b/changelogs/unreleased/35539-can-t-create-a-merge-request-containing-a-binary-file-with-non-utf-8-characters.yml new file mode 100644 index 00000000000..8d92aacc9ef --- /dev/null +++ b/changelogs/unreleased/35539-can-t-create-a-merge-request-containing-a-binary-file-with-non-utf-8-characters.yml @@ -0,0 +1,5 @@ +--- +title: Fix creating merge request diffs when diff contains bytes that are invalid + in UTF-8 +merge_request: +author: diff --git a/db/migrate/20170725145659_add_binary_to_merge_request_diff_files.rb b/db/migrate/20170725145659_add_binary_to_merge_request_diff_files.rb new file mode 100644 index 00000000000..1f5fa7e3d49 --- /dev/null +++ b/db/migrate/20170725145659_add_binary_to_merge_request_diff_files.rb @@ -0,0 +1,9 @@ +class AddBinaryToMergeRequestDiffFiles < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def change + add_column :merge_request_diff_files, :binary, :boolean + end +end diff --git a/db/schema.rb b/db/schema.rb index 61bcd8c7e95..1ec25c7d46f 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: 20170724214302) do +ActiveRecord::Schema.define(version: 20170725145659) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -748,6 +748,7 @@ ActiveRecord::Schema.define(version: 20170724214302) do t.text "new_path", null: false t.text "old_path", null: false t.text "diff", null: false + t.boolean "binary" end add_index "merge_request_diff_files", ["merge_request_diff_id", "relative_order"], name: "index_merge_request_diff_files_on_mr_diff_id_and_order", unique: true, using: :btree diff --git a/spec/features/projects/ref_switcher_spec.rb b/spec/features/projects/ref_switcher_spec.rb index 31c7b492ab7..9f5544ac43e 100644 --- a/spec/features/projects/ref_switcher_spec.rb +++ b/spec/features/projects/ref_switcher_spec.rb @@ -19,14 +19,14 @@ feature 'Ref switcher', feature: true, js: true do input.set 'binary' wait_for_requests - expect(find('.dropdown-content ul')).to have_selector('li', count: 6) + expect(find('.dropdown-content ul')).to have_selector('li', count: 7) page.within '.dropdown-content ul' do input.native.send_keys :enter end end - expect(page).to have_title 'binary-encoding' + expect(page).to have_title 'add-pdf-text-binary' end it "user selects ref with special characters" do diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 0f2db3380a7..11f4c16ff96 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -195,6 +195,7 @@ MergeRequestDiffFile: - a_mode - b_mode - too_large +- binary Ci::Pipeline: - id - project_id diff --git a/spec/models/merge_request_diff_file_spec.rb b/spec/models/merge_request_diff_file_spec.rb index 7276f5b5061..239620ef4fc 100644 --- a/spec/models/merge_request_diff_file_spec.rb +++ b/spec/models/merge_request_diff_file_spec.rb @@ -1,8 +1,33 @@ require 'rails_helper' describe MergeRequestDiffFile, type: :model do + describe '#diff' do + let(:unpacked) { 'unpacked' } + let(:packed) { [unpacked].pack('m0') } + + before do + subject.diff = packed + end + + context 'when the diff is marked as binary' do + before do + subject.binary = true + end + + it 'unpacks from base 64' do + expect(subject.diff).to eq(unpacked) + end + end + + context 'when the diff is not marked as binary' do + it 'returns the raw diff' do + expect(subject.diff).to eq(packed) + end + end + end + describe '#utf8_diff' do - it 'does not raise error when a hash value is in binary' do + it 'does not raise error when the diff is binary' do subject.diff = "\x05\x00\x68\x65\x6c\x6c\x6f" expect { subject.utf8_diff }.not_to raise_error diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index edc2f4bb9f0..0e77752bccc 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -105,6 +105,15 @@ describe MergeRequestDiff, models: true do expect(mr_diff.empty?).to be_truthy end + + it 'saves binary diffs correctly' do + path = 'files/images/icn-time-tracking.pdf' + mr_diff = create(:merge_request, source_branch: 'add-pdf-text-binary', target_branch: 'master').merge_request_diff + diff_file = mr_diff.merge_request_diff_files.find_by(new_path: path) + + expect(diff_file).to be_binary + expect(diff_file.diff).to eq(mr_diff.compare.diffs(paths: [path]).to_a.first.diff) + end end describe '#commit_shas' do diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 0a194ca4c90..c32c05b03e2 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -41,7 +41,8 @@ module TestEnv 'csv' => '3dd0896', 'v1.1.0' => 'b83d6e3', 'add-ipython-files' => '93ee732', - 'add-pdf-file' => 'e774ebd' + 'add-pdf-file' => 'e774ebd', + 'add-pdf-text-binary' => '79faa7b' }.freeze # gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily -- cgit v1.2.1 From 6ac0a142e00e5bf0945ea624c93bbfe54c91a14e Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Wed, 26 Jul 2017 17:16:59 +0200 Subject: Remove unnecessary begin/end --- lib/gitlab/health_checks/fs_shards_check.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/gitlab/health_checks/fs_shards_check.rb b/lib/gitlab/health_checks/fs_shards_check.rb index 928fb014ef4..a4740e9e9b7 100644 --- a/lib/gitlab/health_checks/fs_shards_check.rb +++ b/lib/gitlab/health_checks/fs_shards_check.rb @@ -67,12 +67,10 @@ module Gitlab end def with_temp_file(storage_name) - begin - temp_file_path = Dir::Tmpname.create(%w(fs_shards_check +deleted), storage_path(storage_name)) { |path| path } - yield temp_file_path - ensure - delete_test_file(temp_file_path) - end + temp_file_path = Dir::Tmpname.create(%w(fs_shards_check +deleted), storage_path(storage_name)) { |path| path } + yield temp_file_path + ensure + delete_test_file(temp_file_path) end def storage_path(storage_name) -- cgit v1.2.1 From 02139f5a775fafb3999976cdd213d7ef14e720d7 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 26 Jul 2017 12:40:59 -0400 Subject: Update the large table list in AddColumnWithDefaultToLargeTable cop - ci_builds -- 33 million rows, 55 GB - merge_request_diff_files -- 5 million rows, 9 GB (and growing rapidly) - merge_request_diffs -- 5 million rows, 190 GB --- rubocop/cop/migration/add_column_with_default_to_large_table.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rubocop/cop/migration/add_column_with_default_to_large_table.rb b/rubocop/cop/migration/add_column_with_default_to_large_table.rb index 2372e6b60ea..87788b0d9c2 100644 --- a/rubocop/cop/migration/add_column_with_default_to_large_table.rb +++ b/rubocop/cop/migration/add_column_with_default_to_large_table.rb @@ -20,8 +20,11 @@ module RuboCop 'necessary'.freeze LARGE_TABLES = %i[ + ci_builds events issues + merge_request_diff_files + merge_request_diffs merge_requests namespaces notes -- cgit v1.2.1 From a5d2ce8e61fc4f606148ec0323154421111c5012 Mon Sep 17 00:00:00 2001 From: Casper Date: Wed, 26 Jul 2017 16:48:13 +0000 Subject: Use LDAP-attributes configured in gitlab.yml in lookup instead of just hard-coded attributes. --- lib/gitlab/ldap/adapter.rb | 2 +- spec/lib/gitlab/ldap/adapter_spec.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/gitlab/ldap/adapter.rb b/lib/gitlab/ldap/adapter.rb index 7b05290e5cc..8867a91c244 100644 --- a/lib/gitlab/ldap/adapter.rb +++ b/lib/gitlab/ldap/adapter.rb @@ -101,7 +101,7 @@ module Gitlab end def user_attributes - %W(#{config.uid} cn mail dn) + %W(#{config.uid} cn dn) + config.attributes['username'] + config.attributes['email'] end end end diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb index 9454878b057..0f4b8dbf7b7 100644 --- a/spec/lib/gitlab/ldap/adapter_spec.rb +++ b/spec/lib/gitlab/ldap/adapter_spec.rb @@ -16,7 +16,7 @@ describe Gitlab::LDAP::Adapter, lib: true do expect(adapter).to receive(:ldap_search) do |arg| expect(arg[:filter].to_s).to eq('(uid=johndoe)') expect(arg[:base]).to eq('dc=example,dc=com') - expect(arg[:attributes]).to match(%w{uid cn mail dn}) + expect(arg[:attributes]).to match(%w{uid cn dn uid userid sAMAccountName mail email userPrincipalName}) end.and_return({}) adapter.users('uid', 'johndoe') @@ -26,7 +26,7 @@ describe Gitlab::LDAP::Adapter, lib: true do expect(adapter).to receive(:ldap_search).with( base: 'uid=johndoe,ou=users,dc=example,dc=com', scope: Net::LDAP::SearchScope_BaseObject, - attributes: %w{uid cn mail dn}, + attributes: %w{uid cn dn uid userid sAMAccountName mail email userPrincipalName}, filter: nil ).and_return({}) @@ -63,7 +63,7 @@ describe Gitlab::LDAP::Adapter, lib: true do it 'uses the right uid attribute when non-default' do stub_ldap_config(uid: 'sAMAccountName') expect(adapter).to receive(:ldap_search).with( - hash_including(attributes: %w{sAMAccountName cn mail dn}) + hash_including(attributes: %w{sAMAccountName cn dn uid userid sAMAccountName mail email userPrincipalName}) ).and_return({}) adapter.users('sAMAccountName', 'johndoe') -- cgit v1.2.1 From 03c11c3a333e46894030a724392bd714e9a0abdf Mon Sep 17 00:00:00 2001 From: Ben Bodenmiller Date: Wed, 26 Jul 2017 18:43:43 +0000 Subject: remove extra space --- doc/administration/container_registry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/administration/container_registry.md b/doc/administration/container_registry.md index 8cb0e5b1562..57e54815b68 100644 --- a/doc/administration/container_registry.md +++ b/doc/administration/container_registry.md @@ -112,7 +112,7 @@ GitLab from source respectively. >**Note:** Be careful to choose a port different than the one that Registry listens to (`5000` by default), -otherwise you will run into conflicts . +otherwise you will run into conflicts. --- -- cgit v1.2.1 From db2ea59f52555be8e10a60cc51aae832f5824d9d Mon Sep 17 00:00:00 2001 From: Ben Bodenmiller Date: Wed, 26 Jul 2017 18:56:43 +0000 Subject: change Fogbugz button to FogBugz --- app/views/projects/new.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index a2d7a21d5f6..87cc23fc649 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -72,7 +72,7 @@ %div - if fogbugz_import_enabled? = link_to new_import_fogbugz_path, class: 'btn import_fogbugz' do - = icon('bug', text: 'Fogbugz') + = icon('bug', text: 'FogBugz') %div - if gitea_import_enabled? = link_to new_import_gitea_url, class: 'btn import_gitea' do -- cgit v1.2.1 From 8961b7ec602d583c00b2df4c310092a2472a0ee2 Mon Sep 17 00:00:00 2001 From: winh Date: Wed, 26 Jul 2017 13:45:09 +0200 Subject: Make header dropdown styles consistent --- app/assets/stylesheets/framework/header.scss | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index 605f4284bb5..33d016652e5 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -313,6 +313,25 @@ header { .impersonation i { color: $red-500; } + + // TODO: fallback to global style + .dropdown-menu, + .dropdown-menu-nav { + li { + padding: 0 1px; + + a { + border-radius: 0; + padding: 8px 16px; + + &:hover, + &:active, + &:focus { + background-color: $gray-darker; + } + } + } + } } .navbar-nav { -- cgit v1.2.1 From 830257c920362e8c2c42a8c5014f6b7083b72542 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Wed, 26 Jul 2017 16:43:41 -0500 Subject: Fix participant name link trailing space on milestone page --- app/views/shared/milestones/_participants_tab.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/shared/milestones/_participants_tab.html.haml b/app/views/shared/milestones/_participants_tab.html.haml index 549d2e2f61e..1615871385e 100644 --- a/app/views/shared/milestones/_participants_tab.html.haml +++ b/app/views/shared/milestones/_participants_tab.html.haml @@ -4,5 +4,5 @@ = link_to user, title: user.name, class: "darken" do = image_tag avatar_icon(user, 32), class: "avatar s32" %strong= truncate(user.name, length: 40) - %br - %small.cgray= user.username + %div + %small.cgray= user.username -- cgit v1.2.1 From aa2b3ff1e4c8bb725a96ed55906d142300ccf017 Mon Sep 17 00:00:00 2001 From: Jarka Kadlecova Date: Wed, 26 Jul 2017 09:57:56 +0200 Subject: Display specific error message when JIRA test fails --- .../integrations/integration_settings_form.js | 2 +- app/models/project_services/jira_service.rb | 8 ++++-- changelogs/unreleased/32483-jira-error.yml | 4 +++ .../projects/services/jira_service_spec.rb | 2 +- .../integrations/integration_settings_form_spec.js | 4 +-- spec/models/project_services/jira_service_spec.rb | 31 +++++++++++++++++----- 6 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 changelogs/unreleased/32483-jira-error.yml diff --git a/app/assets/javascripts/integrations/integration_settings_form.js b/app/assets/javascripts/integrations/integration_settings_form.js index ddd3a6aab99..cf1e6a14725 100644 --- a/app/assets/javascripts/integrations/integration_settings_form.js +++ b/app/assets/javascripts/integrations/integration_settings_form.js @@ -102,7 +102,7 @@ export default class IntegrationSettingsForm { }) .done((res) => { if (res.error) { - new Flash(res.message, null, null, { + new Flash(`${res.message} ${res.service_response}`, null, null, { title: 'Save anyway', clickHandler: (e) => { e.preventDefault(); diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 37f2c96a22f..2aa19443198 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -160,7 +160,10 @@ class JiraService < IssueTrackerService def test(_) result = test_settings - { success: result.present?, result: result } + success = result.present? + result = @error if @error && !success + + { success: success, result: result } end # JIRA does not need test data. @@ -288,7 +291,8 @@ class JiraService < IssueTrackerService yield rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, Errno::ECONNREFUSED, URI::InvalidURIError, JIRA::HTTPError, OpenSSL::SSL::SSLError => e - Rails.logger.info "#{self.class.name} Send message ERROR: #{client_url} - #{e.message}" + @error = e.message + Rails.logger.info "#{self.class.name} Send message ERROR: #{client_url} - #{@error}" nil end diff --git a/changelogs/unreleased/32483-jira-error.yml b/changelogs/unreleased/32483-jira-error.yml new file mode 100644 index 00000000000..1c530ca5e0f --- /dev/null +++ b/changelogs/unreleased/32483-jira-error.yml @@ -0,0 +1,4 @@ +--- +title: Display specific error message when JIRA test fails +merge_request: +author: diff --git a/spec/features/projects/services/jira_service_spec.rb b/spec/features/projects/services/jira_service_spec.rb index b71eec0ecfd..28870261596 100644 --- a/spec/features/projects/services/jira_service_spec.rb +++ b/spec/features/projects/services/jira_service_spec.rb @@ -62,7 +62,7 @@ feature 'Setup Jira service', :feature, :js do click_button('Test settings and save changes') wait_for_requests - expect(find('.flash-container-page')).to have_content 'Test failed.' + expect(find('.flash-container-page')).to have_content 'Test failed. message' expect(find('.flash-container-page')).to have_content 'Save anyway' find('.flash-alert .flash-action').trigger('click') diff --git a/spec/javascripts/integrations/integration_settings_form_spec.js b/spec/javascripts/integrations/integration_settings_form_spec.js index 45909d4e70e..3daeb91b1e2 100644 --- a/spec/javascripts/integrations/integration_settings_form_spec.js +++ b/spec/javascripts/integrations/integration_settings_form_spec.js @@ -135,10 +135,10 @@ describe('IntegrationSettingsForm', () => { integrationSettingsForm.testSettings(formData); - deferred.resolve({ error: true, message: errorMessage }); + deferred.resolve({ error: true, message: errorMessage, service_response: 'some error' }); const $flashContainer = $('.flash-container'); - expect($flashContainer.find('.flash-text').text()).toEqual(errorMessage); + expect($flashContainer.find('.flash-text').text()).toEqual('Test failed. some error'); expect($flashContainer.find('.flash-action')).toBeDefined(); expect($flashContainer.find('.flash-action').text()).toEqual('Save anyway'); }); diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index d7d09808a98..ded8e709c38 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -197,21 +197,38 @@ describe JiraService, models: true do ) end - def test_settings(api_url) + def test_settings(api_url = nil) + api_url ||= 'jira.example.com' test_url = "http://#{api_url}/rest/api/2/serverInfo" WebMock.stub_request(:get, test_url).with(basic_auth: %w(jira_username jira_password)).to_return(body: { url: 'http://url' }.to_json ) - jira_service.test_settings + jira_service.test(nil) end - it 'tries to get JIRA project with URL when API URL not set' do - test_settings('jira.example.com') + context 'when the test succeeds' do + it 'tries to get JIRA project with URL when API URL not set' do + test_settings('jira.example.com') + end + + it 'returns correct result' do + expect(test_settings).to eq( { success: true, result: { 'url' => 'http://url' } }) + end + + it 'tries to get JIRA project with API URL if set' do + jira_service.update(api_url: 'http://jira.api.com') + test_settings('jira.api.com') + end end - it 'tries to get JIRA project with API URL if set' do - jira_service.update(api_url: 'http://jira.api.com') - test_settings('jira.api.com') + context 'when the test fails' do + it 'returns result with the error' do + test_url = 'http://jira.example.com/rest/api/2/serverInfo' + WebMock.stub_request(:get, test_url).with(basic_auth: %w(jira_username jira_password)) + .to_raise(JIRA::HTTPError.new(double(message: 'Some specific failure.'))) + + expect(jira_service.test(nil)).to eq( { success: false, result: 'Some specific failure.' }) + end end end -- cgit v1.2.1 From 69129f11df7aa738bfed7a84eead6fdf5d25a814 Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Mon, 17 Jul 2017 20:41:50 +0900 Subject: Remove help message about prioritized labels for non-members --- app/views/projects/labels/index.html.haml | 13 ++++++++----- .../unreleased/35191-prioritized-labels-for-non-member.yml | 4 ++++ spec/features/projects/labels/update_prioritization_spec.rb | 8 ++++++++ 3 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 changelogs/unreleased/35191-prioritized-labels-for-non-member.yml diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml index d02ea5cccc3..4b9da02c6b8 100644 --- a/app/views/projects/labels/index.html.haml +++ b/app/views/projects/labels/index.html.haml @@ -1,6 +1,7 @@ - @no_container = true - page_title "Labels" - hide_class = '' +- can_admin_label = can?(current_user, :admin_label, @project) - if show_new_nav? && can?(current_user, :admin_label, @project) - content_for :breadcrumbs_extra do @@ -12,15 +13,17 @@ %div{ class: container_class } .top-area.adjust .nav-text - Labels can be applied to issues and merge requests. Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging. + Labels can be applied to issues and merge requests. + - if can_admin_label + Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging. - .nav-controls{ class: ("visible-xs" if show_new_nav?) } - - if can?(current_user, :admin_label, @project) + - if can_admin_label + .nav-controls{ class: ("visible-xs" if show_new_nav?) } = link_to new_project_label_path(@project), class: "btn btn-new" do New label .labels - - if can?(current_user, :admin_label, @project) + - if can_admin_label -# Only show it in the first page - hide = @available_labels.empty? || (params[:page].present? && params[:page] != '1') .prioritized-labels{ class: ('hide' if hide) } @@ -33,7 +36,7 @@ - if @labels.present? .other-labels - - if can?(current_user, :admin_label, @project) + - if can_admin_label %h5{ class: ('hide' if hide) } Other Labels %ul.content-list.manage-labels-list.js-other-labels = render partial: 'shared/label', subject: @project, collection: @labels, as: :label diff --git a/changelogs/unreleased/35191-prioritized-labels-for-non-member.yml b/changelogs/unreleased/35191-prioritized-labels-for-non-member.yml new file mode 100644 index 00000000000..fbe55d4c2b0 --- /dev/null +++ b/changelogs/unreleased/35191-prioritized-labels-for-non-member.yml @@ -0,0 +1,4 @@ +--- +title: Remove help message about prioritized labels for non-members +merge_request: 12912 +author: Takuya Noguchi diff --git a/spec/features/projects/labels/update_prioritization_spec.rb b/spec/features/projects/labels/update_prioritization_spec.rb index 61f6d734ed3..9b51b427845 100644 --- a/spec/features/projects/labels/update_prioritization_spec.rb +++ b/spec/features/projects/labels/update_prioritization_spec.rb @@ -114,6 +114,12 @@ feature 'Prioritize labels', feature: true do expect(page.all('li').last).to have_content('bug') end end + + it 'shows a help message about prioritized labels' do + visit project_labels_path(project) + + expect(page).to have_content 'Star a label' + end end context 'as a guest' do @@ -128,6 +134,7 @@ feature 'Prioritize labels', feature: true do expect(page).to have_content 'wontfix' expect(page).to have_content 'feature' expect(page).not_to have_css('.prioritized-labels') + expect(page).not_to have_content 'Star a label' end end @@ -139,6 +146,7 @@ feature 'Prioritize labels', feature: true do expect(page).to have_content 'wontfix' expect(page).to have_content 'feature' expect(page).not_to have_css('.prioritized-labels') + expect(page).not_to have_content 'Star a label' end end end -- cgit v1.2.1 From 3256f6f4045661edf6816dbd0914fbedbffd2649 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 27 Jul 2017 08:41:47 +0100 Subject: Compile JS lang files before webpack compile Closes #35615 --- lib/tasks/gitlab/assets.rake | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/tasks/gitlab/assets.rake b/lib/tasks/gitlab/assets.rake index 003d57adbbd..259a755d724 100644 --- a/lib/tasks/gitlab/assets.rake +++ b/lib/tasks/gitlab/assets.rake @@ -4,6 +4,7 @@ namespace :gitlab do task compile: [ 'yarn:check', 'rake:assets:precompile', + 'gettext:po_to_json', 'webpack:compile', 'fix_urls' ] -- cgit v1.2.1 From 05e152fa7f39c3ae9492159a6c29532a27b4b40a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 27 Jul 2017 09:58:06 +0200 Subject: Fix the :project factory by not copying the test repo twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also, fixing some calls to the :project factory with the :test_repo trait since this trait is already included in the :project factory. Signed-off-by: Rémy Coutable --- spec/factories/projects.rb | 4 ---- spec/features/projects/blobs/edit_spec.rb | 2 +- spec/lib/gitlab/import_export/fork_spec.rb | 2 +- spec/lib/gitlab/import_export/merge_request_parser_spec.rb | 2 +- spec/lib/gitlab/import_export/repo_restorer_spec.rb | 2 +- spec/requests/api/todos_spec.rb | 2 +- 6 files changed, 5 insertions(+), 9 deletions(-) diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index 1bb2db11e7f..485ed48d2de 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -171,10 +171,6 @@ FactoryGirl.define do end after :create do |project, evaluator| - TestEnv.copy_repo(project, - bare_repo: TestEnv.factory_repo_path_bare, - refs: TestEnv::BRANCH_SHA) - if evaluator.create_template args = evaluator.create_template diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb index c9384a09ccd..ddd27083147 100644 --- a/spec/features/projects/blobs/edit_spec.rb +++ b/spec/features/projects/blobs/edit_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Editing file blob', feature: true, js: true do include TreeHelper - let(:project) { create(:project, :public, :test_repo) } + let(:project) { create(:project, :public) } let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'master') } let(:branch) { 'master' } let(:file_path) { project.repository.ls_files(project.repository.root_ref)[1] } diff --git a/spec/lib/gitlab/import_export/fork_spec.rb b/spec/lib/gitlab/import_export/fork_spec.rb index 70796781532..e8eb7e4f8f4 100644 --- a/spec/lib/gitlab/import_export/fork_spec.rb +++ b/spec/lib/gitlab/import_export/fork_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'forked project import', services: true do let(:user) { create(:user) } - let!(:project_with_repo) { create(:project, :test_repo, name: 'test-repo-restorer', path: 'test-repo-restorer') } + let!(:project_with_repo) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') } let!(:project) { create(:empty_project, name: 'test-repo-restorer-no-repo', path: 'test-repo-restorer-no-repo') } let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) } diff --git a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb index 349be4596b6..f2b66c4421c 100644 --- a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb +++ b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::ImportExport::MergeRequestParser do let(:user) { create(:user) } - let!(:project) { create(:project, :test_repo, name: 'test-repo-restorer', path: 'test-repo-restorer') } + let!(:project) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') } let(:forked_from_project) { create(:project) } let(:fork_link) { create(:forked_project_link, forked_from_project: project) } diff --git a/spec/lib/gitlab/import_export/repo_restorer_spec.rb b/spec/lib/gitlab/import_export/repo_restorer_spec.rb index 30b6a0d8845..09bfaa8fb75 100644 --- a/spec/lib/gitlab/import_export/repo_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/repo_restorer_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::ImportExport::RepoRestorer, services: true do describe 'bundle a project Git repo' do let(:user) { create(:user) } - let!(:project_with_repo) { create(:project, :test_repo, name: 'test-repo-restorer', path: 'test-repo-restorer') } + let!(:project_with_repo) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') } let!(:project) { create(:empty_project) } let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) } diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb index 92533f4dfea..9fc73c6e092 100644 --- a/spec/requests/api/todos_spec.rb +++ b/spec/requests/api/todos_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe API::Todos do - let(:project_1) { create(:empty_project, :test_repo) } + let(:project_1) { create(:project) } let(:project_2) { create(:empty_project) } let(:author_1) { create(:user) } let(:author_2) { create(:user) } -- cgit v1.2.1 From c58023858182b300fbbb1a6ad192f8ea975bfe98 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Thu, 27 Jul 2017 08:30:14 +0000 Subject: Inline JS Removal for Merge Requests --- app/assets/javascripts/dispatcher.js | 19 +++++++++++++++++++ app/assets/javascripts/how_to_merge.js | 4 ++-- .../merge_requests/creations/_new_compare.html.haml | 9 +-------- .../merge_requests/creations/_new_submit.html.haml | 7 +------ app/views/projects/merge_requests/show.html.haml | 15 ++++----------- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index ffe97c071ba..1dc6edacfed 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -20,6 +20,8 @@ /* global NamespaceSelects */ /* global Project */ /* global ProjectAvatar */ +/* global MergeRequest */ +/* global Compare */ /* global CompareAutocomplete */ /* global ProjectNew */ /* global ProjectShow */ @@ -221,6 +223,19 @@ import PerformanceBar from './performance_bar'; new gl.IssuableTemplateSelectors(); break; case 'projects:merge_requests:creations:new': + const mrNewCompareNode = document.querySelector('.js-merge-request-new-compare'); + if (mrNewCompareNode) { + new Compare({ + targetProjectUrl: mrNewCompareNode.dataset.targetProjectUrl, + sourceBranchUrl: mrNewCompareNode.dataset.sourceBranchUrl, + targetBranchUrl: mrNewCompareNode.dataset.targetBranchUrl, + }); + } else { + const mrNewSubmitNode = document.querySelector('.js-merge-request-new-submit'); + new MergeRequest({ + action: mrNewSubmitNode.dataset.mrSubmitAction, + }); + } case 'projects:merge_requests:creations:diffs': case 'projects:merge_requests:edit': new gl.Diff(); @@ -257,6 +272,10 @@ import PerformanceBar from './performance_bar'; new gl.Diff(); shortcut_handler = new ShortcutsIssuable(true); new ZenMode(); + const mrShowNode = document.querySelector('.merge-request'); + window.mergeRequest = new MergeRequest({ + action: mrShowNode.dataset.mrAction, + }); break; case 'dashboard:activity': new gl.Activities(); diff --git a/app/assets/javascripts/how_to_merge.js b/app/assets/javascripts/how_to_merge.js index f739db751a6..19f4a946f73 100644 --- a/app/assets/javascripts/how_to_merge.js +++ b/app/assets/javascripts/how_to_merge.js @@ -3,10 +3,10 @@ document.addEventListener('DOMContentLoaded', () => { modal: true, show: false, }); - $('.how_to_merge_link').bind('click', () => { + $('.how_to_merge_link').on('click', () => { modal.show(); }); - $('.modal-header .close').bind('click', () => { + $('.modal-header .close').on('click', () => { modal.hide(); }); }); diff --git a/app/views/projects/merge_requests/creations/_new_compare.html.haml b/app/views/projects/merge_requests/creations/_new_compare.html.haml index 4e5aae496b1..8958b2cf5e1 100644 --- a/app/views/projects/merge_requests/creations/_new_compare.html.haml +++ b/app/views/projects/merge_requests/creations/_new_compare.html.haml @@ -3,7 +3,7 @@ = form_for [@project.namespace.becomes(Namespace), @project, @merge_request], url: project_new_merge_request_path(@project), method: :get, html: { class: "merge-request-form form-inline js-requires-input" } do |f| .hide.alert.alert-danger.mr-compare-errors - .merge-request-branches.row + .merge-request-branches.js-merge-request-new-compare.row{ 'data-target-project-url': project_new_merge_request_update_branches_path(@source_project), 'data-source-branch-url': project_new_merge_request_branch_from_path(@source_project), 'data-target-branch-url': project_new_merge_request_branch_to_path(@source_project) } .col-md-6 .panel.panel-default.panel-new-merge-request .panel-heading @@ -66,10 +66,3 @@ - if @merge_request.errors.any? = form_errors(@merge_request) = f.submit 'Compare branches and continue', class: "btn btn-new mr-compare-btn" - -:javascript - new Compare({ - targetProjectUrl: "#{project_new_merge_request_update_branches_path(@source_project)}", - sourceBranchUrl: "#{project_new_merge_request_branch_from_path(@source_project)}", - targetBranchUrl: "#{project_new_merge_request_branch_to_path(@source_project)}" - }); diff --git a/app/views/projects/merge_requests/creations/_new_submit.html.haml b/app/views/projects/merge_requests/creations/_new_submit.html.haml index c72dd1d8e29..4b5fa28078a 100644 --- a/app/views/projects/merge_requests/creations/_new_submit.html.haml +++ b/app/views/projects/merge_requests/creations/_new_submit.html.haml @@ -17,7 +17,7 @@ = f.hidden_field :target_project_id = f.hidden_field :target_branch -.mr-compare.merge-request +.mr-compare.merge-request.js-merge-request-new-submit{ 'data-mr-submit-action': "#{j params[:tab].presence || 'new'}" } - if @commits.empty? .commits-empty %h4 @@ -50,8 +50,3 @@ .mr-loading-status = spinner - -:javascript - var merge_request = new MergeRequest({ - action: "#{j params[:tab].presence || 'new'}", - }); diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml index 2efc1d68190..ea6cd16c7ad 100644 --- a/app/views/projects/merge_requests/show.html.haml +++ b/app/views/projects/merge_requests/show.html.haml @@ -3,10 +3,10 @@ - page_description @merge_request.description - page_card_attributes @merge_request.card_attributes - content_for :page_specific_javascripts do - = page_specific_javascript_bundle_tag('common_vue') - = page_specific_javascript_bundle_tag('diff_notes') + = webpack_bundle_tag('common_vue') + = webpack_bundle_tag('diff_notes') -.merge-request{ 'data-url' => merge_request_path(@merge_request, format: :json), 'data-project-path' => project_path(@merge_request.project) } +.merge-request{ 'data-mr-action': "#{j params[:tab].presence || 'show'}", 'data-url' => merge_request_path(@merge_request, format: :json), 'data-project-path' => project_path(@merge_request.project) } = render "projects/merge_requests/mr_title" .merge-request-details.issuable-details{ data: { id: @merge_request.project.id } } @@ -15,13 +15,13 @@ - if @merge_request.source_branch_exists? = render "projects/merge_requests/how_to_merge" + -# haml-lint:disable InlineJavaScript :javascript window.gl.mrWidgetData = #{serialize_issuable(@merge_request)} #js-vue-mr-widget.mr-widget - content_for :page_specific_javascripts do - = webpack_bundle_tag 'common_vue' = webpack_bundle_tag 'vue_merge_request_widget' .content-block.content-block-small.emoji-list-container @@ -88,10 +88,3 @@ = render "projects/commit/change", type: 'revert', commit: @merge_request.merge_commit, title: @merge_request.title - if @merge_request.can_be_cherry_picked? = render "projects/commit/change", type: 'cherry-pick', commit: @merge_request.merge_commit, title: @merge_request.title - -:javascript - $(function () { - window.mergeRequest = new MergeRequest({ - action: "#{j params[:tab].presence || 'show'}", - }); - }); -- cgit v1.2.1 From bfe8b96874c66c54e2e4c1a66a520087b217e9e7 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 26 Jul 2017 12:34:52 +0200 Subject: Add specs --- spec/features/oauth_login_spec.rb | 2 +- spec/lib/gitlab/request_forgery_protection_spec.rb | 89 ++++++++++++++++++++++ spec/requests/api/helpers_spec.rb | 50 ++++++++++-- spec/support/forgery_protection.rb | 11 +++ 4 files changed, 145 insertions(+), 7 deletions(-) create mode 100644 spec/lib/gitlab/request_forgery_protection_spec.rb create mode 100644 spec/support/forgery_protection.rb diff --git a/spec/features/oauth_login_spec.rb b/spec/features/oauth_login_spec.rb index 0064c9ef25e..49d8e52f861 100644 --- a/spec/features/oauth_login_spec.rb +++ b/spec/features/oauth_login_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'OAuth Login', js: true do +feature 'OAuth Login', :js, :allow_forgery_protection do include DeviseHelpers def enter_code(code) diff --git a/spec/lib/gitlab/request_forgery_protection_spec.rb b/spec/lib/gitlab/request_forgery_protection_spec.rb new file mode 100644 index 00000000000..305de613866 --- /dev/null +++ b/spec/lib/gitlab/request_forgery_protection_spec.rb @@ -0,0 +1,89 @@ +require 'spec_helper' + +describe Gitlab::RequestForgeryProtection, :allow_forgery_protection do + let(:csrf_token) { SecureRandom.base64(ActionController::RequestForgeryProtection::AUTHENTICITY_TOKEN_LENGTH) } + let(:env) do + { + 'rack.input' => '', + 'rack.session' => { + _csrf_token: csrf_token + } + } + end + + describe '.call' do + context 'when the request method is GET' do + before do + env['REQUEST_METHOD'] = 'GET' + end + + it 'does not raise an exception' do + expect { described_class.call(env) }.not_to raise_exception + end + end + + context 'when the request method is POST' do + before do + env['REQUEST_METHOD'] = 'POST' + end + + context 'when the CSRF token is valid' do + before do + env['HTTP_X_CSRF_TOKEN'] = csrf_token + end + + it 'does not raise an exception' do + expect { described_class.call(env) }.not_to raise_exception + end + end + + context 'when the CSRF token is invalid' do + before do + env['HTTP_X_CSRF_TOKEN'] = 'foo' + end + + it 'raises an ActionController::InvalidAuthenticityToken exception' do + expect { described_class.call(env) }.to raise_exception(ActionController::InvalidAuthenticityToken) + end + end + end + end + + describe '.verified?' do + context 'when the request method is GET' do + before do + env['REQUEST_METHOD'] = 'GET' + end + + it 'returns true' do + expect(described_class.verified?(env)).to be_truthy + end + end + + context 'when the request method is POST' do + before do + env['REQUEST_METHOD'] = 'POST' + end + + context 'when the CSRF token is valid' do + before do + env['HTTP_X_CSRF_TOKEN'] = csrf_token + end + + it 'returns true' do + expect(described_class.verified?(env)).to be_truthy + end + end + + context 'when the CSRF token is invalid' do + before do + env['HTTP_X_CSRF_TOKEN'] = 'foo' + end + + it 'returns false' do + expect(described_class.verified?(env)).to be_falsey + end + end + end + end +end diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb index 25ec44fa036..7a1bd76af7a 100644 --- a/spec/requests/api/helpers_spec.rb +++ b/spec/requests/api/helpers_spec.rb @@ -10,8 +10,16 @@ describe API::Helpers do let(:key) { create(:key, user: user) } let(:params) { {} } - let(:env) { { 'REQUEST_METHOD' => 'GET' } } - let(:request) { Rack::Request.new(env) } + let(:csrf_token) { SecureRandom.base64(ActionController::RequestForgeryProtection::AUTHENTICITY_TOKEN_LENGTH) } + let(:env) do + { + 'rack.input' => '', + 'rack.session' => { + _csrf_token: csrf_token + }, + 'REQUEST_METHOD' => 'GET' + } + end let(:header) { } before do @@ -58,7 +66,7 @@ describe API::Helpers do describe ".current_user" do subject { current_user } - describe "Warden authentication" do + describe "Warden authentication", :allow_forgery_protection do before do doorkeeper_guard_returns false end @@ -99,7 +107,17 @@ describe API::Helpers do env['REQUEST_METHOD'] = 'PUT' end - it { is_expected.to be_nil } + context 'without CSRF token' do + it { is_expected.to be_nil } + end + + context 'with CSRF token' do + before do + env['HTTP_X_CSRF_TOKEN'] = csrf_token + end + + it { is_expected.to eq(user) } + end end context "POST request" do @@ -107,7 +125,17 @@ describe API::Helpers do env['REQUEST_METHOD'] = 'POST' end - it { is_expected.to be_nil } + context 'without CSRF token' do + it { is_expected.to be_nil } + end + + context 'with CSRF token' do + before do + env['HTTP_X_CSRF_TOKEN'] = csrf_token + end + + it { is_expected.to eq(user) } + end end context "DELETE request" do @@ -115,7 +143,17 @@ describe API::Helpers do env['REQUEST_METHOD'] = 'DELETE' end - it { is_expected.to be_nil } + context 'without CSRF token' do + it { is_expected.to be_nil } + end + + context 'with CSRF token' do + before do + env['HTTP_X_CSRF_TOKEN'] = csrf_token + end + + it { is_expected.to eq(user) } + end end end end diff --git a/spec/support/forgery_protection.rb b/spec/support/forgery_protection.rb new file mode 100644 index 00000000000..a5e7b761651 --- /dev/null +++ b/spec/support/forgery_protection.rb @@ -0,0 +1,11 @@ +RSpec.configure do |config| + config.around(:each, :allow_forgery_protection) do |example| + begin + ActionController::Base.allow_forgery_protection = true + + example.call + ensure + ActionController::Base.allow_forgery_protection = false + end + end +end -- cgit v1.2.1 From cbfdc7e3b53c5443a82c78bc69c77ad000648973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 27 Jul 2017 10:46:59 +0200 Subject: Ensure the overriding of Gitlab::Application.routes.default_url_options is only local MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/features/dashboard/issues_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb index 2a5ef08da60..ea7a9efc326 100644 --- a/spec/features/dashboard/issues_spec.rb +++ b/spec/features/dashboard/issues_spec.rb @@ -80,6 +80,8 @@ RSpec.describe 'Dashboard Issues', feature: true do end it 'shows the new issue page', js: true do + original_defaults = Gitlab::Application.routes.default_url_options + Gitlab::Application.routes.default_url_options = { host: Capybara.current_session.server.host, port: Capybara.current_session.server.port, @@ -95,6 +97,8 @@ RSpec.describe 'Dashboard Issues', feature: true do page.within('#content-body') do expect(page).to have_selector('.issue-form') end + + Gitlab::Application.routes.default_url_options = original_defaults end end end -- cgit v1.2.1 From ea1012ccb4da9c8e0dae1a9cb710b39c97baa8a1 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Thu, 13 Jul 2017 18:03:52 +0200 Subject: Make the attribute list for application settings reusable --- .../admin/application_settings_controller.rb | 81 +-------------------- app/helpers/application_settings_helper.rb | 85 ++++++++++++++++++++++ .../unreleased/bvl-add-all-settings-to-api.yml | 4 + lib/api/entities.rb | 33 +-------- lib/api/settings.rb | 3 +- 5 files changed, 96 insertions(+), 110 deletions(-) create mode 100644 changelogs/unreleased/bvl-add-all-settings-to-api.yml diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 4c0f7556894..8367c22d1ca 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -76,88 +76,13 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController params.delete(:domain_blacklist_raw) if params[:domain_blacklist_file] params.require(:application_setting).permit( - application_setting_params_attributes + visible_application_setting_attributes ) end - def application_setting_params_attributes - [ - :admin_notification_email, - :after_sign_out_path, - :after_sign_up_text, - :akismet_api_key, - :akismet_enabled, - :container_registry_token_expire_delay, - :default_artifacts_expire_in, - :default_branch_protection, - :default_group_visibility, - :default_project_visibility, - :default_projects_limit, - :default_snippet_visibility, - :domain_blacklist_enabled, + def visible_application_setting_attributes + ApplicationSettingsHelper.visible_attributes + [ :domain_blacklist_file, - :domain_blacklist_raw, - :domain_whitelist_raw, - :email_author_in_body, - :enabled_git_access_protocol, - :gravatar_enabled, - :help_page_text, - :help_page_hide_commercial_content, - :help_page_support_url, - :home_page_url, - :housekeeping_bitmaps_enabled, - :housekeeping_enabled, - :housekeeping_full_repack_period, - :housekeeping_gc_period, - :housekeeping_incremental_repack_period, - :html_emails_enabled, - :koding_enabled, - :koding_url, - :password_authentication_enabled, - :plantuml_enabled, - :plantuml_url, - :max_artifacts_size, - :max_attachment_size, - :max_pages_size, - :metrics_enabled, - :metrics_host, - :metrics_method_call_threshold, - :metrics_packet_size, - :metrics_pool_size, - :metrics_port, - :metrics_sample_interval, - :metrics_timeout, - :performance_bar_allowed_group_id, - :performance_bar_enabled, - :recaptcha_enabled, - :recaptcha_private_key, - :recaptcha_site_key, - :repository_checks_enabled, - :require_two_factor_authentication, - :session_expire_delay, - :sign_in_text, - :signup_enabled, - :sentry_dsn, - :sentry_enabled, - :clientside_sentry_dsn, - :clientside_sentry_enabled, - :send_user_confirmation_email, - :shared_runners_enabled, - :shared_runners_text, - :sidekiq_throttling_enabled, - :sidekiq_throttling_factor, - :two_factor_grace_period, - :user_default_external, - :user_oauth_applications, - :unique_ips_limit_per_user, - :unique_ips_limit_time_window, - :unique_ips_limit_enabled, - :version_check_enabled, - :terminal_max_session_time, - :polling_interval_multiplier, - :prometheus_metrics_enabled, - :usage_ping_enabled, - disabled_oauth_sign_in_sources: [], import_sources: [], repository_storages: [], diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 29b88c60dab..6825adcb39f 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -1,4 +1,5 @@ module ApplicationSettingsHelper + extend self delegate :gravatar_enabled?, :signup_enabled?, :password_authentication_enabled?, @@ -91,4 +92,88 @@ module ApplicationSettingsHelper def sidekiq_queue_options_for_select options_for_select(Sidekiq::Queue.all.map(&:name), @application_setting.sidekiq_throttling_queues) end + + def visible_attributes + [ + :admin_notification_email, + :after_sign_out_path, + :after_sign_up_text, + :akismet_api_key, + :akismet_enabled, + :clientside_sentry_dsn, + :clientside_sentry_enabled, + :container_registry_token_expire_delay, + :default_artifacts_expire_in, + :default_branch_protection, + :default_group_visibility, + :default_project_visibility, + :default_projects_limit, + :default_snippet_visibility, + :disabled_oauth_sign_in_sources, + :domain_blacklist_enabled, + :domain_blacklist_raw, + :domain_whitelist_raw, + :email_author_in_body, + :enabled_git_access_protocol, + :gravatar_enabled, + :help_page_hide_commercial_content, + :help_page_support_url, + :help_page_text, + :home_page_url, + :housekeeping_bitmaps_enabled, + :housekeeping_enabled, + :housekeeping_full_repack_period, + :housekeeping_gc_period, + :housekeeping_incremental_repack_period, + :html_emails_enabled, + :import_sources, + :koding_enabled, + :koding_url, + :max_artifacts_size, + :max_attachment_size, + :max_pages_size, + :metrics_enabled, + :metrics_host, + :metrics_method_call_threshold, + :metrics_packet_size, + :metrics_pool_size, + :metrics_port, + :metrics_sample_interval, + :metrics_timeout, + :password_authentication_enabled, + :performance_bar_allowed_group_id, + :performance_bar_enabled, + :plantuml_enabled, + :plantuml_url, + :polling_interval_multiplier, + :prometheus_metrics_enabled, + :recaptcha_enabled, + :recaptcha_private_key, + :recaptcha_site_key, + :repository_checks_enabled, + :repository_storages, + :require_two_factor_authentication, + :restricted_visibility_levels, + :send_user_confirmation_email, + :sentry_dsn, + :sentry_enabled, + :session_expire_delay, + :shared_runners_enabled, + :shared_runners_text, + :sidekiq_throttling_enabled, + :sidekiq_throttling_factor, + :sidekiq_throttling_queues, + :sign_in_text, + :signup_enabled, + :terminal_max_session_time, + :two_factor_grace_period, + :unique_ips_limit_enabled, + :unique_ips_limit_per_user, + :unique_ips_limit_time_window, + :usage_ping_enabled, + :user_default_external, + :user_oauth_applications, + :version_check_enabled + ] + end end diff --git a/changelogs/unreleased/bvl-add-all-settings-to-api.yml b/changelogs/unreleased/bvl-add-all-settings-to-api.yml new file mode 100644 index 00000000000..bfaf237a21c --- /dev/null +++ b/changelogs/unreleased/bvl-add-all-settings-to-api.yml @@ -0,0 +1,4 @@ +--- +title: Make all application-settings accessible through the API +merge_request: 12851 +author: diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 5cdc441e8cb..ce25be34ec4 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -671,43 +671,14 @@ module API class ApplicationSetting < Grape::Entity expose :id - expose :default_projects_limit - expose :signup_enabled - expose :password_authentication_enabled - expose :password_authentication_enabled, as: :signin_enabled - expose :gravatar_enabled - expose :sign_in_text - expose :after_sign_up_text - expose :created_at - expose :updated_at - expose :home_page_url - expose :default_branch_protection + expose(*::ApplicationSettingsHelper.visible_attributes) expose(:restricted_visibility_levels) do |setting, _options| setting.restricted_visibility_levels.map { |level| Gitlab::VisibilityLevel.string_level(level) } end - expose :max_attachment_size - expose :session_expire_delay expose(:default_project_visibility) { |setting, _options| Gitlab::VisibilityLevel.string_level(setting.default_project_visibility) } expose(:default_snippet_visibility) { |setting, _options| Gitlab::VisibilityLevel.string_level(setting.default_snippet_visibility) } expose(:default_group_visibility) { |setting, _options| Gitlab::VisibilityLevel.string_level(setting.default_group_visibility) } - expose :default_artifacts_expire_in - expose :domain_whitelist - expose :domain_blacklist_enabled - expose :domain_blacklist - expose :user_oauth_applications - expose :after_sign_out_path - expose :container_registry_token_expire_delay - expose :repository_storage - expose :repository_storages - expose :koding_enabled - expose :koding_url - expose :plantuml_enabled - expose :plantuml_url - expose :terminal_max_session_time - expose :polling_interval_multiplier - expose :help_page_hide_commercial_content - expose :help_page_text - expose :help_page_support_url + expose :password_authentication_enabled, as: :signin_enabled end class Release < Grape::Entity diff --git a/lib/api/settings.rb b/lib/api/settings.rb index b19095d1252..ca21f3e6f4c 100644 --- a/lib/api/settings.rb +++ b/lib/api/settings.rb @@ -174,7 +174,8 @@ module API optional :terminal_max_session_time, type: Integer, desc: 'Maximum time for web terminal websocket connection (in seconds). Set to 0 for unlimited time.' optional :polling_interval_multiplier, type: BigDecimal, desc: 'Interval multiplier used by endpoints that perform polling. Set to 0 to disable polling.' - at_least_one_of(*at_least_one_of_ce) + optional(*::ApplicationSettingsHelper.visible_attributes) + at_least_one_of(*::ApplicationSettingsHelper.visible_attributes) end put "application/settings" do attrs = declared_params(include_missing: false) -- cgit v1.2.1 From c11ed138a02d29230e192a064011347e93b7fb9f Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Thu, 13 Jul 2017 18:10:01 +0200 Subject: Remove deprecated `repository_storage` attribute In favor of the new `repository_storages` --- app/models/application_setting.rb | 2 ++ doc/api/settings.md | 4 +-- lib/api/settings.rb | 55 +------------------------------------- spec/requests/api/settings_spec.rb | 5 ++-- 4 files changed, 6 insertions(+), 60 deletions(-) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 898ce45f60e..bd7c4cd45ea 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -315,7 +315,9 @@ class ApplicationSetting < ActiveRecord::Base Array(read_attribute(:repository_storages)) end + # DEPRECATED # repository_storage is still required in the API. Remove in 9.0 + # Still used in API v3 def repository_storage repository_storages.first end diff --git a/doc/api/settings.md b/doc/api/settings.md index 0b4cc98cea6..94a9f8265fb 100644 --- a/doc/api/settings.md +++ b/doc/api/settings.md @@ -42,7 +42,6 @@ Example response: "gravatar_enabled" : true, "sign_in_text" : null, "container_registry_token_expire_delay": 5, - "repository_storage": "default", "repository_storages": ["default"], "koding_enabled": false, "koding_url": null, @@ -81,7 +80,6 @@ PUT /application/settings | `after_sign_out_path` | string | no | Where to redirect users after logout | | `container_registry_token_expire_delay` | integer | no | Container Registry token duration in minutes | | `repository_storages` | array of strings | no | A list of names of enabled storage paths, taken from `gitlab.yml`. New projects will be created in one of these stores, chosen at random. | -| `repository_storage` | string | no | The first entry in `repository_storages`. Deprecated, but retained for compatibility reasons | | `enabled_git_access_protocol` | string | no | Enabled protocols for Git access. Allowed values are: `ssh`, `http`, and `nil` to allow both protocols. | | `koding_enabled` | boolean | no | Enable Koding integration. Default is `false`. | | `koding_url` | string | yes (if `koding_enabled` is `true`) | The Koding instance URL for integration. | @@ -121,7 +119,7 @@ Example response: "user_oauth_applications": true, "after_sign_out_path": "", "container_registry_token_expire_delay": 5, - "repository_storage": "default", + "repository_storages": ["default"], "koding_enabled": false, "koding_url": null, "plantuml_enabled": false, diff --git a/lib/api/settings.rb b/lib/api/settings.rb index ca21f3e6f4c..d55a61fa638 100644 --- a/lib/api/settings.rb +++ b/lib/api/settings.rb @@ -20,59 +20,6 @@ module API success Entities::ApplicationSetting end params do - # CE - at_least_one_of_ce = [ - :admin_notification_email, - :after_sign_out_path, - :after_sign_up_text, - :akismet_enabled, - :container_registry_token_expire_delay, - :default_artifacts_expire_in, - :default_branch_protection, - :default_group_visibility, - :default_project_visibility, - :default_projects_limit, - :default_snippet_visibility, - :disabled_oauth_sign_in_sources, - :domain_blacklist_enabled, - :domain_whitelist, - :email_author_in_body, - :enabled_git_access_protocol, - :gravatar_enabled, - :help_page_hide_commercial_content, - :help_page_text, - :help_page_support_url, - :home_page_url, - :housekeeping_enabled, - :html_emails_enabled, - :import_sources, - :koding_enabled, - :max_artifacts_size, - :max_attachment_size, - :max_pages_size, - :metrics_enabled, - :plantuml_enabled, - :polling_interval_multiplier, - :recaptcha_enabled, - :repository_checks_enabled, - :repository_storage, - :require_two_factor_authentication, - :restricted_visibility_levels, - :send_user_confirmation_email, - :sentry_enabled, - :clientside_sentry_enabled, - :session_expire_delay, - :shared_runners_enabled, - :sidekiq_throttling_enabled, - :sign_in_text, - :password_authentication_enabled, - :signin_enabled, - :signup_enabled, - :terminal_max_session_time, - :user_default_external, - :user_oauth_applications, - :version_check_enabled - ] optional :default_branch_protection, type: Integer, values: [0, 1, 2], desc: 'Determine if developers can push to master' optional :default_project_visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The default project visibility' optional :default_snippet_visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The default snippet visibility' @@ -151,7 +98,7 @@ module API given clientside_sentry_enabled: ->(val) { val } do requires :clientside_sentry_dsn, type: String, desc: 'Clientside Sentry Data Source Name' end - optional :repository_storage, type: String, desc: 'Storage paths for new projects' + optional :repository_storages, type: Array[String], desc: 'Storage paths for new projects' optional :repository_checks_enabled, type: Boolean, desc: "GitLab will periodically run 'git fsck' in all project and wiki repositories to look for silent disk corruption issues." optional :koding_enabled, type: Boolean, desc: 'Enable Koding' given koding_enabled: ->(val) { val } do diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb index b71ac6c30b5..c3ed5cd8ece 100644 --- a/spec/requests/api/settings_spec.rb +++ b/spec/requests/api/settings_spec.rb @@ -11,7 +11,7 @@ describe API::Settings, 'Settings' do expect(json_response).to be_an Hash expect(json_response['default_projects_limit']).to eq(42) expect(json_response['password_authentication_enabled']).to be_truthy - expect(json_response['repository_storage']).to eq('default') + expect(json_response['repository_storages']).to eq(['default']) expect(json_response['koding_enabled']).to be_falsey expect(json_response['koding_url']).to be_nil expect(json_response['plantuml_enabled']).to be_falsey @@ -33,7 +33,7 @@ describe API::Settings, 'Settings' do put api("/application/settings", admin), default_projects_limit: 3, password_authentication_enabled: false, - repository_storage: 'custom', + repository_storages: ['custom'], koding_enabled: true, koding_url: 'http://koding.example.com', plantuml_enabled: true, @@ -47,7 +47,6 @@ describe API::Settings, 'Settings' do expect(response).to have_http_status(200) expect(json_response['default_projects_limit']).to eq(3) expect(json_response['password_authentication_enabled']).to be_falsey - expect(json_response['repository_storage']).to eq('custom') expect(json_response['repository_storages']).to eq(['custom']) expect(json_response['koding_enabled']).to be_truthy expect(json_response['koding_url']).to eq('http://koding.example.com') -- cgit v1.2.1 From d27dec80ceb372a5aace7c69e3bdba841d1ed863 Mon Sep 17 00:00:00 2001 From: Markus Koller Date: Thu, 20 Jul 2017 10:50:07 +0200 Subject: Support custom directory in gitlab:backup:create task --- .../unreleased/feature-backup-custom-path.yml | 4 ++ config/initializers/1_settings.rb | 4 -- doc/raketasks/backup_restore.md | 9 ++++ lib/backup/manager.rb | 42 +++++++++++------ spec/lib/gitlab/backup/manager_spec.rb | 52 ++++++++++++++++++++++ spec/support/stub_configuration.rb | 29 +++++++++--- 6 files changed, 115 insertions(+), 25 deletions(-) create mode 100644 changelogs/unreleased/feature-backup-custom-path.yml diff --git a/changelogs/unreleased/feature-backup-custom-path.yml b/changelogs/unreleased/feature-backup-custom-path.yml new file mode 100644 index 00000000000..1c5f25b3ee5 --- /dev/null +++ b/changelogs/unreleased/feature-backup-custom-path.yml @@ -0,0 +1,4 @@ +--- +title: Support custom directory in gitlab:backup:create task +merge_request: 12984 +author: Markus Koller diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 201a1d062b9..02d3161f769 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -459,10 +459,6 @@ Settings.backup['pg_schema'] = nil Settings.backup['path'] = Settings.absolute(Settings.backup['path'] || "tmp/backups/") Settings.backup['archive_permissions'] ||= 0600 Settings.backup['upload'] ||= Settingslogic.new({ 'remote_directory' => nil, 'connection' => nil }) -# Convert upload connection settings to use symbol keys, to make Fog happy -if Settings.backup['upload']['connection'] - Settings.backup['upload']['connection'] = Hash[Settings.backup['upload']['connection'].map { |k, v| [k.to_sym, v] }] -end Settings.backup['upload']['multipart_chunk_size'] ||= 104857600 Settings.backup['upload']['encryption'] ||= nil Settings.backup['upload']['storage_class'] ||= nil diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md index 855f437cd73..6ccd79641bc 100644 --- a/doc/raketasks/backup_restore.md +++ b/doc/raketasks/backup_restore.md @@ -270,6 +270,15 @@ For installations from source: remote_directory: 'gitlab_backups' ``` +### Specifying a custom directory for backups + +If you want to group your backups you can pass a `DIRECTORY` environment variable: + +``` +sudo gitlab-rake gitlab:backup:create DIRECTORY=daily +sudo gitlab-rake gitlab:backup:create DIRECTORY=weekly +``` + ### Backup archive permissions The backup archives created by GitLab (`1393513186_2014_02_27_gitlab_backup.tar`) diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb index f755c99ea4a..ca6d6848d41 100644 --- a/lib/backup/manager.rb +++ b/lib/backup/manager.rb @@ -8,18 +8,9 @@ module Backup # Make sure there is a connection ActiveRecord::Base.connection.reconnect! - # saving additional informations - s = {} - s[:db_version] = "#{ActiveRecord::Migrator.current_version}" - s[:backup_created_at] = Time.now - s[:gitlab_version] = Gitlab::VERSION - s[:tar_version] = tar_version - s[:skipped] = ENV["SKIP"] - tar_file = "#{s[:backup_created_at].strftime('%s_%Y_%m_%d_')}#{s[:gitlab_version]}#{FILE_NAME_SUFFIX}" - Dir.chdir(backup_path) do File.open("#{backup_path}/backup_information.yml", "w+") do |file| - file << s.to_yaml.gsub(/^---\n/, '') + file << backup_information.to_yaml.gsub(/^---\n/, '') end # create archive @@ -33,11 +24,11 @@ module Backup abort 'Backup failed' end - upload(tar_file) + upload end end - def upload(tar_file) + def upload $progress.print "Uploading backup archive to remote storage #{remote_directory} ... " connection_settings = Gitlab.config.backup.upload.connection @@ -48,7 +39,7 @@ module Backup directory = connect_to_remote_directory(connection_settings) - if directory.files.create(key: tar_file, body: File.open(tar_file), public: false, + if directory.files.create(key: remote_target, body: File.open(tar_file), public: false, multipart_chunk_size: Gitlab.config.backup.upload.multipart_chunk_size, encryption: Gitlab.config.backup.upload.encryption, storage_class: Gitlab.config.backup.upload.storage_class) @@ -177,7 +168,8 @@ module Backup end def connect_to_remote_directory(connection_settings) - connection = ::Fog::Storage.new(connection_settings) + # our settings use string keys, but Fog expects symbols + connection = ::Fog::Storage.new(connection_settings.symbolize_keys) # We only attempt to create the directory for local backups. For AWS # and other cloud providers, we cannot guarantee the user will have @@ -193,6 +185,14 @@ module Backup Gitlab.config.backup.upload.remote_directory end + def remote_target + if ENV['DIRECTORY'] + File.join(ENV['DIRECTORY'], tar_file) + else + tar_file + end + end + def backup_contents folders_to_backup + archives_to_backup + ["backup_information.yml"] end @@ -214,5 +214,19 @@ module Backup def settings @settings ||= YAML.load_file("backup_information.yml") end + + def tar_file + @tar_file ||= "#{backup_information[:backup_created_at].strftime('%s_%Y_%m_%d_')}#{backup_information[:gitlab_version]}#{FILE_NAME_SUFFIX}" + end + + def backup_information + @backup_information ||= { + db_version: ActiveRecord::Migrator.current_version.to_s, + backup_created_at: Time.now, + gitlab_version: Gitlab::VERSION, + tar_version: tar_version, + skipped: ENV["SKIP"] + } + end end end diff --git a/spec/lib/gitlab/backup/manager_spec.rb b/spec/lib/gitlab/backup/manager_spec.rb index 1c3d2547fec..8536d152272 100644 --- a/spec/lib/gitlab/backup/manager_spec.rb +++ b/spec/lib/gitlab/backup/manager_spec.rb @@ -214,4 +214,56 @@ describe Backup::Manager, lib: true do end end end + + describe '#upload' do + let(:backup_file) { Tempfile.new('backup', Gitlab.config.backup.path) } + let(:backup_filename) { File.basename(backup_file.path) } + + before do + allow(subject).to receive(:tar_file).and_return(backup_filename) + + stub_backup_setting( + upload: { + connection: { + provider: 'AWS', + aws_access_key_id: 'id', + aws_secret_access_key: 'secret' + }, + remote_directory: 'directory', + multipart_chunk_size: 104857600, + encryption: nil, + storage_class: nil + } + ) + + # the Fog mock only knows about directories we create explicitly + Fog.mock! + connection = ::Fog::Storage.new(Gitlab.config.backup.upload.connection.symbolize_keys) + connection.directories.create(key: Gitlab.config.backup.upload.remote_directory) + end + + context 'target path' do + it 'uses the tar filename by default' do + expect_any_instance_of(Fog::Collection).to receive(:create) + .with(hash_including(key: backup_filename)) + .and_return(true) + + Dir.chdir(Gitlab.config.backup.path) do + subject.upload + end + end + + it 'adds the DIRECTORY environment variable if present' do + stub_env('DIRECTORY', 'daily') + + expect_any_instance_of(Fog::Collection).to receive(:create) + .with(hash_including(key: "daily/#{backup_filename}")) + .and_return(true) + + Dir.chdir(Gitlab.config.backup.path) do + subject.upload + end + end + end + end end diff --git a/spec/support/stub_configuration.rb b/spec/support/stub_configuration.rb index 80ecce92dc1..516f8878679 100644 --- a/spec/support/stub_configuration.rb +++ b/spec/support/stub_configuration.rb @@ -4,9 +4,9 @@ module StubConfiguration # Stubbing both of these because we're not yet consistent with how we access # current application settings - allow_any_instance_of(ApplicationSetting).to receive_messages(messages) + allow_any_instance_of(ApplicationSetting).to receive_messages(to_settings(messages)) allow(Gitlab::CurrentSettings.current_application_settings) - .to receive_messages(messages) + .to receive_messages(to_settings(messages)) end def stub_not_protect_default_branch @@ -15,23 +15,27 @@ module StubConfiguration end def stub_config_setting(messages) - allow(Gitlab.config.gitlab).to receive_messages(messages) + allow(Gitlab.config.gitlab).to receive_messages(to_settings(messages)) end def stub_gravatar_setting(messages) - allow(Gitlab.config.gravatar).to receive_messages(messages) + allow(Gitlab.config.gravatar).to receive_messages(to_settings(messages)) end def stub_incoming_email_setting(messages) - allow(Gitlab.config.incoming_email).to receive_messages(messages) + allow(Gitlab.config.incoming_email).to receive_messages(to_settings(messages)) end def stub_mattermost_setting(messages) - allow(Gitlab.config.mattermost).to receive_messages(messages) + allow(Gitlab.config.mattermost).to receive_messages(to_settings(messages)) end def stub_omniauth_setting(messages) - allow(Gitlab.config.omniauth).to receive_messages(messages) + allow(Gitlab.config.omniauth).to receive_messages(to_settings(messages)) + end + + def stub_backup_setting(messages) + allow(Gitlab.config.backup).to receive_messages(to_settings(messages)) end private @@ -54,4 +58,15 @@ module StubConfiguration messages[predicate.to_sym] = messages[key.to_sym] end end + + # Support nested hashes by converting all values into Settingslogic objects + def to_settings(hash) + hash.transform_values do |value| + if value.is_a? Hash + Settingslogic.new(value.deep_stringify_keys) + else + value + end + end + end end -- cgit v1.2.1 From 5c51db0bce6d0f1b94aaf14d1ac9c8d70f7f9468 Mon Sep 17 00:00:00 2001 From: Hiroyuki Sato Date: Wed, 26 Jul 2017 21:22:43 +0900 Subject: Use simplified route --- app/views/projects/wikis/edit.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/wikis/edit.html.haml b/app/views/projects/wikis/edit.html.haml index e2d835d8af0..8fd60216536 100644 --- a/app/views/projects/wikis/edit.html.haml +++ b/app/views/projects/wikis/edit.html.haml @@ -4,7 +4,7 @@ - if @conflict .alert.alert-danger Someone edited the page the same time you did. Please check out - = link_to "the page", namespace_project_wiki_path(@project.namespace, @project, @page), target: "_blank" + = link_to "the page", project_wiki_path(@project, @page), target: "_blank" and make sure your changes will not unintentionally remove theirs. .wiki-page-header.has-sidebar-toggle -- cgit v1.2.1 From fa3e4ddff0adf8dd678cba7d5671117b8f66db75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 27 Jul 2017 12:27:09 +0000 Subject: Remove mentions of SeanPackham since he's no longer with GitLab --- doc/development/doc_styleguide.md | 4 ++-- doc/university/process/README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/development/doc_styleguide.md b/doc/development/doc_styleguide.md index 36c55cbaceb..90d1d9657b9 100644 --- a/doc/development/doc_styleguide.md +++ b/doc/development/doc_styleguide.md @@ -105,8 +105,8 @@ merge request. considered beta or experimental, put this info in a note, not in the heading. - When introducing a new document, be careful for the headings to be grammatically and syntactically correct. It is advised to mention one or all - of the following GitLab members for a review: `@axil`, `@rspeicher`, `@marcia`, - `@SeanPackham`. This is to ensure that no document with wrong heading is going + of the following GitLab members for a review: `@axil`, `@rspeicher`, `@marcia`. + This is to ensure that no document with wrong heading is going live without an audit, thus preventing dead links and redirection issues when corrected - Leave exactly one newline after a heading diff --git a/doc/university/process/README.md b/doc/university/process/README.md index 7ff53c2cc3f..04f2d52514f 100644 --- a/doc/university/process/README.md +++ b/doc/university/process/README.md @@ -27,4 +27,4 @@ please submit a merge request to add an upcoming class, assign to 1. Please upload any video recordings to our Youtube channel. We prefer them to be public, if needed they can be unlisted but if so they should be linked from this page. -1. Please create a merge request and assign to [SeanPackham](https://gitlab.com/u/SeanPackham). +1. Please create a merge request and assign to [Erica](https://gitlab.com/u/Erica). -- cgit v1.2.1 From 649382b1c27b09e5b54a5cdb21f078f37ecd7306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Wed, 26 Jul 2017 14:33:09 +0200 Subject: Fix the /projects/:id/repository/branches endpoint to handle dots in the branch name when the project full patch contains a `/` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- .../unreleased/rc-fix-branches-api-endpoint.yml | 5 + doc/api/README.md | 13 +- lib/api/branches.rb | 14 +- .../fixtures/api/schemas/public_api/v4/branch.json | 20 + .../api/schemas/public_api/v4/branches.json | 4 + .../api/schemas/public_api/v4/commit/basic.json | 37 ++ spec/requests/api/branches_spec.rb | 508 ++++++++++++--------- spec/requests/api/groups_spec.rb | 2 +- spec/requests/api/projects_spec.rb | 2 +- spec/requests/api/v3/groups_spec.rb | 2 +- spec/requests/api/v3/projects_spec.rb | 2 +- spec/support/api/schema_matcher.rb | 9 +- spec/support/api/status_shared_examples.rb | 42 -- .../requests/api/status_shared_examples.rb | 42 ++ 14 files changed, 440 insertions(+), 262 deletions(-) create mode 100644 changelogs/unreleased/rc-fix-branches-api-endpoint.yml create mode 100644 spec/fixtures/api/schemas/public_api/v4/branch.json create mode 100644 spec/fixtures/api/schemas/public_api/v4/branches.json create mode 100644 spec/fixtures/api/schemas/public_api/v4/commit/basic.json delete mode 100644 spec/support/api/status_shared_examples.rb create mode 100644 spec/support/shared_examples/requests/api/status_shared_examples.rb diff --git a/changelogs/unreleased/rc-fix-branches-api-endpoint.yml b/changelogs/unreleased/rc-fix-branches-api-endpoint.yml new file mode 100644 index 00000000000..217dfff8c63 --- /dev/null +++ b/changelogs/unreleased/rc-fix-branches-api-endpoint.yml @@ -0,0 +1,5 @@ +--- +title: Fix the /projects/:id/repository/branches endpoint to handle dots in the branch + name when the project full patch contains a `/` +merge_request: +author: diff --git a/doc/api/README.md b/doc/api/README.md index a888c0ebb4e..fe29563eaca 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -340,7 +340,18 @@ URL-encoded. For example, `/` is represented by `%2F`: ``` -/api/v4/projects/diaspora%2Fdiaspora +GET /api/v4/projects/diaspora%2Fdiaspora +``` + +## Branches & tags name encoding + +If your branch or tag contains a `/`, make sure the branch/tag name is +URL-encoded. + +For example, `/` is represented by `%2F`: + +``` +GET /api/v4/projects/1/branches/my%2Fbranch/commits ``` ## `id` vs `iid` diff --git a/lib/api/branches.rb b/lib/api/branches.rb index 3d816f8771d..cc81f3898ab 100644 --- a/lib/api/branches.rb +++ b/lib/api/branches.rb @@ -16,7 +16,7 @@ module API params do use :pagination end - get ":id/repository/branches" do + get ':id/repository/branches' do branches = ::Kaminari.paginate_array(user_project.repository.branches.sort_by(&:name)) present paginate(branches), with: Entities::RepoBranch, project: user_project @@ -28,7 +28,7 @@ module API params do requires :branch, type: String, desc: 'The name of the branch' end - get ':id/repository/branches/:branch', requirements: { branch: /.+/ } do + get ':id/repository/branches/:branch', requirements: { id: %r{[^/]+}, branch: %r{[^/]+} } do branch = user_project.repository.find_branch(params[:branch]) not_found!("Branch") unless branch @@ -46,7 +46,7 @@ module API optional :developers_can_push, type: Boolean, desc: 'Flag if developers can push to that branch' optional :developers_can_merge, type: Boolean, desc: 'Flag if developers can merge to that branch' end - put ':id/repository/branches/:branch/protect', requirements: { branch: /.+/ } do + put ':id/repository/branches/:branch/protect', requirements: { id: %r{[^/]+}, branch: %r{[^/]+} } do authorize_admin_project branch = user_project.repository.find_branch(params[:branch]) @@ -81,7 +81,7 @@ module API params do requires :branch, type: String, desc: 'The name of the branch' end - put ':id/repository/branches/:branch/unprotect', requirements: { branch: /.+/ } do + put ':id/repository/branches/:branch/unprotect', requirements: { id: %r{[^/]+}, branch: %r{[^/]+} } do authorize_admin_project branch = user_project.repository.find_branch(params[:branch]) @@ -99,7 +99,7 @@ module API requires :branch, type: String, desc: 'The name of the branch' requires :ref, type: String, desc: 'Create branch from commit sha or existing branch' end - post ":id/repository/branches" do + post ':id/repository/branches' do authorize_push_project result = CreateBranchService.new(user_project, current_user) @@ -118,7 +118,7 @@ module API params do requires :branch, type: String, desc: 'The name of the branch' end - delete ":id/repository/branches/:branch", requirements: { branch: /.+/ } do + delete ':id/repository/branches/:branch', requirements: { id: %r{[^/]+}, branch: %r{[^/]+} } do authorize_push_project result = DeleteBranchService.new(user_project, current_user) @@ -130,7 +130,7 @@ module API end desc 'Delete all merged branches' - delete ":id/repository/merged_branches" do + delete ':id/repository/merged_branches' do DeleteMergedBranchesService.new(user_project, current_user).async_execute accepted! diff --git a/spec/fixtures/api/schemas/public_api/v4/branch.json b/spec/fixtures/api/schemas/public_api/v4/branch.json new file mode 100644 index 00000000000..a3581178974 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/branch.json @@ -0,0 +1,20 @@ +{ + "type": "object", + "required" : [ + "name", + "commit", + "merged", + "protected", + "developers_can_push", + "developers_can_merge" + ], + "properties" : { + "name": { "type": "string" }, + "commit": { "$ref": "commit/basic.json" }, + "merged": { "type": "boolean" }, + "protected": { "type": "boolean" }, + "developers_can_push": { "type": "boolean" }, + "developers_can_merge": { "type": "boolean" } + }, + "additionalProperties": false +} diff --git a/spec/fixtures/api/schemas/public_api/v4/branches.json b/spec/fixtures/api/schemas/public_api/v4/branches.json new file mode 100644 index 00000000000..854c902b485 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/branches.json @@ -0,0 +1,4 @@ +{ + "type": "array", + "items": { "$ref": "branch.json" } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/commit/basic.json b/spec/fixtures/api/schemas/public_api/v4/commit/basic.json new file mode 100644 index 00000000000..9d99628a286 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/commit/basic.json @@ -0,0 +1,37 @@ +{ + "type": "object", + "required" : [ + "id", + "short_id", + "title", + "created_at", + "parent_ids", + "message", + "author_name", + "author_email", + "authored_date", + "committer_name", + "committer_email", + "committed_date" + ], + "properties" : { + "id": { "type": ["string", "null"] }, + "short_id": { "type": ["string", "null"] }, + "title": { "type": "string" }, + "created_at": { "type": "date" }, + "parent_ids": { + "type": ["array", "null"], + "items": { + "type": "string", + "additionalProperties": false + } + }, + "message": { "type": "string" }, + "author_name": { "type": "string" }, + "author_email": { "type": "string" }, + "authored_date": { "type": "date" }, + "committer_name": { "type": "string" }, + "committer_email": { "type": "string" }, + "committed_date": { "type": "date" } + } +} diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb index c64499fc8c0..5a2e1b2cf2d 100644 --- a/spec/requests/api/branches_spec.rb +++ b/spec/requests/api/branches_spec.rb @@ -1,25 +1,31 @@ require 'spec_helper' -require 'mime/types' describe API::Branches do let(:user) { create(:user) } - let!(:project) { create(:project, :repository, creator: user) } - let!(:master) { create(:project_member, :master, user: user, project: project) } - let(:guest) { create(:user).tap { |u| create(:project_member, :guest, user: u, project: project) } } - let!(:branch_name) { 'feature' } - let!(:branch_sha) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } - let(:branch_with_dot) { CreateBranchService.new(project, user).execute("with.1.2.3", "master")[:branch] } + let(:guest) { create(:user).tap { |u| project.add_guest(u) } } + let(:project) { create(:project, :repository, creator: user, path: 'my.project') } + let(:branch_name) { 'feature' } + let(:branch_sha) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } + let(:branch_with_dot) { project.repository.find_branch('ends-with.json') } + let(:branch_with_slash) { project.repository.find_branch('improve/awesome') } + + let(:project_id) { project.id } + let(:current_user) { nil } + + before do + project.add_master(user) + end describe "GET /projects/:id/repository/branches" do - let(:route) { "/projects/#{project.id}/repository/branches" } + let(:route) { "/projects/#{project_id}/repository/branches" } shared_examples_for 'repository branches' do it 'returns the repository branches' do get api(route, current_user), per_page: 100 - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/branches') expect(response).to include_pagination_headers - expect(json_response).to be_an Array branch_names = json_response.map { |x| x['name'] } expect(branch_names).to match_array(project.repository.branch_names) end @@ -34,10 +40,9 @@ describe API::Branches do end context 'when unauthenticated', 'and project is public' do - it_behaves_like 'repository branches' do - let(:project) { create(:project, :public, :repository) } - let(:current_user) { nil } - end + let(:project) { create(:project, :public, :repository) } + + it_behaves_like 'repository branches' end context 'when unauthenticated', 'and project is private' do @@ -47,9 +52,15 @@ describe API::Branches do end end - context 'when authenticated', 'as a developer' do - it_behaves_like 'repository branches' do - let(:current_user) { user } + context 'when authenticated', 'as a master' do + let(:current_user) { user } + + it_behaves_like 'repository branches' + + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } + + it_behaves_like 'repository branches' end end @@ -61,31 +72,15 @@ describe API::Branches do end describe "GET /projects/:id/repository/branches/:branch" do - let(:route) { "/projects/#{project.id}/repository/branches/#{branch_name}" } + let(:route) { "/projects/#{project_id}/repository/branches/#{branch_name}" } - shared_examples_for 'repository branch' do |merged: false| + shared_examples_for 'repository branch' do it 'returns the repository branch' do get api(route, current_user) - expect(response).to have_http_status(200) - expect(json_response['name']).to eq(branch_name) - expect(json_response['merged']).to eq(merged) - expect(json_response['protected']).to eq(false) - expect(json_response['developers_can_push']).to eq(false) - expect(json_response['developers_can_merge']).to eq(false) - - json_commit = json_response['commit'] - expect(json_commit['id']).to eq(branch_sha) - expect(json_commit).to have_key('short_id') - expect(json_commit).to have_key('title') - expect(json_commit).to have_key('message') - expect(json_commit).to have_key('author_name') - expect(json_commit).to have_key('author_email') - expect(json_commit).to have_key('authored_date') - expect(json_commit).to have_key('committer_name') - expect(json_commit).to have_key('committer_email') - expect(json_commit).to have_key('committed_date') - expect(json_commit).to have_key('parent_ids') + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/branch') + expect(json_response['name']).to eq(CGI.unescape(branch_name)) end context 'when branch does not exist' do @@ -107,10 +102,9 @@ describe API::Branches do end context 'when unauthenticated', 'and project is public' do - it_behaves_like 'repository branch' do - let(:project) { create(:project, :public, :repository) } - let(:current_user) { nil } - end + let(:project) { create(:project, :public, :repository) } + + it_behaves_like 'repository branch' end context 'when unauthenticated', 'and project is private' do @@ -120,22 +114,41 @@ describe API::Branches do end end - context 'when authenticated', 'as a developer' do + context 'when authenticated', 'as a master' do let(:current_user) { user } + it_behaves_like 'repository branch' context 'when branch contains a dot' do let(:branch_name) { branch_with_dot.name } - let(:branch_sha) { project.commit('master').sha } it_behaves_like 'repository branch' end - context 'when branch is merged' do - let(:branch_name) { 'merge-test' } - let(:branch_sha) { project.commit('merge-test').sha } + context 'when branch contains a slash' do + let(:branch_name) { branch_with_slash.name } + + it_behaves_like '404 response' do + let(:request) { get api(route, current_user) } + end + end + + context 'when branch contains an escaped slash' do + let(:branch_name) { CGI.escape(branch_with_slash.name) } + + it_behaves_like 'repository branch' + end + + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } + + it_behaves_like 'repository branch' - it_behaves_like 'repository branch', merged: true + context 'when branch contains a dot' do + let(:branch_name) { branch_with_dot.name } + + it_behaves_like 'repository branch' + end end end @@ -147,268 +160,348 @@ describe API::Branches do end describe 'PUT /projects/:id/repository/branches/:branch/protect' do - context "when a protected branch doesn't already exist" do - it 'protects a single branch' do - put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user) + let(:route) { "/projects/#{project_id}/repository/branches/#{branch_name}/protect" } - expect(response).to have_http_status(200) - expect(json_response['name']).to eq(branch_name) - expect(json_response['commit']['id']).to eq(branch_sha) - expect(json_response['protected']).to eq(true) - expect(json_response['developers_can_push']).to eq(false) - expect(json_response['developers_can_merge']).to eq(false) - end - - it "protects a single branch with dots in the name" do - put api("/projects/#{project.id}/repository/branches/#{branch_with_dot.name}/protect", user) + shared_examples_for 'repository new protected branch' do + it 'protects a single branch' do + put api(route, current_user) - expect(response).to have_http_status(200) - expect(json_response['name']).to eq(branch_with_dot.name) + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/branch') + expect(json_response['name']).to eq(CGI.unescape(branch_name)) expect(json_response['protected']).to eq(true) end it 'protects a single branch and developers can push' do - put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user), - developers_can_push: true + put api(route, current_user), developers_can_push: true - expect(response).to have_http_status(200) - expect(json_response['name']).to eq(branch_name) - expect(json_response['commit']['id']).to eq(branch_sha) + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/branch') + expect(json_response['name']).to eq(CGI.unescape(branch_name)) expect(json_response['protected']).to eq(true) expect(json_response['developers_can_push']).to eq(true) expect(json_response['developers_can_merge']).to eq(false) end it 'protects a single branch and developers can merge' do - put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user), - developers_can_merge: true + put api(route, current_user), developers_can_merge: true - expect(response).to have_http_status(200) - expect(json_response['name']).to eq(branch_name) - expect(json_response['commit']['id']).to eq(branch_sha) + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/branch') + expect(json_response['name']).to eq(CGI.unescape(branch_name)) expect(json_response['protected']).to eq(true) expect(json_response['developers_can_push']).to eq(false) expect(json_response['developers_can_merge']).to eq(true) end it 'protects a single branch and developers can push and merge' do - put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user), - developers_can_push: true, developers_can_merge: true + put api(route, current_user), developers_can_push: true, developers_can_merge: true - expect(response).to have_http_status(200) - expect(json_response['name']).to eq(branch_name) - expect(json_response['commit']['id']).to eq(branch_sha) + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/branch') + expect(json_response['name']).to eq(CGI.unescape(branch_name)) expect(json_response['protected']).to eq(true) expect(json_response['developers_can_push']).to eq(true) expect(json_response['developers_can_merge']).to eq(true) end + + context 'when branch does not exist' do + let(:branch_name) { 'unknown' } + + it_behaves_like '404 response' do + let(:request) { put api(route, current_user) } + let(:message) { '404 Branch Not Found' } + end + end + + context 'when repository is disabled' do + include_context 'disabled repository' + + it_behaves_like '403 response' do + let(:request) { put api(route, current_user) } + end + end end - context 'for an existing protected branch' do - before do - project.repository.add_branch(user, protected_branch.name, 'master') + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { put api(route) } + let(:message) { '404 Project Not Found' } end + end + + context 'when authenticated', 'as a guest' do + it_behaves_like '403 response' do + let(:request) { put api(route, guest) } + end + end + + context 'when authenticated', 'as a master' do + let(:current_user) { user } - context "when developers can push and merge" do - let(:protected_branch) { create(:protected_branch, :developers_can_push, :developers_can_merge, project: project, name: 'protected_branch') } + context "when a protected branch doesn't already exist" do + it_behaves_like 'repository new protected branch' - it 'updates that a developer cannot push or merge' do - put api("/projects/#{project.id}/repository/branches/#{protected_branch.name}/protect", user), - developers_can_push: false, developers_can_merge: false + context 'when branch contains a dot' do + let(:branch_name) { branch_with_dot.name } - expect(response).to have_http_status(200) - expect(json_response['name']).to eq(protected_branch.name) - expect(json_response['protected']).to eq(true) - expect(json_response['developers_can_push']).to eq(false) - expect(json_response['developers_can_merge']).to eq(false) + it_behaves_like 'repository new protected branch' end - it "doesn't result in 0 access levels when 'developers_can_push' is switched off" do - put api("/projects/#{project.id}/repository/branches/#{protected_branch.name}/protect", user), - developers_can_push: false + context 'when branch contains a slash' do + let(:branch_name) { branch_with_slash.name } - expect(response).to have_http_status(200) - expect(json_response['name']).to eq(protected_branch.name) - expect(protected_branch.reload.push_access_levels.first).to be_present - expect(protected_branch.reload.push_access_levels.first.access_level).to eq(Gitlab::Access::MASTER) + it_behaves_like '404 response' do + let(:request) { put api(route, current_user) } + end end - it "doesn't result in 0 access levels when 'developers_can_merge' is switched off" do - put api("/projects/#{project.id}/repository/branches/#{protected_branch.name}/protect", user), - developers_can_merge: false + context 'when branch contains an escaped slash' do + let(:branch_name) { CGI.escape(branch_with_slash.name) } - expect(response).to have_http_status(200) - expect(json_response['name']).to eq(protected_branch.name) - expect(protected_branch.reload.merge_access_levels.first).to be_present - expect(protected_branch.reload.merge_access_levels.first.access_level).to eq(Gitlab::Access::MASTER) + it_behaves_like 'repository new protected branch' + end + + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } + + it_behaves_like 'repository new protected branch' + + context 'when branch contains a dot' do + let(:branch_name) { branch_with_dot.name } + + it_behaves_like 'repository new protected branch' + end end end - context "when developers cannot push or merge" do - let(:protected_branch) { create(:protected_branch, project: project, name: 'protected_branch') } + context 'when protected branch already exists' do + before do + project.repository.add_branch(user, protected_branch.name, 'master') + end + + context 'when developers can push and merge' do + let(:protected_branch) { create(:protected_branch, :developers_can_push, :developers_can_merge, project: project, name: 'protected_branch') } + + it 'updates that a developer cannot push or merge' do + put api("/projects/#{project.id}/repository/branches/#{protected_branch.name}/protect", user), + developers_can_push: false, developers_can_merge: false + + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/branch') + expect(json_response['name']).to eq(protected_branch.name) + expect(json_response['protected']).to eq(true) + expect(json_response['developers_can_push']).to eq(false) + expect(json_response['developers_can_merge']).to eq(false) + expect(protected_branch.reload.push_access_levels.first.access_level).to eq(Gitlab::Access::MASTER) + expect(protected_branch.reload.merge_access_levels.first.access_level).to eq(Gitlab::Access::MASTER) + end + end + + context 'when developers cannot push or merge' do + let(:protected_branch) { create(:protected_branch, project: project, name: 'protected_branch') } - it 'updates that a developer can push and merge' do - put api("/projects/#{project.id}/repository/branches/#{protected_branch.name}/protect", user), - developers_can_push: true, developers_can_merge: true + it 'updates that a developer can push and merge' do + put api("/projects/#{project.id}/repository/branches/#{protected_branch.name}/protect", user), + developers_can_push: true, developers_can_merge: true - expect(response).to have_http_status(200) - expect(json_response['name']).to eq(protected_branch.name) - expect(json_response['protected']).to eq(true) - expect(json_response['developers_can_push']).to eq(true) - expect(json_response['developers_can_merge']).to eq(true) + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/branch') + expect(json_response['name']).to eq(protected_branch.name) + expect(json_response['protected']).to eq(true) + expect(json_response['developers_can_push']).to eq(true) + expect(json_response['developers_can_merge']).to eq(true) + end end end end + end - context "multiple API calls" do - it "returns success when `protect` is called twice" do - put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user) - put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user) + describe 'PUT /projects/:id/repository/branches/:branch/unprotect' do + let(:route) { "/projects/#{project_id}/repository/branches/#{branch_name}/unprotect" } - expect(response).to have_http_status(200) - expect(json_response['name']).to eq(branch_name) - expect(json_response['protected']).to eq(true) - expect(json_response['developers_can_push']).to eq(false) - expect(json_response['developers_can_merge']).to eq(false) + shared_examples_for 'repository unprotected branch' do + it 'unprotects a single branch' do + put api(route, current_user) + + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/branch') + expect(json_response['name']).to eq(CGI.unescape(branch_name)) + expect(json_response['protected']).to eq(false) end - it "returns success when `protect` is called twice with `developers_can_push` turned on" do - put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user), developers_can_push: true - put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user), developers_can_push: true + context 'when branch does not exist' do + let(:branch_name) { 'unknown' } - expect(response).to have_http_status(200) - expect(json_response['name']).to eq(branch_name) - expect(json_response['protected']).to eq(true) - expect(json_response['developers_can_push']).to eq(true) - expect(json_response['developers_can_merge']).to eq(false) + it_behaves_like '404 response' do + let(:request) { put api(route, current_user) } + let(:message) { '404 Branch Not Found' } + end end - it "returns success when `protect` is called twice with `developers_can_merge` turned on" do - put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user), developers_can_merge: true - put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user), developers_can_merge: true + context 'when repository is disabled' do + include_context 'disabled repository' - expect(response).to have_http_status(200) - expect(json_response['name']).to eq(branch_name) - expect(json_response['protected']).to eq(true) - expect(json_response['developers_can_push']).to eq(false) - expect(json_response['developers_can_merge']).to eq(true) + it_behaves_like '403 response' do + let(:request) { put api(route, current_user) } + end end end - it "returns a 404 error if branch not found" do - put api("/projects/#{project.id}/repository/branches/unknown/protect", user) - expect(response).to have_http_status(404) + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { put api(route) } + let(:message) { '404 Project Not Found' } + end end - it "returns a 403 error if guest" do - put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", guest) - expect(response).to have_http_status(403) + context 'when authenticated', 'as a guest' do + it_behaves_like '403 response' do + let(:request) { put api(route, guest) } + end end - end - describe "PUT /projects/:id/repository/branches/:branch/unprotect" do - it "unprotects a single branch" do - put api("/projects/#{project.id}/repository/branches/#{branch_name}/unprotect", user) - expect(response).to have_http_status(200) + context 'when authenticated', 'as a master' do + let(:current_user) { user } + + context "when a protected branch doesn't already exist" do + it_behaves_like 'repository unprotected branch' + + context 'when branch contains a dot' do + let(:branch_name) { branch_with_dot.name } + + it_behaves_like 'repository unprotected branch' + end + + context 'when branch contains a slash' do + let(:branch_name) { branch_with_slash.name } + + it_behaves_like '404 response' do + let(:request) { put api(route, current_user) } + end + end + + context 'when branch contains an escaped slash' do + let(:branch_name) { CGI.escape(branch_with_slash.name) } - expect(json_response['name']).to eq(branch_name) - expect(json_response['commit']['id']).to eq(branch_sha) - expect(json_response['protected']).to eq(false) + it_behaves_like 'repository unprotected branch' + end + + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } + + it_behaves_like 'repository unprotected branch' + + context 'when branch contains a dot' do + let(:branch_name) { branch_with_dot.name } + + it_behaves_like 'repository unprotected branch' + end + end + end end + end - it "update branches with dots in branch name" do - put api("/projects/#{project.id}/repository/branches/#{branch_with_dot.name}/unprotect", user) + describe 'POST /projects/:id/repository/branches' do + let(:route) { "/projects/#{project_id}/repository/branches" } - expect(response).to have_http_status(200) - expect(json_response['name']).to eq(branch_with_dot.name) - expect(json_response['protected']).to eq(false) + shared_examples_for 'repository new branch' do + it 'creates a new branch' do + post api(route, current_user), branch: 'feature1', ref: branch_sha + + expect(response).to have_gitlab_http_status(201) + expect(response).to match_response_schema('public_api/v4/branch') + expect(json_response['name']).to eq('feature1') + expect(json_response['commit']['id']).to eq(branch_sha) + end + + context 'when repository is disabled' do + include_context 'disabled repository' + + it_behaves_like '403 response' do + let(:request) { post api(route, current_user) } + end + end end - it "returns success when unprotect branch" do - put api("/projects/#{project.id}/repository/branches/unknown/unprotect", user) - expect(response).to have_http_status(404) + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { post api(route) } + let(:message) { '404 Project Not Found' } + end end - it "returns success when unprotect branch again" do - put api("/projects/#{project.id}/repository/branches/#{branch_name}/unprotect", user) - put api("/projects/#{project.id}/repository/branches/#{branch_name}/unprotect", user) - expect(response).to have_http_status(200) + context 'when authenticated', 'as a guest' do + it_behaves_like '403 response' do + let(:request) { post api(route, guest) } + end end - end - describe "POST /projects/:id/repository/branches" do - it "creates a new branch" do - post api("/projects/#{project.id}/repository/branches", user), - branch: 'feature1', - ref: branch_sha + context 'when authenticated', 'as a master' do + let(:current_user) { user } - expect(response).to have_http_status(201) + context "when a protected branch doesn't already exist" do + it_behaves_like 'repository new branch' - expect(json_response['name']).to eq('feature1') - expect(json_response['commit']['id']).to eq(branch_sha) - end + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } - it "denies for user without push access" do - post api("/projects/#{project.id}/repository/branches", guest), - branch: branch_name, - ref: branch_sha - expect(response).to have_http_status(403) + it_behaves_like 'repository new branch' + end + end end it 'returns 400 if branch name is invalid' do - post api("/projects/#{project.id}/repository/branches", user), - branch: 'new design', - ref: branch_sha - expect(response).to have_http_status(400) + post api(route, user), branch: 'new design', ref: branch_sha + + expect(response).to have_gitlab_http_status(400) expect(json_response['message']).to eq('Branch name is invalid') end it 'returns 400 if branch already exists' do - post api("/projects/#{project.id}/repository/branches", user), - branch: 'new_design1', - ref: branch_sha - expect(response).to have_http_status(201) - - post api("/projects/#{project.id}/repository/branches", user), - branch: 'new_design1', - ref: branch_sha - expect(response).to have_http_status(400) + post api(route, user), branch: 'new_design1', ref: branch_sha + + expect(response).to have_gitlab_http_status(201) + + post api(route, user), branch: 'new_design1', ref: branch_sha + + expect(response).to have_gitlab_http_status(400) expect(json_response['message']).to eq('Branch already exists') end it 'returns 400 if ref name is invalid' do - post api("/projects/#{project.id}/repository/branches", user), - branch: 'new_design3', - ref: 'foo' - expect(response).to have_http_status(400) + post api(route, user), branch: 'new_design3', ref: 'foo' + + expect(response).to have_gitlab_http_status(400) expect(json_response['message']).to eq('Invalid reference name') end end - describe "DELETE /projects/:id/repository/branches/:branch" do + describe 'DELETE /projects/:id/repository/branches/:branch' do before do allow_any_instance_of(Repository).to receive(:rm_branch).and_return(true) end - it "removes branch" do + it 'removes branch' do delete api("/projects/#{project.id}/repository/branches/#{branch_name}", user) - expect(response).to have_http_status(204) + expect(response).to have_gitlab_http_status(204) end - it "removes a branch with dots in the branch name" do + it 'removes a branch with dots in the branch name' do delete api("/projects/#{project.id}/repository/branches/#{branch_with_dot.name}", user) - expect(response).to have_http_status(204) + expect(response).to have_gitlab_http_status(204) end it 'returns 404 if branch not exists' do delete api("/projects/#{project.id}/repository/branches/foobar", user) - expect(response).to have_http_status(404) + + expect(response).to have_gitlab_http_status(404) end end - describe "DELETE /projects/:id/repository/merged_branches" do + describe 'DELETE /projects/:id/repository/merged_branches' do before do allow_any_instance_of(Repository).to receive(:rm_branch).and_return(true) end @@ -416,13 +509,14 @@ describe API::Branches do it 'returns 202 with json body' do delete api("/projects/#{project.id}/repository/merged_branches", user) - expect(response).to have_http_status(202) + expect(response).to have_gitlab_http_status(202) expect(json_response['message']).to eql('202 Accepted') end it 'returns a 403 error if guest' do delete api("/projects/#{project.id}/repository/merged_branches", guest) - expect(response).to have_http_status(403) + + expect(response).to have_gitlab_http_status(403) end end end diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index 656f098aea8..1d7adc6ac45 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -510,7 +510,7 @@ describe API::Groups do describe "POST /groups/:id/projects/:project_id" do let(:project) { create(:empty_project) } - let(:project_path) { project.full_path.gsub('/', '%2F') } + let(:project_path) { CGI.escape(project.full_path) } before(:each) do allow_any_instance_of(Projects::TransferService) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 79e7e1a95df..6ed68fcff09 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -768,7 +768,7 @@ describe API::Projects do dot_user = create(:user, username: 'dot.user') project = create(:empty_project, creator_id: dot_user.id, namespace: dot_user.namespace) - get api("/projects/#{dot_user.namespace.name}%2F#{project.path}", dot_user) + get api("/projects/#{CGI.escape(project.full_path)}", dot_user) expect(response).to have_http_status(200) expect(json_response['name']).to eq(project.name) end diff --git a/spec/requests/api/v3/groups_spec.rb b/spec/requests/api/v3/groups_spec.rb index 63c5707b2e4..5cdc528e190 100644 --- a/spec/requests/api/v3/groups_spec.rb +++ b/spec/requests/api/v3/groups_spec.rb @@ -502,7 +502,7 @@ describe API::V3::Groups do describe "POST /groups/:id/projects/:project_id" do let(:project) { create(:empty_project) } - let(:project_path) { "#{project.namespace.path}%2F#{project.path}" } + let(:project_path) { CGI.escape(project.full_path) } before(:each) do allow_any_instance_of(Projects::TransferService) diff --git a/spec/requests/api/v3/projects_spec.rb b/spec/requests/api/v3/projects_spec.rb index af44ffa2331..bbfcaab1ea1 100644 --- a/spec/requests/api/v3/projects_spec.rb +++ b/spec/requests/api/v3/projects_spec.rb @@ -720,7 +720,7 @@ describe API::V3::Projects do dot_user = create(:user, username: 'dot.user') project = create(:empty_project, creator_id: dot_user.id, namespace: dot_user.namespace) - get v3_api("/projects/#{dot_user.namespace.name}%2F#{project.path}", dot_user) + get v3_api("/projects/#{CGI.escape(project.full_path)}", dot_user) expect(response).to have_http_status(200) expect(json_response['name']).to eq(project.name) end diff --git a/spec/support/api/schema_matcher.rb b/spec/support/api/schema_matcher.rb index dff0dfba675..67599f77adb 100644 --- a/spec/support/api/schema_matcher.rb +++ b/spec/support/api/schema_matcher.rb @@ -5,7 +5,14 @@ end RSpec::Matchers.define :match_response_schema do |schema, **options| match do |response| - JSON::Validator.validate!(schema_path(schema), response.body, options) + @errors = JSON::Validator.fully_validate(schema_path(schema), response.body, options) + + @errors.empty? + end + + failure_message do |response| + "didn't match the schema defined by #{schema_path(schema)}" \ + " The validation errors were:\n#{@errors.join("\n")}" end end diff --git a/spec/support/api/status_shared_examples.rb b/spec/support/api/status_shared_examples.rb deleted file mode 100644 index 3481749a7f0..00000000000 --- a/spec/support/api/status_shared_examples.rb +++ /dev/null @@ -1,42 +0,0 @@ -# Specs for status checking. -# -# Requires an API request: -# let(:request) { get api("/projects/#{project.id}/repository/branches", user) } -shared_examples_for '400 response' do - before do - # Fires the request - request - end - - it 'returns 400' do - expect(response).to have_http_status(400) - end -end - -shared_examples_for '403 response' do - before do - # Fires the request - request - end - - it 'returns 403' do - expect(response).to have_http_status(403) - end -end - -shared_examples_for '404 response' do - let(:message) { nil } - before do - # Fires the request - request - end - - it 'returns 404' do - expect(response).to have_http_status(404) - expect(json_response).to be_an Object - - if message.present? - expect(json_response['message']).to eq(message) - end - end -end diff --git a/spec/support/shared_examples/requests/api/status_shared_examples.rb b/spec/support/shared_examples/requests/api/status_shared_examples.rb new file mode 100644 index 00000000000..226277411d6 --- /dev/null +++ b/spec/support/shared_examples/requests/api/status_shared_examples.rb @@ -0,0 +1,42 @@ +# Specs for status checking. +# +# Requires an API request: +# let(:request) { get api("/projects/#{project.id}/repository/branches", user) } +shared_examples_for '400 response' do + before do + # Fires the request + request + end + + it 'returns 400' do + expect(response).to have_gitlab_http_status(400) + end +end + +shared_examples_for '403 response' do + before do + # Fires the request + request + end + + it 'returns 403' do + expect(response).to have_gitlab_http_status(403) + end +end + +shared_examples_for '404 response' do + let(:message) { nil } + before do + # Fires the request + request + end + + it 'returns 404' do + expect(response).to have_gitlab_http_status(404) + expect(json_response).to be_an Object + + if message.present? + expect(json_response['message']).to eq(message) + end + end +end -- cgit v1.2.1 From 4e3e0dc8d4d742e388372e969324483ab51a3363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 27 Jul 2017 13:01:14 +0200 Subject: DRY the branches API requirements definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- changelogs/unreleased/rc-fix-branches-api-endpoint.yml | 2 +- lib/api/api.rb | 3 +++ lib/api/branches.rb | 12 +++++++----- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/changelogs/unreleased/rc-fix-branches-api-endpoint.yml b/changelogs/unreleased/rc-fix-branches-api-endpoint.yml index 217dfff8c63..a8f49298258 100644 --- a/changelogs/unreleased/rc-fix-branches-api-endpoint.yml +++ b/changelogs/unreleased/rc-fix-branches-api-endpoint.yml @@ -1,5 +1,5 @@ --- title: Fix the /projects/:id/repository/branches endpoint to handle dots in the branch name when the project full patch contains a `/` -merge_request: +merge_request: 13115 author: diff --git a/lib/api/api.rb b/lib/api/api.rb index 3bdafa3edc1..045a0db1842 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -86,6 +86,9 @@ module API helpers ::API::Helpers helpers ::API::Helpers::CommonHelpers + NO_SLASH_URL_PART_REGEX = %r{[^/]+} + PROJECT_ENDPOINT_REQUIREMENTS = { id: NO_SLASH_URL_PART_REGEX }.freeze + # Keep in alphabetical order mount ::API::AccessRequests mount ::API::AwardEmoji diff --git a/lib/api/branches.rb b/lib/api/branches.rb index cc81f3898ab..9dd60d1833b 100644 --- a/lib/api/branches.rb +++ b/lib/api/branches.rb @@ -4,12 +4,14 @@ module API class Branches < Grape::API include PaginationParams + BRANCH_ENDPOINT_REQUIREMENTS = API::PROJECT_ENDPOINT_REQUIREMENTS.merge(branch: API::NO_SLASH_URL_PART_REGEX) + before { authorize! :download_code, user_project } params do requires :id, type: String, desc: 'The ID of a project' end - resource :projects, requirements: { id: %r{[^/]+} } do + resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do desc 'Get a project repository branches' do success Entities::RepoBranch end @@ -28,7 +30,7 @@ module API params do requires :branch, type: String, desc: 'The name of the branch' end - get ':id/repository/branches/:branch', requirements: { id: %r{[^/]+}, branch: %r{[^/]+} } do + get ':id/repository/branches/:branch', requirements: BRANCH_ENDPOINT_REQUIREMENTS do branch = user_project.repository.find_branch(params[:branch]) not_found!("Branch") unless branch @@ -46,7 +48,7 @@ module API optional :developers_can_push, type: Boolean, desc: 'Flag if developers can push to that branch' optional :developers_can_merge, type: Boolean, desc: 'Flag if developers can merge to that branch' end - put ':id/repository/branches/:branch/protect', requirements: { id: %r{[^/]+}, branch: %r{[^/]+} } do + put ':id/repository/branches/:branch/protect', requirements: BRANCH_ENDPOINT_REQUIREMENTS do authorize_admin_project branch = user_project.repository.find_branch(params[:branch]) @@ -81,7 +83,7 @@ module API params do requires :branch, type: String, desc: 'The name of the branch' end - put ':id/repository/branches/:branch/unprotect', requirements: { id: %r{[^/]+}, branch: %r{[^/]+} } do + put ':id/repository/branches/:branch/unprotect', requirements: BRANCH_ENDPOINT_REQUIREMENTS do authorize_admin_project branch = user_project.repository.find_branch(params[:branch]) @@ -118,7 +120,7 @@ module API params do requires :branch, type: String, desc: 'The name of the branch' end - delete ':id/repository/branches/:branch', requirements: { id: %r{[^/]+}, branch: %r{[^/]+} } do + delete ':id/repository/branches/:branch', requirements: BRANCH_ENDPOINT_REQUIREMENTS do authorize_push_project result = DeleteBranchService.new(user_project, current_user) -- cgit v1.2.1 From 7e113b6824628a7e82e93965300f2ce3b9aadf4b Mon Sep 17 00:00:00 2001 From: Keifer Furzland Date: Wed, 28 Jun 2017 23:13:10 -0500 Subject: Remove superfluous type defs in specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/controllers/sent_notifications_controller_spec.rb | 2 +- spec/features/abuse_report_spec.rb | 2 +- spec/features/admin/admin_abuse_reports_spec.rb | 2 +- spec/features/admin/admin_appearance_spec.rb | 2 +- spec/features/admin/admin_broadcast_messages_spec.rb | 2 +- spec/features/admin/admin_cohorts_spec.rb | 2 +- spec/features/admin/admin_deploy_keys_spec.rb | 2 +- .../admin/admin_disables_git_access_protocol_spec.rb | 2 +- spec/features/admin/admin_disables_two_factor_spec.rb | 2 +- spec/features/admin/admin_groups_spec.rb | 2 +- spec/features/admin/admin_health_check_spec.rb | 2 +- spec/features/admin/admin_hook_logs_spec.rb | 2 +- spec/features/admin/admin_hooks_spec.rb | 2 +- spec/features/admin/admin_manage_applications_spec.rb | 2 +- spec/features/admin/admin_projects_spec.rb | 2 +- spec/features/admin/admin_requests_profiles_spec.rb | 2 +- spec/features/admin/admin_settings_spec.rb | 2 +- spec/features/admin/admin_users_impersonation_tokens_spec.rb | 2 +- spec/features/admin/admin_users_spec.rb | 2 +- spec/features/admin/admin_uses_repository_checks_spec.rb | 2 +- spec/features/atom/dashboard_issues_spec.rb | 2 +- spec/features/atom/dashboard_spec.rb | 2 +- spec/features/atom/issues_spec.rb | 2 +- spec/features/atom/users_spec.rb | 2 +- spec/features/boards/add_issues_modal_spec.rb | 2 +- spec/features/boards/boards_spec.rb | 2 +- spec/features/boards/issue_ordering_spec.rb | 2 +- spec/features/boards/keyboard_shortcut_spec.rb | 2 +- spec/features/boards/modal_filter_spec.rb | 2 +- spec/features/boards/new_issue_spec.rb | 2 +- spec/features/boards/sidebar_spec.rb | 2 +- spec/features/boards/sub_group_project_spec.rb | 2 +- spec/features/calendar_spec.rb | 2 +- spec/features/commits_spec.rb | 6 +++--- spec/features/copy_as_gfm_spec.rb | 2 +- spec/features/cycle_analytics_spec.rb | 2 +- spec/features/dashboard/active_tab_spec.rb | 2 +- spec/features/dashboard/archived_projects_spec.rb | 2 +- spec/features/dashboard/datetime_on_tooltips_spec.rb | 2 +- spec/features/dashboard/group_spec.rb | 2 +- spec/features/dashboard/help_spec.rb | 2 +- spec/features/dashboard/issuables_counter_spec.rb | 2 +- spec/features/dashboard/issues_filter_spec.rb | 2 +- spec/features/dashboard/issues_spec.rb | 2 +- spec/features/dashboard/label_filter_spec.rb | 2 +- spec/features/dashboard/milestone_filter_spec.rb | 2 +- spec/features/dashboard/milestone_tabs_spec.rb | 2 +- spec/features/dashboard/milestones_spec.rb | 2 +- .../features/dashboard/project_member_activity_index_spec.rb | 2 +- spec/features/dashboard/shortcuts_spec.rb | 2 +- spec/features/dashboard/snippets_spec.rb | 2 +- spec/features/dashboard/user_filters_projects_spec.rb | 2 +- spec/features/discussion_comments/commit_spec.rb | 2 +- spec/features/discussion_comments/issue_spec.rb | 2 +- spec/features/discussion_comments/merge_request_spec.rb | 2 +- spec/features/discussion_comments/snippets_spec.rb | 2 +- spec/features/expand_collapse_diffs_spec.rb | 2 +- spec/features/explore/groups_list_spec.rb | 2 +- spec/features/explore/new_menu_spec.rb | 2 +- spec/features/gitlab_flavored_markdown_spec.rb | 4 ++-- spec/features/global_search_spec.rb | 2 +- spec/features/groups/activity_spec.rb | 2 +- spec/features/groups/group_name_toggle_spec.rb | 2 +- spec/features/groups/group_settings_spec.rb | 2 +- spec/features/groups/issues_spec.rb | 2 +- spec/features/groups/labels/edit_spec.rb | 2 +- spec/features/groups/labels/subscription_spec.rb | 2 +- spec/features/groups/members/leave_group_spec.rb | 2 +- spec/features/groups/members/list_members_spec.rb | 2 +- spec/features/groups/members/manage_access_requests_spec.rb | 2 +- spec/features/groups/members/manage_members.rb | 2 +- spec/features/groups/members/request_access_spec.rb | 2 +- spec/features/groups/members/sort_members_spec.rb | 2 +- spec/features/groups/merge_requests_spec.rb | 2 +- spec/features/groups/milestone_spec.rb | 2 +- spec/features/groups/show_spec.rb | 2 +- spec/features/groups_spec.rb | 2 +- spec/features/help_pages_spec.rb | 2 +- spec/features/issuables/close_reopen_report_toggle_spec.rb | 2 +- spec/features/issuables/default_sort_order_spec.rb | 2 +- spec/features/issuables/issuable_list_spec.rb | 2 +- spec/features/issues/award_emoji_spec.rb | 2 +- spec/features/issues/award_spec.rb | 2 +- spec/features/issues/bulk_assignment_labels_spec.rb | 2 +- spec/features/issues/create_branch_merge_request_spec.rb | 2 +- .../create_issue_for_discussions_in_merge_request_spec.rb | 2 +- ...eate_issue_for_single_discussion_in_merge_request_spec.rb | 2 +- .../issues/filtered_search/dropdown_assignee_spec.rb | 2 +- spec/features/issues/filtered_search/dropdown_author_spec.rb | 2 +- spec/features/issues/filtered_search/dropdown_hint_spec.rb | 2 +- spec/features/issues/filtered_search/dropdown_label_spec.rb | 2 +- .../issues/filtered_search/dropdown_milestone_spec.rb | 2 +- spec/features/issues/filtered_search/filter_issues_spec.rb | 2 +- spec/features/issues/filtered_search/recent_searches_spec.rb | 2 +- spec/features/issues/filtered_search/search_bar_spec.rb | 2 +- spec/features/issues/filtered_search/visual_tokens_spec.rb | 2 +- spec/features/issues/form_spec.rb | 2 +- spec/features/issues/gfm_autocomplete_spec.rb | 2 +- spec/features/issues/group_label_sidebar_spec.rb | 2 +- spec/features/issues/issue_detail_spec.rb | 2 +- spec/features/issues/issue_sidebar_spec.rb | 2 +- spec/features/issues/markdown_toolbar_spec.rb | 2 +- spec/features/issues/note_polling_spec.rb | 2 +- spec/features/issues/notes_on_issues_spec.rb | 2 +- spec/features/issues/spam_issues_spec.rb | 2 +- spec/features/issues/todo_spec.rb | 2 +- spec/features/issues/user_uses_slash_commands_spec.rb | 2 +- spec/features/issues_spec.rb | 2 +- spec/features/login_spec.rb | 2 +- spec/features/markdown_spec.rb | 2 +- spec/features/merge_requests/assign_issues_spec.rb | 2 +- spec/features/merge_requests/award_spec.rb | 2 +- .../check_if_mergeable_with_unresolved_discussions_spec.rb | 2 +- spec/features/merge_requests/closes_issues_spec.rb | 2 +- spec/features/merge_requests/conflicts_spec.rb | 2 +- spec/features/merge_requests/create_new_mr_spec.rb | 2 +- spec/features/merge_requests/deleted_source_branch_spec.rb | 2 +- spec/features/merge_requests/diff_notes_avatars_spec.rb | 2 +- spec/features/merge_requests/diff_notes_resolve_spec.rb | 2 +- spec/features/merge_requests/diffs_spec.rb | 2 +- spec/features/merge_requests/discussion_spec.rb | 2 +- spec/features/merge_requests/edit_mr_spec.rb | 2 +- spec/features/merge_requests/filter_by_labels_spec.rb | 2 +- spec/features/merge_requests/filter_by_milestone_spec.rb | 2 +- spec/features/merge_requests/filter_merge_requests_spec.rb | 2 +- spec/features/merge_requests/form_spec.rb | 2 +- .../merge_requests/merge_commit_message_toggle_spec.rb | 2 +- .../merge_requests/merge_immediately_with_pipeline_spec.rb | 2 +- .../merge_requests/merge_when_pipeline_succeeds_spec.rb | 2 +- spec/features/merge_requests/mini_pipeline_graph_spec.rb | 2 +- .../only_allow_merge_if_build_succeeds_spec.rb | 2 +- spec/features/merge_requests/pipelines_spec.rb | 2 +- spec/features/merge_requests/reset_filters_spec.rb | 2 +- spec/features/merge_requests/target_branch_spec.rb | 2 +- .../merge_requests/toggle_whitespace_changes_spec.rb | 2 +- spec/features/merge_requests/toggler_behavior_spec.rb | 2 +- spec/features/merge_requests/update_merge_requests_spec.rb | 2 +- .../merge_requests/user_lists_merge_requests_spec.rb | 2 +- .../features/merge_requests/user_uses_slash_commands_spec.rb | 2 +- spec/features/merge_requests/versions_spec.rb | 2 +- spec/features/merge_requests/widget_deployments_spec.rb | 2 +- spec/features/merge_requests/widget_spec.rb | 2 +- spec/features/merge_requests/wip_message_spec.rb | 2 +- spec/features/milestone_spec.rb | 2 +- spec/features/milestones/show_spec.rb | 2 +- spec/features/password_reset_spec.rb | 2 +- spec/features/profile_spec.rb | 2 +- spec/features/profiles/account_spec.rb | 2 +- spec/features/profiles/chat_names_spec.rb | 2 +- spec/features/profiles/keys_spec.rb | 2 +- spec/features/profiles/oauth_applications_spec.rb | 2 +- spec/features/profiles/password_spec.rb | 2 +- spec/features/profiles/personal_access_tokens_spec.rb | 2 +- spec/features/profiles/preferences_spec.rb | 2 +- .../profiles/user_changes_notified_of_own_activity_spec.rb | 2 +- spec/features/projects/artifacts/browse_spec.rb | 2 +- spec/features/projects/artifacts/download_spec.rb | 2 +- spec/features/projects/artifacts/file_spec.rb | 2 +- spec/features/projects/artifacts/raw_spec.rb | 2 +- .../projects/blobs/blob_line_permalink_updater_spec.rb | 2 +- spec/features/projects/blobs/blob_show_spec.rb | 2 +- spec/features/projects/blobs/edit_spec.rb | 2 +- spec/features/projects/blobs/shortcuts_blob_spec.rb | 2 +- spec/features/projects/branches/download_buttons_spec.rb | 2 +- .../projects/branches/new_branch_ref_dropdown_spec.rb | 2 +- spec/features/projects/branches_spec.rb | 2 +- spec/features/projects/commit/mini_pipeline_graph_spec.rb | 2 +- spec/features/projects/deploy_keys_spec.rb | 2 +- .../developer_views_empty_project_instructions_spec.rb | 2 +- spec/features/projects/diffs/diff_show_spec.rb | 2 +- spec/features/projects/edit_spec.rb | 2 +- .../projects/environments/environment_metrics_spec.rb | 2 +- spec/features/projects/environments/environment_spec.rb | 2 +- spec/features/projects/environments/environments_spec.rb | 2 +- spec/features/projects/features_visibility_spec.rb | 2 +- spec/features/projects/files/browse_files_spec.rb | 2 +- spec/features/projects/files/creating_a_file_spec.rb | 2 +- spec/features/projects/files/dockerfile_dropdown_spec.rb | 2 +- spec/features/projects/files/download_buttons_spec.rb | 2 +- spec/features/projects/files/edit_file_soft_wrap_spec.rb | 2 +- spec/features/projects/files/editing_a_file_spec.rb | 2 +- .../files/files_sort_submodules_with_folders_spec.rb | 2 +- spec/features/projects/files/find_file_keyboard_spec.rb | 2 +- spec/features/projects/files/find_files_spec.rb | 2 +- spec/features/projects/files/gitignore_dropdown_spec.rb | 2 +- spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb | 2 +- .../files/project_owner_creates_license_file_spec.rb | 2 +- ...sees_link_to_create_license_file_in_empty_project_spec.rb | 2 +- spec/features/projects/gfm_autocomplete_load_spec.rb | 2 +- spec/features/projects/group_links_spec.rb | 2 +- spec/features/projects/import_export/export_file_spec.rb | 2 +- spec/features/projects/import_export/import_file_spec.rb | 2 +- .../projects/import_export/namespace_export_file_spec.rb | 2 +- spec/features/projects/issuable_templates_spec.rb | 2 +- spec/features/projects/jobs_spec.rb | 2 +- .../projects/labels/issues_sorted_by_priority_spec.rb | 2 +- spec/features/projects/labels/subscription_spec.rb | 2 +- spec/features/projects/labels/update_prioritization_spec.rb | 2 +- spec/features/projects/main/download_buttons_spec.rb | 2 +- .../projects/members/anonymous_user_sees_members_spec.rb | 2 +- spec/features/projects/members/group_links_spec.rb | 2 +- .../members/group_member_cannot_leave_group_project_spec.rb | 2 +- ...member_cannot_request_access_to_his_group_project_spec.rb | 2 +- spec/features/projects/members/group_members_spec.rb | 2 +- .../group_requester_cannot_request_access_to_project_spec.rb | 2 +- spec/features/projects/members/list_spec.rb | 2 +- .../members/master_adds_member_with_expiration_date_spec.rb | 2 +- .../projects/members/master_manages_access_requests_spec.rb | 2 +- .../member_cannot_request_access_to_his_project_spec.rb | 2 +- spec/features/projects/members/member_leaves_project_spec.rb | 2 +- .../projects/members/owner_cannot_leave_project_spec.rb | 2 +- .../owner_cannot_request_access_to_his_project_spec.rb | 2 +- spec/features/projects/members/sorting_spec.rb | 2 +- spec/features/projects/members/user_requests_access_spec.rb | 2 +- spec/features/projects/milestones/milestone_spec.rb | 2 +- spec/features/projects/milestones/milestones_sorting_spec.rb | 2 +- spec/features/projects/milestones/new_spec.rb | 2 +- spec/features/projects/pages_spec.rb | 2 +- spec/features/projects/pipeline_schedules_spec.rb | 2 +- spec/features/projects/pipelines/pipeline_spec.rb | 2 +- spec/features/projects/pipelines/pipelines_spec.rb | 2 +- spec/features/projects/project_settings_spec.rb | 2 +- spec/features/projects/ref_switcher_spec.rb | 2 +- spec/features/projects/services/jira_service_spec.rb | 2 +- .../projects/services/mattermost_slash_command_spec.rb | 2 +- spec/features/projects/services/slack_service_spec.rb | 2 +- spec/features/projects/services/slack_slash_command_spec.rb | 2 +- spec/features/projects/settings/integration_settings_spec.rb | 2 +- .../projects/settings/merge_requests_settings_spec.rb | 2 +- spec/features/projects/settings/pipelines_settings_spec.rb | 2 +- spec/features/projects/settings/repository_settings_spec.rb | 2 +- spec/features/projects/settings/visibility_settings_spec.rb | 2 +- spec/features/projects/shortcuts_spec.rb | 2 +- spec/features/projects/snippets/create_snippet_spec.rb | 2 +- spec/features/projects/snippets/show_spec.rb | 2 +- spec/features/projects/snippets_spec.rb | 2 +- spec/features/projects/sub_group_issuables_spec.rb | 2 +- spec/features/projects/tags/download_buttons_spec.rb | 2 +- spec/features/projects/wiki/markdown_preview_spec.rb | 2 +- spec/features/projects/wiki/shortcuts_spec.rb | 2 +- .../features/projects/wiki/user_git_access_wiki_page_spec.rb | 2 +- spec/features/projects/wiki/user_updates_wiki_page_spec.rb | 2 +- .../projects/wiki/user_views_project_wiki_page_spec.rb | 2 +- .../projects/wiki/user_views_wiki_in_project_page_spec.rb | 2 +- spec/features/projects_spec.rb | 2 +- spec/features/protected_branches_spec.rb | 2 +- spec/features/protected_tags_spec.rb | 2 +- spec/features/raven_js_spec.rb | 2 +- spec/features/reportable_note/commit_spec.rb | 2 +- spec/features/reportable_note/issue_spec.rb | 2 +- spec/features/reportable_note/merge_request_spec.rb | 2 +- spec/features/reportable_note/snippets_spec.rb | 2 +- spec/features/search_spec.rb | 4 ++-- spec/features/security/admin_access_spec.rb | 2 +- spec/features/security/dashboard_access_spec.rb | 2 +- spec/features/security/group/internal_access_spec.rb | 2 +- spec/features/security/group/private_access_spec.rb | 2 +- spec/features/security/group/public_access_spec.rb | 2 +- spec/features/security/profile_access_spec.rb | 2 +- spec/features/security/project/internal_access_spec.rb | 2 +- spec/features/security/project/private_access_spec.rb | 2 +- spec/features/security/project/public_access_spec.rb | 2 +- .../security/project/snippet/internal_access_spec.rb | 2 +- .../features/security/project/snippet/private_access_spec.rb | 2 +- spec/features/security/project/snippet/public_access_spec.rb | 2 +- spec/features/signup_spec.rb | 2 +- spec/features/snippets/explore_spec.rb | 2 +- spec/features/snippets/internal_snippet_spec.rb | 2 +- spec/features/snippets/notes_on_personal_snippets_spec.rb | 2 +- spec/features/snippets/public_snippets_spec.rb | 2 +- spec/features/snippets/search_snippets_spec.rb | 2 +- spec/features/snippets/show_spec.rb | 2 +- spec/features/snippets/user_creates_snippet_spec.rb | 2 +- spec/features/snippets/user_deletes_snippet_spec.rb | 2 +- spec/features/snippets/user_edits_snippet_spec.rb | 2 +- spec/features/snippets/user_snippets_spec.rb | 2 +- spec/features/snippets_spec.rb | 2 +- spec/features/tags/master_creates_tag_spec.rb | 2 +- spec/features/tags/master_deletes_tag_spec.rb | 2 +- spec/features/tags/master_updates_tag_spec.rb | 2 +- spec/features/tags/master_views_tags_spec.rb | 2 +- spec/features/task_lists_spec.rb | 4 ++-- spec/features/triggers_spec.rb | 2 +- spec/features/unsubscribe_links_spec.rb | 2 +- spec/features/uploads/user_uploads_avatar_to_group_spec.rb | 2 +- spec/features/uploads/user_uploads_avatar_to_profile_spec.rb | 2 +- spec/features/uploads/user_uploads_file_to_note_spec.rb | 2 +- spec/features/users/projects_spec.rb | 2 +- spec/features/users/snippets_spec.rb | 2 +- spec/features/users_spec.rb | 2 +- spec/helpers/namespaces_helper_spec.rb | 2 +- spec/models/abuse_report_spec.rb | 2 +- spec/models/appearance_spec.rb | 2 +- spec/models/blob_viewer/base_spec.rb | 2 +- spec/models/blob_viewer/changelog_spec.rb | 2 +- spec/models/blob_viewer/composer_json_spec.rb | 2 +- spec/models/blob_viewer/gemspec_spec.rb | 2 +- spec/models/blob_viewer/gitlab_ci_yml_spec.rb | 2 +- spec/models/blob_viewer/license_spec.rb | 2 +- spec/models/blob_viewer/package_json_spec.rb | 2 +- spec/models/blob_viewer/podspec_json_spec.rb | 2 +- spec/models/blob_viewer/podspec_spec.rb | 2 +- spec/models/blob_viewer/readme_spec.rb | 2 +- spec/models/blob_viewer/route_map_spec.rb | 2 +- spec/models/blob_viewer/server_side_spec.rb | 2 +- spec/models/chat_team_spec.rb | 2 +- spec/models/ci/build_spec.rb | 12 ++++++------ spec/models/ci/legacy_stage_spec.rb | 2 +- spec/models/commit_status_spec.rb | 2 +- spec/models/concerns/discussion_on_diff_spec.rb | 2 +- spec/models/concerns/noteable_spec.rb | 2 +- spec/models/cycle_analytics/code_spec.rb | 2 +- spec/models/cycle_analytics/plan_spec.rb | 2 +- spec/models/cycle_analytics/production_spec.rb | 2 +- spec/models/cycle_analytics/review_spec.rb | 2 +- spec/models/cycle_analytics/staging_spec.rb | 2 +- spec/models/cycle_analytics/test_spec.rb | 2 +- spec/models/diff_discussion_spec.rb | 2 +- spec/models/diff_viewer/base_spec.rb | 2 +- spec/models/diff_viewer/server_side_spec.rb | 2 +- spec/models/discussion_spec.rb | 2 +- spec/models/merge_request_diff_commit_spec.rb | 2 +- spec/models/merge_request_diff_file_spec.rb | 2 +- spec/models/notification_setting_spec.rb | 6 +++--- .../mattermost_slash_commands_service_spec.rb | 2 +- .../project_services/slack_slash_commands_service_spec.rb | 2 +- spec/models/protected_branch/merge_access_level_spec.rb | 2 +- spec/models/protected_branch/push_access_level_spec.rb | 2 +- spec/models/release_spec.rb | 2 +- spec/models/sent_notification_spec.rb | 2 +- spec/models/timelog_spec.rb | 2 +- spec/models/upload_spec.rb | 2 +- spec/models/user_agent_detail_spec.rb | 2 +- spec/policies/ci/build_policy_spec.rb | 2 +- spec/policies/ci/trigger_policy_spec.rb | 2 +- spec/routing/environments_spec.rb | 2 +- spec/support/json_response_helpers.rb | 2 +- spec/views/ci/status/_badge.html.haml_spec.rb | 2 +- spec/views/projects/_home_panel.html.haml_spec.rb | 2 +- spec/views/projects/blob/_viewer.html.haml_spec.rb | 2 +- spec/views/projects/commit/_commit_box.html.haml_spec.rb | 2 +- spec/views/projects/commit/show.html.haml_spec.rb | 2 +- spec/views/projects/diffs/_viewer.html.haml_spec.rb | 2 +- spec/views/projects/jobs/show.html.haml_spec.rb | 2 +- .../merge_requests/creations/_new_submit.html.haml_spec.rb | 2 +- .../projects/notes/_more_actions_dropdown.html.haml_spec.rb | 2 +- spec/views/projects/pipelines/_stage.html.haml_spec.rb | 2 +- .../projects/registry/repositories/index.html.haml_spec.rb | 2 +- spec/views/projects/tags/index.html.haml_spec.rb | 2 +- 349 files changed, 361 insertions(+), 361 deletions(-) diff --git a/spec/controllers/sent_notifications_controller_spec.rb b/spec/controllers/sent_notifications_controller_spec.rb index c8771eda313..5d2734b8827 100644 --- a/spec/controllers/sent_notifications_controller_spec.rb +++ b/spec/controllers/sent_notifications_controller_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe SentNotificationsController, type: :controller do +describe SentNotificationsController do let(:user) { create(:user) } let(:project) { create(:empty_project) } let(:sent_notification) { create(:sent_notification, project: project, noteable: issue, recipient: user) } diff --git a/spec/features/abuse_report_spec.rb b/spec/features/abuse_report_spec.rb index f26d3a6a72f..091fdcec3db 100644 --- a/spec/features/abuse_report_spec.rb +++ b/spec/features/abuse_report_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Abuse reports', feature: true do +feature 'Abuse reports' do let(:another_user) { create(:user) } before do diff --git a/spec/features/admin/admin_abuse_reports_spec.rb b/spec/features/admin/admin_abuse_reports_spec.rb index 8672c009f90..2144f6ba635 100644 --- a/spec/features/admin/admin_abuse_reports_spec.rb +++ b/spec/features/admin/admin_abuse_reports_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Admin::AbuseReports", feature: true, js: true do +describe "Admin::AbuseReports", js: true do let(:user) { create(:user) } context 'as an admin' do diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb index 2f90f668e89..5f3a37c1dcc 100644 --- a/spec/features/admin/admin_appearance_spec.rb +++ b/spec/features/admin/admin_appearance_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Admin Appearance', feature: true do +feature 'Admin Appearance' do let!(:appearance) { create(:appearance) } scenario 'Create new appearance' do diff --git a/spec/features/admin/admin_broadcast_messages_spec.rb b/spec/features/admin/admin_broadcast_messages_spec.rb index e55308e393b..cbccf370514 100644 --- a/spec/features/admin/admin_broadcast_messages_spec.rb +++ b/spec/features/admin/admin_broadcast_messages_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Admin Broadcast Messages', feature: true do +feature 'Admin Broadcast Messages' do before do sign_in(create(:admin)) create(:broadcast_message, :expired, message: 'Migration to new server') diff --git a/spec/features/admin/admin_cohorts_spec.rb b/spec/features/admin/admin_cohorts_spec.rb index 6840456e509..bca52bf674c 100644 --- a/spec/features/admin/admin_cohorts_spec.rb +++ b/spec/features/admin/admin_cohorts_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Admin cohorts page', feature: true do +feature 'Admin cohorts page' do before do sign_in(create(:admin)) end diff --git a/spec/features/admin/admin_deploy_keys_spec.rb b/spec/features/admin/admin_deploy_keys_spec.rb index aaeaaa829e1..241c7cbc34e 100644 --- a/spec/features/admin/admin_deploy_keys_spec.rb +++ b/spec/features/admin/admin_deploy_keys_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -RSpec.describe 'admin deploy keys', type: :feature do +RSpec.describe 'admin deploy keys' do let!(:deploy_key) { create(:deploy_key, public: true) } let!(:another_deploy_key) { create(:another_deploy_key, public: true) } diff --git a/spec/features/admin/admin_disables_git_access_protocol_spec.rb b/spec/features/admin/admin_disables_git_access_protocol_spec.rb index e2280b6e3b1..931f4ec3d24 100644 --- a/spec/features/admin/admin_disables_git_access_protocol_spec.rb +++ b/spec/features/admin/admin_disables_git_access_protocol_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Admin disables Git access protocol', feature: true do +feature 'Admin disables Git access protocol' do include StubENV let(:project) { create(:empty_project, :empty_repo) } diff --git a/spec/features/admin/admin_disables_two_factor_spec.rb b/spec/features/admin/admin_disables_two_factor_spec.rb index 15dc6b6c234..e214ae6b78d 100644 --- a/spec/features/admin/admin_disables_two_factor_spec.rb +++ b/spec/features/admin/admin_disables_two_factor_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Admin disables 2FA for a user', feature: true do +feature 'Admin disables 2FA for a user' do scenario 'successfully', js: true do sign_in(create(:admin)) user = create(:user, :two_factor) diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb index d15d9982884..2e1bfcdcec3 100644 --- a/spec/features/admin/admin_groups_spec.rb +++ b/spec/features/admin/admin_groups_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Admin Groups', feature: true do +feature 'Admin Groups' do include Select2Helper let(:internal) { Gitlab::VisibilityLevel::INTERNAL } diff --git a/spec/features/admin/admin_health_check_spec.rb b/spec/features/admin/admin_health_check_spec.rb index c404e054dba..106e7370a98 100644 --- a/spec/features/admin/admin_health_check_spec.rb +++ b/spec/features/admin/admin_health_check_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature "Admin Health Check", feature: true do +feature "Admin Health Check" do include StubENV before do diff --git a/spec/features/admin/admin_hook_logs_spec.rb b/spec/features/admin/admin_hook_logs_spec.rb index 94dace7a1fd..710822ac042 100644 --- a/spec/features/admin/admin_hook_logs_spec.rb +++ b/spec/features/admin/admin_hook_logs_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Admin::HookLogs', feature: true do +feature 'Admin::HookLogs' do let(:project) { create(:project) } let(:system_hook) { create(:system_hook) } let(:hook_log) { create(:web_hook_log, web_hook: system_hook, internal_error_message: 'some error') } diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb index 9a438b65e68..30fcb334b60 100644 --- a/spec/features/admin/admin_hooks_spec.rb +++ b/spec/features/admin/admin_hooks_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Admin::Hooks', feature: true do +describe 'Admin::Hooks' do before do @project = create(:project) sign_in(create(:admin)) diff --git a/spec/features/admin/admin_manage_applications_spec.rb b/spec/features/admin/admin_manage_applications_spec.rb index 2e04a82806f..c1ece123230 100644 --- a/spec/features/admin/admin_manage_applications_spec.rb +++ b/spec/features/admin/admin_manage_applications_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -RSpec.describe 'admin manage applications', feature: true do +RSpec.describe 'admin manage applications' do before do sign_in(create(:admin)) end diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb index 942cc60e5dd..9856d90bffe 100644 --- a/spec/features/admin/admin_projects_spec.rb +++ b/spec/features/admin/admin_projects_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Admin::Projects", feature: true do +describe "Admin::Projects" do include Select2Helper let(:user) { create :user } diff --git a/spec/features/admin/admin_requests_profiles_spec.rb b/spec/features/admin/admin_requests_profiles_spec.rb index bf0c21cd04a..380cd5d7703 100644 --- a/spec/features/admin/admin_requests_profiles_spec.rb +++ b/spec/features/admin/admin_requests_profiles_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Admin::RequestsProfilesController', feature: true do +describe 'Admin::RequestsProfilesController' do before do FileUtils.mkdir_p(Gitlab::RequestProfiler::PROFILES_DIR) sign_in(create(:admin)) diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index a44fa0b86d5..c1eced417cf 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Admin updates settings', feature: true do +feature 'Admin updates settings' do include StubENV before do diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb index d01722805c4..97ffc54415c 100644 --- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb +++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Admin > Users > Impersonation Tokens', feature: true, js: true do +describe 'Admin > Users > Impersonation Tokens', js: true do let(:admin) { create(:admin) } let!(:user) { create(:user) } diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index 3bc8f8aed54..e2e2b13cf8a 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Admin::Users", feature: true do +describe "Admin::Users" do let!(:user) do create(:omniauth_user, provider: 'twitter', extern_uid: '123456') end diff --git a/spec/features/admin/admin_uses_repository_checks_spec.rb b/spec/features/admin/admin_uses_repository_checks_spec.rb index 113353862be..5b3ee6ee822 100644 --- a/spec/features/admin/admin_uses_repository_checks_spec.rb +++ b/spec/features/admin/admin_uses_repository_checks_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Admin uses repository checks', feature: true do +feature 'Admin uses repository checks' do include StubENV before do diff --git a/spec/features/atom/dashboard_issues_spec.rb b/spec/features/atom/dashboard_issues_spec.rb index 711c8a710f3..5aae2dbaf91 100644 --- a/spec/features/atom/dashboard_issues_spec.rb +++ b/spec/features/atom/dashboard_issues_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Dashboard Issues Feed", feature: true do +describe "Dashboard Issues Feed" do describe "GET /issues" do let!(:user) { create(:user, email: 'private1@example.com', public_email: 'public1@example.com') } let!(:assignee) { create(:user, email: 'private2@example.com', public_email: 'public2@example.com') } diff --git a/spec/features/atom/dashboard_spec.rb b/spec/features/atom/dashboard_spec.rb index 2f4bb45d74b..321c8a2a670 100644 --- a/spec/features/atom/dashboard_spec.rb +++ b/spec/features/atom/dashboard_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Dashboard Feed", feature: true do +describe "Dashboard Feed" do describe "GET /" do let!(:user) { create(:user, name: "Jonh") } diff --git a/spec/features/atom/issues_spec.rb b/spec/features/atom/issues_spec.rb index 011fdce21d8..3eeb4d35131 100644 --- a/spec/features/atom/issues_spec.rb +++ b/spec/features/atom/issues_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Issues Feed', feature: true do +describe 'Issues Feed' do describe 'GET /issues' do let!(:user) { create(:user, email: 'private1@example.com', public_email: 'public1@example.com') } let!(:assignee) { create(:user, email: 'private2@example.com', public_email: 'public2@example.com') } diff --git a/spec/features/atom/users_spec.rb b/spec/features/atom/users_spec.rb index 44ae7204bcf..052b07689f5 100644 --- a/spec/features/atom/users_spec.rb +++ b/spec/features/atom/users_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "User Feed", feature: true do +describe "User Feed" do describe "GET /" do let!(:user) { create(:user) } diff --git a/spec/features/boards/add_issues_modal_spec.rb b/spec/features/boards/add_issues_modal_spec.rb index d883b467c67..c87469696da 100644 --- a/spec/features/boards/add_issues_modal_spec.rb +++ b/spec/features/boards/add_issues_modal_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Issue Boards add issue modal', :feature, :js do +describe 'Issue Boards add issue modal', :js do let(:project) { create(:empty_project, :public) } let(:board) { create(:board, project: project) } let(:user) { create(:user) } diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index b939fb5e89e..c3711c9b2c5 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Issue Boards', feature: true, js: true do +describe 'Issue Boards', js: true do include DragTo let(:group) { create(:group, :nested) } diff --git a/spec/features/boards/issue_ordering_spec.rb b/spec/features/boards/issue_ordering_spec.rb index 17b0da80947..f4be56a4463 100644 --- a/spec/features/boards/issue_ordering_spec.rb +++ b/spec/features/boards/issue_ordering_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Issue Boards', :feature, :js do +describe 'Issue Boards', :js do include DragTo let(:project) { create(:empty_project, :public) } diff --git a/spec/features/boards/keyboard_shortcut_spec.rb b/spec/features/boards/keyboard_shortcut_spec.rb index 8c16148023e..415eda0e058 100644 --- a/spec/features/boards/keyboard_shortcut_spec.rb +++ b/spec/features/boards/keyboard_shortcut_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Issue Boards shortcut', feature: true, js: true do +describe 'Issue Boards shortcut', js: true do let(:project) { create(:empty_project) } before do diff --git a/spec/features/boards/modal_filter_spec.rb b/spec/features/boards/modal_filter_spec.rb index ce05bb71759..1c8b9c46569 100644 --- a/spec/features/boards/modal_filter_spec.rb +++ b/spec/features/boards/modal_filter_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Issue Boards add issue modal filtering', :feature, :js do +describe 'Issue Boards add issue modal filtering', :js do let(:project) { create(:empty_project, :public) } let(:board) { create(:board, project: project) } let(:planning) { create(:label, project: project, name: 'Planning') } diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb index 6b267694201..1dbe3dbda11 100644 --- a/spec/features/boards/new_issue_spec.rb +++ b/spec/features/boards/new_issue_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Issue Boards new issue', feature: true, js: true do +describe 'Issue Boards new issue', js: true do let(:project) { create(:empty_project, :public) } let(:board) { create(:board, project: project) } let!(:list) { create(:list, board: board, position: 0) } diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index fa17ef92bbb..3f58fe1c32c 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Issue Boards', feature: true, js: true do +describe 'Issue Boards', js: true do let(:user) { create(:user) } let(:user2) { create(:user) } let(:project) { create(:empty_project, :public) } diff --git a/spec/features/boards/sub_group_project_spec.rb b/spec/features/boards/sub_group_project_spec.rb index f88bf237301..f54f2234203 100644 --- a/spec/features/boards/sub_group_project_spec.rb +++ b/spec/features/boards/sub_group_project_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Sub-group project issue boards', :feature, :js do +describe 'Sub-group project issue boards', :js do let(:group) { create(:group) } let(:nested_group_1) { create(:group, parent: group) } let(:project) { create(:empty_project, group: nested_group_1) } diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb index adbd82e3057..1e7fd7b62bd 100644 --- a/spec/features/calendar_spec.rb +++ b/spec/features/calendar_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Contributions Calendar', :feature, :js do +feature 'Contributions Calendar', :js do let(:user) { create(:user) } let(:contributed_project) { create(:empty_project, :public) } let(:issue_note) { create(:note, project: contributed_project) } diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index fb1e47994ef..479fb713297 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -77,7 +77,7 @@ describe 'Commits' do end end - describe 'Commit builds', :feature, :js do + describe 'Commit builds', :js do before do visit ci_status_path(pipeline) end @@ -152,7 +152,7 @@ describe 'Commits' do visit ci_status_path(pipeline) end - it 'Renders header', :feature, :js do + it 'Renders header', :js do expect(page).to have_content pipeline.sha[0..7] expect(page).to have_content pipeline.git_commit_message expect(page).to have_content pipeline.user.name @@ -165,7 +165,7 @@ describe 'Commits' do end end - context 'when accessing internal project with disallowed access', :feature, :js do + context 'when accessing internal project with disallowed access', :js do before do project.update( visibility_level: Gitlab::VisibilityLevel::INTERNAL, diff --git a/spec/features/copy_as_gfm_spec.rb b/spec/features/copy_as_gfm_spec.rb index 11d5a4f421f..3e6a27eafd8 100644 --- a/spec/features/copy_as_gfm_spec.rb +++ b/spec/features/copy_as_gfm_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Copy as GFM', feature: true, js: true do +describe 'Copy as GFM', js: true do include MarkupHelper include RepoHelpers include ActionView::Helpers::JavaScriptHelper diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb index f530063352a..5c60cca10b9 100644 --- a/spec/features/cycle_analytics_spec.rb +++ b/spec/features/cycle_analytics_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Cycle Analytics', feature: true, js: true do +feature 'Cycle Analytics', js: true do let(:user) { create(:user) } let(:guest) { create(:user) } let(:project) { create(:project, :repository) } diff --git a/spec/features/dashboard/active_tab_spec.rb b/spec/features/dashboard/active_tab_spec.rb index 203d206b80b..067e4337e6a 100644 --- a/spec/features/dashboard/active_tab_spec.rb +++ b/spec/features/dashboard/active_tab_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -RSpec.describe 'Dashboard Active Tab', js: true, feature: true do +RSpec.describe 'Dashboard Active Tab', js: true do before do sign_in(create(:user)) end diff --git a/spec/features/dashboard/archived_projects_spec.rb b/spec/features/dashboard/archived_projects_spec.rb index dda4d517e39..814ec0e59c7 100644 --- a/spec/features/dashboard/archived_projects_spec.rb +++ b/spec/features/dashboard/archived_projects_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -RSpec.describe 'Dashboard Archived Project', feature: true do +RSpec.describe 'Dashboard Archived Project' do let(:user) { create :user } let(:project) { create :project} let(:archived_project) { create(:project, :archived) } diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb index 8949267c82e..b6dce1b8ec4 100644 --- a/spec/features/dashboard/datetime_on_tooltips_spec.rb +++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Tooltips on .timeago dates', feature: true, js: true do +feature 'Tooltips on .timeago dates', js: true do let(:user) { create(:user) } let(:project) { create(:project, name: 'test', namespace: user.namespace) } let(:created_date) { Date.yesterday.to_time } diff --git a/spec/features/dashboard/group_spec.rb b/spec/features/dashboard/group_spec.rb index ffaefb9c632..60a16830cdc 100644 --- a/spec/features/dashboard/group_spec.rb +++ b/spec/features/dashboard/group_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -RSpec.describe 'Dashboard Group', feature: true do +RSpec.describe 'Dashboard Group' do before do sign_in(create(:user)) end diff --git a/spec/features/dashboard/help_spec.rb b/spec/features/dashboard/help_spec.rb index fa7ea4c96b6..68bfbf22736 100644 --- a/spec/features/dashboard/help_spec.rb +++ b/spec/features/dashboard/help_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -RSpec.describe 'Dashboard Help', feature: true do +RSpec.describe 'Dashboard Help' do before do sign_in(create(:user)) end diff --git a/spec/features/dashboard/issuables_counter_spec.rb b/spec/features/dashboard/issuables_counter_spec.rb index 6b666934563..ae68b0f65d5 100644 --- a/spec/features/dashboard/issuables_counter_spec.rb +++ b/spec/features/dashboard/issuables_counter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Navigation bar counter', :use_clean_rails_memory_store_caching, feature: true do +describe 'Navigation bar counter', :use_clean_rails_memory_store_caching do let(:user) { create(:user) } let(:project) { create(:empty_project, namespace: user.namespace) } let(:issue) { create(:issue, project: project) } diff --git a/spec/features/dashboard/issues_filter_spec.rb b/spec/features/dashboard/issues_filter_spec.rb index 9b84f67b555..0ce642f32f2 100644 --- a/spec/features/dashboard/issues_filter_spec.rb +++ b/spec/features/dashboard/issues_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Dashboard Issues filtering', js: true do +feature 'Dashboard Issues filtering', :js do include SortingHelper let(:user) { create(:user) } diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb index ea7a9efc326..7c0bf8de14c 100644 --- a/spec/features/dashboard/issues_spec.rb +++ b/spec/features/dashboard/issues_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -RSpec.describe 'Dashboard Issues', feature: true do +RSpec.describe 'Dashboard Issues' do let(:current_user) { create :user } let(:user) { current_user } # Shared examples depend on this being available let!(:public_project) { create(:empty_project, :public) } diff --git a/spec/features/dashboard/label_filter_spec.rb b/spec/features/dashboard/label_filter_spec.rb index 8b7dacef913..b1a207682c3 100644 --- a/spec/features/dashboard/label_filter_spec.rb +++ b/spec/features/dashboard/label_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Dashboard > label filter', feature: true, js: true do +describe 'Dashboard > label filter', js: true do let(:user) { create(:user) } let(:project) { create(:project, name: 'test', namespace: user.namespace) } let(:project2) { create(:project, name: 'test2', path: 'test2', namespace: user.namespace) } diff --git a/spec/features/dashboard/milestone_filter_spec.rb b/spec/features/dashboard/milestone_filter_spec.rb index d06497041de..c965b565ca3 100644 --- a/spec/features/dashboard/milestone_filter_spec.rb +++ b/spec/features/dashboard/milestone_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Dashboard > milestone filter', :feature, :js do +feature 'Dashboard > milestone filter', :js do include FilterItemSelectHelper let(:user) { create(:user) } diff --git a/spec/features/dashboard/milestone_tabs_spec.rb b/spec/features/dashboard/milestone_tabs_spec.rb index 8340a4f59df..cf32d705365 100644 --- a/spec/features/dashboard/milestone_tabs_spec.rb +++ b/spec/features/dashboard/milestone_tabs_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Dashboard milestone tabs', :js, :feature do +describe 'Dashboard milestone tabs', :js do let(:user) { create(:user) } let(:project) { create(:empty_project) } let!(:label) { create(:label, project: project) } diff --git a/spec/features/dashboard/milestones_spec.rb b/spec/features/dashboard/milestones_spec.rb index 7a6a448d4c2..488f7397c69 100644 --- a/spec/features/dashboard/milestones_spec.rb +++ b/spec/features/dashboard/milestones_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Dashboard > Milestones', feature: true do +feature 'Dashboard > Milestones' do describe 'as anonymous user' do before do visit dashboard_milestones_path diff --git a/spec/features/dashboard/project_member_activity_index_spec.rb b/spec/features/dashboard/project_member_activity_index_spec.rb index ea0b2e99c3e..f3b538e490e 100644 --- a/spec/features/dashboard/project_member_activity_index_spec.rb +++ b/spec/features/dashboard/project_member_activity_index_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Project member activity', feature: true, js: true do +feature 'Project member activity', js: true do let(:user) { create(:user) } let(:project) { create(:empty_project, :public, name: 'x', namespace: user.namespace) } diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb index bb29dae1bdc..5f1f0c10339 100644 --- a/spec/features/dashboard/shortcuts_spec.rb +++ b/spec/features/dashboard/shortcuts_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Dashboard shortcuts', :feature, :js do +feature 'Dashboard shortcuts', :js do context 'logged in' do before do sign_in(create(:user)) diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb index c5ae9aad9c6..c29bcc7c9e9 100644 --- a/spec/features/dashboard/snippets_spec.rb +++ b/spec/features/dashboard/snippets_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Dashboard snippets', feature: true do +describe 'Dashboard snippets' do context 'when the project has snippets' do let(:project) { create(:empty_project, :public) } let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.owner, project: project) } diff --git a/spec/features/dashboard/user_filters_projects_spec.rb b/spec/features/dashboard/user_filters_projects_spec.rb index 711d3617335..c352b6ded14 100644 --- a/spec/features/dashboard/user_filters_projects_spec.rb +++ b/spec/features/dashboard/user_filters_projects_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Dashboard > User filters projects', :feature do +describe 'Dashboard > User filters projects' do let(:user) { create(:user) } let(:project) { create(:project, name: 'Victorialand', namespace: user.namespace) } let(:user2) { create(:user) } diff --git a/spec/features/discussion_comments/commit_spec.rb b/spec/features/discussion_comments/commit_spec.rb index 26d21207678..fa83ad5d17c 100644 --- a/spec/features/discussion_comments/commit_spec.rb +++ b/spec/features/discussion_comments/commit_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Discussion Comments Merge Request', :feature, :js do +describe 'Discussion Comments Merge Request', :js do include RepoHelpers let(:user) { create(:user) } diff --git a/spec/features/discussion_comments/issue_spec.rb b/spec/features/discussion_comments/issue_spec.rb index 11dbe10e1df..f52ba9c4d09 100644 --- a/spec/features/discussion_comments/issue_spec.rb +++ b/spec/features/discussion_comments/issue_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Discussion Comments Issue', :feature, :js do +describe 'Discussion Comments Issue', :js do let(:user) { create(:user) } let(:project) { create(:empty_project) } let(:issue) { create(:issue, project: project) } diff --git a/spec/features/discussion_comments/merge_request_spec.rb b/spec/features/discussion_comments/merge_request_spec.rb index db745be6fa1..042f39f47e0 100644 --- a/spec/features/discussion_comments/merge_request_spec.rb +++ b/spec/features/discussion_comments/merge_request_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Discussion Comments Merge Request', :feature, :js do +describe 'Discussion Comments Merge Request', :js do let(:user) { create(:user) } let(:project) { create(:project) } let(:merge_request) { create(:merge_request, source_project: project) } diff --git a/spec/features/discussion_comments/snippets_spec.rb b/spec/features/discussion_comments/snippets_spec.rb index eddbd4bde9b..50ba13499d9 100644 --- a/spec/features/discussion_comments/snippets_spec.rb +++ b/spec/features/discussion_comments/snippets_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Discussion Comments Issue', :feature, :js do +describe 'Discussion Comments Issue', :js do let(:user) { create(:user) } let(:project) { create(:empty_project) } let(:snippet) { create(:project_snippet, :private, project: project, author: user) } diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb index 18c06a48111..357d86497d9 100644 --- a/spec/features/expand_collapse_diffs_spec.rb +++ b/spec/features/expand_collapse_diffs_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Expand and collapse diffs', js: true, feature: true do +feature 'Expand and collapse diffs', js: true do let(:branch) { 'expand-collapse-diffs' } let(:project) { create(:project, :repository) } diff --git a/spec/features/explore/groups_list_spec.rb b/spec/features/explore/groups_list_spec.rb index 008d12714cc..84f41eca999 100644 --- a/spec/features/explore/groups_list_spec.rb +++ b/spec/features/explore/groups_list_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Explore Groups page', :js, :feature do +describe 'Explore Groups page', :js do let!(:user) { create :user } let!(:group) { create(:group) } let!(:public_group) { create(:group, :public) } diff --git a/spec/features/explore/new_menu_spec.rb b/spec/features/explore/new_menu_spec.rb index e51d527bdf9..2cd06258e22 100644 --- a/spec/features/explore/new_menu_spec.rb +++ b/spec/features/explore/new_menu_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Top Plus Menu', feature: true, js: true do +feature 'Top Plus Menu', :js do let(:user) { create(:user) } let(:group) { create(:group) } let(:project) { create(:project, :repository, creator: user, namespace: user.namespace) } diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb index 8659a868682..300296a2b94 100644 --- a/spec/features/gitlab_flavored_markdown_spec.rb +++ b/spec/features/gitlab_flavored_markdown_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "GitLab Flavored Markdown", feature: true do +describe "GitLab Flavored Markdown" do let(:user) { create(:user) } let(:project) { create(:empty_project) } let(:issue) { create(:issue, project: project) } @@ -49,7 +49,7 @@ describe "GitLab Flavored Markdown", feature: true do end end - describe "for issues", feature: true, js: true do + describe "for issues", js: true do before do @other_issue = create(:issue, author: user, diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb index efa5e95de89..627a930c997 100644 --- a/spec/features/global_search_spec.rb +++ b/spec/features/global_search_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Global search', feature: true do +feature 'Global search' do let(:user) { create(:user) } let(:project) { create(:empty_project, namespace: user.namespace) } diff --git a/spec/features/groups/activity_spec.rb b/spec/features/groups/activity_spec.rb index 262d9434ddf..d3b25ec3d6c 100644 --- a/spec/features/groups/activity_spec.rb +++ b/spec/features/groups/activity_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Group activity page', feature: true do +feature 'Group activity page' do let(:user) { create(:group_member, :developer, user: create(:user), group: group ).user } let(:group) { create(:group) } let(:path) { activity_group_path(group) } diff --git a/spec/features/groups/group_name_toggle_spec.rb b/spec/features/groups/group_name_toggle_spec.rb index ea779a3baf0..a7b8b702ab7 100644 --- a/spec/features/groups/group_name_toggle_spec.rb +++ b/spec/features/groups/group_name_toggle_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Group name toggle', feature: true, js: true do +feature 'Group name toggle', js: true do let(:group) { create(:group) } let(:nested_group_1) { create(:group, parent: group) } let(:nested_group_2) { create(:group, parent: nested_group_1) } diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb index f7ef7f29066..47553922ede 100644 --- a/spec/features/groups/group_settings_spec.rb +++ b/spec/features/groups/group_settings_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Edit group settings', feature: true do +feature 'Edit group settings' do given(:user) { create(:user) } given(:group) { create(:group, path: 'foo') } diff --git a/spec/features/groups/issues_spec.rb b/spec/features/groups/issues_spec.rb index d6b88542ef7..449a99a2c7b 100644 --- a/spec/features/groups/issues_spec.rb +++ b/spec/features/groups/issues_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Group issues page', feature: true do +feature 'Group issues page' do let(:path) { issues_group_path(group) } let(:issuable) { create(:issue, project: project, title: "this is my created issuable")} diff --git a/spec/features/groups/labels/edit_spec.rb b/spec/features/groups/labels/edit_spec.rb index 88d104d5a06..fb338127861 100644 --- a/spec/features/groups/labels/edit_spec.rb +++ b/spec/features/groups/labels/edit_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Edit group label', feature: true do +feature 'Edit group label' do given(:user) { create(:user) } given(:group) { create(:group) } given(:label) { create(:group_label, group: group) } diff --git a/spec/features/groups/labels/subscription_spec.rb b/spec/features/groups/labels/subscription_spec.rb index 8b891c52d08..1dd09d4f203 100644 --- a/spec/features/groups/labels/subscription_spec.rb +++ b/spec/features/groups/labels/subscription_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Labels subscription', feature: true do +feature 'Labels subscription' do let(:user) { create(:user) } let(:group) { create(:group) } let!(:feature) { create(:group_label, group: group, title: 'feature') } diff --git a/spec/features/groups/members/leave_group_spec.rb b/spec/features/groups/members/leave_group_spec.rb index b438f57753c..067a2dc850f 100644 --- a/spec/features/groups/members/leave_group_spec.rb +++ b/spec/features/groups/members/leave_group_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Groups > Members > Leave group', feature: true do +feature 'Groups > Members > Leave group' do let(:user) { create(:user) } let(:other_user) { create(:user) } let(:group) { create(:group) } diff --git a/spec/features/groups/members/list_members_spec.rb b/spec/features/groups/members/list_members_spec.rb index f6493c4c50e..5c5d48c3623 100644 --- a/spec/features/groups/members/list_members_spec.rb +++ b/spec/features/groups/members/list_members_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Groups > Members > List members', feature: true do +feature 'Groups > Members > List members' do include Select2Helper let(:user1) { create(:user, name: 'John Doe') } diff --git a/spec/features/groups/members/manage_access_requests_spec.rb b/spec/features/groups/members/manage_access_requests_spec.rb index 51a4d769b9c..b83cd657ef7 100644 --- a/spec/features/groups/members/manage_access_requests_spec.rb +++ b/spec/features/groups/members/manage_access_requests_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Groups > Members > Manage access requests', feature: true do +feature 'Groups > Members > Manage access requests' do let(:user) { create(:user) } let(:owner) { create(:user) } let(:group) { create(:group, :public, :access_requestable) } diff --git a/spec/features/groups/members/manage_members.rb b/spec/features/groups/members/manage_members.rb index 4b226893701..9039b283393 100644 --- a/spec/features/groups/members/manage_members.rb +++ b/spec/features/groups/members/manage_members.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Groups > Members > Manage members', feature: true do +feature 'Groups > Members > Manage members' do include Select2Helper let(:user1) { create(:user, name: 'John Doe') } diff --git a/spec/features/groups/members/request_access_spec.rb b/spec/features/groups/members/request_access_spec.rb index 3764e4792ca..1f3c7fd3859 100644 --- a/spec/features/groups/members/request_access_spec.rb +++ b/spec/features/groups/members/request_access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Groups > Members > Request access', feature: true do +feature 'Groups > Members > Request access' do let(:user) { create(:user) } let(:owner) { create(:user) } let(:group) { create(:group, :public, :access_requestable) } diff --git a/spec/features/groups/members/sort_members_spec.rb b/spec/features/groups/members/sort_members_spec.rb index 92ff45e0cdc..e175ad04f86 100644 --- a/spec/features/groups/members/sort_members_spec.rb +++ b/spec/features/groups/members/sort_members_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Groups > Members > Sort members', feature: true do +feature 'Groups > Members > Sort members' do let(:owner) { create(:user, name: 'John Doe') } let(:developer) { create(:user, name: 'Mary Jane', last_sign_in_at: 5.days.ago) } let(:group) { create(:group) } diff --git a/spec/features/groups/merge_requests_spec.rb b/spec/features/groups/merge_requests_spec.rb index b55078c3bf6..cbf147b6a5c 100644 --- a/spec/features/groups/merge_requests_spec.rb +++ b/spec/features/groups/merge_requests_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Group merge requests page', feature: true do +feature 'Group merge requests page' do let(:path) { merge_requests_group_path(group) } let(:issuable) { create(:merge_request, source_project: project, target_project: project, title: 'this is my created issuable') } diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb index 0f3f005040f..574bbe0e0e1 100644 --- a/spec/features/groups/milestone_spec.rb +++ b/spec/features/groups/milestone_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Group milestones', :feature, :js do +feature 'Group milestones', :js do let(:group) { create(:group) } let!(:project) { create(:project_empty_repo, group: group) } let(:user) { create(:group_member, :master, user: create(:user), group: group ).user } diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb index cbf97d0674b..303013e59d5 100644 --- a/spec/features/groups/show_spec.rb +++ b/spec/features/groups/show_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Group show page', feature: true do +feature 'Group show page' do let(:group) { create(:group) } let(:path) { group_path(group) } diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb index 6f8c8999f98..e59a484d992 100644 --- a/spec/features/groups_spec.rb +++ b/spec/features/groups_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Group', feature: true do +feature 'Group' do before do sign_in(create(:admin)) end diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb index 7fe65ee554d..bd4f233cba9 100644 --- a/spec/features/help_pages_spec.rb +++ b/spec/features/help_pages_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Help Pages', feature: true do +describe 'Help Pages' do describe 'Get the main help page' do shared_examples_for 'help page' do |prefix: ''| it 'prefixes links correctly' do diff --git a/spec/features/issuables/close_reopen_report_toggle_spec.rb b/spec/features/issuables/close_reopen_report_toggle_spec.rb index 9a99bb705b7..cf1f0624140 100644 --- a/spec/features/issuables/close_reopen_report_toggle_spec.rb +++ b/spec/features/issuables/close_reopen_report_toggle_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Issuables Close/Reopen/Report toggle', :feature do +describe 'Issuables Close/Reopen/Report toggle' do let(:user) { create(:user) } shared_examples 'an issuable close/reopen/report toggle' do diff --git a/spec/features/issuables/default_sort_order_spec.rb b/spec/features/issuables/default_sort_order_spec.rb index 56c9b10e757..7c20c96528e 100644 --- a/spec/features/issuables/default_sort_order_spec.rb +++ b/spec/features/issuables/default_sort_order_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Projects > Issuables > Default sort order', feature: true do +describe 'Projects > Issuables > Default sort order' do let(:project) { create(:empty_project, :public) } let(:first_created_issuable) { issuables.order_created_asc.first } diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb index 32fee2d9c34..557de721222 100644 --- a/spec/features/issuables/issuable_list_spec.rb +++ b/spec/features/issuables/issuable_list_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'issuable list', feature: true do +describe 'issuable list' do let(:project) { create(:empty_project) } let(:user) { create(:user) } diff --git a/spec/features/issues/award_emoji_spec.rb b/spec/features/issues/award_emoji_spec.rb index 823c779e0d9..134e618feac 100644 --- a/spec/features/issues/award_emoji_spec.rb +++ b/spec/features/issues/award_emoji_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Awards Emoji', feature: true do +describe 'Awards Emoji' do let!(:project) { create(:project, :public) } let!(:user) { create(:user) } let(:issue) do diff --git a/spec/features/issues/award_spec.rb b/spec/features/issues/award_spec.rb index 76cffc1d8c9..e95eb19f7d1 100644 --- a/spec/features/issues/award_spec.rb +++ b/spec/features/issues/award_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Issue awards', js: true, feature: true do +feature 'Issue awards', js: true do let(:user) { create(:user) } let(:project) { create(:project, :public) } let(:issue) { create(:issue, project: project) } diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb index 034d8afb54d..847e3856ba5 100644 --- a/spec/features/issues/bulk_assignment_labels_spec.rb +++ b/spec/features/issues/bulk_assignment_labels_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Issues > Labels bulk assignment', feature: true do +feature 'Issues > Labels bulk assignment' do let(:user) { create(:user) } let!(:project) { create(:project) } let!(:issue1) { create(:issue, project: project, title: "Issue 1") } diff --git a/spec/features/issues/create_branch_merge_request_spec.rb b/spec/features/issues/create_branch_merge_request_spec.rb index 6e778f4d7e5..88e81d12602 100644 --- a/spec/features/issues/create_branch_merge_request_spec.rb +++ b/spec/features/issues/create_branch_merge_request_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Create Branch/Merge Request Dropdown on issue page', feature: true, js: true do +feature 'Create Branch/Merge Request Dropdown on issue page', js: true do let(:user) { create(:user) } let!(:project) { create(:project) } let(:issue) { create(:issue, project: project, title: 'Cherry-Coloured Funk') } diff --git a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb index dd9a7f1253d..3c51e8053da 100644 --- a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb +++ b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Resolving all open discussions in a merge request from an issue', feature: true, js: true do +feature 'Resolving all open discussions in a merge request from an issue', js: true do let(:user) { create(:user) } let(:project) { create(:project) } let(:merge_request) { create(:merge_request, source_project: project) } diff --git a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb index 5c291f7b817..d468c7d9c75 100644 --- a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb +++ b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Resolve an open discussion in a merge request by creating an issue', feature: true do +feature 'Resolve an open discussion in a merge request by creating an issue' do let(:user) { create(:user) } let(:project) { create(:project, only_allow_merge_if_all_discussions_are_resolved: true) } let(:merge_request) { create(:merge_request, source_project: project) } diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb index 2765d5448a4..a403d885de0 100644 --- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Dropdown assignee', :feature, :js do +describe 'Dropdown assignee', :js do include FilteredSearchHelpers let!(:project) { create(:empty_project) } diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb index 98b1c5ee1b5..b7d9bbd7e1d 100644 --- a/spec/features/issues/filtered_search/dropdown_author_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Dropdown author', js: true, feature: true do +describe 'Dropdown author', js: true do include FilteredSearchHelpers let!(:project) { create(:empty_project) } diff --git a/spec/features/issues/filtered_search/dropdown_hint_spec.rb b/spec/features/issues/filtered_search/dropdown_hint_spec.rb index fdc003f81b3..292fd683271 100644 --- a/spec/features/issues/filtered_search/dropdown_hint_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_hint_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Dropdown hint', :js, :feature do +describe 'Dropdown hint', :js do include FilteredSearchHelpers let!(:project) { create(:empty_project) } diff --git a/spec/features/issues/filtered_search/dropdown_label_spec.rb b/spec/features/issues/filtered_search/dropdown_label_spec.rb index 26a0320675f..e8f005d7752 100644 --- a/spec/features/issues/filtered_search/dropdown_label_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_label_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Dropdown label', js: true, feature: true do +describe 'Dropdown label', js: true do include FilteredSearchHelpers let(:project) { create(:empty_project) } diff --git a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb index 7c74d8dffff..ace73f4b1a6 100644 --- a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Dropdown milestone', :feature, :js do +describe 'Dropdown milestone', :js do include FilteredSearchHelpers let!(:project) { create(:empty_project) } diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index 9fc6391fa98..cd2cbf4bfe7 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Filter issues', js: true, feature: true do +describe 'Filter issues', js: true do include Devise::Test::IntegrationHelpers include FilteredSearchHelpers diff --git a/spec/features/issues/filtered_search/recent_searches_spec.rb b/spec/features/issues/filtered_search/recent_searches_spec.rb index 4a91ce4be07..5842bb22beb 100644 --- a/spec/features/issues/filtered_search/recent_searches_spec.rb +++ b/spec/features/issues/filtered_search/recent_searches_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Recent searches', js: true, feature: true do +describe 'Recent searches', js: true do include FilteredSearchHelpers let(:project_1) { create(:empty_project, :public) } diff --git a/spec/features/issues/filtered_search/search_bar_spec.rb b/spec/features/issues/filtered_search/search_bar_spec.rb index b16c5c280c7..115875d72ce 100644 --- a/spec/features/issues/filtered_search/search_bar_spec.rb +++ b/spec/features/issues/filtered_search/search_bar_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Search bar', js: true, feature: true do +describe 'Search bar', js: true do include FilteredSearchHelpers let!(:project) { create(:empty_project) } diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb index a15c3d1d447..d00d0a9c81b 100644 --- a/spec/features/issues/filtered_search/visual_tokens_spec.rb +++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Visual tokens', js: true, feature: true do +describe 'Visual tokens', js: true do include FilteredSearchHelpers include WaitForRequests diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb index 05742004f06..b56b8744d7e 100644 --- a/spec/features/issues/form_spec.rb +++ b/spec/features/issues/form_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'New/edit issue', :feature, :js do +describe 'New/edit issue', :js do include ActionView::Helpers::JavaScriptHelper include FormHelper diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb index 9b4cc653af5..b84635c5134 100644 --- a/spec/features/issues/gfm_autocomplete_spec.rb +++ b/spec/features/issues/gfm_autocomplete_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'GFM autocomplete', feature: true, js: true do +feature 'GFM autocomplete', js: true do let(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') } let(:project) { create(:project) } let(:label) { create(:label, project: project, title: 'special+') } diff --git a/spec/features/issues/group_label_sidebar_spec.rb b/spec/features/issues/group_label_sidebar_spec.rb index 5531a662c67..a8ac1d605cb 100644 --- a/spec/features/issues/group_label_sidebar_spec.rb +++ b/spec/features/issues/group_label_sidebar_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Group label on issue', :feature do +describe 'Group label on issue' do it 'renders link to the project issues page' do group = create(:group) project = create(:empty_project, :public, namespace: group) diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb index e1c55d246ab..28b636f9359 100644 --- a/spec/features/issues/issue_detail_spec.rb +++ b/spec/features/issues/issue_detail_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Issue Detail', js: true, feature: true do +feature 'Issue Detail', :js do let(:user) { create(:user) } let(:project) { create(:project, :public) } let(:issue) { create(:issue, project: project, author: user) } diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb index f75d2c72672..8e22441e0e8 100644 --- a/spec/features/issues/issue_sidebar_spec.rb +++ b/spec/features/issues/issue_sidebar_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Issue Sidebar', feature: true do +feature 'Issue Sidebar' do include MobileHelpers let(:group) { create(:group, :nested) } diff --git a/spec/features/issues/markdown_toolbar_spec.rb b/spec/features/issues/markdown_toolbar_spec.rb index affba35f61c..6aed27e8790 100644 --- a/spec/features/issues/markdown_toolbar_spec.rb +++ b/spec/features/issues/markdown_toolbar_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Issue markdown toolbar', feature: true, js: true do +feature 'Issue markdown toolbar', js: true do let(:project) { create(:project, :public) } let(:issue) { create(:issue, project: project) } let(:user) { create(:user) } diff --git a/spec/features/issues/note_polling_spec.rb b/spec/features/issues/note_polling_spec.rb index 184cde5b9c5..b524260750e 100644 --- a/spec/features/issues/note_polling_spec.rb +++ b/spec/features/issues/note_polling_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Issue notes polling', :feature, :js do +feature 'Issue notes polling', :js do include NoteInteractionHelpers let(:project) { create(:empty_project, :public) } diff --git a/spec/features/issues/notes_on_issues_spec.rb b/spec/features/issues/notes_on_issues_spec.rb index 6fb103e5477..be4c23645d9 100644 --- a/spec/features/issues/notes_on_issues_spec.rb +++ b/spec/features/issues/notes_on_issues_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Create notes on issues', :js, :feature do +describe 'Create notes on issues', :js do let(:user) { create(:user) } shared_examples 'notes with reference' do diff --git a/spec/features/issues/spam_issues_spec.rb b/spec/features/issues/spam_issues_spec.rb index 39a458fe3d0..332ce78b138 100644 --- a/spec/features/issues/spam_issues_spec.rb +++ b/spec/features/issues/spam_issues_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'New issue', feature: true, js: true do +describe 'New issue', js: true do include StubENV let(:project) { create(:project, :public) } diff --git a/spec/features/issues/todo_spec.rb b/spec/features/issues/todo_spec.rb index f57b58f68e3..7ca5ef4649a 100644 --- a/spec/features/issues/todo_spec.rb +++ b/spec/features/issues/todo_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Manually create a todo item from issue', feature: true, js: true do +feature 'Manually create a todo item from issue', js: true do let!(:project) { create(:project) } let!(:issue) { create(:issue, project: project) } let!(:user) { create(:user)} diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb index 0c3c27e3e45..4b63cc844f3 100644 --- a/spec/features/issues/user_uses_slash_commands_spec.rb +++ b/spec/features/issues/user_uses_slash_commands_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Issues > User uses quick actions', feature: true, js: true do +feature 'Issues > User uses quick actions', js: true do include QuickActionsHelpers it_behaves_like 'issuable record that supports quick actions in its description and notes', :issue do diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index 0016fa10f67..722237481ea 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Issues', feature: true do +describe 'Issues' do include DropzoneHelper include IssueHelpers include SortingHelper diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb index 2a2213b67ed..c9983f0941f 100644 --- a/spec/features/login_spec.rb +++ b/spec/features/login_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Login', feature: true do +feature 'Login' do describe 'initial login after setup' do it 'allows the initial admin to create a password' do # This behavior is dependent on there only being one user diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb index 1aca3e3a9fd..b70d3060f05 100644 --- a/spec/features/markdown_spec.rb +++ b/spec/features/markdown_spec.rb @@ -24,7 +24,7 @@ require 'erb' # # See the MarkdownFeature class for setup details. -describe 'GitLab Markdown', feature: true do +describe 'GitLab Markdown' do include Capybara::Node::Matchers include MarkupHelper include MarkdownMatchers diff --git a/spec/features/merge_requests/assign_issues_spec.rb b/spec/features/merge_requests/assign_issues_spec.rb index 985f42e484c..04c2a694fff 100644 --- a/spec/features/merge_requests/assign_issues_spec.rb +++ b/spec/features/merge_requests/assign_issues_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Merge request issue assignment', js: true, feature: true do +feature 'Merge request issue assignment', js: true do let(:user) { create(:user) } let(:project) { create(:project, :public) } let(:issue1) { create(:issue, project: project) } diff --git a/spec/features/merge_requests/award_spec.rb b/spec/features/merge_requests/award_spec.rb index 3b01c763281..5a12d6f43f3 100644 --- a/spec/features/merge_requests/award_spec.rb +++ b/spec/features/merge_requests/award_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Merge request awards', js: true, feature: true do +feature 'Merge request awards', js: true do let(:user) { create(:user) } let(:project) { create(:project, :public) } let(:merge_request) { create(:merge_request, source_project: project) } diff --git a/spec/features/merge_requests/check_if_mergeable_with_unresolved_discussions_spec.rb b/spec/features/merge_requests/check_if_mergeable_with_unresolved_discussions_spec.rb index f2d6c0d9769..c3d7d2fa23f 100644 --- a/spec/features/merge_requests/check_if_mergeable_with_unresolved_discussions_spec.rb +++ b/spec/features/merge_requests/check_if_mergeable_with_unresolved_discussions_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Check if mergeable with unresolved discussions', js: true, feature: true do +feature 'Check if mergeable with unresolved discussions', js: true do let(:user) { create(:user) } let(:project) { create(:project) } let!(:merge_request) { create(:merge_request_with_diff_notes, source_project: project, author: user) } diff --git a/spec/features/merge_requests/closes_issues_spec.rb b/spec/features/merge_requests/closes_issues_spec.rb index 527837b56be..24000ea75d1 100644 --- a/spec/features/merge_requests/closes_issues_spec.rb +++ b/spec/features/merge_requests/closes_issues_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Merge Request closing issues message', feature: true, js: true do +feature 'Merge Request closing issues message', js: true do let(:user) { create(:user) } let(:project) { create(:project, :public) } let(:issue_1) { create(:issue, project: project)} diff --git a/spec/features/merge_requests/conflicts_spec.rb b/spec/features/merge_requests/conflicts_spec.rb index 5c0909b6a59..3c5ddf8396d 100644 --- a/spec/features/merge_requests/conflicts_spec.rb +++ b/spec/features/merge_requests/conflicts_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Merge request conflict resolution', js: true, feature: true do +feature 'Merge request conflict resolution', js: true do let(:user) { create(:user) } let(:project) { create(:project) } diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb index e0d97dec586..67322bdc8a8 100644 --- a/spec/features/merge_requests/create_new_mr_spec.rb +++ b/spec/features/merge_requests/create_new_mr_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Create New Merge Request', feature: true, js: true do +feature 'Create New Merge Request', js: true do let(:user) { create(:user) } let(:project) { create(:project, :public) } diff --git a/spec/features/merge_requests/deleted_source_branch_spec.rb b/spec/features/merge_requests/deleted_source_branch_spec.rb index 8d7160e2df2..874c6e2ff69 100644 --- a/spec/features/merge_requests/deleted_source_branch_spec.rb +++ b/spec/features/merge_requests/deleted_source_branch_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' # This test serves as a regression test for a bug that caused an error # message to be shown by JavaScript when the source branch was deleted. # Please do not remove "js: true". -describe 'Deleted source branch', feature: true, js: true do +describe 'Deleted source branch', js: true do let(:user) { create(:user) } let(:merge_request) { create(:merge_request) } diff --git a/spec/features/merge_requests/diff_notes_avatars_spec.rb b/spec/features/merge_requests/diff_notes_avatars_spec.rb index 4fc70027193..7f082f12d47 100644 --- a/spec/features/merge_requests/diff_notes_avatars_spec.rb +++ b/spec/features/merge_requests/diff_notes_avatars_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Diff note avatars', feature: true, js: true do +feature 'Diff note avatars', js: true do include NoteInteractionHelpers let(:user) { create(:user) } diff --git a/spec/features/merge_requests/diff_notes_resolve_spec.rb b/spec/features/merge_requests/diff_notes_resolve_spec.rb index 93e2d134389..a2f0b24d6a8 100644 --- a/spec/features/merge_requests/diff_notes_resolve_spec.rb +++ b/spec/features/merge_requests/diff_notes_resolve_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Diff notes resolve', feature: true, js: true do +feature 'Diff notes resolve', js: true do let(:user) { create(:user) } let(:project) { create(:project, :public) } let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user, title: "Bug NS-04") } diff --git a/spec/features/merge_requests/diffs_spec.rb b/spec/features/merge_requests/diffs_spec.rb index d9de4e388d5..499cd38e648 100644 --- a/spec/features/merge_requests/diffs_spec.rb +++ b/spec/features/merge_requests/diffs_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Diffs URL', js: true, feature: true do +feature 'Diffs URL', js: true do let(:project) { create(:project, :public) } let(:merge_request) { create(:merge_request, source_project: project) } diff --git a/spec/features/merge_requests/discussion_spec.rb b/spec/features/merge_requests/discussion_spec.rb index 55846f8609b..d1cc43e0690 100644 --- a/spec/features/merge_requests/discussion_spec.rb +++ b/spec/features/merge_requests/discussion_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Merge Request Discussions', feature: true do +feature 'Merge Request Discussions' do before do sign_in(create(:admin)) end diff --git a/spec/features/merge_requests/edit_mr_spec.rb b/spec/features/merge_requests/edit_mr_spec.rb index b7063f35546..2b0ecfc8c72 100644 --- a/spec/features/merge_requests/edit_mr_spec.rb +++ b/spec/features/merge_requests/edit_mr_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Edit Merge Request', feature: true do +feature 'Edit Merge Request' do let(:user) { create(:user) } let(:project) { create(:project, :public) } let(:merge_request) { create(:merge_request, :simple, source_project: project) } diff --git a/spec/features/merge_requests/filter_by_labels_spec.rb b/spec/features/merge_requests/filter_by_labels_spec.rb index 754f82900e4..220e0c8dc68 100644 --- a/spec/features/merge_requests/filter_by_labels_spec.rb +++ b/spec/features/merge_requests/filter_by_labels_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Issue filtering by Labels', feature: true, js: true do +feature 'Issue filtering by Labels', js: true do include FilteredSearchHelpers include MergeRequestHelpers diff --git a/spec/features/merge_requests/filter_by_milestone_spec.rb b/spec/features/merge_requests/filter_by_milestone_spec.rb index d2af150d852..f6b9aa733a4 100644 --- a/spec/features/merge_requests/filter_by_milestone_spec.rb +++ b/spec/features/merge_requests/filter_by_milestone_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Merge Request filtering by Milestone', feature: true do +feature 'Merge Request filtering by Milestone' do include FilteredSearchHelpers include MergeRequestHelpers diff --git a/spec/features/merge_requests/filter_merge_requests_spec.rb b/spec/features/merge_requests/filter_merge_requests_spec.rb index e8085ec36aa..38eb158d06e 100644 --- a/spec/features/merge_requests/filter_merge_requests_spec.rb +++ b/spec/features/merge_requests/filter_merge_requests_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Filter merge requests', feature: true do +describe 'Filter merge requests' do include FilteredSearchHelpers include MergeRequestHelpers diff --git a/spec/features/merge_requests/form_spec.rb b/spec/features/merge_requests/form_spec.rb index 171386e16ad..e06cd627b20 100644 --- a/spec/features/merge_requests/form_spec.rb +++ b/spec/features/merge_requests/form_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'New/edit merge request', feature: true, js: true do +describe 'New/edit merge request', :js do let!(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } let(:fork_project) { create(:project, forked_from_project: project) } let!(:user) { create(:user)} diff --git a/spec/features/merge_requests/merge_commit_message_toggle_spec.rb b/spec/features/merge_requests/merge_commit_message_toggle_spec.rb index 6cd62ecec72..784f362a28f 100644 --- a/spec/features/merge_requests/merge_commit_message_toggle_spec.rb +++ b/spec/features/merge_requests/merge_commit_message_toggle_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Clicking toggle commit message link', feature: true, js: true do +feature 'Clicking toggle commit message link', js: true do let(:user) { create(:user) } let(:project) { create(:project, :public) } let(:issue_1) { create(:issue, project: project)} diff --git a/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb b/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb index d3475bee5cc..13142d3b3c9 100644 --- a/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb +++ b/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Merge immediately', :feature, :js do +feature 'Merge immediately', :js do let(:user) { create(:user) } let(:project) { create(:project, :public) } diff --git a/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb b/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb index 230b04296b3..9fbdc1b2c80 100644 --- a/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb +++ b/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Merge When Pipeline Succeeds', :feature, :js do +feature 'Merge When Pipeline Succeeds', :js do let(:user) { create(:user) } let(:project) { create(:project, :public) } diff --git a/spec/features/merge_requests/mini_pipeline_graph_spec.rb b/spec/features/merge_requests/mini_pipeline_graph_spec.rb index 4adf72a60b0..ee6e440e70d 100644 --- a/spec/features/merge_requests/mini_pipeline_graph_spec.rb +++ b/spec/features/merge_requests/mini_pipeline_graph_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Mini Pipeline Graph', :js, :feature do +feature 'Mini Pipeline Graph', :js do let(:user) { create(:user) } let(:project) { create(:project, :public) } let(:merge_request) { create(:merge_request, source_project: project, head_pipeline: pipeline) } diff --git a/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb b/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb index 651cb9d86fb..5c6eec44ff7 100644 --- a/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb +++ b/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Only allow merge requests to be merged if the pipeline succeeds', feature: true, js: true do +feature 'Only allow merge requests to be merged if the pipeline succeeds', js: true do let(:merge_request) { create(:merge_request_with_diffs) } let(:project) { merge_request.target_project } diff --git a/spec/features/merge_requests/pipelines_spec.rb b/spec/features/merge_requests/pipelines_spec.rb index 837366ced3c..b3d6cf8deb4 100644 --- a/spec/features/merge_requests/pipelines_spec.rb +++ b/spec/features/merge_requests/pipelines_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Pipelines for Merge Requests', feature: true, js: true do +feature 'Pipelines for Merge Requests', js: true do given(:user) { create(:user) } given(:merge_request) { create(:merge_request) } given(:project) { merge_request.target_project } diff --git a/spec/features/merge_requests/reset_filters_spec.rb b/spec/features/merge_requests/reset_filters_spec.rb index 275f81f50dc..423213709a3 100644 --- a/spec/features/merge_requests/reset_filters_spec.rb +++ b/spec/features/merge_requests/reset_filters_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Merge requests filter clear button', feature: true, js: true do +feature 'Merge requests filter clear button', js: true do include FilteredSearchHelpers include MergeRequestHelpers include IssueHelpers diff --git a/spec/features/merge_requests/target_branch_spec.rb b/spec/features/merge_requests/target_branch_spec.rb index 3ed76926eab..9bbf2610bcb 100644 --- a/spec/features/merge_requests/target_branch_spec.rb +++ b/spec/features/merge_requests/target_branch_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Target branch', feature: true, js: true do +describe 'Target branch', js: true do let(:user) { create(:user) } let(:merge_request) { create(:merge_request) } let(:project) { merge_request.project } diff --git a/spec/features/merge_requests/toggle_whitespace_changes_spec.rb b/spec/features/merge_requests/toggle_whitespace_changes_spec.rb index 912aa34b0c8..dd989fd49b2 100644 --- a/spec/features/merge_requests/toggle_whitespace_changes_spec.rb +++ b/spec/features/merge_requests/toggle_whitespace_changes_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Toggle Whitespace Changes', js: true, feature: true do +feature 'Toggle Whitespace Changes', js: true do before do sign_in(create(:admin)) merge_request = create(:merge_request) diff --git a/spec/features/merge_requests/toggler_behavior_spec.rb b/spec/features/merge_requests/toggler_behavior_spec.rb index 01251105f72..2283164ca2f 100644 --- a/spec/features/merge_requests/toggler_behavior_spec.rb +++ b/spec/features/merge_requests/toggler_behavior_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'toggler_behavior', js: true, feature: true do +feature 'toggler_behavior', js: true do let(:user) { create(:user) } let(:project) { create(:project) } let(:merge_request) { create(:merge_request, source_project: project, author: user) } diff --git a/spec/features/merge_requests/update_merge_requests_spec.rb b/spec/features/merge_requests/update_merge_requests_spec.rb index 43153e2cfa4..db2f2b523d2 100644 --- a/spec/features/merge_requests/update_merge_requests_spec.rb +++ b/spec/features/merge_requests/update_merge_requests_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Multiple merge requests updating from merge_requests#index', feature: true do +feature 'Multiple merge requests updating from merge_requests#index' do let!(:user) { create(:user)} let!(:project) { create(:project) } let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } diff --git a/spec/features/merge_requests/user_lists_merge_requests_spec.rb b/spec/features/merge_requests/user_lists_merge_requests_spec.rb index f541f495995..d38d2d57b35 100644 --- a/spec/features/merge_requests/user_lists_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_lists_merge_requests_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Projects > Merge requests > User lists merge requests', feature: true do +describe 'Projects > Merge requests > User lists merge requests' do include MergeRequestHelpers include SortingHelper diff --git a/spec/features/merge_requests/user_uses_slash_commands_spec.rb b/spec/features/merge_requests/user_uses_slash_commands_spec.rb index b2187e01bdb..881527e1501 100644 --- a/spec/features/merge_requests/user_uses_slash_commands_spec.rb +++ b/spec/features/merge_requests/user_uses_slash_commands_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Merge Requests > User uses quick actions', feature: true, js: true do +feature 'Merge Requests > User uses quick actions', js: true do include QuickActionsHelpers let(:user) { create(:user) } diff --git a/spec/features/merge_requests/versions_spec.rb b/spec/features/merge_requests/versions_spec.rb index 218d57b49e3..8e231fbc281 100644 --- a/spec/features/merge_requests/versions_spec.rb +++ b/spec/features/merge_requests/versions_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Merge Request versions', js: true, feature: true do +feature 'Merge Request versions', js: true do let(:merge_request) { create(:merge_request, importing: true) } let(:project) { merge_request.source_project } let!(:merge_request_diff1) { merge_request.merge_request_diffs.create(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') } diff --git a/spec/features/merge_requests/widget_deployments_spec.rb b/spec/features/merge_requests/widget_deployments_spec.rb index b0fe5f3e1cb..c0221525c9f 100644 --- a/spec/features/merge_requests/widget_deployments_spec.rb +++ b/spec/features/merge_requests/widget_deployments_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Widget Deployments Header', feature: true, js: true do +feature 'Widget Deployments Header', js: true do describe 'when deployed to an environment' do given(:user) { create(:user) } given(:project) { merge_request.target_project } diff --git a/spec/features/merge_requests/widget_spec.rb b/spec/features/merge_requests/widget_spec.rb index 46c558659c7..8d7bbf14d86 100644 --- a/spec/features/merge_requests/widget_spec.rb +++ b/spec/features/merge_requests/widget_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Merge request', :feature, :js do +describe 'Merge request', :js do let(:user) { create(:user) } let(:project) { create(:project) } let(:merge_request) { create(:merge_request, source_project: project) } diff --git a/spec/features/merge_requests/wip_message_spec.rb b/spec/features/merge_requests/wip_message_spec.rb index 91cf8fc7218..5a685056bf3 100644 --- a/spec/features/merge_requests/wip_message_spec.rb +++ b/spec/features/merge_requests/wip_message_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Work In Progress help message', feature: true do +feature 'Work In Progress help message' do let!(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } let!(:user) { create(:user) } diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb index ce0c27cbe77..1d05184d6fc 100644 --- a/spec/features/milestone_spec.rb +++ b/spec/features/milestone_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Milestone', feature: true do +feature 'Milestone' do let(:group) { create(:group, :public) } let(:project) { create(:empty_project, :public, namespace: group) } let(:user) { create(:user) } diff --git a/spec/features/milestones/show_spec.rb b/spec/features/milestones/show_spec.rb index 626a1f35e62..199a5ba83b3 100644 --- a/spec/features/milestones/show_spec.rb +++ b/spec/features/milestones/show_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Milestone show', feature: true do +describe 'Milestone show' do let(:user) { create(:user) } let(:project) { create(:empty_project) } let(:milestone) { create(:milestone, project: project) } diff --git a/spec/features/password_reset_spec.rb b/spec/features/password_reset_spec.rb index 257d363438c..5e1e7dc078f 100644 --- a/spec/features/password_reset_spec.rb +++ b/spec/features/password_reset_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Password reset', feature: true do +feature 'Password reset' do describe 'throttling' do it 'sends reset instructions when not previously sent' do user = create(:user) diff --git a/spec/features/profile_spec.rb b/spec/features/profile_spec.rb index fae11a993b5..672022304da 100644 --- a/spec/features/profile_spec.rb +++ b/spec/features/profile_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Profile account page', feature: true do +describe 'Profile account page' do let(:user) { create(:user) } before do diff --git a/spec/features/profiles/account_spec.rb b/spec/features/profiles/account_spec.rb index 9d782ecf63b..7791047877d 100644 --- a/spec/features/profiles/account_spec.rb +++ b/spec/features/profiles/account_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Profile > Account', feature: true do +feature 'Profile > Account' do given(:user) { create(:user, username: 'foo') } before do diff --git a/spec/features/profiles/chat_names_spec.rb b/spec/features/profiles/chat_names_spec.rb index e4c236f4c68..35793539e0e 100644 --- a/spec/features/profiles/chat_names_spec.rb +++ b/spec/features/profiles/chat_names_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Profile > Chat', feature: true do +feature 'Profile > Chat' do given(:user) { create(:user) } given(:service) { create(:service) } diff --git a/spec/features/profiles/keys_spec.rb b/spec/features/profiles/keys_spec.rb index 9439a258a75..6541ea6bf57 100644 --- a/spec/features/profiles/keys_spec.rb +++ b/spec/features/profiles/keys_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Profile > SSH Keys', feature: true do +feature 'Profile > SSH Keys' do let(:user) { create(:user) } before do diff --git a/spec/features/profiles/oauth_applications_spec.rb b/spec/features/profiles/oauth_applications_spec.rb index c7886421c83..45f78444362 100644 --- a/spec/features/profiles/oauth_applications_spec.rb +++ b/spec/features/profiles/oauth_applications_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Profile > Applications', feature: true do +describe 'Profile > Applications' do let(:user) { create(:user) } before do diff --git a/spec/features/profiles/password_spec.rb b/spec/features/profiles/password_spec.rb index 26d6d6658aa..2c757f99a27 100644 --- a/spec/features/profiles/password_spec.rb +++ b/spec/features/profiles/password_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Profile > Password', feature: true do +describe 'Profile > Password' do context 'Password authentication enabled' do let(:user) { create(:user, password_automatically_set: true) } diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb index 3c08b6bc091..f3124bbf29e 100644 --- a/spec/features/profiles/personal_access_tokens_spec.rb +++ b/spec/features/profiles/personal_access_tokens_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Profile > Personal Access Tokens', feature: true, js: true do +describe 'Profile > Personal Access Tokens', js: true do let(:user) { create(:user) } def active_personal_access_tokens diff --git a/spec/features/profiles/preferences_spec.rb b/spec/features/profiles/preferences_spec.rb index 65fed82c256..9123aa9d155 100644 --- a/spec/features/profiles/preferences_spec.rb +++ b/spec/features/profiles/preferences_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Profile > Preferences', feature: true do +describe 'Profile > Preferences' do let(:user) { create(:user) } before do diff --git a/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb b/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb index 75daef0c38c..6a4173d43e1 100644 --- a/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb +++ b/spec/features/profiles/user_changes_notified_of_own_activity_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Profile > Notifications > User changes notified_of_own_activity setting', feature: true, js: true do +feature 'Profile > Notifications > User changes notified_of_own_activity setting', js: true do let(:user) { create(:user) } before do diff --git a/spec/features/projects/artifacts/browse_spec.rb b/spec/features/projects/artifacts/browse_spec.rb index a34c0c4cecd..7dfb19f29bd 100644 --- a/spec/features/projects/artifacts/browse_spec.rb +++ b/spec/features/projects/artifacts/browse_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Browse artifact', :js, feature: true do +feature 'Browse artifact', :js do let(:project) { create(:project, :public) } let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') } let(:job) { create(:ci_build, :artifacts, pipeline: pipeline) } diff --git a/spec/features/projects/artifacts/download_spec.rb b/spec/features/projects/artifacts/download_spec.rb index b76f2be880e..f1c210281ad 100644 --- a/spec/features/projects/artifacts/download_spec.rb +++ b/spec/features/projects/artifacts/download_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Download artifact', :js, feature: true do +feature 'Download artifact', :js do let(:project) { create(:project, :public) } let(:pipeline) { create(:ci_empty_pipeline, status: :success, project: project, sha: project.commit.sha, ref: 'master') } let(:job) { create(:ci_build, :artifacts, :success, pipeline: pipeline) } diff --git a/spec/features/projects/artifacts/file_spec.rb b/spec/features/projects/artifacts/file_spec.rb index 6d48470ca3a..aaa98ac4851 100644 --- a/spec/features/projects/artifacts/file_spec.rb +++ b/spec/features/projects/artifacts/file_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Artifact file', :js, feature: true do +feature 'Artifact file', :js do let(:project) { create(:project, :public) } let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') } let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) } diff --git a/spec/features/projects/artifacts/raw_spec.rb b/spec/features/projects/artifacts/raw_spec.rb index 3f38d720a0f..73292cb3873 100644 --- a/spec/features/projects/artifacts/raw_spec.rb +++ b/spec/features/projects/artifacts/raw_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Raw artifact', :js, feature: true do +feature 'Raw artifact', :js do let(:project) { create(:project, :public) } let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') } let(:job) { create(:ci_build, :artifacts, pipeline: pipeline) } diff --git a/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb b/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb index 7564338b301..1160f674974 100644 --- a/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb +++ b/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Blob button line permalinks (BlobLinePermalinkUpdater)', feature: true, js: true do +feature 'Blob button line permalinks (BlobLinePermalinkUpdater)', js: true do include TreeHelper let(:project) { create(:project, :public, :repository) } diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb index 3427f639930..8a32488b845 100644 --- a/spec/features/projects/blobs/blob_show_spec.rb +++ b/spec/features/projects/blobs/blob_show_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'File blob', :js, feature: true do +feature 'File blob', :js do let(:project) { create(:project, :public) } def visit_blob(path, anchor: nil, ref: 'master') diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb index ddd27083147..9855cfd85c4 100644 --- a/spec/features/projects/blobs/edit_spec.rb +++ b/spec/features/projects/blobs/edit_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Editing file blob', feature: true, js: true do +feature 'Editing file blob', js: true do include TreeHelper let(:project) { create(:project, :public) } diff --git a/spec/features/projects/blobs/shortcuts_blob_spec.rb b/spec/features/projects/blobs/shortcuts_blob_spec.rb index 9cacda84378..1e3080fa319 100644 --- a/spec/features/projects/blobs/shortcuts_blob_spec.rb +++ b/spec/features/projects/blobs/shortcuts_blob_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Blob shortcuts', feature: true do +feature 'Blob shortcuts' do include TreeHelper let(:project) { create(:project, :public, :repository) } let(:path) { project.repository.ls_files(project.repository.root_ref)[0] } diff --git a/spec/features/projects/branches/download_buttons_spec.rb b/spec/features/projects/branches/download_buttons_spec.rb index f01860cc434..47d7f27290b 100644 --- a/spec/features/projects/branches/download_buttons_spec.rb +++ b/spec/features/projects/branches/download_buttons_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Download buttons in branches page', feature: true do +feature 'Download buttons in branches page' do given(:user) { create(:user) } given(:role) { :developer } given(:status) { 'success' } diff --git a/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb b/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb index 8c35dac0b3d..2123e96b816 100644 --- a/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb +++ b/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'New Branch Ref Dropdown', :js, :feature do +describe 'New Branch Ref Dropdown', :js do let(:user) { create(:user) } let(:project) { create(:project, :public) } let(:toggle) { find('.create-from .dropdown-menu-toggle') } diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb index d18cd3d6adc..498dd8ee4bf 100644 --- a/spec/features/projects/branches_spec.rb +++ b/spec/features/projects/branches_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Branches', feature: true do +describe 'Branches' do let(:user) { create(:user) } let(:project) { create(:project, :public) } let(:repository) { project.repository } diff --git a/spec/features/projects/commit/mini_pipeline_graph_spec.rb b/spec/features/projects/commit/mini_pipeline_graph_spec.rb index a5736b6072a..81a12225779 100644 --- a/spec/features/projects/commit/mini_pipeline_graph_spec.rb +++ b/spec/features/projects/commit/mini_pipeline_graph_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Mini Pipeline Graph in Commit View', :js, :feature do +feature 'Mini Pipeline Graph in Commit View', :js do let(:user) { create(:user) } let(:project) { create(:project, :public) } diff --git a/spec/features/projects/deploy_keys_spec.rb b/spec/features/projects/deploy_keys_spec.rb index cf3e1ff451e..2d1a9b931b5 100644 --- a/spec/features/projects/deploy_keys_spec.rb +++ b/spec/features/projects/deploy_keys_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Project deploy keys', :js, :feature do +describe 'Project deploy keys', :js do let(:user) { create(:user) } let(:project) { create(:project_empty_repo) } diff --git a/spec/features/projects/developer_views_empty_project_instructions_spec.rb b/spec/features/projects/developer_views_empty_project_instructions_spec.rb index 1b0d13e07db..7145e286229 100644 --- a/spec/features/projects/developer_views_empty_project_instructions_spec.rb +++ b/spec/features/projects/developer_views_empty_project_instructions_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Developer views empty project instructions', feature: true do +feature 'Developer views empty project instructions' do let(:project) { create(:empty_project, :empty_repo) } let(:developer) { create(:user) } diff --git a/spec/features/projects/diffs/diff_show_spec.rb b/spec/features/projects/diffs/diff_show_spec.rb index 4baccb24806..bc102895aaf 100644 --- a/spec/features/projects/diffs/diff_show_spec.rb +++ b/spec/features/projects/diffs/diff_show_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Diff file viewer', :js, feature: true do +feature 'Diff file viewer', :js do let(:project) { create(:project, :public, :repository) } def visit_commit(sha, anchor: nil) diff --git a/spec/features/projects/edit_spec.rb b/spec/features/projects/edit_spec.rb index 1fca0dde534..d3b1d1f7be3 100644 --- a/spec/features/projects/edit_spec.rb +++ b/spec/features/projects/edit_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Project edit', feature: true, js: true do +feature 'Project edit', js: true do let(:user) { create(:user) } let(:project) { create(:project) } diff --git a/spec/features/projects/environments/environment_metrics_spec.rb b/spec/features/projects/environments/environment_metrics_spec.rb index cf0dfcfb1f3..82a722c5960 100644 --- a/spec/features/projects/environments/environment_metrics_spec.rb +++ b/spec/features/projects/environments/environment_metrics_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Environment > Metrics', :feature do +feature 'Environment > Metrics' do include PrometheusHelpers given(:user) { create(:user) } diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb index c31b816f7fb..db29055812c 100644 --- a/spec/features/projects/environments/environment_spec.rb +++ b/spec/features/projects/environments/environment_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Environment', :feature do +feature 'Environment' do given(:project) { create(:empty_project) } given(:user) { create(:user) } given(:role) { :developer } diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb index 99b917cb420..e40e0b0c871 100644 --- a/spec/features/projects/environments/environments_spec.rb +++ b/spec/features/projects/environments/environments_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Environments page', :feature, :js do +feature 'Environments page', :js do given(:project) { create(:empty_project) } given(:user) { create(:user) } given(:role) { :developer } diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb index 1588f8a828a..16b0fa6e1ae 100644 --- a/spec/features/projects/features_visibility_spec.rb +++ b/spec/features/projects/features_visibility_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Edit Project Settings', feature: true do +describe 'Edit Project Settings' do let(:member) { create(:user) } let!(:project) { create(:project, :public, path: 'gitlab', name: 'sample') } let!(:issue) { create(:issue, project: project) } diff --git a/spec/features/projects/files/browse_files_spec.rb b/spec/features/projects/files/browse_files_spec.rb index d9a561b23a2..77b2fd4f80f 100644 --- a/spec/features/projects/files/browse_files_spec.rb +++ b/spec/features/projects/files/browse_files_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'user browses project', feature: true, js: true do +feature 'user browses project', js: true do let(:project) { create(:project) } let(:user) { create(:user) } diff --git a/spec/features/projects/files/creating_a_file_spec.rb b/spec/features/projects/files/creating_a_file_spec.rb index 55350db4c34..d49e1541869 100644 --- a/spec/features/projects/files/creating_a_file_spec.rb +++ b/spec/features/projects/files/creating_a_file_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'User wants to create a file', feature: true do +feature 'User wants to create a file' do let(:project) { create(:project) } let(:user) { create(:user) } diff --git a/spec/features/projects/files/dockerfile_dropdown_spec.rb b/spec/features/projects/files/dockerfile_dropdown_spec.rb index 0cd0c9addd0..6d44c49bb6f 100644 --- a/spec/features/projects/files/dockerfile_dropdown_spec.rb +++ b/spec/features/projects/files/dockerfile_dropdown_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require 'fileutils' -feature 'User wants to add a Dockerfile file', feature: true do +feature 'User wants to add a Dockerfile file' do before do user = create(:user) project = create(:project) diff --git a/spec/features/projects/files/download_buttons_spec.rb b/spec/features/projects/files/download_buttons_spec.rb index a2874483149..25168203d15 100644 --- a/spec/features/projects/files/download_buttons_spec.rb +++ b/spec/features/projects/files/download_buttons_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Download buttons in files tree', feature: true do +feature 'Download buttons in files tree' do given(:user) { create(:user) } given(:role) { :developer } given(:status) { 'success' } diff --git a/spec/features/projects/files/edit_file_soft_wrap_spec.rb b/spec/features/projects/files/edit_file_soft_wrap_spec.rb index 930e4cf488a..8a4511df842 100644 --- a/spec/features/projects/files/edit_file_soft_wrap_spec.rb +++ b/spec/features/projects/files/edit_file_soft_wrap_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'User uses soft wrap whilst editing file', feature: true, js: true do +feature 'User uses soft wrap whilst editing file', js: true do before do user = create(:user) project = create(:project) diff --git a/spec/features/projects/files/editing_a_file_spec.rb b/spec/features/projects/files/editing_a_file_spec.rb index c295380dfc9..e084ab17441 100644 --- a/spec/features/projects/files/editing_a_file_spec.rb +++ b/spec/features/projects/files/editing_a_file_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'User wants to edit a file', feature: true do +feature 'User wants to edit a file' do let(:project) { create(:project) } let(:user) { create(:user) } let(:commit_params) do diff --git a/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb b/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb index 9a1eaee08de..702b99de733 100644 --- a/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb +++ b/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'User views files page', feature: true do +feature 'User views files page' do let(:user) { create(:user) } let(:project) { create(:forked_project_with_submodules) } diff --git a/spec/features/projects/files/find_file_keyboard_spec.rb b/spec/features/projects/files/find_file_keyboard_spec.rb index 772f81c8853..d7e96811e33 100644 --- a/spec/features/projects/files/find_file_keyboard_spec.rb +++ b/spec/features/projects/files/find_file_keyboard_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Find file keyboard shortcuts', feature: true, js: true do +feature 'Find file keyboard shortcuts', js: true do let(:user) { create(:user) } let(:project) { create(:project) } diff --git a/spec/features/projects/files/find_files_spec.rb b/spec/features/projects/files/find_files_spec.rb index 7a99596585f..05003f6a4f5 100644 --- a/spec/features/projects/files/find_files_spec.rb +++ b/spec/features/projects/files/find_files_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Find files button in the tree header', feature: true do +feature 'Find files button in the tree header' do given(:user) { create(:user) } given(:project) { create(:project) } diff --git a/spec/features/projects/files/gitignore_dropdown_spec.rb b/spec/features/projects/files/gitignore_dropdown_spec.rb index a3a7b08c013..4340c98d0d9 100644 --- a/spec/features/projects/files/gitignore_dropdown_spec.rb +++ b/spec/features/projects/files/gitignore_dropdown_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'User wants to add a .gitignore file', feature: true do +feature 'User wants to add a .gitignore file' do before do user = create(:user) project = create(:project) diff --git a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb index 41afe8014d9..f42a26b6954 100644 --- a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb +++ b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'User wants to add a .gitlab-ci.yml file', feature: true do +feature 'User wants to add a .gitlab-ci.yml file' do before do user = create(:user) project = create(:project) diff --git a/spec/features/projects/files/project_owner_creates_license_file_spec.rb b/spec/features/projects/files/project_owner_creates_license_file_spec.rb index 57f4a6f1b6f..300b631a2f4 100644 --- a/spec/features/projects/files/project_owner_creates_license_file_spec.rb +++ b/spec/features/projects/files/project_owner_creates_license_file_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'project owner creates a license file', feature: true, js: true do +feature 'project owner creates a license file', js: true do let(:project_master) { create(:user) } let(:project) { create(:project) } background do diff --git a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb index 0604ecb8c8b..1f4b3763b40 100644 --- a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb +++ b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'project owner sees a link to create a license file in empty project', feature: true, js: true do +feature 'project owner sees a link to create a license file in empty project', js: true do let(:project_master) { create(:user) } let(:project) { create(:empty_project) } background do diff --git a/spec/features/projects/gfm_autocomplete_load_spec.rb b/spec/features/projects/gfm_autocomplete_load_spec.rb index aa2306069ad..7bcd3f632a8 100644 --- a/spec/features/projects/gfm_autocomplete_load_spec.rb +++ b/spec/features/projects/gfm_autocomplete_load_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'GFM autocomplete loading', feature: true, js: true do +describe 'GFM autocomplete loading', js: true do let(:project) { create(:project) } before do diff --git a/spec/features/projects/group_links_spec.rb b/spec/features/projects/group_links_spec.rb index 631955a60a1..5195d027a9f 100644 --- a/spec/features/projects/group_links_spec.rb +++ b/spec/features/projects/group_links_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Project group links', :feature, :js do +feature 'Project group links', :js do include Select2Helper let(:master) { create(:user) } diff --git a/spec/features/projects/import_export/export_file_spec.rb b/spec/features/projects/import_export/export_file_spec.rb index 43c2c401f4a..62d244ff259 100644 --- a/spec/features/projects/import_export/export_file_spec.rb +++ b/spec/features/projects/import_export/export_file_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' # It looks up for any sensitive word inside the JSON, so if a sensitive word is found # we''l have to either include it adding the model that includes it to the +safe_list+ # or make sure the attribute is blacklisted in the +import_export.yml+ configuration -feature 'Import/Export - project export integration test', feature: true, js: true do +feature 'Import/Export - project export integration test', js: true do include Select2Helper include ExportFileHelper diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb index 533ff4612ff..c0cfb9eafe2 100644 --- a/spec/features/projects/import_export/import_file_spec.rb +++ b/spec/features/projects/import_export/import_file_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Import/Export - project import integration test', feature: true, js: true do +feature 'Import/Export - project import integration test', js: true do include Select2Helper let(:file) { File.join(Rails.root, 'spec', 'features', 'projects', 'import_export', 'test_project_export.tar.gz') } diff --git a/spec/features/projects/import_export/namespace_export_file_spec.rb b/spec/features/projects/import_export/namespace_export_file_spec.rb index 74ced0d3b35..3917e72c39e 100644 --- a/spec/features/projects/import_export/namespace_export_file_spec.rb +++ b/spec/features/projects/import_export/namespace_export_file_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Import/Export - Namespace export file cleanup', feature: true, js: true do +feature 'Import/Export - Namespace export file cleanup', js: true do let(:export_path) { "#{Dir.tmpdir}/import_file_spec" } let(:config_hash) { YAML.load_file(Gitlab::ImportExport.config_file).deep_stringify_keys } diff --git a/spec/features/projects/issuable_templates_spec.rb b/spec/features/projects/issuable_templates_spec.rb index 88bb678362b..8c2e49377e7 100644 --- a/spec/features/projects/issuable_templates_spec.rb +++ b/spec/features/projects/issuable_templates_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'issuable templates', feature: true, js: true do +feature 'issuable templates', js: true do let(:user) { create(:user) } let(:project) { create(:project, :public) } diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index 411987573fa..395d68d3fb4 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require 'tempfile' -feature 'Jobs', :feature do +feature 'Jobs' do let(:user) { create(:user) } let(:user_access_level) { :developer } let(:project) { create(:project) } diff --git a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb index 652008bae73..0292a3192d8 100644 --- a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb +++ b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Issue prioritization', feature: true do +feature 'Issue prioritization' do let(:user) { create(:user) } let(:project) { create(:project, name: 'test', namespace: user.namespace) } diff --git a/spec/features/projects/labels/subscription_spec.rb b/spec/features/projects/labels/subscription_spec.rb index 58421e11e0a..3115a643d5d 100644 --- a/spec/features/projects/labels/subscription_spec.rb +++ b/spec/features/projects/labels/subscription_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Labels subscription', feature: true do +feature 'Labels subscription' do let(:user) { create(:user) } let(:group) { create(:group) } let(:project) { create(:empty_project, :public, namespace: group) } diff --git a/spec/features/projects/labels/update_prioritization_spec.rb b/spec/features/projects/labels/update_prioritization_spec.rb index 9b51b427845..223f94ff9f9 100644 --- a/spec/features/projects/labels/update_prioritization_spec.rb +++ b/spec/features/projects/labels/update_prioritization_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Prioritize labels', feature: true do +feature 'Prioritize labels' do include DragTo let(:user) { create(:user) } diff --git a/spec/features/projects/main/download_buttons_spec.rb b/spec/features/projects/main/download_buttons_spec.rb index 8b952d2f3a5..a8ae0ecbae0 100644 --- a/spec/features/projects/main/download_buttons_spec.rb +++ b/spec/features/projects/main/download_buttons_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Download buttons in project main page', feature: true do +feature 'Download buttons in project main page' do given(:user) { create(:user) } given(:role) { :developer } given(:status) { 'success' } diff --git a/spec/features/projects/members/anonymous_user_sees_members_spec.rb b/spec/features/projects/members/anonymous_user_sees_members_spec.rb index 28c8d20aad5..a26e7becdb9 100644 --- a/spec/features/projects/members/anonymous_user_sees_members_spec.rb +++ b/spec/features/projects/members/anonymous_user_sees_members_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Members > Anonymous user sees members', feature: true do +feature 'Projects > Members > Anonymous user sees members' do let(:user) { create(:user) } let(:group) { create(:group, :public) } let(:project) { create(:empty_project, :public) } diff --git a/spec/features/projects/members/group_links_spec.rb b/spec/features/projects/members/group_links_spec.rb index b9154915b34..acda5808313 100644 --- a/spec/features/projects/members/group_links_spec.rb +++ b/spec/features/projects/members/group_links_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Members > Anonymous user sees members', feature: true, js: true do +feature 'Projects > Members > Anonymous user sees members', js: true do let(:user) { create(:user) } let(:group) { create(:group, :public) } let(:project) { create(:empty_project, :public) } diff --git a/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb b/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb index 2c99c2c7888..6b450fa4e45 100644 --- a/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb +++ b/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Members > Group member cannot leave group project', feature: true do +feature 'Projects > Members > Group member cannot leave group project' do let(:user) { create(:user) } let(:group) { create(:group) } let(:project) { create(:project, namespace: group) } diff --git a/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb b/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb index 35142273eae..296a80a3c60 100644 --- a/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb +++ b/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Members > Group member cannot request access to his group project', feature: true do +feature 'Projects > Members > Group member cannot request access to his group project' do let(:user) { create(:user) } let(:group) { create(:group) } let(:project) { create(:project, namespace: group) } diff --git a/spec/features/projects/members/group_members_spec.rb b/spec/features/projects/members/group_members_spec.rb index bfc604bb8d6..154f9f4a26c 100644 --- a/spec/features/projects/members/group_members_spec.rb +++ b/spec/features/projects/members/group_members_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects members', feature: true do +feature 'Projects members' do let(:user) { create(:user) } let(:developer) { create(:user) } let(:group) { create(:group, :public, :access_requestable) } diff --git a/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb b/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb index 46f5744b32d..c8988aa63a7 100644 --- a/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb +++ b/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Members > Group requester cannot request access to project', feature: true, js: true do +feature 'Projects > Members > Group requester cannot request access to project', js: true do let(:user) { create(:user) } let(:owner) { create(:user) } let(:group) { create(:group, :public, :access_requestable) } diff --git a/spec/features/projects/members/list_spec.rb b/spec/features/projects/members/list_spec.rb index 301f68a67d3..237c059e595 100644 --- a/spec/features/projects/members/list_spec.rb +++ b/spec/features/projects/members/list_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Project members list', feature: true do +feature 'Project members list' do include Select2Helper let(:user1) { create(:user, name: 'John Doe') } diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb index 14edfb6e673..cd621b6b3ce 100644 --- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb +++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Members > Master adds member with expiration date', feature: true, js: true do +feature 'Projects > Members > Master adds member with expiration date', js: true do include Select2Helper include ActiveSupport::Testing::TimeHelpers diff --git a/spec/features/projects/members/master_manages_access_requests_spec.rb b/spec/features/projects/members/master_manages_access_requests_spec.rb index a359c209556..0f96a7cc70d 100644 --- a/spec/features/projects/members/master_manages_access_requests_spec.rb +++ b/spec/features/projects/members/master_manages_access_requests_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Members > Master manages access requests', feature: true do +feature 'Projects > Members > Master manages access requests' do let(:user) { create(:user) } let(:master) { create(:user) } let(:project) { create(:empty_project, :public, :access_requestable) } diff --git a/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb b/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb index 55852012bae..04806f8fd9e 100644 --- a/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb +++ b/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Members > Member cannot request access to his project', feature: true do +feature 'Projects > Members > Member cannot request access to his project' do let(:member) { create(:user) } let(:project) { create(:project) } diff --git a/spec/features/projects/members/member_leaves_project_spec.rb b/spec/features/projects/members/member_leaves_project_spec.rb index 3de13aee0ee..e72283d3628 100644 --- a/spec/features/projects/members/member_leaves_project_spec.rb +++ b/spec/features/projects/members/member_leaves_project_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Members > Member leaves project', feature: true do +feature 'Projects > Members > Member leaves project' do let(:user) { create(:user) } let(:project) { create(:project) } diff --git a/spec/features/projects/members/owner_cannot_leave_project_spec.rb b/spec/features/projects/members/owner_cannot_leave_project_spec.rb index fae52325be0..15162d01c44 100644 --- a/spec/features/projects/members/owner_cannot_leave_project_spec.rb +++ b/spec/features/projects/members/owner_cannot_leave_project_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Members > Owner cannot leave project', feature: true do +feature 'Projects > Members > Owner cannot leave project' do let(:project) { create(:project) } background do diff --git a/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb b/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb index a7a5e01465f..c27925c8dc4 100644 --- a/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb +++ b/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Members > Owner cannot request access to his project', feature: true do +feature 'Projects > Members > Owner cannot request access to his project' do let(:project) { create(:project) } background do diff --git a/spec/features/projects/members/sorting_spec.rb b/spec/features/projects/members/sorting_spec.rb index dc7236fa120..45c2647e6e2 100644 --- a/spec/features/projects/members/sorting_spec.rb +++ b/spec/features/projects/members/sorting_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Members > Sorting', feature: true do +feature 'Projects > Members > Sorting' do let(:master) { create(:user, name: 'John Doe') } let(:developer) { create(:user, name: 'Mary Jane', last_sign_in_at: 5.days.ago) } let(:project) { create(:empty_project, namespace: master.namespace, creator: master) } diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb index ab86e2da4f6..2979563f33a 100644 --- a/spec/features/projects/members/user_requests_access_spec.rb +++ b/spec/features/projects/members/user_requests_access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Members > User requests access', feature: true do +feature 'Projects > Members > User requests access' do let(:user) { create(:user) } let(:project) { create(:project, :public, :access_requestable) } let(:master) { project.owner } diff --git a/spec/features/projects/milestones/milestone_spec.rb b/spec/features/projects/milestones/milestone_spec.rb index 642ca7448a3..b1c38ecc9ab 100644 --- a/spec/features/projects/milestones/milestone_spec.rb +++ b/spec/features/projects/milestones/milestone_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Project milestone', :feature do +feature 'Project milestone' do let(:user) { create(:user) } let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) } let(:milestone) { create(:milestone, project: project) } diff --git a/spec/features/projects/milestones/milestones_sorting_spec.rb b/spec/features/projects/milestones/milestones_sorting_spec.rb index 53cd2711666..4bd1929ac1e 100644 --- a/spec/features/projects/milestones/milestones_sorting_spec.rb +++ b/spec/features/projects/milestones/milestones_sorting_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Milestones sorting', :feature, :js do +feature 'Milestones sorting', :js do include SortingHelper let(:user) { create(:user) } let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) } diff --git a/spec/features/projects/milestones/new_spec.rb b/spec/features/projects/milestones/new_spec.rb index 3c81db502bc..7cfcccda439 100644 --- a/spec/features/projects/milestones/new_spec.rb +++ b/spec/features/projects/milestones/new_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Creating a new project milestone', :feature, :js do +feature 'Creating a new project milestone', :js do let(:user) { create(:user) } let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) } diff --git a/spec/features/projects/pages_spec.rb b/spec/features/projects/pages_spec.rb index a8593709f1b..42f23ee5dec 100644 --- a/spec/features/projects/pages_spec.rb +++ b/spec/features/projects/pages_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Pages', feature: true do +feature 'Pages' do given(:project) { create(:empty_project) } given(:user) { create(:user) } given(:role) { :master } diff --git a/spec/features/projects/pipeline_schedules_spec.rb b/spec/features/projects/pipeline_schedules_spec.rb index de6dd8fc8a6..47ed4c7e7c1 100644 --- a/spec/features/projects/pipeline_schedules_spec.rb +++ b/spec/features/projects/pipeline_schedules_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Pipeline Schedules', :feature, js: true do +feature 'Pipeline Schedules', :js do include PipelineSchedulesHelper let!(:project) { create(:project) } diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index 4a08d9088aa..d4319bca331 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Pipeline', :feature, :js do +describe 'Pipeline', :js do let(:project) { create(:empty_project) } let(:user) { create(:user) } diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index d776fbc2b12..6bef7317d30 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Pipelines', :feature, :js do +describe 'Pipelines', :js do let(:project) { create(:empty_project) } context 'when user is logged in' do diff --git a/spec/features/projects/project_settings_spec.rb b/spec/features/projects/project_settings_spec.rb index 89d227eb98f..7e43ef92a72 100644 --- a/spec/features/projects/project_settings_spec.rb +++ b/spec/features/projects/project_settings_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Edit Project Settings', feature: true do +describe 'Edit Project Settings' do include Select2Helper let(:user) { create(:user) } diff --git a/spec/features/projects/ref_switcher_spec.rb b/spec/features/projects/ref_switcher_spec.rb index 9f5544ac43e..2512818b297 100644 --- a/spec/features/projects/ref_switcher_spec.rb +++ b/spec/features/projects/ref_switcher_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Ref switcher', feature: true, js: true do +feature 'Ref switcher', js: true do let(:user) { create(:user) } let(:project) { create(:project, :public) } diff --git a/spec/features/projects/services/jira_service_spec.rb b/spec/features/projects/services/jira_service_spec.rb index b71eec0ecfd..d0e26cc7dac 100644 --- a/spec/features/projects/services/jira_service_spec.rb +++ b/spec/features/projects/services/jira_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Setup Jira service', :feature, :js do +feature 'Setup Jira service', :js do let(:user) { create(:user) } let(:project) { create(:empty_project) } let(:service) { project.create_jira_service } diff --git a/spec/features/projects/services/mattermost_slash_command_spec.rb b/spec/features/projects/services/mattermost_slash_command_spec.rb index 3319b0fedf3..134d7e5e8b7 100644 --- a/spec/features/projects/services/mattermost_slash_command_spec.rb +++ b/spec/features/projects/services/mattermost_slash_command_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Setup Mattermost slash commands', :feature, :js do +feature 'Setup Mattermost slash commands', :js do let(:user) { create(:user) } let(:project) { create(:empty_project) } let(:service) { project.create_mattermost_slash_commands_service } diff --git a/spec/features/projects/services/slack_service_spec.rb b/spec/features/projects/services/slack_service_spec.rb index 709cd1226c3..c10ec5e2987 100644 --- a/spec/features/projects/services/slack_service_spec.rb +++ b/spec/features/projects/services/slack_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Slack service > Setup events', feature: true do +feature 'Projects > Slack service > Setup events' do let(:user) { create(:user) } let(:service) { SlackService.new } let(:project) { create(:project, slack_service: service) } diff --git a/spec/features/projects/services/slack_slash_command_spec.rb b/spec/features/projects/services/slack_slash_command_spec.rb index 71f5a8d7a4e..a8baf126269 100644 --- a/spec/features/projects/services/slack_slash_command_spec.rb +++ b/spec/features/projects/services/slack_slash_command_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Slack slash commands', feature: true do +feature 'Slack slash commands' do given(:user) { create(:user) } given(:project) { create(:project) } given(:service) { project.create_slack_slash_commands_service } diff --git a/spec/features/projects/settings/integration_settings_spec.rb b/spec/features/projects/settings/integration_settings_spec.rb index 6ae242af87f..1de4918e142 100644 --- a/spec/features/projects/settings/integration_settings_spec.rb +++ b/spec/features/projects/settings/integration_settings_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Integration settings', feature: true do +feature 'Integration settings' do let(:project) { create(:empty_project) } let(:user) { create(:user) } let(:role) { :developer } diff --git a/spec/features/projects/settings/merge_requests_settings_spec.rb b/spec/features/projects/settings/merge_requests_settings_spec.rb index ecaf65c4ad9..796e2026905 100644 --- a/spec/features/projects/settings/merge_requests_settings_spec.rb +++ b/spec/features/projects/settings/merge_requests_settings_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Project settings > Merge Requests', feature: true, js: true do +feature 'Project settings > Merge Requests', :js do let(:project) { create(:empty_project, :public) } let(:user) { create(:user) } diff --git a/spec/features/projects/settings/pipelines_settings_spec.rb b/spec/features/projects/settings/pipelines_settings_spec.rb index 724cfa10e72..f24d7ff64d0 100644 --- a/spec/features/projects/settings/pipelines_settings_spec.rb +++ b/spec/features/projects/settings/pipelines_settings_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature "Pipelines settings", feature: true do +feature "Pipelines settings" do let(:project) { create(:empty_project) } let(:user) { create(:user) } let(:role) { :developer } diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb index 98539518f6c..15180d4b498 100644 --- a/spec/features/projects/settings/repository_settings_spec.rb +++ b/spec/features/projects/settings/repository_settings_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Repository settings', feature: true do +feature 'Repository settings' do let(:project) { create(:project_empty_repo) } let(:user) { create(:user) } let(:role) { :developer } diff --git a/spec/features/projects/settings/visibility_settings_spec.rb b/spec/features/projects/settings/visibility_settings_spec.rb index 32d8f1fd16a..1756c7d00fe 100644 --- a/spec/features/projects/settings/visibility_settings_spec.rb +++ b/spec/features/projects/settings/visibility_settings_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Visibility settings', feature: true, js: true do +feature 'Visibility settings', js: true do let(:user) { create(:user) } let(:project) { create(:project, namespace: user.namespace, visibility_level: 20) } diff --git a/spec/features/projects/shortcuts_spec.rb b/spec/features/projects/shortcuts_spec.rb index 8dd70e07b30..bf18c444c3d 100644 --- a/spec/features/projects/shortcuts_spec.rb +++ b/spec/features/projects/shortcuts_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Project shortcuts', feature: true do +feature 'Project shortcuts' do let(:project) { create(:project, name: 'Victorialand') } let(:user) { create(:user) } diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb index 06d32423a13..23d4b9233b3 100644 --- a/spec/features/projects/snippets/create_snippet_spec.rb +++ b/spec/features/projects/snippets/create_snippet_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Create Snippet', :js, feature: true do +feature 'Create Snippet', :js do include DropzoneHelper let(:user) { create(:user) } diff --git a/spec/features/projects/snippets/show_spec.rb b/spec/features/projects/snippets/show_spec.rb index 52698fe1fa3..08dc7cf6c5b 100644 --- a/spec/features/projects/snippets/show_spec.rb +++ b/spec/features/projects/snippets/show_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Project snippet', :js, feature: true do +feature 'Project snippet', :js do let(:user) { create(:user) } let(:project) { create(:project, :repository) } let(:snippet) { create(:project_snippet, project: project, file_name: file_name, content: content) } diff --git a/spec/features/projects/snippets_spec.rb b/spec/features/projects/snippets_spec.rb index 513a05151b2..0822684a42c 100644 --- a/spec/features/projects/snippets_spec.rb +++ b/spec/features/projects/snippets_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Project snippets', :js, feature: true do +describe 'Project snippets', :js do context 'when the project has snippets' do let(:project) { create(:empty_project, :public) } let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.owner, project: project) } diff --git a/spec/features/projects/sub_group_issuables_spec.rb b/spec/features/projects/sub_group_issuables_spec.rb index 007910bb931..262dcc0abff 100644 --- a/spec/features/projects/sub_group_issuables_spec.rb +++ b/spec/features/projects/sub_group_issuables_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Subgroup Issuables', :feature, :js, :nested_groups do +describe 'Subgroup Issuables', :js, :nested_groups do let!(:group) { create(:group, name: 'group') } let!(:subgroup) { create(:group, parent: group, name: 'subgroup') } let!(:project) { create(:empty_project, namespace: subgroup, name: 'project') } diff --git a/spec/features/projects/tags/download_buttons_spec.rb b/spec/features/projects/tags/download_buttons_spec.rb index 34c5e59c3e5..a6c5a486bcc 100644 --- a/spec/features/projects/tags/download_buttons_spec.rb +++ b/spec/features/projects/tags/download_buttons_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Download buttons in tags page', feature: true do +feature 'Download buttons in tags page' do given(:user) { create(:user) } given(:role) { :developer } given(:status) { 'success' } diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb index 231e8eed4fb..45f799ebb48 100644 --- a/spec/features/projects/wiki/markdown_preview_spec.rb +++ b/spec/features/projects/wiki/markdown_preview_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Wiki > User previews markdown changes', feature: true, js: true do +feature 'Projects > Wiki > User previews markdown changes', js: true do let(:user) { create(:user) } let(:project) { create(:project, namespace: user.namespace) } let(:wiki_content) do diff --git a/spec/features/projects/wiki/shortcuts_spec.rb b/spec/features/projects/wiki/shortcuts_spec.rb index ea816082479..2c668185666 100644 --- a/spec/features/projects/wiki/shortcuts_spec.rb +++ b/spec/features/projects/wiki/shortcuts_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Wiki shortcuts', :feature, :js do +feature 'Wiki shortcuts', :js do let(:user) { create(:user) } let(:project) { create(:empty_project, namespace: user.namespace) } let(:wiki_page) do diff --git a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb index 9445b88af8d..3450c91260b 100644 --- a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Projects > Wiki > User views Git access wiki page', :feature do +describe 'Projects > Wiki > User views Git access wiki page' do let(:user) { create(:user) } let(:project) { create(:project, :public) } let(:wiki_page) do diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb index 425195840d8..6ebf59cba98 100644 --- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Wiki > User updates wiki page', feature: true do +feature 'Projects > Wiki > User updates wiki page' do let(:user) { create(:user) } background do diff --git a/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb b/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb index 13e882ad665..92e96f11219 100644 --- a/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projects > Wiki > User views the wiki page', feature: true do +feature 'Projects > Wiki > User views the wiki page' do let(:user) { create(:user) } let(:project) { create(:project, :public) } let(:old_page_version_id) { wiki_page.versions.last.id } diff --git a/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb index 2234af1d795..8d1e6f66039 100644 --- a/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb +++ b/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Projects > Wiki > User views wiki in project page', feature: true do +describe 'Projects > Wiki > User views wiki in project page' do let(:user) { create(:user) } before do diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index 10c7e5934e4..3295f7f9174 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Project', feature: true do +feature 'Project' do describe 'description' do let(:project) { create(:project, :repository) } let(:path) { project_path(project) } diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb index 8a3574546c2..3677bf38724 100644 --- a/spec/features/protected_branches_spec.rb +++ b/spec/features/protected_branches_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Protected Branches', feature: true, js: true do +feature 'Protected Branches', js: true do let(:user) { create(:user, :admin) } let(:project) { create(:project, :repository) } diff --git a/spec/features/protected_tags_spec.rb b/spec/features/protected_tags_spec.rb index 7a22cf60996..c9ba1a8c088 100644 --- a/spec/features/protected_tags_spec.rb +++ b/spec/features/protected_tags_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projected Tags', feature: true, js: true do +feature 'Projected Tags', js: true do let(:user) { create(:user, :admin) } let(:project) { create(:project, :repository) } diff --git a/spec/features/raven_js_spec.rb b/spec/features/raven_js_spec.rb index e8fa49c18cb..b1f51959d54 100644 --- a/spec/features/raven_js_spec.rb +++ b/spec/features/raven_js_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'RavenJS', :feature, :js do +feature 'RavenJS', :js do let(:raven_path) { '/raven.bundle.js' } it 'should not load raven if sentry is disabled' do diff --git a/spec/features/reportable_note/commit_spec.rb b/spec/features/reportable_note/commit_spec.rb index d82ebe02f77..1074eb62b33 100644 --- a/spec/features/reportable_note/commit_spec.rb +++ b/spec/features/reportable_note/commit_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Reportable note on commit', :feature, :js do +describe 'Reportable note on commit', :js do include RepoHelpers let(:user) { create(:user) } diff --git a/spec/features/reportable_note/issue_spec.rb b/spec/features/reportable_note/issue_spec.rb index cb1cb1a1417..9964a32db2e 100644 --- a/spec/features/reportable_note/issue_spec.rb +++ b/spec/features/reportable_note/issue_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Reportable note on issue', :feature, :js do +describe 'Reportable note on issue', :js do let(:user) { create(:user) } let(:project) { create(:empty_project) } let(:issue) { create(:issue, project: project) } diff --git a/spec/features/reportable_note/merge_request_spec.rb b/spec/features/reportable_note/merge_request_spec.rb index 8a531b9a9e9..a491abdb6cb 100644 --- a/spec/features/reportable_note/merge_request_spec.rb +++ b/spec/features/reportable_note/merge_request_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Reportable note on merge request', :feature, :js do +describe 'Reportable note on merge request', :js do let(:user) { create(:user) } let(:project) { create(:project) } let(:merge_request) { create(:merge_request, source_project: project) } diff --git a/spec/features/reportable_note/snippets_spec.rb b/spec/features/reportable_note/snippets_spec.rb index f560a0ebfd9..9a14024684c 100644 --- a/spec/features/reportable_note/snippets_spec.rb +++ b/spec/features/reportable_note/snippets_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Reportable note on snippets', :feature, :js do +describe 'Reportable note on snippets', :js do let(:user) { create(:user) } let(:project) { create(:empty_project) } diff --git a/spec/features/search_spec.rb b/spec/features/search_spec.rb index 12ef23440b7..b29f19f1562 100644 --- a/spec/features/search_spec.rb +++ b/spec/features/search_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Search", feature: true do +describe "Search" do include FilteredSearchHelpers let(:user) { create(:user) } @@ -154,7 +154,7 @@ describe "Search", feature: true do end end - describe 'Right header search field', feature: true do + describe 'Right header search field' do it 'allows enter key to search', js: true do visit project_path(project) fill_in 'search', with: 'gitlab' diff --git a/spec/features/security/admin_access_spec.rb b/spec/features/security/admin_access_spec.rb index e180ca53eb5..3ca1303bda6 100644 --- a/spec/features/security/admin_access_spec.rb +++ b/spec/features/security/admin_access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Admin::Projects", feature: true do +describe "Admin::Projects" do include AccessMatchers describe "GET /admin/projects" do diff --git a/spec/features/security/dashboard_access_spec.rb b/spec/features/security/dashboard_access_spec.rb index 40f773956d1..149bd32e736 100644 --- a/spec/features/security/dashboard_access_spec.rb +++ b/spec/features/security/dashboard_access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Dashboard access", feature: true do +describe "Dashboard access" do include AccessMatchers describe "GET /dashboard" do diff --git a/spec/features/security/group/internal_access_spec.rb b/spec/features/security/group/internal_access_spec.rb index 87cce32d6c6..53573043ac7 100644 --- a/spec/features/security/group/internal_access_spec.rb +++ b/spec/features/security/group/internal_access_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Internal Group access', feature: true do +describe 'Internal Group access' do include AccessMatchers let(:group) { create(:group, :internal) } diff --git a/spec/features/security/group/private_access_spec.rb b/spec/features/security/group/private_access_spec.rb index 1d6b3e77c22..76c4e2c7197 100644 --- a/spec/features/security/group/private_access_spec.rb +++ b/spec/features/security/group/private_access_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Private Group access', feature: true do +describe 'Private Group access' do include AccessMatchers let(:group) { create(:group, :private) } diff --git a/spec/features/security/group/public_access_spec.rb b/spec/features/security/group/public_access_spec.rb index d7d76177269..52e87d8d055 100644 --- a/spec/features/security/group/public_access_spec.rb +++ b/spec/features/security/group/public_access_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Public Group access', feature: true do +describe 'Public Group access' do include AccessMatchers let(:group) { create(:group, :public) } diff --git a/spec/features/security/profile_access_spec.rb b/spec/features/security/profile_access_spec.rb index c19678ab381..41eb7b26578 100644 --- a/spec/features/security/profile_access_spec.rb +++ b/spec/features/security/profile_access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Profile access", feature: true do +describe "Profile access" do include AccessMatchers describe "GET /profile/keys" do diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb index 1000a0bdd89..290cebf511a 100644 --- a/spec/features/security/project/internal_access_spec.rb +++ b/spec/features/security/project/internal_access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Internal Project Access", feature: true do +describe "Internal Project Access" do include AccessMatchers set(:project) { create(:project, :internal) } diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb index 94d759393ca..276d817b59c 100644 --- a/spec/features/security/project/private_access_spec.rb +++ b/spec/features/security/project/private_access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Private Project Access", feature: true do +describe "Private Project Access" do include AccessMatchers set(:project) { create(:project, :private, public_builds: false) } diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb index d45e1dbc09b..417b0894a5c 100644 --- a/spec/features/security/project/public_access_spec.rb +++ b/spec/features/security/project/public_access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Public Project Access", feature: true do +describe "Public Project Access" do include AccessMatchers set(:project) { create(:project, :public) } diff --git a/spec/features/security/project/snippet/internal_access_spec.rb b/spec/features/security/project/snippet/internal_access_spec.rb index 2420caa88c4..178782af56c 100644 --- a/spec/features/security/project/snippet/internal_access_spec.rb +++ b/spec/features/security/project/snippet/internal_access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Internal Project Snippets Access", feature: true do +describe "Internal Project Snippets Access" do include AccessMatchers let(:project) { create(:empty_project, :internal) } diff --git a/spec/features/security/project/snippet/private_access_spec.rb b/spec/features/security/project/snippet/private_access_spec.rb index 0b8548a675b..7725c25ca1f 100644 --- a/spec/features/security/project/snippet/private_access_spec.rb +++ b/spec/features/security/project/snippet/private_access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Private Project Snippets Access", feature: true do +describe "Private Project Snippets Access" do include AccessMatchers let(:project) { create(:empty_project, :private) } diff --git a/spec/features/security/project/snippet/public_access_spec.rb b/spec/features/security/project/snippet/public_access_spec.rb index 153f8f964a6..52aec75dcd0 100644 --- a/spec/features/security/project/snippet/public_access_spec.rb +++ b/spec/features/security/project/snippet/public_access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Public Project Snippets Access", feature: true do +describe "Public Project Snippets Access" do include AccessMatchers let(:project) { create(:empty_project, :public) } diff --git a/spec/features/signup_spec.rb b/spec/features/signup_spec.rb index 5d6d1e79af2..b6367b88e17 100644 --- a/spec/features/signup_spec.rb +++ b/spec/features/signup_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Signup', feature: true do +feature 'Signup' do describe 'signup with no errors' do context "when sending confirmation email" do before do diff --git a/spec/features/snippets/explore_spec.rb b/spec/features/snippets/explore_spec.rb index 97d1c2d65e6..835fd90adc8 100644 --- a/spec/features/snippets/explore_spec.rb +++ b/spec/features/snippets/explore_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Explore Snippets', feature: true do +feature 'Explore Snippets' do let!(:public_snippet) { create(:personal_snippet, :public) } let!(:internal_snippet) { create(:personal_snippet, :internal) } let!(:private_snippet) { create(:personal_snippet, :private) } diff --git a/spec/features/snippets/internal_snippet_spec.rb b/spec/features/snippets/internal_snippet_spec.rb index fb3e75f2102..3a229612235 100644 --- a/spec/features/snippets/internal_snippet_spec.rb +++ b/spec/features/snippets/internal_snippet_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Internal Snippets', feature: true, js: true do +feature 'Internal Snippets', js: true do let(:internal_snippet) { create(:personal_snippet, :internal) } describe 'normal user' do diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb index 17e93209f0c..f1d0905738b 100644 --- a/spec/features/snippets/notes_on_personal_snippets_spec.rb +++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Comments on personal snippets', :js, feature: true do +describe 'Comments on personal snippets', :js do include NoteInteractionHelpers let!(:user) { create(:user) } diff --git a/spec/features/snippets/public_snippets_spec.rb b/spec/features/snippets/public_snippets_spec.rb index afd945a8555..bdeeca7187e 100644 --- a/spec/features/snippets/public_snippets_spec.rb +++ b/spec/features/snippets/public_snippets_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Public Snippets', :js, feature: true do +feature 'Public Snippets', :js do scenario 'Unauthenticated user should see public snippets' do public_snippet = create(:personal_snippet, :public) diff --git a/spec/features/snippets/search_snippets_spec.rb b/spec/features/snippets/search_snippets_spec.rb index 5483df39a8b..cd66a2cb20c 100644 --- a/spec/features/snippets/search_snippets_spec.rb +++ b/spec/features/snippets/search_snippets_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Search Snippets', feature: true do +feature 'Search Snippets' do scenario 'User searches for snippets by title' do public_snippet = create(:personal_snippet, :public, title: 'Beginning and Middle') private_snippet = create(:personal_snippet, :private, title: 'Middle and End') diff --git a/spec/features/snippets/show_spec.rb b/spec/features/snippets/show_spec.rb index 95fc1d2bb62..5a48f5774ca 100644 --- a/spec/features/snippets/show_spec.rb +++ b/spec/features/snippets/show_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Snippet', :js, feature: true do +feature 'Snippet', :js do let(:project) { create(:project, :repository) } let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content) } diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb index 698d3b5d3e3..a919f5fa20b 100644 --- a/spec/features/snippets/user_creates_snippet_spec.rb +++ b/spec/features/snippets/user_creates_snippet_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'User creates snippet', :js, feature: true do +feature 'User creates snippet', :js do include DropzoneHelper let(:user) { create(:user) } diff --git a/spec/features/snippets/user_deletes_snippet_spec.rb b/spec/features/snippets/user_deletes_snippet_spec.rb index 162c2c9e730..ae5b883c477 100644 --- a/spec/features/snippets/user_deletes_snippet_spec.rb +++ b/spec/features/snippets/user_deletes_snippet_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'User deletes snippet', feature: true do +feature 'User deletes snippet' do let(:user) { create(:user) } let(:content) { 'puts "test"' } let(:snippet) { create(:personal_snippet, :public, content: content, author: user) } diff --git a/spec/features/snippets/user_edits_snippet_spec.rb b/spec/features/snippets/user_edits_snippet_spec.rb index c9f9741b4bb..26070e508e2 100644 --- a/spec/features/snippets/user_edits_snippet_spec.rb +++ b/spec/features/snippets/user_edits_snippet_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'User edits snippet', :js, feature: true do +feature 'User edits snippet', :js do include DropzoneHelper let(:file_name) { 'test.rb' } diff --git a/spec/features/snippets/user_snippets_spec.rb b/spec/features/snippets/user_snippets_spec.rb index 019310f2326..7bc27486787 100644 --- a/spec/features/snippets/user_snippets_spec.rb +++ b/spec/features/snippets/user_snippets_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'User Snippets', feature: true do +feature 'User Snippets' do let(:author) { create(:user) } let!(:public_snippet) { create(:personal_snippet, :public, author: author, title: "This is a public snippet") } let!(:internal_snippet) { create(:personal_snippet, :internal, author: author, title: "This is an internal snippet") } diff --git a/spec/features/snippets_spec.rb b/spec/features/snippets_spec.rb index 70b16bfc810..ae3b876f87c 100644 --- a/spec/features/snippets_spec.rb +++ b/spec/features/snippets_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Snippets', feature: true do +describe 'Snippets' do context 'when the project has snippets' do let(:project) { create(:empty_project, :public) } let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.owner, project: project) } diff --git a/spec/features/tags/master_creates_tag_spec.rb b/spec/features/tags/master_creates_tag_spec.rb index 1cef3d5c6f4..35e1ca32f67 100644 --- a/spec/features/tags/master_creates_tag_spec.rb +++ b/spec/features/tags/master_creates_tag_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Master creates tag', feature: true do +feature 'Master creates tag' do let(:user) { create(:user) } let(:project) { create(:project, namespace: user.namespace) } diff --git a/spec/features/tags/master_deletes_tag_spec.rb b/spec/features/tags/master_deletes_tag_spec.rb index 98af1d6b4f7..e3c904ef3aa 100644 --- a/spec/features/tags/master_deletes_tag_spec.rb +++ b/spec/features/tags/master_deletes_tag_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Master deletes tag', feature: true do +feature 'Master deletes tag' do let(:user) { create(:user) } let(:project) { create(:project, namespace: user.namespace) } diff --git a/spec/features/tags/master_updates_tag_spec.rb b/spec/features/tags/master_updates_tag_spec.rb index 1b61fde7227..d6e84a1c685 100644 --- a/spec/features/tags/master_updates_tag_spec.rb +++ b/spec/features/tags/master_updates_tag_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Master updates tag', feature: true do +feature 'Master updates tag' do let(:user) { create(:user) } let(:project) { create(:project, namespace: user.namespace) } diff --git a/spec/features/tags/master_views_tags_spec.rb b/spec/features/tags/master_views_tags_spec.rb index fb910feae34..27936bc7f52 100644 --- a/spec/features/tags/master_views_tags_spec.rb +++ b/spec/features/tags/master_views_tags_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Master views tags', feature: true do +feature 'Master views tags' do let(:user) { create(:user) } before do diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb index dfc362321aa..7e198ce0677 100644 --- a/spec/features/task_lists_spec.rb +++ b/spec/features/task_lists_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Task Lists', feature: true do +feature 'Task Lists' do include Warden::Test::Helpers let(:project) { create(:empty_project) } @@ -62,7 +62,7 @@ feature 'Task Lists', feature: true do visit project_issue_path(project, issue) end - describe 'for Issues', feature: true do + describe 'for Issues' do describe 'multiple tasks', js: true do let!(:issue) { create(:issue, description: markdown, author: user, project: project) } diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb index 47d5f94f54e..604fe326e96 100644 --- a/spec/features/triggers_spec.rb +++ b/spec/features/triggers_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Triggers', feature: true, js: true do +feature 'Triggers', js: true do let(:trigger_title) { 'trigger desc' } let(:user) { create(:user) } let(:user2) { create(:user) } diff --git a/spec/features/unsubscribe_links_spec.rb b/spec/features/unsubscribe_links_spec.rb index 352f8ba70ac..d728dc59b3f 100644 --- a/spec/features/unsubscribe_links_spec.rb +++ b/spec/features/unsubscribe_links_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Unsubscribe links', feature: true do +describe 'Unsubscribe links' do include Warden::Test::Helpers let(:recipient) { create(:user) } diff --git a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb index 8188d4c79f4..e8884bc1a00 100644 --- a/spec/features/uploads/user_uploads_avatar_to_group_spec.rb +++ b/spec/features/uploads/user_uploads_avatar_to_group_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'User uploads avatar to group', feature: true do +feature 'User uploads avatar to group' do scenario 'they see the new avatar' do user = create(:user) group = create(:group) diff --git a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb index 2628508afe8..52003bb0859 100644 --- a/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb +++ b/spec/features/uploads/user_uploads_avatar_to_profile_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'User uploads avatar to profile', feature: true do +feature 'User uploads avatar to profile' do scenario 'they see their new avatar' do user = create(:user) sign_in(user) diff --git a/spec/features/uploads/user_uploads_file_to_note_spec.rb b/spec/features/uploads/user_uploads_file_to_note_spec.rb index 01f10ca0933..0654923d9a6 100644 --- a/spec/features/uploads/user_uploads_file_to_note_spec.rb +++ b/spec/features/uploads/user_uploads_file_to_note_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'User uploads file to note', feature: true do +feature 'User uploads file to note' do include DropzoneHelper let(:user) { create(:user) } diff --git a/spec/features/users/projects_spec.rb b/spec/features/users/projects_spec.rb index 797ed0e6437..b961d2337ed 100644 --- a/spec/features/users/projects_spec.rb +++ b/spec/features/users/projects_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Projects tab on a user profile', :feature, :js do +describe 'Projects tab on a user profile', :js do let(:user) { create(:user) } let!(:project) { create(:empty_project, namespace: user.namespace) } let!(:project2) { create(:empty_project, namespace: user.namespace) } diff --git a/spec/features/users/snippets_spec.rb b/spec/features/users/snippets_spec.rb index 42738b137af..13760b4c2fc 100644 --- a/spec/features/users/snippets_spec.rb +++ b/spec/features/users/snippets_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Snippets tab on a user profile', feature: true, js: true do +describe 'Snippets tab on a user profile', js: true do context 'when the user has snippets' do let(:user) { create(:user) } diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb index 84af13d3e49..ff004d85272 100644 --- a/spec/features/users_spec.rb +++ b/spec/features/users_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Users', feature: true, js: true do +feature 'Users', js: true do let(:user) { create(:user, username: 'user1', name: 'User 1', email: 'user1@gitlab.com') } scenario 'GET /users/sign_in creates a new user account' do diff --git a/spec/helpers/namespaces_helper_spec.rb b/spec/helpers/namespaces_helper_spec.rb index e5143a0263d..8365b3f5538 100644 --- a/spec/helpers/namespaces_helper_spec.rb +++ b/spec/helpers/namespaces_helper_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe NamespacesHelper, type: :helper do +describe NamespacesHelper do let!(:admin) { create(:admin) } let!(:admin_group) { create(:group, :private) } let!(:user) { create(:user) } diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb index c1bf5551fe0..d4da30b1641 100644 --- a/spec/models/abuse_report_spec.rb +++ b/spec/models/abuse_report_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -RSpec.describe AbuseReport, type: :model do +RSpec.describe AbuseReport do subject { create(:abuse_report) } let(:user) { create(:admin) } diff --git a/spec/models/appearance_spec.rb b/spec/models/appearance_spec.rb index 1060bf3cbf4..7cd3a84d592 100644 --- a/spec/models/appearance_spec.rb +++ b/spec/models/appearance_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -RSpec.describe Appearance, type: :model do +RSpec.describe Appearance do subject { build(:appearance) } it { is_expected.to be_valid } diff --git a/spec/models/blob_viewer/base_spec.rb b/spec/models/blob_viewer/base_spec.rb index 574438838d8..e3640097dff 100644 --- a/spec/models/blob_viewer/base_spec.rb +++ b/spec/models/blob_viewer/base_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BlobViewer::Base, model: true do +describe BlobViewer::Base do include FakeBlobHelpers let(:project) { build(:empty_project) } diff --git a/spec/models/blob_viewer/changelog_spec.rb b/spec/models/blob_viewer/changelog_spec.rb index 9066c5a05ac..db41eca0fc8 100644 --- a/spec/models/blob_viewer/changelog_spec.rb +++ b/spec/models/blob_viewer/changelog_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BlobViewer::Changelog, model: true do +describe BlobViewer::Changelog do include FakeBlobHelpers let(:project) { create(:project, :repository) } diff --git a/spec/models/blob_viewer/composer_json_spec.rb b/spec/models/blob_viewer/composer_json_spec.rb index df4f1f4815c..82f6f7e5046 100644 --- a/spec/models/blob_viewer/composer_json_spec.rb +++ b/spec/models/blob_viewer/composer_json_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BlobViewer::ComposerJson, model: true do +describe BlobViewer::ComposerJson do include FakeBlobHelpers let(:project) { build(:project) } diff --git a/spec/models/blob_viewer/gemspec_spec.rb b/spec/models/blob_viewer/gemspec_spec.rb index 81e932de290..14cc5f3c0fd 100644 --- a/spec/models/blob_viewer/gemspec_spec.rb +++ b/spec/models/blob_viewer/gemspec_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BlobViewer::Gemspec, model: true do +describe BlobViewer::Gemspec do include FakeBlobHelpers let(:project) { build(:project) } diff --git a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb index 0c6c24ece21..7a4f9866375 100644 --- a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb +++ b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BlobViewer::GitlabCiYml, model: true do +describe BlobViewer::GitlabCiYml do include FakeBlobHelpers let(:project) { build(:project) } diff --git a/spec/models/blob_viewer/license_spec.rb b/spec/models/blob_viewer/license_spec.rb index 944ddd32b92..222ed166ee0 100644 --- a/spec/models/blob_viewer/license_spec.rb +++ b/spec/models/blob_viewer/license_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BlobViewer::License, model: true do +describe BlobViewer::License do include FakeBlobHelpers let(:project) { create(:project, :repository) } diff --git a/spec/models/blob_viewer/package_json_spec.rb b/spec/models/blob_viewer/package_json_spec.rb index 5c9a9c81963..96fb1b08c99 100644 --- a/spec/models/blob_viewer/package_json_spec.rb +++ b/spec/models/blob_viewer/package_json_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BlobViewer::PackageJson, model: true do +describe BlobViewer::PackageJson do include FakeBlobHelpers let(:project) { build(:project) } diff --git a/spec/models/blob_viewer/podspec_json_spec.rb b/spec/models/blob_viewer/podspec_json_spec.rb index 42a00940bc5..f510077a87b 100644 --- a/spec/models/blob_viewer/podspec_json_spec.rb +++ b/spec/models/blob_viewer/podspec_json_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BlobViewer::PodspecJson, model: true do +describe BlobViewer::PodspecJson do include FakeBlobHelpers let(:project) { build(:project) } diff --git a/spec/models/blob_viewer/podspec_spec.rb b/spec/models/blob_viewer/podspec_spec.rb index 6c9f0f42d53..7c38083550c 100644 --- a/spec/models/blob_viewer/podspec_spec.rb +++ b/spec/models/blob_viewer/podspec_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BlobViewer::Podspec, model: true do +describe BlobViewer::Podspec do include FakeBlobHelpers let(:project) { build(:project) } diff --git a/spec/models/blob_viewer/readme_spec.rb b/spec/models/blob_viewer/readme_spec.rb index 02679dbb544..926df21ffda 100644 --- a/spec/models/blob_viewer/readme_spec.rb +++ b/spec/models/blob_viewer/readme_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BlobViewer::Readme, model: true do +describe BlobViewer::Readme do include FakeBlobHelpers let(:project) { create(:project, :repository) } diff --git a/spec/models/blob_viewer/route_map_spec.rb b/spec/models/blob_viewer/route_map_spec.rb index 4854e0262d9..115731b4970 100644 --- a/spec/models/blob_viewer/route_map_spec.rb +++ b/spec/models/blob_viewer/route_map_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BlobViewer::RouteMap, model: true do +describe BlobViewer::RouteMap do include FakeBlobHelpers let(:project) { build(:project) } diff --git a/spec/models/blob_viewer/server_side_spec.rb b/spec/models/blob_viewer/server_side_spec.rb index f047953d540..2639eec9e84 100644 --- a/spec/models/blob_viewer/server_side_spec.rb +++ b/spec/models/blob_viewer/server_side_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BlobViewer::ServerSide, model: true do +describe BlobViewer::ServerSide do include FakeBlobHelpers let(:project) { build(:empty_project) } diff --git a/spec/models/chat_team_spec.rb b/spec/models/chat_team_spec.rb index 5283561a83f..e0e5f73e6fe 100644 --- a/spec/models/chat_team_spec.rb +++ b/spec/models/chat_team_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ChatTeam, type: :model do +describe ChatTeam do subject { create(:chat_team) } # Associations diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 0b521d720f3..a18da3768d5 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::Build, :models do +describe Ci::Build do let(:user) { create(:user) } let(:project) { create(:project, :repository) } let(:build) { create(:ci_build, pipeline: pipeline) } @@ -225,7 +225,7 @@ describe Ci::Build, :models do it 'expects to have retried builds instead the original ones' do project.add_developer(user) - retried_rspec = Ci::Build.retry(rspec_test, user) + retried_rspec = described_class.retry(rspec_test, user) expect(staging.depends_on_builds.map(&:id)) .to contain_exactly(build.id, retried_rspec.id, rubocop_test.id) @@ -620,9 +620,9 @@ describe Ci::Build, :models do describe '#first_pending' do let!(:first) { create(:ci_build, pipeline: pipeline, status: 'pending', created_at: Date.yesterday) } let!(:second) { create(:ci_build, pipeline: pipeline, status: 'pending') } - subject { Ci::Build.first_pending } + subject { described_class.first_pending } - it { is_expected.to be_a(Ci::Build) } + it { is_expected.to be_a(described_class) } it('returns with the first pending build') { is_expected.to eq(first) } end @@ -945,7 +945,7 @@ describe Ci::Build, :models do end context 'when build is retried' do - let!(:new_build) { Ci::Build.retry(build, user) } + let!(:new_build) { described_class.retry(build, user) } it 'does not return any of them' do is_expected.not_to include(build, new_build) @@ -953,7 +953,7 @@ describe Ci::Build, :models do end context 'when other build is retried' do - let!(:retried_build) { Ci::Build.retry(other_build, user) } + let!(:retried_build) { described_class.retry(other_build, user) } before do retried_build.success diff --git a/spec/models/ci/legacy_stage_spec.rb b/spec/models/ci/legacy_stage_spec.rb index d43c33d3807..0c33c1466b7 100644 --- a/spec/models/ci/legacy_stage_spec.rb +++ b/spec/models/ci/legacy_stage_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::LegacyStage, :models do +describe Ci::LegacyStage do let(:stage) { build(:ci_stage) } let(:pipeline) { stage.pipeline } let(:stage_name) { stage.name } diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb index 1e074c7ad26..6fb4794ea5f 100644 --- a/spec/models/commit_status_spec.rb +++ b/spec/models/commit_status_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe CommitStatus, :models do +describe CommitStatus do let(:project) { create(:project, :repository) } let(:pipeline) do diff --git a/spec/models/concerns/discussion_on_diff_spec.rb b/spec/models/concerns/discussion_on_diff_spec.rb index f3e148f95f0..2322eb206fb 100644 --- a/spec/models/concerns/discussion_on_diff_spec.rb +++ b/spec/models/concerns/discussion_on_diff_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe DiscussionOnDiff, model: true do +describe DiscussionOnDiff do subject { create(:diff_note_on_merge_request).to_discussion } describe "#truncated_diff_lines" do diff --git a/spec/models/concerns/noteable_spec.rb b/spec/models/concerns/noteable_spec.rb index bdae742ff1d..485a6e165a1 100644 --- a/spec/models/concerns/noteable_spec.rb +++ b/spec/models/concerns/noteable_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Noteable, model: true do +describe Noteable do let!(:active_diff_note1) { create(:diff_note_on_merge_request) } let(:project) { active_diff_note1.project } subject { active_diff_note1.noteable } diff --git a/spec/models/cycle_analytics/code_spec.rb b/spec/models/cycle_analytics/code_spec.rb index 9053485939e..f2f1928926c 100644 --- a/spec/models/cycle_analytics/code_spec.rb +++ b/spec/models/cycle_analytics/code_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'CycleAnalytics#code', feature: true do +describe 'CycleAnalytics#code' do extend CycleAnalyticsHelpers::TestGeneration let(:project) { create(:project, :repository) } diff --git a/spec/models/cycle_analytics/plan_spec.rb b/spec/models/cycle_analytics/plan_spec.rb index 4f33f3c6d69..6fbb2a2d102 100644 --- a/spec/models/cycle_analytics/plan_spec.rb +++ b/spec/models/cycle_analytics/plan_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'CycleAnalytics#plan', feature: true do +describe 'CycleAnalytics#plan' do extend CycleAnalyticsHelpers::TestGeneration let(:project) { create(:project, :repository) } diff --git a/spec/models/cycle_analytics/production_spec.rb b/spec/models/cycle_analytics/production_spec.rb index 4744b9e05ea..f8681c0a2f9 100644 --- a/spec/models/cycle_analytics/production_spec.rb +++ b/spec/models/cycle_analytics/production_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'CycleAnalytics#production', feature: true do +describe 'CycleAnalytics#production' do extend CycleAnalyticsHelpers::TestGeneration let(:project) { create(:project, :repository) } diff --git a/spec/models/cycle_analytics/review_spec.rb b/spec/models/cycle_analytics/review_spec.rb index febb18c9884..0ac58695b35 100644 --- a/spec/models/cycle_analytics/review_spec.rb +++ b/spec/models/cycle_analytics/review_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'CycleAnalytics#review', feature: true do +describe 'CycleAnalytics#review' do extend CycleAnalyticsHelpers::TestGeneration let(:project) { create(:project, :repository) } diff --git a/spec/models/cycle_analytics/staging_spec.rb b/spec/models/cycle_analytics/staging_spec.rb index f78d7a23105..b66d5623910 100644 --- a/spec/models/cycle_analytics/staging_spec.rb +++ b/spec/models/cycle_analytics/staging_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'CycleAnalytics#staging', feature: true do +describe 'CycleAnalytics#staging' do extend CycleAnalyticsHelpers::TestGeneration let(:project) { create(:project, :repository) } diff --git a/spec/models/cycle_analytics/test_spec.rb b/spec/models/cycle_analytics/test_spec.rb index fd58bd1d6ad..690c09bc2dc 100644 --- a/spec/models/cycle_analytics/test_spec.rb +++ b/spec/models/cycle_analytics/test_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'CycleAnalytics#test', feature: true do +describe 'CycleAnalytics#test' do extend CycleAnalyticsHelpers::TestGeneration let(:project) { create(:project, :repository) } diff --git a/spec/models/diff_discussion_spec.rb b/spec/models/diff_discussion_spec.rb index 45b2f6e4beb..2704698f6c9 100644 --- a/spec/models/diff_discussion_spec.rb +++ b/spec/models/diff_discussion_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe DiffDiscussion, model: true do +describe DiffDiscussion do include RepoHelpers subject { described_class.new([diff_note]) } diff --git a/spec/models/diff_viewer/base_spec.rb b/spec/models/diff_viewer/base_spec.rb index 3755f4a56f3..b26de3f3b97 100644 --- a/spec/models/diff_viewer/base_spec.rb +++ b/spec/models/diff_viewer/base_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe DiffViewer::Base, model: true do +describe DiffViewer::Base do include FakeBlobHelpers let(:project) { create(:project, :repository) } diff --git a/spec/models/diff_viewer/server_side_spec.rb b/spec/models/diff_viewer/server_side_spec.rb index 2d926e06936..92e613f92de 100644 --- a/spec/models/diff_viewer/server_side_spec.rb +++ b/spec/models/diff_viewer/server_side_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe DiffViewer::ServerSide, model: true do +describe DiffViewer::ServerSide do let(:project) { create(:project, :repository) } let(:commit) { project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') } let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') } diff --git a/spec/models/discussion_spec.rb b/spec/models/discussion_spec.rb index 0221e23ced8..a46f7ed6507 100644 --- a/spec/models/discussion_spec.rb +++ b/spec/models/discussion_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Discussion, model: true do +describe Discussion do subject { described_class.new([first_note, second_note, third_note]) } let(:first_note) { create(:diff_note_on_merge_request) } diff --git a/spec/models/merge_request_diff_commit_spec.rb b/spec/models/merge_request_diff_commit_spec.rb index dbfd1526518..9d4a0ecf8c0 100644 --- a/spec/models/merge_request_diff_commit_spec.rb +++ b/spec/models/merge_request_diff_commit_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe MergeRequestDiffCommit, type: :model do +describe MergeRequestDiffCommit do let(:merge_request) { create(:merge_request) } subject { merge_request.commits.first } diff --git a/spec/models/merge_request_diff_file_spec.rb b/spec/models/merge_request_diff_file_spec.rb index 239620ef4fc..faa47660a74 100644 --- a/spec/models/merge_request_diff_file_spec.rb +++ b/spec/models/merge_request_diff_file_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe MergeRequestDiffFile, type: :model do +describe MergeRequestDiffFile do describe '#diff' do let(:unpacked) { 'unpacked' } let(:packed) { [unpacked].pack('m0') } diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb index 76a7b07949f..07e296424ca 100644 --- a/spec/models/notification_setting_spec.rb +++ b/spec/models/notification_setting_spec.rb @@ -1,13 +1,13 @@ require 'rails_helper' -RSpec.describe NotificationSetting, type: :model do +RSpec.describe NotificationSetting do describe "Associations" do it { is_expected.to belong_to(:user) } it { is_expected.to belong_to(:source) } end describe "Validation" do - subject { NotificationSetting.new(source_id: 1, source_type: 'Project') } + subject { described_class.new(source_id: 1, source_type: 'Project') } it { is_expected.to validate_presence_of(:user) } it { is_expected.to validate_presence_of(:level) } @@ -22,7 +22,7 @@ RSpec.describe NotificationSetting, type: :model do context "events" do let(:user) { create(:user) } - let(:notification_setting) { NotificationSetting.new(source_id: 1, source_type: 'Project', user_id: user.id) } + let(:notification_setting) { described_class.new(source_id: 1, source_type: 'Project', user_id: user.id) } before do notification_setting.level = "custom" diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb index fa38d23e82f..4c21c8b88bd 100644 --- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb +++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MattermostSlashCommandsService, :models do +describe MattermostSlashCommandsService do it_behaves_like "chat slash commands service" context 'Mattermost API' do diff --git a/spec/models/project_services/slack_slash_commands_service_spec.rb b/spec/models/project_services/slack_slash_commands_service_spec.rb index 5766aa340e2..aea674c4f6b 100644 --- a/spec/models/project_services/slack_slash_commands_service_spec.rb +++ b/spec/models/project_services/slack_slash_commands_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe SlackSlashCommandsService, :models do +describe SlackSlashCommandsService do it_behaves_like "chat slash commands service" describe '#trigger' do diff --git a/spec/models/protected_branch/merge_access_level_spec.rb b/spec/models/protected_branch/merge_access_level_spec.rb index 1e7242e9fa8..f70503eadbc 100644 --- a/spec/models/protected_branch/merge_access_level_spec.rb +++ b/spec/models/protected_branch/merge_access_level_spec.rb @@ -1,5 +1,5 @@ require 'spec_helper' -describe ProtectedBranch::MergeAccessLevel, :models do +describe ProtectedBranch::MergeAccessLevel do it { is_expected.to validate_inclusion_of(:access_level).in_array([Gitlab::Access::MASTER, Gitlab::Access::DEVELOPER, Gitlab::Access::NO_ACCESS]) } end diff --git a/spec/models/protected_branch/push_access_level_spec.rb b/spec/models/protected_branch/push_access_level_spec.rb index de68351198c..f161f345761 100644 --- a/spec/models/protected_branch/push_access_level_spec.rb +++ b/spec/models/protected_branch/push_access_level_spec.rb @@ -1,5 +1,5 @@ require 'spec_helper' -describe ProtectedBranch::PushAccessLevel, :models do +describe ProtectedBranch::PushAccessLevel do it { is_expected.to validate_inclusion_of(:access_level).in_array([Gitlab::Access::MASTER, Gitlab::Access::DEVELOPER, Gitlab::Access::NO_ACCESS]) } end diff --git a/spec/models/release_spec.rb b/spec/models/release_spec.rb index 527005b2b69..3f86347c3ae 100644 --- a/spec/models/release_spec.rb +++ b/spec/models/release_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -RSpec.describe Release, type: :model do +RSpec.describe Release do let(:release) { create(:release) } it { expect(release).to be_valid } diff --git a/spec/models/sent_notification_spec.rb b/spec/models/sent_notification_spec.rb index 5710edbc9e0..823cdb853eb 100644 --- a/spec/models/sent_notification_spec.rb +++ b/spec/models/sent_notification_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe SentNotification, model: true do +describe SentNotification do describe 'validation' do describe 'note validity' do context "when the project doesn't match the noteable's project" do diff --git a/spec/models/timelog_spec.rb b/spec/models/timelog_spec.rb index ebc694213b6..6e30798356c 100644 --- a/spec/models/timelog_spec.rb +++ b/spec/models/timelog_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -RSpec.describe Timelog, type: :model do +RSpec.describe Timelog do subject { build(:timelog) } let(:issue) { create(:issue) } let(:merge_request) { create(:merge_request) } diff --git a/spec/models/upload_spec.rb b/spec/models/upload_spec.rb index 2dea2c6015f..345382ea8c7 100644 --- a/spec/models/upload_spec.rb +++ b/spec/models/upload_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Upload, type: :model do +describe Upload do describe 'assocations' do it { is_expected.to belong_to(:model) } end diff --git a/spec/models/user_agent_detail_spec.rb b/spec/models/user_agent_detail_spec.rb index a8c25766e73..b4669f8c1c2 100644 --- a/spec/models/user_agent_detail_spec.rb +++ b/spec/models/user_agent_detail_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe UserAgentDetail, type: :model do +describe UserAgentDetail do describe '.submittable?' do it 'is submittable when not already submitted' do detail = build(:user_agent_detail) diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb index e3ea3c960a4..a83a83a7349 100644 --- a/spec/policies/ci/build_policy_spec.rb +++ b/spec/policies/ci/build_policy_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::BuildPolicy, :models do +describe Ci::BuildPolicy do let(:user) { create(:user) } let(:build) { create(:ci_build, pipeline: pipeline) } let(:pipeline) { create(:ci_empty_pipeline, project: project) } diff --git a/spec/policies/ci/trigger_policy_spec.rb b/spec/policies/ci/trigger_policy_spec.rb index ed4010e723b..3d3e3d3755b 100644 --- a/spec/policies/ci/trigger_policy_spec.rb +++ b/spec/policies/ci/trigger_policy_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::TriggerPolicy, :models do +describe Ci::TriggerPolicy do let(:user) { create(:user) } let(:project) { create(:empty_project) } let(:trigger) { create(:ci_trigger, project: project, owner: owner) } diff --git a/spec/routing/environments_spec.rb b/spec/routing/environments_spec.rb index 624f3c43f0a..9b70c2a24be 100644 --- a/spec/routing/environments_spec.rb +++ b/spec/routing/environments_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'environments routing', :routing do +describe 'environments routing' do let(:project) { create(:empty_project) } let(:environment) do diff --git a/spec/support/json_response_helpers.rb b/spec/support/json_response_helpers.rb index e8d2ef2d7f0..aa235529c56 100644 --- a/spec/support/json_response_helpers.rb +++ b/spec/support/json_response_helpers.rb @@ -3,7 +3,7 @@ shared_context 'JSON response' do end RSpec.configure do |config| - config.include_context 'JSON response', type: :controller + config.include_context 'JSON response' config.include_context 'JSON response', type: :request config.include_context 'JSON response', :api end diff --git a/spec/views/ci/status/_badge.html.haml_spec.rb b/spec/views/ci/status/_badge.html.haml_spec.rb index 6a4738ba443..de0b59f83f8 100644 --- a/spec/views/ci/status/_badge.html.haml_spec.rb +++ b/spec/views/ci/status/_badge.html.haml_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'ci/status/_badge', :view do +describe 'ci/status/_badge' do let(:user) { create(:user) } let(:project) { create(:empty_project, :private) } let(:pipeline) { create(:ci_pipeline, project: project) } diff --git a/spec/views/projects/_home_panel.html.haml_spec.rb b/spec/views/projects/_home_panel.html.haml_spec.rb index f5381a48207..f8c6cb6b5c6 100644 --- a/spec/views/projects/_home_panel.html.haml_spec.rb +++ b/spec/views/projects/_home_panel.html.haml_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'projects/_home_panel', :view do +describe 'projects/_home_panel' do let(:project) { create(:empty_project, :public) } let(:notification_settings) do diff --git a/spec/views/projects/blob/_viewer.html.haml_spec.rb b/spec/views/projects/blob/_viewer.html.haml_spec.rb index bbd7f98fa8d..af833168bd9 100644 --- a/spec/views/projects/blob/_viewer.html.haml_spec.rb +++ b/spec/views/projects/blob/_viewer.html.haml_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'projects/blob/_viewer.html.haml', :view do +describe 'projects/blob/_viewer.html.haml' do include FakeBlobHelpers let(:project) { build(:empty_project) } diff --git a/spec/views/projects/commit/_commit_box.html.haml_spec.rb b/spec/views/projects/commit/_commit_box.html.haml_spec.rb index ab120929c6c..448b925cf34 100644 --- a/spec/views/projects/commit/_commit_box.html.haml_spec.rb +++ b/spec/views/projects/commit/_commit_box.html.haml_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'projects/commit/_commit_box.html.haml', :view do +describe 'projects/commit/_commit_box.html.haml' do let(:user) { create(:user) } let(:project) { create(:project, :repository) } diff --git a/spec/views/projects/commit/show.html.haml_spec.rb b/spec/views/projects/commit/show.html.haml_spec.rb index 92b4aa12d49..32c95c6bb0d 100644 --- a/spec/views/projects/commit/show.html.haml_spec.rb +++ b/spec/views/projects/commit/show.html.haml_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'projects/commit/show.html.haml', :view do +describe 'projects/commit/show.html.haml' do let(:project) { create(:project, :repository) } before do diff --git a/spec/views/projects/diffs/_viewer.html.haml_spec.rb b/spec/views/projects/diffs/_viewer.html.haml_spec.rb index 32469202508..8ac32db5585 100644 --- a/spec/views/projects/diffs/_viewer.html.haml_spec.rb +++ b/spec/views/projects/diffs/_viewer.html.haml_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'projects/diffs/_viewer.html.haml', :view do +describe 'projects/diffs/_viewer.html.haml' do include FakeBlobHelpers let(:project) { create(:project, :repository) } diff --git a/spec/views/projects/jobs/show.html.haml_spec.rb b/spec/views/projects/jobs/show.html.haml_spec.rb index d9a7ba265f8..117f48450e2 100644 --- a/spec/views/projects/jobs/show.html.haml_spec.rb +++ b/spec/views/projects/jobs/show.html.haml_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'projects/jobs/show', :view do +describe 'projects/jobs/show' do let(:project) { create(:project, :repository) } let(:build) { create(:ci_build, pipeline: pipeline) } diff --git a/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb b/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb index 1e9bdf9108f..5770cf92b4e 100644 --- a/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb +++ b/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'projects/merge_requests/creations/_new_submit.html.haml', :view do +describe 'projects/merge_requests/creations/_new_submit.html.haml' do let(:merge_request) { create(:merge_request) } let!(:pipeline) { create(:ci_empty_pipeline) } diff --git a/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb b/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb index e56c0f6be03..37ce7121ccb 100644 --- a/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb +++ b/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'projects/notes/_more_actions_dropdown', :view do +describe 'projects/notes/_more_actions_dropdown' do let(:author_user) { create(:user) } let(:not_author_user) { create(:user) } diff --git a/spec/views/projects/pipelines/_stage.html.haml_spec.rb b/spec/views/projects/pipelines/_stage.html.haml_spec.rb index 9c91c4e0fbd..e40e16e742b 100644 --- a/spec/views/projects/pipelines/_stage.html.haml_spec.rb +++ b/spec/views/projects/pipelines/_stage.html.haml_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'projects/pipelines/_stage', :view do +describe 'projects/pipelines/_stage' do let(:project) { create(:project, :repository) } let(:pipeline) { create(:ci_pipeline, project: project) } let(:stage) { build(:ci_stage, pipeline: pipeline) } diff --git a/spec/views/projects/registry/repositories/index.html.haml_spec.rb b/spec/views/projects/registry/repositories/index.html.haml_spec.rb index ceeace3dc8d..f13b657d474 100644 --- a/spec/views/projects/registry/repositories/index.html.haml_spec.rb +++ b/spec/views/projects/registry/repositories/index.html.haml_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'projects/registry/repositories/index', :view do +describe 'projects/registry/repositories/index' do let(:group) { create(:group, path: 'group') } let(:project) { create(:empty_project, group: group, path: 'test') } diff --git a/spec/views/projects/tags/index.html.haml_spec.rb b/spec/views/projects/tags/index.html.haml_spec.rb index 33122365e9a..f65cd9f398f 100644 --- a/spec/views/projects/tags/index.html.haml_spec.rb +++ b/spec/views/projects/tags/index.html.haml_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'projects/tags/index', :view do +describe 'projects/tags/index' do let(:project) { create(:project) } before do -- cgit v1.2.1 From ddccd24c1388dadc057ac3c4c0a49f3fea847292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 10 Jul 2017 16:24:02 +0200 Subject: Remove superfluous lib: true, type: redis, service: true, models: true, services: true, no_db: true, api: true MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/db/production/settings_spec.rb | 2 +- spec/features/issuables/markdown_references_spec.rb | 2 +- spec/finders/access_requests_finder_spec.rb | 2 +- spec/initializers/6_validations_spec.rb | 2 +- spec/initializers/8_metrics_spec.rb | 2 +- spec/initializers/secret_token_spec.rb | 2 +- spec/initializers/settings_spec.rb | 2 +- spec/initializers/trusted_proxies_spec.rb | 2 +- spec/lib/banzai/cross_project_reference_spec.rb | 2 +- spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb | 2 +- spec/lib/banzai/filter/autolink_filter_spec.rb | 2 +- spec/lib/banzai/filter/blockquote_fence_filter_spec.rb | 2 +- spec/lib/banzai/filter/commit_range_reference_filter_spec.rb | 2 +- spec/lib/banzai/filter/commit_reference_filter_spec.rb | 2 +- spec/lib/banzai/filter/emoji_filter_spec.rb | 2 +- spec/lib/banzai/filter/external_issue_reference_filter_spec.rb | 2 +- spec/lib/banzai/filter/external_link_filter_spec.rb | 2 +- spec/lib/banzai/filter/gollum_tags_filter_spec.rb | 2 +- spec/lib/banzai/filter/html_entity_filter_spec.rb | 2 +- spec/lib/banzai/filter/image_link_filter_spec.rb | 2 +- spec/lib/banzai/filter/inline_diff_filter_spec.rb | 2 +- spec/lib/banzai/filter/issuable_state_filter_spec.rb | 2 +- spec/lib/banzai/filter/issue_reference_filter_spec.rb | 2 +- spec/lib/banzai/filter/label_reference_filter_spec.rb | 2 +- spec/lib/banzai/filter/markdown_filter_spec.rb | 2 +- spec/lib/banzai/filter/math_filter_spec.rb | 2 +- spec/lib/banzai/filter/merge_request_reference_filter_spec.rb | 2 +- spec/lib/banzai/filter/milestone_reference_filter_spec.rb | 2 +- spec/lib/banzai/filter/plantuml_filter_spec.rb | 2 +- spec/lib/banzai/filter/redactor_filter_spec.rb | 2 +- spec/lib/banzai/filter/reference_filter_spec.rb | 2 +- spec/lib/banzai/filter/relative_link_filter_spec.rb | 2 +- spec/lib/banzai/filter/sanitization_filter_spec.rb | 2 +- spec/lib/banzai/filter/snippet_reference_filter_spec.rb | 2 +- spec/lib/banzai/filter/syntax_highlight_filter_spec.rb | 2 +- spec/lib/banzai/filter/table_of_contents_filter_spec.rb | 2 +- spec/lib/banzai/filter/upload_link_filter_spec.rb | 2 +- spec/lib/banzai/filter/user_reference_filter_spec.rb | 2 +- spec/lib/banzai/filter/video_link_filter_spec.rb | 2 +- spec/lib/banzai/filter/wiki_link_filter_spec.rb | 2 +- spec/lib/banzai/filter/yaml_front_matter_filter_spec.rb | 2 +- spec/lib/banzai/issuable_extractor_spec.rb | 2 +- spec/lib/banzai/reference_parser/base_parser_spec.rb | 2 +- spec/lib/banzai/reference_parser/commit_parser_spec.rb | 2 +- spec/lib/banzai/reference_parser/commit_range_parser_spec.rb | 2 +- spec/lib/banzai/reference_parser/external_issue_parser_spec.rb | 2 +- spec/lib/banzai/reference_parser/issue_parser_spec.rb | 2 +- spec/lib/banzai/reference_parser/label_parser_spec.rb | 2 +- spec/lib/banzai/reference_parser/merge_request_parser_spec.rb | 2 +- spec/lib/banzai/reference_parser/milestone_parser_spec.rb | 2 +- spec/lib/banzai/reference_parser/snippet_parser_spec.rb | 2 +- spec/lib/banzai/reference_parser/user_parser_spec.rb | 2 +- spec/lib/ci/ansi2html_spec.rb | 2 +- spec/lib/ci/charts_spec.rb | 2 +- spec/lib/ci/mask_secret_spec.rb | 2 +- spec/lib/constraints/group_url_constrainer_spec.rb | 2 +- spec/lib/constraints/project_url_constrainer_spec.rb | 2 +- spec/lib/constraints/user_url_constrainer_spec.rb | 2 +- spec/lib/disable_email_interceptor_spec.rb | 2 +- spec/lib/event_filter_spec.rb | 2 +- spec/lib/extracts_path_spec.rb | 2 +- spec/lib/feature_spec.rb | 2 +- spec/lib/file_size_validator_spec.rb | 2 +- spec/lib/gitlab/asciidoc_spec.rb | 2 +- spec/lib/gitlab/auth/unique_ips_limiter_spec.rb | 2 +- spec/lib/gitlab/auth_spec.rb | 2 +- spec/lib/gitlab/backup/manager_spec.rb | 2 +- spec/lib/gitlab/backup/repository_spec.rb | 2 +- spec/lib/gitlab/bitbucket_import/importer_spec.rb | 2 +- spec/lib/gitlab/bitbucket_import/project_creator_spec.rb | 2 +- spec/lib/gitlab/blame_spec.rb | 2 +- spec/lib/gitlab/chat_name_token_spec.rb | 2 +- spec/lib/gitlab/checks/change_access_spec.rb | 2 +- spec/lib/gitlab/checks/force_push_spec.rb | 2 +- spec/lib/gitlab/ci_access_spec.rb | 2 +- spec/lib/gitlab/closing_issue_extractor_spec.rb | 2 +- spec/lib/gitlab/color_schemes_spec.rb | 2 +- spec/lib/gitlab/conflict/file_collection_spec.rb | 2 +- spec/lib/gitlab/conflict/file_spec.rb | 2 +- spec/lib/gitlab/conflict/parser_spec.rb | 2 +- spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb | 2 +- spec/lib/gitlab/data_builder/note_spec.rb | 2 +- spec/lib/gitlab/data_builder/push_spec.rb | 2 +- spec/lib/gitlab/database/migration_helpers_spec.rb | 2 +- spec/lib/gitlab/database_spec.rb | 2 +- spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb | 2 +- spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb | 2 +- spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb | 2 +- spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb | 2 +- spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb | 2 +- spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb | 2 +- spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb | 2 +- spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb | 2 +- spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb | 2 +- spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb | 2 +- spec/lib/gitlab/dependency_linker_spec.rb | 2 +- spec/lib/gitlab/diff/diff_refs_spec.rb | 2 +- spec/lib/gitlab/diff/file_spec.rb | 2 +- spec/lib/gitlab/diff/highlight_spec.rb | 2 +- spec/lib/gitlab/diff/inline_diff_markdown_marker_spec.rb | 2 +- spec/lib/gitlab/diff/inline_diff_marker_spec.rb | 2 +- spec/lib/gitlab/diff/inline_diff_spec.rb | 2 +- spec/lib/gitlab/diff/line_mapper_spec.rb | 2 +- spec/lib/gitlab/diff/parallel_diff_spec.rb | 2 +- spec/lib/gitlab/diff/parser_spec.rb | 2 +- spec/lib/gitlab/diff/position_spec.rb | 2 +- spec/lib/gitlab/diff/position_tracer_spec.rb | 2 +- spec/lib/gitlab/email/attachment_uploader_spec.rb | 2 +- spec/lib/gitlab/email/handler/create_issue_handler_spec.rb | 2 +- spec/lib/gitlab/email/handler/create_note_handler_spec.rb | 2 +- spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb | 2 +- spec/lib/gitlab/email/receiver_spec.rb | 2 +- spec/lib/gitlab/email/reply_parser_spec.rb | 2 +- spec/lib/gitlab/exclusive_lease_spec.rb | 2 +- spec/lib/gitlab/file_finder_spec.rb | 2 +- spec/lib/gitlab/fogbugz_import/client_spec.rb | 2 +- spec/lib/gitlab/git/hook_spec.rb | 2 +- spec/lib/gitlab/git/rev_list_spec.rb | 2 +- spec/lib/gitlab/git_access_spec.rb | 2 +- spec/lib/gitlab/git_access_wiki_spec.rb | 2 +- spec/lib/gitlab/git_ref_validator_spec.rb | 2 +- spec/lib/gitlab/git_spec.rb | 2 +- spec/lib/gitlab/gitaly_client/diff_spec.rb | 2 +- spec/lib/gitlab/gitaly_client/diff_stitcher_spec.rb | 2 +- spec/lib/gitlab/gitaly_client_spec.rb | 2 +- spec/lib/gitlab/github_import/branch_formatter_spec.rb | 2 +- spec/lib/gitlab/github_import/client_spec.rb | 2 +- spec/lib/gitlab/github_import/comment_formatter_spec.rb | 2 +- spec/lib/gitlab/github_import/importer_spec.rb | 2 +- spec/lib/gitlab/github_import/issuable_formatter_spec.rb | 2 +- spec/lib/gitlab/github_import/issue_formatter_spec.rb | 2 +- spec/lib/gitlab/github_import/label_formatter_spec.rb | 2 +- spec/lib/gitlab/github_import/milestone_formatter_spec.rb | 2 +- spec/lib/gitlab/github_import/project_creator_spec.rb | 2 +- spec/lib/gitlab/github_import/pull_request_formatter_spec.rb | 2 +- spec/lib/gitlab/github_import/release_formatter_spec.rb | 2 +- spec/lib/gitlab/github_import/user_formatter_spec.rb | 2 +- spec/lib/gitlab/github_import/wiki_formatter_spec.rb | 2 +- spec/lib/gitlab/gitlab_import/client_spec.rb | 2 +- spec/lib/gitlab/gitlab_import/importer_spec.rb | 2 +- spec/lib/gitlab/gitlab_import/project_creator_spec.rb | 2 +- spec/lib/gitlab/google_code_import/client_spec.rb | 2 +- spec/lib/gitlab/google_code_import/importer_spec.rb | 2 +- spec/lib/gitlab/google_code_import/project_creator_spec.rb | 2 +- spec/lib/gitlab/graphs/commits_spec.rb | 2 +- spec/lib/gitlab/highlight_spec.rb | 2 +- spec/lib/gitlab/i18n_spec.rb | 2 +- spec/lib/gitlab/import_export/attribute_cleaner_spec.rb | 2 +- spec/lib/gitlab/import_export/attribute_configuration_spec.rb | 2 +- spec/lib/gitlab/import_export/avatar_restorer_spec.rb | 2 +- spec/lib/gitlab/import_export/avatar_saver_spec.rb | 2 +- spec/lib/gitlab/import_export/file_importer_spec.rb | 2 +- spec/lib/gitlab/import_export/fork_spec.rb | 2 +- spec/lib/gitlab/import_export/hash_util_spec.rb | 2 +- spec/lib/gitlab/import_export/import_export_spec.rb | 2 +- spec/lib/gitlab/import_export/members_mapper_spec.rb | 2 +- spec/lib/gitlab/import_export/model_configuration_spec.rb | 2 +- spec/lib/gitlab/import_export/project_tree_restorer_spec.rb | 2 +- spec/lib/gitlab/import_export/project_tree_saver_spec.rb | 2 +- spec/lib/gitlab/import_export/reader_spec.rb | 2 +- spec/lib/gitlab/import_export/relation_factory_spec.rb | 2 +- spec/lib/gitlab/import_export/repo_restorer_spec.rb | 2 +- spec/lib/gitlab/import_export/repo_saver_spec.rb | 2 +- spec/lib/gitlab/import_export/version_checker_spec.rb | 2 +- spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb | 2 +- spec/lib/gitlab/incoming_email_spec.rb | 2 +- spec/lib/gitlab/issuable_metadata_spec.rb | 2 +- spec/lib/gitlab/issuable_sorter_spec.rb | 2 +- spec/lib/gitlab/key_fingerprint_spec.rb | 2 +- spec/lib/gitlab/lazy_spec.rb | 2 +- spec/lib/gitlab/ldap/access_spec.rb | 2 +- spec/lib/gitlab/ldap/adapter_spec.rb | 2 +- spec/lib/gitlab/ldap/auth_hash_spec.rb | 2 +- spec/lib/gitlab/ldap/authentication_spec.rb | 2 +- spec/lib/gitlab/ldap/config_spec.rb | 2 +- spec/lib/gitlab/ldap/user_spec.rb | 2 +- spec/lib/gitlab/lfs_token_spec.rb | 2 +- spec/lib/gitlab/markup_helper_spec.rb | 2 +- spec/lib/gitlab/middleware/go_spec.rb | 2 +- spec/lib/gitlab/o_auth/auth_hash_spec.rb | 2 +- spec/lib/gitlab/o_auth/provider_spec.rb | 2 +- spec/lib/gitlab/o_auth/user_spec.rb | 2 +- spec/lib/gitlab/optimistic_locking_spec.rb | 2 +- spec/lib/gitlab/other_markup_spec.rb | 2 +- spec/lib/gitlab/path_regex_spec.rb | 2 +- spec/lib/gitlab/polling_interval_spec.rb | 2 +- spec/lib/gitlab/popen_spec.rb | 2 +- spec/lib/gitlab/project_search_results_spec.rb | 2 +- spec/lib/gitlab/project_transfer_spec.rb | 2 +- spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb | 2 +- .../prometheus/queries/additional_metrics_deployment_query_spec.rb | 2 +- .../prometheus/queries/additional_metrics_environment_query_spec.rb | 2 +- spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb | 2 +- spec/lib/gitlab/prometheus/queries/matched_metrics_query_spec.rb | 2 +- spec/lib/gitlab/prometheus_client_spec.rb | 2 +- spec/lib/gitlab/reference_extractor_spec.rb | 2 +- spec/lib/gitlab/regex_spec.rb | 2 +- spec/lib/gitlab/request_context_spec.rb | 2 +- spec/lib/gitlab/request_profiler_spec.rb | 2 +- spec/lib/gitlab/route_map_spec.rb | 2 +- spec/lib/gitlab/saml/user_spec.rb | 2 +- spec/lib/gitlab/shell_spec.rb | 4 ++-- spec/lib/gitlab/sherlock/collection_spec.rb | 2 +- spec/lib/gitlab/sherlock/file_sample_spec.rb | 2 +- spec/lib/gitlab/sherlock/line_profiler_spec.rb | 2 +- spec/lib/gitlab/sherlock/line_sample_spec.rb | 2 +- spec/lib/gitlab/sherlock/location_spec.rb | 2 +- spec/lib/gitlab/sherlock/middleware_spec.rb | 2 +- spec/lib/gitlab/sherlock/query_spec.rb | 2 +- spec/lib/gitlab/sherlock/transaction_spec.rb | 2 +- spec/lib/gitlab/slash_commands/command_spec.rb | 2 +- spec/lib/gitlab/slash_commands/deploy_spec.rb | 2 +- spec/lib/gitlab/slash_commands/issue_new_spec.rb | 2 +- spec/lib/gitlab/slash_commands/issue_search_spec.rb | 2 +- spec/lib/gitlab/slash_commands/issue_show_spec.rb | 2 +- spec/lib/gitlab/sql/glob_spec.rb | 2 +- spec/lib/gitlab/sql/union_spec.rb | 2 +- spec/lib/gitlab/string_range_marker_spec.rb | 2 +- spec/lib/gitlab/string_regex_marker_spec.rb | 2 +- spec/lib/gitlab/upgrader_spec.rb | 2 +- spec/lib/gitlab/url_blocker_spec.rb | 2 +- spec/lib/gitlab/url_builder_spec.rb | 2 +- spec/lib/gitlab/url_sanitizer_spec.rb | 2 +- spec/lib/gitlab/user_access_spec.rb | 2 +- spec/lib/gitlab/user_activities_spec.rb | 2 +- spec/lib/gitlab/utils_spec.rb | 2 +- spec/lib/gitlab/version_info_spec.rb | 2 +- spec/lib/gitlab/visibility_level_spec.rb | 2 +- spec/lib/gitlab/workhorse_spec.rb | 2 +- spec/lib/gitlab_spec.rb | 2 +- spec/lib/repository_cache_spec.rb | 2 +- spec/lib/system_check/simple_executor_spec.rb | 2 +- spec/lib/system_check_spec.rb | 2 +- spec/models/ability_spec.rb | 2 +- spec/models/application_setting_spec.rb | 2 +- spec/models/award_emoji_spec.rb | 2 +- spec/models/broadcast_message_spec.rb | 2 +- spec/models/chat_name_spec.rb | 2 +- spec/models/ci/artifact_blob_spec.rb | 2 +- spec/models/ci/group_spec.rb | 2 +- spec/models/ci/group_variable_spec.rb | 2 +- spec/models/ci/pipeline_schedule_spec.rb | 2 +- spec/models/ci/pipeline_schedule_variable_spec.rb | 2 +- spec/models/ci/pipeline_spec.rb | 2 +- spec/models/ci/runner_spec.rb | 2 +- spec/models/ci/trigger_spec.rb | 2 +- spec/models/ci/variable_spec.rb | 2 +- spec/models/commit_range_spec.rb | 2 +- spec/models/commit_spec.rb | 2 +- spec/models/compare_spec.rb | 2 +- spec/models/concerns/case_sensitivity_spec.rb | 2 +- spec/models/concerns/participable_spec.rb | 2 +- spec/models/concerns/resolvable_discussion_spec.rb | 2 +- spec/models/concerns/resolvable_note_spec.rb | 2 +- spec/models/concerns/uniquify_spec.rb | 2 +- spec/models/cycle_analytics/issue_spec.rb | 2 +- spec/models/deploy_key_spec.rb | 2 +- spec/models/deploy_keys_project_spec.rb | 2 +- spec/models/deployment_spec.rb | 2 +- spec/models/diff_note_spec.rb | 2 +- spec/models/email_spec.rb | 2 +- spec/models/environment_spec.rb | 2 +- spec/models/event_spec.rb | 2 +- spec/models/external_issue_spec.rb | 2 +- spec/models/generic_commit_status_spec.rb | 2 +- spec/models/global_milestone_spec.rb | 2 +- spec/models/group_label_spec.rb | 2 +- spec/models/group_milestone_spec.rb | 2 +- spec/models/group_spec.rb | 2 +- spec/models/guest_spec.rb | 2 +- spec/models/hooks/project_hook_spec.rb | 2 +- spec/models/hooks/service_hook_spec.rb | 2 +- spec/models/hooks/system_hook_spec.rb | 2 +- spec/models/hooks/web_hook_log_spec.rb | 2 +- spec/models/hooks/web_hook_spec.rb | 2 +- spec/models/identity_spec.rb | 2 +- spec/models/issue/metrics_spec.rb | 2 +- spec/models/issue_spec.rb | 2 +- spec/models/key_spec.rb | 2 +- spec/models/label_link_spec.rb | 2 +- spec/models/label_priority_spec.rb | 2 +- spec/models/label_spec.rb | 2 +- spec/models/legacy_diff_discussion_spec.rb | 2 +- spec/models/lfs_objects_project_spec.rb | 2 +- spec/models/member_spec.rb | 2 +- spec/models/members/group_member_spec.rb | 2 +- spec/models/members/project_member_spec.rb | 2 +- spec/models/merge_request/metrics_spec.rb | 2 +- spec/models/merge_request_diff_spec.rb | 2 +- spec/models/merge_request_spec.rb | 2 +- spec/models/milestone_spec.rb | 2 +- spec/models/namespace_spec.rb | 6 +++--- spec/models/network/graph_spec.rb | 2 +- spec/models/note_spec.rb | 2 +- spec/models/pages_domain_spec.rb | 2 +- spec/models/personal_access_token_spec.rb | 2 +- spec/models/project_label_spec.rb | 2 +- spec/models/project_services/asana_service_spec.rb | 2 +- spec/models/project_services/assembla_service_spec.rb | 2 +- spec/models/project_services/bamboo_service_spec.rb | 2 +- spec/models/project_services/bugzilla_service_spec.rb | 2 +- spec/models/project_services/buildkite_service_spec.rb | 2 +- spec/models/project_services/campfire_service_spec.rb | 2 +- spec/models/project_services/chat_message/issue_message_spec.rb | 2 +- spec/models/project_services/chat_message/merge_message_spec.rb | 2 +- spec/models/project_services/chat_message/note_message_spec.rb | 2 +- spec/models/project_services/chat_message/push_message_spec.rb | 2 +- spec/models/project_services/chat_message/wiki_page_message_spec.rb | 2 +- spec/models/project_services/chat_notification_service_spec.rb | 2 +- spec/models/project_services/custom_issue_tracker_service_spec.rb | 2 +- spec/models/project_services/drone_ci_service_spec.rb | 2 +- spec/models/project_services/external_wiki_service_spec.rb | 2 +- spec/models/project_services/flowdock_service_spec.rb | 2 +- spec/models/project_services/gemnasium_service_spec.rb | 2 +- spec/models/project_services/gitlab_issue_tracker_service_spec.rb | 2 +- spec/models/project_services/hipchat_service_spec.rb | 2 +- spec/models/project_services/irker_service_spec.rb | 2 +- spec/models/project_services/issue_tracker_service_spec.rb | 2 +- spec/models/project_services/jira_service_spec.rb | 2 +- spec/models/project_services/kubernetes_service_spec.rb | 2 +- spec/models/project_services/mattermost_service_spec.rb | 2 +- spec/models/project_services/microsoft_teams_service_spec.rb | 2 +- spec/models/project_services/pivotaltracker_service_spec.rb | 2 +- spec/models/project_services/prometheus_service_spec.rb | 2 +- spec/models/project_services/pushover_service_spec.rb | 2 +- spec/models/project_services/redmine_service_spec.rb | 2 +- spec/models/project_services/slack_service_spec.rb | 2 +- spec/models/project_services/teamcity_service_spec.rb | 2 +- spec/models/project_snippet_spec.rb | 2 +- spec/models/project_spec.rb | 2 +- spec/models/project_statistics_spec.rb | 2 +- spec/models/project_team_spec.rb | 2 +- spec/models/project_wiki_spec.rb | 2 +- spec/models/protectable_dropdown_spec.rb | 2 +- spec/models/protected_branch_spec.rb | 2 +- spec/models/protected_tag_spec.rb | 2 +- spec/models/redirect_route_spec.rb | 2 +- spec/models/repository_spec.rb | 2 +- spec/models/route_spec.rb | 2 +- spec/models/service_spec.rb | 2 +- spec/models/snippet_blob_spec.rb | 2 +- spec/models/snippet_spec.rb | 2 +- spec/models/spam_log_spec.rb | 2 +- spec/models/subscription_spec.rb | 2 +- spec/models/system_note_metadata_spec.rb | 2 +- spec/models/todo_spec.rb | 2 +- spec/models/tree_spec.rb | 2 +- spec/models/user_spec.rb | 2 +- spec/models/wiki_directory_spec.rb | 2 +- spec/models/wiki_page_spec.rb | 2 +- spec/policies/base_policy_spec.rb | 2 +- spec/policies/deploy_key_policy_spec.rb | 2 +- spec/policies/global_policy_spec.rb | 2 +- spec/policies/group_policy_spec.rb | 2 +- spec/policies/issue_policy_spec.rb | 2 +- spec/policies/personal_snippet_policy_spec.rb | 2 +- spec/policies/project_policy_spec.rb | 2 +- spec/policies/project_snippet_policy_spec.rb | 2 +- spec/policies/user_policy_spec.rb | 2 +- spec/requests/api/events_spec.rb | 2 +- spec/requests/api/internal_spec.rb | 2 +- spec/requests/api/jobs_spec.rb | 2 +- spec/requests/git_http_spec.rb | 2 +- spec/requests/projects/cycle_analytics_events_spec.rb | 2 +- spec/routing/project_routing_spec.rb | 2 +- spec/services/access_token_validation_service_spec.rb | 2 +- spec/services/after_branch_delete_service_spec.rb | 2 +- .../services/auth/container_registry_authentication_service_spec.rb | 2 +- spec/services/boards/create_service_spec.rb | 2 +- spec/services/boards/issues/create_service_spec.rb | 2 +- spec/services/boards/issues/list_service_spec.rb | 2 +- spec/services/boards/issues/move_service_spec.rb | 2 +- spec/services/boards/list_service_spec.rb | 2 +- spec/services/boards/lists/create_service_spec.rb | 2 +- spec/services/boards/lists/destroy_service_spec.rb | 2 +- spec/services/boards/lists/generate_service_spec.rb | 2 +- spec/services/boards/lists/list_service_spec.rb | 2 +- spec/services/boards/lists/move_service_spec.rb | 2 +- spec/services/chat_names/authorize_user_service_spec.rb | 2 +- spec/services/chat_names/find_user_service_spec.rb | 2 +- spec/services/ci/create_pipeline_service_spec.rb | 2 +- spec/services/ci/create_trigger_request_service_spec.rb | 2 +- spec/services/ci/play_build_service_spec.rb | 2 +- spec/services/ci/process_pipeline_service_spec.rb | 2 +- spec/services/ci/register_job_service_spec.rb | 2 +- spec/services/ci/retry_build_service_spec.rb | 2 +- spec/services/ci/retry_pipeline_service_spec.rb | 2 +- spec/services/ci/stop_environments_service_spec.rb | 2 +- spec/services/ci/update_build_queue_service_spec.rb | 2 +- spec/services/ci/update_runner_service_spec.rb | 2 +- spec/services/compare_service_spec.rb | 2 +- spec/services/create_branch_service_spec.rb | 2 +- spec/services/create_deployment_service_spec.rb | 2 +- spec/services/create_release_service_spec.rb | 2 +- spec/services/create_snippet_service_spec.rb | 2 +- spec/services/delete_branch_service_spec.rb | 2 +- spec/services/delete_merged_branches_service_spec.rb | 2 +- spec/services/discussions/update_diff_position_service_spec.rb | 2 +- spec/services/emails/create_service_spec.rb | 2 +- spec/services/emails/destroy_service_spec.rb | 2 +- spec/services/event_create_service_spec.rb | 2 +- spec/services/git_hooks_service_spec.rb | 2 +- spec/services/git_push_service_spec.rb | 2 +- spec/services/git_tag_push_service_spec.rb | 2 +- spec/services/gravatar_service_spec.rb | 2 +- spec/services/groups/create_service_spec.rb | 2 +- spec/services/groups/destroy_service_spec.rb | 2 +- spec/services/groups/update_service_spec.rb | 2 +- spec/services/import_export_clean_up_service_spec.rb | 2 +- spec/services/issuable/bulk_update_service_spec.rb | 2 +- spec/services/issues/build_service_spec.rb | 2 +- spec/services/issues/close_service_spec.rb | 2 +- spec/services/issues/create_service_spec.rb | 2 +- spec/services/issues/duplicate_service_spec.rb | 2 +- spec/services/issues/move_service_spec.rb | 2 +- spec/services/issues/reopen_service_spec.rb | 2 +- spec/services/issues/resolve_discussions_spec.rb | 2 +- spec/services/issues/update_service_spec.rb | 2 +- spec/services/labels/create_service_spec.rb | 2 +- spec/services/labels/find_or_create_service_spec.rb | 2 +- spec/services/labels/promote_service_spec.rb | 2 +- spec/services/labels/transfer_service_spec.rb | 2 +- spec/services/labels/update_service_spec.rb | 2 +- spec/services/members/approve_access_request_service_spec.rb | 2 +- spec/services/members/authorized_destroy_service_spec.rb | 2 +- spec/services/members/create_service_spec.rb | 2 +- spec/services/members/destroy_service_spec.rb | 2 +- spec/services/members/request_access_service_spec.rb | 2 +- spec/services/merge_requests/assign_issues_service_spec.rb | 2 +- spec/services/merge_requests/build_service_spec.rb | 2 +- spec/services/merge_requests/close_service_spec.rb | 2 +- spec/services/merge_requests/create_from_issue_service_spec.rb | 2 +- spec/services/merge_requests/create_service_spec.rb | 2 +- spec/services/merge_requests/merge_service_spec.rb | 2 +- spec/services/merge_requests/post_merge_service_spec.rb | 2 +- spec/services/merge_requests/refresh_service_spec.rb | 2 +- spec/services/merge_requests/reopen_service_spec.rb | 2 +- .../merge_requests/resolved_discussion_notification_service_spec.rb | 2 +- spec/services/merge_requests/update_service_spec.rb | 2 +- spec/services/milestones/close_service_spec.rb | 2 +- spec/services/milestones/create_service_spec.rb | 2 +- spec/services/milestones/destroy_service_spec.rb | 2 +- spec/services/note_summary_spec.rb | 2 +- spec/services/notes/build_service_spec.rb | 2 +- spec/services/notes/create_service_spec.rb | 2 +- spec/services/notes/destroy_service_spec.rb | 2 +- spec/services/notes/post_process_service_spec.rb | 2 +- spec/services/notes/quick_actions_service_spec.rb | 2 +- spec/services/notes/update_service_spec.rb | 2 +- spec/services/notification_recipient_service_spec.rb | 2 +- spec/services/notification_service_spec.rb | 2 +- spec/services/pages_service_spec.rb | 2 +- spec/services/projects/autocomplete_service_spec.rb | 2 +- spec/services/projects/create_service_spec.rb | 2 +- spec/services/projects/destroy_service_spec.rb | 2 +- spec/services/projects/download_service_spec.rb | 2 +- spec/services/projects/enable_deploy_key_service_spec.rb | 2 +- spec/services/projects/fork_service_spec.rb | 2 +- spec/services/projects/import_service_spec.rb | 2 +- spec/services/projects/participants_service_spec.rb | 2 +- spec/services/projects/propagate_service_template_spec.rb | 2 +- spec/services/projects/transfer_service_spec.rb | 2 +- spec/services/projects/unlink_fork_service_spec.rb | 2 +- spec/services/projects/update_pages_configuration_service_spec.rb | 2 +- spec/services/projects/update_service_spec.rb | 2 +- spec/services/protected_branches/create_service_spec.rb | 2 +- spec/services/protected_branches/update_service_spec.rb | 2 +- spec/services/protected_tags/create_service_spec.rb | 2 +- spec/services/protected_tags/update_service_spec.rb | 2 +- spec/services/quick_actions/interpret_service_spec.rb | 2 +- spec/services/repair_ldap_blocked_user_service_spec.rb | 2 +- spec/services/repository_archive_clean_up_service_spec.rb | 2 +- spec/services/search/global_service_spec.rb | 2 +- spec/services/search/group_service_spec.rb | 2 +- spec/services/search/snippet_service_spec.rb | 2 +- spec/services/search_service_spec.rb | 2 +- spec/services/spam_service_spec.rb | 2 +- spec/services/system_hooks_service_spec.rb | 2 +- spec/services/system_note_service_spec.rb | 2 +- spec/services/tags/create_service_spec.rb | 2 +- spec/services/tags/destroy_service_spec.rb | 2 +- spec/services/todo_service_spec.rb | 2 +- spec/services/update_release_service_spec.rb | 2 +- spec/services/update_snippet_service_spec.rb | 2 +- spec/services/upload_service_spec.rb | 2 +- spec/services/users/activity_service_spec.rb | 2 +- spec/services/users/build_service_spec.rb | 2 +- spec/services/users/create_service_spec.rb | 2 +- spec/services/users/destroy_service_spec.rb | 2 +- spec/services/users/migrate_to_ghost_user_service_spec.rb | 2 +- spec/services/users/update_service_spec.rb | 2 +- spec/services/web_hook_service_spec.rb | 2 +- spec/services/wiki_pages/create_service_spec.rb | 2 +- spec/services/wiki_pages/destroy_service_spec.rb | 2 +- spec/services/wiki_pages/update_service_spec.rb | 2 +- 495 files changed, 498 insertions(+), 498 deletions(-) diff --git a/spec/db/production/settings_spec.rb b/spec/db/production/settings_spec.rb index a9d015e0666..79e67330854 100644 --- a/spec/db/production/settings_spec.rb +++ b/spec/db/production/settings_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require 'rainbow/ext/string' -describe 'seed production settings', lib: true do +describe 'seed production settings' do include StubENV let(:settings_file) { Rails.root.join('db/fixtures/production/010_settings.rb') } let(:settings) { Gitlab::CurrentSettings.current_application_settings } diff --git a/spec/features/issuables/markdown_references_spec.rb b/spec/features/issuables/markdown_references_spec.rb index f51b2e4001a..169381d703a 100644 --- a/spec/features/issuables/markdown_references_spec.rb +++ b/spec/features/issuables/markdown_references_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe 'Markdown References', :feature, :js do +describe 'Markdown References', :js do let(:user) { create(:user) } let(:actual_project) { create(:project, :public) } let(:merge_request) { create(:merge_request, target_project: actual_project, source_project: actual_project)} diff --git a/spec/finders/access_requests_finder_spec.rb b/spec/finders/access_requests_finder_spec.rb index c7278e971ae..1d0c15392b2 100644 --- a/spec/finders/access_requests_finder_spec.rb +++ b/spec/finders/access_requests_finder_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe AccessRequestsFinder, services: true do +describe AccessRequestsFinder do let(:user) { create(:user) } let(:access_requester) { create(:user) } diff --git a/spec/initializers/6_validations_spec.rb b/spec/initializers/6_validations_spec.rb index 374517fec37..0877770c167 100644 --- a/spec/initializers/6_validations_spec.rb +++ b/spec/initializers/6_validations_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require_relative '../../config/initializers/6_validations.rb' -describe '6_validations', lib: true do +describe '6_validations' do before :all do FileUtils.mkdir_p('tmp/tests/paths/a/b/c/d') FileUtils.mkdir_p('tmp/tests/paths/a/b/c2') diff --git a/spec/initializers/8_metrics_spec.rb b/spec/initializers/8_metrics_spec.rb index d4189f902fd..4e6052a9f80 100644 --- a/spec/initializers/8_metrics_spec.rb +++ b/spec/initializers/8_metrics_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'instrument_classes', lib: true do +describe 'instrument_classes' do let(:config) { double(:config) } let(:unicorn_sampler) { double(:unicorn_sampler) } diff --git a/spec/initializers/secret_token_spec.rb b/spec/initializers/secret_token_spec.rb index 65c97da2efd..84ad55e9f98 100644 --- a/spec/initializers/secret_token_spec.rb +++ b/spec/initializers/secret_token_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require_relative '../../config/initializers/secret_token' -describe 'create_tokens', lib: true do +describe 'create_tokens' do include StubENV let(:secrets) { ActiveSupport::OrderedOptions.new } diff --git a/spec/initializers/settings_spec.rb b/spec/initializers/settings_spec.rb index 47b4e431823..61439ac9506 100644 --- a/spec/initializers/settings_spec.rb +++ b/spec/initializers/settings_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require_relative '../../config/initializers/1_settings' -describe Settings, lib: true do +describe Settings do describe '#host_without_www' do context 'URL with protocol' do it 'returns the host' do diff --git a/spec/initializers/trusted_proxies_spec.rb b/spec/initializers/trusted_proxies_spec.rb index 70a18f31744..02a9446ad7b 100644 --- a/spec/initializers/trusted_proxies_spec.rb +++ b/spec/initializers/trusted_proxies_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'trusted_proxies', lib: true do +describe 'trusted_proxies' do context 'with default config' do before do set_trusted_proxies([]) diff --git a/spec/lib/banzai/cross_project_reference_spec.rb b/spec/lib/banzai/cross_project_reference_spec.rb index 787212581e2..d70749536b8 100644 --- a/spec/lib/banzai/cross_project_reference_spec.rb +++ b/spec/lib/banzai/cross_project_reference_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::CrossProjectReference, lib: true do +describe Banzai::CrossProjectReference do include described_class describe '#project_from_ref' do diff --git a/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb b/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb index 33b812ef425..34f1657b6d3 100644 --- a/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb +++ b/spec/lib/banzai/filter/ascii_doc_post_processing_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::AsciiDocPostProcessingFilter, lib: true do +describe Banzai::Filter::AsciiDocPostProcessingFilter do include FilterSpecHelper it "adds class for elements with data-math-style" do diff --git a/spec/lib/banzai/filter/autolink_filter_spec.rb b/spec/lib/banzai/filter/autolink_filter_spec.rb index a6d2ea11fcc..b7c2ff03125 100644 --- a/spec/lib/banzai/filter/autolink_filter_spec.rb +++ b/spec/lib/banzai/filter/autolink_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::AutolinkFilter, lib: true do +describe Banzai::Filter::AutolinkFilter do include FilterSpecHelper let(:link) { 'http://about.gitlab.com/' } diff --git a/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb b/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb index 2799249ae3e..8224dc5a6b9 100644 --- a/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb +++ b/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Banzai::Filter::BlockquoteFenceFilter, lib: true do +describe Banzai::Filter::BlockquoteFenceFilter do include FilterSpecHelper it 'converts blockquote fences to blockquote lines' do diff --git a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb index 60c27bc0d3c..11d48387544 100644 --- a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do +describe Banzai::Filter::CommitRangeReferenceFilter do include FilterSpecHelper let(:project) { create(:project, :public, :repository) } diff --git a/spec/lib/banzai/filter/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_reference_filter_spec.rb index f6893641481..fb2a36d1ba1 100644 --- a/spec/lib/banzai/filter/commit_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/commit_reference_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::CommitReferenceFilter, lib: true do +describe Banzai::Filter::CommitReferenceFilter do include FilterSpecHelper let(:project) { create(:project, :public, :repository) } diff --git a/spec/lib/banzai/filter/emoji_filter_spec.rb b/spec/lib/banzai/filter/emoji_filter_spec.rb index 086a006c45f..10910f22d4a 100644 --- a/spec/lib/banzai/filter/emoji_filter_spec.rb +++ b/spec/lib/banzai/filter/emoji_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::EmojiFilter, lib: true do +describe Banzai::Filter::EmojiFilter do include FilterSpecHelper before do diff --git a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb index fb320e0148a..a0d391d981c 100644 --- a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::ExternalIssueReferenceFilter, lib: true do +describe Banzai::Filter::ExternalIssueReferenceFilter do include FilterSpecHelper def helper diff --git a/spec/lib/banzai/filter/external_link_filter_spec.rb b/spec/lib/banzai/filter/external_link_filter_spec.rb index 0f8ec8de7a0..2a3c0cd78b8 100644 --- a/spec/lib/banzai/filter/external_link_filter_spec.rb +++ b/spec/lib/banzai/filter/external_link_filter_spec.rb @@ -17,7 +17,7 @@ shared_examples 'an external link with rel attribute' do end end -describe Banzai::Filter::ExternalLinkFilter, lib: true do +describe Banzai::Filter::ExternalLinkFilter do include FilterSpecHelper it 'ignores elements without an href attribute' do diff --git a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb index cbb2808c6bb..663e3514436 100644 --- a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb +++ b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::GollumTagsFilter, lib: true do +describe Banzai::Filter::GollumTagsFilter do include FilterSpecHelper let(:project) { create(:empty_project) } diff --git a/spec/lib/banzai/filter/html_entity_filter_spec.rb b/spec/lib/banzai/filter/html_entity_filter_spec.rb index f9e6bd609f0..91e18d876d5 100644 --- a/spec/lib/banzai/filter/html_entity_filter_spec.rb +++ b/spec/lib/banzai/filter/html_entity_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::HtmlEntityFilter, lib: true do +describe Banzai::Filter::HtmlEntityFilter do include FilterSpecHelper let(:unescaped) { 'foo &&&' } diff --git a/spec/lib/banzai/filter/image_link_filter_spec.rb b/spec/lib/banzai/filter/image_link_filter_spec.rb index 294558b3db2..51920869545 100644 --- a/spec/lib/banzai/filter/image_link_filter_spec.rb +++ b/spec/lib/banzai/filter/image_link_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::ImageLinkFilter, lib: true do +describe Banzai::Filter::ImageLinkFilter do include FilterSpecHelper def image(path) diff --git a/spec/lib/banzai/filter/inline_diff_filter_spec.rb b/spec/lib/banzai/filter/inline_diff_filter_spec.rb index 9e526371294..63c4ab61b86 100644 --- a/spec/lib/banzai/filter/inline_diff_filter_spec.rb +++ b/spec/lib/banzai/filter/inline_diff_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::InlineDiffFilter, lib: true do +describe Banzai::Filter::InlineDiffFilter do include FilterSpecHelper it 'adds inline diff span tags for deletions when using square brackets' do diff --git a/spec/lib/banzai/filter/issuable_state_filter_spec.rb b/spec/lib/banzai/filter/issuable_state_filter_spec.rb index 9c2399815b9..7cf2f4282f8 100644 --- a/spec/lib/banzai/filter/issuable_state_filter_spec.rb +++ b/spec/lib/banzai/filter/issuable_state_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::IssuableStateFilter, lib: true do +describe Banzai::Filter::IssuableStateFilter do include ActionView::Helpers::UrlHelper include FilterSpecHelper diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb index a79d365d6c5..045bf3e0cc9 100644 --- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::IssueReferenceFilter, lib: true do +describe Banzai::Filter::IssueReferenceFilter do include FilterSpecHelper def helper diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb index 8daef3ca691..1daa6ac7f9e 100644 --- a/spec/lib/banzai/filter/label_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require 'html/pipeline' -describe Banzai::Filter::LabelReferenceFilter, lib: true do +describe Banzai::Filter::LabelReferenceFilter do include FilterSpecHelper let(:project) { create(:empty_project, :public, name: 'sample-project') } diff --git a/spec/lib/banzai/filter/markdown_filter_spec.rb b/spec/lib/banzai/filter/markdown_filter_spec.rb index 897288b8ad5..00c407d1b69 100644 --- a/spec/lib/banzai/filter/markdown_filter_spec.rb +++ b/spec/lib/banzai/filter/markdown_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::MarkdownFilter, lib: true do +describe Banzai::Filter::MarkdownFilter do include FilterSpecHelper context 'code block' do diff --git a/spec/lib/banzai/filter/math_filter_spec.rb b/spec/lib/banzai/filter/math_filter_spec.rb index 51883782e19..cade8cb409e 100644 --- a/spec/lib/banzai/filter/math_filter_spec.rb +++ b/spec/lib/banzai/filter/math_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::MathFilter, lib: true do +describe Banzai::Filter::MathFilter do include FilterSpecHelper it 'leaves regular inline code unchanged' do diff --git a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb index 1ad329b6452..683972a3112 100644 --- a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do +describe Banzai::Filter::MergeRequestReferenceFilter do include FilterSpecHelper let(:project) { create(:empty_project, :public) } diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb index 7fab5613afc..8fe05dc2e53 100644 --- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::MilestoneReferenceFilter, lib: true do +describe Banzai::Filter::MilestoneReferenceFilter do include FilterSpecHelper let(:project) { create(:empty_project, :public) } diff --git a/spec/lib/banzai/filter/plantuml_filter_spec.rb b/spec/lib/banzai/filter/plantuml_filter_spec.rb index 9b8ecb201f3..8235c411eb7 100644 --- a/spec/lib/banzai/filter/plantuml_filter_spec.rb +++ b/spec/lib/banzai/filter/plantuml_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::PlantumlFilter, lib: true do +describe Banzai::Filter::PlantumlFilter do include FilterSpecHelper it 'should replace plantuml pre tag with img tag' do diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb index b81cdbb8957..fb6b81d4f10 100644 --- a/spec/lib/banzai/filter/redactor_filter_spec.rb +++ b/spec/lib/banzai/filter/redactor_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::RedactorFilter, lib: true do +describe Banzai::Filter::RedactorFilter do include ActionView::Helpers::UrlHelper include FilterSpecHelper diff --git a/spec/lib/banzai/filter/reference_filter_spec.rb b/spec/lib/banzai/filter/reference_filter_spec.rb index ba0fa4a609a..b9ca68e8935 100644 --- a/spec/lib/banzai/filter/reference_filter_spec.rb +++ b/spec/lib/banzai/filter/reference_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::ReferenceFilter, lib: true do +describe Banzai::Filter::ReferenceFilter do let(:project) { build(:project) } describe '#each_node' do diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb index 1ce7bd7706e..ddebf2264d9 100644 --- a/spec/lib/banzai/filter/relative_link_filter_spec.rb +++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::RelativeLinkFilter, lib: true do +describe Banzai::Filter::RelativeLinkFilter do def filter(doc, contexts = {}) contexts.reverse_merge!({ commit: commit, diff --git a/spec/lib/banzai/filter/sanitization_filter_spec.rb b/spec/lib/banzai/filter/sanitization_filter_spec.rb index a8a0aa6d395..35a32a46eff 100644 --- a/spec/lib/banzai/filter/sanitization_filter_spec.rb +++ b/spec/lib/banzai/filter/sanitization_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::SanitizationFilter, lib: true do +describe Banzai::Filter::SanitizationFilter do include FilterSpecHelper describe 'default whitelist' do diff --git a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb index 9704db0c221..5f548888223 100644 --- a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::SnippetReferenceFilter, lib: true do +describe Banzai::Filter::SnippetReferenceFilter do include FilterSpecHelper let(:project) { create(:empty_project, :public) } diff --git a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb index f61fc8ceb9e..5a23e0e70cc 100644 --- a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb +++ b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::SyntaxHighlightFilter, lib: true do +describe Banzai::Filter::SyntaxHighlightFilter do include FilterSpecHelper context "when no language is specified" do diff --git a/spec/lib/banzai/filter/table_of_contents_filter_spec.rb b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb index 70b31f3a880..ff6b19459bb 100644 --- a/spec/lib/banzai/filter/table_of_contents_filter_spec.rb +++ b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::TableOfContentsFilter, lib: true do +describe Banzai::Filter::TableOfContentsFilter do include FilterSpecHelper def header(level, text) diff --git a/spec/lib/banzai/filter/upload_link_filter_spec.rb b/spec/lib/banzai/filter/upload_link_filter_spec.rb index 6327ca8bbfd..3bc9635b50e 100644 --- a/spec/lib/banzai/filter/upload_link_filter_spec.rb +++ b/spec/lib/banzai/filter/upload_link_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::UploadLinkFilter, lib: true do +describe Banzai::Filter::UploadLinkFilter do def filter(doc, contexts = {}) contexts.reverse_merge!({ project: project diff --git a/spec/lib/banzai/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb index 77561e00573..7ea9df5eda5 100644 --- a/spec/lib/banzai/filter/user_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::UserReferenceFilter, lib: true do +describe Banzai::Filter::UserReferenceFilter do include FilterSpecHelper let(:project) { create(:empty_project, :public) } diff --git a/spec/lib/banzai/filter/video_link_filter_spec.rb b/spec/lib/banzai/filter/video_link_filter_spec.rb index 00494f545a3..81dda0687f3 100644 --- a/spec/lib/banzai/filter/video_link_filter_spec.rb +++ b/spec/lib/banzai/filter/video_link_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::VideoLinkFilter, lib: true do +describe Banzai::Filter::VideoLinkFilter do def filter(doc, contexts = {}) contexts.reverse_merge!({ project: project diff --git a/spec/lib/banzai/filter/wiki_link_filter_spec.rb b/spec/lib/banzai/filter/wiki_link_filter_spec.rb index 92d88c4172c..ceafd12a68e 100644 --- a/spec/lib/banzai/filter/wiki_link_filter_spec.rb +++ b/spec/lib/banzai/filter/wiki_link_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::Filter::WikiLinkFilter, lib: true do +describe Banzai::Filter::WikiLinkFilter do include FilterSpecHelper let(:namespace) { build_stubbed(:namespace, name: "wiki_link_ns") } diff --git a/spec/lib/banzai/filter/yaml_front_matter_filter_spec.rb b/spec/lib/banzai/filter/yaml_front_matter_filter_spec.rb index fe70eada7eb..9f1b862ef19 100644 --- a/spec/lib/banzai/filter/yaml_front_matter_filter_spec.rb +++ b/spec/lib/banzai/filter/yaml_front_matter_filter_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Banzai::Filter::YamlFrontMatterFilter, lib: true do +describe Banzai::Filter::YamlFrontMatterFilter do include FilterSpecHelper it 'allows for `encoding:` before the frontmatter' do diff --git a/spec/lib/banzai/issuable_extractor_spec.rb b/spec/lib/banzai/issuable_extractor_spec.rb index 866297f94a9..728271e757b 100644 --- a/spec/lib/banzai/issuable_extractor_spec.rb +++ b/spec/lib/banzai/issuable_extractor_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::IssuableExtractor, lib: true do +describe Banzai::IssuableExtractor do let(:project) { create(:empty_project) } let(:user) { create(:user) } let(:extractor) { described_class.new(project, user) } diff --git a/spec/lib/banzai/reference_parser/base_parser_spec.rb b/spec/lib/banzai/reference_parser/base_parser_spec.rb index b444ca05b8e..0bf45329657 100644 --- a/spec/lib/banzai/reference_parser/base_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/base_parser_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::ReferenceParser::BaseParser, lib: true do +describe Banzai::ReferenceParser::BaseParser do include ReferenceParserHelpers let(:user) { create(:user) } diff --git a/spec/lib/banzai/reference_parser/commit_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_parser_spec.rb index a314a6119cb..69bf28cdf85 100644 --- a/spec/lib/banzai/reference_parser/commit_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/commit_parser_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::ReferenceParser::CommitParser, lib: true do +describe Banzai::ReferenceParser::CommitParser do include ReferenceParserHelpers let(:project) { create(:empty_project, :public) } diff --git a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb index 5dca5e784da..b384a59bfb4 100644 --- a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::ReferenceParser::CommitRangeParser, lib: true do +describe Banzai::ReferenceParser::CommitRangeParser do include ReferenceParserHelpers let(:project) { create(:empty_project, :public) } diff --git a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb index d212bbac619..a3256afdbb1 100644 --- a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::ReferenceParser::ExternalIssueParser, lib: true do +describe Banzai::ReferenceParser::ExternalIssueParser do include ReferenceParserHelpers let(:project) { create(:empty_project, :public) } diff --git a/spec/lib/banzai/reference_parser/issue_parser_spec.rb b/spec/lib/banzai/reference_parser/issue_parser_spec.rb index acdd23f81f3..94b989fe91d 100644 --- a/spec/lib/banzai/reference_parser/issue_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/issue_parser_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::ReferenceParser::IssueParser, lib: true do +describe Banzai::ReferenceParser::IssueParser do include ReferenceParserHelpers let(:project) { create(:empty_project, :public) } diff --git a/spec/lib/banzai/reference_parser/label_parser_spec.rb b/spec/lib/banzai/reference_parser/label_parser_spec.rb index ddd699f3c25..cf1b2a92195 100644 --- a/spec/lib/banzai/reference_parser/label_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/label_parser_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::ReferenceParser::LabelParser, lib: true do +describe Banzai::ReferenceParser::LabelParser do include ReferenceParserHelpers let(:project) { create(:empty_project, :public) } diff --git a/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb b/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb index cb69ca16800..775749ae3a7 100644 --- a/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/merge_request_parser_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::ReferenceParser::MergeRequestParser, lib: true do +describe Banzai::ReferenceParser::MergeRequestParser do include ReferenceParserHelpers let(:user) { create(:user) } diff --git a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb index 72d4f3bc18e..2cfcafa8798 100644 --- a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::ReferenceParser::MilestoneParser, lib: true do +describe Banzai::ReferenceParser::MilestoneParser do include ReferenceParserHelpers let(:project) { create(:empty_project, :public) } diff --git a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb index 620875ece20..c6d0b7be254 100644 --- a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::ReferenceParser::SnippetParser, lib: true do +describe Banzai::ReferenceParser::SnippetParser do include ReferenceParserHelpers let(:project) { create(:empty_project, :public) } diff --git a/spec/lib/banzai/reference_parser/user_parser_spec.rb b/spec/lib/banzai/reference_parser/user_parser_spec.rb index dfebb971f3a..64f2b607d7c 100644 --- a/spec/lib/banzai/reference_parser/user_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/user_parser_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Banzai::ReferenceParser::UserParser, lib: true do +describe Banzai::ReferenceParser::UserParser do include ReferenceParserHelpers let(:group) { create(:group) } diff --git a/spec/lib/ci/ansi2html_spec.rb b/spec/lib/ci/ansi2html_spec.rb index a5dfb49478a..e49ecadde20 100644 --- a/spec/lib/ci/ansi2html_spec.rb +++ b/spec/lib/ci/ansi2html_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::Ansi2html, lib: true do +describe Ci::Ansi2html do subject { described_class } it "prints non-ansi as-is" do diff --git a/spec/lib/ci/charts_spec.rb b/spec/lib/ci/charts_spec.rb index 51cbfd2a848..8e2d2724426 100644 --- a/spec/lib/ci/charts_spec.rb +++ b/spec/lib/ci/charts_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::Charts, lib: true do +describe Ci::Charts do context "pipeline_times" do let(:project) { create(:empty_project) } let(:chart) { Ci::Charts::PipelineTime.new(project) } diff --git a/spec/lib/ci/mask_secret_spec.rb b/spec/lib/ci/mask_secret_spec.rb index 3101bed20fb..f7b753b022b 100644 --- a/spec/lib/ci/mask_secret_spec.rb +++ b/spec/lib/ci/mask_secret_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::MaskSecret, lib: true do +describe Ci::MaskSecret do subject { described_class } describe '#mask' do diff --git a/spec/lib/constraints/group_url_constrainer_spec.rb b/spec/lib/constraints/group_url_constrainer_spec.rb index db680489a8d..4dab58b26a0 100644 --- a/spec/lib/constraints/group_url_constrainer_spec.rb +++ b/spec/lib/constraints/group_url_constrainer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GroupUrlConstrainer, lib: true do +describe GroupUrlConstrainer do let!(:group) { create(:group, path: 'gitlab') } describe '#matches?' do diff --git a/spec/lib/constraints/project_url_constrainer_spec.rb b/spec/lib/constraints/project_url_constrainer_spec.rb index b6884e37aa3..e4b5dfc574a 100644 --- a/spec/lib/constraints/project_url_constrainer_spec.rb +++ b/spec/lib/constraints/project_url_constrainer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ProjectUrlConstrainer, lib: true do +describe ProjectUrlConstrainer do let!(:project) { create(:empty_project) } let!(:namespace) { project.namespace } diff --git a/spec/lib/constraints/user_url_constrainer_spec.rb b/spec/lib/constraints/user_url_constrainer_spec.rb index ed69b830979..cb3b4ff1391 100644 --- a/spec/lib/constraints/user_url_constrainer_spec.rb +++ b/spec/lib/constraints/user_url_constrainer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe UserUrlConstrainer, lib: true do +describe UserUrlConstrainer do let!(:user) { create(:user, username: 'dz') } describe '#matches?' do diff --git a/spec/lib/disable_email_interceptor_spec.rb b/spec/lib/disable_email_interceptor_spec.rb index 8f51474476d..9fc1dd523f1 100644 --- a/spec/lib/disable_email_interceptor_spec.rb +++ b/spec/lib/disable_email_interceptor_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe DisableEmailInterceptor, lib: true do +describe DisableEmailInterceptor do before do Mail.register_interceptor(DisableEmailInterceptor) end diff --git a/spec/lib/event_filter_spec.rb b/spec/lib/event_filter_spec.rb index d70690f589d..09425c6bf68 100644 --- a/spec/lib/event_filter_spec.rb +++ b/spec/lib/event_filter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe EventFilter, lib: true do +describe EventFilter do describe '#apply_filter' do let(:source_user) { create(:user) } let!(:public_project) { create(:empty_project, :public) } diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb index dfffef8b9b7..1772ca216e4 100644 --- a/spec/lib/extracts_path_spec.rb +++ b/spec/lib/extracts_path_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ExtractsPath, lib: true do +describe ExtractsPath do include ExtractsPath include RepoHelpers include Gitlab::Routing diff --git a/spec/lib/feature_spec.rb b/spec/lib/feature_spec.rb index 5cc3a3745e4..1076c63b5f2 100644 --- a/spec/lib/feature_spec.rb +++ b/spec/lib/feature_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Feature, lib: true do +describe Feature do describe '.get' do let(:feature) { double(:feature) } let(:key) { 'my_feature' } diff --git a/spec/lib/file_size_validator_spec.rb b/spec/lib/file_size_validator_spec.rb index fda6f9a6c88..681cc9ef21c 100644 --- a/spec/lib/file_size_validator_spec.rb +++ b/spec/lib/file_size_validator_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe FileSizeValidator, lib: true do +describe FileSizeValidator do let(:validator) { FileSizeValidator.new(options) } let(:attachment) { AttachmentUploader.new } let(:note) { create(:note) } diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb index 43d52b941ab..f668f78c2b8 100644 --- a/spec/lib/gitlab/asciidoc_spec.rb +++ b/spec/lib/gitlab/asciidoc_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' require 'nokogiri' module Gitlab - describe Asciidoc, lib: true do + describe Asciidoc do let(:input) { 'ascii' } let(:context) { {} } let(:html) { 'H2O' } diff --git a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb index 15b3db0ed3d..f29431b937c 100644 --- a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb +++ b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Auth::UniqueIpsLimiter, :clean_gitlab_redis_shared_state, lib: true do +describe Gitlab::Auth::UniqueIpsLimiter, :clean_gitlab_redis_shared_state do include_context 'unique ips sign in limit' let(:user) { create(:user) } diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb index 55780518230..a9db0d5164d 100644 --- a/spec/lib/gitlab/auth_spec.rb +++ b/spec/lib/gitlab/auth_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Auth, lib: true do +describe Gitlab::Auth do let(:gl_auth) { described_class } describe 'constants' do diff --git a/spec/lib/gitlab/backup/manager_spec.rb b/spec/lib/gitlab/backup/manager_spec.rb index 1c3d2547fec..349502a0e61 100644 --- a/spec/lib/gitlab/backup/manager_spec.rb +++ b/spec/lib/gitlab/backup/manager_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Backup::Manager, lib: true do +describe Backup::Manager do include StubENV let(:progress) { StringIO.new } diff --git a/spec/lib/gitlab/backup/repository_spec.rb b/spec/lib/gitlab/backup/repository_spec.rb index 51c1e9d657b..db860b01ba4 100644 --- a/spec/lib/gitlab/backup/repository_spec.rb +++ b/spec/lib/gitlab/backup/repository_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Backup::Repository, lib: true do +describe Backup::Repository do let(:progress) { StringIO.new } let!(:project) { create(:empty_project) } diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb index d8beb05601c..35c8a24aef4 100644 --- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb +++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::BitbucketImport::Importer, lib: true do +describe Gitlab::BitbucketImport::Importer do include ImportSpecHelper before do diff --git a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb index 773d0d4d288..4bc0eaddd9e 100644 --- a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb +++ b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::BitbucketImport::ProjectCreator, lib: true do +describe Gitlab::BitbucketImport::ProjectCreator do let(:user) { create(:user) } let(:repo) do diff --git a/spec/lib/gitlab/blame_spec.rb b/spec/lib/gitlab/blame_spec.rb index 26b1baf75be..7cab04e9fc9 100644 --- a/spec/lib/gitlab/blame_spec.rb +++ b/spec/lib/gitlab/blame_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Blame, lib: true do +describe Gitlab::Blame do let(:project) { create(:project, :repository) } let(:path) { 'files/ruby/popen.rb' } let(:commit) { project.commit('master') } diff --git a/spec/lib/gitlab/chat_name_token_spec.rb b/spec/lib/gitlab/chat_name_token_spec.rb index 8c1e6efa9db..1e9fb9077fc 100644 --- a/spec/lib/gitlab/chat_name_token_spec.rb +++ b/spec/lib/gitlab/chat_name_token_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ChatNameToken, lib: true do +describe Gitlab::ChatNameToken do context 'when using unknown token' do let(:token) { } diff --git a/spec/lib/gitlab/checks/change_access_spec.rb b/spec/lib/gitlab/checks/change_access_spec.rb index 643e590438a..6c25b7349e1 100644 --- a/spec/lib/gitlab/checks/change_access_spec.rb +++ b/spec/lib/gitlab/checks/change_access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Checks::ChangeAccess, lib: true do +describe Gitlab::Checks::ChangeAccess do describe '#exec' do let(:user) { create(:user) } let(:project) { create(:project, :repository) } diff --git a/spec/lib/gitlab/checks/force_push_spec.rb b/spec/lib/gitlab/checks/force_push_spec.rb index bc66ce83d4a..6c4cfa1203e 100644 --- a/spec/lib/gitlab/checks/force_push_spec.rb +++ b/spec/lib/gitlab/checks/force_push_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Checks::ForcePush, lib: true do +describe Gitlab::Checks::ForcePush do let(:project) { create(:project, :repository) } context "exit code checking" do diff --git a/spec/lib/gitlab/ci_access_spec.rb b/spec/lib/gitlab/ci_access_spec.rb index eaf8f1d0f1c..fcb9f10d6c0 100644 --- a/spec/lib/gitlab/ci_access_spec.rb +++ b/spec/lib/gitlab/ci_access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::CiAccess, lib: true do +describe Gitlab::CiAccess do let(:access) { Gitlab::CiAccess.new } describe '#can_do_action?' do diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb index fe988266ae3..8ff6125ada1 100644 --- a/spec/lib/gitlab/closing_issue_extractor_spec.rb +++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ClosingIssueExtractor, lib: true do +describe Gitlab::ClosingIssueExtractor do let(:project) { create(:empty_project) } let(:project2) { create(:empty_project) } let(:forked_project) { Projects::ForkService.new(project, project.creator).execute } diff --git a/spec/lib/gitlab/color_schemes_spec.rb b/spec/lib/gitlab/color_schemes_spec.rb index 0a1ec66f199..c7be45dbcd3 100644 --- a/spec/lib/gitlab/color_schemes_spec.rb +++ b/spec/lib/gitlab/color_schemes_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ColorSchemes, lib: true do +describe Gitlab::ColorSchemes do describe '.body_classes' do it 'returns a space-separated list of class names' do css = described_class.body_classes diff --git a/spec/lib/gitlab/conflict/file_collection_spec.rb b/spec/lib/gitlab/conflict/file_collection_spec.rb index 27f23ea70dc..a4d7628b03a 100644 --- a/spec/lib/gitlab/conflict/file_collection_spec.rb +++ b/spec/lib/gitlab/conflict/file_collection_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Conflict::FileCollection, lib: true do +describe Gitlab::Conflict::FileCollection do let(:merge_request) { create(:merge_request, source_branch: 'conflict-resolvable', target_branch: 'conflict-start') } let(:file_collection) { described_class.read_only(merge_request) } diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb index 585eeb77bd5..c0a10124730 100644 --- a/spec/lib/gitlab/conflict/file_spec.rb +++ b/spec/lib/gitlab/conflict/file_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Conflict::File, lib: true do +describe Gitlab::Conflict::File do let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:rugged) { repository.rugged } diff --git a/spec/lib/gitlab/conflict/parser_spec.rb b/spec/lib/gitlab/conflict/parser_spec.rb index aed57b75789..ad99a5fb6bf 100644 --- a/spec/lib/gitlab/conflict/parser_spec.rb +++ b/spec/lib/gitlab/conflict/parser_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Conflict::Parser, lib: true do +describe Gitlab::Conflict::Parser do let(:parser) { Gitlab::Conflict::Parser.new } describe '#parse' do diff --git a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb index 3dd76ba5b8a..592448aef96 100644 --- a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::CycleAnalytics::StageSummary, models: true do +describe Gitlab::CycleAnalytics::StageSummary do let(:project) { create(:project, :repository) } let(:from) { 1.day.ago } let(:user) { create(:user, :admin) } diff --git a/spec/lib/gitlab/data_builder/note_spec.rb b/spec/lib/gitlab/data_builder/note_spec.rb index 04ec34492e1..6415e4083d6 100644 --- a/spec/lib/gitlab/data_builder/note_spec.rb +++ b/spec/lib/gitlab/data_builder/note_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::DataBuilder::Note, lib: true do +describe Gitlab::DataBuilder::Note do let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:data) { described_class.build(note, user) } diff --git a/spec/lib/gitlab/data_builder/push_spec.rb b/spec/lib/gitlab/data_builder/push_spec.rb index 73936969832..cb430b47463 100644 --- a/spec/lib/gitlab/data_builder/push_spec.rb +++ b/spec/lib/gitlab/data_builder/push_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::DataBuilder::Push, lib: true do +describe Gitlab::DataBuilder::Push do let(:project) { create(:project, :repository) } let(:user) { create(:user) } diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index a2acd15c8fb..0e0354bc532 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Database::MigrationHelpers, lib: true do +describe Gitlab::Database::MigrationHelpers do let(:model) do ActiveRecord::Migration.new.extend( Gitlab::Database::MigrationHelpers diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb index cbf6c35356e..c5f9aecd867 100644 --- a/spec/lib/gitlab/database_spec.rb +++ b/spec/lib/gitlab/database_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Database, lib: true do +describe Gitlab::Database do before do stub_const('MigrationTest', Class.new { include Gitlab::Database }) end diff --git a/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb index df77f4037af..3a93d5e1e97 100644 --- a/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/cartfile_linker_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Gitlab::DependencyLinker::CartfileLinker, lib: true do +describe Gitlab::DependencyLinker::CartfileLinker do describe '.support?' do it 'supports Cartfile' do expect(described_class.support?('Cartfile')).to be_truthy diff --git a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb index d7a926e800f..4d222564fd0 100644 --- a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Gitlab::DependencyLinker::ComposerJsonLinker, lib: true do +describe Gitlab::DependencyLinker::ComposerJsonLinker do describe '.support?' do it 'supports composer.json' do expect(described_class.support?('composer.json')).to be_truthy diff --git a/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb index 3f8335f03ea..a97803b119e 100644 --- a/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/gemfile_linker_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Gitlab::DependencyLinker::GemfileLinker, lib: true do +describe Gitlab::DependencyLinker::GemfileLinker do describe '.support?' do it 'supports Gemfile' do expect(described_class.support?('Gemfile')).to be_truthy diff --git a/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb index d4a71403939..24ad7d12f4c 100644 --- a/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/gemspec_linker_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Gitlab::DependencyLinker::GemspecLinker, lib: true do +describe Gitlab::DependencyLinker::GemspecLinker do describe '.support?' do it 'supports *.gemspec' do expect(described_class.support?('gitlab_git.gemspec')).to be_truthy diff --git a/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb index e279e0c9019..ae5ad39ad11 100644 --- a/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/godeps_json_linker_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Gitlab::DependencyLinker::GodepsJsonLinker, lib: true do +describe Gitlab::DependencyLinker::GodepsJsonLinker do describe '.support?' do it 'supports Godeps.json' do expect(described_class.support?('Godeps.json')).to be_truthy diff --git a/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb index 8c979ae1869..1e8b72afb7b 100644 --- a/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/package_json_linker_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Gitlab::DependencyLinker::PackageJsonLinker, lib: true do +describe Gitlab::DependencyLinker::PackageJsonLinker do describe '.support?' do it 'supports package.json' do expect(described_class.support?('package.json')).to be_truthy diff --git a/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb index 06007cf97f7..cdfd7ad9826 100644 --- a/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/podfile_linker_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Gitlab::DependencyLinker::PodfileLinker, lib: true do +describe Gitlab::DependencyLinker::PodfileLinker do describe '.support?' do it 'supports Podfile' do expect(described_class.support?('Podfile')).to be_truthy diff --git a/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb index d722865264b..d4a398c5948 100644 --- a/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/podspec_json_linker_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Gitlab::DependencyLinker::PodspecJsonLinker, lib: true do +describe Gitlab::DependencyLinker::PodspecJsonLinker do describe '.support?' do it 'supports *.podspec.json' do expect(described_class.support?('Reachability.podspec.json')).to be_truthy diff --git a/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb index dfc366b5817..ed60ab45955 100644 --- a/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/podspec_linker_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Gitlab::DependencyLinker::PodspecLinker, lib: true do +describe Gitlab::DependencyLinker::PodspecLinker do describe '.support?' do it 'supports *.podspec' do expect(described_class.support?('Reachability.podspec')).to be_truthy diff --git a/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb index 64b233f3e68..ef952b3abd5 100644 --- a/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker/requirements_txt_linker_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Gitlab::DependencyLinker::RequirementsTxtLinker, lib: true do +describe Gitlab::DependencyLinker::RequirementsTxtLinker do describe '.support?' do it 'supports requirements.txt' do expect(described_class.support?('requirements.txt')).to be_truthy diff --git a/spec/lib/gitlab/dependency_linker_spec.rb b/spec/lib/gitlab/dependency_linker_spec.rb index 3d1cfbcfbf7..10d2f701298 100644 --- a/spec/lib/gitlab/dependency_linker_spec.rb +++ b/spec/lib/gitlab/dependency_linker_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Gitlab::DependencyLinker, lib: true do +describe Gitlab::DependencyLinker do describe '.link' do it 'links using GemfileLinker' do blob_name = 'Gemfile' diff --git a/spec/lib/gitlab/diff/diff_refs_spec.rb b/spec/lib/gitlab/diff/diff_refs_spec.rb index a8173558c00..c73708d90a8 100644 --- a/spec/lib/gitlab/diff/diff_refs_spec.rb +++ b/spec/lib/gitlab/diff/diff_refs_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Diff::DiffRefs, lib: true do +describe Gitlab::Diff::DiffRefs do let(:project) { create(:project, :repository) } describe '#compare_in' do diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb index f289131cc3a..cd2fa98b14c 100644 --- a/spec/lib/gitlab/diff/file_spec.rb +++ b/spec/lib/gitlab/diff/file_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Diff::File, lib: true do +describe Gitlab::Diff::File do include RepoHelpers let(:project) { create(:project, :repository) } diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb index 7d7d4a55e63..ffa83d6a8f2 100644 --- a/spec/lib/gitlab/diff/highlight_spec.rb +++ b/spec/lib/gitlab/diff/highlight_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Diff::Highlight, lib: true do +describe Gitlab::Diff::Highlight do include RepoHelpers let(:project) { create(:project, :repository) } diff --git a/spec/lib/gitlab/diff/inline_diff_markdown_marker_spec.rb b/spec/lib/gitlab/diff/inline_diff_markdown_marker_spec.rb index d6e8b8ac4b2..046b096e366 100644 --- a/spec/lib/gitlab/diff/inline_diff_markdown_marker_spec.rb +++ b/spec/lib/gitlab/diff/inline_diff_markdown_marker_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Diff::InlineDiffMarkdownMarker, lib: true do +describe Gitlab::Diff::InlineDiffMarkdownMarker do describe '#mark' do let(:raw) { "abc 'def'" } let(:inline_diffs) { [2..5] } diff --git a/spec/lib/gitlab/diff/inline_diff_marker_spec.rb b/spec/lib/gitlab/diff/inline_diff_marker_spec.rb index 95da344802d..c3bf34c24ae 100644 --- a/spec/lib/gitlab/diff/inline_diff_marker_spec.rb +++ b/spec/lib/gitlab/diff/inline_diff_marker_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Diff::InlineDiffMarker, lib: true do +describe Gitlab::Diff::InlineDiffMarker do describe '#mark' do context "when the rich text is html safe" do let(:raw) { "abc 'def'" } diff --git a/spec/lib/gitlab/diff/inline_diff_spec.rb b/spec/lib/gitlab/diff/inline_diff_spec.rb index 8ca3f73509e..15451c2cf99 100644 --- a/spec/lib/gitlab/diff/inline_diff_spec.rb +++ b/spec/lib/gitlab/diff/inline_diff_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Diff::InlineDiff, lib: true do +describe Gitlab::Diff::InlineDiff do describe '.for_lines' do let(:diff) do <<-EOF.strip_heredoc diff --git a/spec/lib/gitlab/diff/line_mapper_spec.rb b/spec/lib/gitlab/diff/line_mapper_spec.rb index 2c7ecd1907e..42750bf9ea1 100644 --- a/spec/lib/gitlab/diff/line_mapper_spec.rb +++ b/spec/lib/gitlab/diff/line_mapper_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Diff::LineMapper, lib: true do +describe Gitlab::Diff::LineMapper do include RepoHelpers let(:project) { create(:project, :repository) } diff --git a/spec/lib/gitlab/diff/parallel_diff_spec.rb b/spec/lib/gitlab/diff/parallel_diff_spec.rb index 0f779339c54..e9fc7be366a 100644 --- a/spec/lib/gitlab/diff/parallel_diff_spec.rb +++ b/spec/lib/gitlab/diff/parallel_diff_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Diff::ParallelDiff, lib: true do +describe Gitlab::Diff::ParallelDiff do include RepoHelpers let(:project) { create(:project, :repository) } diff --git a/spec/lib/gitlab/diff/parser_spec.rb b/spec/lib/gitlab/diff/parser_spec.rb index e76128ecd87..e16c31d7eb8 100644 --- a/spec/lib/gitlab/diff/parser_spec.rb +++ b/spec/lib/gitlab/diff/parser_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Diff::Parser, lib: true do +describe Gitlab::Diff::Parser do include RepoHelpers let(:project) { create(:project) } diff --git a/spec/lib/gitlab/diff/position_spec.rb b/spec/lib/gitlab/diff/position_spec.rb index b3d46e69ccb..d4a2a852c12 100644 --- a/spec/lib/gitlab/diff/position_spec.rb +++ b/spec/lib/gitlab/diff/position_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Diff::Position, lib: true do +describe Gitlab::Diff::Position do include RepoHelpers let(:project) { create(:project, :repository) } diff --git a/spec/lib/gitlab/diff/position_tracer_spec.rb b/spec/lib/gitlab/diff/position_tracer_spec.rb index 93d30b90937..8beebc10040 100644 --- a/spec/lib/gitlab/diff/position_tracer_spec.rb +++ b/spec/lib/gitlab/diff/position_tracer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Diff::PositionTracer, lib: true do +describe Gitlab::Diff::PositionTracer do # Douwe's diary New York City, 2016-06-28 # -------------------------------------------------------------------------- # diff --git a/spec/lib/gitlab/email/attachment_uploader_spec.rb b/spec/lib/gitlab/email/attachment_uploader_spec.rb index 08b2577ecc4..f61dbc67ad1 100644 --- a/spec/lib/gitlab/email/attachment_uploader_spec.rb +++ b/spec/lib/gitlab/email/attachment_uploader_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe Gitlab::Email::AttachmentUploader, lib: true do +describe Gitlab::Email::AttachmentUploader do describe "#execute" do let(:project) { build(:project) } let(:message_raw) { fixture_file("emails/attachment.eml") } diff --git a/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb b/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb index 4a9c9a7fe34..bd36d1d309d 100644 --- a/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb +++ b/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require_relative '../email_shared_blocks' -describe Gitlab::Email::Handler::CreateIssueHandler, lib: true do +describe Gitlab::Email::Handler::CreateIssueHandler do include_context :email_shared_context it_behaves_like :reply_processing_shared_examples diff --git a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb index cd0309e248d..0127b012c91 100644 --- a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb +++ b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require_relative '../email_shared_blocks' -describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do +describe Gitlab::Email::Handler::CreateNoteHandler do include_context :email_shared_context it_behaves_like :reply_processing_shared_examples diff --git a/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb b/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb index 0939e6c4514..66c38498e4e 100644 --- a/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb +++ b/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require_relative '../email_shared_blocks' -describe Gitlab::Email::Handler::UnsubscribeHandler, lib: true do +describe Gitlab::Email::Handler::UnsubscribeHandler do include_context :email_shared_context before do diff --git a/spec/lib/gitlab/email/receiver_spec.rb b/spec/lib/gitlab/email/receiver_spec.rb index c6e3524f743..88565ea5311 100644 --- a/spec/lib/gitlab/email/receiver_spec.rb +++ b/spec/lib/gitlab/email/receiver_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require_relative 'email_shared_blocks' -describe Gitlab::Email::Receiver, lib: true do +describe Gitlab::Email::Receiver do include_context :email_shared_context context "when the email contains a valid email address in a Delivered-To header" do diff --git a/spec/lib/gitlab/email/reply_parser_spec.rb b/spec/lib/gitlab/email/reply_parser_spec.rb index 2ea5e6460a3..e21a998adfe 100644 --- a/spec/lib/gitlab/email/reply_parser_spec.rb +++ b/spec/lib/gitlab/email/reply_parser_spec.rb @@ -1,7 +1,7 @@ require "spec_helper" # Inspired in great part by Discourse's Email::Receiver -describe Gitlab::Email::ReplyParser, lib: true do +describe Gitlab::Email::ReplyParser do describe '#execute' do def test_parse_body(mail_string) described_class.new(Mail::Message.new(mail_string)).execute diff --git a/spec/lib/gitlab/exclusive_lease_spec.rb b/spec/lib/gitlab/exclusive_lease_spec.rb index 590d6da4113..c1ed47cf64a 100644 --- a/spec/lib/gitlab/exclusive_lease_spec.rb +++ b/spec/lib/gitlab/exclusive_lease_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ExclusiveLease, type: :clean_gitlab_redis_shared_state do +describe Gitlab::ExclusiveLease, :clean_gitlab_redis_shared_state do let(:unique_key) { SecureRandom.hex(10) } describe '#try_obtain' do diff --git a/spec/lib/gitlab/file_finder_spec.rb b/spec/lib/gitlab/file_finder_spec.rb index 5a32ffd462c..3fb6315a39a 100644 --- a/spec/lib/gitlab/file_finder_spec.rb +++ b/spec/lib/gitlab/file_finder_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::FileFinder, lib: true do +describe Gitlab::FileFinder do describe '#find' do let(:project) { create(:project, :public, :repository) } let(:finder) { described_class.new(project, project.default_branch) } diff --git a/spec/lib/gitlab/fogbugz_import/client_spec.rb b/spec/lib/gitlab/fogbugz_import/client_spec.rb index 252cd4c55c7..dcd1a2d9813 100644 --- a/spec/lib/gitlab/fogbugz_import/client_spec.rb +++ b/spec/lib/gitlab/fogbugz_import/client_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::FogbugzImport::Client, lib: true do +describe Gitlab::FogbugzImport::Client do let(:client) { described_class.new(uri: '', token: '') } let(:one_user) { { 'people' => { 'person' => { "ixPerson" => "2", "sFullName" => "James" } } } } let(:two_users) { { 'people' => { 'person' => [one_user, { "ixPerson" => "3" }] } } } diff --git a/spec/lib/gitlab/git/hook_spec.rb b/spec/lib/gitlab/git/hook_spec.rb index 19f45ea1cb2..ff823e53cac 100644 --- a/spec/lib/gitlab/git/hook_spec.rb +++ b/spec/lib/gitlab/git/hook_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require 'fileutils' -describe Gitlab::Git::Hook, lib: true do +describe Gitlab::Git::Hook do before do # We need this because in the spec/spec_helper.rb we define it like this: # allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil]) diff --git a/spec/lib/gitlab/git/rev_list_spec.rb b/spec/lib/gitlab/git/rev_list_spec.rb index 78894ba9409..26fc33b8327 100644 --- a/spec/lib/gitlab/git/rev_list_spec.rb +++ b/spec/lib/gitlab/git/rev_list_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Git::RevList, lib: true do +describe Gitlab::Git::RevList do let(:project) { create(:project, :repository) } before do diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index 9a86cfa66e4..14c424b86e4 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GitAccess, lib: true do +describe Gitlab::GitAccess do let(:pull_access_check) { access.check('git-upload-pack', '_any') } let(:push_access_check) { access.check('git-receive-pack', '_any') } let(:access) { Gitlab::GitAccess.new(actor, project, protocol, authentication_abilities: authentication_abilities, redirected_path: redirected_path) } diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb index 797ec8cb23e..2a710fbdf06 100644 --- a/spec/lib/gitlab/git_access_wiki_spec.rb +++ b/spec/lib/gitlab/git_access_wiki_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GitAccessWiki, lib: true do +describe Gitlab::GitAccessWiki do let(:access) { Gitlab::GitAccessWiki.new(user, project, 'web', authentication_abilities: authentication_abilities, redirected_path: redirected_path) } let(:project) { create(:project, :repository) } let(:user) { create(:user) } diff --git a/spec/lib/gitlab/git_ref_validator_spec.rb b/spec/lib/gitlab/git_ref_validator_spec.rb index cc8daa535d6..91a25b7c0f0 100644 --- a/spec/lib/gitlab/git_ref_validator_spec.rb +++ b/spec/lib/gitlab/git_ref_validator_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GitRefValidator, lib: true do +describe Gitlab::GitRefValidator do it { expect(Gitlab::GitRefValidator.validate('feature/new')).to be_truthy } it { expect(Gitlab::GitRefValidator.validate('implement_@all')).to be_truthy } it { expect(Gitlab::GitRefValidator.validate('my_new_feature')).to be_truthy } diff --git a/spec/lib/gitlab/git_spec.rb b/spec/lib/gitlab/git_spec.rb index 36f0e6507c8..88f5c106c80 100644 --- a/spec/lib/gitlab/git_spec.rb +++ b/spec/lib/gitlab/git_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Git, lib: true do +describe Gitlab::Git do let(:committer_email) { 'user@example.org' } let(:committer_name) { 'John Doe' } diff --git a/spec/lib/gitlab/gitaly_client/diff_spec.rb b/spec/lib/gitlab/gitaly_client/diff_spec.rb index 2960c9a79ad..00a31ac0b96 100644 --- a/spec/lib/gitlab/gitaly_client/diff_spec.rb +++ b/spec/lib/gitlab/gitaly_client/diff_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GitalyClient::Diff, lib: true do +describe Gitlab::GitalyClient::Diff do let(:diff_fields) do { to_path: ".gitmodules", diff --git a/spec/lib/gitlab/gitaly_client/diff_stitcher_spec.rb b/spec/lib/gitlab/gitaly_client/diff_stitcher_spec.rb index 07650013052..cd3242b9326 100644 --- a/spec/lib/gitlab/gitaly_client/diff_stitcher_spec.rb +++ b/spec/lib/gitlab/gitaly_client/diff_stitcher_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GitalyClient::DiffStitcher, lib: true do +describe Gitlab::GitalyClient::DiffStitcher do describe 'enumeration' do it 'combines segregated diff messages together' do diff_1 = OpenStruct.new( diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb index 558ddb3fbd6..921e786a55c 100644 --- a/spec/lib/gitlab/gitaly_client_spec.rb +++ b/spec/lib/gitlab/gitaly_client_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' # We stub Gitaly in `spec/support/gitaly.rb` for other tests. We don't want # those stubs while testing the GitalyClient itself. -describe Gitlab::GitalyClient, lib: true, skip_gitaly_mock: true do +describe Gitlab::GitalyClient, skip_gitaly_mock: true do describe '.stub' do # Notice that this is referring to gRPC "stubs", not rspec stubs before do diff --git a/spec/lib/gitlab/github_import/branch_formatter_spec.rb b/spec/lib/gitlab/github_import/branch_formatter_spec.rb index 3a31f93efa5..426b43f8b51 100644 --- a/spec/lib/gitlab/github_import/branch_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/branch_formatter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GithubImport::BranchFormatter, lib: true do +describe Gitlab::GithubImport::BranchFormatter do let(:project) { create(:project, :repository) } let(:commit) { create(:commit, project: project) } let(:repo) { double } diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb index 21f2a9e225b..66273255b6f 100644 --- a/spec/lib/gitlab/github_import/client_spec.rb +++ b/spec/lib/gitlab/github_import/client_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GithubImport::Client, lib: true do +describe Gitlab::GithubImport::Client do let(:token) { '123456' } let(:github_provider) { Settingslogic.new('app_id' => 'asd123', 'app_secret' => 'asd123', 'name' => 'github', 'args' => { 'client_options' => {} }) } diff --git a/spec/lib/gitlab/github_import/comment_formatter_spec.rb b/spec/lib/gitlab/github_import/comment_formatter_spec.rb index cc38872e426..ef89634685a 100644 --- a/spec/lib/gitlab/github_import/comment_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/comment_formatter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GithubImport::CommentFormatter, lib: true do +describe Gitlab::GithubImport::CommentFormatter do let(:client) { double } let(:project) { create(:empty_project) } let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') } diff --git a/spec/lib/gitlab/github_import/importer_spec.rb b/spec/lib/gitlab/github_import/importer_spec.rb index 9d5e20841b5..d00a2deaf7b 100644 --- a/spec/lib/gitlab/github_import/importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GithubImport::Importer, lib: true do +describe Gitlab::GithubImport::Importer do shared_examples 'Gitlab::GithubImport::Importer#execute' do let(:expected_not_called) { [] } diff --git a/spec/lib/gitlab/github_import/issuable_formatter_spec.rb b/spec/lib/gitlab/github_import/issuable_formatter_spec.rb index 6bc5f98ed2c..05294d227bd 100644 --- a/spec/lib/gitlab/github_import/issuable_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/issuable_formatter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GithubImport::IssuableFormatter, lib: true do +describe Gitlab::GithubImport::IssuableFormatter do let(:raw_data) do double(number: 42) end diff --git a/spec/lib/gitlab/github_import/issue_formatter_spec.rb b/spec/lib/gitlab/github_import/issue_formatter_spec.rb index a4089592cf2..39b15926193 100644 --- a/spec/lib/gitlab/github_import/issue_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/issue_formatter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GithubImport::IssueFormatter, lib: true do +describe Gitlab::GithubImport::IssueFormatter do let(:client) { double } let!(:project) { create(:empty_project, namespace: create(:namespace, path: 'octocat')) } let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') } diff --git a/spec/lib/gitlab/github_import/label_formatter_spec.rb b/spec/lib/gitlab/github_import/label_formatter_spec.rb index 565435824fd..2cc7ac0b446 100644 --- a/spec/lib/gitlab/github_import/label_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/label_formatter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GithubImport::LabelFormatter, lib: true do +describe Gitlab::GithubImport::LabelFormatter do let(:project) { create(:empty_project) } let(:raw) { double(name: 'improvements', color: 'e6e6e6') } diff --git a/spec/lib/gitlab/github_import/milestone_formatter_spec.rb b/spec/lib/gitlab/github_import/milestone_formatter_spec.rb index 6d38041c468..310e0536fd7 100644 --- a/spec/lib/gitlab/github_import/milestone_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/milestone_formatter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GithubImport::MilestoneFormatter, lib: true do +describe Gitlab::GithubImport::MilestoneFormatter do let(:project) { create(:empty_project) } let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') } let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } diff --git a/spec/lib/gitlab/github_import/project_creator_spec.rb b/spec/lib/gitlab/github_import/project_creator_spec.rb index a73b1f4ff5d..948e7469a18 100644 --- a/spec/lib/gitlab/github_import/project_creator_spec.rb +++ b/spec/lib/gitlab/github_import/project_creator_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GithubImport::ProjectCreator, lib: true do +describe Gitlab::GithubImport::ProjectCreator do let(:user) { create(:user) } let(:namespace) { create(:group, owner: user) } 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 b7c59918a76..2e42f6239b7 100644 --- a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GithubImport::PullRequestFormatter, lib: true do +describe Gitlab::GithubImport::PullRequestFormatter do let(:client) { double } let(:project) { create(:project, :repository) } let(:source_sha) { create(:commit, project: project).id } diff --git a/spec/lib/gitlab/github_import/release_formatter_spec.rb b/spec/lib/gitlab/github_import/release_formatter_spec.rb index 13b15e669ab..1357cb636ae 100644 --- a/spec/lib/gitlab/github_import/release_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/release_formatter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GithubImport::ReleaseFormatter, lib: true do +describe Gitlab::GithubImport::ReleaseFormatter do let!(:project) { create(:empty_project, namespace: create(:namespace, path: 'octocat')) } let(:octocat) { double(id: 123456, login: 'octocat') } let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') } diff --git a/spec/lib/gitlab/github_import/user_formatter_spec.rb b/spec/lib/gitlab/github_import/user_formatter_spec.rb index db792233657..98e3a7c28b9 100644 --- a/spec/lib/gitlab/github_import/user_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/user_formatter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GithubImport::UserFormatter, lib: true do +describe Gitlab::GithubImport::UserFormatter do let(:client) { double } let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') } diff --git a/spec/lib/gitlab/github_import/wiki_formatter_spec.rb b/spec/lib/gitlab/github_import/wiki_formatter_spec.rb index 1bd29b8a563..de50265bc14 100644 --- a/spec/lib/gitlab/github_import/wiki_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/wiki_formatter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GithubImport::WikiFormatter, lib: true do +describe Gitlab::GithubImport::WikiFormatter do let(:project) do create(:project, namespace: create(:namespace, path: 'gitlabhq'), diff --git a/spec/lib/gitlab/gitlab_import/client_spec.rb b/spec/lib/gitlab/gitlab_import/client_spec.rb index cd8e805466a..977135b3310 100644 --- a/spec/lib/gitlab/gitlab_import/client_spec.rb +++ b/spec/lib/gitlab/gitlab_import/client_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GitlabImport::Client, lib: true do +describe Gitlab::GitlabImport::Client do include ImportSpecHelper let(:token) { '123456' } diff --git a/spec/lib/gitlab/gitlab_import/importer_spec.rb b/spec/lib/gitlab/gitlab_import/importer_spec.rb index 4f588da0a83..16b14474b89 100644 --- a/spec/lib/gitlab/gitlab_import/importer_spec.rb +++ b/spec/lib/gitlab/gitlab_import/importer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GitlabImport::Importer, lib: true do +describe Gitlab::GitlabImport::Importer do include ImportSpecHelper describe '#execute' do diff --git a/spec/lib/gitlab/gitlab_import/project_creator_spec.rb b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb index 483f65cd053..2d8923d14bb 100644 --- a/spec/lib/gitlab/gitlab_import/project_creator_spec.rb +++ b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GitlabImport::ProjectCreator, lib: true do +describe Gitlab::GitlabImport::ProjectCreator do let(:user) { create(:user) } let(:repo) do { diff --git a/spec/lib/gitlab/google_code_import/client_spec.rb b/spec/lib/gitlab/google_code_import/client_spec.rb index 85949ae8dc4..37985c062b4 100644 --- a/spec/lib/gitlab/google_code_import/client_spec.rb +++ b/spec/lib/gitlab/google_code_import/client_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe Gitlab::GoogleCodeImport::Client, lib: true do +describe Gitlab::GoogleCodeImport::Client do let(:raw_data) { JSON.parse(fixture_file("GoogleCodeProjectHosting.json")) } subject { described_class.new(raw_data) } diff --git a/spec/lib/gitlab/google_code_import/importer_spec.rb b/spec/lib/gitlab/google_code_import/importer_spec.rb index 622a0f513f4..85f40825005 100644 --- a/spec/lib/gitlab/google_code_import/importer_spec.rb +++ b/spec/lib/gitlab/google_code_import/importer_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe Gitlab::GoogleCodeImport::Importer, lib: true do +describe Gitlab::GoogleCodeImport::Importer do let(:mapped_user) { create(:user, username: "thilo123") } let(:raw_data) { JSON.parse(fixture_file("GoogleCodeProjectHosting.json")) } let(:client) { Gitlab::GoogleCodeImport::Client.new(raw_data) } diff --git a/spec/lib/gitlab/google_code_import/project_creator_spec.rb b/spec/lib/gitlab/google_code_import/project_creator_spec.rb index 499a896ee76..35549b48687 100644 --- a/spec/lib/gitlab/google_code_import/project_creator_spec.rb +++ b/spec/lib/gitlab/google_code_import/project_creator_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::GoogleCodeImport::ProjectCreator, lib: true do +describe Gitlab::GoogleCodeImport::ProjectCreator do let(:user) { create(:user) } let(:repo) do Gitlab::GoogleCodeImport::Repository.new( diff --git a/spec/lib/gitlab/graphs/commits_spec.rb b/spec/lib/gitlab/graphs/commits_spec.rb index abb5a26060f..3f9382a9143 100644 --- a/spec/lib/gitlab/graphs/commits_spec.rb +++ b/spec/lib/gitlab/graphs/commits_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Graphs::Commits, lib: true do +describe Gitlab::Graphs::Commits do let!(:project) { create(:empty_project, :public) } let!(:commit1) { create(:commit, git_commit: RepoHelpers.sample_commit, project: project, committed_date: Time.now) } diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb index 07687b470c5..9afd9916264 100644 --- a/spec/lib/gitlab/highlight_spec.rb +++ b/spec/lib/gitlab/highlight_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Highlight, lib: true do +describe Gitlab::Highlight do include RepoHelpers let(:project) { create(:project, :repository) } diff --git a/spec/lib/gitlab/i18n_spec.rb b/spec/lib/gitlab/i18n_spec.rb index 0dba4132101..785035d993f 100644 --- a/spec/lib/gitlab/i18n_spec.rb +++ b/spec/lib/gitlab/i18n_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::I18n, lib: true do +describe Gitlab::I18n do let(:user) { create(:user, preferred_language: 'es') } describe '.locale=' do diff --git a/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb b/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb index 63bab0f0d0d..574748756bd 100644 --- a/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb +++ b/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ImportExport::AttributeCleaner, lib: true do +describe Gitlab::ImportExport::AttributeCleaner do let(:relation_class){ double('relation_class').as_null_object } let(:unsafe_hash) do { diff --git a/spec/lib/gitlab/import_export/attribute_configuration_spec.rb b/spec/lib/gitlab/import_export/attribute_configuration_spec.rb index e24d070706a..65f073b2df3 100644 --- a/spec/lib/gitlab/import_export/attribute_configuration_spec.rb +++ b/spec/lib/gitlab/import_export/attribute_configuration_spec.rb @@ -7,7 +7,7 @@ require 'spec_helper' # to be included as part of the export, or blacklist them using the import_export.yml configuration file. # Likewise, new models added to import_export.yml, will need to be added with their correspondent attributes # to this spec. -describe 'Import/Export attribute configuration', lib: true do +describe 'Import/Export attribute configuration' do include ConfigurationHelper let(:config_hash) { YAML.load_file(Gitlab::ImportExport.config_file).deep_stringify_keys } diff --git a/spec/lib/gitlab/import_export/avatar_restorer_spec.rb b/spec/lib/gitlab/import_export/avatar_restorer_spec.rb index 08a42fd27a2..a7b292c8558 100644 --- a/spec/lib/gitlab/import_export/avatar_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/avatar_restorer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ImportExport::AvatarRestorer, lib: true do +describe Gitlab::ImportExport::AvatarRestorer do include UploadHelpers let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: 'test') } diff --git a/spec/lib/gitlab/import_export/avatar_saver_spec.rb b/spec/lib/gitlab/import_export/avatar_saver_spec.rb index 579a31ead58..814f85de03b 100644 --- a/spec/lib/gitlab/import_export/avatar_saver_spec.rb +++ b/spec/lib/gitlab/import_export/avatar_saver_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ImportExport::AvatarSaver, lib: true do +describe Gitlab::ImportExport::AvatarSaver do let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: 'test') } let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } let(:project_with_avatar) { create(:empty_project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } diff --git a/spec/lib/gitlab/import_export/file_importer_spec.rb b/spec/lib/gitlab/import_export/file_importer_spec.rb index b88b9c18c15..690c7625c52 100644 --- a/spec/lib/gitlab/import_export/file_importer_spec.rb +++ b/spec/lib/gitlab/import_export/file_importer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ImportExport::FileImporter, lib: true do +describe Gitlab::ImportExport::FileImporter do let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: 'test') } let(:export_path) { "#{Dir.tmpdir}/file_importer_spec" } let(:valid_file) { "#{shared.export_path}/valid.json" } diff --git a/spec/lib/gitlab/import_export/fork_spec.rb b/spec/lib/gitlab/import_export/fork_spec.rb index e8eb7e4f8f4..08588a76fe6 100644 --- a/spec/lib/gitlab/import_export/fork_spec.rb +++ b/spec/lib/gitlab/import_export/fork_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'forked project import', services: true do +describe 'forked project import' do let(:user) { create(:user) } let!(:project_with_repo) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') } let!(:project) { create(:empty_project, name: 'test-repo-restorer-no-repo', path: 'test-repo-restorer-no-repo') } diff --git a/spec/lib/gitlab/import_export/hash_util_spec.rb b/spec/lib/gitlab/import_export/hash_util_spec.rb index 1c3a0b23ece..366582dece3 100644 --- a/spec/lib/gitlab/import_export/hash_util_spec.rb +++ b/spec/lib/gitlab/import_export/hash_util_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ImportExport::HashUtil, lib: true do +describe Gitlab::ImportExport::HashUtil do let(:stringified_array) { [{ 'test' => 1 }] } let(:stringified_array_with_date) { [{ 'test_date' => '2016-04-06 06:17:44 +0200' }] } diff --git a/spec/lib/gitlab/import_export/import_export_spec.rb b/spec/lib/gitlab/import_export/import_export_spec.rb index f3fd0d82875..07415d41f93 100644 --- a/spec/lib/gitlab/import_export/import_export_spec.rb +++ b/spec/lib/gitlab/import_export/import_export_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ImportExport, services: true do +describe Gitlab::ImportExport do describe 'export filename' do let(:group) { create(:group, :nested) } let(:project) { create(:empty_project, :public, path: 'project-path', namespace: group) } diff --git a/spec/lib/gitlab/import_export/members_mapper_spec.rb b/spec/lib/gitlab/import_export/members_mapper_spec.rb index 3e0291c9ae9..f66a2ab7dda 100644 --- a/spec/lib/gitlab/import_export/members_mapper_spec.rb +++ b/spec/lib/gitlab/import_export/members_mapper_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ImportExport::MembersMapper, services: true do +describe Gitlab::ImportExport::MembersMapper do describe 'map members' do let(:user) { create(:admin) } let(:project) { create(:empty_project, :public, name: 'searchable_project') } diff --git a/spec/lib/gitlab/import_export/model_configuration_spec.rb b/spec/lib/gitlab/import_export/model_configuration_spec.rb index 2ede5cdd2ad..5cb8f2589c8 100644 --- a/spec/lib/gitlab/import_export/model_configuration_spec.rb +++ b/spec/lib/gitlab/import_export/model_configuration_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' # Part of the test security suite for the Import/Export feature # Finds if a new model has been added that can potentially be part of the Import/Export # If it finds a new model, it will show a +failure_message+ with the options available. -describe 'Import/Export model configuration', lib: true do +describe 'Import/Export model configuration' do include ConfigurationHelper let(:config_hash) { YAML.load_file(Gitlab::ImportExport.config_file).deep_stringify_keys } diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb index d50d238ddcd..d1ec0e45bbd 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' include ImportExport::CommonUtil -describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do +describe Gitlab::ImportExport::ProjectTreeRestorer do describe 'restore project tree' do before(:context) do @user = create(:user) diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb index 22a65e24f26..0c7e733b01f 100644 --- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ImportExport::ProjectTreeSaver, services: true do +describe Gitlab::ImportExport::ProjectTreeSaver do describe 'saves the project tree into a json object' do let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) } let(:project_tree_saver) { described_class.new(project: project, current_user: user, shared: shared) } diff --git a/spec/lib/gitlab/import_export/reader_spec.rb b/spec/lib/gitlab/import_export/reader_spec.rb index d700af142be..e9f5273725d 100644 --- a/spec/lib/gitlab/import_export/reader_spec.rb +++ b/spec/lib/gitlab/import_export/reader_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ImportExport::Reader, lib: true do +describe Gitlab::ImportExport::Reader do let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: '') } let(:test_config) { 'spec/support/import_export/import_export.yml' } let(:project_tree_hash) do diff --git a/spec/lib/gitlab/import_export/relation_factory_spec.rb b/spec/lib/gitlab/import_export/relation_factory_spec.rb index 5417c7534ea..baa90af84f7 100644 --- a/spec/lib/gitlab/import_export/relation_factory_spec.rb +++ b/spec/lib/gitlab/import_export/relation_factory_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ImportExport::RelationFactory, lib: true do +describe Gitlab::ImportExport::RelationFactory do let(:project) { create(:empty_project) } let(:members_mapper) { double('members_mapper').as_null_object } let(:user) { create(:admin) } diff --git a/spec/lib/gitlab/import_export/repo_restorer_spec.rb b/spec/lib/gitlab/import_export/repo_restorer_spec.rb index 09bfaa8fb75..d3be2965bf4 100644 --- a/spec/lib/gitlab/import_export/repo_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/repo_restorer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ImportExport::RepoRestorer, services: true do +describe Gitlab::ImportExport::RepoRestorer do describe 'bundle a project Git repo' do let(:user) { create(:user) } let!(:project_with_repo) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') } diff --git a/spec/lib/gitlab/import_export/repo_saver_spec.rb b/spec/lib/gitlab/import_export/repo_saver_spec.rb index a7f4e11271e..87af13e0beb 100644 --- a/spec/lib/gitlab/import_export/repo_saver_spec.rb +++ b/spec/lib/gitlab/import_export/repo_saver_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ImportExport::RepoSaver, services: true do +describe Gitlab::ImportExport::RepoSaver do describe 'bundle a project Git repo' do let(:user) { create(:user) } let!(:project) { create(:empty_project, :public, name: 'searchable_project') } diff --git a/spec/lib/gitlab/import_export/version_checker_spec.rb b/spec/lib/gitlab/import_export/version_checker_spec.rb index 2405ac5abfe..e7d50f75682 100644 --- a/spec/lib/gitlab/import_export/version_checker_spec.rb +++ b/spec/lib/gitlab/import_export/version_checker_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' include ImportExport::CommonUtil -describe Gitlab::ImportExport::VersionChecker, services: true do +describe Gitlab::ImportExport::VersionChecker do let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: '') } describe 'bundle a project Git repo' do diff --git a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb index 071e5fac3f0..78137aeff5e 100644 --- a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb +++ b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ImportExport::WikiRepoSaver, services: true do +describe Gitlab::ImportExport::WikiRepoSaver do describe 'bundle a wiki Git repo' do let(:user) { create(:user) } let!(:project) { create(:empty_project, :public, name: 'searchable_project') } diff --git a/spec/lib/gitlab/incoming_email_spec.rb b/spec/lib/gitlab/incoming_email_spec.rb index 698bd72d0f8..c959add7a36 100644 --- a/spec/lib/gitlab/incoming_email_spec.rb +++ b/spec/lib/gitlab/incoming_email_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe Gitlab::IncomingEmail, lib: true do +describe Gitlab::IncomingEmail do describe "self.enabled?" do context "when reply by email is enabled" do before do diff --git a/spec/lib/gitlab/issuable_metadata_spec.rb b/spec/lib/gitlab/issuable_metadata_spec.rb index f9f4b290dbf..2455969a183 100644 --- a/spec/lib/gitlab/issuable_metadata_spec.rb +++ b/spec/lib/gitlab/issuable_metadata_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::IssuableMetadata, lib: true do +describe Gitlab::IssuableMetadata do let(:user) { create(:user) } let!(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace) } diff --git a/spec/lib/gitlab/issuable_sorter_spec.rb b/spec/lib/gitlab/issuable_sorter_spec.rb index c9a434b2bcf..aeb32ef96d6 100644 --- a/spec/lib/gitlab/issuable_sorter_spec.rb +++ b/spec/lib/gitlab/issuable_sorter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::IssuableSorter, lib: true do +describe Gitlab::IssuableSorter do let(:namespace1) { build(:namespace, id: 1) } let(:project1) { build(:project, id: 1, namespace: namespace1) } diff --git a/spec/lib/gitlab/key_fingerprint_spec.rb b/spec/lib/gitlab/key_fingerprint_spec.rb index d09f51f3bfc..266eab6e793 100644 --- a/spec/lib/gitlab/key_fingerprint_spec.rb +++ b/spec/lib/gitlab/key_fingerprint_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe Gitlab::KeyFingerprint, lib: true do +describe Gitlab::KeyFingerprint do let(:key) { "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" } let(:fingerprint) { "3f:a2:ee:de:b5:de:53:c3:aa:2f:9c:45:24:4c:47:7b" } diff --git a/spec/lib/gitlab/lazy_spec.rb b/spec/lib/gitlab/lazy_spec.rb index b5ca89dd242..37a3ac74316 100644 --- a/spec/lib/gitlab/lazy_spec.rb +++ b/spec/lib/gitlab/lazy_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Lazy, lib: true do +describe Gitlab::Lazy do let(:dummy) { double(:dummy) } context 'when not calling any methods' do diff --git a/spec/lib/gitlab/ldap/access_spec.rb b/spec/lib/gitlab/ldap/access_spec.rb index 756fcb0fcaf..f800e267568 100644 --- a/spec/lib/gitlab/ldap/access_spec.rb +++ b/spec/lib/gitlab/ldap/access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::LDAP::Access, lib: true do +describe Gitlab::LDAP::Access do let(:access) { Gitlab::LDAP::Access.new user } let(:user) { create(:omniauth_user) } diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb index 0f4b8dbf7b7..d17d440d833 100644 --- a/spec/lib/gitlab/ldap/adapter_spec.rb +++ b/spec/lib/gitlab/ldap/adapter_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::LDAP::Adapter, lib: true do +describe Gitlab::LDAP::Adapter do include LdapHelpers let(:ldap) { double(:ldap) } diff --git a/spec/lib/gitlab/ldap/auth_hash_spec.rb b/spec/lib/gitlab/ldap/auth_hash_spec.rb index 7a2f774b948..bd546115afa 100644 --- a/spec/lib/gitlab/ldap/auth_hash_spec.rb +++ b/spec/lib/gitlab/ldap/auth_hash_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::LDAP::AuthHash, lib: true do +describe Gitlab::LDAP::AuthHash do let(:auth_hash) do Gitlab::LDAP::AuthHash.new( OmniAuth::AuthHash.new( diff --git a/spec/lib/gitlab/ldap/authentication_spec.rb b/spec/lib/gitlab/ldap/authentication_spec.rb index f689b47fec4..01b6282af0c 100644 --- a/spec/lib/gitlab/ldap/authentication_spec.rb +++ b/spec/lib/gitlab/ldap/authentication_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::LDAP::Authentication, lib: true do +describe Gitlab::LDAP::Authentication do let(:user) { create(:omniauth_user, extern_uid: dn) } let(:dn) { 'uid=john,ou=people,dc=example,dc=com' } let(:login) { 'john' } diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb index 3a56797d68b..0d99ebf23e8 100644 --- a/spec/lib/gitlab/ldap/config_spec.rb +++ b/spec/lib/gitlab/ldap/config_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::LDAP::Config, lib: true do +describe Gitlab::LDAP::Config do include LdapHelpers let(:config) { Gitlab::LDAP::Config.new('ldapmain') } diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb index b796d8bf076..efc7a551761 100644 --- a/spec/lib/gitlab/ldap/user_spec.rb +++ b/spec/lib/gitlab/ldap/user_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::LDAP::User, lib: true do +describe Gitlab::LDAP::User do let(:ldap_user) { Gitlab::LDAP::User.new(auth_hash) } let(:gl_user) { ldap_user.gl_user } let(:info) do diff --git a/spec/lib/gitlab/lfs_token_spec.rb b/spec/lib/gitlab/lfs_token_spec.rb index e9c1163e22a..3a20dad16d0 100644 --- a/spec/lib/gitlab/lfs_token_spec.rb +++ b/spec/lib/gitlab/lfs_token_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::LfsToken, lib: true do +describe Gitlab::LfsToken do describe '#token' do shared_examples 'an LFS token generator' do it 'returns a randomly generated token' do diff --git a/spec/lib/gitlab/markup_helper_spec.rb b/spec/lib/gitlab/markup_helper_spec.rb index 93b91b849f2..e610fab05da 100644 --- a/spec/lib/gitlab/markup_helper_spec.rb +++ b/spec/lib/gitlab/markup_helper_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::MarkupHelper, lib: true do +describe Gitlab::MarkupHelper do describe '#markup?' do %w(textile rdoc org creole wiki mediawiki rst adoc ad asciidoc mdown md markdown).each do |type| diff --git a/spec/lib/gitlab/middleware/go_spec.rb b/spec/lib/gitlab/middleware/go_spec.rb index c2ab015d5cb..6af1564da19 100644 --- a/spec/lib/gitlab/middleware/go_spec.rb +++ b/spec/lib/gitlab/middleware/go_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Middleware::Go, lib: true do +describe Gitlab::Middleware::Go do let(:app) { double(:app) } let(:middleware) { described_class.new(app) } diff --git a/spec/lib/gitlab/o_auth/auth_hash_spec.rb b/spec/lib/gitlab/o_auth/auth_hash_spec.rb index 19ab17419fc..4b77e6473be 100644 --- a/spec/lib/gitlab/o_auth/auth_hash_spec.rb +++ b/spec/lib/gitlab/o_auth/auth_hash_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::OAuth::AuthHash, lib: true do +describe Gitlab::OAuth::AuthHash do let(:auth_hash) do Gitlab::OAuth::AuthHash.new( OmniAuth::AuthHash.new( diff --git a/spec/lib/gitlab/o_auth/provider_spec.rb b/spec/lib/gitlab/o_auth/provider_spec.rb index 1e2a1f8c039..30faf107e3f 100644 --- a/spec/lib/gitlab/o_auth/provider_spec.rb +++ b/spec/lib/gitlab/o_auth/provider_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::OAuth::Provider, lib: true do +describe Gitlab::OAuth::Provider do describe '#config_for' do context 'for an LDAP provider' do context 'when the provider exists' do diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb index ea29cb9caf1..b70e49e2602 100644 --- a/spec/lib/gitlab/o_auth/user_spec.rb +++ b/spec/lib/gitlab/o_auth/user_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::OAuth::User, lib: true do +describe Gitlab::OAuth::User do let(:oauth_user) { Gitlab::OAuth::User.new(auth_hash) } let(:gl_user) { oauth_user.gl_user } let(:uid) { 'my-uid' } diff --git a/spec/lib/gitlab/optimistic_locking_spec.rb b/spec/lib/gitlab/optimistic_locking_spec.rb index acce2be93f2..81f81d4f963 100644 --- a/spec/lib/gitlab/optimistic_locking_spec.rb +++ b/spec/lib/gitlab/optimistic_locking_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::OptimisticLocking, lib: true do +describe Gitlab::OptimisticLocking do let!(:pipeline) { create(:ci_pipeline) } let!(:pipeline2) { Ci::Pipeline.find(pipeline.id) } diff --git a/spec/lib/gitlab/other_markup_spec.rb b/spec/lib/gitlab/other_markup_spec.rb index c0f5fa9dc1f..e26f39e193e 100644 --- a/spec/lib/gitlab/other_markup_spec.rb +++ b/spec/lib/gitlab/other_markup_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::OtherMarkup, lib: true do +describe Gitlab::OtherMarkup do let(:context) { {} } context "XSS Checks" do diff --git a/spec/lib/gitlab/path_regex_spec.rb b/spec/lib/gitlab/path_regex_spec.rb index 20be743d224..2f989397f7e 100644 --- a/spec/lib/gitlab/path_regex_spec.rb +++ b/spec/lib/gitlab/path_regex_spec.rb @@ -1,7 +1,7 @@ # coding: utf-8 require 'spec_helper' -describe Gitlab::PathRegex, lib: true do +describe Gitlab::PathRegex do # Pass in a full path to remove the format segment: # `/ci/lint(.:format)` -> `/ci/lint` def without_format(path) diff --git a/spec/lib/gitlab/polling_interval_spec.rb b/spec/lib/gitlab/polling_interval_spec.rb index 5ea8ecb1c30..eb8e618156b 100644 --- a/spec/lib/gitlab/polling_interval_spec.rb +++ b/spec/lib/gitlab/polling_interval_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::PollingInterval, lib: true do +describe Gitlab::PollingInterval do let(:polling_interval) { described_class } describe '.set_header' do diff --git a/spec/lib/gitlab/popen_spec.rb b/spec/lib/gitlab/popen_spec.rb index af50ecdb2ab..4567f220c11 100644 --- a/spec/lib/gitlab/popen_spec.rb +++ b/spec/lib/gitlab/popen_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Gitlab::Popen', lib: true, no_db: true do +describe 'Gitlab::Popen' do let(:path) { Rails.root.join('tmp').to_s } before do diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb index 3d22784909d..d17b436b910 100644 --- a/spec/lib/gitlab/project_search_results_spec.rb +++ b/spec/lib/gitlab/project_search_results_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ProjectSearchResults, lib: true do +describe Gitlab::ProjectSearchResults do let(:user) { create(:user) } let(:project) { create(:empty_project) } let(:query) { 'hello world' } diff --git a/spec/lib/gitlab/project_transfer_spec.rb b/spec/lib/gitlab/project_transfer_spec.rb index e2d6b1b9ab7..ff943db1d9c 100644 --- a/spec/lib/gitlab/project_transfer_spec.rb +++ b/spec/lib/gitlab/project_transfer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ProjectTransfer, lib: true do +describe Gitlab::ProjectTransfer do before do @root_dir = File.join(Rails.root, "public", "uploads") @project_transfer = Gitlab::ProjectTransfer.new diff --git a/spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb b/spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb index 61d48b05454..d7df4e35c31 100644 --- a/spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb +++ b/spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Prometheus::AdditionalMetricsParser, lib: true do +describe Gitlab::Prometheus::AdditionalMetricsParser do include Prometheus::MetricBuilders let(:parser_error_class) { Gitlab::Prometheus::ParsingError } diff --git a/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb index 4909aec5a4d..e42e034f4fb 100644 --- a/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb +++ b/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Prometheus::Queries::AdditionalMetricsDeploymentQuery, lib: true do +describe Gitlab::Prometheus::Queries::AdditionalMetricsDeploymentQuery do include Prometheus::MetricBuilders let(:client) { double('prometheus_client') } diff --git a/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb index 8e6e3bb5946..e9fd66d45fe 100644 --- a/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb +++ b/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Prometheus::Queries::AdditionalMetricsEnvironmentQuery, lib: true do +describe Gitlab::Prometheus::Queries::AdditionalMetricsEnvironmentQuery do include Prometheus::MetricBuilders let(:client) { double('prometheus_client') } diff --git a/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb index d957dd932c4..ffe3ad85baa 100644 --- a/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb +++ b/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Prometheus::Queries::DeploymentQuery, lib: true do +describe Gitlab::Prometheus::Queries::DeploymentQuery do let(:environment) { create(:environment, slug: 'environment-slug') } let(:deployment) { create(:deployment, environment: environment) } diff --git a/spec/lib/gitlab/prometheus/queries/matched_metrics_query_spec.rb b/spec/lib/gitlab/prometheus/queries/matched_metrics_query_spec.rb index d2796ab72da..2b488101496 100644 --- a/spec/lib/gitlab/prometheus/queries/matched_metrics_query_spec.rb +++ b/spec/lib/gitlab/prometheus/queries/matched_metrics_query_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Prometheus::Queries::MatchedMetricsQuery, lib: true do +describe Gitlab::Prometheus::Queries::MatchedMetricsQuery do include Prometheus::MetricBuilders let(:metric_group_class) { Gitlab::Prometheus::MetricGroup } diff --git a/spec/lib/gitlab/prometheus_client_spec.rb b/spec/lib/gitlab/prometheus_client_spec.rb index 46eaadae206..de625324092 100644 --- a/spec/lib/gitlab/prometheus_client_spec.rb +++ b/spec/lib/gitlab/prometheus_client_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::PrometheusClient, lib: true do +describe Gitlab::PrometheusClient do include PrometheusHelpers subject { described_class.new(api_url: 'https://prometheus.example.com') } diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb index 917692e9c6c..e41e2faac15 100644 --- a/spec/lib/gitlab/reference_extractor_spec.rb +++ b/spec/lib/gitlab/reference_extractor_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ReferenceExtractor, lib: true do +describe Gitlab::ReferenceExtractor do let(:project) { create(:empty_project) } before do diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb index 251f82849bf..68a57826647 100644 --- a/spec/lib/gitlab/regex_spec.rb +++ b/spec/lib/gitlab/regex_spec.rb @@ -1,7 +1,7 @@ # coding: utf-8 require 'spec_helper' -describe Gitlab::Regex, lib: true do +describe Gitlab::Regex do describe '.project_name_regex' do subject { described_class.project_name_regex } diff --git a/spec/lib/gitlab/request_context_spec.rb b/spec/lib/gitlab/request_context_spec.rb index a91c8655cdd..16673ea313e 100644 --- a/spec/lib/gitlab/request_context_spec.rb +++ b/spec/lib/gitlab/request_context_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::RequestContext, lib: true do +describe Gitlab::RequestContext do describe '#client_ip' do subject { Gitlab::RequestContext.client_ip } let(:app) { -> (env) {} } diff --git a/spec/lib/gitlab/request_profiler_spec.rb b/spec/lib/gitlab/request_profiler_spec.rb index ae9c06ebb7d..fd8cbf39bce 100644 --- a/spec/lib/gitlab/request_profiler_spec.rb +++ b/spec/lib/gitlab/request_profiler_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::RequestProfiler, lib: true do +describe Gitlab::RequestProfiler do describe '.profile_token' do it 'returns a token' do expect(described_class.profile_token).to be_present diff --git a/spec/lib/gitlab/route_map_spec.rb b/spec/lib/gitlab/route_map_spec.rb index e8feb21e4d7..d672f7b5675 100644 --- a/spec/lib/gitlab/route_map_spec.rb +++ b/spec/lib/gitlab/route_map_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::RouteMap, lib: true do +describe Gitlab::RouteMap do describe '#initialize' do context 'when the data is not YAML' do it 'raises an error' do diff --git a/spec/lib/gitlab/saml/user_spec.rb b/spec/lib/gitlab/saml/user_spec.rb index a4d2367b72a..2827a18515e 100644 --- a/spec/lib/gitlab/saml/user_spec.rb +++ b/spec/lib/gitlab/saml/user_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Saml::User, lib: true do +describe Gitlab::Saml::User do let(:saml_user) { described_class.new(auth_hash) } let(:gl_user) { saml_user.gl_user } let(:uid) { 'my-uid' } diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb index 5b1b8f9516a..8ab250a6203 100644 --- a/spec/lib/gitlab/shell_spec.rb +++ b/spec/lib/gitlab/shell_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require 'stringio' -describe Gitlab::Shell, lib: true do +describe Gitlab::Shell do let(:project) { double('Project', id: 7, path: 'diaspora') } let(:gitlab_shell) { Gitlab::Shell.new } let(:popen_vars) { { 'GIT_TERMINAL_PROMPT' => ENV['GIT_TERMINAL_PROMPT'] } } @@ -59,7 +59,7 @@ describe Gitlab::Shell, lib: true do end end - describe Gitlab::Shell::KeyAdder, lib: true do + describe Gitlab::Shell::KeyAdder do describe '#add_key' do it 'removes trailing garbage' do io = spy(:io) diff --git a/spec/lib/gitlab/sherlock/collection_spec.rb b/spec/lib/gitlab/sherlock/collection_spec.rb index 2ae79b50e77..873ed14f804 100644 --- a/spec/lib/gitlab/sherlock/collection_spec.rb +++ b/spec/lib/gitlab/sherlock/collection_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Sherlock::Collection, lib: true do +describe Gitlab::Sherlock::Collection do let(:collection) { described_class.new } let(:transaction) do diff --git a/spec/lib/gitlab/sherlock/file_sample_spec.rb b/spec/lib/gitlab/sherlock/file_sample_spec.rb index 4989d14def3..394421504e0 100644 --- a/spec/lib/gitlab/sherlock/file_sample_spec.rb +++ b/spec/lib/gitlab/sherlock/file_sample_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Sherlock::FileSample, lib: true do +describe Gitlab::Sherlock::FileSample do let(:sample) { described_class.new(__FILE__, [], 150.4, 2) } describe '#id' do diff --git a/spec/lib/gitlab/sherlock/line_profiler_spec.rb b/spec/lib/gitlab/sherlock/line_profiler_spec.rb index 39c6b2a4844..f2f8040fa0b 100644 --- a/spec/lib/gitlab/sherlock/line_profiler_spec.rb +++ b/spec/lib/gitlab/sherlock/line_profiler_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Sherlock::LineProfiler, lib: true do +describe Gitlab::Sherlock::LineProfiler do let(:profiler) { described_class.new } describe '#profile' do diff --git a/spec/lib/gitlab/sherlock/line_sample_spec.rb b/spec/lib/gitlab/sherlock/line_sample_spec.rb index f9b61f8684e..5f02f6a3213 100644 --- a/spec/lib/gitlab/sherlock/line_sample_spec.rb +++ b/spec/lib/gitlab/sherlock/line_sample_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Sherlock::LineSample, lib: true do +describe Gitlab::Sherlock::LineSample do let(:sample) { described_class.new(150.0, 4) } describe '#duration' do diff --git a/spec/lib/gitlab/sherlock/location_spec.rb b/spec/lib/gitlab/sherlock/location_spec.rb index 5739afa6b1e..b295a624b35 100644 --- a/spec/lib/gitlab/sherlock/location_spec.rb +++ b/spec/lib/gitlab/sherlock/location_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Sherlock::Location, lib: true do +describe Gitlab::Sherlock::Location do let(:location) { described_class.new(__FILE__, 1) } describe 'from_ruby_location' do diff --git a/spec/lib/gitlab/sherlock/middleware_spec.rb b/spec/lib/gitlab/sherlock/middleware_spec.rb index b98ab0b14a2..2016023df06 100644 --- a/spec/lib/gitlab/sherlock/middleware_spec.rb +++ b/spec/lib/gitlab/sherlock/middleware_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Sherlock::Middleware, lib: true do +describe Gitlab::Sherlock::Middleware do let(:app) { double(:app) } let(:middleware) { described_class.new(app) } diff --git a/spec/lib/gitlab/sherlock/query_spec.rb b/spec/lib/gitlab/sherlock/query_spec.rb index d97b5eef573..426071c7f92 100644 --- a/spec/lib/gitlab/sherlock/query_spec.rb +++ b/spec/lib/gitlab/sherlock/query_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Sherlock::Query, lib: true do +describe Gitlab::Sherlock::Query do let(:started_at) { Time.utc(2015, 1, 1) } let(:finished_at) { started_at + 5 } diff --git a/spec/lib/gitlab/sherlock/transaction_spec.rb b/spec/lib/gitlab/sherlock/transaction_spec.rb index 6ae1aa20ea7..4a14dfbec56 100644 --- a/spec/lib/gitlab/sherlock/transaction_spec.rb +++ b/spec/lib/gitlab/sherlock/transaction_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Sherlock::Transaction, lib: true do +describe Gitlab::Sherlock::Transaction do let(:transaction) { described_class.new('POST', '/cat_pictures') } describe '#id' do diff --git a/spec/lib/gitlab/slash_commands/command_spec.rb b/spec/lib/gitlab/slash_commands/command_spec.rb index 28d7f9858c3..f0ecf59406a 100644 --- a/spec/lib/gitlab/slash_commands/command_spec.rb +++ b/spec/lib/gitlab/slash_commands/command_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::SlashCommands::Command, service: true do +describe Gitlab::SlashCommands::Command do let(:project) { create(:empty_project) } let(:user) { create(:user) } diff --git a/spec/lib/gitlab/slash_commands/deploy_spec.rb b/spec/lib/gitlab/slash_commands/deploy_spec.rb index d919f7260db..e52aaed7328 100644 --- a/spec/lib/gitlab/slash_commands/deploy_spec.rb +++ b/spec/lib/gitlab/slash_commands/deploy_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::SlashCommands::Deploy, service: true do +describe Gitlab::SlashCommands::Deploy do describe '#execute' do let(:project) { create(:empty_project) } let(:user) { create(:user) } diff --git a/spec/lib/gitlab/slash_commands/issue_new_spec.rb b/spec/lib/gitlab/slash_commands/issue_new_spec.rb index 4de50d4a8bb..5dfb1b506bc 100644 --- a/spec/lib/gitlab/slash_commands/issue_new_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_new_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::SlashCommands::IssueNew, service: true do +describe Gitlab::SlashCommands::IssueNew do describe '#execute' do let(:project) { create(:empty_project) } let(:user) { create(:user) } diff --git a/spec/lib/gitlab/slash_commands/issue_search_spec.rb b/spec/lib/gitlab/slash_commands/issue_search_spec.rb index 06fff0afc50..e5409fe2339 100644 --- a/spec/lib/gitlab/slash_commands/issue_search_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_search_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::SlashCommands::IssueSearch, service: true do +describe Gitlab::SlashCommands::IssueSearch do describe '#execute' do let!(:issue) { create(:issue, project: project, title: 'find me') } let!(:confidential) { create(:issue, :confidential, project: project, title: 'mepmep find') } diff --git a/spec/lib/gitlab/slash_commands/issue_show_spec.rb b/spec/lib/gitlab/slash_commands/issue_show_spec.rb index 1899f664ccd..f67a17c7922 100644 --- a/spec/lib/gitlab/slash_commands/issue_show_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_show_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::SlashCommands::IssueShow, service: true do +describe Gitlab::SlashCommands::IssueShow do describe '#execute' do let(:issue) { create(:issue, project: project) } let(:project) { create(:empty_project) } diff --git a/spec/lib/gitlab/sql/glob_spec.rb b/spec/lib/gitlab/sql/glob_spec.rb index 451c583310d..f0bb4294d62 100644 --- a/spec/lib/gitlab/sql/glob_spec.rb +++ b/spec/lib/gitlab/sql/glob_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::SQL::Glob, lib: true do +describe Gitlab::SQL::Glob do describe '.to_like' do it 'matches * as %' do expect(glob('apple', '*')).to be(true) diff --git a/spec/lib/gitlab/sql/union_spec.rb b/spec/lib/gitlab/sql/union_spec.rb index 849edb09476..5346881444d 100644 --- a/spec/lib/gitlab/sql/union_spec.rb +++ b/spec/lib/gitlab/sql/union_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::SQL::Union, lib: true do +describe Gitlab::SQL::Union do let(:relation_1) { User.where(email: 'alice@example.com').select(:id) } let(:relation_2) { User.where(email: 'bob@example.com').select(:id) } diff --git a/spec/lib/gitlab/string_range_marker_spec.rb b/spec/lib/gitlab/string_range_marker_spec.rb index 7c77772b3f6..abeaa7f0ddb 100644 --- a/spec/lib/gitlab/string_range_marker_spec.rb +++ b/spec/lib/gitlab/string_range_marker_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::StringRangeMarker, lib: true do +describe Gitlab::StringRangeMarker do describe '#mark' do context "when the rich text is html safe" do let(:raw) { "abc " } diff --git a/spec/lib/gitlab/string_regex_marker_spec.rb b/spec/lib/gitlab/string_regex_marker_spec.rb index 2f5cf6c6e3b..d715f9bd641 100644 --- a/spec/lib/gitlab/string_regex_marker_spec.rb +++ b/spec/lib/gitlab/string_regex_marker_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::StringRegexMarker, lib: true do +describe Gitlab::StringRegexMarker do describe '#mark' do let(:raw) { %{"name": "AFNetworking"} } let(:rich) { %{"name": "AFNetworking"}.html_safe } diff --git a/spec/lib/gitlab/upgrader_spec.rb b/spec/lib/gitlab/upgrader_spec.rb index fcfd8d58b70..eb128e343e6 100644 --- a/spec/lib/gitlab/upgrader_spec.rb +++ b/spec/lib/gitlab/upgrader_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Upgrader, lib: true do +describe Gitlab::Upgrader do let(:upgrader) { Gitlab::Upgrader.new } let(:current_version) { Gitlab::VERSION } diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb index a504d299307..f5b4882815f 100644 --- a/spec/lib/gitlab/url_blocker_spec.rb +++ b/spec/lib/gitlab/url_blocker_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::UrlBlocker, lib: true do +describe Gitlab::UrlBlocker do describe '#blocked_url?' do it 'allows imports from configured web host and port' do import_url = "http://#{Gitlab.config.gitlab.host}:#{Gitlab.config.gitlab.port}/t.git" diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb index e9a6e273516..50422020823 100644 --- a/spec/lib/gitlab/url_builder_spec.rb +++ b/spec/lib/gitlab/url_builder_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::UrlBuilder, lib: true do +describe Gitlab::UrlBuilder do describe '.build' do context 'when passing a Commit' do it 'returns a proper URL' do diff --git a/spec/lib/gitlab/url_sanitizer_spec.rb b/spec/lib/gitlab/url_sanitizer_spec.rb index 6bce724a3f6..308b1a128be 100644 --- a/spec/lib/gitlab/url_sanitizer_spec.rb +++ b/spec/lib/gitlab/url_sanitizer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::UrlSanitizer, lib: true do +describe Gitlab::UrlSanitizer do let(:credentials) { { user: 'blah', password: 'password' } } let(:url_sanitizer) do described_class.new("https://github.com/me/project.git", credentials: credentials) diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb index 0d87cf25dbb..648c464db78 100644 --- a/spec/lib/gitlab/user_access_spec.rb +++ b/spec/lib/gitlab/user_access_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::UserAccess, lib: true do +describe Gitlab::UserAccess do let(:access) { Gitlab::UserAccess.new(user, project: project) } let(:project) { create(:project) } let(:user) { create(:user) } diff --git a/spec/lib/gitlab/user_activities_spec.rb b/spec/lib/gitlab/user_activities_spec.rb index a4ea0ac59e9..6bce2ee13cf 100644 --- a/spec/lib/gitlab/user_activities_spec.rb +++ b/spec/lib/gitlab/user_activities_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::UserActivities, :clean_gitlab_redis_shared_state, lib: true do +describe Gitlab::UserActivities, :clean_gitlab_redis_shared_state do let(:now) { Time.now } describe '.record' do diff --git a/spec/lib/gitlab/utils_spec.rb b/spec/lib/gitlab/utils_spec.rb index 00941aec380..111c873f79c 100644 --- a/spec/lib/gitlab/utils_spec.rb +++ b/spec/lib/gitlab/utils_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Utils, lib: true do +describe Gitlab::Utils do delegate :to_boolean, :boolean_to_yes_no, to: :described_class describe '.to_boolean' do diff --git a/spec/lib/gitlab/version_info_spec.rb b/spec/lib/gitlab/version_info_spec.rb index 706ee9bec58..e7e1a92ae54 100644 --- a/spec/lib/gitlab/version_info_spec.rb +++ b/spec/lib/gitlab/version_info_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Gitlab::VersionInfo', lib: true, no_db: true do +describe 'Gitlab::VersionInfo' do before do @unknown = Gitlab::VersionInfo.new @v0_0_1 = Gitlab::VersionInfo.new(0, 0, 1) diff --git a/spec/lib/gitlab/visibility_level_spec.rb b/spec/lib/gitlab/visibility_level_spec.rb index db9d2807be6..48a67773de9 100644 --- a/spec/lib/gitlab/visibility_level_spec.rb +++ b/spec/lib/gitlab/visibility_level_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::VisibilityLevel, lib: true do +describe Gitlab::VisibilityLevel do describe '.level_value' do it 'converts "public" to integer value' do expect(described_class.level_value('public')).to eq(Gitlab::VisibilityLevel::PUBLIC) diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb index 6ca1edb01b9..c593e1db1bf 100644 --- a/spec/lib/gitlab/workhorse_spec.rb +++ b/spec/lib/gitlab/workhorse_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Workhorse, lib: true do +describe Gitlab::Workhorse do let(:project) { create(:project, :repository) } let(:repository) { project.repository } diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb index c4c107c9eea..f97136f0191 100644 --- a/spec/lib/gitlab_spec.rb +++ b/spec/lib/gitlab_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe Gitlab, lib: true do +describe Gitlab do describe '.com?' do it 'is true when on GitLab.com' do stub_config_setting(url: 'https://gitlab.com') diff --git a/spec/lib/repository_cache_spec.rb b/spec/lib/repository_cache_spec.rb index 5892f3481a4..41d1706ab6d 100644 --- a/spec/lib/repository_cache_spec.rb +++ b/spec/lib/repository_cache_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe RepositoryCache, lib: true do +describe RepositoryCache do let(:project) { create(:empty_project) } let(:backend) { double('backend').as_null_object } let(:cache) { RepositoryCache.new('example', project.id, backend) } diff --git a/spec/lib/system_check/simple_executor_spec.rb b/spec/lib/system_check/simple_executor_spec.rb index 795f11ee1f8..025ea2673b4 100644 --- a/spec/lib/system_check/simple_executor_spec.rb +++ b/spec/lib/system_check/simple_executor_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require 'rake_helper' -describe SystemCheck::SimpleExecutor, lib: true do +describe SystemCheck::SimpleExecutor do class SimpleCheck < SystemCheck::BaseCheck set_name 'my simple check' diff --git a/spec/lib/system_check_spec.rb b/spec/lib/system_check_spec.rb index 23d9beddb08..9a75c41f783 100644 --- a/spec/lib/system_check_spec.rb +++ b/spec/lib/system_check_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' require 'rake_helper' -describe SystemCheck, lib: true do +describe SystemCheck do class SimpleCheck < SystemCheck::BaseCheck def check? true diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 58f1a620ab4..cb57626b597 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ability, lib: true do +describe Ability do context 'using a nil subject' do it 'has no permissions' do expect(Ability.policy_for(nil, nil)).to be_banned diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index e600eab6565..41129b945b6 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ApplicationSetting, models: true do +describe ApplicationSetting do let(:setting) { ApplicationSetting.create_from_defaults } it { expect(setting).to be_valid } diff --git a/spec/models/award_emoji_spec.rb b/spec/models/award_emoji_spec.rb index 2a9a27752c1..87e60d9c16b 100644 --- a/spec/models/award_emoji_spec.rb +++ b/spec/models/award_emoji_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe AwardEmoji, models: true do +describe AwardEmoji do describe 'Associations' do it { is_expected.to belong_to(:awardable) } it { is_expected.to belong_to(:user) } diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb index 333f4139a96..75e7c7d42bd 100644 --- a/spec/models/broadcast_message_spec.rb +++ b/spec/models/broadcast_message_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BroadcastMessage, models: true do +describe BroadcastMessage do subject { build(:broadcast_message) } it { is_expected.to be_valid } diff --git a/spec/models/chat_name_spec.rb b/spec/models/chat_name_spec.rb index b02971cab82..8581bcbb08b 100644 --- a/spec/models/chat_name_spec.rb +++ b/spec/models/chat_name_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ChatName, models: true do +describe ChatName do subject { create(:chat_name) } it { is_expected.to belong_to(:service) } diff --git a/spec/models/ci/artifact_blob_spec.rb b/spec/models/ci/artifact_blob_spec.rb index 968593d7e9b..a10a8af5303 100644 --- a/spec/models/ci/artifact_blob_spec.rb +++ b/spec/models/ci/artifact_blob_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::ArtifactBlob, models: true do +describe Ci::ArtifactBlob do let(:build) { create(:ci_build, :artifacts) } let(:entry) { build.artifacts_metadata_entry('other_artifacts_0.1.2/another-subdirectory/banana_sample.gif') } diff --git a/spec/models/ci/group_spec.rb b/spec/models/ci/group_spec.rb index 62e15093089..51123e73fe6 100644 --- a/spec/models/ci/group_spec.rb +++ b/spec/models/ci/group_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::Group, models: true do +describe Ci::Group do subject do described_class.new('test', name: 'rspec', jobs: jobs) end diff --git a/spec/models/ci/group_variable_spec.rb b/spec/models/ci/group_variable_spec.rb index 24b914face9..145189e7469 100644 --- a/spec/models/ci/group_variable_spec.rb +++ b/spec/models/ci/group_variable_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::GroupVariable, models: true do +describe Ci::GroupVariable do subject { build(:ci_group_variable) } it { is_expected.to include_module(HasVariable) } diff --git a/spec/models/ci/pipeline_schedule_spec.rb b/spec/models/ci/pipeline_schedule_spec.rb index 6427deda31e..3ae86ab2b4b 100644 --- a/spec/models/ci/pipeline_schedule_spec.rb +++ b/spec/models/ci/pipeline_schedule_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::PipelineSchedule, models: true do +describe Ci::PipelineSchedule do it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:owner) } diff --git a/spec/models/ci/pipeline_schedule_variable_spec.rb b/spec/models/ci/pipeline_schedule_variable_spec.rb index 0de76a57b7f..dc8427f28bc 100644 --- a/spec/models/ci/pipeline_schedule_variable_spec.rb +++ b/spec/models/ci/pipeline_schedule_variable_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::PipelineScheduleVariable, models: true do +describe Ci::PipelineScheduleVariable do subject { build(:ci_pipeline_schedule_variable) } it { is_expected.to include_module(HasVariable) } diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index bbd45f10b1b..9461905c787 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::Pipeline, models: true do +describe Ci::Pipeline do include EmailHelpers let(:user) { create(:user) } diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index 4b9cce28e0e..9a4ed86990a 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::Runner, models: true do +describe Ci::Runner do describe 'validation' do context 'when runner is not allowed to pick untagged jobs' do context 'when runner does not have tags' do diff --git a/spec/models/ci/trigger_spec.rb b/spec/models/ci/trigger_spec.rb index 92c15c13c18..de51f4879fd 100644 --- a/spec/models/ci/trigger_spec.rb +++ b/spec/models/ci/trigger_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::Trigger, models: true do +describe Ci::Trigger do let(:project) { create :empty_project } describe 'associations' do diff --git a/spec/models/ci/variable_spec.rb b/spec/models/ci/variable_spec.rb index 890ffaae494..e4ff551151e 100644 --- a/spec/models/ci/variable_spec.rb +++ b/spec/models/ci/variable_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::Variable, models: true do +describe Ci::Variable do subject { build(:ci_variable) } describe 'validations' do diff --git a/spec/models/commit_range_spec.rb b/spec/models/commit_range_spec.rb index ba9c3f66d21..07e10b44938 100644 --- a/spec/models/commit_range_spec.rb +++ b/spec/models/commit_range_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe CommitRange, models: true do +describe CommitRange do describe 'modules' do subject { described_class } diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 528b211c9d6..2285c338599 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Commit, models: true do +describe Commit do let(:project) { create(:project, :public, :repository) } let(:commit) { project.commit } diff --git a/spec/models/compare_spec.rb b/spec/models/compare_spec.rb index da003dbf794..04f3cecae00 100644 --- a/spec/models/compare_spec.rb +++ b/spec/models/compare_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Compare, models: true do +describe Compare do include RepoHelpers let(:project) { create(:project, :public, :repository) } diff --git a/spec/models/concerns/case_sensitivity_spec.rb b/spec/models/concerns/case_sensitivity_spec.rb index a6fccb668e3..5c0dfaeb4d3 100644 --- a/spec/models/concerns/case_sensitivity_spec.rb +++ b/spec/models/concerns/case_sensitivity_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe CaseSensitivity, models: true do +describe CaseSensitivity do describe '.iwhere' do let(:connection) { ActiveRecord::Base.connection } let(:model) { Class.new { include CaseSensitivity } } diff --git a/spec/models/concerns/participable_spec.rb b/spec/models/concerns/participable_spec.rb index a9f4ef9ee5e..431f1482615 100644 --- a/spec/models/concerns/participable_spec.rb +++ b/spec/models/concerns/participable_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Participable, models: true do +describe Participable do let(:model) do Class.new do include Participable diff --git a/spec/models/concerns/resolvable_discussion_spec.rb b/spec/models/concerns/resolvable_discussion_spec.rb index 3934992c143..1616c2ea985 100644 --- a/spec/models/concerns/resolvable_discussion_spec.rb +++ b/spec/models/concerns/resolvable_discussion_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Discussion, ResolvableDiscussion, models: true do +describe Discussion, ResolvableDiscussion do subject { described_class.new([first_note, second_note, third_note]) } let(:first_note) { create(:discussion_note_on_merge_request) } diff --git a/spec/models/concerns/resolvable_note_spec.rb b/spec/models/concerns/resolvable_note_spec.rb index 1503ccdff11..53eaa6f8461 100644 --- a/spec/models/concerns/resolvable_note_spec.rb +++ b/spec/models/concerns/resolvable_note_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Note, ResolvableNote, models: true do +describe Note, ResolvableNote do let(:project) { create(:project) } let(:merge_request) { create(:merge_request, source_project: project) } subject { create(:discussion_note_on_merge_request, noteable: merge_request, project: project) } diff --git a/spec/models/concerns/uniquify_spec.rb b/spec/models/concerns/uniquify_spec.rb index 83187d732e4..914730718e7 100644 --- a/spec/models/concerns/uniquify_spec.rb +++ b/spec/models/concerns/uniquify_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Uniquify, models: true do +describe Uniquify do let(:uniquify) { described_class.new } describe "#string" do diff --git a/spec/models/cycle_analytics/issue_spec.rb b/spec/models/cycle_analytics/issue_spec.rb index fc7d18bd40e..985e1bf80be 100644 --- a/spec/models/cycle_analytics/issue_spec.rb +++ b/spec/models/cycle_analytics/issue_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'CycleAnalytics#issue', models: true do +describe 'CycleAnalytics#issue' do extend CycleAnalyticsHelpers::TestGeneration let(:project) { create(:project, :repository) } diff --git a/spec/models/deploy_key_spec.rb b/spec/models/deploy_key_spec.rb index 8ef8218cf74..2aece75b817 100644 --- a/spec/models/deploy_key_spec.rb +++ b/spec/models/deploy_key_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe DeployKey, models: true do +describe DeployKey do include EmailHelpers describe "Associations" do diff --git a/spec/models/deploy_keys_project_spec.rb b/spec/models/deploy_keys_project_spec.rb index aacc178a19e..f10b65ba9d8 100644 --- a/spec/models/deploy_keys_project_spec.rb +++ b/spec/models/deploy_keys_project_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe DeployKeysProject, models: true do +describe DeployKeysProject do describe "Associations" do it { is_expected.to belong_to(:deploy_key) } it { is_expected.to belong_to(:project) } diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb index bb84d3fc13d..6447095078b 100644 --- a/spec/models/deployment_spec.rb +++ b/spec/models/deployment_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Deployment, models: true do +describe Deployment do subject { build(:deployment) } it { is_expected.to belong_to(:project) } diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb index 297c2108dc2..4aa9ec789a3 100644 --- a/spec/models/diff_note_spec.rb +++ b/spec/models/diff_note_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe DiffNote, models: true do +describe DiffNote do include RepoHelpers let(:merge_request) { create(:merge_request) } diff --git a/spec/models/email_spec.rb b/spec/models/email_spec.rb index fe4de1b2afb..1d6fabe48b1 100644 --- a/spec/models/email_spec.rb +++ b/spec/models/email_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Email, models: true do +describe Email do describe 'validations' do it_behaves_like 'an object with email-formated attributes', :email do subject { build(:email) } diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index 0a2cd8c2957..ebf2c070116 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Environment, models: true do +describe Environment do set(:project) { create(:empty_project) } subject(:environment) { create(:environment, project: project) } diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index 10b9bf9f43a..4a4b84c9566 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Event, models: true do +describe Event do describe "Associations" do it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:target) } diff --git a/spec/models/external_issue_spec.rb b/spec/models/external_issue_spec.rb index cd50bda8996..c8748daf46b 100644 --- a/spec/models/external_issue_spec.rb +++ b/spec/models/external_issue_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ExternalIssue, models: true do +describe ExternalIssue do let(:project) { double('project', id: 1, to_reference: 'namespace1/project1') } let(:issue) { described_class.new('EXT-1234', project) } diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb index 152e97e09bf..aedc74deb78 100644 --- a/spec/models/generic_commit_status_spec.rb +++ b/spec/models/generic_commit_status_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GenericCommitStatus, models: true do +describe GenericCommitStatus do let(:project) { create(:empty_project) } let(:pipeline) { create(:ci_pipeline, project: project) } let(:external_url) { 'http://example.gitlab.com/status' } diff --git a/spec/models/global_milestone_spec.rb b/spec/models/global_milestone_spec.rb index a14efda3eda..17462f70a6d 100644 --- a/spec/models/global_milestone_spec.rb +++ b/spec/models/global_milestone_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GlobalMilestone, models: true do +describe GlobalMilestone do let(:user) { create(:user) } let(:user2) { create(:user) } let(:group) { create(:group) } diff --git a/spec/models/group_label_spec.rb b/spec/models/group_label_spec.rb index 555a876daeb..f7828059295 100644 --- a/spec/models/group_label_spec.rb +++ b/spec/models/group_label_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GroupLabel, models: true do +describe GroupLabel do describe 'relationships' do it { is_expected.to belong_to(:group) } end diff --git a/spec/models/group_milestone_spec.rb b/spec/models/group_milestone_spec.rb index 916afb7aaf5..6d1a7f188c8 100644 --- a/spec/models/group_milestone_spec.rb +++ b/spec/models/group_milestone_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GroupMilestone, models: true do +describe GroupMilestone do let(:group) { create(:group) } let(:project) { create(:empty_project, group: group) } let(:project_milestone) do diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index d8e868265ed..3f66d9b0ab9 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Group, models: true do +describe Group do let!(:group) { create(:group, :access_requestable) } describe 'associations' do diff --git a/spec/models/guest_spec.rb b/spec/models/guest_spec.rb index c60bd7af958..ac9aaa76550 100644 --- a/spec/models/guest_spec.rb +++ b/spec/models/guest_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Guest, lib: true do +describe Guest do let(:public_project) { build_stubbed(:empty_project, :public) } let(:private_project) { build_stubbed(:empty_project, :private) } let(:internal_project) { build_stubbed(:empty_project, :internal) } diff --git a/spec/models/hooks/project_hook_spec.rb b/spec/models/hooks/project_hook_spec.rb index 0af270014b5..c9b948fb747 100644 --- a/spec/models/hooks/project_hook_spec.rb +++ b/spec/models/hooks/project_hook_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ProjectHook, models: true do +describe ProjectHook do describe 'associations' do it { is_expected.to belong_to :project } end diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb index 8e871a41a8c..e32eaafc13f 100644 --- a/spec/models/hooks/service_hook_spec.rb +++ b/spec/models/hooks/service_hook_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ServiceHook, models: true do +describe ServiceHook do describe 'associations' do it { is_expected.to belong_to :service } end diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb index 559778257fa..812dcb437f5 100644 --- a/spec/models/hooks/system_hook_spec.rb +++ b/spec/models/hooks/system_hook_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe SystemHook, models: true do +describe SystemHook do context 'default attributes' do let(:system_hook) { build(:system_hook) } diff --git a/spec/models/hooks/web_hook_log_spec.rb b/spec/models/hooks/web_hook_log_spec.rb index c649cf3b589..19bc88b1333 100644 --- a/spec/models/hooks/web_hook_log_spec.rb +++ b/spec/models/hooks/web_hook_log_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe WebHookLog, models: true do +describe WebHookLog do it { is_expected.to belong_to(:web_hook) } it { is_expected.to serialize(:request_headers).as(Hash) } diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb index 53157c24477..388120160ab 100644 --- a/spec/models/hooks/web_hook_spec.rb +++ b/spec/models/hooks/web_hook_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe WebHook, models: true do +describe WebHook do let(:hook) { build(:project_hook) } describe 'associations' do diff --git a/spec/models/identity_spec.rb b/spec/models/identity_spec.rb index b3aed66a5b6..4ca6556d0f4 100644 --- a/spec/models/identity_spec.rb +++ b/spec/models/identity_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -RSpec.describe Identity, models: true do +RSpec.describe Identity do describe 'relations' do it { is_expected.to belong_to(:user) } end diff --git a/spec/models/issue/metrics_spec.rb b/spec/models/issue/metrics_spec.rb index 08712f2a768..6ceff7d24d4 100644 --- a/spec/models/issue/metrics_spec.rb +++ b/spec/models/issue/metrics_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Issue::Metrics, models: true do +describe Issue::Metrics do let(:project) { create(:empty_project) } subject { create(:issue, project: project) } diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index bf97c6ececd..d72790eefe5 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Issue, models: true do +describe Issue do describe "Associations" do it { is_expected.to belong_to(:milestone) } it { is_expected.to have_many(:assignees) } diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb index f27920f9feb..d41717d0223 100644 --- a/spec/models/key_spec.rb +++ b/spec/models/key_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Key, models: true do +describe Key do include EmailHelpers describe "Associations" do diff --git a/spec/models/label_link_spec.rb b/spec/models/label_link_spec.rb index c18ed8574b1..e2b49bc2de7 100644 --- a/spec/models/label_link_spec.rb +++ b/spec/models/label_link_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe LabelLink, models: true do +describe LabelLink do it { expect(build(:label_link)).to be_valid } it { is_expected.to belong_to(:label) } diff --git a/spec/models/label_priority_spec.rb b/spec/models/label_priority_spec.rb index d18c2f7949a..9dcb0f06b20 100644 --- a/spec/models/label_priority_spec.rb +++ b/spec/models/label_priority_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe LabelPriority, models: true do +describe LabelPriority do describe 'relationships' do it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:label) } diff --git a/spec/models/label_spec.rb b/spec/models/label_spec.rb index 31190fe5685..8914845ea82 100644 --- a/spec/models/label_spec.rb +++ b/spec/models/label_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Label, models: true do +describe Label do describe 'modules' do it { is_expected.to include_module(Referable) } it { is_expected.to include_module(Subscribable) } diff --git a/spec/models/legacy_diff_discussion_spec.rb b/spec/models/legacy_diff_discussion_spec.rb index 6eb4a2aaf39..dae97b69c84 100644 --- a/spec/models/legacy_diff_discussion_spec.rb +++ b/spec/models/legacy_diff_discussion_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe LegacyDiffDiscussion, models: true do +describe LegacyDiffDiscussion do subject { create(:legacy_diff_note_on_merge_request).to_discussion } describe '#reply_attributes' do diff --git a/spec/models/lfs_objects_project_spec.rb b/spec/models/lfs_objects_project_spec.rb index 7bc278e350f..8c74f1f9e86 100644 --- a/spec/models/lfs_objects_project_spec.rb +++ b/spec/models/lfs_objects_project_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe LfsObjectsProject, models: true do +describe LfsObjectsProject do subject { create(:lfs_objects_project, project: project) } let(:project) { create(:empty_project) } diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb index 494a88368ba..22e62ee0823 100644 --- a/spec/models/member_spec.rb +++ b/spec/models/member_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Member, models: true do +describe Member do describe "Associations" do it { is_expected.to belong_to(:user) } end diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb index 37014268a70..5a3b5b1f517 100644 --- a/spec/models/members/group_member_spec.rb +++ b/spec/models/members/group_member_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GroupMember, models: true do +describe GroupMember do describe '.access_level_roles' do it 'returns Gitlab::Access.options_with_owner' do expect(described_class.access_level_roles).to eq(Gitlab::Access.options_with_owner) diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb index cf9c701e8c5..93df1b2fb6c 100644 --- a/spec/models/members/project_member_spec.rb +++ b/spec/models/members/project_member_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ProjectMember, models: true do +describe ProjectMember do describe 'associations' do it { is_expected.to belong_to(:project).with_foreign_key(:source_id) } end diff --git a/spec/models/merge_request/metrics_spec.rb b/spec/models/merge_request/metrics_spec.rb index 9afed311e27..9353d5c3c8a 100644 --- a/spec/models/merge_request/metrics_spec.rb +++ b/spec/models/merge_request/metrics_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MergeRequest::Metrics, models: true do +describe MergeRequest::Metrics do subject { create(:merge_request) } describe "when recording the default set of metrics on merge request save" do diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index 0e77752bccc..d09f880423b 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MergeRequestDiff, models: true do +describe MergeRequestDiff do describe 'create new record' do subject { create(:merge_request).merge_request_diff } diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 6f6a8ac91b8..b2dd02553c1 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MergeRequest, models: true do +describe MergeRequest do include RepoHelpers subject { create(:merge_request) } diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index 2649d04bee3..0dd8a86106b 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Milestone, models: true do +describe Milestone do describe "Validation" do before do allow(subject).to receive(:set_iid).and_return(false) diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index a4090b37f65..827356b660e 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Namespace, models: true do +describe Namespace do let!(:namespace) { create(:namespace) } describe 'associations' do @@ -151,7 +151,7 @@ describe Namespace, models: true do end end - describe '#move_dir', repository: true do + describe '#move_dir' do before do @namespace = create :namespace @project = create(:project_empty_repo, namespace: @namespace) @@ -230,7 +230,7 @@ describe Namespace, models: true do end end - describe '#rm_dir', 'callback', repository: true do + describe '#rm_dir', 'callback' do let!(:project) { create(:project_empty_repo, namespace: namespace) } let(:repository_storage_path) { Gitlab.config.repositories.storages.default['path'] } let(:path_in_dir) { File.join(repository_storage_path, namespace.full_path) } diff --git a/spec/models/network/graph_spec.rb b/spec/models/network/graph_spec.rb index 0fe8a591a45..c364dd6643b 100644 --- a/spec/models/network/graph_spec.rb +++ b/spec/models/network/graph_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Network::Graph, models: true do +describe Network::Graph do let(:project) { create(:project, :repository) } let!(:note_on_commit) { create(:note_on_commit, project: project) } diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index e2b80cb6e61..d20816bc31f 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Note, models: true do +describe Note do include RepoHelpers describe 'associations' do diff --git a/spec/models/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb index d4a777a9bd9..7d835511dfb 100644 --- a/spec/models/pages_domain_spec.rb +++ b/spec/models/pages_domain_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe PagesDomain, models: true do +describe PagesDomain do describe 'associations' do it { is_expected.to belong_to(:project) } end diff --git a/spec/models/personal_access_token_spec.rb b/spec/models/personal_access_token_spec.rb index fa781195608..b2f2a3ce914 100644 --- a/spec/models/personal_access_token_spec.rb +++ b/spec/models/personal_access_token_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe PersonalAccessToken, models: true do +describe PersonalAccessToken do describe '.build' do let(:personal_access_token) { build(:personal_access_token) } let(:invalid_personal_access_token) { build(:personal_access_token, :invalid) } diff --git a/spec/models/project_label_spec.rb b/spec/models/project_label_spec.rb index 9cdbfa44e5b..add7e85f388 100644 --- a/spec/models/project_label_spec.rb +++ b/spec/models/project_label_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ProjectLabel, models: true do +describe ProjectLabel do describe 'relationships' do it { is_expected.to belong_to(:project) } end diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb index 95c35162d96..3e568ec3dad 100644 --- a/spec/models/project_services/asana_service_spec.rb +++ b/spec/models/project_services/asana_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe AsanaService, models: true do +describe AsanaService do describe 'Associations' do it { is_expected.to belong_to :project } it { is_expected.to have_one :service_hook } diff --git a/spec/models/project_services/assembla_service_spec.rb b/spec/models/project_services/assembla_service_spec.rb index 96f00af898e..a06bd2de0eb 100644 --- a/spec/models/project_services/assembla_service_spec.rb +++ b/spec/models/project_services/assembla_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe AssemblaService, models: true do +describe AssemblaService do describe "Associations" do it { is_expected.to belong_to :project } it { is_expected.to have_one :service_hook } diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb index 99190d763f2..82f02126de1 100644 --- a/spec/models/project_services/bamboo_service_spec.rb +++ b/spec/models/project_services/bamboo_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BambooService, :use_clean_rails_memory_store_caching, models: true do +describe BambooService, :use_clean_rails_memory_store_caching do include ReactiveCachingHelpers let(:bamboo_url) { 'http://gitlab.com/bamboo' } diff --git a/spec/models/project_services/bugzilla_service_spec.rb b/spec/models/project_services/bugzilla_service_spec.rb index 5f17bbde390..43f7bcb1a19 100644 --- a/spec/models/project_services/bugzilla_service_spec.rb +++ b/spec/models/project_services/bugzilla_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BugzillaService, models: true do +describe BugzillaService do describe 'Associations' do it { is_expected.to belong_to :project } it { is_expected.to have_one :service_hook } diff --git a/spec/models/project_services/buildkite_service_spec.rb b/spec/models/project_services/buildkite_service_spec.rb index b4ee6691e67..3f7eb33e08a 100644 --- a/spec/models/project_services/buildkite_service_spec.rb +++ b/spec/models/project_services/buildkite_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BuildkiteService, :use_clean_rails_memory_store_caching, models: true do +describe BuildkiteService, :use_clean_rails_memory_store_caching do include ReactiveCachingHelpers let(:project) { create(:empty_project) } diff --git a/spec/models/project_services/campfire_service_spec.rb b/spec/models/project_services/campfire_service_spec.rb index 56ff3596190..176850b4c72 100644 --- a/spec/models/project_services/campfire_service_spec.rb +++ b/spec/models/project_services/campfire_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe CampfireService, models: true do +describe CampfireService do describe 'Associations' do it { is_expected.to belong_to :project } it { is_expected.to have_one :service_hook } diff --git a/spec/models/project_services/chat_message/issue_message_spec.rb b/spec/models/project_services/chat_message/issue_message_spec.rb index c159ab00ab1..4bb1db684e6 100644 --- a/spec/models/project_services/chat_message/issue_message_spec.rb +++ b/spec/models/project_services/chat_message/issue_message_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ChatMessage::IssueMessage, models: true do +describe ChatMessage::IssueMessage do subject { described_class.new(args) } let(:args) do diff --git a/spec/models/project_services/chat_message/merge_message_spec.rb b/spec/models/project_services/chat_message/merge_message_spec.rb index 61f17031172..b600a36f578 100644 --- a/spec/models/project_services/chat_message/merge_message_spec.rb +++ b/spec/models/project_services/chat_message/merge_message_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ChatMessage::MergeMessage, models: true do +describe ChatMessage::MergeMessage do subject { described_class.new(args) } let(:args) do diff --git a/spec/models/project_services/chat_message/note_message_spec.rb b/spec/models/project_services/chat_message/note_message_spec.rb index 7996536218a..a09c2f9935c 100644 --- a/spec/models/project_services/chat_message/note_message_spec.rb +++ b/spec/models/project_services/chat_message/note_message_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ChatMessage::NoteMessage, models: true do +describe ChatMessage::NoteMessage do subject { described_class.new(args) } let(:color) { '#345' } diff --git a/spec/models/project_services/chat_message/push_message_spec.rb b/spec/models/project_services/chat_message/push_message_spec.rb index c794f659c41..19c2862264f 100644 --- a/spec/models/project_services/chat_message/push_message_spec.rb +++ b/spec/models/project_services/chat_message/push_message_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ChatMessage::PushMessage, models: true do +describe ChatMessage::PushMessage do subject { described_class.new(args) } let(:args) do diff --git a/spec/models/project_services/chat_message/wiki_page_message_spec.rb b/spec/models/project_services/chat_message/wiki_page_message_spec.rb index 17355c1e6f1..c4adee4f489 100644 --- a/spec/models/project_services/chat_message/wiki_page_message_spec.rb +++ b/spec/models/project_services/chat_message/wiki_page_message_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ChatMessage::WikiPageMessage, models: true do +describe ChatMessage::WikiPageMessage do subject { described_class.new(args) } let(:args) do diff --git a/spec/models/project_services/chat_notification_service_spec.rb b/spec/models/project_services/chat_notification_service_spec.rb index 8fbe42248ae..413ceed73bf 100644 --- a/spec/models/project_services/chat_notification_service_spec.rb +++ b/spec/models/project_services/chat_notification_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ChatNotificationService, models: true do +describe ChatNotificationService do describe 'Associations' do before do allow(subject).to receive(:activated?).and_return(true) diff --git a/spec/models/project_services/custom_issue_tracker_service_spec.rb b/spec/models/project_services/custom_issue_tracker_service_spec.rb index 9e574762232..7e1b1a4f2af 100644 --- a/spec/models/project_services/custom_issue_tracker_service_spec.rb +++ b/spec/models/project_services/custom_issue_tracker_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe CustomIssueTrackerService, models: true do +describe CustomIssueTrackerService do describe 'Associations' do it { is_expected.to belong_to :project } it { is_expected.to have_one :service_hook } diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb index c9ac256ff38..5b0f24ce306 100644 --- a/spec/models/project_services/drone_ci_service_spec.rb +++ b/spec/models/project_services/drone_ci_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe DroneCiService, :use_clean_rails_memory_store_caching, models: true do +describe DroneCiService, :use_clean_rails_memory_store_caching do include ReactiveCachingHelpers describe 'associations' do diff --git a/spec/models/project_services/external_wiki_service_spec.rb b/spec/models/project_services/external_wiki_service_spec.rb index ef10df9e092..22cd9d5e31e 100644 --- a/spec/models/project_services/external_wiki_service_spec.rb +++ b/spec/models/project_services/external_wiki_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ExternalWikiService, models: true do +describe ExternalWikiService do include ExternalWikiHelper describe "Associations" do it { is_expected.to belong_to :project } diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb index 56ace04dd58..e439abb45a4 100644 --- a/spec/models/project_services/flowdock_service_spec.rb +++ b/spec/models/project_services/flowdock_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe FlowdockService, models: true do +describe FlowdockService do describe "Associations" do it { is_expected.to belong_to :project } it { is_expected.to have_one :service_hook } diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb index 65c9e714bd1..d89e7ee8a2a 100644 --- a/spec/models/project_services/gemnasium_service_spec.rb +++ b/spec/models/project_services/gemnasium_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GemnasiumService, models: true do +describe GemnasiumService do describe "Associations" do it { is_expected.to belong_to :project } it { is_expected.to have_one :service_hook } diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb index d45e0a441d4..ff0f73eff4c 100644 --- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb +++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GitlabIssueTrackerService, models: true do +describe GitlabIssueTrackerService do describe "Associations" do it { is_expected.to belong_to :project } it { is_expected.to have_one :service_hook } diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb index c7c8e9651ab..f08e6c863a4 100644 --- a/spec/models/project_services/hipchat_service_spec.rb +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe HipchatService, models: true do +describe HipchatService do describe "Associations" do it { is_expected.to belong_to :project } it { is_expected.to have_one :service_hook } diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb index a5c4938b54e..ce2b26436b3 100644 --- a/spec/models/project_services/irker_service_spec.rb +++ b/spec/models/project_services/irker_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' require 'socket' require 'json' -describe IrkerService, models: true do +describe IrkerService do describe 'Associations' do it { is_expected.to belong_to :project } it { is_expected.to have_one :service_hook } diff --git a/spec/models/project_services/issue_tracker_service_spec.rb b/spec/models/project_services/issue_tracker_service_spec.rb index 869b25b933b..e6a1752576b 100644 --- a/spec/models/project_services/issue_tracker_service_spec.rb +++ b/spec/models/project_services/issue_tracker_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe IssueTrackerService, models: true do +describe IssueTrackerService do describe 'Validations' do let(:project) { create :project } diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index d7d09808a98..62e1d51104e 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe JiraService, models: true do +describe JiraService do include Gitlab::Routing describe "Associations" do diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index b66bb5321ab..55b96a0c12e 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe KubernetesService, :use_clean_rails_memory_store_caching, models: true do +describe KubernetesService, :use_clean_rails_memory_store_caching do include KubernetesHelpers include ReactiveCachingHelpers diff --git a/spec/models/project_services/mattermost_service_spec.rb b/spec/models/project_services/mattermost_service_spec.rb index 490d6aedffc..10c62ca55a7 100644 --- a/spec/models/project_services/mattermost_service_spec.rb +++ b/spec/models/project_services/mattermost_service_spec.rb @@ -1,5 +1,5 @@ require 'spec_helper' -describe MattermostService, models: true do +describe MattermostService do it_behaves_like "slack or mattermost notifications" end diff --git a/spec/models/project_services/microsoft_teams_service_spec.rb b/spec/models/project_services/microsoft_teams_service_spec.rb index fb95c4cda35..f89be20ad78 100644 --- a/spec/models/project_services/microsoft_teams_service_spec.rb +++ b/spec/models/project_services/microsoft_teams_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MicrosoftTeamsService, models: true do +describe MicrosoftTeamsService do let(:chat_service) { described_class.new } let(:webhook_url) { 'https://example.gitlab.com/' } diff --git a/spec/models/project_services/pivotaltracker_service_spec.rb b/spec/models/project_services/pivotaltracker_service_spec.rb index f4c1a9c94b6..002476c1a17 100644 --- a/spec/models/project_services/pivotaltracker_service_spec.rb +++ b/spec/models/project_services/pivotaltracker_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe PivotaltrackerService, models: true do +describe PivotaltrackerService do describe 'Associations' do it { is_expected.to belong_to :project } it { is_expected.to have_one :service_hook } diff --git a/spec/models/project_services/prometheus_service_spec.rb b/spec/models/project_services/prometheus_service_spec.rb index 3fb134ec3b7..bf39e8d7a39 100644 --- a/spec/models/project_services/prometheus_service_spec.rb +++ b/spec/models/project_services/prometheus_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe PrometheusService, :use_clean_rails_memory_store_caching, models: true do +describe PrometheusService, :use_clean_rails_memory_store_caching do include PrometheusHelpers include ReactiveCachingHelpers diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb index 9171d9604ee..e77c4ddcc78 100644 --- a/spec/models/project_services/pushover_service_spec.rb +++ b/spec/models/project_services/pushover_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe PushoverService, models: true do +describe PushoverService do describe 'Associations' do it { is_expected.to belong_to :project } it { is_expected.to have_one :service_hook } diff --git a/spec/models/project_services/redmine_service_spec.rb b/spec/models/project_services/redmine_service_spec.rb index 441b3f896ca..2ac14eab5e1 100644 --- a/spec/models/project_services/redmine_service_spec.rb +++ b/spec/models/project_services/redmine_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe RedmineService, models: true do +describe RedmineService do describe 'Associations' do it { is_expected.to belong_to :project } it { is_expected.to have_one :service_hook } diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb index 9a3ecc66d83..13cf4d1915e 100644 --- a/spec/models/project_services/slack_service_spec.rb +++ b/spec/models/project_services/slack_service_spec.rb @@ -1,5 +1,5 @@ require 'spec_helper' -describe SlackService, models: true do +describe SlackService do it_behaves_like "slack or mattermost notifications" end diff --git a/spec/models/project_services/teamcity_service_spec.rb b/spec/models/project_services/teamcity_service_spec.rb index 3f3a74d0f96..47fd0c79e0b 100644 --- a/spec/models/project_services/teamcity_service_spec.rb +++ b/spec/models/project_services/teamcity_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe TeamcityService, :use_clean_rails_memory_store_caching, models: true do +describe TeamcityService, :use_clean_rails_memory_store_caching do include ReactiveCachingHelpers let(:teamcity_url) { 'http://gitlab.com/teamcity' } diff --git a/spec/models/project_snippet_spec.rb b/spec/models/project_snippet_spec.rb index 5fe4885eeb4..1b439bcfad1 100644 --- a/spec/models/project_snippet_spec.rb +++ b/spec/models/project_snippet_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ProjectSnippet, models: true do +describe ProjectSnippet do describe "Associations" do it { is_expected.to belong_to(:project) } end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 8d916b79b13..2df31a54628 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Project, models: true do +describe Project do describe 'associations' do it { is_expected.to belong_to(:group) } it { is_expected.to belong_to(:namespace) } diff --git a/spec/models/project_statistics_spec.rb b/spec/models/project_statistics_spec.rb index c5ffbda9821..be1b37730b1 100644 --- a/spec/models/project_statistics_spec.rb +++ b/spec/models/project_statistics_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe ProjectStatistics, models: true do +describe ProjectStatistics do let(:project) { create :empty_project } let(:statistics) { project.statistics } diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 49f2f8c0ad1..68228a038a8 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ProjectTeam, models: true do +describe ProjectTeam do let(:master) { create(:user) } let(:reporter) { create(:user) } let(:guest) { create(:user) } diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index 79ab50c1234..fc1cdb3b1e6 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe ProjectWiki, models: true do +describe ProjectWiki do let(:project) { create(:empty_project) } let(:repository) { project.repository } let(:user) { project.owner } diff --git a/spec/models/protectable_dropdown_spec.rb b/spec/models/protectable_dropdown_spec.rb index 4c9bade592b..5c5dcd9f5c9 100644 --- a/spec/models/protectable_dropdown_spec.rb +++ b/spec/models/protectable_dropdown_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ProtectableDropdown, models: true do +describe ProtectableDropdown do let(:project) { create(:project, :repository) } let(:subject) { described_class.new(project, :branches) } diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb index ca347cf92c9..6e8b07b44fb 100644 --- a/spec/models/protected_branch_spec.rb +++ b/spec/models/protected_branch_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ProtectedBranch, models: true do +describe ProtectedBranch do subject { build_stubbed(:protected_branch) } describe 'Associations' do diff --git a/spec/models/protected_tag_spec.rb b/spec/models/protected_tag_spec.rb index 51353852a93..e5a0f6ec23f 100644 --- a/spec/models/protected_tag_spec.rb +++ b/spec/models/protected_tag_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ProtectedTag, models: true do +describe ProtectedTag do describe 'Associations' do it { is_expected.to belong_to(:project) } end diff --git a/spec/models/redirect_route_spec.rb b/spec/models/redirect_route_spec.rb index a97af28cb8e..37948ea3f86 100644 --- a/spec/models/redirect_route_spec.rb +++ b/spec/models/redirect_route_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe RedirectRoute, models: true do +describe RedirectRoute do let(:group) { create(:group) } let!(:redirect_route) { group.redirect_routes.create(path: 'gitlabb') } diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index fcda4248446..07ed66e127a 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Repository, models: true do +describe Repository do include RepoHelpers TestBlob = Struct.new(:path) diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb index 12f7611fb28..32cd5d1d944 100644 --- a/spec/models/route_spec.rb +++ b/spec/models/route_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Route, models: true do +describe Route do let(:group) { create(:group, path: 'git_lab', name: 'git_lab') } let(:route) { group.route } diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index 134882648b9..dba9fc4ac9b 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Service, models: true do +describe Service do describe "Associations" do it { is_expected.to belong_to :project } it { is_expected.to have_one :service_hook } diff --git a/spec/models/snippet_blob_spec.rb b/spec/models/snippet_blob_spec.rb index 120b390586b..7c71c458fcc 100644 --- a/spec/models/snippet_blob_spec.rb +++ b/spec/models/snippet_blob_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe SnippetBlob, models: true do +describe SnippetBlob do let(:snippet) { create(:snippet) } subject { described_class.new(snippet) } diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb index 1e5c96fe593..904bf2c6144 100644 --- a/spec/models/snippet_spec.rb +++ b/spec/models/snippet_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Snippet, models: true do +describe Snippet do describe 'modules' do subject { described_class } diff --git a/spec/models/spam_log_spec.rb b/spec/models/spam_log_spec.rb index 838fba6c92d..0d6b4384ada 100644 --- a/spec/models/spam_log_spec.rb +++ b/spec/models/spam_log_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe SpamLog, models: true do +describe SpamLog do let(:admin) { create(:admin) } describe 'associations' do diff --git a/spec/models/subscription_spec.rb b/spec/models/subscription_spec.rb index 9ab112bb2ee..9e4c2620d82 100644 --- a/spec/models/subscription_spec.rb +++ b/spec/models/subscription_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Subscription, models: true do +describe Subscription do describe 'relationships' do it { is_expected.to belong_to(:project) } it { is_expected.to belong_to(:subscribable) } diff --git a/spec/models/system_note_metadata_spec.rb b/spec/models/system_note_metadata_spec.rb index d238e28209a..1e3f587e460 100644 --- a/spec/models/system_note_metadata_spec.rb +++ b/spec/models/system_note_metadata_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe SystemNoteMetadata, models: true do +describe SystemNoteMetadata do describe 'associations' do it { is_expected.to belong_to(:note) } end diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb index 3f80e1ac534..3e8f3848eca 100644 --- a/spec/models/todo_spec.rb +++ b/spec/models/todo_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Todo, models: true do +describe Todo do let(:issue) { create(:issue) } describe 'relationships' do diff --git a/spec/models/tree_spec.rb b/spec/models/tree_spec.rb index a87983b7492..6bdb62a0864 100644 --- a/spec/models/tree_spec.rb +++ b/spec/models/tree_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Tree, models: true do +describe Tree do let(:repository) { create(:project, :repository).repository } let(:sha) { repository.root_ref } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 20bdb7e37da..105d41957c3 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe User, models: true do +describe User do include Gitlab::CurrentSettings describe 'modules' do diff --git a/spec/models/wiki_directory_spec.rb b/spec/models/wiki_directory_spec.rb index 1caaa557085..c3c62c42b35 100644 --- a/spec/models/wiki_directory_spec.rb +++ b/spec/models/wiki_directory_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -RSpec.describe WikiDirectory, models: true do +RSpec.describe WikiDirectory do describe 'validations' do subject { build(:wiki_directory) } diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 4a73552b8a6..77506a78459 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe WikiPage, models: true do +describe WikiPage do let(:project) { create(:empty_project) } let(:user) { project.owner } let(:wiki) { ProjectWiki.new(project, user) } diff --git a/spec/policies/base_policy_spec.rb b/spec/policies/base_policy_spec.rb index e1963091a72..c03d95b34db 100644 --- a/spec/policies/base_policy_spec.rb +++ b/spec/policies/base_policy_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe BasePolicy, models: true do +describe BasePolicy do describe '.class_for' do it 'detects policy class based on the subject ancestors' do expect(DeclarativePolicy.class_for(GenericCommitStatus.new)).to eq(CommitStatusPolicy) diff --git a/spec/policies/deploy_key_policy_spec.rb b/spec/policies/deploy_key_policy_spec.rb index f15f4a11f02..ca7b7fe7ef7 100644 --- a/spec/policies/deploy_key_policy_spec.rb +++ b/spec/policies/deploy_key_policy_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe DeployKeyPolicy, models: true do +describe DeployKeyPolicy do subject { described_class.new(current_user, deploy_key) } describe 'updating a deploy_key' do diff --git a/spec/policies/global_policy_spec.rb b/spec/policies/global_policy_spec.rb index c3e2b603c4b..2a590e12232 100644 --- a/spec/policies/global_policy_spec.rb +++ b/spec/policies/global_policy_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GlobalPolicy, models: true do +describe GlobalPolicy do let(:current_user) { create(:user) } let(:user) { create(:user) } diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb index 06db0ea56e3..b17a93e3fbe 100644 --- a/spec/policies/group_policy_spec.rb +++ b/spec/policies/group_policy_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GroupPolicy, models: true do +describe GroupPolicy do let(:guest) { create(:user) } let(:reporter) { create(:user) } let(:developer) { create(:user) } diff --git a/spec/policies/issue_policy_spec.rb b/spec/policies/issue_policy_spec.rb index c978cbd6185..279b96fb2af 100644 --- a/spec/policies/issue_policy_spec.rb +++ b/spec/policies/issue_policy_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe IssuePolicy, models: true do +describe IssuePolicy do let(:guest) { create(:user) } let(:author) { create(:user) } let(:assignee) { create(:user) } diff --git a/spec/policies/personal_snippet_policy_spec.rb b/spec/policies/personal_snippet_policy_spec.rb index 4d6350fc653..b70c8646a3d 100644 --- a/spec/policies/personal_snippet_policy_spec.rb +++ b/spec/policies/personal_snippet_policy_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe PersonalSnippetPolicy, models: true do +describe PersonalSnippetPolicy do let(:regular_user) { create(:user) } let(:external_user) { create(:user, :external) } let(:admin_user) { create(:user, :admin) } diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index f244975e597..1f51ced1beb 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ProjectPolicy, models: true do +describe ProjectPolicy do let(:guest) { create(:user) } let(:reporter) { create(:user) } let(:dev) { create(:user) } diff --git a/spec/policies/project_snippet_policy_spec.rb b/spec/policies/project_snippet_policy_spec.rb index 2799f03fb9b..bae35ee31c6 100644 --- a/spec/policies/project_snippet_policy_spec.rb +++ b/spec/policies/project_snippet_policy_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ProjectSnippetPolicy, models: true do +describe ProjectSnippetPolicy do let(:regular_user) { create(:user) } let(:external_user) { create(:user, :external) } let(:project) { create(:empty_project, :public) } diff --git a/spec/policies/user_policy_spec.rb b/spec/policies/user_policy_spec.rb index 0251d5dcf1c..67ab239e4c8 100644 --- a/spec/policies/user_policy_spec.rb +++ b/spec/policies/user_policy_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe UserPolicy, models: true do +describe UserPolicy do let(:current_user) { create(:user) } let(:user) { create(:user) } diff --git a/spec/requests/api/events_spec.rb b/spec/requests/api/events_spec.rb index a19870a95e8..1754ba66a96 100644 --- a/spec/requests/api/events_spec.rb +++ b/spec/requests/api/events_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe API::Events, api: true do +describe API::Events do include ApiHelpers let(:user) { create(:user) } let(:non_member) { create(:user) } diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index cab3089c6b1..ce9b9ac1eb3 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -6,7 +6,7 @@ describe API::Internal do let(:project) { create(:project, :repository) } let(:secret_token) { Gitlab::Shell.secret_token } - describe "GET /internal/check", no_db: true do + describe "GET /internal/check" do it do get api("/internal/check"), secret_token: secret_token diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb index 8d647eb1c7e..f56baf9663d 100644 --- a/spec/requests/api/jobs_spec.rb +++ b/spec/requests/api/jobs_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe API::Jobs, :api do +describe API::Jobs do let!(:project) do create(:project, :repository, public_builds: false) end diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index d043ab2a974..d4a3e8b13e1 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe 'Git HTTP requests', lib: true do +describe 'Git HTTP requests' do include GitHttpHelpers include WorkhorseHelpers include UserActivitiesHelpers diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb index e78d2cfdb33..e5d9d3df5a8 100644 --- a/spec/requests/projects/cycle_analytics_events_spec.rb +++ b/spec/requests/projects/cycle_analytics_events_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'cycle analytics events', api: true do +describe 'cycle analytics events' do let(:user) { create(:user) } let(:project) { create(:project, :repository, public_builds: false) } let(:issue) { create(:issue, project: project, created_at: 2.days.ago) } diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 65314b688a4..c02409b2e0b 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -610,7 +610,7 @@ describe 'project routing' do end end - describe Projects::Registry::TagsController, :routing do + describe Projects::Registry::TagsController, 'routing' do describe '#destroy' do it 'correctly routes to a destroy action' do expect(delete('/gitlab/gitlabhq/registry/repository/1/tags/rc1')) diff --git a/spec/services/access_token_validation_service_spec.rb b/spec/services/access_token_validation_service_spec.rb index 11225fad18a..38a3f522504 100644 --- a/spec/services/access_token_validation_service_spec.rb +++ b/spec/services/access_token_validation_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe AccessTokenValidationService, services: true do +describe AccessTokenValidationService do describe ".include_any_scope?" do let(:request) { double("request") } diff --git a/spec/services/after_branch_delete_service_spec.rb b/spec/services/after_branch_delete_service_spec.rb index 77ca17bc82c..bc9747d1413 100644 --- a/spec/services/after_branch_delete_service_spec.rb +++ b/spec/services/after_branch_delete_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe AfterBranchDeleteService, services: true do +describe AfterBranchDeleteService do let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:service) { described_class.new(project, user) } diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb index 60cb7a9440f..66a8a93b168 100644 --- a/spec/services/auth/container_registry_authentication_service_spec.rb +++ b/spec/services/auth/container_registry_authentication_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Auth::ContainerRegistryAuthenticationService, services: true do +describe Auth::ContainerRegistryAuthenticationService do let(:current_project) { nil } let(:current_user) { nil } let(:current_params) { {} } diff --git a/spec/services/boards/create_service_spec.rb b/spec/services/boards/create_service_spec.rb index 89615df1692..6e3227303fe 100644 --- a/spec/services/boards/create_service_spec.rb +++ b/spec/services/boards/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Boards::CreateService, services: true do +describe Boards::CreateService do describe '#execute' do let(:project) { create(:empty_project) } diff --git a/spec/services/boards/issues/create_service_spec.rb b/spec/services/boards/issues/create_service_spec.rb index 360ee398f77..23ad66e454b 100644 --- a/spec/services/boards/issues/create_service_spec.rb +++ b/spec/services/boards/issues/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Boards::Issues::CreateService, services: true do +describe Boards::Issues::CreateService do describe '#execute' do let(:project) { create(:empty_project) } let(:board) { create(:board, project: project) } diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb index a66cc2cd6e9..2c293088097 100644 --- a/spec/services/boards/issues/list_service_spec.rb +++ b/spec/services/boards/issues/list_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Boards::Issues::ListService, services: true do +describe Boards::Issues::ListService do describe '#execute' do let(:user) { create(:user) } let(:project) { create(:empty_project) } diff --git a/spec/services/boards/issues/move_service_spec.rb b/spec/services/boards/issues/move_service_spec.rb index 4ff7ac6bb2f..7dd1a601700 100644 --- a/spec/services/boards/issues/move_service_spec.rb +++ b/spec/services/boards/issues/move_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Boards::Issues::MoveService, services: true do +describe Boards::Issues::MoveService do describe '#execute' do let(:user) { create(:user) } let(:project) { create(:empty_project) } diff --git a/spec/services/boards/list_service_spec.rb b/spec/services/boards/list_service_spec.rb index dff33e4bcbb..a95b12eeaa3 100644 --- a/spec/services/boards/list_service_spec.rb +++ b/spec/services/boards/list_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Boards::ListService, services: true do +describe Boards::ListService do describe '#execute' do let(:project) { create(:empty_project) } diff --git a/spec/services/boards/lists/create_service_spec.rb b/spec/services/boards/lists/create_service_spec.rb index ebac38e68f1..86d3227a78d 100644 --- a/spec/services/boards/lists/create_service_spec.rb +++ b/spec/services/boards/lists/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Boards::Lists::CreateService, services: true do +describe Boards::Lists::CreateService do describe '#execute' do let(:project) { create(:empty_project) } let(:board) { create(:board, project: project) } diff --git a/spec/services/boards/lists/destroy_service_spec.rb b/spec/services/boards/lists/destroy_service_spec.rb index af2d7c784bb..ad6ae83286d 100644 --- a/spec/services/boards/lists/destroy_service_spec.rb +++ b/spec/services/boards/lists/destroy_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Boards::Lists::DestroyService, services: true do +describe Boards::Lists::DestroyService do describe '#execute' do let(:project) { create(:empty_project) } let(:board) { create(:board, project: project) } diff --git a/spec/services/boards/lists/generate_service_spec.rb b/spec/services/boards/lists/generate_service_spec.rb index ed0337662af..7dec9f7a4a5 100644 --- a/spec/services/boards/lists/generate_service_spec.rb +++ b/spec/services/boards/lists/generate_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Boards::Lists::GenerateService, services: true do +describe Boards::Lists::GenerateService do describe '#execute' do let(:project) { create(:empty_project) } let(:board) { create(:board, project: project) } diff --git a/spec/services/boards/lists/list_service_spec.rb b/spec/services/boards/lists/list_service_spec.rb index 68140759600..c93788d4516 100644 --- a/spec/services/boards/lists/list_service_spec.rb +++ b/spec/services/boards/lists/list_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Boards::Lists::ListService, services: true do +describe Boards::Lists::ListService do let(:project) { create(:empty_project) } let(:board) { create(:board, project: project) } let(:label) { create(:label, project: project) } diff --git a/spec/services/boards/lists/move_service_spec.rb b/spec/services/boards/lists/move_service_spec.rb index 4b3bdd133f2..43e125a21df 100644 --- a/spec/services/boards/lists/move_service_spec.rb +++ b/spec/services/boards/lists/move_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Boards::Lists::MoveService, services: true do +describe Boards::Lists::MoveService do describe '#execute' do let(:project) { create(:empty_project) } let(:board) { create(:board, project: project) } diff --git a/spec/services/chat_names/authorize_user_service_spec.rb b/spec/services/chat_names/authorize_user_service_spec.rb index d50bfb0492c..d88b2504133 100644 --- a/spec/services/chat_names/authorize_user_service_spec.rb +++ b/spec/services/chat_names/authorize_user_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ChatNames::AuthorizeUserService, services: true do +describe ChatNames::AuthorizeUserService do describe '#execute' do let(:service) { create(:service) } diff --git a/spec/services/chat_names/find_user_service_spec.rb b/spec/services/chat_names/find_user_service_spec.rb index 0dc96521fa8..79aaac3aeb6 100644 --- a/spec/services/chat_names/find_user_service_spec.rb +++ b/spec/services/chat_names/find_user_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ChatNames::FindUserService, services: true do +describe ChatNames::FindUserService do describe '#execute' do let(:service) { create(:service) } diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 146d25daba3..4ec495f612e 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::CreatePipelineService, :services do +describe Ci::CreatePipelineService do let(:project) { create(:project, :repository) } let(:user) { create(:admin) } let(:ref_name) { 'refs/heads/master' } diff --git a/spec/services/ci/create_trigger_request_service_spec.rb b/spec/services/ci/create_trigger_request_service_spec.rb index 37ca9804f56..8295813a1ca 100644 --- a/spec/services/ci/create_trigger_request_service_spec.rb +++ b/spec/services/ci/create_trigger_request_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::CreateTriggerRequestService, services: true do +describe Ci::CreateTriggerRequestService do let(:service) { described_class } let(:project) { create(:project, :repository) } let(:trigger) { create(:ci_trigger, project: project, owner: owner) } diff --git a/spec/services/ci/play_build_service_spec.rb b/spec/services/ci/play_build_service_spec.rb index ea211de1f82..1ced26ff98d 100644 --- a/spec/services/ci/play_build_service_spec.rb +++ b/spec/services/ci/play_build_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::PlayBuildService, '#execute', :services do +describe Ci::PlayBuildService, '#execute' do let(:user) { create(:user) } let(:project) { create(:empty_project) } let(:pipeline) { create(:ci_pipeline, project: project) } diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb index 6346f311696..3a702742681 100644 --- a/spec/services/ci/process_pipeline_service_spec.rb +++ b/spec/services/ci/process_pipeline_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::ProcessPipelineService, '#execute', :services do +describe Ci::ProcessPipelineService, '#execute' do let(:user) { create(:user) } let(:project) { create(:empty_project) } diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb index 62ba0b01339..23c0f715c3e 100644 --- a/spec/services/ci/register_job_service_spec.rb +++ b/spec/services/ci/register_job_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' module Ci - describe RegisterJobService, services: true do + describe RegisterJobService do let!(:project) { FactoryGirl.create :empty_project, shared_runners_enabled: false } let!(:pipeline) { FactoryGirl.create :ci_pipeline, project: project } let!(:pending_build) { FactoryGirl.create :ci_build, pipeline: pipeline } diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 2cf62b54666..fd8a57d28f0 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::RetryBuildService, :services do +describe Ci::RetryBuildService do let(:user) { create(:user) } let(:project) { create(:empty_project) } let(:pipeline) { create(:ci_pipeline, project: project) } diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb index 7798db3f3b9..90b0c5a4dce 100644 --- a/spec/services/ci/retry_pipeline_service_spec.rb +++ b/spec/services/ci/retry_pipeline_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::RetryPipelineService, '#execute', :services do +describe Ci::RetryPipelineService, '#execute' do let(:user) { create(:user) } let(:project) { create(:empty_project) } let(:pipeline) { create(:ci_pipeline, project: project) } diff --git a/spec/services/ci/stop_environments_service_spec.rb b/spec/services/ci/stop_environments_service_spec.rb index 98044ad232e..e2a9ed27e87 100644 --- a/spec/services/ci/stop_environments_service_spec.rb +++ b/spec/services/ci/stop_environments_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::StopEnvironmentsService, services: true do +describe Ci::StopEnvironmentsService do let(:project) { create(:project, :private, :repository) } let(:user) { create(:user) } diff --git a/spec/services/ci/update_build_queue_service_spec.rb b/spec/services/ci/update_build_queue_service_spec.rb index efefa8e8eca..0da0e57dbcd 100644 --- a/spec/services/ci/update_build_queue_service_spec.rb +++ b/spec/services/ci/update_build_queue_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::UpdateBuildQueueService, :services do +describe Ci::UpdateBuildQueueService do let(:project) { create(:project, :repository) } let(:build) { create(:ci_build, pipeline: pipeline) } let(:pipeline) { create(:ci_pipeline, project: project) } diff --git a/spec/services/ci/update_runner_service_spec.rb b/spec/services/ci/update_runner_service_spec.rb index e429fcfc72f..7cc04c92d27 100644 --- a/spec/services/ci/update_runner_service_spec.rb +++ b/spec/services/ci/update_runner_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::UpdateRunnerService, :services do +describe Ci::UpdateRunnerService do let(:runner) { create(:ci_runner) } describe '#update' do diff --git a/spec/services/compare_service_spec.rb b/spec/services/compare_service_spec.rb index bea7c965233..9e15eae8c13 100644 --- a/spec/services/compare_service_spec.rb +++ b/spec/services/compare_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe CompareService, services: true do +describe CompareService do let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:service) { described_class.new(project, 'feature') } diff --git a/spec/services/create_branch_service_spec.rb b/spec/services/create_branch_service_spec.rb index 3f548688c20..38096a080a7 100644 --- a/spec/services/create_branch_service_spec.rb +++ b/spec/services/create_branch_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe CreateBranchService, services: true do +describe CreateBranchService do let(:user) { create(:user) } let(:service) { described_class.new(project, user) } diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/create_deployment_service_spec.rb index 2794721e157..049b082277a 100644 --- a/spec/services/create_deployment_service_spec.rb +++ b/spec/services/create_deployment_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe CreateDeploymentService, services: true do +describe CreateDeploymentService do let(:user) { create(:user) } let(:options) { nil } diff --git a/spec/services/create_release_service_spec.rb b/spec/services/create_release_service_spec.rb index 271ccfe7968..e4d1c1a8f9d 100644 --- a/spec/services/create_release_service_spec.rb +++ b/spec/services/create_release_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe CreateReleaseService, services: true do +describe CreateReleaseService do let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:tag_name) { project.repository.tag_names.first } diff --git a/spec/services/create_snippet_service_spec.rb b/spec/services/create_snippet_service_spec.rb index d81d0fd76c9..b6ab6b8271c 100644 --- a/spec/services/create_snippet_service_spec.rb +++ b/spec/services/create_snippet_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe CreateSnippetService, services: true do +describe CreateSnippetService do before do @user = create :user @admin = create :user, admin: true diff --git a/spec/services/delete_branch_service_spec.rb b/spec/services/delete_branch_service_spec.rb index c4685c9aa31..19855c9bee2 100644 --- a/spec/services/delete_branch_service_spec.rb +++ b/spec/services/delete_branch_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe DeleteBranchService, services: true do +describe DeleteBranchService do let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:user) { create(:user) } diff --git a/spec/services/delete_merged_branches_service_spec.rb b/spec/services/delete_merged_branches_service_spec.rb index fe21ca0b3cb..954c5d3ab73 100644 --- a/spec/services/delete_merged_branches_service_spec.rb +++ b/spec/services/delete_merged_branches_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe DeleteMergedBranchesService, services: true do +describe DeleteMergedBranchesService do subject(:service) { described_class.new(project, project.owner) } let(:project) { create(:project, :repository) } diff --git a/spec/services/discussions/update_diff_position_service_spec.rb b/spec/services/discussions/update_diff_position_service_spec.rb index 177e32e13bd..c239494298b 100644 --- a/spec/services/discussions/update_diff_position_service_spec.rb +++ b/spec/services/discussions/update_diff_position_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Discussions::UpdateDiffPositionService, services: true do +describe Discussions::UpdateDiffPositionService do let(:project) { create(:project, :repository) } let(:current_user) { project.owner } let(:create_commit) { project.commit("913c66a37b4a45b9769037c55c2d238bd0942d2e") } diff --git a/spec/services/emails/create_service_spec.rb b/spec/services/emails/create_service_spec.rb index c1f477f551e..641d5538de8 100644 --- a/spec/services/emails/create_service_spec.rb +++ b/spec/services/emails/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Emails::CreateService, services: true do +describe Emails::CreateService do let(:user) { create(:user) } let(:opts) { { email: 'new@email.com' } } diff --git a/spec/services/emails/destroy_service_spec.rb b/spec/services/emails/destroy_service_spec.rb index 5e7ab4a40af..1f4294dd905 100644 --- a/spec/services/emails/destroy_service_spec.rb +++ b/spec/services/emails/destroy_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Emails::DestroyService, services: true do +describe Emails::DestroyService do let!(:user) { create(:user) } let!(:email) { create(:email, user: user) } diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb index 8d067c194cc..561b9d14a0f 100644 --- a/spec/services/event_create_service_spec.rb +++ b/spec/services/event_create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe EventCreateService, services: true do +describe EventCreateService do include UserActivitiesHelpers let(:service) { EventCreateService.new } diff --git a/spec/services/git_hooks_service_spec.rb b/spec/services/git_hooks_service_spec.rb index 213678c27f5..f1242df7e93 100644 --- a/spec/services/git_hooks_service_spec.rb +++ b/spec/services/git_hooks_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GitHooksService, services: true do +describe GitHooksService do include RepoHelpers let(:user) { create(:user) } diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index f801506f1b6..8e6e5864c9a 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GitPushService, services: true do +describe GitPushService do include RepoHelpers let(:user) { create(:user) } diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb index 1fdcb420a8b..d2baeb7b746 100644 --- a/spec/services/git_tag_push_service_spec.rb +++ b/spec/services/git_tag_push_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GitTagPushService, services: true do +describe GitTagPushService do include RepoHelpers let(:user) { create(:user) } diff --git a/spec/services/gravatar_service_spec.rb b/spec/services/gravatar_service_spec.rb index 8c4ad8c7a3e..d2cc53fe0ee 100644 --- a/spec/services/gravatar_service_spec.rb +++ b/spec/services/gravatar_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GravatarService, service: true do +describe GravatarService do describe '#execute' do let(:url) { 'http://example.com/avatar?hash=%{hash}&size=%{size}&email=%{email}&username=%{username}' } diff --git a/spec/services/groups/create_service_spec.rb b/spec/services/groups/create_service_spec.rb index fbd9026640c..b2175717a70 100644 --- a/spec/services/groups/create_service_spec.rb +++ b/spec/services/groups/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Groups::CreateService, '#execute', services: true do +describe Groups::CreateService, '#execute' do let!(:user) { create(:user) } let!(:group_params) { { path: "group_path", visibility_level: Gitlab::VisibilityLevel::PUBLIC } } diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb index d59b37bee36..b3ceb5428cd 100644 --- a/spec/services/groups/destroy_service_spec.rb +++ b/spec/services/groups/destroy_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Groups::DestroyService, services: true do +describe Groups::DestroyService do include DatabaseConnectionHelpers let!(:user) { create(:user) } diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb index f6ad5cebd2c..9902e1aff8b 100644 --- a/spec/services/groups/update_service_spec.rb +++ b/spec/services/groups/update_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Groups::UpdateService, services: true do +describe Groups::UpdateService do let!(:user) { create(:user) } let!(:private_group) { create(:group, :private) } let!(:internal_group) { create(:group, :internal) } diff --git a/spec/services/import_export_clean_up_service_spec.rb b/spec/services/import_export_clean_up_service_spec.rb index 81b1d327696..1875d0448cd 100644 --- a/spec/services/import_export_clean_up_service_spec.rb +++ b/spec/services/import_export_clean_up_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ImportExportCleanUpService, services: true do +describe ImportExportCleanUpService do describe '#execute' do let(:service) { described_class.new } diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb index eb9b1670c71..055aa6156cb 100644 --- a/spec/services/issuable/bulk_update_service_spec.rb +++ b/spec/services/issuable/bulk_update_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Issuable::BulkUpdateService, services: true do +describe Issuable::BulkUpdateService do let(:user) { create(:user) } let(:project) { create(:empty_project, namespace: user.namespace) } diff --git a/spec/services/issues/build_service_spec.rb b/spec/services/issues/build_service_spec.rb index bed25fe7ccf..03f76bd428d 100644 --- a/spec/services/issues/build_service_spec.rb +++ b/spec/services/issues/build_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper.rb' -describe Issues::BuildService, services: true do +describe Issues::BuildService do let(:project) { create(:project, :repository) } let(:user) { create(:user) } diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb index da8b60f1337..a03f68434de 100644 --- a/spec/services/issues/close_service_spec.rb +++ b/spec/services/issues/close_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Issues::CloseService, services: true do +describe Issues::CloseService do let(:user) { create(:user) } let(:user2) { create(:user) } let(:guest) { create(:user) } diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb index ae9d2b2855d..a48748e274d 100644 --- a/spec/services/issues/create_service_spec.rb +++ b/spec/services/issues/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Issues::CreateService, services: true do +describe Issues::CreateService do let(:project) { create(:empty_project) } let(:user) { create(:user) } diff --git a/spec/services/issues/duplicate_service_spec.rb b/spec/services/issues/duplicate_service_spec.rb index 82daf53b173..ed55664e382 100644 --- a/spec/services/issues/duplicate_service_spec.rb +++ b/spec/services/issues/duplicate_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Issues::DuplicateService, services: true do +describe Issues::DuplicateService do let(:user) { create(:user) } let(:canonical_project) { create(:empty_project) } let(:duplicate_project) { create(:empty_project) } diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb index 36d5038fb95..171fc7334c4 100644 --- a/spec/services/issues/move_service_spec.rb +++ b/spec/services/issues/move_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Issues::MoveService, services: true do +describe Issues::MoveService do let(:user) { create(:user) } let(:author) { create(:user) } let(:title) { 'Some issue' } diff --git a/spec/services/issues/reopen_service_spec.rb b/spec/services/issues/reopen_service_spec.rb index 391ecad303a..1ff988e9b47 100644 --- a/spec/services/issues/reopen_service_spec.rb +++ b/spec/services/issues/reopen_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Issues::ReopenService, services: true do +describe Issues::ReopenService do let(:project) { create(:empty_project) } let(:issue) { create(:issue, :closed, project: project) } diff --git a/spec/services/issues/resolve_discussions_spec.rb b/spec/services/issues/resolve_discussions_spec.rb index 86f218dec12..fac66791ffb 100644 --- a/spec/services/issues/resolve_discussions_spec.rb +++ b/spec/services/issues/resolve_discussions_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper.rb' -describe Issues::ResolveDiscussions, services: true do +describe Issues::ResolveDiscussions do class DummyService < Issues::BaseService include ::Issues::ResolveDiscussions diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index 064be940a1c..17d4a072e3d 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -1,7 +1,7 @@ # coding: utf-8 require 'spec_helper' -describe Issues::UpdateService, services: true do +describe Issues::UpdateService do include EmailHelpers let(:user) { create(:user) } diff --git a/spec/services/labels/create_service_spec.rb b/spec/services/labels/create_service_spec.rb index 0ecab0c3475..0fa7b5199fe 100644 --- a/spec/services/labels/create_service_spec.rb +++ b/spec/services/labels/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Labels::CreateService, services: true do +describe Labels::CreateService do describe '#execute' do let(:project) { create(:project) } let(:group) { create(:group) } diff --git a/spec/services/labels/find_or_create_service_spec.rb b/spec/services/labels/find_or_create_service_spec.rb index de8f1827cce..2d3a15a1c11 100644 --- a/spec/services/labels/find_or_create_service_spec.rb +++ b/spec/services/labels/find_or_create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Labels::FindOrCreateService, services: true do +describe Labels::FindOrCreateService do describe '#execute' do let(:group) { create(:group) } let(:project) { create(:empty_project, namespace: group) } diff --git a/spec/services/labels/promote_service_spec.rb b/spec/services/labels/promote_service_spec.rb index 500afdfb916..7cea877ad88 100644 --- a/spec/services/labels/promote_service_spec.rb +++ b/spec/services/labels/promote_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Labels::PromoteService, services: true do +describe Labels::PromoteService do describe '#execute' do let!(:user) { create(:user) } diff --git a/spec/services/labels/transfer_service_spec.rb b/spec/services/labels/transfer_service_spec.rb index 11d5f1cad5e..f70edd3d16e 100644 --- a/spec/services/labels/transfer_service_spec.rb +++ b/spec/services/labels/transfer_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Labels::TransferService, services: true do +describe Labels::TransferService do describe '#execute' do let(:user) { create(:admin) } let(:group_1) { create(:group) } diff --git a/spec/services/labels/update_service_spec.rb b/spec/services/labels/update_service_spec.rb index f2498ea6990..83ea11f62a6 100644 --- a/spec/services/labels/update_service_spec.rb +++ b/spec/services/labels/update_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Labels::UpdateService, services: true do +describe Labels::UpdateService do describe '#execute' do let(:project) { create(:project) } diff --git a/spec/services/members/approve_access_request_service_spec.rb b/spec/services/members/approve_access_request_service_spec.rb index 7d5a66801db..ddba96b8d03 100644 --- a/spec/services/members/approve_access_request_service_spec.rb +++ b/spec/services/members/approve_access_request_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Members::ApproveAccessRequestService, services: true do +describe Members::ApproveAccessRequestService do let(:user) { create(:user) } let(:access_requester) { create(:user) } let(:project) { create(:empty_project, :public, :access_requestable) } diff --git a/spec/services/members/authorized_destroy_service_spec.rb b/spec/services/members/authorized_destroy_service_spec.rb index f99b11f208c..f0abbc46ca3 100644 --- a/spec/services/members/authorized_destroy_service_spec.rb +++ b/spec/services/members/authorized_destroy_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Members::AuthorizedDestroyService, services: true do +describe Members::AuthorizedDestroyService do let(:member_user) { create(:user) } let(:project) { create(:empty_project, :public) } let(:group) { create(:group, :public) } diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb index 5a05ab3ea50..c73a229823d 100644 --- a/spec/services/members/create_service_spec.rb +++ b/spec/services/members/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Members::CreateService, services: true do +describe Members::CreateService do let(:project) { create(:empty_project) } let(:user) { create(:user) } let(:project_user) { create(:user) } diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb index 9ab7839430c..0e30b343eaf 100644 --- a/spec/services/members/destroy_service_spec.rb +++ b/spec/services/members/destroy_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Members::DestroyService, services: true do +describe Members::DestroyService do let(:user) { create(:user) } let(:member_user) { create(:user) } let(:project) { create(:empty_project, :public) } diff --git a/spec/services/members/request_access_service_spec.rb b/spec/services/members/request_access_service_spec.rb index 814c17b9ad0..f39d4f47904 100644 --- a/spec/services/members/request_access_service_spec.rb +++ b/spec/services/members/request_access_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Members::RequestAccessService, services: true do +describe Members::RequestAccessService do let(:user) { create(:user) } shared_examples 'a service raising Gitlab::Access::AccessDeniedError' do diff --git a/spec/services/merge_requests/assign_issues_service_spec.rb b/spec/services/merge_requests/assign_issues_service_spec.rb index d3556020d4d..fcbe0e5985f 100644 --- a/spec/services/merge_requests/assign_issues_service_spec.rb +++ b/spec/services/merge_requests/assign_issues_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MergeRequests::AssignIssuesService, services: true do +describe MergeRequests::AssignIssuesService do let(:user) { create(:user) } let(:project) { create(:project, :public, :repository) } let(:issue) { create(:issue, project: project) } diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb index a40d4c877bc..0dcb636dd35 100644 --- a/spec/services/merge_requests/build_service_spec.rb +++ b/spec/services/merge_requests/build_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MergeRequests::BuildService, services: true do +describe MergeRequests::BuildService do include RepoHelpers let(:project) { create(:project, :repository) } diff --git a/spec/services/merge_requests/close_service_spec.rb b/spec/services/merge_requests/close_service_spec.rb index 074d4672b06..04bf267d167 100644 --- a/spec/services/merge_requests/close_service_spec.rb +++ b/spec/services/merge_requests/close_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MergeRequests::CloseService, services: true do +describe MergeRequests::CloseService do let(:user) { create(:user) } let(:user2) { create(:user) } let(:guest) { create(:user) } diff --git a/spec/services/merge_requests/create_from_issue_service_spec.rb b/spec/services/merge_requests/create_from_issue_service_spec.rb index 1588d30c394..492b55cdece 100644 --- a/spec/services/merge_requests/create_from_issue_service_spec.rb +++ b/spec/services/merge_requests/create_from_issue_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MergeRequests::CreateFromIssueService, services: true do +describe MergeRequests::CreateFromIssueService do let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:issue) { create(:issue, project: project) } diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb index 36a2b672473..8fef480274d 100644 --- a/spec/services/merge_requests/create_service_spec.rb +++ b/spec/services/merge_requests/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MergeRequests::CreateService, services: true do +describe MergeRequests::CreateService do let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:assignee) { create(:user) } diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb index 19d9e4049fe..a8f24b744c2 100644 --- a/spec/services/merge_requests/merge_service_spec.rb +++ b/spec/services/merge_requests/merge_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MergeRequests::MergeService, services: true do +describe MergeRequests::MergeService do let(:user) { create(:user) } let(:user2) { create(:user) } let(:merge_request) { create(:merge_request, :simple, author: user2, assignee: user2) } diff --git a/spec/services/merge_requests/post_merge_service_spec.rb b/spec/services/merge_requests/post_merge_service_spec.rb index a20b32eda5f..a37cdab8928 100644 --- a/spec/services/merge_requests/post_merge_service_spec.rb +++ b/spec/services/merge_requests/post_merge_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MergeRequests::PostMergeService, services: true do +describe MergeRequests::PostMergeService do let(:user) { create(:user) } let(:merge_request) { create(:merge_request, assignee: user) } let(:project) { merge_request.project } diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 74dcf152cb8..6c703dded36 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MergeRequests::RefreshService, services: true do +describe MergeRequests::RefreshService do let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:service) { MergeRequests::RefreshService } diff --git a/spec/services/merge_requests/reopen_service_spec.rb b/spec/services/merge_requests/reopen_service_spec.rb index 6cc403bdb7f..ce1e9f2ff45 100644 --- a/spec/services/merge_requests/reopen_service_spec.rb +++ b/spec/services/merge_requests/reopen_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MergeRequests::ReopenService, services: true do +describe MergeRequests::ReopenService do let(:user) { create(:user) } let(:user2) { create(:user) } let(:guest) { create(:user) } diff --git a/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb b/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb index 7ddd812e513..e3fd906fe7b 100644 --- a/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb +++ b/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MergeRequests::ResolvedDiscussionNotificationService, services: true do +describe MergeRequests::ResolvedDiscussionNotificationService do let(:merge_request) { create(:merge_request) } let(:user) { create(:user) } let(:project) { merge_request.project } diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index be62584ec0e..dddb526e58e 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe MergeRequests::UpdateService, services: true do +describe MergeRequests::UpdateService do include EmailHelpers let(:project) { create(:project, :repository) } diff --git a/spec/services/milestones/close_service_spec.rb b/spec/services/milestones/close_service_spec.rb index d581b94ff43..0838131a18a 100644 --- a/spec/services/milestones/close_service_spec.rb +++ b/spec/services/milestones/close_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Milestones::CloseService, services: true do +describe Milestones::CloseService do let(:user) { create(:user) } let(:project) { create(:empty_project) } let(:milestone) { create(:milestone, title: "Milestone v1.2", project: project) } diff --git a/spec/services/milestones/create_service_spec.rb b/spec/services/milestones/create_service_spec.rb index 6d29edb449a..0c2c41929d7 100644 --- a/spec/services/milestones/create_service_spec.rb +++ b/spec/services/milestones/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Milestones::CreateService, services: true do +describe Milestones::CreateService do let(:project) { create(:empty_project) } let(:user) { create(:user) } diff --git a/spec/services/milestones/destroy_service_spec.rb b/spec/services/milestones/destroy_service_spec.rb index 8d1fe3ae2c1..5739386dd0d 100644 --- a/spec/services/milestones/destroy_service_spec.rb +++ b/spec/services/milestones/destroy_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Milestones::DestroyService, services: true do +describe Milestones::DestroyService do let(:user) { create(:user) } let(:project) { create(:project) } let(:milestone) { create(:milestone, title: 'Milestone v1.0', project: project) } diff --git a/spec/services/note_summary_spec.rb b/spec/services/note_summary_spec.rb index 39f06f8f8e7..dda579c7080 100644 --- a/spec/services/note_summary_spec.rb +++ b/spec/services/note_summary_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe NoteSummary, services: true do +describe NoteSummary do let(:project) { build(:empty_project) } let(:noteable) { build(:issue) } let(:user) { build(:user) } diff --git a/spec/services/notes/build_service_spec.rb b/spec/services/notes/build_service_spec.rb index 133175769ca..6e1c1fe6c02 100644 --- a/spec/services/notes/build_service_spec.rb +++ b/spec/services/notes/build_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Notes::BuildService, services: true do +describe Notes::BuildService do let(:note) { create(:discussion_note_on_issue) } let(:project) { note.project } let(:author) { note.author } diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb index 152c6d20daa..c08a5a940bb 100644 --- a/spec/services/notes/create_service_spec.rb +++ b/spec/services/notes/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Notes::CreateService, services: true do +describe Notes::CreateService do let(:project) { create(:empty_project) } let(:issue) { create(:issue, project: project) } let(:user) { create(:user) } diff --git a/spec/services/notes/destroy_service_spec.rb b/spec/services/notes/destroy_service_spec.rb index f53f96e0c2b..4330190caaa 100644 --- a/spec/services/notes/destroy_service_spec.rb +++ b/spec/services/notes/destroy_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Notes::DestroyService, services: true do +describe Notes::DestroyService do describe '#execute' do it 'deletes a note' do project = create(:empty_project) diff --git a/spec/services/notes/post_process_service_spec.rb b/spec/services/notes/post_process_service_spec.rb index e33a611929b..9044771939d 100644 --- a/spec/services/notes/post_process_service_spec.rb +++ b/spec/services/notes/post_process_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Notes::PostProcessService, services: true do +describe Notes::PostProcessService do let(:project) { create(:empty_project) } let(:issue) { create(:issue, project: project) } let(:user) { create(:user) } diff --git a/spec/services/notes/quick_actions_service_spec.rb b/spec/services/notes/quick_actions_service_spec.rb index 9a98499826f..fc4cd3dc2b7 100644 --- a/spec/services/notes/quick_actions_service_spec.rb +++ b/spec/services/notes/quick_actions_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Notes::QuickActionsService, services: true do +describe Notes::QuickActionsService do shared_context 'note on noteable' do let(:project) { create(:empty_project) } let(:master) { create(:user).tap { |u| project.team << [u, :master] } } diff --git a/spec/services/notes/update_service_spec.rb b/spec/services/notes/update_service_spec.rb index 905e2f46bde..dea2dc02d00 100644 --- a/spec/services/notes/update_service_spec.rb +++ b/spec/services/notes/update_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Notes::UpdateService, services: true do +describe Notes::UpdateService do let(:project) { create(:empty_project) } let(:user) { create(:user) } let(:user2) { create(:user) } diff --git a/spec/services/notification_recipient_service_spec.rb b/spec/services/notification_recipient_service_spec.rb index dfe1ee7c41e..77233dc1b2f 100644 --- a/spec/services/notification_recipient_service_spec.rb +++ b/spec/services/notification_recipient_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe NotificationRecipientService, services: true do +describe NotificationRecipientService do set(:user) { create(:user) } set(:project) { create(:empty_project, :public) } set(:issue) { create(:issue, project: project) } diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 4fc5eb0a527..30fbe363fed 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe NotificationService, services: true do +describe NotificationService do include EmailHelpers let(:notification) { NotificationService.new } diff --git a/spec/services/pages_service_spec.rb b/spec/services/pages_service_spec.rb index cf38c7c75e5..7b9c92c0ce7 100644 --- a/spec/services/pages_service_spec.rb +++ b/spec/services/pages_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe PagesService, services: true do +describe PagesService do let(:build) { create(:ci_build) } let(:data) { Gitlab::DataBuilder::Build.build(build) } let(:service) { PagesService.new(data) } diff --git a/spec/services/projects/autocomplete_service_spec.rb b/spec/services/projects/autocomplete_service_spec.rb index c198c3eedfc..fc7238862ab 100644 --- a/spec/services/projects/autocomplete_service_spec.rb +++ b/spec/services/projects/autocomplete_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::AutocompleteService, services: true do +describe Projects::AutocompleteService do describe '#issues' do describe 'confidential issues' do let(:author) { create(:user) } diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb index 40298dcb723..b0dc7488b5f 100644 --- a/spec/services/projects/create_service_spec.rb +++ b/spec/services/projects/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::CreateService, '#execute', services: true do +describe Projects::CreateService, '#execute' do let(:user) { create :user } let(:opts) do { diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index 357e09bee95..6851c96a6d6 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::DestroyService, services: true do +describe Projects::DestroyService do let!(:user) { create(:user) } let!(:project) { create(:project, :repository, namespace: user.namespace) } let!(:path) { project.repository.path_to_repo } diff --git a/spec/services/projects/download_service_spec.rb b/spec/services/projects/download_service_spec.rb index 33b267c069c..701f6cc8c6a 100644 --- a/spec/services/projects/download_service_spec.rb +++ b/spec/services/projects/download_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::DownloadService, services: true do +describe Projects::DownloadService do describe 'File service' do before do @user = create(:user) diff --git a/spec/services/projects/enable_deploy_key_service_spec.rb b/spec/services/projects/enable_deploy_key_service_spec.rb index 78626fbad4b..9b8c24ba112 100644 --- a/spec/services/projects/enable_deploy_key_service_spec.rb +++ b/spec/services/projects/enable_deploy_key_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::EnableDeployKeyService, services: true do +describe Projects::EnableDeployKeyService do let(:deploy_key) { create(:deploy_key, public: true) } let(:project) { create(:empty_project) } let(:user) { project.creator} diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb index 0df81f3abcb..c90536ba346 100644 --- a/spec/services/projects/fork_service_spec.rb +++ b/spec/services/projects/fork_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::ForkService, services: true do +describe Projects::ForkService do describe 'fork by user' do before do @from_user = create(:user) diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb index e855de38037..67fe610f92a 100644 --- a/spec/services/projects/import_service_spec.rb +++ b/spec/services/projects/import_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::ImportService, services: true do +describe Projects::ImportService do let!(:project) { create(:empty_project) } let(:user) { project.creator } diff --git a/spec/services/projects/participants_service_spec.rb b/spec/services/projects/participants_service_spec.rb index 3688f6d4e23..8777e63a101 100644 --- a/spec/services/projects/participants_service_spec.rb +++ b/spec/services/projects/participants_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::ParticipantsService, services: true do +describe Projects::ParticipantsService do describe '#groups' do describe 'avatar_url' do let(:project) { create(:empty_project, :public) } diff --git a/spec/services/projects/propagate_service_template_spec.rb b/spec/services/projects/propagate_service_template_spec.rb index a6d43c4f0f1..2763437f184 100644 --- a/spec/services/projects/propagate_service_template_spec.rb +++ b/spec/services/projects/propagate_service_template_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::PropagateServiceTemplate, services: true do +describe Projects::PropagateServiceTemplate do describe '.propagate' do let!(:service_template) do PushoverService.create( diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index 441a5276c56..53668c07285 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::TransferService, services: true do +describe Projects::TransferService do let(:user) { create(:user) } let(:group) { create(:group) } let(:project) { create(:project, :repository, namespace: user.namespace) } diff --git a/spec/services/projects/unlink_fork_service_spec.rb b/spec/services/projects/unlink_fork_service_spec.rb index d34652bd7ac..cd5b443b043 100644 --- a/spec/services/projects/unlink_fork_service_spec.rb +++ b/spec/services/projects/unlink_fork_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::UnlinkForkService, services: true do +describe Projects::UnlinkForkService do subject { Projects::UnlinkForkService.new(fork_project, user) } let(:fork_link) { create(:forked_project_link) } diff --git a/spec/services/projects/update_pages_configuration_service_spec.rb b/spec/services/projects/update_pages_configuration_service_spec.rb index 8b329bc21c3..42925e73978 100644 --- a/spec/services/projects/update_pages_configuration_service_spec.rb +++ b/spec/services/projects/update_pages_configuration_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::UpdatePagesConfigurationService, services: true do +describe Projects::UpdatePagesConfigurationService do let(:project) { create(:empty_project) } subject { described_class.new(project) } diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb index 3ee834748df..d7b0df9a671 100644 --- a/spec/services/projects/update_service_spec.rb +++ b/spec/services/projects/update_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::UpdateService, '#execute', :services do +describe Projects::UpdateService, '#execute' do let(:user) { create(:user) } let(:admin) { create(:admin) } diff --git a/spec/services/protected_branches/create_service_spec.rb b/spec/services/protected_branches/create_service_spec.rb index 6ea8f309981..592f9b5929e 100644 --- a/spec/services/protected_branches/create_service_spec.rb +++ b/spec/services/protected_branches/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ProtectedBranches::CreateService, services: true do +describe ProtectedBranches::CreateService do let(:project) { create(:empty_project) } let(:user) { project.owner } let(:params) do diff --git a/spec/services/protected_branches/update_service_spec.rb b/spec/services/protected_branches/update_service_spec.rb index 62bdd49a4d7..5698101af54 100644 --- a/spec/services/protected_branches/update_service_spec.rb +++ b/spec/services/protected_branches/update_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ProtectedBranches::UpdateService, services: true do +describe ProtectedBranches::UpdateService do let(:protected_branch) { create(:protected_branch) } let(:project) { protected_branch.project } let(:user) { project.owner } diff --git a/spec/services/protected_tags/create_service_spec.rb b/spec/services/protected_tags/create_service_spec.rb index d91a58e8de5..3a3cc9c1573 100644 --- a/spec/services/protected_tags/create_service_spec.rb +++ b/spec/services/protected_tags/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ProtectedTags::CreateService, services: true do +describe ProtectedTags::CreateService do let(:project) { create(:empty_project) } let(:user) { project.owner } let(:params) do diff --git a/spec/services/protected_tags/update_service_spec.rb b/spec/services/protected_tags/update_service_spec.rb index e78fde4c48d..d333430088d 100644 --- a/spec/services/protected_tags/update_service_spec.rb +++ b/spec/services/protected_tags/update_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ProtectedTags::UpdateService, services: true do +describe ProtectedTags::UpdateService do let(:protected_tag) { create(:protected_tag) } let(:project) { protected_tag.project } let(:user) { project.owner } diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index 2a2a5c38e4b..42a4a2591ea 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe QuickActions::InterpretService, services: true do +describe QuickActions::InterpretService do let(:project) { create(:empty_project, :public) } let(:developer) { create(:user) } let(:developer2) { create(:user) } diff --git a/spec/services/repair_ldap_blocked_user_service_spec.rb b/spec/services/repair_ldap_blocked_user_service_spec.rb index 87192457298..57a6162206c 100644 --- a/spec/services/repair_ldap_blocked_user_service_spec.rb +++ b/spec/services/repair_ldap_blocked_user_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe RepairLdapBlockedUserService, services: true do +describe RepairLdapBlockedUserService do let(:user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') } let(:identity) { user.ldap_identity } subject(:service) { RepairLdapBlockedUserService.new(user) } diff --git a/spec/services/repository_archive_clean_up_service_spec.rb b/spec/services/repository_archive_clean_up_service_spec.rb index 842585f9e54..2d7fa3f80f7 100644 --- a/spec/services/repository_archive_clean_up_service_spec.rb +++ b/spec/services/repository_archive_clean_up_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe RepositoryArchiveCleanUpService, services: true do +describe RepositoryArchiveCleanUpService do describe '#execute' do subject(:service) { described_class.new } diff --git a/spec/services/search/global_service_spec.rb b/spec/services/search/global_service_spec.rb index cbf4f56213d..c376cdeb725 100644 --- a/spec/services/search/global_service_spec.rb +++ b/spec/services/search/global_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Search::GlobalService, services: true do +describe Search::GlobalService do let(:user) { create(:user) } let(:internal_user) { create(:user) } diff --git a/spec/services/search/group_service_spec.rb b/spec/services/search/group_service_spec.rb index 38f264f6e7b..3315d74658e 100644 --- a/spec/services/search/group_service_spec.rb +++ b/spec/services/search/group_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Search::GroupService, services: true do +describe Search::GroupService do shared_examples_for 'group search' do context 'finding projects by name' do let(:user) { create(:user) } diff --git a/spec/services/search/snippet_service_spec.rb b/spec/services/search/snippet_service_spec.rb index 14f3301d9f4..69438a3fa36 100644 --- a/spec/services/search/snippet_service_spec.rb +++ b/spec/services/search/snippet_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Search::SnippetService, services: true do +describe Search::SnippetService do let(:author) { create(:author) } let(:project) { create(:empty_project) } diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb index 5cf989105d0..a6ec324fe8f 100644 --- a/spec/services/search_service_spec.rb +++ b/spec/services/search_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe SearchService, services: true do +describe SearchService do let(:user) { create(:user) } let(:accessible_group) { create(:group, :private) } diff --git a/spec/services/spam_service_spec.rb b/spec/services/spam_service_spec.rb index 5e6e43b7a90..46349c3e951 100644 --- a/spec/services/spam_service_spec.rb +++ b/spec/services/spam_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe SpamService, services: true do +describe SpamService do describe '#when_recaptcha_verified' do def check_spam(issue, request, recaptcha_verified) described_class.new(issue, request).when_recaptcha_verified(recaptcha_verified) do diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb index 667059f230c..b2d9862e71e 100644 --- a/spec/services/system_hooks_service_spec.rb +++ b/spec/services/system_hooks_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe SystemHooksService, services: true do +describe SystemHooksService do let(:user) { create(:user) } let(:project) { create(:empty_project) } let(:project_member) { create(:project_member) } diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index 681b419aedf..cb59493c343 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe SystemNoteService, services: true do +describe SystemNoteService do include Gitlab::Routing let(:project) { create(:empty_project) } diff --git a/spec/services/tags/create_service_spec.rb b/spec/services/tags/create_service_spec.rb index 9f143cc5667..1b31ce29f7a 100644 --- a/spec/services/tags/create_service_spec.rb +++ b/spec/services/tags/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Tags::CreateService, services: true do +describe Tags::CreateService do let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:user) { create(:user) } diff --git a/spec/services/tags/destroy_service_spec.rb b/spec/services/tags/destroy_service_spec.rb index 28396fc3658..7c8c1dd0d3a 100644 --- a/spec/services/tags/destroy_service_spec.rb +++ b/spec/services/tags/destroy_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Tags::DestroyService, services: true do +describe Tags::DestroyService do let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:user) { create(:user) } diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb index de41cbab14c..8cbffc8ec61 100644 --- a/spec/services/todo_service_spec.rb +++ b/spec/services/todo_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe TodoService, services: true do +describe TodoService do let(:author) { create(:user) } let(:assignee) { create(:user) } let(:non_member) { create(:user) } diff --git a/spec/services/update_release_service_spec.rb b/spec/services/update_release_service_spec.rb index 69ed8de9c31..fecd50e6ca0 100644 --- a/spec/services/update_release_service_spec.rb +++ b/spec/services/update_release_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe UpdateReleaseService, services: true do +describe UpdateReleaseService do let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:tag_name) { project.repository.tag_names.first } diff --git a/spec/services/update_snippet_service_spec.rb b/spec/services/update_snippet_service_spec.rb index 37c2e861362..ef535c5cf1f 100644 --- a/spec/services/update_snippet_service_spec.rb +++ b/spec/services/update_snippet_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe UpdateSnippetService, services: true do +describe UpdateSnippetService do before do @user = create :user @admin = create :user, admin: true diff --git a/spec/services/upload_service_spec.rb b/spec/services/upload_service_spec.rb index 95ba28dbecd..cf76a18f171 100644 --- a/spec/services/upload_service_spec.rb +++ b/spec/services/upload_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe UploadService, services: true do +describe UploadService do describe 'File service' do before do @user = create(:user) diff --git a/spec/services/users/activity_service_spec.rb b/spec/services/users/activity_service_spec.rb index e5330d1d3e4..fef4da0c76e 100644 --- a/spec/services/users/activity_service_spec.rb +++ b/spec/services/users/activity_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Users::ActivityService, services: true do +describe Users::ActivityService do include UserActivitiesHelpers let(:user) { create(:user) } diff --git a/spec/services/users/build_service_spec.rb b/spec/services/users/build_service_spec.rb index 2a6bfc1b3a0..677d4a622e1 100644 --- a/spec/services/users/build_service_spec.rb +++ b/spec/services/users/build_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Users::BuildService, services: true do +describe Users::BuildService do describe '#execute' do let(:params) do { name: 'John Doe', username: 'jduser', email: 'jd@example.com', password: 'mydummypass' } diff --git a/spec/services/users/create_service_spec.rb b/spec/services/users/create_service_spec.rb index 75746278573..24dac569678 100644 --- a/spec/services/users/create_service_spec.rb +++ b/spec/services/users/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Users::CreateService, services: true do +describe Users::CreateService do describe '#execute' do let(:admin_user) { create(:admin) } diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb index 5409f67c091..786335120fd 100644 --- a/spec/services/users/destroy_service_spec.rb +++ b/spec/services/users/destroy_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Users::DestroyService, services: true do +describe Users::DestroyService do describe "Deletes a user and all their personal projects" do let!(:user) { create(:user) } let!(:admin) { create(:admin) } diff --git a/spec/services/users/migrate_to_ghost_user_service_spec.rb b/spec/services/users/migrate_to_ghost_user_service_spec.rb index e52ecd6d614..a0030ce8809 100644 --- a/spec/services/users/migrate_to_ghost_user_service_spec.rb +++ b/spec/services/users/migrate_to_ghost_user_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Users::MigrateToGhostUserService, services: true do +describe Users::MigrateToGhostUserService do let!(:user) { create(:user) } let!(:project) { create(:project) } let(:service) { described_class.new(user) } diff --git a/spec/services/users/update_service_spec.rb b/spec/services/users/update_service_spec.rb index 0b2f840c462..343804e3de0 100644 --- a/spec/services/users/update_service_spec.rb +++ b/spec/services/users/update_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Users::UpdateService, services: true do +describe Users::UpdateService do let(:user) { create(:user) } describe '#execute' do diff --git a/spec/services/web_hook_service_spec.rb b/spec/services/web_hook_service_spec.rb index 7ff37c22963..8d91050b924 100644 --- a/spec/services/web_hook_service_spec.rb +++ b/spec/services/web_hook_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe WebHookService, services: true do +describe WebHookService do let(:project) { create(:empty_project) } let(:project_hook) { create(:project_hook) } let(:headers) do diff --git a/spec/services/wiki_pages/create_service_spec.rb b/spec/services/wiki_pages/create_service_spec.rb index 054e28ae7b0..fa3863e9b30 100644 --- a/spec/services/wiki_pages/create_service_spec.rb +++ b/spec/services/wiki_pages/create_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe WikiPages::CreateService, services: true do +describe WikiPages::CreateService do let(:project) { create(:empty_project) } let(:user) { create(:user) } diff --git a/spec/services/wiki_pages/destroy_service_spec.rb b/spec/services/wiki_pages/destroy_service_spec.rb index 920be4d4c8a..1668cd00ca8 100644 --- a/spec/services/wiki_pages/destroy_service_spec.rb +++ b/spec/services/wiki_pages/destroy_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe WikiPages::DestroyService, services: true do +describe WikiPages::DestroyService do let(:project) { create(:empty_project) } let(:user) { create(:user) } let(:page) { create(:wiki_page) } diff --git a/spec/services/wiki_pages/update_service_spec.rb b/spec/services/wiki_pages/update_service_spec.rb index 5e36ea4cf94..a672c84034b 100644 --- a/spec/services/wiki_pages/update_service_spec.rb +++ b/spec/services/wiki_pages/update_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe WikiPages::UpdateService, services: true do +describe WikiPages::UpdateService do let(:project) { create(:empty_project) } let(:user) { create(:user) } let(:page) { create(:wiki_page) } -- cgit v1.2.1 From cddc5cacfb833fbd188d2f5982381f66dd3eee3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 25 Jul 2017 19:09:00 +0200 Subject: Use described_class when possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/initializers/settings_spec.rb | 40 +++---- spec/lib/disable_email_interceptor_spec.rb | 4 +- spec/lib/event_filter_spec.rb | 16 +-- spec/lib/extracts_path_spec.rb | 2 +- spec/lib/file_size_validator_spec.rb | 2 +- spec/lib/gitlab/bitbucket_import/importer_spec.rb | 2 +- .../bitbucket_import/project_creator_spec.rb | 2 +- spec/lib/gitlab/ci_access_spec.rb | 2 +- spec/lib/gitlab/conflict/file_spec.rb | 4 +- spec/lib/gitlab/conflict/parser_spec.rb | 2 +- spec/lib/gitlab/database/migration_helpers_spec.rb | 2 +- spec/lib/gitlab/diff/highlight_spec.rb | 4 +- spec/lib/gitlab/diff/parser_spec.rb | 2 +- spec/lib/gitlab/git/hook_spec.rb | 8 +- spec/lib/gitlab/git/rev_list_spec.rb | 4 +- spec/lib/gitlab/git_access_spec.rb | 6 +- spec/lib/gitlab/git_access_wiki_spec.rb | 2 +- spec/lib/gitlab/git_ref_validator_spec.rb | 42 +++---- spec/lib/gitlab/git_spec.rb | 6 +- spec/lib/gitlab/gitlab_import/client_spec.rb | 2 +- .../gitlab/gitlab_import/project_creator_spec.rb | 2 +- .../google_code_import/project_creator_spec.rb | 2 +- spec/lib/gitlab/highlight_spec.rb | 4 +- spec/lib/gitlab/key_fingerprint_spec.rb | 2 +- spec/lib/gitlab/ldap/access_spec.rb | 2 +- spec/lib/gitlab/ldap/auth_hash_spec.rb | 2 +- spec/lib/gitlab/ldap/config_spec.rb | 6 +- spec/lib/gitlab/ldap/user_spec.rb | 4 +- spec/lib/gitlab/markup_helper_spec.rb | 12 +- spec/lib/gitlab/o_auth/auth_hash_spec.rb | 2 +- spec/lib/gitlab/o_auth/user_spec.rb | 2 +- spec/lib/gitlab/project_transfer_spec.rb | 2 +- spec/lib/gitlab/reference_extractor_spec.rb | 2 +- spec/lib/gitlab/request_context_spec.rb | 4 +- spec/lib/gitlab/shell_spec.rb | 6 +- spec/lib/gitlab/upgrader_spec.rb | 2 +- spec/lib/gitlab/user_access_spec.rb | 4 +- spec/lib/gitlab/workhorse_spec.rb | 4 +- spec/lib/repository_cache_spec.rb | 2 +- spec/lib/system_check_spec.rb | 2 +- spec/models/ability_spec.rb | 2 +- spec/models/application_setting_spec.rb | 6 +- spec/models/broadcast_message_spec.rb | 8 +- spec/models/ci/pipeline_schedule_spec.rb | 4 +- spec/models/ci/runner_spec.rb | 14 +-- spec/models/global_milestone_spec.rb | 14 +-- spec/models/group_milestone_spec.rb | 4 +- spec/models/group_spec.rb | 2 +- spec/models/guest_spec.rb | 10 +- spec/models/hooks/project_hook_spec.rb | 4 +- spec/models/hooks/system_hook_spec.rb | 2 +- spec/models/member_spec.rb | 2 +- spec/models/members/project_member_spec.rb | 2 +- spec/models/merge_request_diff_spec.rb | 2 +- spec/models/milestone_spec.rb | 10 +- spec/models/namespace_spec.rb | 14 +-- spec/models/note_spec.rb | 2 +- spec/models/project_services/asana_service_spec.rb | 2 +- .../project_services/assembla_service_spec.rb | 2 +- .../project_services/campfire_service_spec.rb | 2 +- .../project_services/flowdock_service_spec.rb | 2 +- .../project_services/gemnasium_service_spec.rb | 2 +- .../gitlab_issue_tracker_service_spec.rb | 4 +- .../project_services/hipchat_service_spec.rb | 2 +- spec/models/project_services/irker_service_spec.rb | 2 +- spec/models/project_services/jira_service_spec.rb | 8 +- .../pivotaltracker_service_spec.rb | 2 +- .../project_services/pushover_service_spec.rb | 2 +- spec/models/project_spec.rb | 18 +-- spec/models/project_wiki_spec.rb | 2 +- spec/models/protected_branch_spec.rb | 36 +++--- spec/models/redirect_route_spec.rb | 2 +- spec/models/route_spec.rb | 4 +- spec/models/sent_notification_spec.rb | 4 +- spec/models/user_spec.rb | 128 ++++++++++----------- spec/models/wiki_directory_spec.rb | 4 +- spec/models/wiki_page_spec.rb | 14 +-- spec/policies/global_policy_spec.rb | 2 +- spec/policies/user_policy_spec.rb | 2 +- spec/services/create_release_service_spec.rb | 2 +- spec/services/event_create_service_spec.rb | 2 +- spec/services/git_hooks_service_spec.rb | 2 +- spec/services/git_tag_push_service_spec.rb | 4 +- spec/services/groups/destroy_service_spec.rb | 2 +- spec/services/issues/update_service_spec.rb | 2 +- spec/services/labels/create_service_spec.rb | 36 +++--- spec/services/labels/update_service_spec.rb | 12 +- spec/services/merge_requests/build_service_spec.rb | 2 +- spec/services/merge_requests/merge_service_spec.rb | 14 +-- .../merge_requests/refresh_service_spec.rb | 2 +- .../services/merge_requests/update_service_spec.rb | 14 +-- spec/services/milestones/close_service_spec.rb | 2 +- spec/services/milestones/create_service_spec.rb | 2 +- spec/services/notes/post_process_service_spec.rb | 2 +- spec/services/notification_service_spec.rb | 2 +- spec/services/pages_service_spec.rb | 2 +- spec/services/projects/destroy_service_spec.rb | 6 +- spec/services/projects/transfer_service_spec.rb | 4 +- spec/services/projects/unlink_fork_service_spec.rb | 2 +- .../repair_ldap_blocked_user_service_spec.rb | 2 +- spec/services/search/global_service_spec.rb | 8 +- spec/services/search/group_service_spec.rb | 2 +- spec/services/search_service_spec.rb | 56 ++++----- spec/services/todo_service_spec.rb | 18 +-- spec/services/update_release_service_spec.rb | 2 +- spec/services/web_hook_service_spec.rb | 6 +- 106 files changed, 390 insertions(+), 390 deletions(-) diff --git a/spec/initializers/settings_spec.rb b/spec/initializers/settings_spec.rb index 61439ac9506..ebdabcf93f1 100644 --- a/spec/initializers/settings_spec.rb +++ b/spec/initializers/settings_spec.rb @@ -5,37 +5,37 @@ describe Settings do describe '#host_without_www' do context 'URL with protocol' do it 'returns the host' do - expect(Settings.host_without_www('http://foo.com')).to eq 'foo.com' - expect(Settings.host_without_www('http://www.foo.com')).to eq 'foo.com' - expect(Settings.host_without_www('http://secure.foo.com')).to eq 'secure.foo.com' - expect(Settings.host_without_www('http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com' + expect(described_class.host_without_www('http://foo.com')).to eq 'foo.com' + expect(described_class.host_without_www('http://www.foo.com')).to eq 'foo.com' + expect(described_class.host_without_www('http://secure.foo.com')).to eq 'secure.foo.com' + expect(described_class.host_without_www('http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com' - expect(Settings.host_without_www('https://foo.com')).to eq 'foo.com' - expect(Settings.host_without_www('https://www.foo.com')).to eq 'foo.com' - expect(Settings.host_without_www('https://secure.foo.com')).to eq 'secure.foo.com' - expect(Settings.host_without_www('https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'secure.gravatar.com' + expect(described_class.host_without_www('https://foo.com')).to eq 'foo.com' + expect(described_class.host_without_www('https://www.foo.com')).to eq 'foo.com' + expect(described_class.host_without_www('https://secure.foo.com')).to eq 'secure.foo.com' + expect(described_class.host_without_www('https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'secure.gravatar.com' end end context 'URL without protocol' do it 'returns the host' do - expect(Settings.host_without_www('foo.com')).to eq 'foo.com' - expect(Settings.host_without_www('www.foo.com')).to eq 'foo.com' - expect(Settings.host_without_www('secure.foo.com')).to eq 'secure.foo.com' - expect(Settings.host_without_www('www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com' + expect(described_class.host_without_www('foo.com')).to eq 'foo.com' + expect(described_class.host_without_www('www.foo.com')).to eq 'foo.com' + expect(described_class.host_without_www('secure.foo.com')).to eq 'secure.foo.com' + expect(described_class.host_without_www('www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com' end context 'URL with user/port' do it 'returns the host' do - expect(Settings.host_without_www('bob:pass@foo.com:8080')).to eq 'foo.com' - expect(Settings.host_without_www('bob:pass@www.foo.com:8080')).to eq 'foo.com' - expect(Settings.host_without_www('bob:pass@secure.foo.com:8080')).to eq 'secure.foo.com' - expect(Settings.host_without_www('bob:pass@www.gravatar.com:8080/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com' + expect(described_class.host_without_www('bob:pass@foo.com:8080')).to eq 'foo.com' + expect(described_class.host_without_www('bob:pass@www.foo.com:8080')).to eq 'foo.com' + expect(described_class.host_without_www('bob:pass@secure.foo.com:8080')).to eq 'secure.foo.com' + expect(described_class.host_without_www('bob:pass@www.gravatar.com:8080/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com' - expect(Settings.host_without_www('http://bob:pass@foo.com:8080')).to eq 'foo.com' - expect(Settings.host_without_www('http://bob:pass@www.foo.com:8080')).to eq 'foo.com' - expect(Settings.host_without_www('http://bob:pass@secure.foo.com:8080')).to eq 'secure.foo.com' - expect(Settings.host_without_www('http://bob:pass@www.gravatar.com:8080/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com' + expect(described_class.host_without_www('http://bob:pass@foo.com:8080')).to eq 'foo.com' + expect(described_class.host_without_www('http://bob:pass@www.foo.com:8080')).to eq 'foo.com' + expect(described_class.host_without_www('http://bob:pass@secure.foo.com:8080')).to eq 'secure.foo.com' + expect(described_class.host_without_www('http://bob:pass@www.gravatar.com:8080/avatar/%{hash}?s=%{size}&d=identicon')).to eq 'gravatar.com' end end end diff --git a/spec/lib/disable_email_interceptor_spec.rb b/spec/lib/disable_email_interceptor_spec.rb index 9fc1dd523f1..3652d928c43 100644 --- a/spec/lib/disable_email_interceptor_spec.rb +++ b/spec/lib/disable_email_interceptor_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe DisableEmailInterceptor do before do - Mail.register_interceptor(DisableEmailInterceptor) + Mail.register_interceptor(described_class) end it 'does not send emails' do @@ -14,7 +14,7 @@ describe DisableEmailInterceptor do # Removing interceptor from the list because unregister_interceptor is # implemented in later version of mail gem # See: https://github.com/mikel/mail/pull/705 - Mail.unregister_interceptor(DisableEmailInterceptor) + Mail.unregister_interceptor(described_class) end def deliver_mail diff --git a/spec/lib/event_filter_spec.rb b/spec/lib/event_filter_spec.rb index 09425c6bf68..b1366e74802 100644 --- a/spec/lib/event_filter_spec.rb +++ b/spec/lib/event_filter_spec.rb @@ -16,42 +16,42 @@ describe EventFilter do let!(:left_event) { create(:event, :left, project: public_project, target: public_project, author: source_user) } it 'applies push filter' do - events = EventFilter.new(EventFilter.push).apply_filter(Event.all) + events = described_class.new(described_class.push).apply_filter(Event.all) expect(events).to contain_exactly(push_event) end it 'applies merged filter' do - events = EventFilter.new(EventFilter.merged).apply_filter(Event.all) + events = described_class.new(described_class.merged).apply_filter(Event.all) expect(events).to contain_exactly(merged_event) end it 'applies issue filter' do - events = EventFilter.new(EventFilter.issue).apply_filter(Event.all) + events = described_class.new(described_class.issue).apply_filter(Event.all) expect(events).to contain_exactly(created_event, updated_event, closed_event, reopened_event) end it 'applies comments filter' do - events = EventFilter.new(EventFilter.comments).apply_filter(Event.all) + events = described_class.new(described_class.comments).apply_filter(Event.all) expect(events).to contain_exactly(comments_event) end it 'applies team filter' do - events = EventFilter.new(EventFilter.team).apply_filter(Event.all) + events = described_class.new(described_class.team).apply_filter(Event.all) expect(events).to contain_exactly(joined_event, left_event) end it 'applies all filter' do - events = EventFilter.new(EventFilter.all).apply_filter(Event.all) + events = described_class.new(described_class.all).apply_filter(Event.all) expect(events).to contain_exactly(push_event, merged_event, created_event, updated_event, closed_event, reopened_event, comments_event, joined_event, left_event) end it 'applies no filter' do - events = EventFilter.new(nil).apply_filter(Event.all) + events = described_class.new(nil).apply_filter(Event.all) expect(events).to contain_exactly(push_event, merged_event, created_event, updated_event, closed_event, reopened_event, comments_event, joined_event, left_event) end it 'applies unknown filter' do - events = EventFilter.new('').apply_filter(Event.all) + events = described_class.new('').apply_filter(Event.all) expect(events).to contain_exactly(push_event, merged_event, created_event, updated_event, closed_event, reopened_event, comments_event, joined_event, left_event) end end diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb index 1772ca216e4..9b89f47ae7e 100644 --- a/spec/lib/extracts_path_spec.rb +++ b/spec/lib/extracts_path_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ExtractsPath do - include ExtractsPath + include described_class include RepoHelpers include Gitlab::Routing diff --git a/spec/lib/file_size_validator_spec.rb b/spec/lib/file_size_validator_spec.rb index 681cc9ef21c..49501931dd2 100644 --- a/spec/lib/file_size_validator_spec.rb +++ b/spec/lib/file_size_validator_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe FileSizeValidator do - let(:validator) { FileSizeValidator.new(options) } + let(:validator) { described_class.new(options) } let(:attachment) { AttachmentUploader.new } let(:note) { create(:note) } diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb index 35c8a24aef4..df66a031fec 100644 --- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb +++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb @@ -58,7 +58,7 @@ describe Gitlab::BitbucketImport::Importer do ) end - let(:importer) { Gitlab::BitbucketImport::Importer.new(project) } + let(:importer) { described_class.new(project) } let(:issues_statuses_sample_data) do { diff --git a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb index 4bc0eaddd9e..d7f7b26740d 100644 --- a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb +++ b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb @@ -27,7 +27,7 @@ describe Gitlab::BitbucketImport::ProjectCreator do it 'creates project' do allow_any_instance_of(Project).to receive(:add_import_job) - project_creator = Gitlab::BitbucketImport::ProjectCreator.new(repo, 'vim', namespace, user, access_params) + project_creator = described_class.new(repo, 'vim', namespace, user, access_params) project = project_creator.execute expect(project.import_url).to eq("ssh://git@bitbucket.org/asd/vim.git") diff --git a/spec/lib/gitlab/ci_access_spec.rb b/spec/lib/gitlab/ci_access_spec.rb index fcb9f10d6c0..75b90e76083 100644 --- a/spec/lib/gitlab/ci_access_spec.rb +++ b/spec/lib/gitlab/ci_access_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::CiAccess do - let(:access) { Gitlab::CiAccess.new } + let(:access) { described_class.new } describe '#can_do_action?' do context 'when action is :build_download_code' do diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb index c0a10124730..5356e9742b4 100644 --- a/spec/lib/gitlab/conflict/file_spec.rb +++ b/spec/lib/gitlab/conflict/file_spec.rb @@ -10,7 +10,7 @@ describe Gitlab::Conflict::File do let(:index) { rugged.merge_commits(our_commit, their_commit) } let(:conflict) { index.conflicts.last } let(:merge_file_result) { index.merge_file('files/ruby/regex.rb') } - let(:conflict_file) { Gitlab::Conflict::File.new(merge_file_result, conflict, merge_request: merge_request) } + let(:conflict_file) { described_class.new(merge_file_result, conflict, merge_request: merge_request) } describe '#resolve_lines' do let(:section_keys) { conflict_file.sections.map { |section| section[:id] }.compact } @@ -220,7 +220,7 @@ end FILE end - let(:conflict_file) { Gitlab::Conflict::File.new({ data: file }, conflict, merge_request: merge_request) } + let(:conflict_file) { described_class.new({ data: file }, conflict, merge_request: merge_request) } let(:sections) { conflict_file.sections } it 'sets the correct match line headers' do diff --git a/spec/lib/gitlab/conflict/parser_spec.rb b/spec/lib/gitlab/conflict/parser_spec.rb index ad99a5fb6bf..fce606a2bb5 100644 --- a/spec/lib/gitlab/conflict/parser_spec.rb +++ b/spec/lib/gitlab/conflict/parser_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::Conflict::Parser do - let(:parser) { Gitlab::Conflict::Parser.new } + let(:parser) { described_class.new } describe '#parse' do def parse_text(text) diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index 0e0354bc532..d3dbd82e8ba 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::Database::MigrationHelpers do let(:model) do ActiveRecord::Migration.new.extend( - Gitlab::Database::MigrationHelpers + described_class ) end diff --git a/spec/lib/gitlab/diff/highlight_spec.rb b/spec/lib/gitlab/diff/highlight_spec.rb index ffa83d6a8f2..cd602ccab8e 100644 --- a/spec/lib/gitlab/diff/highlight_spec.rb +++ b/spec/lib/gitlab/diff/highlight_spec.rb @@ -10,7 +10,7 @@ describe Gitlab::Diff::Highlight do describe '#highlight' do context "with a diff file" do - let(:subject) { Gitlab::Diff::Highlight.new(diff_file, repository: project.repository).highlight } + let(:subject) { described_class.new(diff_file, repository: project.repository).highlight } it 'returns Gitlab::Diff::Line elements' do expect(subject.first).to be_an_instance_of(Gitlab::Diff::Line) @@ -41,7 +41,7 @@ describe Gitlab::Diff::Highlight do end context "with diff lines" do - let(:subject) { Gitlab::Diff::Highlight.new(diff_file.diff_lines, repository: project.repository).highlight } + let(:subject) { described_class.new(diff_file.diff_lines, repository: project.repository).highlight } it 'returns Gitlab::Diff::Line elements' do expect(subject.first).to be_an_instance_of(Gitlab::Diff::Line) diff --git a/spec/lib/gitlab/diff/parser_spec.rb b/spec/lib/gitlab/diff/parser_spec.rb index e16c31d7eb8..c71568e2a65 100644 --- a/spec/lib/gitlab/diff/parser_spec.rb +++ b/spec/lib/gitlab/diff/parser_spec.rb @@ -6,7 +6,7 @@ describe Gitlab::Diff::Parser do let(:project) { create(:project) } let(:commit) { project.commit(sample_commit.id) } let(:diff) { commit.raw_diffs.first } - let(:parser) { Gitlab::Diff::Parser.new } + let(:parser) { described_class.new } describe '#parse' do let(:diff) do diff --git a/spec/lib/gitlab/git/hook_spec.rb b/spec/lib/gitlab/git/hook_spec.rb index ff823e53cac..19391a70cf6 100644 --- a/spec/lib/gitlab/git/hook_spec.rb +++ b/spec/lib/gitlab/git/hook_spec.rb @@ -5,7 +5,7 @@ describe Gitlab::Git::Hook do before do # We need this because in the spec/spec_helper.rb we define it like this: # allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil]) - allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_call_original + allow_any_instance_of(described_class).to receive(:trigger).and_call_original end describe "#trigger" do @@ -48,7 +48,7 @@ describe Gitlab::Git::Hook do it "returns success with no errors" do create_hook(hook_name) - hook = Gitlab::Git::Hook.new(hook_name, project) + hook = described_class.new(hook_name, project) blank = Gitlab::Git::BLANK_SHA ref = Gitlab::Git::BRANCH_REF_PREFIX + 'new_branch' @@ -66,7 +66,7 @@ describe Gitlab::Git::Hook do context "when the hook is unsuccessful" do it "returns failure with errors" do create_failing_hook(hook_name) - hook = Gitlab::Git::Hook.new(hook_name, project) + hook = described_class.new(hook_name, project) blank = Gitlab::Git::BLANK_SHA ref = Gitlab::Git::BRANCH_REF_PREFIX + 'new_branch' @@ -80,7 +80,7 @@ describe Gitlab::Git::Hook do context "when the hook doesn't exist" do it "returns success with no errors" do - hook = Gitlab::Git::Hook.new('unknown_hook', project) + hook = described_class.new('unknown_hook', project) blank = Gitlab::Git::BLANK_SHA ref = Gitlab::Git::BRANCH_REF_PREFIX + 'new_branch' diff --git a/spec/lib/gitlab/git/rev_list_spec.rb b/spec/lib/gitlab/git/rev_list_spec.rb index 26fc33b8327..b051a088171 100644 --- a/spec/lib/gitlab/git/rev_list_spec.rb +++ b/spec/lib/gitlab/git/rev_list_spec.rb @@ -11,7 +11,7 @@ describe Gitlab::Git::RevList do end context "#new_refs" do - let(:rev_list) { Gitlab::Git::RevList.new(newrev: 'newrev', path_to_repo: project.repository.path_to_repo) } + let(:rev_list) { described_class.new(newrev: 'newrev', path_to_repo: project.repository.path_to_repo) } it 'calls out to `popen`' do expect(Gitlab::Popen).to receive(:popen).with([ @@ -33,7 +33,7 @@ describe Gitlab::Git::RevList do end context "#missed_ref" do - let(:rev_list) { Gitlab::Git::RevList.new(oldrev: 'oldrev', newrev: 'newrev', path_to_repo: project.repository.path_to_repo) } + let(:rev_list) { described_class.new(oldrev: 'oldrev', newrev: 'newrev', path_to_repo: project.repository.path_to_repo) } it 'calls out to `popen`' do expect(Gitlab::Popen).to receive(:popen).with([ diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index 14c424b86e4..2d6ea37d0ac 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::GitAccess do let(:pull_access_check) { access.check('git-upload-pack', '_any') } let(:push_access_check) { access.check('git-receive-pack', '_any') } - let(:access) { Gitlab::GitAccess.new(actor, project, protocol, authentication_abilities: authentication_abilities, redirected_path: redirected_path) } + let(:access) { described_class.new(actor, project, protocol, authentication_abilities: authentication_abilities, redirected_path: redirected_path) } let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:actor) { user } @@ -280,7 +280,7 @@ describe Gitlab::GitAccess do context 'when project is public' do let(:public_project) { create(:project, :public, :repository) } - let(:access) { Gitlab::GitAccess.new(nil, public_project, 'web', authentication_abilities: []) } + let(:access) { described_class.new(nil, public_project, 'web', authentication_abilities: []) } context 'when repository is enabled' do it 'give access to download code' do @@ -441,7 +441,7 @@ describe Gitlab::GitAccess do end permissions_matrix[role].each do |action, allowed| - context action do + context action.to_s do subject { access.send(:check_push_access!, changes[action]) } it do diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb index 2a710fbdf06..0376b4ee783 100644 --- a/spec/lib/gitlab/git_access_wiki_spec.rb +++ b/spec/lib/gitlab/git_access_wiki_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::GitAccessWiki do - let(:access) { Gitlab::GitAccessWiki.new(user, project, 'web', authentication_abilities: authentication_abilities, redirected_path: redirected_path) } + let(:access) { described_class.new(user, project, 'web', authentication_abilities: authentication_abilities, redirected_path: redirected_path) } let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:redirected_path) { nil } diff --git a/spec/lib/gitlab/git_ref_validator_spec.rb b/spec/lib/gitlab/git_ref_validator_spec.rb index 91a25b7c0f0..e1fa8ae03f8 100644 --- a/spec/lib/gitlab/git_ref_validator_spec.rb +++ b/spec/lib/gitlab/git_ref_validator_spec.rb @@ -1,25 +1,25 @@ require 'spec_helper' describe Gitlab::GitRefValidator do - it { expect(Gitlab::GitRefValidator.validate('feature/new')).to be_truthy } - it { expect(Gitlab::GitRefValidator.validate('implement_@all')).to be_truthy } - it { expect(Gitlab::GitRefValidator.validate('my_new_feature')).to be_truthy } - it { expect(Gitlab::GitRefValidator.validate('#1')).to be_truthy } - it { expect(Gitlab::GitRefValidator.validate('feature/refs/heads/foo')).to be_truthy } - it { expect(Gitlab::GitRefValidator.validate('feature/~new/')).to be_falsey } - it { expect(Gitlab::GitRefValidator.validate('feature/^new/')).to be_falsey } - it { expect(Gitlab::GitRefValidator.validate('feature/:new/')).to be_falsey } - it { expect(Gitlab::GitRefValidator.validate('feature/?new/')).to be_falsey } - it { expect(Gitlab::GitRefValidator.validate('feature/*new/')).to be_falsey } - it { expect(Gitlab::GitRefValidator.validate('feature/[new/')).to be_falsey } - it { expect(Gitlab::GitRefValidator.validate('feature/new/')).to be_falsey } - it { expect(Gitlab::GitRefValidator.validate('feature/new.')).to be_falsey } - it { expect(Gitlab::GitRefValidator.validate('feature\@{')).to be_falsey } - it { expect(Gitlab::GitRefValidator.validate('feature\new')).to be_falsey } - it { expect(Gitlab::GitRefValidator.validate('feature//new')).to be_falsey } - it { expect(Gitlab::GitRefValidator.validate('feature new')).to be_falsey } - it { expect(Gitlab::GitRefValidator.validate('refs/heads/')).to be_falsey } - it { expect(Gitlab::GitRefValidator.validate('refs/remotes/')).to be_falsey } - it { expect(Gitlab::GitRefValidator.validate('refs/heads/feature')).to be_falsey } - it { expect(Gitlab::GitRefValidator.validate('refs/remotes/origin')).to be_falsey } + it { expect(described_class.validate('feature/new')).to be_truthy } + it { expect(described_class.validate('implement_@all')).to be_truthy } + it { expect(described_class.validate('my_new_feature')).to be_truthy } + it { expect(described_class.validate('#1')).to be_truthy } + it { expect(described_class.validate('feature/refs/heads/foo')).to be_truthy } + it { expect(described_class.validate('feature/~new/')).to be_falsey } + it { expect(described_class.validate('feature/^new/')).to be_falsey } + it { expect(described_class.validate('feature/:new/')).to be_falsey } + it { expect(described_class.validate('feature/?new/')).to be_falsey } + it { expect(described_class.validate('feature/*new/')).to be_falsey } + it { expect(described_class.validate('feature/[new/')).to be_falsey } + it { expect(described_class.validate('feature/new/')).to be_falsey } + it { expect(described_class.validate('feature/new.')).to be_falsey } + it { expect(described_class.validate('feature\@{')).to be_falsey } + it { expect(described_class.validate('feature\new')).to be_falsey } + it { expect(described_class.validate('feature//new')).to be_falsey } + it { expect(described_class.validate('feature new')).to be_falsey } + it { expect(described_class.validate('refs/heads/')).to be_falsey } + it { expect(described_class.validate('refs/remotes/')).to be_falsey } + it { expect(described_class.validate('refs/heads/feature')).to be_falsey } + it { expect(described_class.validate('refs/remotes/origin')).to be_falsey } end diff --git a/spec/lib/gitlab/git_spec.rb b/spec/lib/gitlab/git_spec.rb index 88f5c106c80..4702a978f19 100644 --- a/spec/lib/gitlab/git_spec.rb +++ b/spec/lib/gitlab/git_spec.rb @@ -6,7 +6,7 @@ describe Gitlab::Git do describe 'committer_hash' do it "returns a hash containing the given email and name" do - committer_hash = Gitlab::Git.committer_hash(email: committer_email, name: committer_name) + committer_hash = described_class.committer_hash(email: committer_email, name: committer_name) expect(committer_hash[:email]).to eq(committer_email) expect(committer_hash[:name]).to eq(committer_name) @@ -15,7 +15,7 @@ describe Gitlab::Git do context 'when email is nil' do it "returns nil" do - committer_hash = Gitlab::Git.committer_hash(email: nil, name: committer_name) + committer_hash = described_class.committer_hash(email: nil, name: committer_name) expect(committer_hash).to be_nil end @@ -23,7 +23,7 @@ describe Gitlab::Git do context 'when name is nil' do it "returns nil" do - committer_hash = Gitlab::Git.committer_hash(email: committer_email, name: nil) + committer_hash = described_class.committer_hash(email: committer_email, name: nil) expect(committer_hash).to be_nil end diff --git a/spec/lib/gitlab/gitlab_import/client_spec.rb b/spec/lib/gitlab/gitlab_import/client_spec.rb index 977135b3310..50e8d7183ce 100644 --- a/spec/lib/gitlab/gitlab_import/client_spec.rb +++ b/spec/lib/gitlab/gitlab_import/client_spec.rb @@ -4,7 +4,7 @@ describe Gitlab::GitlabImport::Client do include ImportSpecHelper let(:token) { '123456' } - let(:client) { Gitlab::GitlabImport::Client.new(token) } + let(:client) { described_class.new(token) } before do stub_omniauth_provider('gitlab') diff --git a/spec/lib/gitlab/gitlab_import/project_creator_spec.rb b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb index 2d8923d14bb..da48d8f0670 100644 --- a/spec/lib/gitlab/gitlab_import/project_creator_spec.rb +++ b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb @@ -23,7 +23,7 @@ describe Gitlab::GitlabImport::ProjectCreator do it 'creates project' do allow_any_instance_of(Project).to receive(:add_import_job) - project_creator = Gitlab::GitlabImport::ProjectCreator.new(repo, namespace, user, access_params) + project_creator = described_class.new(repo, namespace, user, access_params) project = project_creator.execute expect(project.import_url).to eq("https://oauth2:asdffg@gitlab.com/asd/vim.git") diff --git a/spec/lib/gitlab/google_code_import/project_creator_spec.rb b/spec/lib/gitlab/google_code_import/project_creator_spec.rb index 35549b48687..aad53938d52 100644 --- a/spec/lib/gitlab/google_code_import/project_creator_spec.rb +++ b/spec/lib/gitlab/google_code_import/project_creator_spec.rb @@ -18,7 +18,7 @@ describe Gitlab::GoogleCodeImport::ProjectCreator do it 'creates project' do allow_any_instance_of(Project).to receive(:add_import_job) - project_creator = Gitlab::GoogleCodeImport::ProjectCreator.new(repo, namespace, user) + project_creator = described_class.new(repo, namespace, user) project = project_creator.execute expect(project.import_url).to eq("https://vim.googlecode.com/git/") diff --git a/spec/lib/gitlab/highlight_spec.rb b/spec/lib/gitlab/highlight_spec.rb index 9afd9916264..29e61d15726 100644 --- a/spec/lib/gitlab/highlight_spec.rb +++ b/spec/lib/gitlab/highlight_spec.rb @@ -12,7 +12,7 @@ describe Gitlab::Highlight do let(:blob) { repository.blob_at_branch(branch, path) } let(:highlighter) do - Gitlab::Highlight.new(blob.path, blob.data, repository: repository) + described_class.new(blob.path, blob.data, repository: repository) end before do @@ -42,7 +42,7 @@ describe Gitlab::Highlight do let(:path) { 'files/whitespace' } let(:blob) { repository.blob_at_branch(branch, path) } let(:lines) do - Gitlab::Highlight.highlight(blob.path, blob.data, repository: repository).lines + described_class.highlight(blob.path, blob.data, repository: repository).lines end it 'strips extra LFs' do diff --git a/spec/lib/gitlab/key_fingerprint_spec.rb b/spec/lib/gitlab/key_fingerprint_spec.rb index 266eab6e793..d7bebaca675 100644 --- a/spec/lib/gitlab/key_fingerprint_spec.rb +++ b/spec/lib/gitlab/key_fingerprint_spec.rb @@ -6,7 +6,7 @@ describe Gitlab::KeyFingerprint do describe "#fingerprint" do it "generates the key's fingerprint" do - expect(Gitlab::KeyFingerprint.new(key).fingerprint).to eq(fingerprint) + expect(described_class.new(key).fingerprint).to eq(fingerprint) end end end diff --git a/spec/lib/gitlab/ldap/access_spec.rb b/spec/lib/gitlab/ldap/access_spec.rb index f800e267568..6a47350be81 100644 --- a/spec/lib/gitlab/ldap/access_spec.rb +++ b/spec/lib/gitlab/ldap/access_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::LDAP::Access do - let(:access) { Gitlab::LDAP::Access.new user } + let(:access) { described_class.new user } let(:user) { create(:omniauth_user) } describe '.allowed?' do diff --git a/spec/lib/gitlab/ldap/auth_hash_spec.rb b/spec/lib/gitlab/ldap/auth_hash_spec.rb index bd546115afa..57a91193004 100644 --- a/spec/lib/gitlab/ldap/auth_hash_spec.rb +++ b/spec/lib/gitlab/ldap/auth_hash_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::LDAP::AuthHash do let(:auth_hash) do - Gitlab::LDAP::AuthHash.new( + described_class.new( OmniAuth::AuthHash.new( uid: '123456', provider: 'ldapmain', diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb index 0d99ebf23e8..292ec064a67 100644 --- a/spec/lib/gitlab/ldap/config_spec.rb +++ b/spec/lib/gitlab/ldap/config_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' describe Gitlab::LDAP::Config do include LdapHelpers - let(:config) { Gitlab::LDAP::Config.new('ldapmain') } + let(:config) { described_class.new('ldapmain') } describe '#initialize' do it 'requires a provider' do - expect{ Gitlab::LDAP::Config.new }.to raise_error ArgumentError + expect{ described_class.new }.to raise_error ArgumentError end it 'works' do @@ -15,7 +15,7 @@ describe Gitlab::LDAP::Config do end it 'raises an error if a unknown provider is used' do - expect{ Gitlab::LDAP::Config.new 'unknown' }.to raise_error(RuntimeError) + expect{ described_class.new 'unknown' }.to raise_error(RuntimeError) end end diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb index efc7a551761..175ceec44d7 100644 --- a/spec/lib/gitlab/ldap/user_spec.rb +++ b/spec/lib/gitlab/ldap/user_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::LDAP::User do - let(:ldap_user) { Gitlab::LDAP::User.new(auth_hash) } + let(:ldap_user) { described_class.new(auth_hash) } let(:gl_user) { ldap_user.gl_user } let(:info) do { @@ -13,7 +13,7 @@ describe Gitlab::LDAP::User do let(:auth_hash) do OmniAuth::AuthHash.new(uid: 'my-uid', provider: 'ldapmain', info: info) end - let(:ldap_user_upper_case) { Gitlab::LDAP::User.new(auth_hash_upper_case) } + let(:ldap_user_upper_case) { described_class.new(auth_hash_upper_case) } let(:info_upper_case) do { name: 'John', diff --git a/spec/lib/gitlab/markup_helper_spec.rb b/spec/lib/gitlab/markup_helper_spec.rb index e610fab05da..09e518ff989 100644 --- a/spec/lib/gitlab/markup_helper_spec.rb +++ b/spec/lib/gitlab/markup_helper_spec.rb @@ -5,36 +5,36 @@ describe Gitlab::MarkupHelper do %w(textile rdoc org creole wiki mediawiki rst adoc ad asciidoc mdown md markdown).each do |type| it "returns true for #{type} files" do - expect(Gitlab::MarkupHelper.markup?("README.#{type}")).to be_truthy + expect(described_class.markup?("README.#{type}")).to be_truthy end end it 'returns false when given a non-markup filename' do - expect(Gitlab::MarkupHelper.markup?('README.rb')).not_to be_truthy + expect(described_class.markup?('README.rb')).not_to be_truthy end end describe '#gitlab_markdown?' do %w(mdown mkd mkdn md markdown).each do |type| it "returns true for #{type} files" do - expect(Gitlab::MarkupHelper.gitlab_markdown?("README.#{type}")).to be_truthy + expect(described_class.gitlab_markdown?("README.#{type}")).to be_truthy end end it 'returns false when given a non-markdown filename' do - expect(Gitlab::MarkupHelper.gitlab_markdown?('README.rb')).not_to be_truthy + expect(described_class.gitlab_markdown?('README.rb')).not_to be_truthy end end describe '#asciidoc?' do %w(adoc ad asciidoc ADOC).each do |type| it "returns true for #{type} files" do - expect(Gitlab::MarkupHelper.asciidoc?("README.#{type}")).to be_truthy + expect(described_class.asciidoc?("README.#{type}")).to be_truthy end end it 'returns false when given a non-asciidoc filename' do - expect(Gitlab::MarkupHelper.asciidoc?('README.rb')).not_to be_truthy + expect(described_class.asciidoc?('README.rb')).not_to be_truthy end end end diff --git a/spec/lib/gitlab/o_auth/auth_hash_spec.rb b/spec/lib/gitlab/o_auth/auth_hash_spec.rb index 4b77e6473be..d5f4da3ce36 100644 --- a/spec/lib/gitlab/o_auth/auth_hash_spec.rb +++ b/spec/lib/gitlab/o_auth/auth_hash_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::OAuth::AuthHash do let(:auth_hash) do - Gitlab::OAuth::AuthHash.new( + described_class.new( OmniAuth::AuthHash.new( provider: provider_ascii, uid: uid_ascii, diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb index b70e49e2602..47aa19d5fd9 100644 --- a/spec/lib/gitlab/o_auth/user_spec.rb +++ b/spec/lib/gitlab/o_auth/user_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::OAuth::User do - let(:oauth_user) { Gitlab::OAuth::User.new(auth_hash) } + let(:oauth_user) { described_class.new(auth_hash) } let(:gl_user) { oauth_user.gl_user } let(:uid) { 'my-uid' } let(:provider) { 'my-provider' } diff --git a/spec/lib/gitlab/project_transfer_spec.rb b/spec/lib/gitlab/project_transfer_spec.rb index ff943db1d9c..10c5fb148cd 100644 --- a/spec/lib/gitlab/project_transfer_spec.rb +++ b/spec/lib/gitlab/project_transfer_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::ProjectTransfer do before do @root_dir = File.join(Rails.root, "public", "uploads") - @project_transfer = Gitlab::ProjectTransfer.new + @project_transfer = described_class.new allow(@project_transfer).to receive(:root_dir).and_return(@root_dir) @project_path_was = "test_project_was" diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb index e41e2faac15..1a0357534f2 100644 --- a/spec/lib/gitlab/reference_extractor_spec.rb +++ b/spec/lib/gitlab/reference_extractor_spec.rb @@ -7,7 +7,7 @@ describe Gitlab::ReferenceExtractor do project.team << [project.creator, :developer] end - subject { Gitlab::ReferenceExtractor.new(project, project.creator) } + subject { described_class.new(project, project.creator) } it 'accesses valid user objects' do @u_foo = create(:user, username: 'foo') diff --git a/spec/lib/gitlab/request_context_spec.rb b/spec/lib/gitlab/request_context_spec.rb index 16673ea313e..e272bdb9284 100644 --- a/spec/lib/gitlab/request_context_spec.rb +++ b/spec/lib/gitlab/request_context_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::RequestContext do describe '#client_ip' do - subject { Gitlab::RequestContext.client_ip } + subject { described_class.client_ip } let(:app) { -> (env) {} } let(:env) { Hash.new } @@ -16,7 +16,7 @@ describe Gitlab::RequestContext do before do allow_any_instance_of(Rack::Request).to receive(:ip).and_return(ip) - Gitlab::RequestContext.new(app).call(env) + described_class.new(app).call(env) end it { is_expected.to eq(ip) } diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb index 8ab250a6203..b90d8dede0f 100644 --- a/spec/lib/gitlab/shell_spec.rb +++ b/spec/lib/gitlab/shell_spec.rb @@ -3,7 +3,7 @@ require 'stringio' describe Gitlab::Shell do let(:project) { double('Project', id: 7, path: 'diaspora') } - let(:gitlab_shell) { Gitlab::Shell.new } + let(:gitlab_shell) { described_class.new } let(:popen_vars) { { 'GIT_TERMINAL_PROMPT' => ENV['GIT_TERMINAL_PROMPT'] } } before do @@ -30,7 +30,7 @@ describe Gitlab::Shell do allow(Gitlab.config.gitlab_shell).to receive(:secret_file).and_return(secret_file) allow(Gitlab.config.gitlab_shell).to receive(:path).and_return('tmp/tests/shell-secret-test') FileUtils.mkdir('tmp/tests/shell-secret-test') - Gitlab::Shell.ensure_secret_token! + described_class.ensure_secret_token! end after do @@ -39,7 +39,7 @@ describe Gitlab::Shell do end it 'creates and links the secret token file' do - secret_token = Gitlab::Shell.secret_token + secret_token = described_class.secret_token expect(File.exist?(secret_file)).to be(true) expect(File.read(secret_file).chomp).to eq(secret_token) diff --git a/spec/lib/gitlab/upgrader_spec.rb b/spec/lib/gitlab/upgrader_spec.rb index eb128e343e6..6106f13c774 100644 --- a/spec/lib/gitlab/upgrader_spec.rb +++ b/spec/lib/gitlab/upgrader_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::Upgrader do - let(:upgrader) { Gitlab::Upgrader.new } + let(:upgrader) { described_class.new } let(:current_version) { Gitlab::VERSION } describe 'current_version_raw' do diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb index 648c464db78..5ebaf6c1507 100644 --- a/spec/lib/gitlab/user_access_spec.rb +++ b/spec/lib/gitlab/user_access_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::UserAccess do - let(:access) { Gitlab::UserAccess.new(user, project: project) } + let(:access) { described_class.new(user, project: project) } let(:project) { create(:project) } let(:user) { create(:user) } @@ -28,7 +28,7 @@ describe Gitlab::UserAccess do describe 'push to empty project' do let(:empty_project) { create(:project_empty_repo) } - let(:project_access) { Gitlab::UserAccess.new(user, project: empty_project) } + let(:project_access) { described_class.new(user, project: empty_project) } it 'returns true if user is master' do empty_project.team << [user, :master] diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb index c593e1db1bf..654397ccffb 100644 --- a/spec/lib/gitlab/workhorse_spec.rb +++ b/spec/lib/gitlab/workhorse_spec.rb @@ -63,13 +63,13 @@ describe Gitlab::Workhorse do end context 'without ca_pem' do - subject { Gitlab::Workhorse.terminal_websocket(terminal) } + subject { described_class.terminal_websocket(terminal) } it { is_expected.to eq(workhorse) } end context 'with ca_pem' do - subject { Gitlab::Workhorse.terminal_websocket(terminal(ca_pem: "foo")) } + subject { described_class.terminal_websocket(terminal(ca_pem: "foo")) } it { is_expected.to eq(workhorse(ca_pem: "foo")) } end diff --git a/spec/lib/repository_cache_spec.rb b/spec/lib/repository_cache_spec.rb index 41d1706ab6d..0c15ba22bf2 100644 --- a/spec/lib/repository_cache_spec.rb +++ b/spec/lib/repository_cache_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe RepositoryCache do let(:project) { create(:empty_project) } let(:backend) { double('backend').as_null_object } - let(:cache) { RepositoryCache.new('example', project.id, backend) } + let(:cache) { described_class.new('example', project.id, backend) } describe '#cache_key' do it 'includes the namespace' do diff --git a/spec/lib/system_check_spec.rb b/spec/lib/system_check_spec.rb index 9a75c41f783..4d9e17fa6ec 100644 --- a/spec/lib/system_check_spec.rb +++ b/spec/lib/system_check_spec.rb @@ -19,7 +19,7 @@ describe SystemCheck do end describe '.run' do - subject { SystemCheck } + subject { described_class } it 'detects execution of SimpleCheck' do is_expected.to execute_check(SimpleCheck) diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index cb57626b597..aa019288700 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Ability do context 'using a nil subject' do it 'has no permissions' do - expect(Ability.policy_for(nil, nil)).to be_banned + expect(described_class.policy_for(nil, nil)).to be_banned end end diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index 41129b945b6..359753b600e 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ApplicationSetting do - let(:setting) { ApplicationSetting.create_from_defaults } + let(:setting) { described_class.create_from_defaults } it { expect(setting).to be_valid } it { expect(setting.uuid).to be_present } @@ -159,10 +159,10 @@ describe ApplicationSetting do context 'redis unavailable' do it 'returns an ApplicationSetting' do allow(Rails.cache).to receive(:fetch).and_call_original - allow(ApplicationSetting).to receive(:last).and_return(:last) + allow(described_class).to receive(:last).and_return(:last) expect(Rails.cache).to receive(:fetch).with(ApplicationSetting::CACHE_KEY).and_raise(ArgumentError) - expect(ApplicationSetting.current).to eq(:last) + expect(described_class.current).to eq(:last) end end end diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb index 75e7c7d42bd..a8ca1d110e4 100644 --- a/spec/models/broadcast_message_spec.rb +++ b/spec/models/broadcast_message_spec.rb @@ -24,26 +24,26 @@ describe BroadcastMessage do it 'returns message if time match' do message = create(:broadcast_message) - expect(BroadcastMessage.current).to include(message) + expect(described_class.current).to include(message) end it 'returns multiple messages if time match' do message1 = create(:broadcast_message) message2 = create(:broadcast_message) - expect(BroadcastMessage.current).to contain_exactly(message1, message2) + expect(described_class.current).to contain_exactly(message1, message2) end it 'returns empty list if time not come' do create(:broadcast_message, :future) - expect(BroadcastMessage.current).to be_empty + expect(described_class.current).to be_empty end it 'returns empty list if time has passed' do create(:broadcast_message, :expired) - expect(BroadcastMessage.current).to be_empty + expect(described_class.current).to be_empty end end diff --git a/spec/models/ci/pipeline_schedule_spec.rb b/spec/models/ci/pipeline_schedule_spec.rb index 3ae86ab2b4b..9a278212efc 100644 --- a/spec/models/ci/pipeline_schedule_spec.rb +++ b/spec/models/ci/pipeline_schedule_spec.rb @@ -46,7 +46,7 @@ describe Ci::PipelineSchedule do end it 'updates next_run_at automatically' do - expect(Ci::PipelineSchedule.last.next_run_at).to eq(expected_next_run_at) + expect(described_class.last.next_run_at).to eq(expected_next_run_at) end end @@ -61,7 +61,7 @@ describe Ci::PipelineSchedule do it 'updates next_run_at automatically' do pipeline_schedule.update!(cron: new_cron) - expect(Ci::PipelineSchedule.last.next_run_at).to eq(expected_next_run_at) + expect(described_class.last.next_run_at).to eq(expected_next_run_at) end end end diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index 9a4ed86990a..8d12a9c09ca 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -50,7 +50,7 @@ describe Ci::Runner do end describe '.online' do - subject { Ci::Runner.online } + subject { described_class.online } before do @runner1 = FactoryGirl.create(:ci_runner, :shared, contacted_at: 1.year.ago) @@ -352,13 +352,13 @@ describe Ci::Runner do end context 'does not give owned runner' do - subject { Ci::Runner.assignable_for(project) } + subject { described_class.assignable_for(project) } it { is_expected.to be_empty } end context 'does not give shared runner' do - subject { Ci::Runner.assignable_for(another_project) } + subject { described_class.assignable_for(another_project) } it { is_expected.to be_empty } end @@ -366,13 +366,13 @@ describe Ci::Runner do context 'with unlocked runner' do context 'does not give owned runner' do - subject { Ci::Runner.assignable_for(project) } + subject { described_class.assignable_for(project) } it { is_expected.to be_empty } end context 'does give a specific runner' do - subject { Ci::Runner.assignable_for(another_project) } + subject { described_class.assignable_for(another_project) } it { is_expected.to contain_exactly(runner) } end @@ -384,13 +384,13 @@ describe Ci::Runner do end context 'does not give owned runner' do - subject { Ci::Runner.assignable_for(project) } + subject { described_class.assignable_for(project) } it { is_expected.to be_empty } end context 'does not give a locked runner' do - subject { Ci::Runner.assignable_for(another_project) } + subject { described_class.assignable_for(another_project) } it { is_expected.to be_empty } end diff --git a/spec/models/global_milestone_spec.rb b/spec/models/global_milestone_spec.rb index 17462f70a6d..5584a1a5a31 100644 --- a/spec/models/global_milestone_spec.rb +++ b/spec/models/global_milestone_spec.rb @@ -72,7 +72,7 @@ describe GlobalMilestone do project3 ] - @global_milestones = GlobalMilestone.build_collection(projects, {}) + @global_milestones = described_class.build_collection(projects, {}) end it 'has all project milestones' do @@ -106,7 +106,7 @@ describe GlobalMilestone do it 'returns the quantity of global milestones in each possible state' do expected_count = { opened: 1, closed: 2, all: 2 } - count = GlobalMilestone.states_count(Project.all) + count = described_class.states_count(Project.all) expect(count).to eq(expected_count) end @@ -120,7 +120,7 @@ describe GlobalMilestone do it 'returns 0 as the quantity of global milestones in each state' do expected_count = { opened: 0, closed: 0, all: 0 } - count = GlobalMilestone.states_count(Project.all) + count = described_class.states_count(Project.all) expect(count).to eq(expected_count) end @@ -141,7 +141,7 @@ describe GlobalMilestone do ] milestones_relation = Milestone.where(id: milestones.map(&:id)) - @global_milestone = GlobalMilestone.new(milestone1_project1.title, milestones_relation) + @global_milestone = described_class.new(milestone1_project1.title, milestones_relation) end it 'has exactly one group milestone' do @@ -157,7 +157,7 @@ describe GlobalMilestone do let(:milestone) { create(:milestone, title: "git / test", project: project1) } it 'strips out slashes and spaces' do - global_milestone = GlobalMilestone.new(milestone.title, Milestone.where(id: milestone.id)) + global_milestone = described_class.new(milestone.title, Milestone.where(id: milestone.id)) expect(global_milestone.safe_title).to eq('git-test') end @@ -171,7 +171,7 @@ describe GlobalMilestone do create(:active_milestone, title: title), create(:closed_milestone, title: title) ] - global_milestone = GlobalMilestone.new(title, milestones) + global_milestone = described_class.new(title, milestones) expect(global_milestone.state).to eq('active') end @@ -184,7 +184,7 @@ describe GlobalMilestone do create(:closed_milestone, title: title), create(:closed_milestone, title: title) ] - global_milestone = GlobalMilestone.new(title, milestones) + global_milestone = described_class.new(title, milestones) expect(global_milestone.state).to eq('closed') end diff --git a/spec/models/group_milestone_spec.rb b/spec/models/group_milestone_spec.rb index 6d1a7f188c8..ac76c927c39 100644 --- a/spec/models/group_milestone_spec.rb +++ b/spec/models/group_milestone_spec.rb @@ -9,7 +9,7 @@ describe GroupMilestone do describe '.build' do it 'returns milestone with group assigned' do - milestone = GroupMilestone.build( + milestone = described_class.build( group, [project], project_milestone.title @@ -25,7 +25,7 @@ describe GroupMilestone do end it 'returns array of milestones, each with group assigned' do - milestones = GroupMilestone.build_collection(group, [project], {}) + milestones = described_class.build_collection(group, [project], {}) expect(milestones).to all(have_attributes(group: group)) end end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 3f66d9b0ab9..112bd605a64 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -357,7 +357,7 @@ describe Group do subject { build(:group, :nested) } it { is_expected.to be_valid } - it { expect(subject.parent).to be_kind_of(Group) } + it { expect(subject.parent).to be_kind_of(described_class) } end describe '#members_with_parents', :nested_groups do diff --git a/spec/models/guest_spec.rb b/spec/models/guest_spec.rb index ac9aaa76550..0e9b94aac97 100644 --- a/spec/models/guest_spec.rb +++ b/spec/models/guest_spec.rb @@ -8,13 +8,13 @@ describe Guest do describe '.can_pull?' do context 'when project is private' do it 'does not allow to pull the repo' do - expect(Guest.can?(:download_code, private_project)).to eq(false) + expect(described_class.can?(:download_code, private_project)).to eq(false) end end context 'when project is internal' do it 'does not allow to pull the repo' do - expect(Guest.can?(:download_code, internal_project)).to eq(false) + expect(described_class.can?(:download_code, internal_project)).to eq(false) end end @@ -23,7 +23,7 @@ describe Guest do it 'does not allow to pull the repo' do public_project.project_feature.update_attribute(:repository_access_level, ProjectFeature::DISABLED) - expect(Guest.can?(:download_code, public_project)).to eq(false) + expect(described_class.can?(:download_code, public_project)).to eq(false) end end @@ -31,13 +31,13 @@ describe Guest do it 'does not allow to pull the repo' do public_project.project_feature.update_attribute(:repository_access_level, ProjectFeature::PRIVATE) - expect(Guest.can?(:download_code, public_project)).to eq(false) + expect(described_class.can?(:download_code, public_project)).to eq(false) end end context 'when repository is enabled' do it 'allows to pull the repo' do - expect(Guest.can?(:download_code, public_project)).to eq(true) + expect(described_class.can?(:download_code, public_project)).to eq(true) end end end diff --git a/spec/models/hooks/project_hook_spec.rb b/spec/models/hooks/project_hook_spec.rb index c9b948fb747..5dd31b1b5de 100644 --- a/spec/models/hooks/project_hook_spec.rb +++ b/spec/models/hooks/project_hook_spec.rb @@ -13,7 +13,7 @@ describe ProjectHook do it 'returns hooks for push events only' do hook = create(:project_hook, push_events: true) create(:project_hook, push_events: false) - expect(ProjectHook.push_hooks).to eq([hook]) + expect(described_class.push_hooks).to eq([hook]) end end @@ -21,7 +21,7 @@ describe ProjectHook do it 'returns hooks for tag push events only' do hook = create(:project_hook, tag_push_events: true) create(:project_hook, tag_push_events: false) - expect(ProjectHook.tag_push_hooks).to eq([hook]) + expect(described_class.tag_push_hooks).to eq([hook]) end end end diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb index 812dcb437f5..eadc232a989 100644 --- a/spec/models/hooks/system_hook_spec.rb +++ b/spec/models/hooks/system_hook_spec.rb @@ -122,7 +122,7 @@ describe SystemHook do it 'returns hooks for repository update events only' do hook = create(:system_hook, repository_update_events: true) create(:system_hook, repository_update_events: false) - expect(SystemHook.repository_update_hooks).to eq([hook]) + expect(described_class.repository_update_hooks).to eq([hook]) end end diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb index 22e62ee0823..8bfd70b8d46 100644 --- a/spec/models/member_spec.rb +++ b/spec/models/member_spec.rb @@ -6,7 +6,7 @@ describe Member do end describe "Validation" do - subject { Member.new(access_level: Member::GUEST) } + subject { described_class.new(access_level: Member::GUEST) } it { is_expected.to validate_presence_of(:user) } it { is_expected.to validate_presence_of(:source) } diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb index 93df1b2fb6c..025fb2bf441 100644 --- a/spec/models/members/project_member_spec.rb +++ b/spec/models/members/project_member_spec.rb @@ -139,7 +139,7 @@ describe ProjectMember do @project_1.team << [@user_1, :developer] @project_2.team << [@user_2, :reporter] - ProjectMember.truncate_teams([@project_1.id, @project_2.id]) + described_class.truncate_teams([@project_1.id, @project_2.id]) end it { expect(@project_1.users).to be_empty } diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index d09f880423b..0cfaa17676e 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -98,7 +98,7 @@ describe MergeRequestDiff do end it 'saves empty state' do - allow_any_instance_of(MergeRequestDiff).to receive_message_chain(:compare, :commits) + allow_any_instance_of(described_class).to receive_message_chain(:compare, :commits) .and_return([]) mr_diff = create(:merge_request).merge_request_diff diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index 0dd8a86106b..aa376e242e8 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -37,13 +37,13 @@ describe Milestone do describe "unique milestone title" do context "per project" do it "does not accept the same title in a project twice" do - new_milestone = Milestone.new(project: milestone.project, title: milestone.title) + new_milestone = described_class.new(project: milestone.project, title: milestone.title) expect(new_milestone).not_to be_valid end it "accepts the same title in another project" do project = create(:empty_project) - new_milestone = Milestone.new(project: project, title: milestone.title) + new_milestone = described_class.new(project: project, title: milestone.title) expect(new_milestone).to be_valid end @@ -58,7 +58,7 @@ describe Milestone do end it "does not accept the same title in a group twice" do - new_milestone = Milestone.new(group: group, title: milestone.title) + new_milestone = described_class.new(group: group, title: milestone.title) expect(new_milestone).not_to be_valid end @@ -66,7 +66,7 @@ describe Milestone do it "does not accept the same title of a child project milestone" do create(:milestone, project: group.projects.first) - new_milestone = Milestone.new(group: group, title: milestone.title) + new_milestone = described_class.new(group: group, title: milestone.title) expect(new_milestone).not_to be_valid end @@ -214,7 +214,7 @@ describe Milestone do # The call to `#try` is because this returns a relation with a Postgres DB, # and an array of IDs with a MySQL DB. - let(:milestone_ids) { Milestone.upcoming_ids_by_projects(projects).map { |id| id.try(:id) || id } } + let(:milestone_ids) { described_class.upcoming_ids_by_projects(projects).map { |id| id.try(:id) || id } } it 'returns the next upcoming open milestone ID for each project' do expect(milestone_ids).to contain_exactly(current_milestone_project_1.id, current_milestone_project_2.id) diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 827356b660e..f12fe226e6b 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -133,7 +133,7 @@ describe Namespace do it "sums all project storage counters in the namespace" do project1 project2 - statistics = Namespace.with_statistics.find(namespace.id) + statistics = described_class.with_statistics.find(namespace.id) expect(statistics.storage_size).to eq 666 expect(statistics.repository_size).to eq 111 @@ -142,7 +142,7 @@ describe Namespace do end it "correctly handles namespaces without projects" do - statistics = Namespace.with_statistics.find(namespace.id) + statistics = described_class.with_statistics.find(namespace.id) expect(statistics.storage_size).to eq 0 expect(statistics.repository_size).to eq 0 @@ -286,9 +286,9 @@ describe Namespace do @namespace = create(:namespace, name: 'WoW', path: 'woW') end - it { expect(Namespace.find_by_path_or_name('wow')).to eq(@namespace) } - it { expect(Namespace.find_by_path_or_name('WOW')).to eq(@namespace) } - it { expect(Namespace.find_by_path_or_name('unknown')).to eq(nil) } + it { expect(described_class.find_by_path_or_name('wow')).to eq(@namespace) } + it { expect(described_class.find_by_path_or_name('WOW')).to eq(@namespace) } + it { expect(described_class.find_by_path_or_name('unknown')).to eq(nil) } end describe ".clean_path" do @@ -296,8 +296,8 @@ describe Namespace do let!(:namespace) { create(:namespace, path: "JohnGitLab-etc1") } it "cleans the path and makes sure it's available" do - expect(Namespace.clean_path("-john+gitlab-ETC%.git@gmail.com")).to eq("johngitlab-ETC2") - expect(Namespace.clean_path("--%+--valid_*&%name=.git.%.atom.atom.@email.com")).to eq("valid_name") + expect(described_class.clean_path("-john+gitlab-ETC%.git@gmail.com")).to eq("johngitlab-ETC2") + expect(described_class.clean_path("--%+--valid_*&%name=.git.%.atom.atom.@email.com")).to eq("valid_name") end end diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index d20816bc31f..cbe6d42ef53 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -525,7 +525,7 @@ describe Note do it "has a discussion id" do # The discussion_id is set in `after_initialize`, so `reload` won't work - reloaded_note = Note.find(note.id) + reloaded_note = described_class.find(note.id) expect(reloaded_note.discussion_id).not_to be_nil expect(reloaded_note.discussion_id).to match(/\A\h{40}\z/) diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb index 3e568ec3dad..4684c970885 100644 --- a/spec/models/project_services/asana_service_spec.rb +++ b/spec/models/project_services/asana_service_spec.rb @@ -35,7 +35,7 @@ describe AsanaService do end before do - @asana = AsanaService.new + @asana = described_class.new allow(@asana).to receive_messages( project: project, project_id: project.id, diff --git a/spec/models/project_services/assembla_service_spec.rb b/spec/models/project_services/assembla_service_spec.rb index a06bd2de0eb..5cb6d63659e 100644 --- a/spec/models/project_services/assembla_service_spec.rb +++ b/spec/models/project_services/assembla_service_spec.rb @@ -11,7 +11,7 @@ describe AssemblaService do let(:project) { create(:project, :repository) } before do - @assembla_service = AssemblaService.new + @assembla_service = described_class.new allow(@assembla_service).to receive_messages( project_id: project.id, project: project, diff --git a/spec/models/project_services/campfire_service_spec.rb b/spec/models/project_services/campfire_service_spec.rb index 176850b4c72..ed8347edffd 100644 --- a/spec/models/project_services/campfire_service_spec.rb +++ b/spec/models/project_services/campfire_service_spec.rb @@ -29,7 +29,7 @@ describe CampfireService do let(:project) { create(:project, :repository) } before do - @campfire_service = CampfireService.new + @campfire_service = described_class.new allow(@campfire_service).to receive_messages( project_id: project.id, project: project, diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb index e439abb45a4..5e8e880985e 100644 --- a/spec/models/project_services/flowdock_service_spec.rb +++ b/spec/models/project_services/flowdock_service_spec.rb @@ -29,7 +29,7 @@ describe FlowdockService do let(:project) { create(:project, :repository) } before do - @flowdock_service = FlowdockService.new + @flowdock_service = described_class.new allow(@flowdock_service).to receive_messages( project_id: project.id, project: project, diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb index d89e7ee8a2a..4c61bc0af95 100644 --- a/spec/models/project_services/gemnasium_service_spec.rb +++ b/spec/models/project_services/gemnasium_service_spec.rb @@ -31,7 +31,7 @@ describe GemnasiumService do let(:project) { create(:project, :repository) } before do - @gemnasium_service = GemnasiumService.new + @gemnasium_service = described_class.new allow(@gemnasium_service).to receive_messages( project_id: project.id, project: project, diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb index ff0f73eff4c..d19dab8fd39 100644 --- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb +++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb @@ -27,7 +27,7 @@ describe GitlabIssueTrackerService do context 'with absolute urls' do before do - allow(GitlabIssueTrackerService).to receive(:default_url_options).and_return(script_name: "/gitlab/root") + allow(described_class).to receive(:default_url_options).and_return(script_name: "/gitlab/root") end it 'gives the correct path' do @@ -39,7 +39,7 @@ describe GitlabIssueTrackerService do context 'with relative urls' do before do - allow(GitlabIssueTrackerService).to receive(:default_url_options).and_return(script_name: "/gitlab/root") + allow(described_class).to receive(:default_url_options).and_return(script_name: "/gitlab/root") end it 'gives the correct path' do diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb index f08e6c863a4..7614bb897e8 100644 --- a/spec/models/project_services/hipchat_service_spec.rb +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -25,7 +25,7 @@ describe HipchatService do end describe "Execute" do - let(:hipchat) { HipchatService.new } + let(:hipchat) { described_class.new } let(:user) { create(:user) } let(:project) { create(:project, :repository) } let(:api_url) { 'https://hipchat.example.com/v2/room/123456/notification?auth_token=verySecret' } diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb index ce2b26436b3..cb9ca76fc3f 100644 --- a/spec/models/project_services/irker_service_spec.rb +++ b/spec/models/project_services/irker_service_spec.rb @@ -27,7 +27,7 @@ describe IrkerService do end describe 'Execute' do - let(:irker) { IrkerService.new } + let(:irker) { described_class.new } let(:user) { create(:user) } let(:project) { create(:project, :repository) } let(:sample_data) do diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 62e1d51104e..c9e8d7e194d 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -78,7 +78,7 @@ describe JiraService do let(:merge_request) { create(:merge_request) } before do - @jira_service = JiraService.new + @jira_service = described_class.new allow(@jira_service).to receive_messages( project_id: project.id, project: project, @@ -167,7 +167,7 @@ describe JiraService do stub_config_setting(relative_url_root: '/gitlab') stub_config_setting(url: Settings.send(:build_gitlab_url)) - allow(JiraService).to receive(:default_url_options) do + allow(described_class).to receive(:default_url_options) do { script_name: '/gitlab' } end @@ -220,7 +220,7 @@ describe JiraService do context "when a password was previously set" do before do - @jira_service = JiraService.create!( + @jira_service = described_class.create!( project: project, properties: { url: 'http://jira.example.com/web', @@ -301,7 +301,7 @@ describe JiraService do context 'when no password was previously set' do before do - @jira_service = JiraService.create( + @jira_service = described_class.create( project: project, properties: { url: 'http://jira.example.com/rest/api/2', diff --git a/spec/models/project_services/pivotaltracker_service_spec.rb b/spec/models/project_services/pivotaltracker_service_spec.rb index 002476c1a17..f7d2372eca2 100644 --- a/spec/models/project_services/pivotaltracker_service_spec.rb +++ b/spec/models/project_services/pivotaltracker_service_spec.rb @@ -26,7 +26,7 @@ describe PivotaltrackerService do describe 'Execute' do let(:service) do - PivotaltrackerService.new.tap do |service| + described_class.new.tap do |service| service.token = 'secret_api_token' end end diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb index e77c4ddcc78..54b8c658ff6 100644 --- a/spec/models/project_services/pushover_service_spec.rb +++ b/spec/models/project_services/pushover_service_spec.rb @@ -29,7 +29,7 @@ describe PushoverService do end describe 'Execute' do - let(:pushover) { PushoverService.new } + let(:pushover) { described_class.new } let(:user) { create(:user) } let(:project) { create(:project, :repository) } let(:sample_data) do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 2df31a54628..473b7a88d61 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -77,7 +77,7 @@ describe Project do context 'after initialized' do it "has a project_feature" do - expect(Project.new.project_feature).to be_present + expect(described_class.new.project_feature).to be_present end end @@ -438,7 +438,7 @@ describe Project do end it 'returns valid url to repo' do - project = Project.new(path: 'somewhere') + project = described_class.new(path: 'somewhere') expect(project.url_to_repo).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + 'somewhere.git') end @@ -917,7 +917,7 @@ describe Project do end describe '.with_shared_runners' do - subject { Project.with_shared_runners } + subject { described_class.with_shared_runners } context 'when shared runners are enabled for project' do let!(:project) { create(:empty_project, shared_runners_enabled: true) } @@ -942,10 +942,10 @@ describe Project do let!(:project2) { create(:empty_project, :public, group: group) } it 'returns total project count' do - expect(Project).to receive(:count).once.and_call_original + expect(described_class).to receive(:count).once.and_call_original 3.times do - expect(Project.cached_count).to eq(2) + expect(described_class.cached_count).to eq(2) end end end @@ -990,7 +990,7 @@ describe Project do user1.toggle_star(project1) user2.toggle_star(project2) - expect(Project.starred_by(user1)).to contain_exactly(project1) + expect(described_class.starred_by(user1)).to contain_exactly(project1) end end @@ -2012,7 +2012,7 @@ describe Project do let!(:path) { project1.namespace.full_path } it 'returns correct project' do - expect(Project.inside_path(path)).to eq([project1]) + expect(described_class.inside_path(path)).to eq([project1]) end end @@ -2216,7 +2216,7 @@ describe Project do context 'with a user' do let(:projects) do - Project.all.public_or_visible_to_user(user) + described_class.all.public_or_visible_to_user(user) end it 'includes projects the user has access to' do @@ -2230,7 +2230,7 @@ describe Project do context 'without a user' do it 'only includes public projects' do - projects = Project.all.public_or_visible_to_user + projects = described_class.all.public_or_visible_to_user expect(projects).to eq([public_project]) end diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index fc1cdb3b1e6..7fcbeb459e0 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -5,7 +5,7 @@ describe ProjectWiki do let(:repository) { project.repository } let(:user) { project.owner } let(:gitlab_shell) { Gitlab::Shell.new } - let(:project_wiki) { ProjectWiki.new(project, user) } + let(:project_wiki) { described_class.new(project, user) } subject { project_wiki } diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb index 6e8b07b44fb..a54af3bfe59 100644 --- a/spec/models/protected_branch_spec.rb +++ b/spec/models/protected_branch_spec.rb @@ -101,17 +101,17 @@ describe ProtectedBranch do production = create(:protected_branch, name: "production") staging = create(:protected_branch, name: "staging") - expect(ProtectedBranch.matching("production")).to include(production) - expect(ProtectedBranch.matching("production")).not_to include(staging) + expect(described_class.matching("production")).to include(production) + expect(described_class.matching("production")).not_to include(staging) end it "accepts a list of protected branches to search from, so as to avoid a DB call" do production = build(:protected_branch, name: "production") staging = build(:protected_branch, name: "staging") - expect(ProtectedBranch.matching("production")).to be_empty - expect(ProtectedBranch.matching("production", protected_refs: [production, staging])).to include(production) - expect(ProtectedBranch.matching("production", protected_refs: [production, staging])).not_to include(staging) + expect(described_class.matching("production")).to be_empty + expect(described_class.matching("production", protected_refs: [production, staging])).to include(production) + expect(described_class.matching("production", protected_refs: [production, staging])).not_to include(staging) end end @@ -120,17 +120,17 @@ describe ProtectedBranch do production = create(:protected_branch, name: "production/*") staging = create(:protected_branch, name: "staging/*") - expect(ProtectedBranch.matching("production/some-branch")).to include(production) - expect(ProtectedBranch.matching("production/some-branch")).not_to include(staging) + expect(described_class.matching("production/some-branch")).to include(production) + expect(described_class.matching("production/some-branch")).not_to include(staging) end it "accepts a list of protected branches to search from, so as to avoid a DB call" do production = build(:protected_branch, name: "production/*") staging = build(:protected_branch, name: "staging/*") - expect(ProtectedBranch.matching("production/some-branch")).to be_empty - expect(ProtectedBranch.matching("production/some-branch", protected_refs: [production, staging])).to include(production) - expect(ProtectedBranch.matching("production/some-branch", protected_refs: [production, staging])).not_to include(staging) + expect(described_class.matching("production/some-branch")).to be_empty + expect(described_class.matching("production/some-branch", protected_refs: [production, staging])).to include(production) + expect(described_class.matching("production/some-branch", protected_refs: [production, staging])).not_to include(staging) end end end @@ -142,23 +142,23 @@ describe ProtectedBranch do it 'returns true when the branch matches a protected branch via direct match' do create(:protected_branch, project: project, name: "foo") - expect(ProtectedBranch.protected?(project, 'foo')).to eq(true) + expect(described_class.protected?(project, 'foo')).to eq(true) end it 'returns true when the branch matches a protected branch via wildcard match' do create(:protected_branch, project: project, name: "production/*") - expect(ProtectedBranch.protected?(project, 'production/some-branch')).to eq(true) + expect(described_class.protected?(project, 'production/some-branch')).to eq(true) end it 'returns false when the branch does not match a protected branch via direct match' do - expect(ProtectedBranch.protected?(project, 'foo')).to eq(false) + expect(described_class.protected?(project, 'foo')).to eq(false) end it 'returns false when the branch does not match a protected branch via wildcard match' do create(:protected_branch, project: project, name: "production/*") - expect(ProtectedBranch.protected?(project, 'staging/some-branch')).to eq(false) + expect(described_class.protected?(project, 'staging/some-branch')).to eq(false) end end @@ -168,25 +168,25 @@ describe ProtectedBranch do it 'returns false when default_protected_branch is unprotected' do stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE) - expect(ProtectedBranch.protected?(project, 'master')).to be false + expect(described_class.protected?(project, 'master')).to be false end it 'returns false when default_protected_branch lets developers push' do stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH) - expect(ProtectedBranch.protected?(project, 'master')).to be false + expect(described_class.protected?(project, 'master')).to be false end it 'returns true when default_branch_protection does not let developers push but let developer merge branches' do stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE) - expect(ProtectedBranch.protected?(project, 'master')).to be true + expect(described_class.protected?(project, 'master')).to be true end it 'returns true when default_branch_protection is in full protection' do stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_FULL) - expect(ProtectedBranch.protected?(project, 'master')).to be true + expect(described_class.protected?(project, 'master')).to be true end end end diff --git a/spec/models/redirect_route_spec.rb b/spec/models/redirect_route_spec.rb index 37948ea3f86..80943877095 100644 --- a/spec/models/redirect_route_spec.rb +++ b/spec/models/redirect_route_spec.rb @@ -21,7 +21,7 @@ describe RedirectRoute do let!(:redirect5) { group.redirect_routes.create(path: 'gitlabb/test/baz') } it 'returns correct routes' do - expect(RedirectRoute.matching_path_and_descendants('gitlabb/test')).to match_array([redirect2, redirect3, redirect4, redirect5]) + expect(described_class.matching_path_and_descendants('gitlabb/test')).to match_array([redirect2, redirect3, redirect4, redirect5]) end end end diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb index 32cd5d1d944..bdacc60fb53 100644 --- a/spec/models/route_spec.rb +++ b/spec/models/route_spec.rb @@ -34,7 +34,7 @@ describe Route do context 'after create' do it 'calls #delete_conflicting_redirects' do route.destroy - new_route = Route.new(source: group, path: group.path) + new_route = described_class.new(source: group, path: group.path) expect(new_route).to receive(:delete_conflicting_redirects) new_route.save! end @@ -49,7 +49,7 @@ describe Route do let!(:another_group_nested) { create(:group, path: 'another', name: 'another', parent: similar_group) } it 'returns correct routes' do - expect(Route.inside_path('git_lab')).to match_array([nested_group.route, deep_nested_group.route]) + expect(described_class.inside_path('git_lab')).to match_array([nested_group.route, deep_nested_group.route]) end end diff --git a/spec/models/sent_notification_spec.rb b/spec/models/sent_notification_spec.rb index 823cdb853eb..8b6b02916ae 100644 --- a/spec/models/sent_notification_spec.rb +++ b/spec/models/sent_notification_spec.rb @@ -38,7 +38,7 @@ describe SentNotification do let(:issue) { create(:issue) } it 'creates a new SentNotification' do - expect { described_class.record(issue, user.id) }.to change { SentNotification.count }.by(1) + expect { described_class.record(issue, user.id) }.to change { described_class.count }.by(1) end end @@ -47,7 +47,7 @@ describe SentNotification do let(:note) { create(:diff_note_on_merge_request) } it 'creates a new SentNotification' do - expect { described_class.record_note(note, user.id) }.to change { SentNotification.count }.by(1) + expect { described_class.record_note(note, user.id) }.to change { described_class.count }.by(1) end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 105d41957c3..71aadbb4186 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -261,7 +261,7 @@ describe User do it "returns users with 2fa enabled via OTP" do user_with_2fa = create(:user, :two_factor_via_otp) user_without_2fa = create(:user) - users_with_two_factor = User.with_two_factor.pluck(:id) + users_with_two_factor = described_class.with_two_factor.pluck(:id) expect(users_with_two_factor).to include(user_with_2fa.id) expect(users_with_two_factor).not_to include(user_without_2fa.id) @@ -270,7 +270,7 @@ describe User do it "returns users with 2fa enabled via U2F" do user_with_2fa = create(:user, :two_factor_via_u2f) user_without_2fa = create(:user) - users_with_two_factor = User.with_two_factor.pluck(:id) + users_with_two_factor = described_class.with_two_factor.pluck(:id) expect(users_with_two_factor).to include(user_with_2fa.id) expect(users_with_two_factor).not_to include(user_without_2fa.id) @@ -279,7 +279,7 @@ describe User do it "returns users with 2fa enabled via OTP and U2F" do user_with_2fa = create(:user, :two_factor_via_otp, :two_factor_via_u2f) user_without_2fa = create(:user) - users_with_two_factor = User.with_two_factor.pluck(:id) + users_with_two_factor = described_class.with_two_factor.pluck(:id) expect(users_with_two_factor).to eq([user_with_2fa.id]) expect(users_with_two_factor).not_to include(user_without_2fa.id) @@ -290,7 +290,7 @@ describe User do it "excludes users with 2fa enabled via OTP" do user_with_2fa = create(:user, :two_factor_via_otp) user_without_2fa = create(:user) - users_without_two_factor = User.without_two_factor.pluck(:id) + users_without_two_factor = described_class.without_two_factor.pluck(:id) expect(users_without_two_factor).to include(user_without_2fa.id) expect(users_without_two_factor).not_to include(user_with_2fa.id) @@ -299,7 +299,7 @@ describe User do it "excludes users with 2fa enabled via U2F" do user_with_2fa = create(:user, :two_factor_via_u2f) user_without_2fa = create(:user) - users_without_two_factor = User.without_two_factor.pluck(:id) + users_without_two_factor = described_class.without_two_factor.pluck(:id) expect(users_without_two_factor).to include(user_without_2fa.id) expect(users_without_two_factor).not_to include(user_with_2fa.id) @@ -308,7 +308,7 @@ describe User do it "excludes users with 2fa enabled via OTP and U2F" do user_with_2fa = create(:user, :two_factor_via_otp, :two_factor_via_u2f) user_without_2fa = create(:user) - users_without_two_factor = User.without_two_factor.pluck(:id) + users_without_two_factor = described_class.without_two_factor.pluck(:id) expect(users_without_two_factor).to include(user_without_2fa.id) expect(users_without_two_factor).not_to include(user_with_2fa.id) @@ -324,8 +324,8 @@ describe User do create(:todo, user: current_user, author: user_2, state: :done) create(:todo, user: current_user, author: user_3, state: :pending) - expect(User.todo_authors(current_user.id, 'pending')).to eq [user_3] - expect(User.todo_authors(current_user.id, 'done')).to eq [user_2] + expect(described_class.todo_authors(current_user.id, 'pending')).to eq [user_3] + expect(described_class.todo_authors(current_user.id, 'done')).to eq [user_2] end end end @@ -609,39 +609,39 @@ describe User do let(:user) { double } it 'filters by active users by default' do - expect(User).to receive(:active).and_return([user]) + expect(described_class).to receive(:active).and_return([user]) - expect(User.filter(nil)).to include user + expect(described_class.filter(nil)).to include user end it 'filters by admins' do - expect(User).to receive(:admins).and_return([user]) + expect(described_class).to receive(:admins).and_return([user]) - expect(User.filter('admins')).to include user + expect(described_class.filter('admins')).to include user end it 'filters by blocked' do - expect(User).to receive(:blocked).and_return([user]) + expect(described_class).to receive(:blocked).and_return([user]) - expect(User.filter('blocked')).to include user + expect(described_class.filter('blocked')).to include user end it 'filters by two_factor_disabled' do - expect(User).to receive(:without_two_factor).and_return([user]) + expect(described_class).to receive(:without_two_factor).and_return([user]) - expect(User.filter('two_factor_disabled')).to include user + expect(described_class.filter('two_factor_disabled')).to include user end it 'filters by two_factor_enabled' do - expect(User).to receive(:with_two_factor).and_return([user]) + expect(described_class).to receive(:with_two_factor).and_return([user]) - expect(User.filter('two_factor_enabled')).to include user + expect(described_class.filter('two_factor_enabled')).to include user end it 'filters by wop' do - expect(User).to receive(:without_projects).and_return([user]) + expect(described_class).to receive(:without_projects).and_return([user]) - expect(User.filter('wop')).to include user + expect(described_class.filter('wop')).to include user end end @@ -662,9 +662,9 @@ describe User do project.request_access(user_without_project2) end - it { expect(User.without_projects).not_to include user } - it { expect(User.without_projects).to include user_without_project } - it { expect(User.without_projects).to include user_without_project2 } + it { expect(described_class.without_projects).not_to include user } + it { expect(described_class.without_projects).to include user_without_project } + it { expect(described_class.without_projects).to include user_without_project2 } end describe 'user creation' do @@ -680,7 +680,7 @@ describe User do end describe 'with defaults' do - let(:user) { User.new } + let(:user) { described_class.new } it "applies defaults to user" do expect(user.projects_limit).to eq(Gitlab.config.gitlab.default_projects_limit) @@ -690,7 +690,7 @@ describe User do end describe 'with default overrides' do - let(:user) { User.new(projects_limit: 123, can_create_group: false, can_create_team: true) } + let(:user) { described_class.new(projects_limit: 123, can_create_group: false, can_create_team: true) } it "applies defaults to user" do expect(user.projects_limit).to eq(123) @@ -740,18 +740,18 @@ describe User do it 'finds by primary email' do user = create(:user, email: 'foo@example.com') - expect(User.find_by_any_email(user.email)).to eq user + expect(described_class.find_by_any_email(user.email)).to eq user end it 'finds by secondary email' do email = create(:email, email: 'foo@example.com') user = email.user - expect(User.find_by_any_email(email.email)).to eq user + expect(described_class.find_by_any_email(email.email)).to eq user end it 'returns nil when nothing found' do - expect(User.find_by_any_email('')).to be_nil + expect(described_class.find_by_any_email('')).to be_nil end end @@ -899,12 +899,12 @@ describe User do let!(:user) { create(:user, username: username) } it 'gets the correct user' do - expect(User.by_login(user.email.upcase)).to eq user - expect(User.by_login(user.email)).to eq user - expect(User.by_login(username.downcase)).to eq user - expect(User.by_login(username)).to eq user - expect(User.by_login(nil)).to be_nil - expect(User.by_login('')).to be_nil + expect(described_class.by_login(user.email.upcase)).to eq user + expect(described_class.by_login(user.email)).to eq user + expect(described_class.by_login(username.downcase)).to eq user + expect(described_class.by_login(username)).to eq user + expect(described_class.by_login(nil)).to be_nil + expect(described_class.by_login('')).to be_nil end end @@ -938,12 +938,12 @@ describe User do let!(:route) { user.namespace.route } it 'returns the user' do - expect(User.find_by_full_path(route.path)).to eq(user) + expect(described_class.find_by_full_path(route.path)).to eq(user) end it 'is case-insensitive' do - expect(User.find_by_full_path(route.path.upcase)).to eq(user) - expect(User.find_by_full_path(route.path.downcase)).to eq(user) + expect(described_class.find_by_full_path(route.path.upcase)).to eq(user) + expect(described_class.find_by_full_path(route.path.downcase)).to eq(user) end end @@ -952,18 +952,18 @@ describe User do context 'without the follow_redirects option' do it 'returns nil' do - expect(User.find_by_full_path(redirect_route.path)).to eq(nil) + expect(described_class.find_by_full_path(redirect_route.path)).to eq(nil) end end context 'with the follow_redirects option set to true' do it 'returns the user' do - expect(User.find_by_full_path(redirect_route.path, follow_redirects: true)).to eq(user) + expect(described_class.find_by_full_path(redirect_route.path, follow_redirects: true)).to eq(user) end it 'is case-insensitive' do - expect(User.find_by_full_path(redirect_route.path.upcase, follow_redirects: true)).to eq(user) - expect(User.find_by_full_path(redirect_route.path.downcase, follow_redirects: true)).to eq(user) + expect(described_class.find_by_full_path(redirect_route.path.upcase, follow_redirects: true)).to eq(user) + expect(described_class.find_by_full_path(redirect_route.path.downcase, follow_redirects: true)).to eq(user) end end end @@ -971,12 +971,12 @@ describe User do context 'without a route or a redirect route matching the given path' do context 'without the follow_redirects option' do it 'returns nil' do - expect(User.find_by_full_path('unknown')).to eq(nil) + expect(described_class.find_by_full_path('unknown')).to eq(nil) end end context 'with the follow_redirects option set to true' do it 'returns nil' do - expect(User.find_by_full_path('unknown', follow_redirects: true)).to eq(nil) + expect(described_class.find_by_full_path('unknown', follow_redirects: true)).to eq(nil) end end end @@ -986,7 +986,7 @@ describe User do let!(:group) { create(:group, path: 'group_path', owner: user) } it 'returns nil' do - expect(User.find_by_full_path('group_path')).to eq(nil) + expect(described_class.find_by_full_path('group_path')).to eq(nil) end end @@ -994,7 +994,7 @@ describe User do let!(:group) { create(:group, path: 'group_path') } it 'returns nil' do - expect(User.find_by_full_path('group_path')).to eq(nil) + expect(described_class.find_by_full_path('group_path')).to eq(nil) end end end @@ -1044,7 +1044,7 @@ describe User do end describe '#requires_ldap_check?' do - let(:user) { User.new } + let(:user) { described_class.new } it 'is false when LDAP is disabled' do # Create a condition which would otherwise cause 'true' to be returned @@ -1215,7 +1215,7 @@ describe User do describe '#sort' do before do - User.delete_all + described_class.delete_all @user = create :user, created_at: Date.today, last_sign_in_at: Date.today, name: 'Alpha' @user1 = create :user, created_at: Date.today - 1, last_sign_in_at: Date.today - 1, name: 'Omega' @user2 = create :user, created_at: Date.today - 2, last_sign_in_at: nil, name: 'Beta' @@ -1223,34 +1223,34 @@ describe User do context 'when sort by recent_sign_in' do it 'sorts users by the recent sign-in time' do - expect(User.sort('recent_sign_in').first).to eq(@user) + expect(described_class.sort('recent_sign_in').first).to eq(@user) end it 'pushes users who never signed in to the end' do - expect(User.sort('recent_sign_in').third).to eq(@user2) + expect(described_class.sort('recent_sign_in').third).to eq(@user2) end end context 'when sort by oldest_sign_in' do it 'sorts users by the oldest sign-in time' do - expect(User.sort('oldest_sign_in').first).to eq(@user1) + expect(described_class.sort('oldest_sign_in').first).to eq(@user1) end it 'pushes users who never signed in to the end' do - expect(User.sort('oldest_sign_in').third).to eq(@user2) + expect(described_class.sort('oldest_sign_in').third).to eq(@user2) end end it 'sorts users in descending order by their creation time' do - expect(User.sort('created_desc').first).to eq(@user) + expect(described_class.sort('created_desc').first).to eq(@user) end it 'sorts users in ascending order by their creation time' do - expect(User.sort('created_asc').first).to eq(@user2) + expect(described_class.sort('created_asc').first).to eq(@user2) end it 'sorts users by id in descending order when nil is passed' do - expect(User.sort(nil).first).to eq(@user2) + expect(described_class.sort(nil).first).to eq(@user2) end end @@ -1770,7 +1770,7 @@ describe User do describe '.ghost' do it "creates a ghost user if one isn't already present" do - ghost = User.ghost + ghost = described_class.ghost expect(ghost).to be_ghost expect(ghost).to be_persisted @@ -1778,16 +1778,16 @@ describe User do it "does not create a second ghost user if one is already present" do expect do - User.ghost - User.ghost - end.to change { User.count }.by(1) - expect(User.ghost).to eq(User.ghost) + described_class.ghost + described_class.ghost + end.to change { described_class.count }.by(1) + expect(described_class.ghost).to eq(described_class.ghost) end context "when a regular user exists with the username 'ghost'" do it "creates a ghost user with a non-conflicting username" do create(:user, username: 'ghost') - ghost = User.ghost + ghost = described_class.ghost expect(ghost).to be_persisted expect(ghost.username).to eq('ghost1') @@ -1797,7 +1797,7 @@ describe User do context "when a regular user exists with the email 'ghost@example.com'" do it "creates a ghost user with a non-conflicting email" do create(:user, email: 'ghost@example.com') - ghost = User.ghost + ghost = described_class.ghost expect(ghost).to be_persisted expect(ghost.email).to eq('ghost1@example.com') @@ -1810,7 +1810,7 @@ describe User do end it 'creates a ghost user' do - expect(User.ghost).to be_persisted + expect(described_class.ghost).to be_persisted end end end @@ -1889,13 +1889,13 @@ describe User do context '.active' do before do - User.ghost + described_class.ghost create(:user, name: 'user', state: 'active') create(:user, name: 'user', state: 'blocked') end it 'only counts active and non internal users' do - expect(User.active.count).to eq(1) + expect(described_class.active.count).to eq(1) end end diff --git a/spec/models/wiki_directory_spec.rb b/spec/models/wiki_directory_spec.rb index c3c62c42b35..fb8575cfe2b 100644 --- a/spec/models/wiki_directory_spec.rb +++ b/spec/models/wiki_directory_spec.rb @@ -10,7 +10,7 @@ RSpec.describe WikiDirectory do describe '#initialize' do context 'when there are pages' do let(:pages) { [build(:wiki_page)] } - let(:directory) { WikiDirectory.new('/path_up_to/dir', pages) } + let(:directory) { described_class.new('/path_up_to/dir', pages) } it 'sets the slug attribute' do expect(directory.slug).to eq('/path_up_to/dir') @@ -22,7 +22,7 @@ RSpec.describe WikiDirectory do end context 'when there are no pages' do - let(:directory) { WikiDirectory.new('/path_up_to/dir') } + let(:directory) { described_class.new('/path_up_to/dir') } it 'sets the slug attribute' do expect(directory.slug).to eq('/path_up_to/dir') diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 77506a78459..90ad3cdeb93 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -5,13 +5,13 @@ describe WikiPage do let(:user) { project.owner } let(:wiki) { ProjectWiki.new(project, user) } - subject { WikiPage.new(wiki) } + subject { described_class.new(wiki) } describe '.group_by_directory' do context 'when there are no pages' do it 'returns an empty array' do - expect(WikiPage.group_by_directory(nil)).to eq([]) - expect(WikiPage.group_by_directory([])).to eq([]) + expect(described_class.group_by_directory(nil)).to eq([]) + expect(described_class.group_by_directory([])).to eq([]) end end @@ -39,7 +39,7 @@ describe WikiPage do it 'returns an array with pages and directories' do expected_grouped_entries = [page_1, dir_1, dir_1_1, dir_2] - grouped_entries = WikiPage.group_by_directory(wiki.pages) + grouped_entries = described_class.group_by_directory(wiki.pages) grouped_entries.each_with_index do |page_or_dir, i| expected_page_or_dir = expected_grouped_entries[i] @@ -56,7 +56,7 @@ describe WikiPage do expected_order = ['page_1', 'dir_1/page_2', 'dir_1/dir_1_1/page_3', 'dir_2/page_4', 'dir_2/page_5'] - grouped_entries = WikiPage.group_by_directory(wiki.pages) + grouped_entries = described_class.group_by_directory(wiki.pages) actual_order = grouped_entries.map do |page_or_dir| @@ -72,7 +72,7 @@ describe WikiPage do it 'removes hyphens from a name' do name = 'a-name--with-hyphens' - expect(WikiPage.unhyphenize(name)).to eq('a name with hyphens') + expect(described_class.unhyphenize(name)).to eq('a name with hyphens') end end @@ -81,7 +81,7 @@ describe WikiPage do before do create_page("test page", "test content") @page = wiki.wiki.paged("test page") - @wiki_page = WikiPage.new(wiki, @page, true) + @wiki_page = described_class.new(wiki, @page, true) end it "sets the slug attribute" do diff --git a/spec/policies/global_policy_spec.rb b/spec/policies/global_policy_spec.rb index 2a590e12232..a6bf70c1e09 100644 --- a/spec/policies/global_policy_spec.rb +++ b/spec/policies/global_policy_spec.rb @@ -4,7 +4,7 @@ describe GlobalPolicy do let(:current_user) { create(:user) } let(:user) { create(:user) } - subject { GlobalPolicy.new(current_user, [user]) } + subject { described_class.new(current_user, [user]) } describe "reading the list of users" do context "for a logged in user" do diff --git a/spec/policies/user_policy_spec.rb b/spec/policies/user_policy_spec.rb index 67ab239e4c8..6593a6ca3b9 100644 --- a/spec/policies/user_policy_spec.rb +++ b/spec/policies/user_policy_spec.rb @@ -4,7 +4,7 @@ describe UserPolicy do let(:current_user) { create(:user) } let(:user) { create(:user) } - subject { UserPolicy.new(current_user, user) } + subject { described_class.new(current_user, user) } describe "reading a user's information" do it { is_expected.to be_allowed(:read_user) } diff --git a/spec/services/create_release_service_spec.rb b/spec/services/create_release_service_spec.rb index e4d1c1a8f9d..ac0a0458f56 100644 --- a/spec/services/create_release_service_spec.rb +++ b/spec/services/create_release_service_spec.rb @@ -5,7 +5,7 @@ describe CreateReleaseService do let(:user) { create(:user) } let(:tag_name) { project.repository.tag_names.first } let(:description) { 'Awesome release!' } - let(:service) { CreateReleaseService.new(project, user) } + let(:service) { described_class.new(project, user) } it 'creates a new release' do result = service.execute(tag_name, description) diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb index 561b9d14a0f..00104ae1fd9 100644 --- a/spec/services/event_create_service_spec.rb +++ b/spec/services/event_create_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe EventCreateService do include UserActivitiesHelpers - let(:service) { EventCreateService.new } + let(:service) { described_class.new } describe 'Issues' do describe '#open_issue' do diff --git a/spec/services/git_hooks_service_spec.rb b/spec/services/git_hooks_service_spec.rb index f1242df7e93..3ce01a995b4 100644 --- a/spec/services/git_hooks_service_spec.rb +++ b/spec/services/git_hooks_service_spec.rb @@ -5,7 +5,7 @@ describe GitHooksService do let(:user) { create(:user) } let(:project) { create(:project, :repository) } - let(:service) { GitHooksService.new } + let(:service) { described_class.new } before do @blankrev = Gitlab::Git::BLANK_SHA diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb index d2baeb7b746..f877c145390 100644 --- a/spec/services/git_tag_push_service_spec.rb +++ b/spec/services/git_tag_push_service_spec.rb @@ -5,7 +5,7 @@ describe GitTagPushService do let(:user) { create(:user) } let(:project) { create(:project, :repository) } - let(:service) { GitTagPushService.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref) } + let(:service) { described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref) } let(:oldrev) { Gitlab::Git::BLANK_SHA } let(:newrev) { "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b" } # gitlab-test: git rev-parse refs/tags/v1.1.0 @@ -184,7 +184,7 @@ describe GitTagPushService do describe "Webhooks" do context "execute webhooks" do - let(:service) { GitTagPushService.new(project, user, oldrev: 'oldrev', newrev: 'newrev', ref: 'refs/tags/v1.0.0') } + let(:service) { described_class.new(project, user, oldrev: 'oldrev', newrev: 'newrev', ref: 'refs/tags/v1.0.0') } it "when pushing tags" do expect(project).to receive(:execute_hooks) diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb index b3ceb5428cd..3e7aa8c835c 100644 --- a/spec/services/groups/destroy_service_spec.rb +++ b/spec/services/groups/destroy_service_spec.rb @@ -100,7 +100,7 @@ describe Groups::DestroyService do # Kick off the initial group destroy in a new thread, so that # it doesn't share this spec's database transaction. - Thread.new { Groups::DestroyService.new(group, user).async_execute }.join(5) + Thread.new { described_class.new(group, user).async_execute }.join(5) group_record = run_with_new_database_connection do |conn| conn.execute("SELECT * FROM namespaces WHERE id = #{group.id}").first diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index 17d4a072e3d..eec2096fa34 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -488,7 +488,7 @@ describe Issues::UpdateService do context 'updating mentions' do let(:mentionable) { issue } - include_examples 'updating mentions', Issues::UpdateService + include_examples 'updating mentions', described_class end context 'duplicate issue' do diff --git a/spec/services/labels/create_service_spec.rb b/spec/services/labels/create_service_spec.rb index 0fa7b5199fe..ecb88653001 100644 --- a/spec/services/labels/create_service_spec.rb +++ b/spec/services/labels/create_service_spec.rb @@ -17,7 +17,7 @@ describe Labels::CreateService do context 'in a project' do context 'with color in hex-code' do it 'creates a label' do - label = Labels::CreateService.new(params_with(hex_color)).execute(project: project) + label = described_class.new(params_with(hex_color)).execute(project: project) expect(label).to be_persisted expect(label.color).to eq expected_saved_color @@ -26,7 +26,7 @@ describe Labels::CreateService do context 'with color in allowed name' do it 'creates a label' do - label = Labels::CreateService.new(params_with(named_color)).execute(project: project) + label = described_class.new(params_with(named_color)).execute(project: project) expect(label).to be_persisted expect(label.color).to eq expected_saved_color @@ -35,7 +35,7 @@ describe Labels::CreateService do context 'with color in up-case allowed name' do it 'creates a label' do - label = Labels::CreateService.new(params_with(upcase_color)).execute(project: project) + label = described_class.new(params_with(upcase_color)).execute(project: project) expect(label).to be_persisted expect(label.color).to eq expected_saved_color @@ -44,7 +44,7 @@ describe Labels::CreateService do context 'with color surrounded by spaces' do it 'creates a label' do - label = Labels::CreateService.new(params_with(spaced_color)).execute(project: project) + label = described_class.new(params_with(spaced_color)).execute(project: project) expect(label).to be_persisted expect(label.color).to eq expected_saved_color @@ -53,7 +53,7 @@ describe Labels::CreateService do context 'with unknown color' do it 'doesn\'t create a label' do - label = Labels::CreateService.new(params_with(unknown_color)).execute(project: project) + label = described_class.new(params_with(unknown_color)).execute(project: project) expect(label).not_to be_persisted end @@ -61,7 +61,7 @@ describe Labels::CreateService do context 'with no color' do it 'doesn\'t create a label' do - label = Labels::CreateService.new(params_with(no_color)).execute(project: project) + label = described_class.new(params_with(no_color)).execute(project: project) expect(label).not_to be_persisted end @@ -71,7 +71,7 @@ describe Labels::CreateService do context 'in a group' do context 'with color in hex-code' do it 'creates a label' do - label = Labels::CreateService.new(params_with(hex_color)).execute(group: group) + label = described_class.new(params_with(hex_color)).execute(group: group) expect(label).to be_persisted expect(label.color).to eq expected_saved_color @@ -80,7 +80,7 @@ describe Labels::CreateService do context 'with color in allowed name' do it 'creates a label' do - label = Labels::CreateService.new(params_with(named_color)).execute(group: group) + label = described_class.new(params_with(named_color)).execute(group: group) expect(label).to be_persisted expect(label.color).to eq expected_saved_color @@ -89,7 +89,7 @@ describe Labels::CreateService do context 'with color in up-case allowed name' do it 'creates a label' do - label = Labels::CreateService.new(params_with(upcase_color)).execute(group: group) + label = described_class.new(params_with(upcase_color)).execute(group: group) expect(label).to be_persisted expect(label.color).to eq expected_saved_color @@ -98,7 +98,7 @@ describe Labels::CreateService do context 'with color surrounded by spaces' do it 'creates a label' do - label = Labels::CreateService.new(params_with(spaced_color)).execute(group: group) + label = described_class.new(params_with(spaced_color)).execute(group: group) expect(label).to be_persisted expect(label.color).to eq expected_saved_color @@ -107,7 +107,7 @@ describe Labels::CreateService do context 'with unknown color' do it 'doesn\'t create a label' do - label = Labels::CreateService.new(params_with(unknown_color)).execute(group: group) + label = described_class.new(params_with(unknown_color)).execute(group: group) expect(label).not_to be_persisted end @@ -115,7 +115,7 @@ describe Labels::CreateService do context 'with no color' do it 'doesn\'t create a label' do - label = Labels::CreateService.new(params_with(no_color)).execute(group: group) + label = described_class.new(params_with(no_color)).execute(group: group) expect(label).not_to be_persisted end @@ -125,7 +125,7 @@ describe Labels::CreateService do context 'in admin area' do context 'with color in hex-code' do it 'creates a label' do - label = Labels::CreateService.new(params_with(hex_color)).execute(template: true) + label = described_class.new(params_with(hex_color)).execute(template: true) expect(label).to be_persisted expect(label.color).to eq expected_saved_color @@ -134,7 +134,7 @@ describe Labels::CreateService do context 'with color in allowed name' do it 'creates a label' do - label = Labels::CreateService.new(params_with(named_color)).execute(template: true) + label = described_class.new(params_with(named_color)).execute(template: true) expect(label).to be_persisted expect(label.color).to eq expected_saved_color @@ -143,7 +143,7 @@ describe Labels::CreateService do context 'with color in up-case allowed name' do it 'creates a label' do - label = Labels::CreateService.new(params_with(upcase_color)).execute(template: true) + label = described_class.new(params_with(upcase_color)).execute(template: true) expect(label).to be_persisted expect(label.color).to eq expected_saved_color @@ -152,7 +152,7 @@ describe Labels::CreateService do context 'with color surrounded by spaces' do it 'creates a label' do - label = Labels::CreateService.new(params_with(spaced_color)).execute(template: true) + label = described_class.new(params_with(spaced_color)).execute(template: true) expect(label).to be_persisted expect(label.color).to eq expected_saved_color @@ -161,7 +161,7 @@ describe Labels::CreateService do context 'with unknown color' do it 'doesn\'t create a label' do - label = Labels::CreateService.new(params_with(unknown_color)).execute(template: true) + label = described_class.new(params_with(unknown_color)).execute(template: true) expect(label).not_to be_persisted end @@ -169,7 +169,7 @@ describe Labels::CreateService do context 'with no color' do it 'doesn\'t create a label' do - label = Labels::CreateService.new(params_with(no_color)).execute(template: true) + label = described_class.new(params_with(no_color)).execute(template: true) expect(label).not_to be_persisted end diff --git a/spec/services/labels/update_service_spec.rb b/spec/services/labels/update_service_spec.rb index 83ea11f62a6..bb95fe20fbf 100644 --- a/spec/services/labels/update_service_spec.rb +++ b/spec/services/labels/update_service_spec.rb @@ -20,7 +20,7 @@ describe Labels::UpdateService do context 'with color in hex-code' do it 'updates the label' do - label = Labels::UpdateService.new(params_with(hex_color)).execute(@label) + label = described_class.new(params_with(hex_color)).execute(@label) expect(label).to be_valid expect(label.reload.color).to eq expected_saved_color @@ -29,7 +29,7 @@ describe Labels::UpdateService do context 'with color in allowed name' do it 'updates the label' do - label = Labels::UpdateService.new(params_with(named_color)).execute(@label) + label = described_class.new(params_with(named_color)).execute(@label) expect(label).to be_valid expect(label.reload.color).to eq expected_saved_color @@ -38,7 +38,7 @@ describe Labels::UpdateService do context 'with color in up-case allowed name' do it 'updates the label' do - label = Labels::UpdateService.new(params_with(upcase_color)).execute(@label) + label = described_class.new(params_with(upcase_color)).execute(@label) expect(label).to be_valid expect(label.reload.color).to eq expected_saved_color @@ -47,7 +47,7 @@ describe Labels::UpdateService do context 'with color surrounded by spaces' do it 'updates the label' do - label = Labels::UpdateService.new(params_with(spaced_color)).execute(@label) + label = described_class.new(params_with(spaced_color)).execute(@label) expect(label).to be_valid expect(label.reload.color).to eq expected_saved_color @@ -56,7 +56,7 @@ describe Labels::UpdateService do context 'with unknown color' do it 'doesn\'t update the label' do - label = Labels::UpdateService.new(params_with(unknown_color)).execute(@label) + label = described_class.new(params_with(unknown_color)).execute(@label) expect(label).not_to be_valid end @@ -64,7 +64,7 @@ describe Labels::UpdateService do context 'with no color' do it 'doesn\'t update the label' do - label = Labels::UpdateService.new(params_with(no_color)).execute(@label) + label = described_class.new(params_with(no_color)).execute(@label) expect(label).not_to be_valid end diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb index 0dcb636dd35..ea192e51f89 100644 --- a/spec/services/merge_requests/build_service_spec.rb +++ b/spec/services/merge_requests/build_service_spec.rb @@ -19,7 +19,7 @@ describe MergeRequests::BuildService do let(:commits) { nil } let(:service) do - MergeRequests::BuildService.new(project, user, + described_class.new(project, user, description: description, source_branch: source_branch, target_branch: target_branch, diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb index a8f24b744c2..e593bfeeaf7 100644 --- a/spec/services/merge_requests/merge_service_spec.rb +++ b/spec/services/merge_requests/merge_service_spec.rb @@ -13,7 +13,7 @@ describe MergeRequests::MergeService do describe '#execute' do context 'valid params' do - let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') } + let(:service) { described_class.new(project, user, commit_message: 'Awesome message') } before do allow(service).to receive(:execute_hooks) @@ -112,7 +112,7 @@ describe MergeRequests::MergeService do context 'closes related todos' do let(:merge_request) { create(:merge_request, assignee: user, author: user) } let(:project) { merge_request.project } - let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') } + let(:service) { described_class.new(project, user, commit_message: 'Awesome message') } let!(:todo) do create(:todo, :assigned, project: project, @@ -136,7 +136,7 @@ describe MergeRequests::MergeService do context 'source branch removal' do context 'when the source branch is protected' do let(:service) do - MergeRequests::MergeService.new(project, user, should_remove_source_branch: '1') + described_class.new(project, user, should_remove_source_branch: '1') end before do @@ -151,7 +151,7 @@ describe MergeRequests::MergeService do context 'when the source branch is the default branch' do let(:service) do - MergeRequests::MergeService.new(project, user, should_remove_source_branch: '1') + described_class.new(project, user, should_remove_source_branch: '1') end before do @@ -169,7 +169,7 @@ describe MergeRequests::MergeService do let(:service) do merge_request.merge_params['force_remove_source_branch'] = '1' merge_request.save! - MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') + described_class.new(project, user, commit_message: 'Awesome message') end it 'removes the source branch using the author user' do @@ -182,7 +182,7 @@ describe MergeRequests::MergeService do context 'when MR merger set the source branch to be removed' do let(:service) do - MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message', should_remove_source_branch: '1') + described_class.new(project, user, commit_message: 'Awesome message', should_remove_source_branch: '1') end it 'removes the source branch using the current user' do @@ -196,7 +196,7 @@ describe MergeRequests::MergeService do end context "error handling" do - let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') } + let(:service) { described_class.new(project, user, commit_message: 'Awesome message') } before do allow(Rails.logger).to receive(:error) diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 6c703dded36..2af2485eeed 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe MergeRequests::RefreshService do let(:project) { create(:project, :repository) } let(:user) { create(:user) } - let(:service) { MergeRequests::RefreshService } + let(:service) { described_class } describe '#execute' do before do diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index dddb526e58e..dd3ac9c4ac6 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -55,7 +55,7 @@ describe MergeRequests::UpdateService do } end - let(:service) { MergeRequests::UpdateService.new(project, user, opts) } + let(:service) { described_class.new(project, user, opts) } before do allow(service).to receive(:execute_hooks) @@ -145,7 +145,7 @@ describe MergeRequests::UpdateService do } end - let(:service) { MergeRequests::UpdateService.new(project, user, opts) } + let(:service) { described_class.new(project, user, opts) } context 'without pipeline' do before do @@ -205,7 +205,7 @@ describe MergeRequests::UpdateService do context 'with a non-authorised user' do let(:visitor) { create(:user) } - let(:service) { MergeRequests::UpdateService.new(project, visitor, opts) } + let(:service) { described_class.new(project, visitor, opts) } before do merge_request.update_attribute(:merge_error, 'Error') @@ -348,7 +348,7 @@ describe MergeRequests::UpdateService do opts = { label_ids: [label.id] } perform_enqueued_jobs do - @merge_request = MergeRequests::UpdateService.new(project, user, opts).execute(merge_request) + @merge_request = described_class.new(project, user, opts).execute(merge_request) end should_email(subscriber) @@ -364,7 +364,7 @@ describe MergeRequests::UpdateService do opts = { label_ids: [label.id, label2.id] } perform_enqueued_jobs do - @merge_request = MergeRequests::UpdateService.new(project, user, opts).execute(merge_request) + @merge_request = described_class.new(project, user, opts).execute(merge_request) end should_not_email(subscriber) @@ -375,7 +375,7 @@ describe MergeRequests::UpdateService do opts = { label_ids: [label2.id] } perform_enqueued_jobs do - @merge_request = MergeRequests::UpdateService.new(project, user, opts).execute(merge_request) + @merge_request = described_class.new(project, user, opts).execute(merge_request) end should_not_email(subscriber) @@ -386,7 +386,7 @@ describe MergeRequests::UpdateService do context 'updating mentions' do let(:mentionable) { merge_request } - include_examples 'updating mentions', MergeRequests::UpdateService + include_examples 'updating mentions', described_class end context 'when MergeRequest has tasks' do diff --git a/spec/services/milestones/close_service_spec.rb b/spec/services/milestones/close_service_spec.rb index 0838131a18a..fa0686d8061 100644 --- a/spec/services/milestones/close_service_spec.rb +++ b/spec/services/milestones/close_service_spec.rb @@ -11,7 +11,7 @@ describe Milestones::CloseService do describe '#execute' do before do - Milestones::CloseService.new(project, user, {}).execute(milestone) + described_class.new(project, user, {}).execute(milestone) end it { expect(milestone).to be_valid } diff --git a/spec/services/milestones/create_service_spec.rb b/spec/services/milestones/create_service_spec.rb index 0c2c41929d7..c6fe8e65912 100644 --- a/spec/services/milestones/create_service_spec.rb +++ b/spec/services/milestones/create_service_spec.rb @@ -14,7 +14,7 @@ describe Milestones::CreateService do description: 'Patch release to fix security issue' } - @milestone = Milestones::CreateService.new(project, user, opts).execute + @milestone = described_class.new(project, user, opts).execute end it { expect(@milestone).to be_valid } diff --git a/spec/services/notes/post_process_service_spec.rb b/spec/services/notes/post_process_service_spec.rb index 9044771939d..bf9320e5fce 100644 --- a/spec/services/notes/post_process_service_spec.rb +++ b/spec/services/notes/post_process_service_spec.rb @@ -21,7 +21,7 @@ describe Notes::PostProcessService do expect(project).to receive(:execute_hooks) expect(project).to receive(:execute_services) - Notes::PostProcessService.new(@note).execute + described_class.new(@note).execute end end end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 30fbe363fed..c98eb87b94e 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe NotificationService do include EmailHelpers - let(:notification) { NotificationService.new } + let(:notification) { described_class.new } let(:assignee) { create(:user) } around(:each) do |example| diff --git a/spec/services/pages_service_spec.rb b/spec/services/pages_service_spec.rb index 7b9c92c0ce7..f8db6900a0a 100644 --- a/spec/services/pages_service_spec.rb +++ b/spec/services/pages_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe PagesService do let(:build) { create(:ci_build) } let(:data) { Gitlab::DataBuilder::Build.build(build) } - let(:service) { PagesService.new(data) } + let(:service) { described_class.new(data) } before do allow(Gitlab.config.pages).to receive(:enabled).and_return(true) diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index 6851c96a6d6..85b05ef6d05 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -81,7 +81,7 @@ describe Projects::DestroyService do before do new_user = create(:user) project.team.add_user(new_user, Gitlab::Access::DEVELOPER) - allow_any_instance_of(Projects::DestroyService).to receive(:flush_caches).and_raise(::Redis::CannotConnectError) + allow_any_instance_of(described_class).to receive(:flush_caches).and_raise(::Redis::CannotConnectError) end it 'keeps project team intact upon an error' do @@ -114,7 +114,7 @@ describe Projects::DestroyService do context 'errors' do context 'when `remove_legacy_registry_tags` fails' do before do - expect_any_instance_of(Projects::DestroyService) + expect_any_instance_of(described_class) .to receive(:remove_legacy_registry_tags).and_return(false) end @@ -123,7 +123,7 @@ describe Projects::DestroyService do context 'when `remove_repository` fails' do before do - expect_any_instance_of(Projects::DestroyService) + expect_any_instance_of(described_class) .to receive(:remove_repository).and_return(false) end diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index 53668c07285..ae32e85b2a7 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -37,7 +37,7 @@ describe Projects::TransferService do end it 'executes system hooks' do - expect_any_instance_of(Projects::TransferService).to receive(:execute_system_hooks) + expect_any_instance_of(described_class).to receive(:execute_system_hooks) transfer_project(project, user, group) end @@ -80,7 +80,7 @@ describe Projects::TransferService do end it "doesn't run system hooks" do - expect_any_instance_of(Projects::TransferService).not_to receive(:execute_system_hooks) + expect_any_instance_of(described_class).not_to receive(:execute_system_hooks) attempt_project_transfer end diff --git a/spec/services/projects/unlink_fork_service_spec.rb b/spec/services/projects/unlink_fork_service_spec.rb index cd5b443b043..2ae8d5f7c54 100644 --- a/spec/services/projects/unlink_fork_service_spec.rb +++ b/spec/services/projects/unlink_fork_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::UnlinkForkService do - subject { Projects::UnlinkForkService.new(fork_project, user) } + subject { described_class.new(fork_project, user) } let(:fork_link) { create(:forked_project_link) } let(:fork_project) { fork_link.forked_to_project } diff --git a/spec/services/repair_ldap_blocked_user_service_spec.rb b/spec/services/repair_ldap_blocked_user_service_spec.rb index 57a6162206c..bf79cfe74b7 100644 --- a/spec/services/repair_ldap_blocked_user_service_spec.rb +++ b/spec/services/repair_ldap_blocked_user_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe RepairLdapBlockedUserService do let(:user) { create(:omniauth_user, provider: 'ldapmain', state: 'ldap_blocked') } let(:identity) { user.ldap_identity } - subject(:service) { RepairLdapBlockedUserService.new(user) } + subject(:service) { described_class.new(user) } describe '#execute' do it 'changes to normal block after destroying last ldap identity' do diff --git a/spec/services/search/global_service_spec.rb b/spec/services/search/global_service_spec.rb index c376cdeb725..de921573b1a 100644 --- a/spec/services/search/global_service_spec.rb +++ b/spec/services/search/global_service_spec.rb @@ -16,7 +16,7 @@ describe Search::GlobalService do describe '#execute' do context 'unauthenticated' do it 'returns public projects only' do - results = Search::GlobalService.new(nil, search: "searchable").execute + results = described_class.new(nil, search: "searchable").execute expect(results.objects('projects')).to match_array [public_project] end @@ -24,19 +24,19 @@ describe Search::GlobalService do context 'authenticated' do it 'returns public, internal and private projects' do - results = Search::GlobalService.new(user, search: "searchable").execute + results = described_class.new(user, search: "searchable").execute expect(results.objects('projects')).to match_array [public_project, found_project, internal_project] end it 'returns only public & internal projects' do - results = Search::GlobalService.new(internal_user, search: "searchable").execute + results = described_class.new(internal_user, search: "searchable").execute expect(results.objects('projects')).to match_array [internal_project, public_project] end it 'namespace name is searchable' do - results = Search::GlobalService.new(user, search: found_project.namespace.path).execute + results = described_class.new(user, search: found_project.namespace.path).execute expect(results.objects('projects')).to match_array [found_project] end diff --git a/spec/services/search/group_service_spec.rb b/spec/services/search/group_service_spec.rb index 3315d74658e..cb3f02d2883 100644 --- a/spec/services/search/group_service_spec.rb +++ b/spec/services/search/group_service_spec.rb @@ -17,7 +17,7 @@ describe Search::GroupService do let!(:project2) { create(:empty_project, :internal, namespace: nested_group, name: "Inner #{term} 2") } let!(:project3) { create(:empty_project, :internal, namespace: nested_group.parent, name: "Outer #{term}") } - let(:results) { Search::GroupService.new(user, search_group, search: term).execute } + let(:results) { described_class.new(user, search_group, search: term).execute } subject { results.objects('projects') } context 'in parent group' do diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb index a6ec324fe8f..a6ef7561bc8 100644 --- a/spec/services/search_service_spec.rb +++ b/spec/services/search_service_spec.rb @@ -22,7 +22,7 @@ describe SearchService do describe '#project' do context 'when the project is accessible' do it 'returns the project' do - project = SearchService.new(user, project_id: accessible_project.id).project + project = described_class.new(user, project_id: accessible_project.id).project expect(project).to eq accessible_project end @@ -31,7 +31,7 @@ describe SearchService do search_project = create :empty_project search_project.add_guest(user) - project = SearchService.new(user, project_id: search_project.id).project + project = described_class.new(user, project_id: search_project.id).project expect(project).to eq search_project end @@ -39,7 +39,7 @@ describe SearchService do context 'when the project is not accessible' do it 'returns nil' do - project = SearchService.new(user, project_id: inaccessible_project.id).project + project = described_class.new(user, project_id: inaccessible_project.id).project expect(project).to be_nil end @@ -47,7 +47,7 @@ describe SearchService do context 'when there is no project_id' do it 'returns nil' do - project = SearchService.new(user).project + project = described_class.new(user).project expect(project).to be_nil end @@ -57,7 +57,7 @@ describe SearchService do describe '#group' do context 'when the group is accessible' do it 'returns the group' do - group = SearchService.new(user, group_id: accessible_group.id).group + group = described_class.new(user, group_id: accessible_group.id).group expect(group).to eq accessible_group end @@ -65,7 +65,7 @@ describe SearchService do context 'when the group is not accessible' do it 'returns nil' do - group = SearchService.new(user, group_id: inaccessible_group.id).group + group = described_class.new(user, group_id: inaccessible_group.id).group expect(group).to be_nil end @@ -73,7 +73,7 @@ describe SearchService do context 'when there is no group_id' do it 'returns nil' do - group = SearchService.new(user).group + group = described_class.new(user).group expect(group).to be_nil end @@ -83,7 +83,7 @@ describe SearchService do describe '#show_snippets?' do context 'when :snippets is \'true\'' do it 'returns true' do - show_snippets = SearchService.new(user, snippets: 'true').show_snippets? + show_snippets = described_class.new(user, snippets: 'true').show_snippets? expect(show_snippets).to be_truthy end @@ -91,7 +91,7 @@ describe SearchService do context 'when :snippets is not \'true\'' do it 'returns false' do - show_snippets = SearchService.new(user, snippets: 'tru').show_snippets? + show_snippets = described_class.new(user, snippets: 'tru').show_snippets? expect(show_snippets).to be_falsey end @@ -99,7 +99,7 @@ describe SearchService do context 'when :snippets is missing' do it 'returns false' do - show_snippets = SearchService.new(user).show_snippets? + show_snippets = described_class.new(user).show_snippets? expect(show_snippets).to be_falsey end @@ -110,7 +110,7 @@ describe SearchService do context 'with accessible project_id' do context 'and allowed scope' do it 'returns the specified scope' do - scope = SearchService.new(user, project_id: accessible_project.id, scope: 'notes').scope + scope = described_class.new(user, project_id: accessible_project.id, scope: 'notes').scope expect(scope).to eq 'notes' end @@ -118,7 +118,7 @@ describe SearchService do context 'and disallowed scope' do it 'returns the default scope' do - scope = SearchService.new(user, project_id: accessible_project.id, scope: 'projects').scope + scope = described_class.new(user, project_id: accessible_project.id, scope: 'projects').scope expect(scope).to eq 'blobs' end @@ -126,7 +126,7 @@ describe SearchService do context 'and no scope' do it 'returns the default scope' do - scope = SearchService.new(user, project_id: accessible_project.id).scope + scope = described_class.new(user, project_id: accessible_project.id).scope expect(scope).to eq 'blobs' end @@ -136,7 +136,7 @@ describe SearchService do context 'with \'true\' snippets' do context 'and allowed scope' do it 'returns the specified scope' do - scope = SearchService.new(user, snippets: 'true', scope: 'snippet_titles').scope + scope = described_class.new(user, snippets: 'true', scope: 'snippet_titles').scope expect(scope).to eq 'snippet_titles' end @@ -144,7 +144,7 @@ describe SearchService do context 'and disallowed scope' do it 'returns the default scope' do - scope = SearchService.new(user, snippets: 'true', scope: 'projects').scope + scope = described_class.new(user, snippets: 'true', scope: 'projects').scope expect(scope).to eq 'snippet_blobs' end @@ -152,7 +152,7 @@ describe SearchService do context 'and no scope' do it 'returns the default scope' do - scope = SearchService.new(user, snippets: 'true').scope + scope = described_class.new(user, snippets: 'true').scope expect(scope).to eq 'snippet_blobs' end @@ -162,7 +162,7 @@ describe SearchService do context 'with no project_id, no snippets' do context 'and allowed scope' do it 'returns the specified scope' do - scope = SearchService.new(user, scope: 'issues').scope + scope = described_class.new(user, scope: 'issues').scope expect(scope).to eq 'issues' end @@ -170,7 +170,7 @@ describe SearchService do context 'and disallowed scope' do it 'returns the default scope' do - scope = SearchService.new(user, scope: 'blobs').scope + scope = described_class.new(user, scope: 'blobs').scope expect(scope).to eq 'projects' end @@ -178,7 +178,7 @@ describe SearchService do context 'and no scope' do it 'returns the default scope' do - scope = SearchService.new(user).scope + scope = described_class.new(user).scope expect(scope).to eq 'projects' end @@ -189,7 +189,7 @@ describe SearchService do describe '#search_results' do context 'with accessible project_id' do it 'returns an instance of Gitlab::ProjectSearchResults' do - search_results = SearchService.new( + search_results = described_class.new( user, project_id: accessible_project.id, scope: 'notes', @@ -201,7 +201,7 @@ describe SearchService do context 'with accessible project_id and \'true\' snippets' do it 'returns an instance of Gitlab::ProjectSearchResults' do - search_results = SearchService.new( + search_results = described_class.new( user, project_id: accessible_project.id, snippets: 'true', @@ -214,7 +214,7 @@ describe SearchService do context 'with \'true\' snippets' do it 'returns an instance of Gitlab::SnippetSearchResults' do - search_results = SearchService.new( + search_results = described_class.new( user, snippets: 'true', search: snippet.content).search_results @@ -225,7 +225,7 @@ describe SearchService do context 'with no project_id and no snippets' do it 'returns an instance of Gitlab::SearchResults' do - search_results = SearchService.new( + search_results = described_class.new( user, search: public_project.name).search_results @@ -237,7 +237,7 @@ describe SearchService do describe '#search_objects' do context 'with accessible project_id' do it 'returns objects in the project' do - search_objects = SearchService.new( + search_objects = described_class.new( user, project_id: accessible_project.id, scope: 'notes', @@ -249,7 +249,7 @@ describe SearchService do context 'with accessible project_id and \'true\' snippets' do it 'returns objects in the project' do - search_objects = SearchService.new( + search_objects = described_class.new( user, project_id: accessible_project.id, snippets: 'true', @@ -262,7 +262,7 @@ describe SearchService do context 'with \'true\' snippets' do it 'returns objects in snippets' do - search_objects = SearchService.new( + search_objects = described_class.new( user, snippets: 'true', search: snippet.content).search_objects @@ -273,7 +273,7 @@ describe SearchService do context 'with accessible group_id' do it 'returns objects in the group' do - search_objects = SearchService.new( + search_objects = described_class.new( user, group_id: accessible_group.id, search: group_project.name).search_objects @@ -284,7 +284,7 @@ describe SearchService do context 'with no project_id, group_id or snippets' do it 'returns objects in global' do - search_objects = SearchService.new( + search_objects = described_class.new( user, search: public_project.name).search_objects diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb index 8cbffc8ec61..230e40de9e0 100644 --- a/spec/services/todo_service_spec.rb +++ b/spec/services/todo_service_spec.rb @@ -873,21 +873,21 @@ describe TodoService do create(:todo, :mentioned, user: john_doe, target: issue, project: project) todos = TodosFinder.new(john_doe, {}).execute - expect { TodoService.new.mark_todos_as_done(todos, john_doe) } + expect { described_class.new.mark_todos_as_done(todos, john_doe) } .to change { john_doe.todos.done.count }.from(0).to(1) end it 'marks an array of todos as done' do todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project) - expect { TodoService.new.mark_todos_as_done([todo], john_doe) } + expect { described_class.new.mark_todos_as_done([todo], john_doe) } .to change { todo.reload.state }.from('pending').to('done') end it 'returns the ids of updated todos' do # Needed on API todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project) - expect(TodoService.new.mark_todos_as_done([todo], john_doe)).to eq([todo.id]) + expect(described_class.new.mark_todos_as_done([todo], john_doe)).to eq([todo.id]) end context 'when some of the todos are done already' do @@ -895,23 +895,23 @@ describe TodoService do let!(:second_todo) { create(:todo, :mentioned, user: john_doe, target: another_issue, project: project) } it 'returns the ids of those still pending' do - TodoService.new.mark_pending_todos_as_done(issue, john_doe) + described_class.new.mark_pending_todos_as_done(issue, john_doe) - expect(TodoService.new.mark_todos_as_done(Todo.all, john_doe)).to eq([second_todo.id]) + expect(described_class.new.mark_todos_as_done(Todo.all, john_doe)).to eq([second_todo.id]) end it 'returns an empty array 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) + described_class.new.mark_pending_todos_as_done(issue, john_doe) + described_class.new.mark_pending_todos_as_done(another_issue, john_doe) - expect(TodoService.new.mark_todos_as_done(Todo.all, john_doe)).to eq([]) + expect(described_class.new.mark_todos_as_done(Todo.all, john_doe)).to eq([]) end end it 'caches the number of todos of a user', :use_clean_rails_memory_store_caching do create(:todo, :mentioned, user: john_doe, target: issue, project: project) todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project) - TodoService.new.mark_todos_as_done([todo], john_doe) + described_class.new.mark_todos_as_done([todo], john_doe) expect_any_instance_of(TodosFinder).not_to receive(:execute) diff --git a/spec/services/update_release_service_spec.rb b/spec/services/update_release_service_spec.rb index fecd50e6ca0..dc2d0e2d47a 100644 --- a/spec/services/update_release_service_spec.rb +++ b/spec/services/update_release_service_spec.rb @@ -6,7 +6,7 @@ describe UpdateReleaseService do let(:tag_name) { project.repository.tag_names.first } let(:description) { 'Awesome release!' } let(:new_description) { 'The best release!' } - let(:service) { UpdateReleaseService.new(project, user) } + let(:service) { described_class.new(project, user) } context 'with an existing release' do let(:create_service) { CreateReleaseService.new(project, user) } diff --git a/spec/services/web_hook_service_spec.rb b/spec/services/web_hook_service_spec.rb index 8d91050b924..a5de86a0835 100644 --- a/spec/services/web_hook_service_spec.rb +++ b/spec/services/web_hook_service_spec.rb @@ -12,7 +12,7 @@ describe WebHookService do let(:data) do { before: 'oldrev', after: 'newrev', ref: 'ref' } end - let(:service_instance) { WebHookService.new(project_hook, data, 'push_hooks') } + let(:service_instance) { described_class.new(project_hook, data, 'push_hooks') } describe '#execute' do before(:each) do @@ -114,7 +114,7 @@ describe WebHookService do context 'should not log ServiceHooks' do let(:service_hook) { create(:service_hook) } - let(:service_instance) { WebHookService.new(service_hook, data, 'service_hook') } + let(:service_instance) { described_class.new(service_hook, data, 'service_hook') } before do WebMock.stub_request(:post, service_hook.url).to_return(status: 200, body: 'Success') @@ -131,7 +131,7 @@ describe WebHookService do it 'enqueue WebHookWorker' do expect(Sidekiq::Client).to receive(:enqueue).with(WebHookWorker, project_hook.id, data, 'push_hooks') - WebHookService.new(project_hook, data, 'push_hooks').async_execute + described_class.new(project_hook, data, 'push_hooks').async_execute end end end -- cgit v1.2.1 From 3265ac4f39e6760340722c524113ac1691fdcf8d Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Thu, 27 Jul 2017 14:27:15 +0200 Subject: Update prometheus client gem to fix problems with PID handling following unicorn forking new workers. --- Gemfile | 2 +- Gemfile.lock | 4 ++-- changelogs/unreleased/pawel-prometheus_client_pid_reuse_error.yml | 4 ++++ config/unicorn.rb.example | 4 ++++ 4 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/pawel-prometheus_client_pid_reuse_error.yml diff --git a/Gemfile b/Gemfile index 43109de1b45..a2343f81929 100644 --- a/Gemfile +++ b/Gemfile @@ -286,7 +286,7 @@ group :metrics do gem 'influxdb', '~> 0.2', require: false # Prometheus - gem 'prometheus-client-mmap', '~>0.7.0.beta9' + gem 'prometheus-client-mmap', '~>0.7.0.beta11' gem 'raindrops', '~> 0.18' end diff --git a/Gemfile.lock b/Gemfile.lock index 6c2ac9368f2..031741437e3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -595,7 +595,7 @@ GEM premailer-rails (1.9.7) actionmailer (>= 3, < 6) premailer (~> 1.7, >= 1.7.9) - prometheus-client-mmap (0.7.0.beta10) + prometheus-client-mmap (0.7.0.beta11) mmap2 (~> 2.2, >= 2.2.7) pry (0.10.4) coderay (~> 1.1.0) @@ -1047,7 +1047,7 @@ DEPENDENCIES pg (~> 0.18.2) poltergeist (~> 1.9.0) premailer-rails (~> 1.9.7) - prometheus-client-mmap (~> 0.7.0.beta9) + prometheus-client-mmap (~> 0.7.0.beta11) pry-byebug (~> 3.4.1) pry-rails (~> 0.3.4) rack-attack (~> 4.4.1) diff --git a/changelogs/unreleased/pawel-prometheus_client_pid_reuse_error.yml b/changelogs/unreleased/pawel-prometheus_client_pid_reuse_error.yml new file mode 100644 index 00000000000..dfff4c23308 --- /dev/null +++ b/changelogs/unreleased/pawel-prometheus_client_pid_reuse_error.yml @@ -0,0 +1,4 @@ +--- +title: Fix Prometheus client PID reuse bug +merge_request: 13130 +author: diff --git a/config/unicorn.rb.example b/config/unicorn.rb.example index 40a16a32359..cc10da2bd88 100644 --- a/config/unicorn.rb.example +++ b/config/unicorn.rb.example @@ -121,6 +121,10 @@ after_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection + # reset prometheus client, this will cause any opened metrics files to be closed + defined?(::Prometheus::Client.reinitialize_on_pid_change) && + Prometheus::Client.reinitialize_on_pid_change + # if preload_app is true, then you may also want to check and # restart any other shared sockets/descriptors such as Memcached, # and Redis. TokyoCabinet file handles are safe to reuse -- cgit v1.2.1 From 14b9c83f41efeaa8f5468dcb81986d118e74d2d3 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Wed, 26 Jul 2017 13:13:52 +0200 Subject: Added lazy class to Blob Images + Diffs --- app/views/projects/blob/viewers/_image.html.haml | 2 +- app/views/projects/diffs/viewers/_image.html.haml | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/views/projects/blob/viewers/_image.html.haml b/app/views/projects/blob/viewers/_image.html.haml index 1650aa8197f..82c1239147c 100644 --- a/app/views/projects/blob/viewers/_image.html.haml +++ b/app/views/projects/blob/viewers/_image.html.haml @@ -1,2 +1,2 @@ .file-content.image_file - %img{ 'data-src': blob_raw_url, alt: viewer.blob.name } + %img.lazy{ 'data-src': blob_raw_url, alt: viewer.blob.name } diff --git a/app/views/projects/diffs/viewers/_image.html.haml b/app/views/projects/diffs/viewers/_image.html.haml index 05877ceed3d..3068916f4c3 100644 --- a/app/views/projects/diffs/viewers/_image.html.haml +++ b/app/views/projects/diffs/viewers/_image.html.haml @@ -8,7 +8,7 @@ .image %span.wrap .frame{ class: (diff_file.deleted_file? ? 'deleted' : 'added') } - %img{ 'data-src': blob_raw_path, alt: diff_file.file_path } + %img.lazy{ 'data-src': blob_raw_path, alt: diff_file.file_path } %p.image-info= number_to_human_size(blob.size) - else .image @@ -16,7 +16,7 @@ %span.wrap .frame.deleted %a{ href: project_blob_path(@project, tree_join(diff_file.old_content_sha, diff_file.old_path)) } - %img{ 'data-src': old_blob_raw_path, alt: diff_file.old_path } + %img.lazy{ 'data-src': old_blob_raw_path, alt: diff_file.old_path } %p.image-info.hide %span.meta-filesize= number_to_human_size(old_blob.size) | @@ -28,7 +28,7 @@ %span.wrap .frame.added %a{ href: project_blob_path(@project, tree_join(diff_file.content_sha, diff_file.new_path)) } - %img{ 'data-src': blob_raw_path, alt: diff_file.new_path } + %img.lazy{ 'data-src': blob_raw_path, alt: diff_file.new_path } %p.image-info.hide %span.meta-filesize= number_to_human_size(blob.size) | @@ -41,10 +41,10 @@ .swipe.view.hide .swipe-frame .frame.deleted - %img{ 'data-src': old_blob_raw_path, alt: diff_file.old_path } + %img.lazy{ 'data-src': old_blob_raw_path, alt: diff_file.old_path } .swipe-wrap .frame.added - %img{ 'data-src': blob_raw_path, alt: diff_file.new_path } + %img.lazy{ 'data-src': blob_raw_path, alt: diff_file.new_path } %span.swipe-bar %span.top-handle %span.bottom-handle @@ -52,9 +52,9 @@ .onion-skin.view.hide .onion-skin-frame .frame.deleted - %img{ 'data-src': old_blob_raw_path, alt: diff_file.old_path } + %img.lazy{ 'data-src': old_blob_raw_path, alt: diff_file.old_path } .frame.added - %img{ 'data-src': blob_raw_path, alt: diff_file.new_path } + %img.lazy{ 'data-src': blob_raw_path, alt: diff_file.new_path } .controls .transparent .drag-track -- cgit v1.2.1 From 710d0435f7c54801ff9efafc14a46095f3c83244 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Thu, 27 Jul 2017 11:23:34 +0200 Subject: Changed Images in Blob Viewer to image_tag Updated documentation about the lazy class --- app/views/projects/blob/viewers/_image.html.haml | 2 +- app/views/projects/diffs/viewers/_image.html.haml | 14 +++++++------- doc/development/fe_guide/performance.md | 5 +++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/views/projects/blob/viewers/_image.html.haml b/app/views/projects/blob/viewers/_image.html.haml index 82c1239147c..5fd22a59217 100644 --- a/app/views/projects/blob/viewers/_image.html.haml +++ b/app/views/projects/blob/viewers/_image.html.haml @@ -1,2 +1,2 @@ .file-content.image_file - %img.lazy{ 'data-src': blob_raw_url, alt: viewer.blob.name } + = image_tag(blob_raw_url, alt: viewer.blob.name) diff --git a/app/views/projects/diffs/viewers/_image.html.haml b/app/views/projects/diffs/viewers/_image.html.haml index 3068916f4c3..aa004a739d7 100644 --- a/app/views/projects/diffs/viewers/_image.html.haml +++ b/app/views/projects/diffs/viewers/_image.html.haml @@ -8,7 +8,7 @@ .image %span.wrap .frame{ class: (diff_file.deleted_file? ? 'deleted' : 'added') } - %img.lazy{ 'data-src': blob_raw_path, alt: diff_file.file_path } + = image_tag(blob_raw_path, alt: diff_file.file_path) %p.image-info= number_to_human_size(blob.size) - else .image @@ -16,7 +16,7 @@ %span.wrap .frame.deleted %a{ href: project_blob_path(@project, tree_join(diff_file.old_content_sha, diff_file.old_path)) } - %img.lazy{ 'data-src': old_blob_raw_path, alt: diff_file.old_path } + = image_tag(old_blob_raw_path, alt: diff_file.old_path) %p.image-info.hide %span.meta-filesize= number_to_human_size(old_blob.size) | @@ -28,7 +28,7 @@ %span.wrap .frame.added %a{ href: project_blob_path(@project, tree_join(diff_file.content_sha, diff_file.new_path)) } - %img.lazy{ 'data-src': blob_raw_path, alt: diff_file.new_path } + = image_tag(blob_raw_path, alt: diff_file.new_path) %p.image-info.hide %span.meta-filesize= number_to_human_size(blob.size) | @@ -41,10 +41,10 @@ .swipe.view.hide .swipe-frame .frame.deleted - %img.lazy{ 'data-src': old_blob_raw_path, alt: diff_file.old_path } + = image_tag(old_blob_raw_path, alt: diff_file.old_path) .swipe-wrap .frame.added - %img.lazy{ 'data-src': blob_raw_path, alt: diff_file.new_path } + = image_tag(blob_raw_path, alt: diff_file.new_path) %span.swipe-bar %span.top-handle %span.bottom-handle @@ -52,9 +52,9 @@ .onion-skin.view.hide .onion-skin-frame .frame.deleted - %img.lazy{ 'data-src': old_blob_raw_path, alt: diff_file.old_path } + = image_tag(old_blob_raw_path, alt: diff_file.old_path) .frame.added - %img.lazy{ 'data-src': blob_raw_path, alt: diff_file.new_path } + = image_tag(blob_raw_path, alt: diff_file.new_path) .controls .transparent .drag-track diff --git a/doc/development/fe_guide/performance.md b/doc/development/fe_guide/performance.md index f25313d6cff..14ac1133cc0 100644 --- a/doc/development/fe_guide/performance.md +++ b/doc/development/fe_guide/performance.md @@ -29,11 +29,12 @@ To improve the time to first render we are using lazy loading for images. This w the actual image source on the `data-src` attribute. After the HTML is rendered and JavaScript is loaded, the value of `data-src` will be moved to `src` automatically if the image is in the current viewport. -* Prepare images in HTML for lazy loading by renaming the `src` attribute to `data-src` +* Prepare images in HTML for lazy loading by renaming the `src` attribute to `data-src` AND adding the class `lazy` * If you are using the Rails `image_tag` helper, all images will be lazy-loaded by default unless `lazy: false` is provided. If you are asynchronously adding content which contains lazy images then you need to call the function -`gl.lazyLoader.searchLazyImages()` which will search for lazy images and load them if needed. +`gl.lazyLoader.searchLazyImages()` which will search for lazy images and load them if needed. +But in general it should be handled automatically through a `MutationObserver` in the lazy loading function. ## Reducing Asset Footprint -- cgit v1.2.1 From a94e91a45b8fb861060a901b5bcfa218d597a208 Mon Sep 17 00:00:00 2001 From: Alex Lossent Date: Thu, 27 Jul 2017 14:52:42 +0200 Subject: Log web hook execution timeout events If a web hook HTTP request is sent but no response comes within a certain time (10s by default), the hook execution fails and will be retried. This commit makes such timeouts visible in the web hook log, like connection timeouts already are. Also log "no route to host" errors. --- app/services/web_hook_service.rb | 2 +- spec/services/web_hook_service_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/web_hook_service.rb b/app/services/web_hook_service.rb index a5110a23cad..27c3ba197ac 100644 --- a/app/services/web_hook_service.rb +++ b/app/services/web_hook_service.rb @@ -44,7 +44,7 @@ class WebHookService http_status: response.code, message: response.to_s } - rescue SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout => e + rescue SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Net::OpenTimeout, Net::ReadTimeout => e log_execution( trigger: hook_name, url: hook.url, diff --git a/spec/services/web_hook_service_spec.rb b/spec/services/web_hook_service_spec.rb index 7ff37c22963..76f35443e55 100644 --- a/spec/services/web_hook_service_spec.rb +++ b/spec/services/web_hook_service_spec.rb @@ -53,7 +53,7 @@ describe WebHookService, services: true do end it 'handles exceptions' do - exceptions = [SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout] + exceptions = [SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Net::OpenTimeout, Net::ReadTimeout] exceptions.each do |exception_class| exception = exception_class.new('Exception message') -- cgit v1.2.1 From 2cc1658489fe2d2de4052db36b21a788195cfc1b Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 25 Jul 2017 10:41:43 +0200 Subject: Project New moved to external File --- app/assets/javascripts/projects/project_new.js | 43 ++++++++++++++++++++++++ app/views/projects/new.html.haml | 45 ++------------------------ config/webpack.config.js | 1 + 3 files changed, 46 insertions(+), 43 deletions(-) create mode 100644 app/assets/javascripts/projects/project_new.js diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js new file mode 100644 index 00000000000..4f87df8e160 --- /dev/null +++ b/app/assets/javascripts/projects/project_new.js @@ -0,0 +1,43 @@ +document.addEventListener('DOMContentLoaded', () => { + const importBtnTooltip = 'Please enter a valid project name.'; + const $importBtnWrapper = $('.import_gitlab_project'); + + $('.how_to_import_link').bind('click', function (e) { + e.preventDefault(); + $(this).next('.modal').show(); + }); + + $('.modal-header .close').bind('click', () => { + $('.modal').hide(); + }); + + $('.btn_import_gitlab_project').bind('click', () => { + const importHref = $('a.btn_import_gitlab_project').attr('href'); + $('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$('#project_path').val()}`); + }); + + $('.btn_import_gitlab_project').attr('disabled', $('#project_path').val().trim().length === 0); + $importBtnWrapper.attr('title', importBtnTooltip); + + $('#new_project').submit(() => { + const $path = $('#project_path'); + $path.val($path.val().trim()); + }); + + $('#project_path').keyup(() => { + if ($(this).val().trim().length !== 0) { + $('.btn_import_gitlab_project').attr('disabled', false); + $importBtnWrapper.attr('title', ''); + $importBtnWrapper.removeClass('has-tooltip'); + } else { + $('.btn_import_gitlab_project').attr('disabled', true); + $importBtnWrapper.addClass('has-tooltip'); + } + }); + + $('#project_import_url').disable(); + $('.import_git').click(() => { + const $projectImportUrl = $('#project_import_url'); + $projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled')); + }); +}); diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 87cc23fc649..25109f0f414 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -4,6 +4,8 @@ - page_title 'New Project' - header_title "Projects", dashboard_projects_path - visibility_level = params.dig(:project, :visibility_level) || default_project_visibility +- content_for :page_specific_javascripts do + = webpack_bundle_tag 'project_new' .project-edit-container .project-edit-errors @@ -111,46 +113,3 @@ %i.fa.fa-spinner.fa-spin Creating project & repository. %p Please wait a moment, this page will automatically refresh when ready. - -:javascript - var importBtnTooltip = "Please enter a valid project name."; - var $importBtnWrapper = $('.import_gitlab_project'); - - $('.how_to_import_link').bind('click', function (e) { - e.preventDefault(); - var import_modal = $(this).next(".modal").show(); - }); - - $('.modal-header .close').bind('click', function() { - $(".modal").hide(); - }); - - $('.btn_import_gitlab_project').bind('click', function() { - var _href = $("a.btn_import_gitlab_project").attr("href"); - $(".btn_import_gitlab_project").attr("href", _href + '?namespace_id=' + $("#project_namespace_id").val() + '&path=' + $("#project_path").val()); - }); - - $('.btn_import_gitlab_project').attr('disabled', $('#project_path').val().trim().length === 0); - $importBtnWrapper.attr('title', importBtnTooltip); - - $('#new_project').submit(function(){ - var $path = $('#project_path'); - $path.val($path.val().trim()); - }); - - $('#project_path').keyup(function(){ - if($(this).val().trim().length !== 0) { - $('.btn_import_gitlab_project').attr('disabled', false); - $importBtnWrapper.attr('title',''); - $importBtnWrapper.removeClass('has-tooltip'); - } else { - $('.btn_import_gitlab_project').attr('disabled',true); - $importBtnWrapper.addClass('has-tooltip'); - } - }); - - $('#project_import_url').disable(); - $('.import_git').click(function( event ) { - $projectImportUrl = $('#project_import_url'); - $projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled')); - }); diff --git a/config/webpack.config.js b/config/webpack.config.js index f08daa2fddb..902c60b84cb 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -56,6 +56,7 @@ var config = { pipelines: './pipelines/pipelines_bundle.js', pipelines_details: './pipelines/pipeline_details_bundle.js', profile: './profile/profile_bundle.js', + project_new: './projects/project_new.js', prometheus_metrics: './prometheus_metrics', protected_branches: './protected_branches', protected_tags: './protected_tags', -- cgit v1.2.1 From 364a2a2759feb28c3dbc006b79ec81c123aba7bc Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 25 Jul 2017 10:44:45 +0200 Subject: Set New Tags to ignore Inline JS --- app/views/projects/tags/new.html.haml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml index f1bbaf40387..ceb2547034a 100644 --- a/app/views/projects/tags/new.html.haml +++ b/app/views/projects/tags/new.html.haml @@ -41,6 +41,7 @@ = button_tag 'Create tag', class: 'btn btn-create', tabindex: 3 = link_to 'Cancel', project_tags_path(@project), class: 'btn btn-cancel' +-# haml-lint:disable InlineJavaScript :javascript window.gl = window.gl || { }; window.gl.availableRefs = #{@project.repository.ref_names.to_json}; -- cgit v1.2.1 From 24d9142cabcf8b09a9954c2ccd9b429c86ba683d Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 25 Jul 2017 10:51:21 +0200 Subject: Inline JS of Wiki Sidebar to dispatcher --- app/assets/javascripts/dispatcher.js | 1 + app/views/projects/wikis/_sidebar.html.haml | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 1dc6edacfed..99d9ab3cacd 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -511,6 +511,7 @@ import PerformanceBar from './performance_bar'; shortcut_handler = new ShortcutsWiki(); new ZenMode(); new gl.GLForm($('.wiki-form'), true); + new Sidebar(); break; case 'snippets': shortcut_handler = new ShortcutsNavigation(); diff --git a/app/views/projects/wikis/_sidebar.html.haml b/app/views/projects/wikis/_sidebar.html.haml index 62873d3aa66..e71ce1f357f 100644 --- a/app/views/projects/wikis/_sidebar.html.haml +++ b/app/views/projects/wikis/_sidebar.html.haml @@ -19,6 +19,3 @@ More Pages = render 'projects/wikis/new' - -:javascript - new Sidebar(); -- cgit v1.2.1 From 395e34bd0fd32e6f8d8145f14d71ea3c1350b46f Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 25 Jul 2017 11:45:08 +0200 Subject: Changed the data for New Tag to a script block --- app/assets/javascripts/dispatcher.js | 2 +- app/views/projects/tags/new.html.haml | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 99d9ab3cacd..6aa0d10ea5d 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -250,7 +250,7 @@ import PerformanceBar from './performance_bar'; case 'projects:tags:new': new ZenMode(); new gl.GLForm($('.tag-form'), true); - new RefSelectDropdown($('.js-branch-select'), window.gl.availableRefs); + new RefSelectDropdown($('.js-branch-select'), JSON.parse(document.getElementById('availableRefs').innerHTML)); break; case 'projects:snippets:new': case 'projects:snippets:edit': diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml index ceb2547034a..521b4d927bc 100644 --- a/app/views/projects/tags/new.html.haml +++ b/app/views/projects/tags/new.html.haml @@ -40,8 +40,4 @@ .form-actions = button_tag 'Create tag', class: 'btn btn-create', tabindex: 3 = link_to 'Cancel', project_tags_path(@project), class: 'btn btn-cancel' - --# haml-lint:disable InlineJavaScript -:javascript - window.gl = window.gl || { }; - window.gl.availableRefs = #{@project.repository.ref_names.to_json}; +%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe -- cgit v1.2.1 From 84a3ab25fe9dd9002c8c47976d7f17fc2a897071 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 25 Jul 2017 12:12:30 +0200 Subject: Moved Inline JS for Pipelines Charts + new Pipeline to dispatcher --- app/assets/javascripts/dispatcher.js | 4 ++++ .../javascripts/pipelines/pipelines_times.js | 27 ++++++++++++++++++++++ .../projects/pipelines/charts/_pipeline_times.haml | 5 ++++ app/views/projects/pipelines/new.html.haml | 5 +--- config/webpack.config.js | 3 ++- 5 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 app/assets/javascripts/pipelines/pipelines_times.js diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 6aa0d10ea5d..4c84a88274d 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -8,6 +8,7 @@ /* global LabelsSelect */ /* global MilestoneSelect */ /* global Commit */ +/* global NewBranchForm */ /* global NotificationsForm */ /* global NotificationsDropdown */ /* global GroupAvatar */ @@ -316,6 +317,9 @@ import PerformanceBar from './performance_bar'; case 'projects:edit': setupProjectEdit(); break; + case 'projects:pipelines:new': + new NewBranchForm($('.js-new-pipeline-form'), JSON.parse(document.getElementById('availableRefs').innerHTML)); + break; case 'projects:pipelines:builds': case 'projects:pipelines:failures': case 'projects:pipelines:show': diff --git a/app/assets/javascripts/pipelines/pipelines_times.js b/app/assets/javascripts/pipelines/pipelines_times.js new file mode 100644 index 00000000000..b5e7a0e53d9 --- /dev/null +++ b/app/assets/javascripts/pipelines/pipelines_times.js @@ -0,0 +1,27 @@ +import Chart from 'vendor/Chart'; + +document.addEventListener('DOMContentLoaded', () => { + const chartData = JSON.parse(document.getElementById('pipelinesTimesChartsData').innerHTML); + const data = { + labels: chartData.labels, + datasets: [{ + fillColor: 'rgba(220,220,220,0.5)', + strokeColor: 'rgba(220,220,220,1)', + barStrokeWidth: 1, + barValueSpacing: 1, + barDatasetSpacing: 1, + data: chartData.values, + }], + }; + const ctx = $('#build_timesChart').get(0).getContext('2d'); + const options = { + scaleOverlay: true, + responsive: true, + maintainAspectRatio: false, + }; + if (window.innerWidth < 768) { + // Scale fonts if window width lower than 768px (iPad portrait) + options.scaleFontSize = 8; + } + new Chart(ctx).Bar(data, options); +}); diff --git a/app/views/projects/pipelines/charts/_pipeline_times.haml b/app/views/projects/pipelines/charts/_pipeline_times.haml index 1292f580a81..55477a922e7 100644 --- a/app/views/projects/pipelines/charts/_pipeline_times.haml +++ b/app/views/projects/pipelines/charts/_pipeline_times.haml @@ -1,9 +1,14 @@ +- content_for :page_specific_javascripts do + = webpack_bundle_tag('pipelines_times') + %div %p.light = _("Commit duration in minutes for last 30 commits") %canvas#build_timesChart{ height: 200 } +%script#pipelinesTimesChartsData{ type: "application/json" }= { :labels => @charts[:pipeline_times].labels, :values => @charts[:pipeline_times].pipeline_times }.to_json.html_safe + :javascript var data = { labels : #{@charts[:pipeline_times].labels.to_json}, diff --git a/app/views/projects/pipelines/new.html.haml b/app/views/projects/pipelines/new.html.haml index c966df62856..4ad37d0e882 100644 --- a/app/views/projects/pipelines/new.html.haml +++ b/app/views/projects/pipelines/new.html.haml @@ -20,7 +20,4 @@ = f.submit 'Create pipeline', class: 'btn btn-create', tabindex: 3 = link_to 'Cancel', project_pipelines_path(@project), class: 'btn btn-cancel' -:javascript - var availableRefs = #{@project.repository.ref_names.to_json}; - - new NewBranchForm($('.js-new-pipeline-form'), availableRefs) +%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe diff --git a/config/webpack.config.js b/config/webpack.config.js index 902c60b84cb..9a9399cbf02 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -54,7 +54,8 @@ var config = { notebook_viewer: './blob/notebook_viewer.js', pdf_viewer: './blob/pdf_viewer.js', pipelines: './pipelines/pipelines_bundle.js', - pipelines_details: './pipelines/pipeline_details_bundle.js', + pipelines_details: './pipelines/pipeline_details_bundle.js', + pipelines_times: './pipelines/pipelines_times.js', profile: './profile/profile_bundle.js', project_new: './projects/project_new.js', prometheus_metrics: './prometheus_metrics', -- cgit v1.2.1 From 57d2db4c0730a75c4ac932adc3613949550a0279 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 25 Jul 2017 12:48:45 +0200 Subject: TreeContent moved to external JS --- app/assets/javascripts/dispatcher.js | 3 +++ app/views/projects/tree/_tree_content.html.haml | 8 +------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 4c84a88274d..bb15b14bb98 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -373,6 +373,9 @@ import PerformanceBar from './performance_bar'; shortcut_handler = new ShortcutsNavigation(); new TreeView(); new BlobViewer(); + $('#tree-slider').waitForImages(function() { + gl.utils.ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath); + }); break; case 'projects:find_file:show': shortcut_handler = true; diff --git a/app/views/projects/tree/_tree_content.html.haml b/app/views/projects/tree/_tree_content.html.haml index 6560bd5ab3f..bdd1623c075 100644 --- a/app/views/projects/tree/_tree_content.html.haml +++ b/app/views/projects/tree/_tree_content.html.haml @@ -1,4 +1,4 @@ -.tree-content-holder +.tree-content-holder.js-tree-content{ 'data-logs-path': escape_javascript(@logs_path)} .table-holder %table.table#tree-slider{ class: "table_#{@hex_path} tree-table" } %thead @@ -22,9 +22,3 @@ - if can_edit_tree? = render 'projects/blob/upload', title: _('Upload New File'), placeholder: _('Upload New File'), button_title: _('Upload file'), form_path: project_create_blob_path(@project, @id), method: :post = render 'projects/blob/new_dir' - -:javascript - // Load last commit log for each file in tree - $('#tree-slider').waitForImages(function() { - gl.utils.ajaxGet("#{escape_javascript(@logs_path)}"); - }); -- cgit v1.2.1 From f149a76b2d9ab8f5249a8d613c4c3f9153201d3e Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 25 Jul 2017 13:19:27 +0200 Subject: Converted Pipelines Charts --- .../javascripts/pipelines/pipelines_charts.js | 38 ++++++++++++++++++++++ .../projects/pipelines/charts/_pipeline_times.haml | 22 ------------- .../projects/pipelines/charts/_pipelines.haml | 36 +++++--------------- config/webpack.config.js | 1 + 4 files changed, 47 insertions(+), 50 deletions(-) create mode 100644 app/assets/javascripts/pipelines/pipelines_charts.js diff --git a/app/assets/javascripts/pipelines/pipelines_charts.js b/app/assets/javascripts/pipelines/pipelines_charts.js new file mode 100644 index 00000000000..001faf4be33 --- /dev/null +++ b/app/assets/javascripts/pipelines/pipelines_charts.js @@ -0,0 +1,38 @@ +import Chart from 'vendor/Chart'; + +document.addEventListener('DOMContentLoaded', () => { + const chartData = JSON.parse(document.getElementById('pipelinesChartsData').innerHTML); + const buildChart = (chartScope) => { + const data = { + labels: chartScope.labels, + datasets: [{ + fillColor: '#7f8fa4', + strokeColor: '#7f8fa4', + pointColor: '#7f8fa4', + pointStrokeColor: '#EEE', + data: chartScope.totalValues, + }, + { + fillColor: '#44aa22', + strokeColor: '#44aa22', + pointColor: '#44aa22', + pointStrokeColor: '#fff', + data: chartScope.successValues, + }, + ], + }; + const ctx = $(`#${chartScope.scope}Chart`).get(0).getContext('2d'); + const options = { + scaleOverlay: true, + responsive: true, + maintainAspectRatio: false, + }; + if (window.innerWidth < 768) { + // Scale fonts if window width lower than 768px (iPad portrait) + options.scaleFontSize = 8; + } + new Chart(ctx).Line(data, options); + }; + + chartData.forEach(scope => buildChart(scope)); +}); diff --git a/app/views/projects/pipelines/charts/_pipeline_times.haml b/app/views/projects/pipelines/charts/_pipeline_times.haml index 55477a922e7..a5dbd1b1532 100644 --- a/app/views/projects/pipelines/charts/_pipeline_times.haml +++ b/app/views/projects/pipelines/charts/_pipeline_times.haml @@ -8,25 +8,3 @@ %canvas#build_timesChart{ height: 200 } %script#pipelinesTimesChartsData{ type: "application/json" }= { :labels => @charts[:pipeline_times].labels, :values => @charts[:pipeline_times].pipeline_times }.to_json.html_safe - -:javascript - var data = { - labels : #{@charts[:pipeline_times].labels.to_json}, - datasets : [ - { - fillColor : "rgba(220,220,220,0.5)", - strokeColor : "rgba(220,220,220,1)", - barStrokeWidth: 1, - barValueSpacing: 1, - barDatasetSpacing: 1, - data : #{@charts[:pipeline_times].pipeline_times.to_json} - } - ] - } - var ctx = $("#build_timesChart").get(0).getContext("2d"); - var options = { scaleOverlay: true, responsive: true, maintainAspectRatio: false }; - if (window.innerWidth < 768) { - // Scale fonts if window width lower than 768px (iPad portrait) - options.scaleFontSize = 8 - } - new Chart(ctx).Bar(data, options); diff --git a/app/views/projects/pipelines/charts/_pipelines.haml b/app/views/projects/pipelines/charts/_pipelines.haml index be884448087..9de22b39d23 100644 --- a/app/views/projects/pipelines/charts/_pipelines.haml +++ b/app/views/projects/pipelines/charts/_pipelines.haml @@ -1,3 +1,6 @@ +- content_for :page_specific_javascripts do + = webpack_bundle_tag('pipelines_charts') + %h4= _("Pipelines charts") %p   @@ -26,31 +29,8 @@ = _("Jobs for last year") %canvas#yearChart.padded{ height: 250 } -- [:week, :month, :year].each do |scope| - :javascript - var data = { - labels : #{@charts[scope].labels.to_json}, - datasets : [ - { - fillColor : "#7f8fa4", - strokeColor : "#7f8fa4", - pointColor : "#7f8fa4", - pointStrokeColor : "#EEE", - data : #{@charts[scope].total.to_json} - }, - { - fillColor : "#44aa22", - strokeColor : "#44aa22", - pointColor : "#44aa22", - pointStrokeColor : "#fff", - data : #{@charts[scope].success.to_json} - } - ] - } - var ctx = $("##{scope}Chart").get(0).getContext("2d"); - var options = { scaleOverlay: true, responsive: true, maintainAspectRatio: false }; - if (window.innerWidth < 768) { - // Scale fonts if window width lower than 768px (iPad portrait) - options.scaleFontSize = 8 - } - new Chart(ctx).Line(data, options); +%script#pipelinesChartsData{ type: "application/json" } + - chartData = [] + - [:week, :month, :year].each do |scope| + - chartData.push({ 'scope' => scope, 'labels' => @charts[scope].labels, 'totalValues' => @charts[scope].total, 'successValues' => @charts[scope].success }) + = chartData.to_json.html_safe diff --git a/config/webpack.config.js b/config/webpack.config.js index 9a9399cbf02..18d28256a8b 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -54,6 +54,7 @@ var config = { notebook_viewer: './blob/notebook_viewer.js', pdf_viewer: './blob/pdf_viewer.js', pipelines: './pipelines/pipelines_bundle.js', + pipelines_charts: './pipelines/pipelines_charts.js', pipelines_details: './pipelines/pipeline_details_bundle.js', pipelines_times: './pipelines/pipelines_times.js', profile: './profile/profile_bundle.js', -- cgit v1.2.1 From cad80263ade171b9e6bb80156d3222323e6be691 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 25 Jul 2017 15:02:24 +0200 Subject: Fixes New Project Bug --- app/assets/javascripts/projects/project_new.js | 6 +++--- app/views/projects/pipelines/charts/_pipelines.haml | 2 +- app/views/projects/tree/_tree_content.html.haml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js index 4f87df8e160..e3fcf218cfb 100644 --- a/app/assets/javascripts/projects/project_new.js +++ b/app/assets/javascripts/projects/project_new.js @@ -2,9 +2,9 @@ document.addEventListener('DOMContentLoaded', () => { const importBtnTooltip = 'Please enter a valid project name.'; const $importBtnWrapper = $('.import_gitlab_project'); - $('.how_to_import_link').bind('click', function (e) { + $('.how_to_import_link').bind('click', (e) => { e.preventDefault(); - $(this).next('.modal').show(); + $('.how_to_import_link').next('.modal').show(); }); $('.modal-header .close').bind('click', () => { @@ -25,7 +25,7 @@ document.addEventListener('DOMContentLoaded', () => { }); $('#project_path').keyup(() => { - if ($(this).val().trim().length !== 0) { + if ($('#project_path').val().trim().length !== 0) { $('.btn_import_gitlab_project').attr('disabled', false); $importBtnWrapper.attr('title', ''); $importBtnWrapper.removeClass('has-tooltip'); diff --git a/app/views/projects/pipelines/charts/_pipelines.haml b/app/views/projects/pipelines/charts/_pipelines.haml index 9de22b39d23..02f1ef4b6da 100644 --- a/app/views/projects/pipelines/charts/_pipelines.haml +++ b/app/views/projects/pipelines/charts/_pipelines.haml @@ -30,7 +30,7 @@ %canvas#yearChart.padded{ height: 250 } %script#pipelinesChartsData{ type: "application/json" } - - chartData = [] + - chartData = [] - [:week, :month, :year].each do |scope| - chartData.push({ 'scope' => scope, 'labels' => @charts[scope].labels, 'totalValues' => @charts[scope].total, 'successValues' => @charts[scope].success }) = chartData.to_json.html_safe diff --git a/app/views/projects/tree/_tree_content.html.haml b/app/views/projects/tree/_tree_content.html.haml index bdd1623c075..ac3c784375d 100644 --- a/app/views/projects/tree/_tree_content.html.haml +++ b/app/views/projects/tree/_tree_content.html.haml @@ -1,4 +1,4 @@ -.tree-content-holder.js-tree-content{ 'data-logs-path': escape_javascript(@logs_path)} +.tree-content-holder.js-tree-content{ 'data-logs-path': escape_javascript(@logs_path) } .table-holder %table.table#tree-slider{ class: "table_#{@hex_path} tree-table" } %thead -- cgit v1.2.1 From 79793dd16294a5f75b790d53c6f5aae5a33774f4 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 25 Jul 2017 16:10:48 +0200 Subject: Due to more async loading the tests could fail, trying to fix it with wait_for_requests --- spec/features/projects/user_browses_files_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/features/projects/user_browses_files_spec.rb b/spec/features/projects/user_browses_files_spec.rb index 263a3a29a66..d2a57981379 100644 --- a/spec/features/projects/user_browses_files_spec.rb +++ b/spec/features/projects/user_browses_files_spec.rb @@ -87,6 +87,8 @@ describe 'User browses files' do visit(project_tree_path(project, "'test'")) + wait_for_requests + expect(page).to have_css('.tree-commit-link', visible: true) expect(page).not_to have_content('Loading commit data...') end @@ -100,6 +102,8 @@ describe 'User browses files' do visit(project_tree_path(project, 'fix/.testdir')) + wait_for_requests + expect(page).to have_css('.tree-commit-link', visible: true) expect(page).not_to have_content('Loading commit data...') end -- cgit v1.2.1 From 49f2c6c11c0d3428afcf67e2f6f10748af5641a8 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 25 Jul 2017 16:10:48 +0200 Subject: Revert "Due to more async loading the tests could fail, trying to fix it with wait_for_requests" This reverts commit 0c33f384bb2fd2bd97efa4d3fec2888393683fb1. --- spec/features/projects/user_browses_files_spec.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/spec/features/projects/user_browses_files_spec.rb b/spec/features/projects/user_browses_files_spec.rb index d2a57981379..263a3a29a66 100644 --- a/spec/features/projects/user_browses_files_spec.rb +++ b/spec/features/projects/user_browses_files_spec.rb @@ -87,8 +87,6 @@ describe 'User browses files' do visit(project_tree_path(project, "'test'")) - wait_for_requests - expect(page).to have_css('.tree-commit-link', visible: true) expect(page).not_to have_content('Loading commit data...') end @@ -102,8 +100,6 @@ describe 'User browses files' do visit(project_tree_path(project, 'fix/.testdir')) - wait_for_requests - expect(page).to have_css('.tree-commit-link', visible: true) expect(page).not_to have_content('Loading commit data...') end -- cgit v1.2.1 From f05bcf54ab25728e53bca8e24ceb8c7db2157cfa Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Wed, 26 Jul 2017 10:07:39 +0200 Subject: Maybe that fixes the escaping in the URL --- app/views/projects/tree/_tree_content.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/tree/_tree_content.html.haml b/app/views/projects/tree/_tree_content.html.haml index ac3c784375d..3fb2fba9973 100644 --- a/app/views/projects/tree/_tree_content.html.haml +++ b/app/views/projects/tree/_tree_content.html.haml @@ -1,4 +1,4 @@ -.tree-content-holder.js-tree-content{ 'data-logs-path': escape_javascript(@logs_path) } +.tree-content-holder.js-tree-content{ 'data-logs-path': "#{escape_javascript(@logs_path)}" } .table-holder %table.table#tree-slider{ class: "table_#{@hex_path} tree-table" } %thead -- cgit v1.2.1 From bede3e5f31b79f0cd423895ecb1341dae0eb8e35 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Wed, 26 Jul 2017 19:37:20 +0200 Subject: Fixed the strange escaping --- app/views/projects/tree/_tree_content.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/tree/_tree_content.html.haml b/app/views/projects/tree/_tree_content.html.haml index 3fb2fba9973..b5221bcfc82 100644 --- a/app/views/projects/tree/_tree_content.html.haml +++ b/app/views/projects/tree/_tree_content.html.haml @@ -1,4 +1,4 @@ -.tree-content-holder.js-tree-content{ 'data-logs-path': "#{escape_javascript(@logs_path)}" } +.tree-content-holder.js-tree-content{ 'data-logs-path': @logs_path }" } .table-holder %table.table#tree-slider{ class: "table_#{@hex_path} tree-table" } %thead -- cgit v1.2.1 From b762b254335372881ede4f6aa8c4dbb0aaf655da Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Thu, 27 Jul 2017 09:29:55 +0200 Subject: Left a bracket in the line :-/ --- app/views/projects/tree/_tree_content.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/tree/_tree_content.html.haml b/app/views/projects/tree/_tree_content.html.haml index b5221bcfc82..820b947804e 100644 --- a/app/views/projects/tree/_tree_content.html.haml +++ b/app/views/projects/tree/_tree_content.html.haml @@ -1,4 +1,4 @@ -.tree-content-holder.js-tree-content{ 'data-logs-path': @logs_path }" } +.tree-content-holder.js-tree-content{ 'data-logs-path': @logs_path } .table-holder %table.table#tree-slider{ class: "table_#{@hex_path} tree-table" } %thead -- cgit v1.2.1 From 35259a4f48e19a19437be10c02eb8398c108d507 Mon Sep 17 00:00:00 2001 From: Hiroyuki Sato Date: Thu, 27 Jul 2017 22:00:06 +0900 Subject: Encapsulate the commit.sha logic --- app/models/wiki_page.rb | 6 +++++- app/views/projects/wikis/_form.html.haml | 2 +- spec/models/wiki_page_spec.rb | 30 ++++++++++++++++++++++++++---- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 12f12674e56..148998bc9be 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -138,6 +138,10 @@ class WikiPage versions.first end + def last_commit_sha + commit&.sha + end + # Returns the Date that this latest version was # created on. def created_at @@ -196,7 +200,7 @@ class WikiPage @attributes[:content] = new_content @attributes[:format] = format - if last_commit_sha && last_commit_sha != commit.sha + if last_commit_sha && last_commit_sha != self.last_commit_sha raise PageChangedError.new("You are attempting to update a page that has changed since you started editing it.") end diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml index 5c335ba306b..adb8d5aaecb 100644 --- a/app/views/projects/wikis/_form.html.haml +++ b/app/views/projects/wikis/_form.html.haml @@ -5,7 +5,7 @@ = f.hidden_field :title, value: @page.title - if @page.persisted? - = f.hidden_field :last_commit_sha, value: @page.commit.sha + = f.hidden_field :last_commit_sha, value: @page.last_commit_sha .form-group .col-sm-12= f.label :format, class: 'control-label-full-width' .col-sm-12 diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 732a32684e8..e2cdff5fa22 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -211,15 +211,13 @@ describe WikiPage, models: true do context 'with same last commit sha' do it 'returns true' do - last_commit_sha = @page.commit.sha - expect(@page.update('more content', last_commit_sha: last_commit_sha)).to be_truthy + expect(@page.update('more content', last_commit_sha: @page.last_commit_sha)).to be_truthy end end context 'with different last commit sha' do it 'raises exception' do - last_commit_sha = 'xxx' - expect { @page.update('more content', last_commit_sha: last_commit_sha) }.to raise_error(WikiPage::PageChangedError) + expect { @page.update('more content', last_commit_sha: 'xxx') }.to raise_error(WikiPage::PageChangedError) end end end @@ -345,6 +343,30 @@ describe WikiPage, models: true do end end + describe '#last_commit_sha' do + before do + create_page("Update", "content") + @page = wiki.find_page("Update") + end + + after do + destroy_page("Update") + end + + it 'returns commit sha' do + expect(@page.last_commit_sha).to eq @page.commit.sha + end + + it 'is changed after page updated' do + last_commit_sha_before_update = @page.last_commit_sha + + @page.update("new content") + @page = wiki.find_page("Update") + + expect(@page.last_commit_sha).not_to eq last_commit_sha_before_update + end + end + private def remove_temp_repo(path) -- cgit v1.2.1 From 817d9558febde484f23f623bd66d8c861ebc8236 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Tue, 14 Feb 2017 19:01:30 -0500 Subject: Prototype key verification --- Gemfile | 3 +++ Gemfile.lock | 3 +++ app/models/commit.rb | 12 ++++++++++++ app/views/projects/commit/_commit_box.html.haml | 1 + app/views/projects/commit/_signature.html.haml | 4 ++++ app/views/projects/commits/_commit.html.haml | 1 + lib/gitlab/git/commit.rb | 4 ++++ 7 files changed, 28 insertions(+) create mode 100644 app/views/projects/commit/_signature.html.haml diff --git a/Gemfile b/Gemfile index 43109de1b45..93934d03e42 100644 --- a/Gemfile +++ b/Gemfile @@ -58,6 +58,9 @@ gem 'validates_hostname', '~> 1.0.6' # Browser detection gem 'browser', '~> 2.2' +# GPG +gem 'gpgme' + # LDAP Auth # GitLab fork with several improvements to original library. For full list of changes # see https://github.com/intridea/omniauth-ldap/compare/master...gitlabhq:master diff --git a/Gemfile.lock b/Gemfile.lock index 6c2ac9368f2..77e87e2885f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -332,6 +332,8 @@ GEM multi_json (~> 1.11) os (~> 0.9) signet (~> 0.7) + gpgme (2.0.13) + mini_portile2 (~> 2.1) grape (0.19.2) activesupport builder @@ -983,6 +985,7 @@ DEPENDENCIES gollum-rugged_adapter (~> 0.4.4) gon (~> 6.1.0) google-api-client (~> 0.8.6) + gpgme grape (~> 0.19.2) grape-entity (~> 0.6.0) grape-route-helpers (~> 2.0.0) diff --git a/app/models/commit.rb b/app/models/commit.rb index 1e19f00106a..b22aaa3c461 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -234,6 +234,18 @@ class Commit @statuses[ref] = pipelines.latest_status(ref) end + def signature + return @signature if defined?(@signature) + + sig, signed = @raw.extract_signature(project.repository.raw_repository) + if sig && signed + GPGME::Crypto.new.verify(sig, signed_text: signed) do |sign| + @signature = sign + end + end + @signature ||= nil + end + def revert_branch_name "revert-#{short_id}" end diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml index 45109f2c58b..1a0c70ef803 100644 --- a/app/views/projects/commit/_commit_box.html.haml +++ b/app/views/projects/commit/_commit_box.html.haml @@ -6,6 +6,7 @@ = clipboard_button(text: @commit.id, title: _("Copy commit SHA to clipboard")) %span.hidden-xs authored #{time_ago_with_tooltip(@commit.authored_date)} + = render partial: 'signature', object: @commit.signature %span= s_('ByAuthor|by') = author_avatar(@commit, size: 24) %strong diff --git a/app/views/projects/commit/_signature.html.haml b/app/views/projects/commit/_signature.html.haml new file mode 100644 index 00000000000..7335b6b9597 --- /dev/null +++ b/app/views/projects/commit/_signature.html.haml @@ -0,0 +1,4 @@ +- if signature + %a.btn.disabled.btn-xs{ class: ('btn-success' if signature.valid?) } + %i.fa.fa-key{ class: ('fa-inverse' if signature.valid?) } + = signature.valid? ? 'Verified': 'Unverified' diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index 1033bad0d49..5f67727514a 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -39,6 +39,7 @@ .commit-actions.flex-row.hidden-xs - if commit.status(ref) = render_commit_status(commit, ref: ref) + = render partial: 'projects/commit/signature', object: commit.signature = link_to commit.short_id, project_commit_path(project, commit), class: "commit-sha btn btn-transparent" = clipboard_button(text: commit.id, title: _("Copy commit SHA to clipboard")) = link_to_browse_code(project, commit) diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index 09511cc6504..d19f55c423b 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -319,6 +319,10 @@ module Gitlab end end + def extract_signature(repo) + Rugged::Commit.extract_signature(repo.rugged, sha) + end + def stats Gitlab::Git::CommitStats.new(self) end -- cgit v1.2.1 From 28bb5e3d53a585b1fb958d1d91622da0a038bea8 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 16 Feb 2017 15:39:37 +0100 Subject: commit signature with spec --- app/models/commit.rb | 2 +- lib/gitlab/git/commit.rb | 7 +- spec/models/commit_spec.rb | 40 ++++++++ spec/spec_helper.rb | 12 +++ spec/support/gpg_helpers.rb | 222 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 281 insertions(+), 2 deletions(-) create mode 100644 spec/support/gpg_helpers.rb diff --git a/app/models/commit.rb b/app/models/commit.rb index b22aaa3c461..0d50a32d138 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -237,7 +237,7 @@ class Commit def signature return @signature if defined?(@signature) - sig, signed = @raw.extract_signature(project.repository.raw_repository) + sig, signed = @raw.signature(project.repository) if sig && signed GPGME::Crypto.new.verify(sig, signed_text: signed) do |sign| @signature = sign diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index d19f55c423b..4dcaff5e0a0 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -319,7 +319,12 @@ module Gitlab end end - def extract_signature(repo) + # Get the gpg signature of this commit. + # + # Ex. + # commit.signature(repo) + # + def signature(repo) Rugged::Commit.extract_signature(repo.rugged, sha) end diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 528b211c9d6..0fc00ab4f18 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -414,4 +414,44 @@ eos expect(described_class.valid_hash?('a' * 41)).to be false end end + + describe '#signature' do + it 'returns nil if the commit is not signed' do + expect(commit.signature).to be_nil + end + + context 'signed commit', :gpg do + it 'returns a valid signature if the public key is known' do + GPGME::Key.import(GpgHelpers.public_key) + + raw_commit = double(:raw_commit, signature: [ + GpgHelpers.signed_commit_signature, + GpgHelpers.signed_commit_base_data + ]) + allow(raw_commit).to receive :save! + + commit = create :commit, + git_commit: raw_commit, + project: project + + expect(commit.signature).to be_a GPGME::Signature + expect(commit.signature.valid?).to be_truthy + end + + it 'returns an invalid signature if the public commit is unknown', :gpg do + raw_commit = double(:raw_commit, signature: [ + GpgHelpers.signed_commit_signature, + GpgHelpers.signed_commit_base_data + ]) + allow(raw_commit).to receive :save! + + commit = create :commit, + git_commit: raw_commit, + project: project + + expect(commit.signature).to be_a GPGME::Signature + expect(commit.signature.valid?).to be_falsey + end + end + end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e7329210896..6b4ec608efb 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -141,6 +141,18 @@ RSpec.configure do |config| config.around(:each, :postgresql) do |example| example.run if Gitlab::Database.postgresql? end + + config.around(:each, :gpg) do |example| + Dir.mktmpdir do |dir| + original_dir = GPGME::Engine.dirinfo('homedir') + + GPGME::Engine.home_dir = dir + + example.run + + GPGME::Engine.home_dir = original_dir + end + end end FactoryGirl::SyntaxRunner.class_eval do diff --git a/spec/support/gpg_helpers.rb b/spec/support/gpg_helpers.rb new file mode 100644 index 00000000000..3b50d831b00 --- /dev/null +++ b/spec/support/gpg_helpers.rb @@ -0,0 +1,222 @@ +module GpgHelpers + extend self + + def signed_commit_signature + <<~SIGNATURE + -----BEGIN PGP SIGNATURE----- + Version: GnuPG v1 + + iQEcBAABAgAGBQJYpIi9AAoJEMcorxCXLpfAZZIH/R/nhcC4s0j6nqAsi9Kbc4DX + TGZyfjed6puWzqnT90Vy+WyUC7FjWJpkuOKQz+NQD9JcBMRp/OC0GtkNz4djv1se + Nup29qWd+Fg2XGEBakTxAo2e9cg38a2rGEIL6V8i+tYAhDt5OyLdzD/XsF0vt02E + ZikSvV02c6ByrjPq37ZdOgnk1xJrS1NM0Sn4B7L3cAz6TYb1OvyG1Z4HnMWgTBHy + e/uKLPRYhx7a4D4TEt4/JWN3sb0VnaToG623EdJ1APF/MK9Es+H7YfgBsyu18nss + 705F+PZ2vx/1b9z5dLc/jQNf+k9vQH4uhmOFwUJnuQ/qB4/3H/UyLH/HfomK7Zk= + =fzCF + -----END PGP SIGNATURE----- + SIGNATURE + end + + def signed_commit_base_data + <<~SIGNEDDATA + tree ed60cfd202644fda1abaf684e7d965052db18c13 + parent 4ded8b5ce09d2b665e5893945b29d8d626691086 + author Alexis Reigel 1487177917 +0100 + committer Alexis Reigel 1487177917 +0100 + + signed commit, verified key/email + SIGNEDDATA + end + + def public_key + <<~PUBLICKEY + -----BEGIN PGP PUBLIC KEY BLOCK----- + Version: GnuPG v1 + + mQENBFMOSOgBCADFCYxmnXFbrDhfvlf03Q/bQuT+nZu46BFGbo7XkUjDowFXJQhP + PTyxRpAxQXVCRgYs1ISoI+FS22SH+EYq8FSoIMWBwJ+kynvJx14a9EpSDxwgNnfJ + RL+1Cqo6+BzBiTueOmbLm1IYLtCR6IbAHAyj5YUUB6WU7NtZjJUn7tZg3uxNTr7C + TNnn88ohzfFa9NfwZx0YwgxEMn0ijipdEtdx5T/0vGHlZ+WRq88atEu00WNn0x65 + upvjk7I1vB9DTZp/zPTZbUGPNwm6qw9xozNFg/LcdbSMryh0Xg9pPRY6Agw2Jpgi + XxNAApDrlnaexigFfffUkkHac+0EoXwceu8zABEBAAG0HUFsZXhpcyBSZWlnZWwg + PGxleEBwYW50ZXIuY2g+iQE4BBMBAgAiBQJTDkjoAhsDBgsJCAcDAgYVCAIJCgsE + FgIDAQIeAQIXgAAKCRDHKK8Qly6XwO1VB/0aG5oT5ElKvLottcfTL2qpmX2Luwck + FOeR4HOrBgmIuGxasgpIFJXOz1JN/uSB5wWy02WjofupMh88NNGcGA3P4rFbXq8v + yKtmM62yTrYjsmEd64NFwvfcRKzbK57oLUdlZIOMquCe9rTS77Ll/9HIUJXoRmAX + RA0HUtn0RnNF492bV+16ShF3xoh5mVU4v+muTA/izW7lSQ2PtFd2inDvyDyiNKzg + WOUlZESc6YN/kkUJj/4YjqPgIURNx6q/jGw24gH4z6bZ8RfloaEjmhSX0gA4lnMQ + 8+54FADPqQRiXd3Jx5RRUJCOcJ+Z17I4Vfh1IZLlKVlMDvUh4g2SxSSGiQEcBBAB + AgAGBQJTkXXXAAoJEKK3SgWnore32hgH/RFjh9B+er5+ldP4D9/h887AR9E1xN7r + DTN7EF5jlfgXkIAaxk2/my+NNe0qZog9YBrVR+n8LGgwXRnyN9w1yhUE4eO71Zwi + dg4SgU5fK3asWLu+/esKD2S/QndRwIpZOTqsmiqe8N8cVscaoAg+G/TnDJvTKft1 + twIcjrB1fv9B3Fnehy/g/ao+/E1/7CknWE6zB4eSQdOrAfQ9gnJgabLRBUUVltBm + dBZ+lAQyBSAEbkL5FgWhxJNMjuTOVr6IYWvRXneHrMy630wZIk0d7tPEZJvBeIKA + FMtzBJvW6gJ/Xd5mbtb+qvoxfh8Z06vfqNMmhLLEYuvEW1xFSmyWWGuJARwEEAEC + AAYFAlSGz8kACgkQZbw57+NVY/GU0Qf+KCAPBUjVBZeSXJh/7ynsWpNNewZOYyZV + n7fs8tm7soJfISZUbwVAPK8HwGpzrrTW9rpuhKmTgXCbFJszuHys4z3xveByu56y + bmA1izmhaLib1kN9Q7BYzf8gdB657H4AAwwTOQPewyQ2HJxsilM1UVb5x9452oTe + CgigGKVnUT556JZ8I8bs+0hKWJU3aDDyjdaSK82S1dCIPyanhTWTb2wk1vTz5Bw1 + LyKZ8Wasfer6Bk6WJ9JSQRQlg4QRkaK6V5SD33yOyUuXM7oKgLLGPc0qRC6mzHtz + Sq7wkg2K/ZLmBd72/gi3FmhESeU6oKKj6ivboMHXAq+9LuBh30D0cIhGBBARAgAG + BQJTmae5AAoJECUmW1Z+JGhyITgAoJoFNd5Rz9YFh8XhRwA6GaFb7cHfAKCKFVtn + Bks20ZiBiAAl3+3BDroNJ4kBHAQQAQIABgUCVXqf+QAKCRDCDc5p2mWzH3gTB/41 + X9v9LP9oeDNL4tVKhkE8zCTjIKZ8niHYnwHQIGk4Nqz6noV/Qa45xvqCbIYtizKZ + Csqg2nYYkfG2njGPMKTTvtg5UdilUuQEYOFLRod3deuuEelqyNZNsqSOp7Jj5Nzv + DpipI5GxvyI/DD7GQwHHm5nspiBv/ORs3rcT4XatdTp6LhVTNyAp060oQ/aLXVW4 + y1YffvVViKe/ojDcKdUVssXVoKOs4NVImQoHXkHVSmFv0Cb5BGeYd58/j12zLxlk + 7Px9fualT6e5E7lqYl7uZ63t32KKosHNV+RC0VW8jFOblBANxbh6wIXF7qU6mVEA + HUT7th2KlY51an2UmRvTiQEcBBABAgAGBQJWCVptAAoJEH9ChqPNQcDdQZAH/RiY + Wb7VgOKOZpCgBpRvFMnMDH2PYLd6hr1TqJ6GUeq3WPUzlEsqGWF5uT3m07M09esJ + mlYufkmsD89ehZxYfROQ8BA3rTqjzhO9V0rNFm/o8SBbyuGnQwFWOTAgnVC1Hvth + kJM+7JgG8t6qpIpGmMz6uij7hkWYdphhN0SqoS8XgAtjdXK6G5fYpJafwlg7TGFD + F6q5d2RX0BdUhJkIOFNI/JXLpX04WiXEQl2hOwB3la/CT2oqYQONUbzoehUaF5SV + uKlFruUoZ/rbJM1J4imdcEBH2X3bnzdapCqvMudgAALo8NUiJJ/iTiYx/sxQ4XUp + oF567flP1Q08q6w66OyJAhwEEAECAAYFAlODZOkACgkQ5LbUbWbHh8yNzBAAk6LE + nfbdmx2PsFS21ZP8eAiPMBZ61sfmDVgNU5qLDyQRk+xg7lZlFlZ64mka4Bh82rvV + 4evcEOHbuiYS4zupxI9XrBvBpks6mALEAAX/5HXYDgb/9ghNd0xjlheHmMKJk8jE + Mb2kYx/UCimbtG460ZiQg0e+OWNU5fgMEjA8h6FMbt0axPkX+kde+OSg52i1bL5n + fPbGqA3o1+u2FzsufuCEOPsTLKhkiOKnopCMtB8kRih+WQ73G3XkYSkYh2bYW0eF + MoZlgez5lpUWLD0+NWB9qiDXZs1yUJ0CdHA98eahPaPyR8aLqOP0dPkbS6/X4j6N + WjZgZ2sIb8PihowiHYeogMhZZIoBTYqRlbW9/KAptC7UGFMF21Vp7HexFRuoC8qO + PSXfMLH4kw0Lq1mLBTw9+No0L7xfMxKmzT0VLsJkJB09gAGWv2/8voCIPtBm/MZi + C9o3w3tWAczAvZetMXH/dp8Por6pmMoTHHUkbSBZHe1Lt138jLtozZDCuuWQ53O/ + mIT1sds1Oy6IF4e0xrSqpZlDGwj0pqOKmtLFI1ZRrfjb5bnm7sgzcxoM5aPhqJyb + 88XYgBolsiErM+WhnH6cAEK2TUVlVqXzDIbqKBroEK/cM+Bez1SagzAsoarYA5R1 + yewc0ga/1jQI4m6+2WoL4wo4wMNggdWiIWbuqAmJAhwEEAEKAAYFAlZDO+4ACgkQ + MH93QRZS4oGShw/6A6Loa5V9RI9Vqi7AJGFbMVnFJV/oaUrOq8mE8fEY/cw1LQ5h + Ag/8Nx7ZpQc28KbCo0MR3Pj7r2WZKLcxMwaXlFZtNiO4cEITNu5eoC7+KOrFACsO + 1c0dKbMEeDQ2Xqzo2ihw/4DnkuUenrmGnNJMQ5LrEZinSKFFAgeYRdYnMdYqOcXe + Q8rPImFkyOnPbdIOC2yPzjqHIsuazuwd9to+p35VzPNZv7ELFBfx/xDHifniRMrm + sPJh6ABjecOJg7RJW4h9qP+bNbbrJa6VfGAbNUR+h4DiMr6whpGJd41IiXIEGrGW + BT87hO7gwpMrex0loQoHwsfqMxOM0qwMU9ARCJJLctzkj727m/SsyP9cUIFGceBN + cUopmpKCi9z0QZ/bxKWbpqa3AarkWxRLj1ZzmllxC7tjO61kr0zkn8pnEIc79cGw + QlUI9k7QaWFm1yDlpPXLvBi+evYxSONbsSoHwjMIC/cioBh0c0LOXn8TV6OWlS/3 + sWShQG9KxugZdK+MBrZPR23jilHPKpWG8ddEWp4BZugqxppiyZAgEOMlHBr5PkV+ + hBx1vCG0w9IlMJODRIXIUeqot3ixQvLmeoWTuIFPiNPfXskCfNuudbj4+jZewf6z + BL60VJADKJENmsDPPhF6UEiHDIrauNylORhhPR/qEAs4LOiEwRqRtHBEqYKIRgQQ + EQoABgUCU39OnwAKCRA1morv4C3iPRylAKChT88Lvmd1M5LX1hoRqsFeG8IahgCf + Q1VWKh852oZq9dOtbGRxEbv876OIRgQQEQoABgUCU+DpHgAKCRBmKanAQloCxoSL + AJ44D4cwTLOmw+rHl6bB/oqNhoV3bQCbBmyupEB9gn6NUD80BTEzs0jTHWSJAhwE + EAECAAYFAlNv5m4ACgkQxykhoSk/LSQnZg/7BSrZULH/tRDRd1LvuKtHoR7AarqD + iGQXhxvXLp6AZaMcI1UF/hvKeJtho5tKjQ6OpEB1sPXXc68abvRdJFh42GBPmHFD + A8aBsJJePZQTMm4biDfFNw7cK1j0cjUczftAlyFAf5w5y2kM5jo24qdNmVqa5ipE + u0AcmzNntgaWeP9izXdnjpNTSOG6Rbo84IrIku7sR8GxNvlisAS1hhwYkYksNts4 + gu+wmfnkLFyZrncbjVHLVbZnAJhhcdWKhyjcOBRadrAZ/EoK1/3VoLHIdWBpW0f9 + sUYv3u6WUyWa4EFaaHRxttMFWhWq9p2nYfojh2Bf5V6cOLgikkIu03oQp2GPNnOL + ub0PTmSS+93ZmIEW9NIxY0cmz8lFVo9qqip4Dzka2Rp3oTg0x3JKXU+OZV4J/Mfa + LT5uI3Flub3f8etOQw+6/Q5Rg3vGOh14UtEVaA1WcKeyRq7v+XZAA16FN5omCEX8 + xA641xgefvLx4jj0ZfqlHgH+dEoOdbiRQ3IYyzMnX/xLl88Xw49etkeflQFXvkLh + e6QdXrfrm4ZniIWOfCDeQmZS0znDV46YzK0MVu6kYXcmDpVBRREUzsxgJmWg4JW2 + EgHTqSHL8Oi8gvfTMKaPSnTl3cWSKlupQDx/CYuuqdAd7x2hcSivWFu22YcNp4XV + fd0jJPvv+UlnmjOJARwEEAECAAYFAlRcmw8ACgkQlFPUWjJBWVgGCggAgZDWaPcj + Fce9mnRtMDyOVMOZQ0AppvbS97pJ6PLF/dKXz+nyNtkiAPfimRTE3BpXhX3JDke9 + PEaRH/dXTdmzfej9N3DOADFJlRVyxETXyTGiNzyP7vaJAT+9hgW7hbUtgoAbDK31 + ZWijVEw4+Jg9vWhUKBhLrV1lcyQyZAldLYep/sAyynAeaUbsFtbpH8DHXZBIA/0C + 2XWp7o01w8b1CgsUHBfBK9eNlQ3BOu3Y5WY8MW4ZcRuDlH/hbs9V1zK5vkR2zq4d + uSG8KYHsLV1/zskLszLZk27c6QHQb1C6U6CW8shgkdxGRduXMETRL4yYib3s4Mwy + xovU00cYKQ5CIokBHAQQAQIABgUCV2FHnwAKCRCZSfh4lwNdkn7DCACvBLx76e+5 + 9vaGdSne2veRwT/J/a5OWJghn7f679btAxJROvWdeHvWW4vHKz+A6HGvR8E7xGCZ + NdfkokqXcioSRcZFIW7zAev27F31E8V63voY2KDESlkxrRhNZBpvwfXAg2RS9KmB + btmgj6Zo1VnbEXoxPO+5yZzpYxuBPL7xMidSznQe9eswqMLvSNxKQODOGToddreb + 9ClKk+qpQOCTQTEQjw4Y9wjoZ5SdENP1IihnTi/Z31Sr99CL3jPPpXoo8WO4in6z + DPEEvAbszDb+24+WDEoW47ST+x4eDJG0WcVrjNa87k7kMNOWsPr9rNHtgRCNa22M + xaPaKrTZ/F03iQEcBBABCgAGBQJXc+wKAAoJEIhwMVR86tleqikIAKQtWDnrp1dl + tE4G1IVp2i9NwhCOaZVODaGaH3C564B8/WyEbjFjOmm4aDzykiwEUWBMCP0icpHn + 3o5s65gdtgnP/KVWKp3wyJqJYu0rQcyFtKNKi8x5D/7c8y23DRoI2lnI12f7MWPH + wzC3wClulTboV0mC2Cp1TWLBnKGbhpHOGN5ViSPm3rPOesFZ5el38wcwDKWaZbmm + hFtx8fx2T2lTP+5GRCuiXrnsrzA3tZLuRWH44esPxYB8mFg1btgAtXo9Q9MEISWL + g043RQ0VWU3a9F7K3RshTPAUbvUrNtEAFMtij0B4RvLE5cyHEltUB0R4ie3RDZDe + z0VCwrsaI+OJAhwEEAEIAAYFAlePuxUACgkQ+iIJCo0F+QvWZg/+I5R1TdQpMKVM + Fz+XrYXpSgPxeLr3b6svuV8uOPY8kYbOPVxvjbNGuyijbRD/btH9Qg2vDNGbZJ9G + pGUfnNNlXUsTkxp/5sEWAzBH0pTEgiy7wHzCa4u+meXDkLnomdZfSHkFNDw+I2MI + Nrp84DPkMBQ4X5AJ4UcoMUbfqLRbqgHo/DEAYsAwnihF4Lwl8x9ltokcAc+w3SQk + mvHOR1xoeAFtH3NEzUvA3EhZo16o7+dQWyh8GJRsgUA6g6zyqLOn+JTDVh1YlrAF + 1qkhnBsw7G5InL54mhvXwqKoAwI5zO8A+5tSUMUvtZBfUW2DX/yCvaD5v/fjMScF + 5Lw61NYTLyZEW+JlLGGdIrewB72BVPVR5Sak+dwwjxHK2NGdaug3V8gOht8ZwYKx + X9NmYLWi+4DFkQxtSCpwH6WAqfw4OPuvFHyd/VdA5czsQo15rU2Go5JE7FlR1xoy + lCNV4TU3p+eLTNW/L7ty4HPuiPWI3gDpRgh0Tv878IlLKuivlNhfTub8Hf4LzSW1 + g++1lwUf3TxhYUPHmZT2V9Sk+VVgCXIFenn914r+RZMnThCgWh2GmcKDgLKUSdxv + /j14NlTgWqUY3cQM/ciSdAdqZn8WAOjeuVgpqkX5A4NrWbshaqUsksm9QdtpMia1 + Q2hDuR8OIvHP0PiwNv8Bn00nAgyU2NeJAhwEEAEKAAYFAldP7ycACgkQu9aLHqU1 + +zaXsA//Rm+1ckvAAaj1qk9rXpYZVWK8kCeKkHu48bL9r0g9Z1mfCGTgrUd1lPNW + Lh850z+LYzJelZCqnNsgxX8KG567NwdRb+LBy8tzbCgIMomfgqILv7KmRzPQ6AJ7 + Bp8hGnregfD0CCXtEORk/aQF0FCRL8bKsKiN7DOPirP9gfdSgpshr1cLe8a7cPFq + Zza7VhAke5/BCsNzxaUvseuzZ6bZOXlUpbSJH2+f/DYXvwfaJl/Rg+s+DuPtqVgI + TMSsRwL/iIlqfT2Al4SVak4f0q/HVkNgfEFSx2i8OWlVe90V71sNNAOMSDnBRHBC + fNon4vwnv3xkKwH6ecwgZtZwcjPKMUZPjrzEFULOBrNAsC173HypbZZ/wlJBAMd5 + gBd35CQELrq2sOgekofm7Sbq5m2WYr35M0nqIV8q0ySxMWyuY2g46QQVEyGiXrKt + TyJzT7M+UtqD03wjNSBZc7y/a2+kzZJADrz8kNANuR5GGfxZ3zKjmgyQX2QRNYq+ + +bwB6U7NyRgzX/i3sE2pSn2xuwwzqk873r+Afb8gCMSXV1omcwZJAHeUURjv70mU + A9BFjE249JxjDbuzThiErMCG4Gj87NjXYCBq7QsfyKPVAx7esEYoDmR+k4nYH4my + pY1LTgLZUOBtGiLnkGIZ9XVIcZBPRoSKEpRRvcPBtHkJkqwQm8mJAhwEEAEKAAYF + AldQLVYACgkQsOAWYMCDwn9L4xAAgMxHehYdB6+htNj/c7xlFhdv6nyLl8excl0q + jOBLsN00w3F1yGZqNhbKsvHZKhW8PZhX+wMMoczGi1YdOV3AMoB20/t+DRh2giRL + wgLiJblxR4Z4Ge+/ne3/aVHOHyVqmh879TA2coUS0i0BpqRoY70eV/yVqkbXpuFm + reXLt3Syc3HoGd79KiyRht83Og/d7dbxkQOCe7YnRxuVynwMKgIRJt+UgCIM07sR + nA05MWgatp9PiFXkGdfyBy2UkvybcaAyjByBpOjdTPFa2LdjIO4Qsgmg8q8F3z0g + gW3bRPKQDNX6w7UA4tf587x0S1mKwXGeLnezZv1kmAQB//bYgZs4bZsqeB/i832I + sWzX7PEoh/kGWg9/eZBQu+l5d8koD2wRiUvFVussont7LMsNwHJSerS++tj5Tdwj + E8qcNdJYkcjkVxaHugVlm+IQfSrvdMpRq8bfwxGmprU3hAebB0b2OZDMm/uWGiVC + ycjStGUtu/ZJU56zRhkj/4yZPi7gczZAurRXvLt4AhNpkGPNSAxt16fpaBkBPo61 + pHir3K+FvpXN4ezv+mFR1G0hrSTuMk2nU1D7WUkw0xnx/IY7VrGx8PrR8Ilfb+C1 + 9z1g/uuZ4alIWXZ/tAeDPjTQI5QOPgj43DrgWqG2FDAqQ/+nt9RevUVIPMOojOko + BdHaskmJARwEEAEIAAYFAlguvT0ACgkQkDmkVrycD3gyvAf/fks3MtR+yoMRCNIi + VklGwoTv646OOqm3bDZz180cXqGXxSASQ7fglaDGl+of2qRyilU9dzkY1ZHqD2AY + /sycR1QKELfa9rFx12i4w9jyWdZykOggS6Os3e1Dvt9Q4fZzP0+eLCs8Fknancxq + WhUrXqaYz/OZj4Xmjw6jYZxdtJ/B0OFDqxOlN7v3iZSeXNwKJ5vpeJLE6dfy/5pM + ms3aIj8KB+MDSQpgaZ8FKjRn8rSZwUu768sHNTWv5l0UxJbIREB5XE8fQuGxPIJ+ + DyxiKmPMlyuyj6whz+iZP5jkEDpDiqFEJHHmw9qAlhkba0LzJYh2uqS7L15V6ykY + xZ4wl4kBHAQQAQgABgUCWC6/swAKCRDij8qPAN1CxhQJCACP+UCg5zM5h8HtLlPL + Pt1jofqmVqk8KJHJyZzn6EgyoQmNnPDybLHIRTxB+hsQTAZJtQn7UiBpXa0OmBXm + s4MdeRb0tIPN1l66l8+N7OuG0Tf+mALwAM+GqiUgSEGs5gOVF9Ev1pP0dRCKTSGJ + v0NMNUb77Qkn34R4HK+f0nfFKER4RW23F5e6sf6Rq4SzP3sVRdqU5dY1alxMFWNy + 7IrP/QdsBl6ACtYSFAuay/hxyccbu22KhIm0S2ikJJgjNenyq15TGaBoG02nl4lC + TgrOEjNDSXw2Bn4L6AZM8sR08ZjARqKspB7ZnNOcIaIrK61cpgAL4SXdMkvQF7Qj + uhatiQIcBBABCAAGBQJYNfShAAoJEMELqJFB1XEubX4P/0or+wvHMFC1lBTttKlO + mkPHTHDYZFCLQr/6cjAv5OPyrBOh/uJ+QJq6awrn1LD16j2YEZUkgkqHBiNl5f7R + J8Tl97esxZja5iHvgOx54NDxD97WoIgJhEnYuhvY7sACT5YBx4npMKPi0WaqgCfR + GDeQzVcKzgWhScgeSnWBf7+bwIdGO4mg9y58s/4fMK1kw6niK/xo1hkK0w41StV1 + wmK92fEqeFElseaBSmf8efgb4Qi6ic9Zf2mGgjHwTIn7FeTA9r6zzSggw3b5NEG6 + W2bdhVmKheYPBp+kdsQqsw9H/AzUFLL8wg982IRyvnbUkccP/7neWeFJo/1VVogp + ybTBdgxa+dl5UcjxvqJZbFp0mLorWJvOVamoGgvO2WKv0tSUK3LwVxZaIVMbFwEo + G+FfpW8XfqhzdkD6zJO3rjpOcnrouaYB/SpSofbwRxrtxTzcxxMP2B62gd7/VdcY + duyL6Cj21P3vIdveQ26B8zdSiv6MfG/7/zlrpe9strIv3UiHfpG8093TnPB2gwWL + /zdh7Nbsn3rq2Rti00zIqHpopPS4J/dr/jdpXzMymb93HpsA5UTuyYHnqa1YBAgn + qfnkk+lNENso6Ymg8a+S/oFh7Hks7olrhYpmdodL1AqU+YWMsp2L2knOxmpEZc8s + mjVx9YKKxrtZ7FisuwVER+3fiQEzBBABCAAdFiEE4gFIMof/a3u+jGQXNpvllaAP + nh4FAlhrniwACgkQNpvllaAPnh6e1QgAh646441z+ecM8k82DIctj1RT01tY5Ygz + WwDx4HJZy8b/l3J8PF62mZB045vC9DGweX7DgJ/FZXTwMGfS1lU7gBmIMJZnp8lU + m4K1IRgYf70T5LOepaYgJUJ9iPoc1bSw91efkdQSou6Fignet+DMk3268qbO/JO6 + Q8MbsD9XDND1pf6Y1gdtsrXaQTTqnf7l/5zbrYlknOBkDk4x7ZbYgZYfEucba4/R + 3O+dN7Eu9O7dS/PmYDvozPCuEIJrPwxdWnDr+0J6JwHwP9o2OD51CT/LfvL8uGtS + oPcmB4Oon1ORayDWWthlypYONP0kKwIFsR6mgU++UVNj+b+ABbizOokBHAQQAQoA + BgUCWH3oQQAKCRAfFBlUoHXkjEbvB/4zwwaKHd6B1d6XMzysG3/l29IxdNG8Udh0 + d8/o/jEl6jxJiIjVvaFTXXP1/owBjDSP/RwX0mMaluIfedghN+y21UQfi2QJ2FtV + d7hLTKjgLYStGZGakmUlaXvwZsshZmpQJDbFo6SWqBb68yjult8VTnoug+Q+I28o + p2y8sviFoEyBKnYXotSt9HNMLHtYUeFqJWAwVRIt14oaHXQjv7QuB9/RnuY6/sfC + In5y84sJyEylghP4C2+Usl5QtcAR5gByMvpfyPsFxXIcGw+Bxk9Sm0k37tCVAhKB + dIOMd85s8mQJ4nOZu2hLhKBlOgX1HNb/LJECG2QPqlSDtoFXrzcotCRBbGV4aXMg + UmVpZ2VsIDxtYWlsQGtvZmZlaW5mcmVpLm9yZz6JATgEEwECACIFAlicPfgCGwMG + CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEMcorxCXLpfAl0UH+QFkOIlIuFpb + 6MkAdp7qkaP58HG0nFZMWTLiwJnh4rclN5vvU7Dlvyy/JOI1M6wepBl3ujNJ+Pe1 + RL1Jy001sN9ZGvtkCiXwfg+3IRNAacQwdl39lUsaHbzSyo/33U7i9NaQ9QefLpji + on1auZMXQ8OVDPo2sT01kSwutMhYx/8wEc+kh/uckCYLFjx06mF1l+OGxc77CGbr + WeItjrjhTkYjsoaVh776V0Q2m08Ixq7pBXYp91zKT00EUE64LdIN85AkzehzSptF + +lT/BW2C1Ft5E588914PMKvNcufB0twaNFqKZUOCiIXO3cqlLoz5GHLe22mJKngo + NXVsbNZ/8zW5AQ0EUw5I6AEIAMb+U5s17opggc0fgejZleAv8ie1HIKms7PNlaMq + lzQj5bmFAln7DjUvupey8fkpLJtEGAJkp0vBiXohM3KOa78hr9ShJIVuFrz473jj + 9cAMlcLme2yDvPVjtTEFiVwl9+WXgvjtgkQjDKU1v9QJIC4UbcnzYwwyHuXXVUKW + v9gXj2a6Adk0cFF0qbNpBzfKrettsp02PUPlrceVhB8KDgY9/rj90uxQBmeZn9bP + G2W4zR+J+8kLcUAFlVhJasfItDo5bpFl7VH8hX5ZzXBL0NMQQoeNRtnrt/5xJ5Kl + BQbflScVaF1s+3oK75ppEeRZrYP5ESB5JBLUGuFO44hD/OkAEQEAAYkBHwQYAQIA + CQUCUw5I6AIbDAAKCRDHKK8Qly6XwLGiB/0ZUZf+ybfY6RQz4QoRw+RO290bf1Gx + wuL3PPCxaVX3POv1S0RLblYEP+88ikaYv6zpiEoohQPtCXdLfyJswRgTUNWS4DPZ + COW5TLLE2E/zYB0YGwLilZvAkopx+x1tWT2aBjNyXaHC9Z8jhuqlxKhpUbRKpyma + OxtDOS7L3xzzcfowuxFx08tPXgRcQOeINK55v2d8xwKGdfKquQTX1ibf4ipXvWIB + hCn6UW2YqhqIatQp/Swcj5woIv2kCCAI1cDPRpMUu48qJNYmsKEG6FO55/UxSRyF + TseoRTbiwR6tr3X729W1y5FIoFo5tq1NbAMy3o0+sP9pQtbN+1Percgf + =1CGB + -----END PGP PUBLIC KEY BLOCK----- + PUBLICKEY + end +end -- cgit v1.2.1 From fbf1fd1a204a24aef2b80473ec64a520ed2a2dfc Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 22 Feb 2017 12:49:17 +0100 Subject: add gpg key model --- app/models/gpg_key.rb | 35 ++++++++++++++++++++++++ db/migrate/20170222111732_create_gpg_keys.rb | 13 +++++++++ db/schema.rb | 11 ++++++++ spec/models/gpg_key_spec.rb | 41 ++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 app/models/gpg_key.rb create mode 100644 db/migrate/20170222111732_create_gpg_keys.rb create mode 100644 spec/models/gpg_key_spec.rb diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb new file mode 100644 index 00000000000..16de0b542d7 --- /dev/null +++ b/app/models/gpg_key.rb @@ -0,0 +1,35 @@ +class GpgKey < ActiveRecord::Base + KEY_PREFIX = '-----BEGIN PGP PUBLIC KEY BLOCK-----'.freeze + + belongs_to :user + + validates :fingerprint, + presence: true, + uniqueness: true + + validates :key, + presence: true, + uniqueness: true, + format: { + with: /\A#{KEY_PREFIX}((?!#{KEY_PREFIX}).)+\Z/m + } + + before_validation :extract_fingerprint + + def key=(value) + value.strip! unless value.blank? + write_attribute(:key, value) + end + + private + + def extract_fingerprint + import = GPGME::Key.import(key) + + return if import.considered == 0 + + # we can assume that the result only contains one item as the validation + # only allows one key + self.fingerprint = import.imports.first.fingerprint + end +end diff --git a/db/migrate/20170222111732_create_gpg_keys.rb b/db/migrate/20170222111732_create_gpg_keys.rb new file mode 100644 index 00000000000..1b8b7a91fe1 --- /dev/null +++ b/db/migrate/20170222111732_create_gpg_keys.rb @@ -0,0 +1,13 @@ +class CreateGpgKeys < ActiveRecord::Migration + DOWNTIME = false + + def change + create_table :gpg_keys do |t| + t.string :fingerprint + t.text :key + t.references :user, index: true, foreign_key: true + + t.timestamps_with_timezone null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 1ec25c7d46f..54f98559243 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -540,6 +540,16 @@ ActiveRecord::Schema.define(version: 20170725145659) do add_index "forked_project_links", ["forked_to_project_id"], name: "index_forked_project_links_on_forked_to_project_id", unique: true, using: :btree + create_table "gpg_keys", force: :cascade do |t| + t.string "fingerprint" + t.text "key" + t.integer "user_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "gpg_keys", ["user_id"], name: "index_gpg_keys_on_user_id", using: :btree + create_table "identities", force: :cascade do |t| t.string "extern_uid" t.string "provider" @@ -1602,6 +1612,7 @@ ActiveRecord::Schema.define(version: 20170725145659) do add_foreign_key "environments", "projects", name: "fk_d1c8c1da6a", on_delete: :cascade add_foreign_key "events", "projects", name: "fk_0434b48643", on_delete: :cascade add_foreign_key "forked_project_links", "projects", column: "forked_to_project_id", name: "fk_434510edb0", on_delete: :cascade + add_foreign_key "gpg_keys", "users" add_foreign_key "issue_assignees", "issues", name: "fk_b7d881734a", on_delete: :cascade add_foreign_key "issue_assignees", "users", name: "fk_5e0c8d9154", on_delete: :cascade add_foreign_key "issue_metrics", "issues", on_delete: :cascade diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb new file mode 100644 index 00000000000..02623c52fa6 --- /dev/null +++ b/spec/models/gpg_key_spec.rb @@ -0,0 +1,41 @@ +require 'rails_helper' + +describe GpgKey do + describe "associations" do + it { is_expected.to belong_to(:user) } + end + + describe "validation" do + it { is_expected.to validate_presence_of(:fingerprint) } + + it { is_expected.to validate_presence_of(:key) } + it { is_expected.to validate_uniqueness_of(:key) } + it { is_expected.to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----\nkey").for(:key) } + it { is_expected.not_to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----\nkey\n-----BEGIN PGP PUBLIC KEY BLOCK-----").for(:key) } + it { is_expected.not_to allow_value('BEGIN PGP').for(:key) } + end + + context 'callbacks' do + describe 'extract_fingerprint' do + it 'extracts the fingerprint from the gpg key', :gpg do + gpg_key = described_class.new(key: GpgHelpers.public_key) + gpg_key.valid? + expect(gpg_key.fingerprint).to eq '4F4840A503964251CF7D7F5DC728AF10972E97C0' + end + end + end + + describe '#key=' do + it 'strips white spaces' do + key = <<~KEY.strip + -----BEGIN PGP PUBLIC KEY BLOCK----- + Version: GnuPG v1 + + mQENBFMOSOgBCADFCYxmnXFbrDhfvlf03Q/bQuT+nZu46BFGbo7XkUjDowFXJQhP + -----END PGP PUBLIC KEY BLOCK----- + KEY + + expect(described_class.new(key: " #{key} ").key).to eq(key) + end + end +end -- cgit v1.2.1 From 7b7cd6f69d59092a55fc8b293edf09638fba20d9 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 22 Feb 2017 15:37:49 +0100 Subject: add emails method to GgpKey --- app/models/gpg_key.rb | 5 +++++ spec/factories/gpg_keys.rb | 7 +++++++ spec/models/gpg_key_spec.rb | 8 ++++++++ 3 files changed, 20 insertions(+) create mode 100644 spec/factories/gpg_keys.rb diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 16de0b542d7..d77051850f3 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -21,6 +21,11 @@ class GpgKey < ActiveRecord::Base write_attribute(:key, value) end + def emails + raw_key = GPGME::Key.get(fingerprint) + raw_key.uids.map(&:email) + end + private def extract_fingerprint diff --git a/spec/factories/gpg_keys.rb b/spec/factories/gpg_keys.rb new file mode 100644 index 00000000000..e43a3c19672 --- /dev/null +++ b/spec/factories/gpg_keys.rb @@ -0,0 +1,7 @@ +require_relative '../support/gpg_helpers' + +FactoryGirl.define do + factory :gpg_key do + key GpgHelpers.public_key + end +end diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 02623c52fa6..24ef291a021 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -38,4 +38,12 @@ describe GpgKey do expect(described_class.new(key: " #{key} ").key).to eq(key) end end + + describe '#emails' do + it 'returns the emails from the gpg key' do + gpg_key = create :gpg_key + + expect(gpg_key.emails).to match_array %w(mail@koffeinfrei.org lex@panter.ch) + end + end end -- cgit v1.2.1 From ab4120de3165ea262de726aa3e102b74951d2bca Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 22 Feb 2017 16:22:39 +0100 Subject: only validate gpg_key#fingerprint "internally" --- app/models/gpg_key.rb | 14 +++++++++----- spec/models/gpg_key_spec.rb | 2 -- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index d77051850f3..b012db1428f 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -3,17 +3,21 @@ class GpgKey < ActiveRecord::Base belongs_to :user - validates :fingerprint, - presence: true, - uniqueness: true - validates :key, presence: true, uniqueness: true, format: { - with: /\A#{KEY_PREFIX}((?!#{KEY_PREFIX}).)+\Z/m + with: /\A#{KEY_PREFIX}((?!#{KEY_PREFIX}).)+\Z/m, + message: "is invalid. A valid public GPG key begins with '#{KEY_PREFIX}'" } + validates :fingerprint, + presence: true, + uniqueness: true, + # only validate when the `key` is valid, as we don't want the user to show + # the error about the fingerprint + unless: -> { errors.has_key?(:key) } + before_validation :extract_fingerprint def key=(value) diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 24ef291a021..1c5dd95ba65 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -6,8 +6,6 @@ describe GpgKey do end describe "validation" do - it { is_expected.to validate_presence_of(:fingerprint) } - it { is_expected.to validate_presence_of(:key) } it { is_expected.to validate_uniqueness_of(:key) } it { is_expected.to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----\nkey").for(:key) } -- cgit v1.2.1 From 7b4d29f4b5b02b5aee3e3cbfc8282965a38c4622 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 22 Feb 2017 16:24:48 +0100 Subject: add profile gpg key page to manage gpg keys --- app/controllers/profiles/gpg_keys_controller.rb | 33 +++++++++++++++++++ app/models/user.rb | 1 + app/views/layouts/nav/_profile.html.haml | 4 +++ app/views/profiles/gpg_keys/_form.html.haml | 10 ++++++ app/views/profiles/gpg_keys/_key.html.haml | 13 ++++++++ app/views/profiles/gpg_keys/_key_table.html.haml | 11 +++++++ app/views/profiles/gpg_keys/index.html.haml | 18 +++++++++++ config/routes/profile.rb | 1 + spec/features/profiles/gpg_keys_spec.rb | 40 ++++++++++++++++++++++++ 9 files changed, 131 insertions(+) create mode 100644 app/controllers/profiles/gpg_keys_controller.rb create mode 100644 app/views/profiles/gpg_keys/_form.html.haml create mode 100644 app/views/profiles/gpg_keys/_key.html.haml create mode 100644 app/views/profiles/gpg_keys/_key_table.html.haml create mode 100644 app/views/profiles/gpg_keys/index.html.haml create mode 100644 spec/features/profiles/gpg_keys_spec.rb diff --git a/app/controllers/profiles/gpg_keys_controller.rb b/app/controllers/profiles/gpg_keys_controller.rb new file mode 100644 index 00000000000..b04c14a6993 --- /dev/null +++ b/app/controllers/profiles/gpg_keys_controller.rb @@ -0,0 +1,33 @@ +class Profiles::GpgKeysController < Profiles::ApplicationController + def index + @gpg_keys = current_user.gpg_keys + @gpg_key = GpgKey.new + end + + def create + @gpg_key = current_user.gpg_keys.new(gpg_key_params) + + if @gpg_key.save + redirect_to profile_gpg_keys_path + else + @gpg_keys = current_user.gpg_keys.select(&:persisted?) + render :index + end + end + + def destroy + @gpp_key = current_user.gpg_keys.find(params[:id]) + @gpp_key.destroy + + respond_to do |format| + format.html { redirect_to profile_gpg_keys_url, status: 302 } + format.js { head :ok } + end + end + + private + + def gpg_key_params + params.require(:gpg_key).permit(:key) + end +end diff --git a/app/models/user.rb b/app/models/user.rb index c26be6d05a2..5aebd36cf8a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -76,6 +76,7 @@ class User < ActiveRecord::Base where(type.not_eq('DeployKey').or(type.eq(nil))) end, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_many :deploy_keys, -> { where(type: 'DeployKey') }, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent + has_many :gpg_keys, dependent: :destroy has_many :emails, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_many :personal_access_tokens, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml index 424905ea890..26d9640e98a 100644 --- a/app/views/layouts/nav/_profile.html.haml +++ b/app/views/layouts/nav/_profile.html.haml @@ -43,6 +43,10 @@ = link_to profile_keys_path, title: 'SSH Keys' do %span SSH Keys + = nav_link(controller: :gpg_keys) do + = link_to profile_gpg_keys_path, title: 'GPG Keys' do + %span + GPG Keys = nav_link(controller: :preferences) do = link_to profile_preferences_path, title: 'Preferences' do %span diff --git a/app/views/profiles/gpg_keys/_form.html.haml b/app/views/profiles/gpg_keys/_form.html.haml new file mode 100644 index 00000000000..3fcf563d970 --- /dev/null +++ b/app/views/profiles/gpg_keys/_form.html.haml @@ -0,0 +1,10 @@ +%div + = form_for [:profile, @gpg_key], html: { class: 'js-requires-input' } do |f| + = form_errors(@gpg_key) + + .form-group + = f.label :key, class: 'label-light' + = f.text_area :key, class: "form-control", rows: 8, required: true, placeholder: "Don't paste the private part of the GPG key. Paste the public part which begins with '-----BEGIN PGP PUBLIC KEY BLOCK-----'." + + .prepend-top-default + = f.submit 'Add key', class: "btn btn-create" diff --git a/app/views/profiles/gpg_keys/_key.html.haml b/app/views/profiles/gpg_keys/_key.html.haml new file mode 100644 index 00000000000..fc167698ccd --- /dev/null +++ b/app/views/profiles/gpg_keys/_key.html.haml @@ -0,0 +1,13 @@ +%li.key-list-item + .pull-left.append-right-10 + = icon 'key', class: "settings-list-icon hidden-xs" + .key-list-item-info + = key.emails.join(' ') + .description + = key.fingerprint + .pull-right + %span.key-created-at + created #{time_ago_with_tooltip(key.created_at)} + = link_to profile_gpg_key_path(key), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-transparent prepend-left-10" do + %span.sr-only Remove + = icon('trash') diff --git a/app/views/profiles/gpg_keys/_key_table.html.haml b/app/views/profiles/gpg_keys/_key_table.html.haml new file mode 100644 index 00000000000..cabb92c5a24 --- /dev/null +++ b/app/views/profiles/gpg_keys/_key_table.html.haml @@ -0,0 +1,11 @@ +- is_admin = local_assigns.fetch(:admin, false) + +- if @gpg_keys.any? + %ul.well-list + = render partial: 'profiles/gpg_keys/key', collection: @gpg_keys, locals: { is_admin: is_admin } +- else + %p.settings-message.text-center + - if is_admin + There are no GPG keys associated with this account. + - else + There are no GPG keys with access to your account. diff --git a/app/views/profiles/gpg_keys/index.html.haml b/app/views/profiles/gpg_keys/index.html.haml new file mode 100644 index 00000000000..30066522766 --- /dev/null +++ b/app/views/profiles/gpg_keys/index.html.haml @@ -0,0 +1,18 @@ +- page_title "GPG Keys" += render 'profiles/head' + +.row.prepend-top-default + .col-lg-3.profile-settings-sidebar + %h4.prepend-top-0 + = page_title + %p + GPG keys allow you to verify signed commits. + .col-lg-9 + %h5.prepend-top-0 + Add an GPG key + = render 'form' + %hr + %h5 + Your GPG keys (#{@gpg_keys.count}) + .append-bottom-default + = render 'key_table' diff --git a/config/routes/profile.rb b/config/routes/profile.rb index 3dc890e5785..00388b9c0cd 100644 --- a/config/routes/profile.rb +++ b/config/routes/profile.rb @@ -23,6 +23,7 @@ resource :profile, only: [:show, :update] do end resource :preferences, only: [:show, :update] resources :keys, only: [:index, :show, :create, :destroy] + resources :gpg_keys, only: [:index, :create, :destroy] resources :emails, only: [:index, :create, :destroy] resources :chat_names, only: [:index, :new, :create, :destroy] do collection do diff --git a/spec/features/profiles/gpg_keys_spec.rb b/spec/features/profiles/gpg_keys_spec.rb new file mode 100644 index 00000000000..223f2e81842 --- /dev/null +++ b/spec/features/profiles/gpg_keys_spec.rb @@ -0,0 +1,40 @@ +require 'rails_helper' + +feature 'Profile > GPG Keys', :gpg do + let(:user) { create(:user) } + + before do + login_as(user) + end + + describe 'User adds a key' do + before do + visit profile_gpg_keys_path + end + + scenario 'saves the new key' do + fill_in('Key', with: attributes_for(:gpg_key)[:key]) + click_button('Add key') + + expect(page).to have_content('mail@koffeinfrei.org lex@panter.ch') + expect(page).to have_content('4F4840A503964251CF7D7F5DC728AF10972E97C0') + end + end + + scenario 'User sees their keys' do + create(:gpg_key, user: user) + visit profile_gpg_keys_path + + expect(page).to have_content('mail@koffeinfrei.org lex@panter.ch') + expect(page).to have_content('4F4840A503964251CF7D7F5DC728AF10972E97C0') + end + + scenario 'User removes a key via the key index' do + create(:gpg_key, user: user) + visit profile_gpg_keys_path + + click_link('Remove') + + expect(page).to have_content('Your GPG keys (0)') + end +end -- cgit v1.2.1 From e34cef0cd2fcf9a01d3f3b6dd215bbcc25d65d27 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 22 Feb 2017 17:20:42 +0100 Subject: extract gpg functionality to lib class --- app/models/gpg_key.rb | 6 +----- lib/gitlab/gpg.rb | 32 ++++++++++++++++++++++++++++++++ spec/lib/gitlab/gpg_spec.rb | 20 ++++++++++++++++++++ spec/spec_helper.rb | 8 +------- 4 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 lib/gitlab/gpg.rb create mode 100644 spec/lib/gitlab/gpg_spec.rb diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index b012db1428f..aa0e8883a47 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -33,12 +33,8 @@ class GpgKey < ActiveRecord::Base private def extract_fingerprint - import = GPGME::Key.import(key) - - return if import.considered == 0 - # we can assume that the result only contains one item as the validation # only allows one key - self.fingerprint = import.imports.first.fingerprint + self.fingerprint = Gitlab::Gpg.fingerprints_from_key(key).first end end diff --git a/lib/gitlab/gpg.rb b/lib/gitlab/gpg.rb new file mode 100644 index 00000000000..373ef79ab85 --- /dev/null +++ b/lib/gitlab/gpg.rb @@ -0,0 +1,32 @@ +module Gitlab + module Gpg + extend self + + def fingerprints_from_key(key) + using_tmp_keychain do + import = GPGME::Key.import(key) + + return [] if import.imported == 0 + + import.imports.map(&:fingerprint) + end + end + + def using_tmp_keychain + Dir.mktmpdir do |dir| + @original_dirs ||= [GPGME::Engine.dirinfo('homedir')] + @original_dirs.push(dir) + + GPGME::Engine.home_dir = dir + + return_value = yield + + @original_dirs.pop + + GPGME::Engine.home_dir = @original_dirs[-1] + + return_value + end + end + end +end diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb new file mode 100644 index 00000000000..a59302e6738 --- /dev/null +++ b/spec/lib/gitlab/gpg_spec.rb @@ -0,0 +1,20 @@ +require 'rails_helper' + +describe Gitlab::Gpg do + describe '.fingerprints_from_key' do + it 'returns the fingerprint' do + expect( + described_class.fingerprints_from_key(GpgHelpers.public_key) + ).to eq ['4F4840A503964251CF7D7F5DC728AF10972E97C0'] + end + + it 'returns an empty array when the key is invalid' do + expect( + described_class.fingerprints_from_key('bogus') + ).to eq [] + end + end + + describe '.add_to_keychain' do + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 6b4ec608efb..a0df233507b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -143,14 +143,8 @@ RSpec.configure do |config| end config.around(:each, :gpg) do |example| - Dir.mktmpdir do |dir| - original_dir = GPGME::Engine.dirinfo('homedir') - - GPGME::Engine.home_dir = dir - + Gitlab::Gpg.using_tmp_keychain do example.run - - GPGME::Engine.home_dir = original_dir end end end -- cgit v1.2.1 From 87c0fd34557463528a552986a42f4ebb52d3bd56 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 22 Feb 2017 18:36:25 +0100 Subject: add / remove gpg keys to / from system keychain --- app/models/gpg_key.rb | 10 ++++++++++ lib/gitlab/gpg.rb | 8 ++++++++ spec/lib/gitlab/gpg_spec.rb | 20 +++++++++++++++++++- spec/models/gpg_key_spec.rb | 24 +++++++++++++++++++++--- spec/support/gpg_helpers.rb | 2 +- 5 files changed, 59 insertions(+), 5 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index aa0e8883a47..a9f1400650c 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -19,6 +19,8 @@ class GpgKey < ActiveRecord::Base unless: -> { errors.has_key?(:key) } before_validation :extract_fingerprint + after_create :add_to_keychain + after_destroy :remove_from_keychain def key=(value) value.strip! unless value.blank? @@ -37,4 +39,12 @@ class GpgKey < ActiveRecord::Base # only allows one key self.fingerprint = Gitlab::Gpg.fingerprints_from_key(key).first end + + def add_to_keychain + Gitlab::Gpg.add_to_keychain(key) + end + + def remove_from_keychain + Gitlab::Gpg.remove_from_keychain(fingerprint) + end end diff --git a/lib/gitlab/gpg.rb b/lib/gitlab/gpg.rb index 373ef79ab85..64f18d00e46 100644 --- a/lib/gitlab/gpg.rb +++ b/lib/gitlab/gpg.rb @@ -12,6 +12,14 @@ module Gitlab end end + def add_to_keychain(key) + GPGME::Key.import(key) + end + + def remove_from_keychain(fingerprint) + GPGME::Key.get(fingerprint).delete! + end + def using_tmp_keychain Dir.mktmpdir do |dir| @original_dirs ||= [GPGME::Engine.dirinfo('homedir')] diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index a59302e6738..2f779492c24 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -15,6 +15,24 @@ describe Gitlab::Gpg do end end - describe '.add_to_keychain' do + describe '.add_to_keychain', :gpg do + it 'stores the key in the keychain' do + expect(GPGME::Key.find(:public, '4F4840A503964251CF7D7F5DC728AF10972E97C0')).to eq [] + + Gitlab::Gpg.add_to_keychain(GpgHelpers.public_key) + + expect(GPGME::Key.find(:public, '4F4840A503964251CF7D7F5DC728AF10972E97C0')).not_to eq [] + end + end + + describe '.remove_from_keychain', :gpg do + it 'removes the key from the keychain' do + Gitlab::Gpg.add_to_keychain(GpgHelpers.public_key) + expect(GPGME::Key.find(:public, '4F4840A503964251CF7D7F5DC728AF10972E97C0')).not_to eq [] + + Gitlab::Gpg.remove_from_keychain('4F4840A503964251CF7D7F5DC728AF10972E97C0') + + expect(GPGME::Key.find(:public, '4F4840A503964251CF7D7F5DC728AF10972E97C0')).to eq [] + end end end diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 1c5dd95ba65..facdf91550f 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -13,14 +13,32 @@ describe GpgKey do it { is_expected.not_to allow_value('BEGIN PGP').for(:key) } end - context 'callbacks' do + context 'callbacks', :gpg do describe 'extract_fingerprint' do - it 'extracts the fingerprint from the gpg key', :gpg do + it 'extracts the fingerprint from the gpg key' do gpg_key = described_class.new(key: GpgHelpers.public_key) gpg_key.valid? expect(gpg_key.fingerprint).to eq '4F4840A503964251CF7D7F5DC728AF10972E97C0' end end + + describe 'add_to_keychain' do + it 'calls add_to_keychain after create' do + expect(Gitlab::Gpg).to receive(:add_to_keychain).with(GpgHelpers.public_key) + create :gpg_key + end + end + + describe 'remove_from_keychain' do + it 'calls remove_from_keychain after destroy' do + allow(Gitlab::Gpg).to receive :add_to_keychain + gpg_key = create :gpg_key + + expect(Gitlab::Gpg).to receive(:remove_from_keychain).with('4F4840A503964251CF7D7F5DC728AF10972E97C0') + + gpg_key.destroy! + end + end end describe '#key=' do @@ -37,7 +55,7 @@ describe GpgKey do end end - describe '#emails' do + describe '#emails', :gpg do it 'returns the emails from the gpg key' do gpg_key = create :gpg_key diff --git a/spec/support/gpg_helpers.rb b/spec/support/gpg_helpers.rb index 3b50d831b00..2f440488546 100644 --- a/spec/support/gpg_helpers.rb +++ b/spec/support/gpg_helpers.rb @@ -29,7 +29,7 @@ module GpgHelpers end def public_key - <<~PUBLICKEY + <<~PUBLICKEY.strip -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1 -- cgit v1.2.1 From eb77e1068c09cf8ef45689720a2bf200542b8024 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 23 Feb 2017 12:02:36 +0100 Subject: add second gpg key for specs --- spec/factories/gpg_keys.rb | 2 +- spec/lib/gitlab/gpg_spec.rb | 6 +- spec/models/commit_spec.rb | 10 +- spec/models/gpg_key_spec.rb | 4 +- spec/support/gpg_helpers.rb | 510 ++++++++++++++++++++++++++------------------ 5 files changed, 309 insertions(+), 223 deletions(-) diff --git a/spec/factories/gpg_keys.rb b/spec/factories/gpg_keys.rb index e43a3c19672..70c2875b985 100644 --- a/spec/factories/gpg_keys.rb +++ b/spec/factories/gpg_keys.rb @@ -2,6 +2,6 @@ require_relative '../support/gpg_helpers' FactoryGirl.define do factory :gpg_key do - key GpgHelpers.public_key + key GpgHelpers::User1.public_key end end diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index 2f779492c24..04a434a993d 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -4,7 +4,7 @@ describe Gitlab::Gpg do describe '.fingerprints_from_key' do it 'returns the fingerprint' do expect( - described_class.fingerprints_from_key(GpgHelpers.public_key) + described_class.fingerprints_from_key(GpgHelpers::User1.public_key) ).to eq ['4F4840A503964251CF7D7F5DC728AF10972E97C0'] end @@ -19,7 +19,7 @@ describe Gitlab::Gpg do it 'stores the key in the keychain' do expect(GPGME::Key.find(:public, '4F4840A503964251CF7D7F5DC728AF10972E97C0')).to eq [] - Gitlab::Gpg.add_to_keychain(GpgHelpers.public_key) + Gitlab::Gpg.add_to_keychain(GpgHelpers::User1.public_key) expect(GPGME::Key.find(:public, '4F4840A503964251CF7D7F5DC728AF10972E97C0')).not_to eq [] end @@ -27,7 +27,7 @@ describe Gitlab::Gpg do describe '.remove_from_keychain', :gpg do it 'removes the key from the keychain' do - Gitlab::Gpg.add_to_keychain(GpgHelpers.public_key) + Gitlab::Gpg.add_to_keychain(GpgHelpers::User1.public_key) expect(GPGME::Key.find(:public, '4F4840A503964251CF7D7F5DC728AF10972E97C0')).not_to eq [] Gitlab::Gpg.remove_from_keychain('4F4840A503964251CF7D7F5DC728AF10972E97C0') diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 0fc00ab4f18..3c6ce49b48d 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -422,11 +422,11 @@ eos context 'signed commit', :gpg do it 'returns a valid signature if the public key is known' do - GPGME::Key.import(GpgHelpers.public_key) + GPGME::Key.import(GpgHelpers::User1.public_key) raw_commit = double(:raw_commit, signature: [ - GpgHelpers.signed_commit_signature, - GpgHelpers.signed_commit_base_data + GpgHelpers::User1.signed_commit_signature, + GpgHelpers::User1.signed_commit_base_data ]) allow(raw_commit).to receive :save! @@ -440,8 +440,8 @@ eos it 'returns an invalid signature if the public commit is unknown', :gpg do raw_commit = double(:raw_commit, signature: [ - GpgHelpers.signed_commit_signature, - GpgHelpers.signed_commit_base_data + GpgHelpers::User1.signed_commit_signature, + GpgHelpers::User1.signed_commit_base_data ]) allow(raw_commit).to receive :save! diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index facdf91550f..6bfd0b0d4f6 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -16,7 +16,7 @@ describe GpgKey do context 'callbacks', :gpg do describe 'extract_fingerprint' do it 'extracts the fingerprint from the gpg key' do - gpg_key = described_class.new(key: GpgHelpers.public_key) + gpg_key = described_class.new(key: GpgHelpers::User1.public_key) gpg_key.valid? expect(gpg_key.fingerprint).to eq '4F4840A503964251CF7D7F5DC728AF10972E97C0' end @@ -24,7 +24,7 @@ describe GpgKey do describe 'add_to_keychain' do it 'calls add_to_keychain after create' do - expect(Gitlab::Gpg).to receive(:add_to_keychain).with(GpgHelpers.public_key) + expect(Gitlab::Gpg).to receive(:add_to_keychain).with(GpgHelpers::User1.public_key) create :gpg_key end end diff --git a/spec/support/gpg_helpers.rb b/spec/support/gpg_helpers.rb index 2f440488546..375f4415846 100644 --- a/spec/support/gpg_helpers.rb +++ b/spec/support/gpg_helpers.rb @@ -1,222 +1,308 @@ module GpgHelpers - extend self + module User1 + extend self - def signed_commit_signature - <<~SIGNATURE - -----BEGIN PGP SIGNATURE----- - Version: GnuPG v1 + def signed_commit_signature + <<~SIGNATURE + -----BEGIN PGP SIGNATURE----- + Version: GnuPG v1 - iQEcBAABAgAGBQJYpIi9AAoJEMcorxCXLpfAZZIH/R/nhcC4s0j6nqAsi9Kbc4DX - TGZyfjed6puWzqnT90Vy+WyUC7FjWJpkuOKQz+NQD9JcBMRp/OC0GtkNz4djv1se - Nup29qWd+Fg2XGEBakTxAo2e9cg38a2rGEIL6V8i+tYAhDt5OyLdzD/XsF0vt02E - ZikSvV02c6ByrjPq37ZdOgnk1xJrS1NM0Sn4B7L3cAz6TYb1OvyG1Z4HnMWgTBHy - e/uKLPRYhx7a4D4TEt4/JWN3sb0VnaToG623EdJ1APF/MK9Es+H7YfgBsyu18nss - 705F+PZ2vx/1b9z5dLc/jQNf+k9vQH4uhmOFwUJnuQ/qB4/3H/UyLH/HfomK7Zk= - =fzCF - -----END PGP SIGNATURE----- - SIGNATURE - end + iQEcBAABAgAGBQJYpIi9AAoJEMcorxCXLpfAZZIH/R/nhcC4s0j6nqAsi9Kbc4DX + TGZyfjed6puWzqnT90Vy+WyUC7FjWJpkuOKQz+NQD9JcBMRp/OC0GtkNz4djv1se + Nup29qWd+Fg2XGEBakTxAo2e9cg38a2rGEIL6V8i+tYAhDt5OyLdzD/XsF0vt02E + ZikSvV02c6ByrjPq37ZdOgnk1xJrS1NM0Sn4B7L3cAz6TYb1OvyG1Z4HnMWgTBHy + e/uKLPRYhx7a4D4TEt4/JWN3sb0VnaToG623EdJ1APF/MK9Es+H7YfgBsyu18nss + 705F+PZ2vx/1b9z5dLc/jQNf+k9vQH4uhmOFwUJnuQ/qB4/3H/UyLH/HfomK7Zk= + =fzCF + -----END PGP SIGNATURE----- + SIGNATURE + end + + def signed_commit_base_data + <<~SIGNEDDATA + tree ed60cfd202644fda1abaf684e7d965052db18c13 + parent 4ded8b5ce09d2b665e5893945b29d8d626691086 + author Alexis Reigel 1487177917 +0100 + committer Alexis Reigel 1487177917 +0100 + + signed commit, verified key/email + SIGNEDDATA + end - def signed_commit_base_data - <<~SIGNEDDATA - tree ed60cfd202644fda1abaf684e7d965052db18c13 - parent 4ded8b5ce09d2b665e5893945b29d8d626691086 - author Alexis Reigel 1487177917 +0100 - committer Alexis Reigel 1487177917 +0100 + def public_key + <<~PUBLICKEY.strip + -----BEGIN PGP PUBLIC KEY BLOCK----- + Version: GnuPG v1 - signed commit, verified key/email - SIGNEDDATA + mQENBFMOSOgBCADFCYxmnXFbrDhfvlf03Q/bQuT+nZu46BFGbo7XkUjDowFXJQhP + PTyxRpAxQXVCRgYs1ISoI+FS22SH+EYq8FSoIMWBwJ+kynvJx14a9EpSDxwgNnfJ + RL+1Cqo6+BzBiTueOmbLm1IYLtCR6IbAHAyj5YUUB6WU7NtZjJUn7tZg3uxNTr7C + TNnn88ohzfFa9NfwZx0YwgxEMn0ijipdEtdx5T/0vGHlZ+WRq88atEu00WNn0x65 + upvjk7I1vB9DTZp/zPTZbUGPNwm6qw9xozNFg/LcdbSMryh0Xg9pPRY6Agw2Jpgi + XxNAApDrlnaexigFfffUkkHac+0EoXwceu8zABEBAAG0HUFsZXhpcyBSZWlnZWwg + PGxleEBwYW50ZXIuY2g+iQE4BBMBAgAiBQJTDkjoAhsDBgsJCAcDAgYVCAIJCgsE + FgIDAQIeAQIXgAAKCRDHKK8Qly6XwO1VB/0aG5oT5ElKvLottcfTL2qpmX2Luwck + FOeR4HOrBgmIuGxasgpIFJXOz1JN/uSB5wWy02WjofupMh88NNGcGA3P4rFbXq8v + yKtmM62yTrYjsmEd64NFwvfcRKzbK57oLUdlZIOMquCe9rTS77Ll/9HIUJXoRmAX + RA0HUtn0RnNF492bV+16ShF3xoh5mVU4v+muTA/izW7lSQ2PtFd2inDvyDyiNKzg + WOUlZESc6YN/kkUJj/4YjqPgIURNx6q/jGw24gH4z6bZ8RfloaEjmhSX0gA4lnMQ + 8+54FADPqQRiXd3Jx5RRUJCOcJ+Z17I4Vfh1IZLlKVlMDvUh4g2SxSSGiQEcBBAB + AgAGBQJTkXXXAAoJEKK3SgWnore32hgH/RFjh9B+er5+ldP4D9/h887AR9E1xN7r + DTN7EF5jlfgXkIAaxk2/my+NNe0qZog9YBrVR+n8LGgwXRnyN9w1yhUE4eO71Zwi + dg4SgU5fK3asWLu+/esKD2S/QndRwIpZOTqsmiqe8N8cVscaoAg+G/TnDJvTKft1 + twIcjrB1fv9B3Fnehy/g/ao+/E1/7CknWE6zB4eSQdOrAfQ9gnJgabLRBUUVltBm + dBZ+lAQyBSAEbkL5FgWhxJNMjuTOVr6IYWvRXneHrMy630wZIk0d7tPEZJvBeIKA + FMtzBJvW6gJ/Xd5mbtb+qvoxfh8Z06vfqNMmhLLEYuvEW1xFSmyWWGuJARwEEAEC + AAYFAlSGz8kACgkQZbw57+NVY/GU0Qf+KCAPBUjVBZeSXJh/7ynsWpNNewZOYyZV + n7fs8tm7soJfISZUbwVAPK8HwGpzrrTW9rpuhKmTgXCbFJszuHys4z3xveByu56y + bmA1izmhaLib1kN9Q7BYzf8gdB657H4AAwwTOQPewyQ2HJxsilM1UVb5x9452oTe + CgigGKVnUT556JZ8I8bs+0hKWJU3aDDyjdaSK82S1dCIPyanhTWTb2wk1vTz5Bw1 + LyKZ8Wasfer6Bk6WJ9JSQRQlg4QRkaK6V5SD33yOyUuXM7oKgLLGPc0qRC6mzHtz + Sq7wkg2K/ZLmBd72/gi3FmhESeU6oKKj6ivboMHXAq+9LuBh30D0cIhGBBARAgAG + BQJTmae5AAoJECUmW1Z+JGhyITgAoJoFNd5Rz9YFh8XhRwA6GaFb7cHfAKCKFVtn + Bks20ZiBiAAl3+3BDroNJ4kBHAQQAQIABgUCVXqf+QAKCRDCDc5p2mWzH3gTB/41 + X9v9LP9oeDNL4tVKhkE8zCTjIKZ8niHYnwHQIGk4Nqz6noV/Qa45xvqCbIYtizKZ + Csqg2nYYkfG2njGPMKTTvtg5UdilUuQEYOFLRod3deuuEelqyNZNsqSOp7Jj5Nzv + DpipI5GxvyI/DD7GQwHHm5nspiBv/ORs3rcT4XatdTp6LhVTNyAp060oQ/aLXVW4 + y1YffvVViKe/ojDcKdUVssXVoKOs4NVImQoHXkHVSmFv0Cb5BGeYd58/j12zLxlk + 7Px9fualT6e5E7lqYl7uZ63t32KKosHNV+RC0VW8jFOblBANxbh6wIXF7qU6mVEA + HUT7th2KlY51an2UmRvTiQEcBBABAgAGBQJWCVptAAoJEH9ChqPNQcDdQZAH/RiY + Wb7VgOKOZpCgBpRvFMnMDH2PYLd6hr1TqJ6GUeq3WPUzlEsqGWF5uT3m07M09esJ + mlYufkmsD89ehZxYfROQ8BA3rTqjzhO9V0rNFm/o8SBbyuGnQwFWOTAgnVC1Hvth + kJM+7JgG8t6qpIpGmMz6uij7hkWYdphhN0SqoS8XgAtjdXK6G5fYpJafwlg7TGFD + F6q5d2RX0BdUhJkIOFNI/JXLpX04WiXEQl2hOwB3la/CT2oqYQONUbzoehUaF5SV + uKlFruUoZ/rbJM1J4imdcEBH2X3bnzdapCqvMudgAALo8NUiJJ/iTiYx/sxQ4XUp + oF567flP1Q08q6w66OyJAhwEEAECAAYFAlODZOkACgkQ5LbUbWbHh8yNzBAAk6LE + nfbdmx2PsFS21ZP8eAiPMBZ61sfmDVgNU5qLDyQRk+xg7lZlFlZ64mka4Bh82rvV + 4evcEOHbuiYS4zupxI9XrBvBpks6mALEAAX/5HXYDgb/9ghNd0xjlheHmMKJk8jE + Mb2kYx/UCimbtG460ZiQg0e+OWNU5fgMEjA8h6FMbt0axPkX+kde+OSg52i1bL5n + fPbGqA3o1+u2FzsufuCEOPsTLKhkiOKnopCMtB8kRih+WQ73G3XkYSkYh2bYW0eF + MoZlgez5lpUWLD0+NWB9qiDXZs1yUJ0CdHA98eahPaPyR8aLqOP0dPkbS6/X4j6N + WjZgZ2sIb8PihowiHYeogMhZZIoBTYqRlbW9/KAptC7UGFMF21Vp7HexFRuoC8qO + PSXfMLH4kw0Lq1mLBTw9+No0L7xfMxKmzT0VLsJkJB09gAGWv2/8voCIPtBm/MZi + C9o3w3tWAczAvZetMXH/dp8Por6pmMoTHHUkbSBZHe1Lt138jLtozZDCuuWQ53O/ + mIT1sds1Oy6IF4e0xrSqpZlDGwj0pqOKmtLFI1ZRrfjb5bnm7sgzcxoM5aPhqJyb + 88XYgBolsiErM+WhnH6cAEK2TUVlVqXzDIbqKBroEK/cM+Bez1SagzAsoarYA5R1 + yewc0ga/1jQI4m6+2WoL4wo4wMNggdWiIWbuqAmJAhwEEAEKAAYFAlZDO+4ACgkQ + MH93QRZS4oGShw/6A6Loa5V9RI9Vqi7AJGFbMVnFJV/oaUrOq8mE8fEY/cw1LQ5h + Ag/8Nx7ZpQc28KbCo0MR3Pj7r2WZKLcxMwaXlFZtNiO4cEITNu5eoC7+KOrFACsO + 1c0dKbMEeDQ2Xqzo2ihw/4DnkuUenrmGnNJMQ5LrEZinSKFFAgeYRdYnMdYqOcXe + Q8rPImFkyOnPbdIOC2yPzjqHIsuazuwd9to+p35VzPNZv7ELFBfx/xDHifniRMrm + sPJh6ABjecOJg7RJW4h9qP+bNbbrJa6VfGAbNUR+h4DiMr6whpGJd41IiXIEGrGW + BT87hO7gwpMrex0loQoHwsfqMxOM0qwMU9ARCJJLctzkj727m/SsyP9cUIFGceBN + cUopmpKCi9z0QZ/bxKWbpqa3AarkWxRLj1ZzmllxC7tjO61kr0zkn8pnEIc79cGw + QlUI9k7QaWFm1yDlpPXLvBi+evYxSONbsSoHwjMIC/cioBh0c0LOXn8TV6OWlS/3 + sWShQG9KxugZdK+MBrZPR23jilHPKpWG8ddEWp4BZugqxppiyZAgEOMlHBr5PkV+ + hBx1vCG0w9IlMJODRIXIUeqot3ixQvLmeoWTuIFPiNPfXskCfNuudbj4+jZewf6z + BL60VJADKJENmsDPPhF6UEiHDIrauNylORhhPR/qEAs4LOiEwRqRtHBEqYKIRgQQ + EQoABgUCU39OnwAKCRA1morv4C3iPRylAKChT88Lvmd1M5LX1hoRqsFeG8IahgCf + Q1VWKh852oZq9dOtbGRxEbv876OIRgQQEQoABgUCU+DpHgAKCRBmKanAQloCxoSL + AJ44D4cwTLOmw+rHl6bB/oqNhoV3bQCbBmyupEB9gn6NUD80BTEzs0jTHWSJAhwE + EAECAAYFAlNv5m4ACgkQxykhoSk/LSQnZg/7BSrZULH/tRDRd1LvuKtHoR7AarqD + iGQXhxvXLp6AZaMcI1UF/hvKeJtho5tKjQ6OpEB1sPXXc68abvRdJFh42GBPmHFD + A8aBsJJePZQTMm4biDfFNw7cK1j0cjUczftAlyFAf5w5y2kM5jo24qdNmVqa5ipE + u0AcmzNntgaWeP9izXdnjpNTSOG6Rbo84IrIku7sR8GxNvlisAS1hhwYkYksNts4 + gu+wmfnkLFyZrncbjVHLVbZnAJhhcdWKhyjcOBRadrAZ/EoK1/3VoLHIdWBpW0f9 + sUYv3u6WUyWa4EFaaHRxttMFWhWq9p2nYfojh2Bf5V6cOLgikkIu03oQp2GPNnOL + ub0PTmSS+93ZmIEW9NIxY0cmz8lFVo9qqip4Dzka2Rp3oTg0x3JKXU+OZV4J/Mfa + LT5uI3Flub3f8etOQw+6/Q5Rg3vGOh14UtEVaA1WcKeyRq7v+XZAA16FN5omCEX8 + xA641xgefvLx4jj0ZfqlHgH+dEoOdbiRQ3IYyzMnX/xLl88Xw49etkeflQFXvkLh + e6QdXrfrm4ZniIWOfCDeQmZS0znDV46YzK0MVu6kYXcmDpVBRREUzsxgJmWg4JW2 + EgHTqSHL8Oi8gvfTMKaPSnTl3cWSKlupQDx/CYuuqdAd7x2hcSivWFu22YcNp4XV + fd0jJPvv+UlnmjOJARwEEAECAAYFAlRcmw8ACgkQlFPUWjJBWVgGCggAgZDWaPcj + Fce9mnRtMDyOVMOZQ0AppvbS97pJ6PLF/dKXz+nyNtkiAPfimRTE3BpXhX3JDke9 + PEaRH/dXTdmzfej9N3DOADFJlRVyxETXyTGiNzyP7vaJAT+9hgW7hbUtgoAbDK31 + ZWijVEw4+Jg9vWhUKBhLrV1lcyQyZAldLYep/sAyynAeaUbsFtbpH8DHXZBIA/0C + 2XWp7o01w8b1CgsUHBfBK9eNlQ3BOu3Y5WY8MW4ZcRuDlH/hbs9V1zK5vkR2zq4d + uSG8KYHsLV1/zskLszLZk27c6QHQb1C6U6CW8shgkdxGRduXMETRL4yYib3s4Mwy + xovU00cYKQ5CIokBHAQQAQIABgUCV2FHnwAKCRCZSfh4lwNdkn7DCACvBLx76e+5 + 9vaGdSne2veRwT/J/a5OWJghn7f679btAxJROvWdeHvWW4vHKz+A6HGvR8E7xGCZ + NdfkokqXcioSRcZFIW7zAev27F31E8V63voY2KDESlkxrRhNZBpvwfXAg2RS9KmB + btmgj6Zo1VnbEXoxPO+5yZzpYxuBPL7xMidSznQe9eswqMLvSNxKQODOGToddreb + 9ClKk+qpQOCTQTEQjw4Y9wjoZ5SdENP1IihnTi/Z31Sr99CL3jPPpXoo8WO4in6z + DPEEvAbszDb+24+WDEoW47ST+x4eDJG0WcVrjNa87k7kMNOWsPr9rNHtgRCNa22M + xaPaKrTZ/F03iQEcBBABCgAGBQJXc+wKAAoJEIhwMVR86tleqikIAKQtWDnrp1dl + tE4G1IVp2i9NwhCOaZVODaGaH3C564B8/WyEbjFjOmm4aDzykiwEUWBMCP0icpHn + 3o5s65gdtgnP/KVWKp3wyJqJYu0rQcyFtKNKi8x5D/7c8y23DRoI2lnI12f7MWPH + wzC3wClulTboV0mC2Cp1TWLBnKGbhpHOGN5ViSPm3rPOesFZ5el38wcwDKWaZbmm + hFtx8fx2T2lTP+5GRCuiXrnsrzA3tZLuRWH44esPxYB8mFg1btgAtXo9Q9MEISWL + g043RQ0VWU3a9F7K3RshTPAUbvUrNtEAFMtij0B4RvLE5cyHEltUB0R4ie3RDZDe + z0VCwrsaI+OJAhwEEAEIAAYFAlePuxUACgkQ+iIJCo0F+QvWZg/+I5R1TdQpMKVM + Fz+XrYXpSgPxeLr3b6svuV8uOPY8kYbOPVxvjbNGuyijbRD/btH9Qg2vDNGbZJ9G + pGUfnNNlXUsTkxp/5sEWAzBH0pTEgiy7wHzCa4u+meXDkLnomdZfSHkFNDw+I2MI + Nrp84DPkMBQ4X5AJ4UcoMUbfqLRbqgHo/DEAYsAwnihF4Lwl8x9ltokcAc+w3SQk + mvHOR1xoeAFtH3NEzUvA3EhZo16o7+dQWyh8GJRsgUA6g6zyqLOn+JTDVh1YlrAF + 1qkhnBsw7G5InL54mhvXwqKoAwI5zO8A+5tSUMUvtZBfUW2DX/yCvaD5v/fjMScF + 5Lw61NYTLyZEW+JlLGGdIrewB72BVPVR5Sak+dwwjxHK2NGdaug3V8gOht8ZwYKx + X9NmYLWi+4DFkQxtSCpwH6WAqfw4OPuvFHyd/VdA5czsQo15rU2Go5JE7FlR1xoy + lCNV4TU3p+eLTNW/L7ty4HPuiPWI3gDpRgh0Tv878IlLKuivlNhfTub8Hf4LzSW1 + g++1lwUf3TxhYUPHmZT2V9Sk+VVgCXIFenn914r+RZMnThCgWh2GmcKDgLKUSdxv + /j14NlTgWqUY3cQM/ciSdAdqZn8WAOjeuVgpqkX5A4NrWbshaqUsksm9QdtpMia1 + Q2hDuR8OIvHP0PiwNv8Bn00nAgyU2NeJAhwEEAEKAAYFAldP7ycACgkQu9aLHqU1 + +zaXsA//Rm+1ckvAAaj1qk9rXpYZVWK8kCeKkHu48bL9r0g9Z1mfCGTgrUd1lPNW + Lh850z+LYzJelZCqnNsgxX8KG567NwdRb+LBy8tzbCgIMomfgqILv7KmRzPQ6AJ7 + Bp8hGnregfD0CCXtEORk/aQF0FCRL8bKsKiN7DOPirP9gfdSgpshr1cLe8a7cPFq + Zza7VhAke5/BCsNzxaUvseuzZ6bZOXlUpbSJH2+f/DYXvwfaJl/Rg+s+DuPtqVgI + TMSsRwL/iIlqfT2Al4SVak4f0q/HVkNgfEFSx2i8OWlVe90V71sNNAOMSDnBRHBC + fNon4vwnv3xkKwH6ecwgZtZwcjPKMUZPjrzEFULOBrNAsC173HypbZZ/wlJBAMd5 + gBd35CQELrq2sOgekofm7Sbq5m2WYr35M0nqIV8q0ySxMWyuY2g46QQVEyGiXrKt + TyJzT7M+UtqD03wjNSBZc7y/a2+kzZJADrz8kNANuR5GGfxZ3zKjmgyQX2QRNYq+ + +bwB6U7NyRgzX/i3sE2pSn2xuwwzqk873r+Afb8gCMSXV1omcwZJAHeUURjv70mU + A9BFjE249JxjDbuzThiErMCG4Gj87NjXYCBq7QsfyKPVAx7esEYoDmR+k4nYH4my + pY1LTgLZUOBtGiLnkGIZ9XVIcZBPRoSKEpRRvcPBtHkJkqwQm8mJAhwEEAEKAAYF + AldQLVYACgkQsOAWYMCDwn9L4xAAgMxHehYdB6+htNj/c7xlFhdv6nyLl8excl0q + jOBLsN00w3F1yGZqNhbKsvHZKhW8PZhX+wMMoczGi1YdOV3AMoB20/t+DRh2giRL + wgLiJblxR4Z4Ge+/ne3/aVHOHyVqmh879TA2coUS0i0BpqRoY70eV/yVqkbXpuFm + reXLt3Syc3HoGd79KiyRht83Og/d7dbxkQOCe7YnRxuVynwMKgIRJt+UgCIM07sR + nA05MWgatp9PiFXkGdfyBy2UkvybcaAyjByBpOjdTPFa2LdjIO4Qsgmg8q8F3z0g + gW3bRPKQDNX6w7UA4tf587x0S1mKwXGeLnezZv1kmAQB//bYgZs4bZsqeB/i832I + sWzX7PEoh/kGWg9/eZBQu+l5d8koD2wRiUvFVussont7LMsNwHJSerS++tj5Tdwj + E8qcNdJYkcjkVxaHugVlm+IQfSrvdMpRq8bfwxGmprU3hAebB0b2OZDMm/uWGiVC + ycjStGUtu/ZJU56zRhkj/4yZPi7gczZAurRXvLt4AhNpkGPNSAxt16fpaBkBPo61 + pHir3K+FvpXN4ezv+mFR1G0hrSTuMk2nU1D7WUkw0xnx/IY7VrGx8PrR8Ilfb+C1 + 9z1g/uuZ4alIWXZ/tAeDPjTQI5QOPgj43DrgWqG2FDAqQ/+nt9RevUVIPMOojOko + BdHaskmJARwEEAEIAAYFAlguvT0ACgkQkDmkVrycD3gyvAf/fks3MtR+yoMRCNIi + VklGwoTv646OOqm3bDZz180cXqGXxSASQ7fglaDGl+of2qRyilU9dzkY1ZHqD2AY + /sycR1QKELfa9rFx12i4w9jyWdZykOggS6Os3e1Dvt9Q4fZzP0+eLCs8Fknancxq + WhUrXqaYz/OZj4Xmjw6jYZxdtJ/B0OFDqxOlN7v3iZSeXNwKJ5vpeJLE6dfy/5pM + ms3aIj8KB+MDSQpgaZ8FKjRn8rSZwUu768sHNTWv5l0UxJbIREB5XE8fQuGxPIJ+ + DyxiKmPMlyuyj6whz+iZP5jkEDpDiqFEJHHmw9qAlhkba0LzJYh2uqS7L15V6ykY + xZ4wl4kBHAQQAQgABgUCWC6/swAKCRDij8qPAN1CxhQJCACP+UCg5zM5h8HtLlPL + Pt1jofqmVqk8KJHJyZzn6EgyoQmNnPDybLHIRTxB+hsQTAZJtQn7UiBpXa0OmBXm + s4MdeRb0tIPN1l66l8+N7OuG0Tf+mALwAM+GqiUgSEGs5gOVF9Ev1pP0dRCKTSGJ + v0NMNUb77Qkn34R4HK+f0nfFKER4RW23F5e6sf6Rq4SzP3sVRdqU5dY1alxMFWNy + 7IrP/QdsBl6ACtYSFAuay/hxyccbu22KhIm0S2ikJJgjNenyq15TGaBoG02nl4lC + TgrOEjNDSXw2Bn4L6AZM8sR08ZjARqKspB7ZnNOcIaIrK61cpgAL4SXdMkvQF7Qj + uhatiQIcBBABCAAGBQJYNfShAAoJEMELqJFB1XEubX4P/0or+wvHMFC1lBTttKlO + mkPHTHDYZFCLQr/6cjAv5OPyrBOh/uJ+QJq6awrn1LD16j2YEZUkgkqHBiNl5f7R + J8Tl97esxZja5iHvgOx54NDxD97WoIgJhEnYuhvY7sACT5YBx4npMKPi0WaqgCfR + GDeQzVcKzgWhScgeSnWBf7+bwIdGO4mg9y58s/4fMK1kw6niK/xo1hkK0w41StV1 + wmK92fEqeFElseaBSmf8efgb4Qi6ic9Zf2mGgjHwTIn7FeTA9r6zzSggw3b5NEG6 + W2bdhVmKheYPBp+kdsQqsw9H/AzUFLL8wg982IRyvnbUkccP/7neWeFJo/1VVogp + ybTBdgxa+dl5UcjxvqJZbFp0mLorWJvOVamoGgvO2WKv0tSUK3LwVxZaIVMbFwEo + G+FfpW8XfqhzdkD6zJO3rjpOcnrouaYB/SpSofbwRxrtxTzcxxMP2B62gd7/VdcY + duyL6Cj21P3vIdveQ26B8zdSiv6MfG/7/zlrpe9strIv3UiHfpG8093TnPB2gwWL + /zdh7Nbsn3rq2Rti00zIqHpopPS4J/dr/jdpXzMymb93HpsA5UTuyYHnqa1YBAgn + qfnkk+lNENso6Ymg8a+S/oFh7Hks7olrhYpmdodL1AqU+YWMsp2L2knOxmpEZc8s + mjVx9YKKxrtZ7FisuwVER+3fiQEzBBABCAAdFiEE4gFIMof/a3u+jGQXNpvllaAP + nh4FAlhrniwACgkQNpvllaAPnh6e1QgAh646441z+ecM8k82DIctj1RT01tY5Ygz + WwDx4HJZy8b/l3J8PF62mZB045vC9DGweX7DgJ/FZXTwMGfS1lU7gBmIMJZnp8lU + m4K1IRgYf70T5LOepaYgJUJ9iPoc1bSw91efkdQSou6Fignet+DMk3268qbO/JO6 + Q8MbsD9XDND1pf6Y1gdtsrXaQTTqnf7l/5zbrYlknOBkDk4x7ZbYgZYfEucba4/R + 3O+dN7Eu9O7dS/PmYDvozPCuEIJrPwxdWnDr+0J6JwHwP9o2OD51CT/LfvL8uGtS + oPcmB4Oon1ORayDWWthlypYONP0kKwIFsR6mgU++UVNj+b+ABbizOokBHAQQAQoA + BgUCWH3oQQAKCRAfFBlUoHXkjEbvB/4zwwaKHd6B1d6XMzysG3/l29IxdNG8Udh0 + d8/o/jEl6jxJiIjVvaFTXXP1/owBjDSP/RwX0mMaluIfedghN+y21UQfi2QJ2FtV + d7hLTKjgLYStGZGakmUlaXvwZsshZmpQJDbFo6SWqBb68yjult8VTnoug+Q+I28o + p2y8sviFoEyBKnYXotSt9HNMLHtYUeFqJWAwVRIt14oaHXQjv7QuB9/RnuY6/sfC + In5y84sJyEylghP4C2+Usl5QtcAR5gByMvpfyPsFxXIcGw+Bxk9Sm0k37tCVAhKB + dIOMd85s8mQJ4nOZu2hLhKBlOgX1HNb/LJECG2QPqlSDtoFXrzcotCRBbGV4aXMg + UmVpZ2VsIDxtYWlsQGtvZmZlaW5mcmVpLm9yZz6JATgEEwECACIFAlicPfgCGwMG + CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEMcorxCXLpfAl0UH+QFkOIlIuFpb + 6MkAdp7qkaP58HG0nFZMWTLiwJnh4rclN5vvU7Dlvyy/JOI1M6wepBl3ujNJ+Pe1 + RL1Jy001sN9ZGvtkCiXwfg+3IRNAacQwdl39lUsaHbzSyo/33U7i9NaQ9QefLpji + on1auZMXQ8OVDPo2sT01kSwutMhYx/8wEc+kh/uckCYLFjx06mF1l+OGxc77CGbr + WeItjrjhTkYjsoaVh776V0Q2m08Ixq7pBXYp91zKT00EUE64LdIN85AkzehzSptF + +lT/BW2C1Ft5E588914PMKvNcufB0twaNFqKZUOCiIXO3cqlLoz5GHLe22mJKngo + NXVsbNZ/8zW5AQ0EUw5I6AEIAMb+U5s17opggc0fgejZleAv8ie1HIKms7PNlaMq + lzQj5bmFAln7DjUvupey8fkpLJtEGAJkp0vBiXohM3KOa78hr9ShJIVuFrz473jj + 9cAMlcLme2yDvPVjtTEFiVwl9+WXgvjtgkQjDKU1v9QJIC4UbcnzYwwyHuXXVUKW + v9gXj2a6Adk0cFF0qbNpBzfKrettsp02PUPlrceVhB8KDgY9/rj90uxQBmeZn9bP + G2W4zR+J+8kLcUAFlVhJasfItDo5bpFl7VH8hX5ZzXBL0NMQQoeNRtnrt/5xJ5Kl + BQbflScVaF1s+3oK75ppEeRZrYP5ESB5JBLUGuFO44hD/OkAEQEAAYkBHwQYAQIA + CQUCUw5I6AIbDAAKCRDHKK8Qly6XwLGiB/0ZUZf+ybfY6RQz4QoRw+RO290bf1Gx + wuL3PPCxaVX3POv1S0RLblYEP+88ikaYv6zpiEoohQPtCXdLfyJswRgTUNWS4DPZ + COW5TLLE2E/zYB0YGwLilZvAkopx+x1tWT2aBjNyXaHC9Z8jhuqlxKhpUbRKpyma + OxtDOS7L3xzzcfowuxFx08tPXgRcQOeINK55v2d8xwKGdfKquQTX1ibf4ipXvWIB + hCn6UW2YqhqIatQp/Swcj5woIv2kCCAI1cDPRpMUu48qJNYmsKEG6FO55/UxSRyF + TseoRTbiwR6tr3X729W1y5FIoFo5tq1NbAMy3o0+sP9pQtbN+1Percgf + =1CGB + -----END PGP PUBLIC KEY BLOCK----- + PUBLICKEY + end + + def key_id + '972E97C0' + end end - def public_key - <<~PUBLICKEY.strip - -----BEGIN PGP PUBLIC KEY BLOCK----- - Version: GnuPG v1 + module User2 + extend self + + def private_key + <<~KEY.strip + -----BEGIN PGP PRIVATE KEY BLOCK----- + Version: GnuPG v1 + + lQHYBFiuqioBBADg46jkiATWMy9t1npxFWJ77xibPXdUo36LAZgZ6uGungSzcFL4 + 50bdEyMMGm5RJp6DCYkZlwQDlM//YEqwf0Cmq/AibC5m9bHr7hf5sMxl40ssJ4fj + dzT6odihO0vxD2ARSrtiwkESzFxjJ51mjOfdPvAGf0ucxzgeRfUlCrM3kwARAQAB + AAP8CJlDFnbywR9dWfqBxi19sFMOk/smCObNQanuTcx6CDcu4zHi0Yxx6BoNCQES + cDRCLX5HevnpZngzQB3qa7dga+yqxKzwO8v0P0hliL81B1ZVXUk9TWhBj3NS3m3v + +kf2XeTxuZFb9fj44/4HpfbQ2yazTs/Xa+/ZeMqFPCYSNEECAOtjIbwHdfjkpVWR + uiwphRkNimv5hdObufs63m9uqhpKPdPKmr2IXgahPZg5PooxqE0k9IXaX2pBsJUF + DyuL1dsCAPSVL+YAOviP8ecM1jvdKpkFDd67kR5C+7jEvOGl+c2aX3qLvKt62HPR + +DxvYE0Oy0xfoHT14zNSfqthmlhIPqkB/i4WyJaafQVvkkoA9+A5aXbyihOR+RTx + p+CMNYvaAplFAyey7nv8l5+la/N+Sv86utjaenLZmCf34nDQEZy7rFWny7QvQmV0 + dGUgQ2FydHdyaWdodCA8YmV0dGUuY2FydHdyaWdodEBleGFtcGxlLmNvbT6IuAQT + AQIAIgUCWK6qKgIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQv52SX5Ee + /WVCGwP/QsOLTTyEJ6hl0Yy7DLY3kUxS6xiD9fW1FDoTQlxhiO+8TmghmhdtU3TI + ssP30/Su3pNKW3TkILtE9U8I2krEpsX5NkyMwmI6LXdeZjli2Lvtkx0Fm0Psd4HO + ORYJW5HqTx4jDLzeeIcYjqnobztDpfG8ONDvB0EI0GnCTOZNggG0L0JldHRlIENh + cnR3cmlnaHQgPGJldHRlLmNhcnR3cmlnaHRAZXhhbXBsZS5uZXQ+iLgEEwECACIF + AlivAsUCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEL+dkl+RHv1lXOwE + ANh7ce/vUjv6VMkO8o5OZXszhKE5+MSmYO8v/kkHcXNccC5wI6VF4K//r41p8Cyk + 9NzW7Kzjt2+14/BBqWugCx3xjWCuf88KH5PHbuSmfVYbzJmNSy6rfPmusZG5ePqD + xp5l2qQxMdRUX0Z36D/koM4N0ls6PAf6Xrdv9s6IBMMVnQHYBFiuqioBBADe5nUd + VOcbZlnxOjl0KBAT+A5bmyBLUT0BmLPsmA4PuXDSth7WvibPC8wcCdCYVk0IRMYn + eZUiWq/o5c4rthfLR4jg8kruvomQ4E4d4hyI6R0MLxXYZ3XMu67VuScFgbLURw1e + RZ16ANd3Nc1VuFW7ms0vCG0idB8iSZBoULaK8QARAQABAAP5AdCfUT/y2kmi75iF + ZX1ahSkax9LraEWW8TOCuolR6v2b7jFKrr2xX/P1A2DulID2Y1v4/5MJPHR/1G4D + l95Fkw+iGsTvKB5rPG5xye0vOYbbujRa6B9LL6s4Taf486shEegOrdjN9FIweM6f + vuVaDYzIk8Qwv5/sStEBxx8rxIkCAOBftFi56AY0gLniyEMAvVRjyVeOZPPJbS8i + v6L9asJB5wdsGJxJVyUZ/ylar5aCS7sroOcYTN2b1tOPoWuGqIkCAP5RlDRgm3Zg + xL6hXejqZp3G1/DXhKBSI/yUTR/D89H5/qNQe3W7dZqns9mSAJNtqOu+UMZ5UreY + Ond0/dmL5SkCAOO5r6gXM8ZDcNjydlQexCLnH70yVkCL6hG9Va1gOuFyUztRnCd+ + E35YRCEwZREZDr87BRr2Aak5t+lb1EFVqV+nvYifBBgBAgAJBQJYrqoqAhsMAAoJ + EL+dkl+RHv1lQggEANWwQwrlT2BFLWV8Fx+wlg31+mcjkTq0LaWu3oueAluoSl93 + 2B6ToruMh66JoxpSDU44x3JbCaZ/6poiYs5Aff8ZeyEVlfkVaQ7IWd5spjpXaS4i + oCOfkZepmbTuE7TPQWM4iBAtuIfiJGiwcpWWM+KIH281yhfCcbRzzFLsCVQx + =yEqv + -----END PGP PRIVATE KEY BLOCK----- + KEY + end + + def public_key + <<~KEY.strip + -----BEGIN PGP PUBLIC KEY BLOCK----- + Version: GnuPG v1 + + mI0EWK6qKgEEAODjqOSIBNYzL23WenEVYnvvGJs9d1SjfosBmBnq4a6eBLNwUvjn + Rt0TIwwablEmnoMJiRmXBAOUz/9gSrB/QKar8CJsLmb1sevuF/mwzGXjSywnh+N3 + NPqh2KE7S/EPYBFKu2LCQRLMXGMnnWaM590+8AZ/S5zHOB5F9SUKszeTABEBAAG0 + L0JldHRlIENhcnR3cmlnaHQgPGJldHRlLmNhcnR3cmlnaHRAZXhhbXBsZS5jb20+ + iLgEEwECACIFAliuqioCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEL+d + kl+RHv1lQhsD/0LDi008hCeoZdGMuwy2N5FMUusYg/X1tRQ6E0JcYYjvvE5oIZoX + bVN0yLLD99P0rt6TSlt05CC7RPVPCNpKxKbF+TZMjMJiOi13XmY5Yti77ZMdBZtD + 7HeBzjkWCVuR6k8eIwy83niHGI6p6G87Q6XxvDjQ7wdBCNBpwkzmTYIBuI0EWK6q + KgEEAN7mdR1U5xtmWfE6OXQoEBP4DlubIEtRPQGYs+yYDg+5cNK2Hta+Js8LzBwJ + 0JhWTQhExid5lSJar+jlziu2F8tHiODySu6+iZDgTh3iHIjpHQwvFdhndcy7rtW5 + JwWBstRHDV5FnXoA13c1zVW4VbuazS8IbSJ0HyJJkGhQtorxABEBAAGInwQYAQIA + CQUCWK6qKgIbDAAKCRC/nZJfkR79ZUIIBADVsEMK5U9gRS1lfBcfsJYN9fpnI5E6 + tC2lrt6LngJbqEpfd9gek6K7jIeuiaMaUg1OOMdyWwmmf+qaImLOQH3/GXshFZX5 + FWkOyFnebKY6V2kuIqAjn5GXqZm07hO0z0FjOIgQLbiH4iRosHKVljPiiB9vNcoX + wnG0c8xS7AlUMQ== + =Erp5 + -----END PGP PUBLIC KEY BLOCK----- + KEY + end + + def key_id + '911EFD65' + end - mQENBFMOSOgBCADFCYxmnXFbrDhfvlf03Q/bQuT+nZu46BFGbo7XkUjDowFXJQhP - PTyxRpAxQXVCRgYs1ISoI+FS22SH+EYq8FSoIMWBwJ+kynvJx14a9EpSDxwgNnfJ - RL+1Cqo6+BzBiTueOmbLm1IYLtCR6IbAHAyj5YUUB6WU7NtZjJUn7tZg3uxNTr7C - TNnn88ohzfFa9NfwZx0YwgxEMn0ijipdEtdx5T/0vGHlZ+WRq88atEu00WNn0x65 - upvjk7I1vB9DTZp/zPTZbUGPNwm6qw9xozNFg/LcdbSMryh0Xg9pPRY6Agw2Jpgi - XxNAApDrlnaexigFfffUkkHac+0EoXwceu8zABEBAAG0HUFsZXhpcyBSZWlnZWwg - PGxleEBwYW50ZXIuY2g+iQE4BBMBAgAiBQJTDkjoAhsDBgsJCAcDAgYVCAIJCgsE - FgIDAQIeAQIXgAAKCRDHKK8Qly6XwO1VB/0aG5oT5ElKvLottcfTL2qpmX2Luwck - FOeR4HOrBgmIuGxasgpIFJXOz1JN/uSB5wWy02WjofupMh88NNGcGA3P4rFbXq8v - yKtmM62yTrYjsmEd64NFwvfcRKzbK57oLUdlZIOMquCe9rTS77Ll/9HIUJXoRmAX - RA0HUtn0RnNF492bV+16ShF3xoh5mVU4v+muTA/izW7lSQ2PtFd2inDvyDyiNKzg - WOUlZESc6YN/kkUJj/4YjqPgIURNx6q/jGw24gH4z6bZ8RfloaEjmhSX0gA4lnMQ - 8+54FADPqQRiXd3Jx5RRUJCOcJ+Z17I4Vfh1IZLlKVlMDvUh4g2SxSSGiQEcBBAB - AgAGBQJTkXXXAAoJEKK3SgWnore32hgH/RFjh9B+er5+ldP4D9/h887AR9E1xN7r - DTN7EF5jlfgXkIAaxk2/my+NNe0qZog9YBrVR+n8LGgwXRnyN9w1yhUE4eO71Zwi - dg4SgU5fK3asWLu+/esKD2S/QndRwIpZOTqsmiqe8N8cVscaoAg+G/TnDJvTKft1 - twIcjrB1fv9B3Fnehy/g/ao+/E1/7CknWE6zB4eSQdOrAfQ9gnJgabLRBUUVltBm - dBZ+lAQyBSAEbkL5FgWhxJNMjuTOVr6IYWvRXneHrMy630wZIk0d7tPEZJvBeIKA - FMtzBJvW6gJ/Xd5mbtb+qvoxfh8Z06vfqNMmhLLEYuvEW1xFSmyWWGuJARwEEAEC - AAYFAlSGz8kACgkQZbw57+NVY/GU0Qf+KCAPBUjVBZeSXJh/7ynsWpNNewZOYyZV - n7fs8tm7soJfISZUbwVAPK8HwGpzrrTW9rpuhKmTgXCbFJszuHys4z3xveByu56y - bmA1izmhaLib1kN9Q7BYzf8gdB657H4AAwwTOQPewyQ2HJxsilM1UVb5x9452oTe - CgigGKVnUT556JZ8I8bs+0hKWJU3aDDyjdaSK82S1dCIPyanhTWTb2wk1vTz5Bw1 - LyKZ8Wasfer6Bk6WJ9JSQRQlg4QRkaK6V5SD33yOyUuXM7oKgLLGPc0qRC6mzHtz - Sq7wkg2K/ZLmBd72/gi3FmhESeU6oKKj6ivboMHXAq+9LuBh30D0cIhGBBARAgAG - BQJTmae5AAoJECUmW1Z+JGhyITgAoJoFNd5Rz9YFh8XhRwA6GaFb7cHfAKCKFVtn - Bks20ZiBiAAl3+3BDroNJ4kBHAQQAQIABgUCVXqf+QAKCRDCDc5p2mWzH3gTB/41 - X9v9LP9oeDNL4tVKhkE8zCTjIKZ8niHYnwHQIGk4Nqz6noV/Qa45xvqCbIYtizKZ - Csqg2nYYkfG2njGPMKTTvtg5UdilUuQEYOFLRod3deuuEelqyNZNsqSOp7Jj5Nzv - DpipI5GxvyI/DD7GQwHHm5nspiBv/ORs3rcT4XatdTp6LhVTNyAp060oQ/aLXVW4 - y1YffvVViKe/ojDcKdUVssXVoKOs4NVImQoHXkHVSmFv0Cb5BGeYd58/j12zLxlk - 7Px9fualT6e5E7lqYl7uZ63t32KKosHNV+RC0VW8jFOblBANxbh6wIXF7qU6mVEA - HUT7th2KlY51an2UmRvTiQEcBBABAgAGBQJWCVptAAoJEH9ChqPNQcDdQZAH/RiY - Wb7VgOKOZpCgBpRvFMnMDH2PYLd6hr1TqJ6GUeq3WPUzlEsqGWF5uT3m07M09esJ - mlYufkmsD89ehZxYfROQ8BA3rTqjzhO9V0rNFm/o8SBbyuGnQwFWOTAgnVC1Hvth - kJM+7JgG8t6qpIpGmMz6uij7hkWYdphhN0SqoS8XgAtjdXK6G5fYpJafwlg7TGFD - F6q5d2RX0BdUhJkIOFNI/JXLpX04WiXEQl2hOwB3la/CT2oqYQONUbzoehUaF5SV - uKlFruUoZ/rbJM1J4imdcEBH2X3bnzdapCqvMudgAALo8NUiJJ/iTiYx/sxQ4XUp - oF567flP1Q08q6w66OyJAhwEEAECAAYFAlODZOkACgkQ5LbUbWbHh8yNzBAAk6LE - nfbdmx2PsFS21ZP8eAiPMBZ61sfmDVgNU5qLDyQRk+xg7lZlFlZ64mka4Bh82rvV - 4evcEOHbuiYS4zupxI9XrBvBpks6mALEAAX/5HXYDgb/9ghNd0xjlheHmMKJk8jE - Mb2kYx/UCimbtG460ZiQg0e+OWNU5fgMEjA8h6FMbt0axPkX+kde+OSg52i1bL5n - fPbGqA3o1+u2FzsufuCEOPsTLKhkiOKnopCMtB8kRih+WQ73G3XkYSkYh2bYW0eF - MoZlgez5lpUWLD0+NWB9qiDXZs1yUJ0CdHA98eahPaPyR8aLqOP0dPkbS6/X4j6N - WjZgZ2sIb8PihowiHYeogMhZZIoBTYqRlbW9/KAptC7UGFMF21Vp7HexFRuoC8qO - PSXfMLH4kw0Lq1mLBTw9+No0L7xfMxKmzT0VLsJkJB09gAGWv2/8voCIPtBm/MZi - C9o3w3tWAczAvZetMXH/dp8Por6pmMoTHHUkbSBZHe1Lt138jLtozZDCuuWQ53O/ - mIT1sds1Oy6IF4e0xrSqpZlDGwj0pqOKmtLFI1ZRrfjb5bnm7sgzcxoM5aPhqJyb - 88XYgBolsiErM+WhnH6cAEK2TUVlVqXzDIbqKBroEK/cM+Bez1SagzAsoarYA5R1 - yewc0ga/1jQI4m6+2WoL4wo4wMNggdWiIWbuqAmJAhwEEAEKAAYFAlZDO+4ACgkQ - MH93QRZS4oGShw/6A6Loa5V9RI9Vqi7AJGFbMVnFJV/oaUrOq8mE8fEY/cw1LQ5h - Ag/8Nx7ZpQc28KbCo0MR3Pj7r2WZKLcxMwaXlFZtNiO4cEITNu5eoC7+KOrFACsO - 1c0dKbMEeDQ2Xqzo2ihw/4DnkuUenrmGnNJMQ5LrEZinSKFFAgeYRdYnMdYqOcXe - Q8rPImFkyOnPbdIOC2yPzjqHIsuazuwd9to+p35VzPNZv7ELFBfx/xDHifniRMrm - sPJh6ABjecOJg7RJW4h9qP+bNbbrJa6VfGAbNUR+h4DiMr6whpGJd41IiXIEGrGW - BT87hO7gwpMrex0loQoHwsfqMxOM0qwMU9ARCJJLctzkj727m/SsyP9cUIFGceBN - cUopmpKCi9z0QZ/bxKWbpqa3AarkWxRLj1ZzmllxC7tjO61kr0zkn8pnEIc79cGw - QlUI9k7QaWFm1yDlpPXLvBi+evYxSONbsSoHwjMIC/cioBh0c0LOXn8TV6OWlS/3 - sWShQG9KxugZdK+MBrZPR23jilHPKpWG8ddEWp4BZugqxppiyZAgEOMlHBr5PkV+ - hBx1vCG0w9IlMJODRIXIUeqot3ixQvLmeoWTuIFPiNPfXskCfNuudbj4+jZewf6z - BL60VJADKJENmsDPPhF6UEiHDIrauNylORhhPR/qEAs4LOiEwRqRtHBEqYKIRgQQ - EQoABgUCU39OnwAKCRA1morv4C3iPRylAKChT88Lvmd1M5LX1hoRqsFeG8IahgCf - Q1VWKh852oZq9dOtbGRxEbv876OIRgQQEQoABgUCU+DpHgAKCRBmKanAQloCxoSL - AJ44D4cwTLOmw+rHl6bB/oqNhoV3bQCbBmyupEB9gn6NUD80BTEzs0jTHWSJAhwE - EAECAAYFAlNv5m4ACgkQxykhoSk/LSQnZg/7BSrZULH/tRDRd1LvuKtHoR7AarqD - iGQXhxvXLp6AZaMcI1UF/hvKeJtho5tKjQ6OpEB1sPXXc68abvRdJFh42GBPmHFD - A8aBsJJePZQTMm4biDfFNw7cK1j0cjUczftAlyFAf5w5y2kM5jo24qdNmVqa5ipE - u0AcmzNntgaWeP9izXdnjpNTSOG6Rbo84IrIku7sR8GxNvlisAS1hhwYkYksNts4 - gu+wmfnkLFyZrncbjVHLVbZnAJhhcdWKhyjcOBRadrAZ/EoK1/3VoLHIdWBpW0f9 - sUYv3u6WUyWa4EFaaHRxttMFWhWq9p2nYfojh2Bf5V6cOLgikkIu03oQp2GPNnOL - ub0PTmSS+93ZmIEW9NIxY0cmz8lFVo9qqip4Dzka2Rp3oTg0x3JKXU+OZV4J/Mfa - LT5uI3Flub3f8etOQw+6/Q5Rg3vGOh14UtEVaA1WcKeyRq7v+XZAA16FN5omCEX8 - xA641xgefvLx4jj0ZfqlHgH+dEoOdbiRQ3IYyzMnX/xLl88Xw49etkeflQFXvkLh - e6QdXrfrm4ZniIWOfCDeQmZS0znDV46YzK0MVu6kYXcmDpVBRREUzsxgJmWg4JW2 - EgHTqSHL8Oi8gvfTMKaPSnTl3cWSKlupQDx/CYuuqdAd7x2hcSivWFu22YcNp4XV - fd0jJPvv+UlnmjOJARwEEAECAAYFAlRcmw8ACgkQlFPUWjJBWVgGCggAgZDWaPcj - Fce9mnRtMDyOVMOZQ0AppvbS97pJ6PLF/dKXz+nyNtkiAPfimRTE3BpXhX3JDke9 - PEaRH/dXTdmzfej9N3DOADFJlRVyxETXyTGiNzyP7vaJAT+9hgW7hbUtgoAbDK31 - ZWijVEw4+Jg9vWhUKBhLrV1lcyQyZAldLYep/sAyynAeaUbsFtbpH8DHXZBIA/0C - 2XWp7o01w8b1CgsUHBfBK9eNlQ3BOu3Y5WY8MW4ZcRuDlH/hbs9V1zK5vkR2zq4d - uSG8KYHsLV1/zskLszLZk27c6QHQb1C6U6CW8shgkdxGRduXMETRL4yYib3s4Mwy - xovU00cYKQ5CIokBHAQQAQIABgUCV2FHnwAKCRCZSfh4lwNdkn7DCACvBLx76e+5 - 9vaGdSne2veRwT/J/a5OWJghn7f679btAxJROvWdeHvWW4vHKz+A6HGvR8E7xGCZ - NdfkokqXcioSRcZFIW7zAev27F31E8V63voY2KDESlkxrRhNZBpvwfXAg2RS9KmB - btmgj6Zo1VnbEXoxPO+5yZzpYxuBPL7xMidSznQe9eswqMLvSNxKQODOGToddreb - 9ClKk+qpQOCTQTEQjw4Y9wjoZ5SdENP1IihnTi/Z31Sr99CL3jPPpXoo8WO4in6z - DPEEvAbszDb+24+WDEoW47ST+x4eDJG0WcVrjNa87k7kMNOWsPr9rNHtgRCNa22M - xaPaKrTZ/F03iQEcBBABCgAGBQJXc+wKAAoJEIhwMVR86tleqikIAKQtWDnrp1dl - tE4G1IVp2i9NwhCOaZVODaGaH3C564B8/WyEbjFjOmm4aDzykiwEUWBMCP0icpHn - 3o5s65gdtgnP/KVWKp3wyJqJYu0rQcyFtKNKi8x5D/7c8y23DRoI2lnI12f7MWPH - wzC3wClulTboV0mC2Cp1TWLBnKGbhpHOGN5ViSPm3rPOesFZ5el38wcwDKWaZbmm - hFtx8fx2T2lTP+5GRCuiXrnsrzA3tZLuRWH44esPxYB8mFg1btgAtXo9Q9MEISWL - g043RQ0VWU3a9F7K3RshTPAUbvUrNtEAFMtij0B4RvLE5cyHEltUB0R4ie3RDZDe - z0VCwrsaI+OJAhwEEAEIAAYFAlePuxUACgkQ+iIJCo0F+QvWZg/+I5R1TdQpMKVM - Fz+XrYXpSgPxeLr3b6svuV8uOPY8kYbOPVxvjbNGuyijbRD/btH9Qg2vDNGbZJ9G - pGUfnNNlXUsTkxp/5sEWAzBH0pTEgiy7wHzCa4u+meXDkLnomdZfSHkFNDw+I2MI - Nrp84DPkMBQ4X5AJ4UcoMUbfqLRbqgHo/DEAYsAwnihF4Lwl8x9ltokcAc+w3SQk - mvHOR1xoeAFtH3NEzUvA3EhZo16o7+dQWyh8GJRsgUA6g6zyqLOn+JTDVh1YlrAF - 1qkhnBsw7G5InL54mhvXwqKoAwI5zO8A+5tSUMUvtZBfUW2DX/yCvaD5v/fjMScF - 5Lw61NYTLyZEW+JlLGGdIrewB72BVPVR5Sak+dwwjxHK2NGdaug3V8gOht8ZwYKx - X9NmYLWi+4DFkQxtSCpwH6WAqfw4OPuvFHyd/VdA5czsQo15rU2Go5JE7FlR1xoy - lCNV4TU3p+eLTNW/L7ty4HPuiPWI3gDpRgh0Tv878IlLKuivlNhfTub8Hf4LzSW1 - g++1lwUf3TxhYUPHmZT2V9Sk+VVgCXIFenn914r+RZMnThCgWh2GmcKDgLKUSdxv - /j14NlTgWqUY3cQM/ciSdAdqZn8WAOjeuVgpqkX5A4NrWbshaqUsksm9QdtpMia1 - Q2hDuR8OIvHP0PiwNv8Bn00nAgyU2NeJAhwEEAEKAAYFAldP7ycACgkQu9aLHqU1 - +zaXsA//Rm+1ckvAAaj1qk9rXpYZVWK8kCeKkHu48bL9r0g9Z1mfCGTgrUd1lPNW - Lh850z+LYzJelZCqnNsgxX8KG567NwdRb+LBy8tzbCgIMomfgqILv7KmRzPQ6AJ7 - Bp8hGnregfD0CCXtEORk/aQF0FCRL8bKsKiN7DOPirP9gfdSgpshr1cLe8a7cPFq - Zza7VhAke5/BCsNzxaUvseuzZ6bZOXlUpbSJH2+f/DYXvwfaJl/Rg+s+DuPtqVgI - TMSsRwL/iIlqfT2Al4SVak4f0q/HVkNgfEFSx2i8OWlVe90V71sNNAOMSDnBRHBC - fNon4vwnv3xkKwH6ecwgZtZwcjPKMUZPjrzEFULOBrNAsC173HypbZZ/wlJBAMd5 - gBd35CQELrq2sOgekofm7Sbq5m2WYr35M0nqIV8q0ySxMWyuY2g46QQVEyGiXrKt - TyJzT7M+UtqD03wjNSBZc7y/a2+kzZJADrz8kNANuR5GGfxZ3zKjmgyQX2QRNYq+ - +bwB6U7NyRgzX/i3sE2pSn2xuwwzqk873r+Afb8gCMSXV1omcwZJAHeUURjv70mU - A9BFjE249JxjDbuzThiErMCG4Gj87NjXYCBq7QsfyKPVAx7esEYoDmR+k4nYH4my - pY1LTgLZUOBtGiLnkGIZ9XVIcZBPRoSKEpRRvcPBtHkJkqwQm8mJAhwEEAEKAAYF - AldQLVYACgkQsOAWYMCDwn9L4xAAgMxHehYdB6+htNj/c7xlFhdv6nyLl8excl0q - jOBLsN00w3F1yGZqNhbKsvHZKhW8PZhX+wMMoczGi1YdOV3AMoB20/t+DRh2giRL - wgLiJblxR4Z4Ge+/ne3/aVHOHyVqmh879TA2coUS0i0BpqRoY70eV/yVqkbXpuFm - reXLt3Syc3HoGd79KiyRht83Og/d7dbxkQOCe7YnRxuVynwMKgIRJt+UgCIM07sR - nA05MWgatp9PiFXkGdfyBy2UkvybcaAyjByBpOjdTPFa2LdjIO4Qsgmg8q8F3z0g - gW3bRPKQDNX6w7UA4tf587x0S1mKwXGeLnezZv1kmAQB//bYgZs4bZsqeB/i832I - sWzX7PEoh/kGWg9/eZBQu+l5d8koD2wRiUvFVussont7LMsNwHJSerS++tj5Tdwj - E8qcNdJYkcjkVxaHugVlm+IQfSrvdMpRq8bfwxGmprU3hAebB0b2OZDMm/uWGiVC - ycjStGUtu/ZJU56zRhkj/4yZPi7gczZAurRXvLt4AhNpkGPNSAxt16fpaBkBPo61 - pHir3K+FvpXN4ezv+mFR1G0hrSTuMk2nU1D7WUkw0xnx/IY7VrGx8PrR8Ilfb+C1 - 9z1g/uuZ4alIWXZ/tAeDPjTQI5QOPgj43DrgWqG2FDAqQ/+nt9RevUVIPMOojOko - BdHaskmJARwEEAEIAAYFAlguvT0ACgkQkDmkVrycD3gyvAf/fks3MtR+yoMRCNIi - VklGwoTv646OOqm3bDZz180cXqGXxSASQ7fglaDGl+of2qRyilU9dzkY1ZHqD2AY - /sycR1QKELfa9rFx12i4w9jyWdZykOggS6Os3e1Dvt9Q4fZzP0+eLCs8Fknancxq - WhUrXqaYz/OZj4Xmjw6jYZxdtJ/B0OFDqxOlN7v3iZSeXNwKJ5vpeJLE6dfy/5pM - ms3aIj8KB+MDSQpgaZ8FKjRn8rSZwUu768sHNTWv5l0UxJbIREB5XE8fQuGxPIJ+ - DyxiKmPMlyuyj6whz+iZP5jkEDpDiqFEJHHmw9qAlhkba0LzJYh2uqS7L15V6ykY - xZ4wl4kBHAQQAQgABgUCWC6/swAKCRDij8qPAN1CxhQJCACP+UCg5zM5h8HtLlPL - Pt1jofqmVqk8KJHJyZzn6EgyoQmNnPDybLHIRTxB+hsQTAZJtQn7UiBpXa0OmBXm - s4MdeRb0tIPN1l66l8+N7OuG0Tf+mALwAM+GqiUgSEGs5gOVF9Ev1pP0dRCKTSGJ - v0NMNUb77Qkn34R4HK+f0nfFKER4RW23F5e6sf6Rq4SzP3sVRdqU5dY1alxMFWNy - 7IrP/QdsBl6ACtYSFAuay/hxyccbu22KhIm0S2ikJJgjNenyq15TGaBoG02nl4lC - TgrOEjNDSXw2Bn4L6AZM8sR08ZjARqKspB7ZnNOcIaIrK61cpgAL4SXdMkvQF7Qj - uhatiQIcBBABCAAGBQJYNfShAAoJEMELqJFB1XEubX4P/0or+wvHMFC1lBTttKlO - mkPHTHDYZFCLQr/6cjAv5OPyrBOh/uJ+QJq6awrn1LD16j2YEZUkgkqHBiNl5f7R - J8Tl97esxZja5iHvgOx54NDxD97WoIgJhEnYuhvY7sACT5YBx4npMKPi0WaqgCfR - GDeQzVcKzgWhScgeSnWBf7+bwIdGO4mg9y58s/4fMK1kw6niK/xo1hkK0w41StV1 - wmK92fEqeFElseaBSmf8efgb4Qi6ic9Zf2mGgjHwTIn7FeTA9r6zzSggw3b5NEG6 - W2bdhVmKheYPBp+kdsQqsw9H/AzUFLL8wg982IRyvnbUkccP/7neWeFJo/1VVogp - ybTBdgxa+dl5UcjxvqJZbFp0mLorWJvOVamoGgvO2WKv0tSUK3LwVxZaIVMbFwEo - G+FfpW8XfqhzdkD6zJO3rjpOcnrouaYB/SpSofbwRxrtxTzcxxMP2B62gd7/VdcY - duyL6Cj21P3vIdveQ26B8zdSiv6MfG/7/zlrpe9strIv3UiHfpG8093TnPB2gwWL - /zdh7Nbsn3rq2Rti00zIqHpopPS4J/dr/jdpXzMymb93HpsA5UTuyYHnqa1YBAgn - qfnkk+lNENso6Ymg8a+S/oFh7Hks7olrhYpmdodL1AqU+YWMsp2L2knOxmpEZc8s - mjVx9YKKxrtZ7FisuwVER+3fiQEzBBABCAAdFiEE4gFIMof/a3u+jGQXNpvllaAP - nh4FAlhrniwACgkQNpvllaAPnh6e1QgAh646441z+ecM8k82DIctj1RT01tY5Ygz - WwDx4HJZy8b/l3J8PF62mZB045vC9DGweX7DgJ/FZXTwMGfS1lU7gBmIMJZnp8lU - m4K1IRgYf70T5LOepaYgJUJ9iPoc1bSw91efkdQSou6Fignet+DMk3268qbO/JO6 - Q8MbsD9XDND1pf6Y1gdtsrXaQTTqnf7l/5zbrYlknOBkDk4x7ZbYgZYfEucba4/R - 3O+dN7Eu9O7dS/PmYDvozPCuEIJrPwxdWnDr+0J6JwHwP9o2OD51CT/LfvL8uGtS - oPcmB4Oon1ORayDWWthlypYONP0kKwIFsR6mgU++UVNj+b+ABbizOokBHAQQAQoA - BgUCWH3oQQAKCRAfFBlUoHXkjEbvB/4zwwaKHd6B1d6XMzysG3/l29IxdNG8Udh0 - d8/o/jEl6jxJiIjVvaFTXXP1/owBjDSP/RwX0mMaluIfedghN+y21UQfi2QJ2FtV - d7hLTKjgLYStGZGakmUlaXvwZsshZmpQJDbFo6SWqBb68yjult8VTnoug+Q+I28o - p2y8sviFoEyBKnYXotSt9HNMLHtYUeFqJWAwVRIt14oaHXQjv7QuB9/RnuY6/sfC - In5y84sJyEylghP4C2+Usl5QtcAR5gByMvpfyPsFxXIcGw+Bxk9Sm0k37tCVAhKB - dIOMd85s8mQJ4nOZu2hLhKBlOgX1HNb/LJECG2QPqlSDtoFXrzcotCRBbGV4aXMg - UmVpZ2VsIDxtYWlsQGtvZmZlaW5mcmVpLm9yZz6JATgEEwECACIFAlicPfgCGwMG - CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEMcorxCXLpfAl0UH+QFkOIlIuFpb - 6MkAdp7qkaP58HG0nFZMWTLiwJnh4rclN5vvU7Dlvyy/JOI1M6wepBl3ujNJ+Pe1 - RL1Jy001sN9ZGvtkCiXwfg+3IRNAacQwdl39lUsaHbzSyo/33U7i9NaQ9QefLpji - on1auZMXQ8OVDPo2sT01kSwutMhYx/8wEc+kh/uckCYLFjx06mF1l+OGxc77CGbr - WeItjrjhTkYjsoaVh776V0Q2m08Ixq7pBXYp91zKT00EUE64LdIN85AkzehzSptF - +lT/BW2C1Ft5E588914PMKvNcufB0twaNFqKZUOCiIXO3cqlLoz5GHLe22mJKngo - NXVsbNZ/8zW5AQ0EUw5I6AEIAMb+U5s17opggc0fgejZleAv8ie1HIKms7PNlaMq - lzQj5bmFAln7DjUvupey8fkpLJtEGAJkp0vBiXohM3KOa78hr9ShJIVuFrz473jj - 9cAMlcLme2yDvPVjtTEFiVwl9+WXgvjtgkQjDKU1v9QJIC4UbcnzYwwyHuXXVUKW - v9gXj2a6Adk0cFF0qbNpBzfKrettsp02PUPlrceVhB8KDgY9/rj90uxQBmeZn9bP - G2W4zR+J+8kLcUAFlVhJasfItDo5bpFl7VH8hX5ZzXBL0NMQQoeNRtnrt/5xJ5Kl - BQbflScVaF1s+3oK75ppEeRZrYP5ESB5JBLUGuFO44hD/OkAEQEAAYkBHwQYAQIA - CQUCUw5I6AIbDAAKCRDHKK8Qly6XwLGiB/0ZUZf+ybfY6RQz4QoRw+RO290bf1Gx - wuL3PPCxaVX3POv1S0RLblYEP+88ikaYv6zpiEoohQPtCXdLfyJswRgTUNWS4DPZ - COW5TLLE2E/zYB0YGwLilZvAkopx+x1tWT2aBjNyXaHC9Z8jhuqlxKhpUbRKpyma - OxtDOS7L3xzzcfowuxFx08tPXgRcQOeINK55v2d8xwKGdfKquQTX1ibf4ipXvWIB - hCn6UW2YqhqIatQp/Swcj5woIv2kCCAI1cDPRpMUu48qJNYmsKEG6FO55/UxSRyF - TseoRTbiwR6tr3X729W1y5FIoFo5tq1NbAMy3o0+sP9pQtbN+1Percgf - =1CGB - -----END PGP PUBLIC KEY BLOCK----- - PUBLICKEY + def signature + '6D494CA6FC90C0CAE0910E42BF9D925F911EFD65' + end end end -- cgit v1.2.1 From 597ae6e2208a4910544e5877db7fff300a058886 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 23 Feb 2017 12:03:18 +0100 Subject: feature spec for gpg signed commits --- spec/features/commits_spec.rb | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index fb1e47994ef..c303f29a832 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -1,4 +1,5 @@ require 'spec_helper' +require 'fileutils' describe 'Commits' do include CiStatusHelper @@ -203,4 +204,35 @@ describe 'Commits' do end end end + + describe 'GPG signed commits' do + let(:user) { create(:user) } + + before do + project.team << [user, :master] + login_with(user) + end + + it 'shows the signed status', :gpg do + GPGME::Key.import(GpgHelpers::User1.public_key) + + # FIXME: add this to the test repository directly + remote_path = project.repository.path_to_repo + Dir.mktmpdir do |dir| + FileUtils.cd dir do + `git clone --quiet #{remote_path} .` + `git commit --quiet -S#{GpgHelpers::User1.key_id} --allow-empty -m "signed commit, verified key/email"` + `git commit --quiet -S#{GpgHelpers::User2.key_id} --allow-empty -m "signed commit, unverified key/email"` + `git push --quiet` + end + end + + visit namespace_project_commits_path(project.namespace, project, :master) + + within '#commits-list' do + expect(page).to have_content 'Unverified' + expect(page).to have_content 'Verified' + end + end + end end -- cgit v1.2.1 From 5ce61120b19f7f12e7aff714857851f57571ce0e Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 23 Feb 2017 14:07:51 +0100 Subject: use example gpg key instead of my own --- spec/features/profiles/gpg_keys_spec.rb | 8 +- spec/lib/gitlab/gpg_spec.rb | 12 +- spec/models/gpg_key_spec.rb | 8 +- spec/support/gpg_helpers.rb | 275 +++++++++----------------------- 4 files changed, 92 insertions(+), 211 deletions(-) diff --git a/spec/features/profiles/gpg_keys_spec.rb b/spec/features/profiles/gpg_keys_spec.rb index 223f2e81842..42e1a6624b7 100644 --- a/spec/features/profiles/gpg_keys_spec.rb +++ b/spec/features/profiles/gpg_keys_spec.rb @@ -16,8 +16,8 @@ feature 'Profile > GPG Keys', :gpg do fill_in('Key', with: attributes_for(:gpg_key)[:key]) click_button('Add key') - expect(page).to have_content('mail@koffeinfrei.org lex@panter.ch') - expect(page).to have_content('4F4840A503964251CF7D7F5DC728AF10972E97C0') + expect(page).to have_content(GpgHelpers::User1.email) + expect(page).to have_content(GpgHelpers::User1.fingerprint) end end @@ -25,8 +25,8 @@ feature 'Profile > GPG Keys', :gpg do create(:gpg_key, user: user) visit profile_gpg_keys_path - expect(page).to have_content('mail@koffeinfrei.org lex@panter.ch') - expect(page).to have_content('4F4840A503964251CF7D7F5DC728AF10972E97C0') + expect(page).to have_content(GpgHelpers::User1.email) + expect(page).to have_content(GpgHelpers::User1.fingerprint) end scenario 'User removes a key via the key index' do diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index 04a434a993d..6cfc634e2d9 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -5,7 +5,7 @@ describe Gitlab::Gpg do it 'returns the fingerprint' do expect( described_class.fingerprints_from_key(GpgHelpers::User1.public_key) - ).to eq ['4F4840A503964251CF7D7F5DC728AF10972E97C0'] + ).to eq [GpgHelpers::User1.fingerprint] end it 'returns an empty array when the key is invalid' do @@ -17,22 +17,22 @@ describe Gitlab::Gpg do describe '.add_to_keychain', :gpg do it 'stores the key in the keychain' do - expect(GPGME::Key.find(:public, '4F4840A503964251CF7D7F5DC728AF10972E97C0')).to eq [] + expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).to eq [] Gitlab::Gpg.add_to_keychain(GpgHelpers::User1.public_key) - expect(GPGME::Key.find(:public, '4F4840A503964251CF7D7F5DC728AF10972E97C0')).not_to eq [] + expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).not_to eq [] end end describe '.remove_from_keychain', :gpg do it 'removes the key from the keychain' do Gitlab::Gpg.add_to_keychain(GpgHelpers::User1.public_key) - expect(GPGME::Key.find(:public, '4F4840A503964251CF7D7F5DC728AF10972E97C0')).not_to eq [] + expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).not_to eq [] - Gitlab::Gpg.remove_from_keychain('4F4840A503964251CF7D7F5DC728AF10972E97C0') + Gitlab::Gpg.remove_from_keychain(GpgHelpers::User1.fingerprint) - expect(GPGME::Key.find(:public, '4F4840A503964251CF7D7F5DC728AF10972E97C0')).to eq [] + expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).to eq [] end end end diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 6bfd0b0d4f6..917d420878a 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -18,7 +18,7 @@ describe GpgKey do it 'extracts the fingerprint from the gpg key' do gpg_key = described_class.new(key: GpgHelpers::User1.public_key) gpg_key.valid? - expect(gpg_key.fingerprint).to eq '4F4840A503964251CF7D7F5DC728AF10972E97C0' + expect(gpg_key.fingerprint).to eq GpgHelpers::User1.fingerprint end end @@ -34,7 +34,7 @@ describe GpgKey do allow(Gitlab::Gpg).to receive :add_to_keychain gpg_key = create :gpg_key - expect(Gitlab::Gpg).to receive(:remove_from_keychain).with('4F4840A503964251CF7D7F5DC728AF10972E97C0') + expect(Gitlab::Gpg).to receive(:remove_from_keychain).with(GpgHelpers::User1.fingerprint) gpg_key.destroy! end @@ -57,9 +57,9 @@ describe GpgKey do describe '#emails', :gpg do it 'returns the emails from the gpg key' do - gpg_key = create :gpg_key + gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key - expect(gpg_key.emails).to match_array %w(mail@koffeinfrei.org lex@panter.ch) + expect(gpg_key.emails).to eq [GpgHelpers::User1.email] end end end diff --git a/spec/support/gpg_helpers.rb b/spec/support/gpg_helpers.rb index 375f4415846..8e005634c94 100644 --- a/spec/support/gpg_helpers.rb +++ b/spec/support/gpg_helpers.rb @@ -7,13 +7,11 @@ module GpgHelpers -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 - iQEcBAABAgAGBQJYpIi9AAoJEMcorxCXLpfAZZIH/R/nhcC4s0j6nqAsi9Kbc4DX - TGZyfjed6puWzqnT90Vy+WyUC7FjWJpkuOKQz+NQD9JcBMRp/OC0GtkNz4djv1se - Nup29qWd+Fg2XGEBakTxAo2e9cg38a2rGEIL6V8i+tYAhDt5OyLdzD/XsF0vt02E - ZikSvV02c6ByrjPq37ZdOgnk1xJrS1NM0Sn4B7L3cAz6TYb1OvyG1Z4HnMWgTBHy - e/uKLPRYhx7a4D4TEt4/JWN3sb0VnaToG623EdJ1APF/MK9Es+H7YfgBsyu18nss - 705F+PZ2vx/1b9z5dLc/jQNf+k9vQH4uhmOFwUJnuQ/qB4/3H/UyLH/HfomK7Zk= - =fzCF + iJwEAAECAAYFAliu264ACgkQzPvhnwCsix1VXgP9F6zwAMb3OXKZzqGxJ4MQIBoL + OdiUSJpL/4sIA9uhFeIv3GIA+uhsG1BHHsG627+sDy7b8W9VWEd7tbcoz4Mvhf3P + 8g0AIt9/KJuStQZDrXwP1uP6Rrl759nDcNpoOKdSQ5EZ1zlRzeDROlZeDp7Ckfvw + GLmN/74Gl3pk0wfgHFY= + =wSgS -----END PGP SIGNATURE----- SIGNATURE end @@ -21,208 +19,87 @@ module GpgHelpers def signed_commit_base_data <<~SIGNEDDATA tree ed60cfd202644fda1abaf684e7d965052db18c13 - parent 4ded8b5ce09d2b665e5893945b29d8d626691086 - author Alexis Reigel 1487177917 +0100 - committer Alexis Reigel 1487177917 +0100 + parent caf6a0334a855e12f30205fff3d7333df1f65127 + author Nannie Bernhard 1487854510 +0100 + committer Nannie Bernhard 1487854510 +0100 signed commit, verified key/email SIGNEDDATA end + def secret_key + <<~KEY.strip + -----BEGIN PGP PRIVATE KEY BLOCK----- + Version: GnuPG v1 + + lQHYBFiu1ScBBADUhWsrlWHp5e7ASlI5iMcA0XN43fivhVlGYJJy4Ii3Hr2i4f5s + VffHS8QyhgxxzSnPwe2OKnZWWL9cHzUFbiG3fHalEBTjpB+7pG4HBgU8R/tiDOu8 + vkAR+tfJbkuRs9XeG3dGKBX/8WRhIfRucYnM+04l2Myyo5zIx7thJmxXjwARAQAB + AAP/XUtcqrtfSnDYCK4Xvo4e3msUSAEZxOPDNzP51lhfbBQgp7qSGDj9Fw5ZyNwz + 5llse3nksT5OyMUY7HX+rq2UOs12a/piLqvhtX1okp/oTAETmKXNYkZLenv6t94P + NqLi0o2AnXAvL9ueXa7WUY3l4DkvuLcjT4+9Ut2Y71zIjeECAN7q9ohNL7E8tNkf + Elsbx+8KfyHRQXiSUYaQLlvDRq2lYCKIS7sogTqjZMEgbZx2mRX1fakRlvcmqOwB + QoX34zcCAPQPd+yTteNUV12uvDaj8V9DICktPPhbHdYYaUoHjF8RrIHCTRUPzk9E + KzCL9dUP8eXPPBV/ty+zjUwl69IgCmkB/3pnNZ0D4EJsNgu24UgI0N+c8H/PE1D6 + K+bGQ/jK83uYPMXJUsiojssCHLGNp7eBGHFn1PpEqZphgVI50ZMrZQWhJbQtTmFu + bmllIEJlcm5oYXJkIDxuYW5uaWUuYmVybmhhcmRAZXhhbXBsZS5jb20+iLgEEwEC + ACIFAliu1ScCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEMz74Z8ArIsd + p5ID/32hRalvTY+V+QAtzHlGdxugweSBzNgRT3A4UiC9chF6zBOEIw689lqmK6L4 + i3Il9XeKMl87wi9tsVy9TuOMYDTvcFvu1vMAQ5AsDXqZaAEtCUZpFZscNbi7AXG+ + QkoDQbMSxp0Rd6eIRJpk9zis5co87f78xJBZLZua+8awFMS6nQHYBFiu1ScBBADI + XkITf+kKCkD+n8tMsdTLInefu8KrJ8p7YRYCCabEXnWRsDb5zxUAG2VXCVUhYl6Q + XQybkNiBaduS+uxilz7gtYZUMFJvQ09+fV7D2N9B7u/1bGdIYz+cDFJnEJitLY4w + /nju2Sno5CL5Ead8sZuslKetSXPYHR/kbW462EOw5wARAQABAAP+IoZfU1XUdVbr + +RPWp3ny5SekviDPu8co9BZ4ANTh5+8wyfA3oNbGUxTlYthoU07MZYqq+/k63R28 + 6HgVGC3gdvCiRMGmryIQ6roLLRXkfzjXrI7Lgnhx4OtVjo62pAKDqdl45wEa1Q+M + v08CQF6XNpb5R9Xszz4aBC4eV0KjtjkCANlGSQHZ1B81g+iltj1FAhRHkyUFlrc1 + cqLVhNgxtHZ96+R57Uk2A7dIJBsE00eIYaHOfk5X5GD/95s1QvPcQskCAOwUk5xj + NeQ6VV/1+cI91TrWU6VnT2Yj8632fM/JlKKfaS15pp8t5Ha6pNFr3xD4KgQutchq + fPsEOjaU7nwQ/i8B/1rDPTYfNXFpRNt33WAB1XtpgOIHlpmOfaYYqf6lneTlZWBc + TgyO+j+ZsHAvP18ugIRkU8D192NflzgAGwXLryijyYifBBgBAgAJBQJYrtUnAhsM + AAoJEMz74Z8ArIsdlkUEALTl6QUutJsqwVF4ZXKmmw0IEk8PkqW4G+tYRDHJMs6Z + O0nzDS89BG2DL4/UlOs5wRvERnlJYz01TMTxq/ciKaBTEjygFIv9CgIEZh97VacZ + TIqcF40k9SbpJNnh3JLf94xsNxNRJTEhbVC3uruaeILue/IR7pBMEyCs49Gcguwy + =b6UD + -----END PGP PRIVATE KEY BLOCK----- + KEY + end + def public_key - <<~PUBLICKEY.strip + <<~KEY.strip -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1 - mQENBFMOSOgBCADFCYxmnXFbrDhfvlf03Q/bQuT+nZu46BFGbo7XkUjDowFXJQhP - PTyxRpAxQXVCRgYs1ISoI+FS22SH+EYq8FSoIMWBwJ+kynvJx14a9EpSDxwgNnfJ - RL+1Cqo6+BzBiTueOmbLm1IYLtCR6IbAHAyj5YUUB6WU7NtZjJUn7tZg3uxNTr7C - TNnn88ohzfFa9NfwZx0YwgxEMn0ijipdEtdx5T/0vGHlZ+WRq88atEu00WNn0x65 - upvjk7I1vB9DTZp/zPTZbUGPNwm6qw9xozNFg/LcdbSMryh0Xg9pPRY6Agw2Jpgi - XxNAApDrlnaexigFfffUkkHac+0EoXwceu8zABEBAAG0HUFsZXhpcyBSZWlnZWwg - PGxleEBwYW50ZXIuY2g+iQE4BBMBAgAiBQJTDkjoAhsDBgsJCAcDAgYVCAIJCgsE - FgIDAQIeAQIXgAAKCRDHKK8Qly6XwO1VB/0aG5oT5ElKvLottcfTL2qpmX2Luwck - FOeR4HOrBgmIuGxasgpIFJXOz1JN/uSB5wWy02WjofupMh88NNGcGA3P4rFbXq8v - yKtmM62yTrYjsmEd64NFwvfcRKzbK57oLUdlZIOMquCe9rTS77Ll/9HIUJXoRmAX - RA0HUtn0RnNF492bV+16ShF3xoh5mVU4v+muTA/izW7lSQ2PtFd2inDvyDyiNKzg - WOUlZESc6YN/kkUJj/4YjqPgIURNx6q/jGw24gH4z6bZ8RfloaEjmhSX0gA4lnMQ - 8+54FADPqQRiXd3Jx5RRUJCOcJ+Z17I4Vfh1IZLlKVlMDvUh4g2SxSSGiQEcBBAB - AgAGBQJTkXXXAAoJEKK3SgWnore32hgH/RFjh9B+er5+ldP4D9/h887AR9E1xN7r - DTN7EF5jlfgXkIAaxk2/my+NNe0qZog9YBrVR+n8LGgwXRnyN9w1yhUE4eO71Zwi - dg4SgU5fK3asWLu+/esKD2S/QndRwIpZOTqsmiqe8N8cVscaoAg+G/TnDJvTKft1 - twIcjrB1fv9B3Fnehy/g/ao+/E1/7CknWE6zB4eSQdOrAfQ9gnJgabLRBUUVltBm - dBZ+lAQyBSAEbkL5FgWhxJNMjuTOVr6IYWvRXneHrMy630wZIk0d7tPEZJvBeIKA - FMtzBJvW6gJ/Xd5mbtb+qvoxfh8Z06vfqNMmhLLEYuvEW1xFSmyWWGuJARwEEAEC - AAYFAlSGz8kACgkQZbw57+NVY/GU0Qf+KCAPBUjVBZeSXJh/7ynsWpNNewZOYyZV - n7fs8tm7soJfISZUbwVAPK8HwGpzrrTW9rpuhKmTgXCbFJszuHys4z3xveByu56y - bmA1izmhaLib1kN9Q7BYzf8gdB657H4AAwwTOQPewyQ2HJxsilM1UVb5x9452oTe - CgigGKVnUT556JZ8I8bs+0hKWJU3aDDyjdaSK82S1dCIPyanhTWTb2wk1vTz5Bw1 - LyKZ8Wasfer6Bk6WJ9JSQRQlg4QRkaK6V5SD33yOyUuXM7oKgLLGPc0qRC6mzHtz - Sq7wkg2K/ZLmBd72/gi3FmhESeU6oKKj6ivboMHXAq+9LuBh30D0cIhGBBARAgAG - BQJTmae5AAoJECUmW1Z+JGhyITgAoJoFNd5Rz9YFh8XhRwA6GaFb7cHfAKCKFVtn - Bks20ZiBiAAl3+3BDroNJ4kBHAQQAQIABgUCVXqf+QAKCRDCDc5p2mWzH3gTB/41 - X9v9LP9oeDNL4tVKhkE8zCTjIKZ8niHYnwHQIGk4Nqz6noV/Qa45xvqCbIYtizKZ - Csqg2nYYkfG2njGPMKTTvtg5UdilUuQEYOFLRod3deuuEelqyNZNsqSOp7Jj5Nzv - DpipI5GxvyI/DD7GQwHHm5nspiBv/ORs3rcT4XatdTp6LhVTNyAp060oQ/aLXVW4 - y1YffvVViKe/ojDcKdUVssXVoKOs4NVImQoHXkHVSmFv0Cb5BGeYd58/j12zLxlk - 7Px9fualT6e5E7lqYl7uZ63t32KKosHNV+RC0VW8jFOblBANxbh6wIXF7qU6mVEA - HUT7th2KlY51an2UmRvTiQEcBBABAgAGBQJWCVptAAoJEH9ChqPNQcDdQZAH/RiY - Wb7VgOKOZpCgBpRvFMnMDH2PYLd6hr1TqJ6GUeq3WPUzlEsqGWF5uT3m07M09esJ - mlYufkmsD89ehZxYfROQ8BA3rTqjzhO9V0rNFm/o8SBbyuGnQwFWOTAgnVC1Hvth - kJM+7JgG8t6qpIpGmMz6uij7hkWYdphhN0SqoS8XgAtjdXK6G5fYpJafwlg7TGFD - F6q5d2RX0BdUhJkIOFNI/JXLpX04WiXEQl2hOwB3la/CT2oqYQONUbzoehUaF5SV - uKlFruUoZ/rbJM1J4imdcEBH2X3bnzdapCqvMudgAALo8NUiJJ/iTiYx/sxQ4XUp - oF567flP1Q08q6w66OyJAhwEEAECAAYFAlODZOkACgkQ5LbUbWbHh8yNzBAAk6LE - nfbdmx2PsFS21ZP8eAiPMBZ61sfmDVgNU5qLDyQRk+xg7lZlFlZ64mka4Bh82rvV - 4evcEOHbuiYS4zupxI9XrBvBpks6mALEAAX/5HXYDgb/9ghNd0xjlheHmMKJk8jE - Mb2kYx/UCimbtG460ZiQg0e+OWNU5fgMEjA8h6FMbt0axPkX+kde+OSg52i1bL5n - fPbGqA3o1+u2FzsufuCEOPsTLKhkiOKnopCMtB8kRih+WQ73G3XkYSkYh2bYW0eF - MoZlgez5lpUWLD0+NWB9qiDXZs1yUJ0CdHA98eahPaPyR8aLqOP0dPkbS6/X4j6N - WjZgZ2sIb8PihowiHYeogMhZZIoBTYqRlbW9/KAptC7UGFMF21Vp7HexFRuoC8qO - PSXfMLH4kw0Lq1mLBTw9+No0L7xfMxKmzT0VLsJkJB09gAGWv2/8voCIPtBm/MZi - C9o3w3tWAczAvZetMXH/dp8Por6pmMoTHHUkbSBZHe1Lt138jLtozZDCuuWQ53O/ - mIT1sds1Oy6IF4e0xrSqpZlDGwj0pqOKmtLFI1ZRrfjb5bnm7sgzcxoM5aPhqJyb - 88XYgBolsiErM+WhnH6cAEK2TUVlVqXzDIbqKBroEK/cM+Bez1SagzAsoarYA5R1 - yewc0ga/1jQI4m6+2WoL4wo4wMNggdWiIWbuqAmJAhwEEAEKAAYFAlZDO+4ACgkQ - MH93QRZS4oGShw/6A6Loa5V9RI9Vqi7AJGFbMVnFJV/oaUrOq8mE8fEY/cw1LQ5h - Ag/8Nx7ZpQc28KbCo0MR3Pj7r2WZKLcxMwaXlFZtNiO4cEITNu5eoC7+KOrFACsO - 1c0dKbMEeDQ2Xqzo2ihw/4DnkuUenrmGnNJMQ5LrEZinSKFFAgeYRdYnMdYqOcXe - Q8rPImFkyOnPbdIOC2yPzjqHIsuazuwd9to+p35VzPNZv7ELFBfx/xDHifniRMrm - sPJh6ABjecOJg7RJW4h9qP+bNbbrJa6VfGAbNUR+h4DiMr6whpGJd41IiXIEGrGW - BT87hO7gwpMrex0loQoHwsfqMxOM0qwMU9ARCJJLctzkj727m/SsyP9cUIFGceBN - cUopmpKCi9z0QZ/bxKWbpqa3AarkWxRLj1ZzmllxC7tjO61kr0zkn8pnEIc79cGw - QlUI9k7QaWFm1yDlpPXLvBi+evYxSONbsSoHwjMIC/cioBh0c0LOXn8TV6OWlS/3 - sWShQG9KxugZdK+MBrZPR23jilHPKpWG8ddEWp4BZugqxppiyZAgEOMlHBr5PkV+ - hBx1vCG0w9IlMJODRIXIUeqot3ixQvLmeoWTuIFPiNPfXskCfNuudbj4+jZewf6z - BL60VJADKJENmsDPPhF6UEiHDIrauNylORhhPR/qEAs4LOiEwRqRtHBEqYKIRgQQ - EQoABgUCU39OnwAKCRA1morv4C3iPRylAKChT88Lvmd1M5LX1hoRqsFeG8IahgCf - Q1VWKh852oZq9dOtbGRxEbv876OIRgQQEQoABgUCU+DpHgAKCRBmKanAQloCxoSL - AJ44D4cwTLOmw+rHl6bB/oqNhoV3bQCbBmyupEB9gn6NUD80BTEzs0jTHWSJAhwE - EAECAAYFAlNv5m4ACgkQxykhoSk/LSQnZg/7BSrZULH/tRDRd1LvuKtHoR7AarqD - iGQXhxvXLp6AZaMcI1UF/hvKeJtho5tKjQ6OpEB1sPXXc68abvRdJFh42GBPmHFD - A8aBsJJePZQTMm4biDfFNw7cK1j0cjUczftAlyFAf5w5y2kM5jo24qdNmVqa5ipE - u0AcmzNntgaWeP9izXdnjpNTSOG6Rbo84IrIku7sR8GxNvlisAS1hhwYkYksNts4 - gu+wmfnkLFyZrncbjVHLVbZnAJhhcdWKhyjcOBRadrAZ/EoK1/3VoLHIdWBpW0f9 - sUYv3u6WUyWa4EFaaHRxttMFWhWq9p2nYfojh2Bf5V6cOLgikkIu03oQp2GPNnOL - ub0PTmSS+93ZmIEW9NIxY0cmz8lFVo9qqip4Dzka2Rp3oTg0x3JKXU+OZV4J/Mfa - LT5uI3Flub3f8etOQw+6/Q5Rg3vGOh14UtEVaA1WcKeyRq7v+XZAA16FN5omCEX8 - xA641xgefvLx4jj0ZfqlHgH+dEoOdbiRQ3IYyzMnX/xLl88Xw49etkeflQFXvkLh - e6QdXrfrm4ZniIWOfCDeQmZS0znDV46YzK0MVu6kYXcmDpVBRREUzsxgJmWg4JW2 - EgHTqSHL8Oi8gvfTMKaPSnTl3cWSKlupQDx/CYuuqdAd7x2hcSivWFu22YcNp4XV - fd0jJPvv+UlnmjOJARwEEAECAAYFAlRcmw8ACgkQlFPUWjJBWVgGCggAgZDWaPcj - Fce9mnRtMDyOVMOZQ0AppvbS97pJ6PLF/dKXz+nyNtkiAPfimRTE3BpXhX3JDke9 - PEaRH/dXTdmzfej9N3DOADFJlRVyxETXyTGiNzyP7vaJAT+9hgW7hbUtgoAbDK31 - ZWijVEw4+Jg9vWhUKBhLrV1lcyQyZAldLYep/sAyynAeaUbsFtbpH8DHXZBIA/0C - 2XWp7o01w8b1CgsUHBfBK9eNlQ3BOu3Y5WY8MW4ZcRuDlH/hbs9V1zK5vkR2zq4d - uSG8KYHsLV1/zskLszLZk27c6QHQb1C6U6CW8shgkdxGRduXMETRL4yYib3s4Mwy - xovU00cYKQ5CIokBHAQQAQIABgUCV2FHnwAKCRCZSfh4lwNdkn7DCACvBLx76e+5 - 9vaGdSne2veRwT/J/a5OWJghn7f679btAxJROvWdeHvWW4vHKz+A6HGvR8E7xGCZ - NdfkokqXcioSRcZFIW7zAev27F31E8V63voY2KDESlkxrRhNZBpvwfXAg2RS9KmB - btmgj6Zo1VnbEXoxPO+5yZzpYxuBPL7xMidSznQe9eswqMLvSNxKQODOGToddreb - 9ClKk+qpQOCTQTEQjw4Y9wjoZ5SdENP1IihnTi/Z31Sr99CL3jPPpXoo8WO4in6z - DPEEvAbszDb+24+WDEoW47ST+x4eDJG0WcVrjNa87k7kMNOWsPr9rNHtgRCNa22M - xaPaKrTZ/F03iQEcBBABCgAGBQJXc+wKAAoJEIhwMVR86tleqikIAKQtWDnrp1dl - tE4G1IVp2i9NwhCOaZVODaGaH3C564B8/WyEbjFjOmm4aDzykiwEUWBMCP0icpHn - 3o5s65gdtgnP/KVWKp3wyJqJYu0rQcyFtKNKi8x5D/7c8y23DRoI2lnI12f7MWPH - wzC3wClulTboV0mC2Cp1TWLBnKGbhpHOGN5ViSPm3rPOesFZ5el38wcwDKWaZbmm - hFtx8fx2T2lTP+5GRCuiXrnsrzA3tZLuRWH44esPxYB8mFg1btgAtXo9Q9MEISWL - g043RQ0VWU3a9F7K3RshTPAUbvUrNtEAFMtij0B4RvLE5cyHEltUB0R4ie3RDZDe - z0VCwrsaI+OJAhwEEAEIAAYFAlePuxUACgkQ+iIJCo0F+QvWZg/+I5R1TdQpMKVM - Fz+XrYXpSgPxeLr3b6svuV8uOPY8kYbOPVxvjbNGuyijbRD/btH9Qg2vDNGbZJ9G - pGUfnNNlXUsTkxp/5sEWAzBH0pTEgiy7wHzCa4u+meXDkLnomdZfSHkFNDw+I2MI - Nrp84DPkMBQ4X5AJ4UcoMUbfqLRbqgHo/DEAYsAwnihF4Lwl8x9ltokcAc+w3SQk - mvHOR1xoeAFtH3NEzUvA3EhZo16o7+dQWyh8GJRsgUA6g6zyqLOn+JTDVh1YlrAF - 1qkhnBsw7G5InL54mhvXwqKoAwI5zO8A+5tSUMUvtZBfUW2DX/yCvaD5v/fjMScF - 5Lw61NYTLyZEW+JlLGGdIrewB72BVPVR5Sak+dwwjxHK2NGdaug3V8gOht8ZwYKx - X9NmYLWi+4DFkQxtSCpwH6WAqfw4OPuvFHyd/VdA5czsQo15rU2Go5JE7FlR1xoy - lCNV4TU3p+eLTNW/L7ty4HPuiPWI3gDpRgh0Tv878IlLKuivlNhfTub8Hf4LzSW1 - g++1lwUf3TxhYUPHmZT2V9Sk+VVgCXIFenn914r+RZMnThCgWh2GmcKDgLKUSdxv - /j14NlTgWqUY3cQM/ciSdAdqZn8WAOjeuVgpqkX5A4NrWbshaqUsksm9QdtpMia1 - Q2hDuR8OIvHP0PiwNv8Bn00nAgyU2NeJAhwEEAEKAAYFAldP7ycACgkQu9aLHqU1 - +zaXsA//Rm+1ckvAAaj1qk9rXpYZVWK8kCeKkHu48bL9r0g9Z1mfCGTgrUd1lPNW - Lh850z+LYzJelZCqnNsgxX8KG567NwdRb+LBy8tzbCgIMomfgqILv7KmRzPQ6AJ7 - Bp8hGnregfD0CCXtEORk/aQF0FCRL8bKsKiN7DOPirP9gfdSgpshr1cLe8a7cPFq - Zza7VhAke5/BCsNzxaUvseuzZ6bZOXlUpbSJH2+f/DYXvwfaJl/Rg+s+DuPtqVgI - TMSsRwL/iIlqfT2Al4SVak4f0q/HVkNgfEFSx2i8OWlVe90V71sNNAOMSDnBRHBC - fNon4vwnv3xkKwH6ecwgZtZwcjPKMUZPjrzEFULOBrNAsC173HypbZZ/wlJBAMd5 - gBd35CQELrq2sOgekofm7Sbq5m2WYr35M0nqIV8q0ySxMWyuY2g46QQVEyGiXrKt - TyJzT7M+UtqD03wjNSBZc7y/a2+kzZJADrz8kNANuR5GGfxZ3zKjmgyQX2QRNYq+ - +bwB6U7NyRgzX/i3sE2pSn2xuwwzqk873r+Afb8gCMSXV1omcwZJAHeUURjv70mU - A9BFjE249JxjDbuzThiErMCG4Gj87NjXYCBq7QsfyKPVAx7esEYoDmR+k4nYH4my - pY1LTgLZUOBtGiLnkGIZ9XVIcZBPRoSKEpRRvcPBtHkJkqwQm8mJAhwEEAEKAAYF - AldQLVYACgkQsOAWYMCDwn9L4xAAgMxHehYdB6+htNj/c7xlFhdv6nyLl8excl0q - jOBLsN00w3F1yGZqNhbKsvHZKhW8PZhX+wMMoczGi1YdOV3AMoB20/t+DRh2giRL - wgLiJblxR4Z4Ge+/ne3/aVHOHyVqmh879TA2coUS0i0BpqRoY70eV/yVqkbXpuFm - reXLt3Syc3HoGd79KiyRht83Og/d7dbxkQOCe7YnRxuVynwMKgIRJt+UgCIM07sR - nA05MWgatp9PiFXkGdfyBy2UkvybcaAyjByBpOjdTPFa2LdjIO4Qsgmg8q8F3z0g - gW3bRPKQDNX6w7UA4tf587x0S1mKwXGeLnezZv1kmAQB//bYgZs4bZsqeB/i832I - sWzX7PEoh/kGWg9/eZBQu+l5d8koD2wRiUvFVussont7LMsNwHJSerS++tj5Tdwj - E8qcNdJYkcjkVxaHugVlm+IQfSrvdMpRq8bfwxGmprU3hAebB0b2OZDMm/uWGiVC - ycjStGUtu/ZJU56zRhkj/4yZPi7gczZAurRXvLt4AhNpkGPNSAxt16fpaBkBPo61 - pHir3K+FvpXN4ezv+mFR1G0hrSTuMk2nU1D7WUkw0xnx/IY7VrGx8PrR8Ilfb+C1 - 9z1g/uuZ4alIWXZ/tAeDPjTQI5QOPgj43DrgWqG2FDAqQ/+nt9RevUVIPMOojOko - BdHaskmJARwEEAEIAAYFAlguvT0ACgkQkDmkVrycD3gyvAf/fks3MtR+yoMRCNIi - VklGwoTv646OOqm3bDZz180cXqGXxSASQ7fglaDGl+of2qRyilU9dzkY1ZHqD2AY - /sycR1QKELfa9rFx12i4w9jyWdZykOggS6Os3e1Dvt9Q4fZzP0+eLCs8Fknancxq - WhUrXqaYz/OZj4Xmjw6jYZxdtJ/B0OFDqxOlN7v3iZSeXNwKJ5vpeJLE6dfy/5pM - ms3aIj8KB+MDSQpgaZ8FKjRn8rSZwUu768sHNTWv5l0UxJbIREB5XE8fQuGxPIJ+ - DyxiKmPMlyuyj6whz+iZP5jkEDpDiqFEJHHmw9qAlhkba0LzJYh2uqS7L15V6ykY - xZ4wl4kBHAQQAQgABgUCWC6/swAKCRDij8qPAN1CxhQJCACP+UCg5zM5h8HtLlPL - Pt1jofqmVqk8KJHJyZzn6EgyoQmNnPDybLHIRTxB+hsQTAZJtQn7UiBpXa0OmBXm - s4MdeRb0tIPN1l66l8+N7OuG0Tf+mALwAM+GqiUgSEGs5gOVF9Ev1pP0dRCKTSGJ - v0NMNUb77Qkn34R4HK+f0nfFKER4RW23F5e6sf6Rq4SzP3sVRdqU5dY1alxMFWNy - 7IrP/QdsBl6ACtYSFAuay/hxyccbu22KhIm0S2ikJJgjNenyq15TGaBoG02nl4lC - TgrOEjNDSXw2Bn4L6AZM8sR08ZjARqKspB7ZnNOcIaIrK61cpgAL4SXdMkvQF7Qj - uhatiQIcBBABCAAGBQJYNfShAAoJEMELqJFB1XEubX4P/0or+wvHMFC1lBTttKlO - mkPHTHDYZFCLQr/6cjAv5OPyrBOh/uJ+QJq6awrn1LD16j2YEZUkgkqHBiNl5f7R - J8Tl97esxZja5iHvgOx54NDxD97WoIgJhEnYuhvY7sACT5YBx4npMKPi0WaqgCfR - GDeQzVcKzgWhScgeSnWBf7+bwIdGO4mg9y58s/4fMK1kw6niK/xo1hkK0w41StV1 - wmK92fEqeFElseaBSmf8efgb4Qi6ic9Zf2mGgjHwTIn7FeTA9r6zzSggw3b5NEG6 - W2bdhVmKheYPBp+kdsQqsw9H/AzUFLL8wg982IRyvnbUkccP/7neWeFJo/1VVogp - ybTBdgxa+dl5UcjxvqJZbFp0mLorWJvOVamoGgvO2WKv0tSUK3LwVxZaIVMbFwEo - G+FfpW8XfqhzdkD6zJO3rjpOcnrouaYB/SpSofbwRxrtxTzcxxMP2B62gd7/VdcY - duyL6Cj21P3vIdveQ26B8zdSiv6MfG/7/zlrpe9strIv3UiHfpG8093TnPB2gwWL - /zdh7Nbsn3rq2Rti00zIqHpopPS4J/dr/jdpXzMymb93HpsA5UTuyYHnqa1YBAgn - qfnkk+lNENso6Ymg8a+S/oFh7Hks7olrhYpmdodL1AqU+YWMsp2L2knOxmpEZc8s - mjVx9YKKxrtZ7FisuwVER+3fiQEzBBABCAAdFiEE4gFIMof/a3u+jGQXNpvllaAP - nh4FAlhrniwACgkQNpvllaAPnh6e1QgAh646441z+ecM8k82DIctj1RT01tY5Ygz - WwDx4HJZy8b/l3J8PF62mZB045vC9DGweX7DgJ/FZXTwMGfS1lU7gBmIMJZnp8lU - m4K1IRgYf70T5LOepaYgJUJ9iPoc1bSw91efkdQSou6Fignet+DMk3268qbO/JO6 - Q8MbsD9XDND1pf6Y1gdtsrXaQTTqnf7l/5zbrYlknOBkDk4x7ZbYgZYfEucba4/R - 3O+dN7Eu9O7dS/PmYDvozPCuEIJrPwxdWnDr+0J6JwHwP9o2OD51CT/LfvL8uGtS - oPcmB4Oon1ORayDWWthlypYONP0kKwIFsR6mgU++UVNj+b+ABbizOokBHAQQAQoA - BgUCWH3oQQAKCRAfFBlUoHXkjEbvB/4zwwaKHd6B1d6XMzysG3/l29IxdNG8Udh0 - d8/o/jEl6jxJiIjVvaFTXXP1/owBjDSP/RwX0mMaluIfedghN+y21UQfi2QJ2FtV - d7hLTKjgLYStGZGakmUlaXvwZsshZmpQJDbFo6SWqBb68yjult8VTnoug+Q+I28o - p2y8sviFoEyBKnYXotSt9HNMLHtYUeFqJWAwVRIt14oaHXQjv7QuB9/RnuY6/sfC - In5y84sJyEylghP4C2+Usl5QtcAR5gByMvpfyPsFxXIcGw+Bxk9Sm0k37tCVAhKB - dIOMd85s8mQJ4nOZu2hLhKBlOgX1HNb/LJECG2QPqlSDtoFXrzcotCRBbGV4aXMg - UmVpZ2VsIDxtYWlsQGtvZmZlaW5mcmVpLm9yZz6JATgEEwECACIFAlicPfgCGwMG - CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEMcorxCXLpfAl0UH+QFkOIlIuFpb - 6MkAdp7qkaP58HG0nFZMWTLiwJnh4rclN5vvU7Dlvyy/JOI1M6wepBl3ujNJ+Pe1 - RL1Jy001sN9ZGvtkCiXwfg+3IRNAacQwdl39lUsaHbzSyo/33U7i9NaQ9QefLpji - on1auZMXQ8OVDPo2sT01kSwutMhYx/8wEc+kh/uckCYLFjx06mF1l+OGxc77CGbr - WeItjrjhTkYjsoaVh776V0Q2m08Ixq7pBXYp91zKT00EUE64LdIN85AkzehzSptF - +lT/BW2C1Ft5E588914PMKvNcufB0twaNFqKZUOCiIXO3cqlLoz5GHLe22mJKngo - NXVsbNZ/8zW5AQ0EUw5I6AEIAMb+U5s17opggc0fgejZleAv8ie1HIKms7PNlaMq - lzQj5bmFAln7DjUvupey8fkpLJtEGAJkp0vBiXohM3KOa78hr9ShJIVuFrz473jj - 9cAMlcLme2yDvPVjtTEFiVwl9+WXgvjtgkQjDKU1v9QJIC4UbcnzYwwyHuXXVUKW - v9gXj2a6Adk0cFF0qbNpBzfKrettsp02PUPlrceVhB8KDgY9/rj90uxQBmeZn9bP - G2W4zR+J+8kLcUAFlVhJasfItDo5bpFl7VH8hX5ZzXBL0NMQQoeNRtnrt/5xJ5Kl - BQbflScVaF1s+3oK75ppEeRZrYP5ESB5JBLUGuFO44hD/OkAEQEAAYkBHwQYAQIA - CQUCUw5I6AIbDAAKCRDHKK8Qly6XwLGiB/0ZUZf+ybfY6RQz4QoRw+RO290bf1Gx - wuL3PPCxaVX3POv1S0RLblYEP+88ikaYv6zpiEoohQPtCXdLfyJswRgTUNWS4DPZ - COW5TLLE2E/zYB0YGwLilZvAkopx+x1tWT2aBjNyXaHC9Z8jhuqlxKhpUbRKpyma - OxtDOS7L3xzzcfowuxFx08tPXgRcQOeINK55v2d8xwKGdfKquQTX1ibf4ipXvWIB - hCn6UW2YqhqIatQp/Swcj5woIv2kCCAI1cDPRpMUu48qJNYmsKEG6FO55/UxSRyF - TseoRTbiwR6tr3X729W1y5FIoFo5tq1NbAMy3o0+sP9pQtbN+1Percgf - =1CGB + mI0EWK7VJwEEANSFayuVYenl7sBKUjmIxwDRc3jd+K+FWUZgknLgiLcevaLh/mxV + 98dLxDKGDHHNKc/B7Y4qdlZYv1wfNQVuIbd8dqUQFOOkH7ukbgcGBTxH+2IM67y+ + QBH618luS5Gz1d4bd0YoFf/xZGEh9G5xicz7TiXYzLKjnMjHu2EmbFePABEBAAG0 + LU5hbm5pZSBCZXJuaGFyZCA8bmFubmllLmJlcm5oYXJkQGV4YW1wbGUuY29tPoi4 + BBMBAgAiBQJYrtUnAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRDM++Gf + AKyLHaeSA/99oUWpb02PlfkALcx5RncboMHkgczYEU9wOFIgvXIReswThCMOvPZa + piui+ItyJfV3ijJfO8IvbbFcvU7jjGA073Bb7tbzAEOQLA16mWgBLQlGaRWbHDW4 + uwFxvkJKA0GzEsadEXeniESaZPc4rOXKPO3+/MSQWS2bmvvGsBTEuriNBFiu1ScB + BADIXkITf+kKCkD+n8tMsdTLInefu8KrJ8p7YRYCCabEXnWRsDb5zxUAG2VXCVUh + Yl6QXQybkNiBaduS+uxilz7gtYZUMFJvQ09+fV7D2N9B7u/1bGdIYz+cDFJnEJit + LY4w/nju2Sno5CL5Ead8sZuslKetSXPYHR/kbW462EOw5wARAQABiJ8EGAECAAkF + Aliu1ScCGwwACgkQzPvhnwCsix2WRQQAtOXpBS60myrBUXhlcqabDQgSTw+Spbgb + 61hEMckyzpk7SfMNLz0EbYMvj9SU6znBG8RGeUljPTVMxPGr9yIpoFMSPKAUi/0K + AgRmH3tVpxlMipwXjST1Jukk2eHckt/3jGw3E1ElMSFtULe6u5p4gu578hHukEwT + IKzj0ZyC7DI= + =Ug0r -----END PGP PUBLIC KEY BLOCK----- - PUBLICKEY + KEY end def key_id - '972E97C0' + '00AC8B1D' + end + + def fingerprint + '5F7EA3981A5845B141ABD522CCFBE19F00AC8B1D' + end + + def email + 'nannie.bernhard@example.com' end end @@ -301,8 +178,12 @@ module GpgHelpers '911EFD65' end - def signature + def fingerprint '6D494CA6FC90C0CAE0910E42BF9D925F911EFD65' end + + def email + 'bette.cartwright@example.com' + end end end -- cgit v1.2.1 From 41c96c45f2696af54dde81271741a6342db5d55a Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Fri, 24 Feb 2017 20:17:08 +0100 Subject: test with a gpg key with multiple emails --- spec/features/profiles/gpg_keys_spec.rb | 4 ++-- spec/models/gpg_key_spec.rb | 2 +- spec/support/gpg_helpers.rb | 31 ++++++++++++++++++------------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/spec/features/profiles/gpg_keys_spec.rb b/spec/features/profiles/gpg_keys_spec.rb index 42e1a6624b7..e7939533272 100644 --- a/spec/features/profiles/gpg_keys_spec.rb +++ b/spec/features/profiles/gpg_keys_spec.rb @@ -16,7 +16,7 @@ feature 'Profile > GPG Keys', :gpg do fill_in('Key', with: attributes_for(:gpg_key)[:key]) click_button('Add key') - expect(page).to have_content(GpgHelpers::User1.email) + expect(page).to have_content(GpgHelpers::User1.emails.join) expect(page).to have_content(GpgHelpers::User1.fingerprint) end end @@ -25,7 +25,7 @@ feature 'Profile > GPG Keys', :gpg do create(:gpg_key, user: user) visit profile_gpg_keys_path - expect(page).to have_content(GpgHelpers::User1.email) + expect(page).to have_content(GpgHelpers::User1.emails.join) expect(page).to have_content(GpgHelpers::User1.fingerprint) end diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 917d420878a..889396c19c3 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -59,7 +59,7 @@ describe GpgKey do it 'returns the emails from the gpg key' do gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key - expect(gpg_key.emails).to eq [GpgHelpers::User1.email] + expect(gpg_key.emails).to eq GpgHelpers::User1.emails end end end diff --git a/spec/support/gpg_helpers.rb b/spec/support/gpg_helpers.rb index 8e005634c94..52c478e1976 100644 --- a/spec/support/gpg_helpers.rb +++ b/spec/support/gpg_helpers.rb @@ -98,8 +98,8 @@ module GpgHelpers '5F7EA3981A5845B141ABD522CCFBE19F00AC8B1D' end - def email - 'nannie.bernhard@example.com' + def emails + ['nannie.bernhard@example.com'] end end @@ -161,15 +161,20 @@ module GpgHelpers iLgEEwECACIFAliuqioCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEL+d kl+RHv1lQhsD/0LDi008hCeoZdGMuwy2N5FMUusYg/X1tRQ6E0JcYYjvvE5oIZoX bVN0yLLD99P0rt6TSlt05CC7RPVPCNpKxKbF+TZMjMJiOi13XmY5Yti77ZMdBZtD - 7HeBzjkWCVuR6k8eIwy83niHGI6p6G87Q6XxvDjQ7wdBCNBpwkzmTYIBuI0EWK6q - KgEEAN7mdR1U5xtmWfE6OXQoEBP4DlubIEtRPQGYs+yYDg+5cNK2Hta+Js8LzBwJ - 0JhWTQhExid5lSJar+jlziu2F8tHiODySu6+iZDgTh3iHIjpHQwvFdhndcy7rtW5 - JwWBstRHDV5FnXoA13c1zVW4VbuazS8IbSJ0HyJJkGhQtorxABEBAAGInwQYAQIA - CQUCWK6qKgIbDAAKCRC/nZJfkR79ZUIIBADVsEMK5U9gRS1lfBcfsJYN9fpnI5E6 - tC2lrt6LngJbqEpfd9gek6K7jIeuiaMaUg1OOMdyWwmmf+qaImLOQH3/GXshFZX5 - FWkOyFnebKY6V2kuIqAjn5GXqZm07hO0z0FjOIgQLbiH4iRosHKVljPiiB9vNcoX - wnG0c8xS7AlUMQ== - =Erp5 + 7HeBzjkWCVuR6k8eIwy83niHGI6p6G87Q6XxvDjQ7wdBCNBpwkzmTYIBtC9CZXR0 + ZSBDYXJ0d3JpZ2h0IDxiZXR0ZS5jYXJ0d3JpZ2h0QGV4YW1wbGUubmV0Poi4BBMB + AgAiBQJYrwLFAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRC/nZJfkR79 + ZVzsBADYe3Hv71I7+lTJDvKOTmV7M4ShOfjEpmDvL/5JB3FzXHAucCOlReCv/6+N + afAspPTc1uys47dvtePwQalroAsd8Y1grn/PCh+Tx27kpn1WG8yZjUsuq3z5rrGR + uXj6g8aeZdqkMTHUVF9Gd+g/5KDODdJbOjwH+l63b/bOiATDFbiNBFiuqioBBADe + 5nUdVOcbZlnxOjl0KBAT+A5bmyBLUT0BmLPsmA4PuXDSth7WvibPC8wcCdCYVk0I + RMYneZUiWq/o5c4rthfLR4jg8kruvomQ4E4d4hyI6R0MLxXYZ3XMu67VuScFgbLU + Rw1eRZ16ANd3Nc1VuFW7ms0vCG0idB8iSZBoULaK8QARAQABiJ8EGAECAAkFAliu + qioCGwwACgkQv52SX5Ee/WVCCAQA1bBDCuVPYEUtZXwXH7CWDfX6ZyOROrQtpa7e + i54CW6hKX3fYHpOiu4yHromjGlINTjjHclsJpn/qmiJizkB9/xl7IRWV+RVpDshZ + 3mymOldpLiKgI5+Rl6mZtO4TtM9BYziIEC24h+IkaLBylZYz4ogfbzXKF8JxtHPM + UuwJVDE= + =0vYo -----END PGP PUBLIC KEY BLOCK----- KEY end @@ -182,8 +187,8 @@ module GpgHelpers '6D494CA6FC90C0CAE0910E42BF9D925F911EFD65' end - def email - 'bette.cartwright@example.com' + def emails + ['bette.cartwright@example.com', 'bette.cartwright@example.net'] end end end -- cgit v1.2.1 From 0e3d3d60bae48f3698f9e7b0e060edb67170b11e Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Fri, 24 Feb 2017 20:07:57 +0100 Subject: email handling for gpg keys --- app/models/gpg_key.rb | 3 +-- lib/gitlab/gpg.rb | 20 ++++++++++++++++++++ spec/lib/gitlab/gpg_spec.rb | 26 ++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index a9f1400650c..146ca2f2705 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -28,8 +28,7 @@ class GpgKey < ActiveRecord::Base end def emails - raw_key = GPGME::Key.get(fingerprint) - raw_key.uids.map(&:email) + Gitlab::Gpg::CurrentKeyChain.emails(fingerprint) end private diff --git a/lib/gitlab/gpg.rb b/lib/gitlab/gpg.rb index 64f18d00e46..73a4b691cff 100644 --- a/lib/gitlab/gpg.rb +++ b/lib/gitlab/gpg.rb @@ -2,6 +2,14 @@ module Gitlab module Gpg extend self + module CurrentKeyChain + extend self + + def emails(fingerprint) + GPGME::Key.find(:public, fingerprint).flat_map { |raw_key| raw_key.uids.map(&:email) } + end + end + def fingerprints_from_key(key) using_tmp_keychain do import = GPGME::Key.import(key) @@ -12,6 +20,18 @@ module Gitlab end end + def emails_from_key(key) + using_tmp_keychain do + import = GPGME::Key.import(key) + + return [] if import.imported == 0 + + fingerprints = import.imports.map(&:fingerprint) + + GPGME::Key.find(:public, fingerprints).flat_map { |raw_key| raw_key.uids.map(&:email) } + end + end + def add_to_keychain(key) GPGME::Key.import(key) end diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index 6cfc634e2d9..2a55e7d89de 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -15,6 +15,20 @@ describe Gitlab::Gpg do end end + describe '.emails_from_key' do + it 'returns the emails' do + expect( + described_class.emails_from_key(GpgHelpers::User1.public_key) + ).to eq GpgHelpers::User1.emails + end + + it 'returns an empty array when the key is invalid' do + expect( + described_class.emails_from_key('bogus') + ).to eq [] + end + end + describe '.add_to_keychain', :gpg do it 'stores the key in the keychain' do expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).to eq [] @@ -36,3 +50,15 @@ describe Gitlab::Gpg do end end end + +describe Gitlab::Gpg::CurrentKeyChain, :gpg do + describe '.emails' do + it 'returns the emails' do + Gitlab::Gpg.add_to_keychain(GpgHelpers::User2.public_key) + + expect( + described_class.emails(GpgHelpers::User2.fingerprint) + ).to match_array GpgHelpers::User2.emails + end + end +end -- cgit v1.2.1 From 0668521b2b8ed32f4a3f192a8ad04c64f6c1c0cd Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Fri, 24 Feb 2017 20:16:04 +0100 Subject: move current keychain methods to namespace --- app/models/gpg_key.rb | 4 ++-- lib/gitlab/gpg.rb | 16 ++++++++-------- spec/lib/gitlab/gpg_spec.rb | 34 +++++++++++++++++----------------- spec/models/gpg_key_spec.rb | 8 +++++--- 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 146ca2f2705..1101dbae4a9 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -40,10 +40,10 @@ class GpgKey < ActiveRecord::Base end def add_to_keychain - Gitlab::Gpg.add_to_keychain(key) + Gitlab::Gpg::CurrentKeyChain.add(key) end def remove_from_keychain - Gitlab::Gpg.remove_from_keychain(fingerprint) + Gitlab::Gpg::CurrentKeyChain.remove(fingerprint) end end diff --git a/lib/gitlab/gpg.rb b/lib/gitlab/gpg.rb index 73a4b691cff..f478f1ae5d8 100644 --- a/lib/gitlab/gpg.rb +++ b/lib/gitlab/gpg.rb @@ -5,6 +5,14 @@ module Gitlab module CurrentKeyChain extend self + def add(key) + GPGME::Key.import(key) + end + + def remove(fingerprint) + GPGME::Key.get(fingerprint).delete! + end + def emails(fingerprint) GPGME::Key.find(:public, fingerprint).flat_map { |raw_key| raw_key.uids.map(&:email) } end @@ -32,14 +40,6 @@ module Gitlab end end - def add_to_keychain(key) - GPGME::Key.import(key) - end - - def remove_from_keychain(fingerprint) - GPGME::Key.get(fingerprint).delete! - end - def using_tmp_keychain Dir.mktmpdir do |dir| @original_dirs ||= [GPGME::Engine.dirinfo('homedir')] diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index 2a55e7d89de..c0df719c0c2 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -28,37 +28,37 @@ describe Gitlab::Gpg do ).to eq [] end end +end + +describe Gitlab::Gpg::CurrentKeyChain, :gpg do + describe '.emails' do + it 'returns the emails' do + Gitlab::Gpg::CurrentKeyChain.add(GpgHelpers::User2.public_key) + + expect( + described_class.emails(GpgHelpers::User2.fingerprint) + ).to match_array GpgHelpers::User2.emails + end + end - describe '.add_to_keychain', :gpg do + describe '.add', :gpg do it 'stores the key in the keychain' do expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).to eq [] - Gitlab::Gpg.add_to_keychain(GpgHelpers::User1.public_key) + Gitlab::Gpg::CurrentKeyChain.add(GpgHelpers::User1.public_key) expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).not_to eq [] end end - describe '.remove_from_keychain', :gpg do + describe '.remove', :gpg do it 'removes the key from the keychain' do - Gitlab::Gpg.add_to_keychain(GpgHelpers::User1.public_key) + Gitlab::Gpg::CurrentKeyChain.add(GpgHelpers::User1.public_key) expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).not_to eq [] - Gitlab::Gpg.remove_from_keychain(GpgHelpers::User1.fingerprint) + Gitlab::Gpg::CurrentKeyChain.remove(GpgHelpers::User1.fingerprint) expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).to eq [] end end end - -describe Gitlab::Gpg::CurrentKeyChain, :gpg do - describe '.emails' do - it 'returns the emails' do - Gitlab::Gpg.add_to_keychain(GpgHelpers::User2.public_key) - - expect( - described_class.emails(GpgHelpers::User2.fingerprint) - ).to match_array GpgHelpers::User2.emails - end - end -end diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 889396c19c3..e8c41299937 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -24,17 +24,19 @@ describe GpgKey do describe 'add_to_keychain' do it 'calls add_to_keychain after create' do - expect(Gitlab::Gpg).to receive(:add_to_keychain).with(GpgHelpers::User1.public_key) + expect(Gitlab::Gpg::CurrentKeyChain).to receive(:add).with(GpgHelpers::User1.public_key) create :gpg_key end end describe 'remove_from_keychain' do it 'calls remove_from_keychain after destroy' do - allow(Gitlab::Gpg).to receive :add_to_keychain + allow(Gitlab::Gpg::CurrentKeyChain).to receive :add gpg_key = create :gpg_key - expect(Gitlab::Gpg).to receive(:remove_from_keychain).with(GpgHelpers::User1.fingerprint) + expect( + Gitlab::Gpg::CurrentKeyChain + ).to receive(:remove).with(GpgHelpers::User1.fingerprint) gpg_key.destroy! end -- cgit v1.2.1 From f0fe1b9d4397e6c1c6aa2da6e371e234db774fe2 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Fri, 24 Feb 2017 21:28:26 +0100 Subject: gpg email verification --- app/helpers/badges_helper.rb | 11 ++++++++ app/models/gpg_key.rb | 16 +++++++++++ app/views/profiles/gpg_keys/_key.html.haml | 2 +- spec/features/profiles/gpg_keys_spec.rb | 20 +++++++------ spec/models/gpg_key_spec.rb | 45 ++++++++++++++++++++++++++++-- 5 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 app/helpers/badges_helper.rb diff --git a/app/helpers/badges_helper.rb b/app/helpers/badges_helper.rb new file mode 100644 index 00000000000..e1c8927ab54 --- /dev/null +++ b/app/helpers/badges_helper.rb @@ -0,0 +1,11 @@ +module BadgesHelper + def verified_email_badge(email, verified) + css_classes = %w(btn btn-xs disabled) + + css_classes << 'btn-success' if verified + + content_tag 'span', class: css_classes do + "#{email} #{verified ? 'Verified' : 'Unverified'}" + end + end +end diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 1101dbae4a9..04c7ce2e79f 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -31,6 +31,18 @@ class GpgKey < ActiveRecord::Base Gitlab::Gpg::CurrentKeyChain.emails(fingerprint) end + def emails_with_verified_status + emails_in_key_chain = emails + emails_from_key = Gitlab::Gpg.emails_from_key(key) + + emails_from_key.map do |email| + [ + email, + email == user.email && emails_in_key_chain.include?(email) + ] + end + end + private def extract_fingerprint @@ -40,6 +52,10 @@ class GpgKey < ActiveRecord::Base end def add_to_keychain + emails_from_key = Gitlab::Gpg.emails_from_key(key) + + return unless emails_from_key.include?(user.email) + Gitlab::Gpg::CurrentKeyChain.add(key) end diff --git a/app/views/profiles/gpg_keys/_key.html.haml b/app/views/profiles/gpg_keys/_key.html.haml index fc167698ccd..d7450a22f4c 100644 --- a/app/views/profiles/gpg_keys/_key.html.haml +++ b/app/views/profiles/gpg_keys/_key.html.haml @@ -2,7 +2,7 @@ .pull-left.append-right-10 = icon 'key', class: "settings-list-icon hidden-xs" .key-list-item-info - = key.emails.join(' ') + = key.emails_with_verified_status.map { |email, verified| verified_email_badge(email, verified) }.join(' ').html_safe .description = key.fingerprint .pull-right diff --git a/spec/features/profiles/gpg_keys_spec.rb b/spec/features/profiles/gpg_keys_spec.rb index e7939533272..552cca4a84e 100644 --- a/spec/features/profiles/gpg_keys_spec.rb +++ b/spec/features/profiles/gpg_keys_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' feature 'Profile > GPG Keys', :gpg do - let(:user) { create(:user) } + let(:user) { create(:user, email: GpgHelpers::User2.emails.first) } before do login_as(user) @@ -13,24 +13,26 @@ feature 'Profile > GPG Keys', :gpg do end scenario 'saves the new key' do - fill_in('Key', with: attributes_for(:gpg_key)[:key]) + fill_in('Key', with: GpgHelpers::User2.public_key) click_button('Add key') - expect(page).to have_content(GpgHelpers::User1.emails.join) - expect(page).to have_content(GpgHelpers::User1.fingerprint) + expect(page).to have_content('bette.cartwright@example.com Verified') + expect(page).to have_content('bette.cartwright@example.net Unverified') + expect(page).to have_content(GpgHelpers::User2.fingerprint) end end - scenario 'User sees their keys' do - create(:gpg_key, user: user) + scenario 'User sees their key' do + create(:gpg_key, user: user, key: GpgHelpers::User2.public_key) visit profile_gpg_keys_path - expect(page).to have_content(GpgHelpers::User1.emails.join) - expect(page).to have_content(GpgHelpers::User1.fingerprint) + expect(page).to have_content('bette.cartwright@example.com Verified') + expect(page).to have_content('bette.cartwright@example.net Unverified') + expect(page).to have_content(GpgHelpers::User2.fingerprint) end scenario 'User removes a key via the key index' do - create(:gpg_key, user: user) + create(:gpg_key, user: user, key: GpgHelpers::User2.public_key) visit profile_gpg_keys_path click_link('Remove') diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index e8c41299937..695a2f65c09 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -23,9 +23,20 @@ describe GpgKey do end describe 'add_to_keychain' do - it 'calls add_to_keychain after create' do - expect(Gitlab::Gpg::CurrentKeyChain).to receive(:add).with(GpgHelpers::User1.public_key) - create :gpg_key + context "user's email matches one of the key's emails" do + it 'calls .add after create' do + expect(Gitlab::Gpg::CurrentKeyChain).to receive(:add).with(GpgHelpers::User2.public_key) + user = create :user, email: GpgHelpers::User2.emails.first + create :gpg_key, user: user, key: GpgHelpers::User2.public_key + end + end + + context "user's email does not match one of the key's emails" do + it 'does not call .add after create' do + expect(Gitlab::Gpg::CurrentKeyChain).not_to receive(:add) + user = create :user + create :gpg_key, user: user, key: GpgHelpers::User2.public_key + end end end @@ -64,4 +75,32 @@ describe GpgKey do expect(gpg_key.emails).to eq GpgHelpers::User1.emails end end + + describe '#emails_with_verified_status', :gpg do + context 'key is in the keychain' do + it 'email is verified if the user has the matching email' do + user = create :user, email: 'bette.cartwright@example.com' + gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key, user: user + + expect(gpg_key.emails_with_verified_status).to match_array [ + ['bette.cartwright@example.com', true], + ['bette.cartwright@example.net', false] + ] + end + end + + context 'key is in not the keychain' do + it 'emails are unverified' do + user = create :user, email: 'bette.cartwright@example.com' + gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key, user: user + + Gitlab::Gpg::CurrentKeyChain.remove(GpgHelpers::User2.fingerprint) + + expect(gpg_key.emails_with_verified_status).to match_array [ + ['bette.cartwright@example.com', false], + ['bette.cartwright@example.net', false] + ] + end + end + end end -- cgit v1.2.1 From c1281982bd7975b45bed5b8e2c5ef5e242ea18fd Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 28 Feb 2017 10:49:59 +0100 Subject: notification email on add new gpg key --- app/mailers/emails/profile.rb | 10 ++++++++++ app/models/gpg_key.rb | 7 +++++++ app/services/notification_service.rb | 10 ++++++++++ app/views/notify/new_gpg_key_email.html.haml | 10 ++++++++++ app/views/notify/new_gpg_key_email.text.erb | 7 +++++++ spec/factories/gpg_keys.rb | 1 + spec/mailers/emails/profile_spec.rb | 30 ++++++++++++++++++++++++++++ spec/models/gpg_key_spec.rb | 14 +++++++++++++ spec/services/notification_service_spec.rb | 12 +++++++++++ 9 files changed, 101 insertions(+) create mode 100644 app/views/notify/new_gpg_key_email.html.haml create mode 100644 app/views/notify/new_gpg_key_email.text.erb diff --git a/app/mailers/emails/profile.rb b/app/mailers/emails/profile.rb index 256cbcd73a1..4580e1c83bd 100644 --- a/app/mailers/emails/profile.rb +++ b/app/mailers/emails/profile.rb @@ -22,5 +22,15 @@ module Emails @target_url = user_url(@user) mail(to: @user.notification_email, subject: subject("SSH key was added to your account")) end + + def new_gpg_key_email(gpg_key_id) + @gpg_key = GpgKey.find_by_id(gpg_key_id) + + return unless @gpg_key + + @current_user = @user = @gpg_key.user + @target_url = user_url(@user) + mail(to: @user.notification_email, subject: subject("GPG key was added to your account")) + end end end diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 04c7ce2e79f..83a303ae953 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -1,4 +1,6 @@ class GpgKey < ActiveRecord::Base + include AfterCommitQueue + KEY_PREFIX = '-----BEGIN PGP PUBLIC KEY BLOCK-----'.freeze belongs_to :user @@ -20,6 +22,7 @@ class GpgKey < ActiveRecord::Base before_validation :extract_fingerprint after_create :add_to_keychain + after_create :notify_user after_destroy :remove_from_keychain def key=(value) @@ -62,4 +65,8 @@ class GpgKey < ActiveRecord::Base def remove_from_keychain Gitlab::Gpg::CurrentKeyChain.remove(fingerprint) end + + def notify_user + run_after_commit { NotificationService.new.new_gpg_key(self) } + end end diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 3a98a5f6b64..b94921d2a08 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -17,6 +17,16 @@ class NotificationService end end + # Always notify the user about gpg key added + # + # This is a security email so it will be sent even if the user user disabled + # notifications + def new_gpg_key(gpg_key) + if gpg_key.user + mailer.new_gpg_key_email(gpg_key.id).deliver_later + end + end + # Always notify user about email added to profile def new_email(email) if email.user diff --git a/app/views/notify/new_gpg_key_email.html.haml b/app/views/notify/new_gpg_key_email.html.haml new file mode 100644 index 00000000000..4b9350c4e88 --- /dev/null +++ b/app/views/notify/new_gpg_key_email.html.haml @@ -0,0 +1,10 @@ +%p + Hi #{@user.name}! +%p + A new GPG key was added to your account: +%p + Fingerprint: + %code= @gpg_key.fingerprint +%p + If this key was added in error, you can remove it under + = link_to "GPG Keys", profile_gpg_keys_url diff --git a/app/views/notify/new_gpg_key_email.text.erb b/app/views/notify/new_gpg_key_email.text.erb new file mode 100644 index 00000000000..80b5a1fd7ff --- /dev/null +++ b/app/views/notify/new_gpg_key_email.text.erb @@ -0,0 +1,7 @@ +Hi <%= @user.name %>! + +A new GPG key was added to your account: + +Fingerprint: <%= @gpg_key.fingerprint %> + +If this key was added in error, you can remove it at <%= profile_gpg_keys_url %> diff --git a/spec/factories/gpg_keys.rb b/spec/factories/gpg_keys.rb index 70c2875b985..1258dce8940 100644 --- a/spec/factories/gpg_keys.rb +++ b/spec/factories/gpg_keys.rb @@ -3,5 +3,6 @@ require_relative '../support/gpg_helpers' FactoryGirl.define do factory :gpg_key do key GpgHelpers::User1.public_key + user end end diff --git a/spec/mailers/emails/profile_spec.rb b/spec/mailers/emails/profile_spec.rb index 8c1c9bf135f..09e5094cf84 100644 --- a/spec/mailers/emails/profile_spec.rb +++ b/spec/mailers/emails/profile_spec.rb @@ -91,6 +91,36 @@ describe Emails::Profile do end end + describe 'user added gpg key' do + let(:gpg_key) { create(:gpg_key) } + + subject { Notify.new_gpg_key_email(gpg_key.id) } + + it_behaves_like 'an email sent from GitLab' + it_behaves_like 'it should not have Gmail Actions links' + it_behaves_like 'a user cannot unsubscribe through footer link' + + it 'is sent to the new user' do + is_expected.to deliver_to gpg_key.user.email + end + + it 'has the correct subject' do + is_expected.to have_subject /^GPG key was added to your account$/i + end + + it 'contains the new gpg key title' do + is_expected.to have_body_text /#{gpg_key.fingerprint}/ + end + + it 'includes a link to gpg keys page' do + is_expected.to have_body_text /#{profile_gpg_keys_path}/ + end + + context 'with GPG key that does not exist' do + it { expect { Notify.new_gpg_key_email('foo') }.not_to raise_error } + end + end + describe 'user added email' do let(:email) { create(:email) } diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 695a2f65c09..4292892da4f 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -103,4 +103,18 @@ describe GpgKey do end end end + + describe 'notification' do + include EmailHelpers + + let(:user) { create(:user) } + + it 'sends a notification' do + perform_enqueued_jobs do + create(:gpg_key, user: user) + end + + should_email(user) + end + end end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 4fc5eb0a527..0f07a89aad9 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -93,6 +93,18 @@ describe NotificationService, services: true do end end + describe 'GpgKeys' do + describe '#new_gpg_key' do + let!(:key) { create(:gpg_key) } + + it { expect(notification.new_gpg_key(key)).to be_truthy } + + it 'sends email to key owner' do + expect{ notification.new_gpg_key(key) }.to change{ ActionMailer::Base.deliveries.size }.by(1) + end + end + end + describe 'Email' do describe '#new_email' do let!(:email) { create(:email) } -- cgit v1.2.1 From 8bd94a7304d392ad030295b5dfcd84c0100eddd1 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 28 Feb 2017 15:25:12 +0100 Subject: remove gpg from keychain when user's email changes --- app/models/gpg_key.rb | 31 ++++++++++------- app/models/user.rb | 7 ++++ lib/gitlab/gpg.rb | 4 ++- spec/features/commits_spec.rb | 16 +++++++-- spec/models/gpg_key_spec.rb | 80 ++++++++++++++++++++++++++++++------------- spec/models/user_spec.rb | 20 +++++++++++ 6 files changed, 118 insertions(+), 40 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 83a303ae953..8332ba3ee6e 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -21,9 +21,9 @@ class GpgKey < ActiveRecord::Base unless: -> { errors.has_key?(:key) } before_validation :extract_fingerprint - after_create :add_to_keychain + after_create :synchronize_keychain after_create :notify_user - after_destroy :remove_from_keychain + after_destroy :synchronize_keychain def key=(value) value.strip! unless value.blank? @@ -31,21 +31,32 @@ class GpgKey < ActiveRecord::Base end def emails - Gitlab::Gpg::CurrentKeyChain.emails(fingerprint) + @emails ||= Gitlab::Gpg.emails_from_key(key) end - def emails_with_verified_status - emails_in_key_chain = emails - emails_from_key = Gitlab::Gpg.emails_from_key(key) + def emails_in_keychain + @emails_in_keychain ||= Gitlab::Gpg::CurrentKeyChain.emails(fingerprint) + end - emails_from_key.map do |email| + def emails_with_verified_status + emails.map do |email| [ email, - email == user.email && emails_in_key_chain.include?(email) + email == user.email && emails_in_keychain.include?(email) ] end end + def synchronize_keychain + if emails.include?(user.email) + add_to_keychain + else + remove_from_keychain + end + + @emails_in_keychain = nil + end + private def extract_fingerprint @@ -55,10 +66,6 @@ class GpgKey < ActiveRecord::Base end def add_to_keychain - emails_from_key = Gitlab::Gpg.emails_from_key(key) - - return unless emails_from_key.include?(user.email) - Gitlab::Gpg::CurrentKeyChain.add(key) end diff --git a/app/models/user.rb b/app/models/user.rb index 5aebd36cf8a..42c83e3d206 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -155,6 +155,7 @@ class User < ActiveRecord::Base before_validation :set_public_email, if: :public_email_changed? after_update :update_emails_with_primary_email, if: :email_changed? + after_update :synchronize_gpg_keys, if: :email_changed? before_save :ensure_authentication_token, :ensure_incoming_email_token before_save :ensure_user_rights_and_limits, if: :external_changed? after_save :ensure_namespace_correct @@ -1157,4 +1158,10 @@ class User < ActiveRecord::Base ensure Gitlab::ExclusiveLease.cancel(lease_key, uuid) end + + def synchronize_gpg_keys + gpg_keys.each do |gpg_key| + gpg_key.synchronize_keychain + end + end end diff --git a/lib/gitlab/gpg.rb b/lib/gitlab/gpg.rb index f478f1ae5d8..ee0467ae264 100644 --- a/lib/gitlab/gpg.rb +++ b/lib/gitlab/gpg.rb @@ -10,7 +10,9 @@ module Gitlab end def remove(fingerprint) - GPGME::Key.get(fingerprint).delete! + # `#get` raises an EOFError if the keychain is empty, which is why we + # use the friendlier `#find` + GPGME::Key.find(:public, fingerprint).each(&:delete!) end def emails(fingerprint) diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index c303f29a832..79952eda2ff 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -206,7 +206,8 @@ describe 'Commits' do end describe 'GPG signed commits' do - let(:user) { create(:user) } + let!(:user) { create :user, email: GpgHelpers::User1.emails.first } + let!(:gpg_key) { create :gpg_key, key: GpgHelpers::User1.public_key, user: user } before do project.team << [user, :master] @@ -214,8 +215,6 @@ describe 'Commits' do end it 'shows the signed status', :gpg do - GPGME::Key.import(GpgHelpers::User1.public_key) - # FIXME: add this to the test repository directly remote_path = project.repository.path_to_repo Dir.mktmpdir do |dir| @@ -233,6 +232,17 @@ describe 'Commits' do expect(page).to have_content 'Unverified' expect(page).to have_content 'Verified' end + + # user changes his email which makes the gpg key unverified + user.skip_reconfirmation! + user.update_attributes!(email: 'bette.cartwright@example.org') + + visit namespace_project_commits_path(project.namespace, project, :master) + + within '#commits-list' do + expect(page).to have_content 'Unverified' + expect(page).not_to have_content 'Verified' + end end end end diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 4292892da4f..18746ad9d88 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -22,33 +22,16 @@ describe GpgKey do end end - describe 'add_to_keychain' do - context "user's email matches one of the key's emails" do - it 'calls .add after create' do - expect(Gitlab::Gpg::CurrentKeyChain).to receive(:add).with(GpgHelpers::User2.public_key) - user = create :user, email: GpgHelpers::User2.emails.first - create :gpg_key, user: user, key: GpgHelpers::User2.public_key - end + describe 'synchronize_keychain' do + it 'calls #synchronize_keychain after create' do + gpg_key = build :gpg_key + expect(gpg_key).to receive(:synchronize_keychain) + gpg_key.save! end - context "user's email does not match one of the key's emails" do - it 'does not call .add after create' do - expect(Gitlab::Gpg::CurrentKeyChain).not_to receive(:add) - user = create :user - create :gpg_key, user: user, key: GpgHelpers::User2.public_key - end - end - end - - describe 'remove_from_keychain' do - it 'calls remove_from_keychain after destroy' do - allow(Gitlab::Gpg::CurrentKeyChain).to receive :add + it 'calls #remove_from_keychain after destroy' do gpg_key = create :gpg_key - - expect( - Gitlab::Gpg::CurrentKeyChain - ).to receive(:remove).with(GpgHelpers::User1.fingerprint) - + expect(gpg_key).to receive(:synchronize_keychain) gpg_key.destroy! end end @@ -76,6 +59,15 @@ describe GpgKey do end end + describe '#emails_in_keychain', :gpg do + it 'returns the emails from the keychain' do + user = create :user, email: GpgHelpers::User1.emails.first + gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key, user: user + + expect(gpg_key.emails_in_keychain).to eq GpgHelpers::User1.emails + end + end + describe '#emails_with_verified_status', :gpg do context 'key is in the keychain' do it 'email is verified if the user has the matching email' do @@ -104,6 +96,46 @@ describe GpgKey do end end + describe '#synchronize_keychain', :gpg do + context "user's email matches one of the key's emails" do + it 'adds the key to the keychain' do + user = create :user, email: GpgHelpers::User1.emails.first + gpg_key = create :gpg_key, user: user + + expect(gpg_key).to receive(:add_to_keychain) + + gpg_key.synchronize_keychain + end + end + + context "user's email does not match one of the key's emails" do + it 'does not add the key to the keychain' do + user = create :user, email: 'stepanie@cole.us' + gpg_key = create :gpg_key, user: user + + expect(gpg_key).to receive(:remove_from_keychain) + + gpg_key.synchronize_keychain + end + end + end + + describe '#add_to_keychain', :gpg do + it 'calls .add_to_keychain' do + expect(Gitlab::Gpg::CurrentKeyChain).to receive(:add).with(GpgHelpers::User2.public_key) + gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key + gpg_key.send(:add_to_keychain) + end + end + + describe '#remove_from_keychain', :gpg do + it 'calls .remove_from_keychain' do + allow(Gitlab::Gpg::CurrentKeyChain).to receive(:remove).with(GpgHelpers::User2.fingerprint) + gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key + gpg_key.send(:remove_from_keychain) + end + end + describe 'notification' do include EmailHelpers diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 20bdb7e37da..60979fd6c06 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1956,4 +1956,24 @@ describe User, models: true do expect(user.allow_password_authentication?).to be_falsey end end + + context 'callbacks' do + context '.synchronize_gpg_keys' do + let(:user) do + create(:user, email: 'tula.torphy@abshire.ca').tap do |user| + user.skip_reconfirmation! + end + end + + it 'does nothing when the name is updated' do + expect(user).not_to receive(:synchronize_gpg_keys) + user.update_attributes!(name: 'Bette') + end + + it 'synchronizes the gpg keys when the email is updated' do + expect(user).to receive(:synchronize_gpg_keys) + user.update_attributes!(email: 'shawnee.ritchie@denesik.com') + end + end + end end -- cgit v1.2.1 From d1101ec02ec718d0ce15e76217980f6fa21c9089 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Mon, 12 Jun 2017 14:26:13 +0200 Subject: use more descriptive variable names --- app/models/commit.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/models/commit.rb b/app/models/commit.rb index 0d50a32d138..9c8edbb097d 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -237,13 +237,16 @@ class Commit def signature return @signature if defined?(@signature) - sig, signed = @raw.signature(project.repository) - if sig && signed - GPGME::Crypto.new.verify(sig, signed_text: signed) do |sign| - @signature = sign + @signature = nil + + signature, signed_text = @raw.signature(project.repository) + if signature && signed_text + GPGME::Crypto.new.verify(signature, signed_text: signed_text) do |verified_signature| + @signature = verified_signature end end - @signature ||= nil + + @signature end def revert_branch_name -- cgit v1.2.1 From 7e13d96715750f74db399bf40ee4ec9679bbe806 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Mon, 12 Jun 2017 16:16:33 +0200 Subject: don't sync to keychain file --- app/models/gpg_key.rb | 26 +------------ app/models/user.rb | 7 ---- lib/gitlab/gpg.rb | 18 --------- spec/lib/gitlab/gpg_spec.rb | 33 ---------------- spec/models/gpg_key_spec.rb | 95 ++++----------------------------------------- spec/models/user_spec.rb | 20 ---------- 6 files changed, 9 insertions(+), 190 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 8332ba3ee6e..d4570e36e06 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -21,9 +21,7 @@ class GpgKey < ActiveRecord::Base unless: -> { errors.has_key?(:key) } before_validation :extract_fingerprint - after_create :synchronize_keychain after_create :notify_user - after_destroy :synchronize_keychain def key=(value) value.strip! unless value.blank? @@ -34,29 +32,15 @@ class GpgKey < ActiveRecord::Base @emails ||= Gitlab::Gpg.emails_from_key(key) end - def emails_in_keychain - @emails_in_keychain ||= Gitlab::Gpg::CurrentKeyChain.emails(fingerprint) - end - def emails_with_verified_status emails.map do |email| [ email, - email == user.email && emails_in_keychain.include?(email) + email == user.email ] end end - def synchronize_keychain - if emails.include?(user.email) - add_to_keychain - else - remove_from_keychain - end - - @emails_in_keychain = nil - end - private def extract_fingerprint @@ -65,14 +49,6 @@ class GpgKey < ActiveRecord::Base self.fingerprint = Gitlab::Gpg.fingerprints_from_key(key).first end - def add_to_keychain - Gitlab::Gpg::CurrentKeyChain.add(key) - end - - def remove_from_keychain - Gitlab::Gpg::CurrentKeyChain.remove(fingerprint) - end - def notify_user run_after_commit { NotificationService.new.new_gpg_key(self) } end diff --git a/app/models/user.rb b/app/models/user.rb index 42c83e3d206..5aebd36cf8a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -155,7 +155,6 @@ class User < ActiveRecord::Base before_validation :set_public_email, if: :public_email_changed? after_update :update_emails_with_primary_email, if: :email_changed? - after_update :synchronize_gpg_keys, if: :email_changed? before_save :ensure_authentication_token, :ensure_incoming_email_token before_save :ensure_user_rights_and_limits, if: :external_changed? after_save :ensure_namespace_correct @@ -1158,10 +1157,4 @@ class User < ActiveRecord::Base ensure Gitlab::ExclusiveLease.cancel(lease_key, uuid) end - - def synchronize_gpg_keys - gpg_keys.each do |gpg_key| - gpg_key.synchronize_keychain - end - end end diff --git a/lib/gitlab/gpg.rb b/lib/gitlab/gpg.rb index ee0467ae264..384a9138fa1 100644 --- a/lib/gitlab/gpg.rb +++ b/lib/gitlab/gpg.rb @@ -2,24 +2,6 @@ module Gitlab module Gpg extend self - module CurrentKeyChain - extend self - - def add(key) - GPGME::Key.import(key) - end - - def remove(fingerprint) - # `#get` raises an EOFError if the keychain is empty, which is why we - # use the friendlier `#find` - GPGME::Key.find(:public, fingerprint).each(&:delete!) - end - - def emails(fingerprint) - GPGME::Key.find(:public, fingerprint).flat_map { |raw_key| raw_key.uids.map(&:email) } - end - end - def fingerprints_from_key(key) using_tmp_keychain do import = GPGME::Key.import(key) diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index c0df719c0c2..bdcf9ee0e65 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -29,36 +29,3 @@ describe Gitlab::Gpg do end end end - -describe Gitlab::Gpg::CurrentKeyChain, :gpg do - describe '.emails' do - it 'returns the emails' do - Gitlab::Gpg::CurrentKeyChain.add(GpgHelpers::User2.public_key) - - expect( - described_class.emails(GpgHelpers::User2.fingerprint) - ).to match_array GpgHelpers::User2.emails - end - end - - describe '.add', :gpg do - it 'stores the key in the keychain' do - expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).to eq [] - - Gitlab::Gpg::CurrentKeyChain.add(GpgHelpers::User1.public_key) - - expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).not_to eq [] - end - end - - describe '.remove', :gpg do - it 'removes the key from the keychain' do - Gitlab::Gpg::CurrentKeyChain.add(GpgHelpers::User1.public_key) - expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).not_to eq [] - - Gitlab::Gpg::CurrentKeyChain.remove(GpgHelpers::User1.fingerprint) - - expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).to eq [] - end - end -end diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 18746ad9d88..6ee436b6a6d 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -21,20 +21,6 @@ describe GpgKey do expect(gpg_key.fingerprint).to eq GpgHelpers::User1.fingerprint end end - - describe 'synchronize_keychain' do - it 'calls #synchronize_keychain after create' do - gpg_key = build :gpg_key - expect(gpg_key).to receive(:synchronize_keychain) - gpg_key.save! - end - - it 'calls #remove_from_keychain after destroy' do - gpg_key = create :gpg_key - expect(gpg_key).to receive(:synchronize_keychain) - gpg_key.destroy! - end - end end describe '#key=' do @@ -59,80 +45,15 @@ describe GpgKey do end end - describe '#emails_in_keychain', :gpg do - it 'returns the emails from the keychain' do - user = create :user, email: GpgHelpers::User1.emails.first - gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key, user: user - - expect(gpg_key.emails_in_keychain).to eq GpgHelpers::User1.emails - end - end - describe '#emails_with_verified_status', :gpg do - context 'key is in the keychain' do - it 'email is verified if the user has the matching email' do - user = create :user, email: 'bette.cartwright@example.com' - gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key, user: user - - expect(gpg_key.emails_with_verified_status).to match_array [ - ['bette.cartwright@example.com', true], - ['bette.cartwright@example.net', false] - ] - end - end - - context 'key is in not the keychain' do - it 'emails are unverified' do - user = create :user, email: 'bette.cartwright@example.com' - gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key, user: user - - Gitlab::Gpg::CurrentKeyChain.remove(GpgHelpers::User2.fingerprint) - - expect(gpg_key.emails_with_verified_status).to match_array [ - ['bette.cartwright@example.com', false], - ['bette.cartwright@example.net', false] - ] - end - end - end - - describe '#synchronize_keychain', :gpg do - context "user's email matches one of the key's emails" do - it 'adds the key to the keychain' do - user = create :user, email: GpgHelpers::User1.emails.first - gpg_key = create :gpg_key, user: user - - expect(gpg_key).to receive(:add_to_keychain) - - gpg_key.synchronize_keychain - end - end - - context "user's email does not match one of the key's emails" do - it 'does not add the key to the keychain' do - user = create :user, email: 'stepanie@cole.us' - gpg_key = create :gpg_key, user: user - - expect(gpg_key).to receive(:remove_from_keychain) - - gpg_key.synchronize_keychain - end - end - end - - describe '#add_to_keychain', :gpg do - it 'calls .add_to_keychain' do - expect(Gitlab::Gpg::CurrentKeyChain).to receive(:add).with(GpgHelpers::User2.public_key) - gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key - gpg_key.send(:add_to_keychain) - end - end - - describe '#remove_from_keychain', :gpg do - it 'calls .remove_from_keychain' do - allow(Gitlab::Gpg::CurrentKeyChain).to receive(:remove).with(GpgHelpers::User2.fingerprint) - gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key - gpg_key.send(:remove_from_keychain) + it 'email is verified if the user has the matching email' do + user = create :user, email: 'bette.cartwright@example.com' + gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key, user: user + + expect(gpg_key.emails_with_verified_status).to match_array [ + ['bette.cartwright@example.com', true], + ['bette.cartwright@example.net', false] + ] end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 60979fd6c06..20bdb7e37da 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1956,24 +1956,4 @@ describe User, models: true do expect(user.allow_password_authentication?).to be_falsey end end - - context 'callbacks' do - context '.synchronize_gpg_keys' do - let(:user) do - create(:user, email: 'tula.torphy@abshire.ca').tap do |user| - user.skip_reconfirmation! - end - end - - it 'does nothing when the name is updated' do - expect(user).not_to receive(:synchronize_gpg_keys) - user.update_attributes!(name: 'Bette') - end - - it 'synchronizes the gpg keys when the email is updated' do - expect(user).to receive(:synchronize_gpg_keys) - user.update_attributes!(email: 'shawnee.ritchie@denesik.com') - end - end - end end -- cgit v1.2.1 From 3c42d730986222d891c9b7985edf3942021afcef Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 13 Jun 2017 13:46:43 +0200 Subject: add primary keyid attribute to gpg keys --- app/models/gpg_key.rb | 15 ++++++++++++++- .../20170613103429_add_primary_keyid_to_gpg_keys.rb | 17 +++++++++++++++++ db/schema.rb | 2 ++ lib/gitlab/gpg.rb | 12 ++++++++++++ spec/features/commits_spec.rb | 4 ++-- spec/lib/gitlab/gpg_spec.rb | 14 ++++++++++++++ spec/models/gpg_key_spec.rb | 8 ++++++++ spec/support/gpg_helpers.rb | 8 ++++---- 8 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 db/migrate/20170613103429_add_primary_keyid_to_gpg_keys.rb diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index d4570e36e06..26f9a3975c9 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -20,7 +20,14 @@ class GpgKey < ActiveRecord::Base # the error about the fingerprint unless: -> { errors.has_key?(:key) } - before_validation :extract_fingerprint + validates :primary_keyid, + presence: true, + uniqueness: true, + # only validate when the `key` is valid, as we don't want the user to show + # the error about the fingerprint + unless: -> { errors.has_key?(:key) } + + before_validation :extract_fingerprint, :extract_primary_keyid after_create :notify_user def key=(value) @@ -49,6 +56,12 @@ class GpgKey < ActiveRecord::Base self.fingerprint = Gitlab::Gpg.fingerprints_from_key(key).first end + def extract_primary_keyid + # we can assume that the result only contains one item as the validation + # only allows one key + self.primary_keyid = Gitlab::Gpg.primary_keyids_from_key(key).first + end + def notify_user run_after_commit { NotificationService.new.new_gpg_key(self) } end diff --git a/db/migrate/20170613103429_add_primary_keyid_to_gpg_keys.rb b/db/migrate/20170613103429_add_primary_keyid_to_gpg_keys.rb new file mode 100644 index 00000000000..13f0500971b --- /dev/null +++ b/db/migrate/20170613103429_add_primary_keyid_to_gpg_keys.rb @@ -0,0 +1,17 @@ +class AddPrimaryKeyidToGpgKeys < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_column :gpg_keys, :primary_keyid, :string + add_concurrent_index :gpg_keys, :primary_keyid + end + + def down + remove_concurrent_index :gpg_keys, :primary_keyid if index_exists?(:gpg_keys, :primary_keyid) + remove_column :gpg_keys, :primary_keyid, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 54f98559243..fbf20f4eb66 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -546,8 +546,10 @@ ActiveRecord::Schema.define(version: 20170725145659) do t.integer "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.string "primary_keyid" end + add_index "gpg_keys", ["primary_keyid"], name: "index_gpg_keys_on_primary_keyid", using: :btree add_index "gpg_keys", ["user_id"], name: "index_gpg_keys_on_user_id", using: :btree create_table "identities", force: :cascade do |t| diff --git a/lib/gitlab/gpg.rb b/lib/gitlab/gpg.rb index 384a9138fa1..486e040adb6 100644 --- a/lib/gitlab/gpg.rb +++ b/lib/gitlab/gpg.rb @@ -12,6 +12,18 @@ module Gitlab end end + def primary_keyids_from_key(key) + using_tmp_keychain do + import = GPGME::Key.import(key) + + return [] if import.imported == 0 + + fingerprints = import.imports.map(&:fingerprint) + + GPGME::Key.find(:public, fingerprints).map { |raw_key| raw_key.primary_subkey.keyid } + end + end + def emails_from_key(key) using_tmp_keychain do import = GPGME::Key.import(key) diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 79952eda2ff..1dbcf09d4a0 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -220,8 +220,8 @@ describe 'Commits' do Dir.mktmpdir do |dir| FileUtils.cd dir do `git clone --quiet #{remote_path} .` - `git commit --quiet -S#{GpgHelpers::User1.key_id} --allow-empty -m "signed commit, verified key/email"` - `git commit --quiet -S#{GpgHelpers::User2.key_id} --allow-empty -m "signed commit, unverified key/email"` + `git commit --quiet -S#{GpgHelpers::User1.primary_keyid} --allow-empty -m "signed commit, verified key/email"` + `git commit --quiet -S#{GpgHelpers::User2.primary_keyid} --allow-empty -m "signed commit, unverified key/email"` `git push --quiet` end end diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index bdcf9ee0e65..55f34e0cf99 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -15,6 +15,20 @@ describe Gitlab::Gpg do end end + describe '.primary_keyids_from_key' do + it 'returns the keyid' do + expect( + described_class.primary_keyids_from_key(GpgHelpers::User1.public_key) + ).to eq [GpgHelpers::User1.primary_keyid] + end + + it 'returns an empty array when the key is invalid' do + expect( + described_class.primary_keyids_from_key('bogus') + ).to eq [] + end + end + describe '.emails_from_key' do it 'returns the emails' do expect( diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 6ee436b6a6d..ac446fca819 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -21,6 +21,14 @@ describe GpgKey do expect(gpg_key.fingerprint).to eq GpgHelpers::User1.fingerprint end end + + describe 'extract_primary_keyid' do + it 'extracts the primary keyid from the gpg key' do + gpg_key = described_class.new(key: GpgHelpers::User1.public_key) + gpg_key.valid? + expect(gpg_key.primary_keyid).to eq GpgHelpers::User1.primary_keyid + end + end end describe '#key=' do diff --git a/spec/support/gpg_helpers.rb b/spec/support/gpg_helpers.rb index 52c478e1976..f9128a629f2 100644 --- a/spec/support/gpg_helpers.rb +++ b/spec/support/gpg_helpers.rb @@ -90,8 +90,8 @@ module GpgHelpers KEY end - def key_id - '00AC8B1D' + def primary_keyid + fingerprint[-16..-1] end def fingerprint @@ -179,8 +179,8 @@ module GpgHelpers KEY end - def key_id - '911EFD65' + def primary_keyid + fingerprint[-16..-1] end def fingerprint -- cgit v1.2.1 From 2f956fae0399f6f2eb370ed186c7bb4a9486178b Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 13 Jun 2017 14:26:42 +0200 Subject: verify gpg commit using tmp keyring and db query --- app/models/commit.rb | 17 ++++++++++++++++- lib/gitlab/gpg.rb | 8 ++++++++ spec/lib/gitlab/gpg_spec.rb | 17 +++++++++++++++++ spec/models/commit_spec.rb | 4 ++-- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/app/models/commit.rb b/app/models/commit.rb index 9c8edbb097d..a6a11a2d3a5 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -240,7 +240,22 @@ class Commit @signature = nil signature, signed_text = @raw.signature(project.repository) - if signature && signed_text + + return unless signature && signed_text + + Gitlab::Gpg.using_tmp_keychain do + # first we need to get the keyid from the signature... + GPGME::Crypto.new.verify(signature, signed_text: signed_text) do |verified_signature| + @signature = verified_signature + end + + # ... then we query the gpg key belonging to the keyid. + gpg_key = GpgKey.find_by(primary_keyid: @signature.fingerprint) + + return @signature unless gpg_key + + Gitlab::Gpg::CurrentKeyChain.add(gpg_key.key) + GPGME::Crypto.new.verify(signature, signed_text: signed_text) do |verified_signature| @signature = verified_signature end diff --git a/lib/gitlab/gpg.rb b/lib/gitlab/gpg.rb index 486e040adb6..258901bb238 100644 --- a/lib/gitlab/gpg.rb +++ b/lib/gitlab/gpg.rb @@ -2,6 +2,14 @@ module Gitlab module Gpg extend self + module CurrentKeyChain + extend self + + def add(key) + GPGME::Key.import(key) + end + end + def fingerprints_from_key(key) using_tmp_keychain do import = GPGME::Key.import(key) diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index 55f34e0cf99..edf7405d7f1 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -43,3 +43,20 @@ describe Gitlab::Gpg do end end end + +describe Gitlab::Gpg::CurrentKeyChain, :gpg do + describe '.add', :gpg do + it 'stores the key in the keychain' do + expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).to eq [] + + described_class.add(GpgHelpers::User1.public_key) + + keys = GPGME::Key.find(:public, GpgHelpers::User1.fingerprint) + expect(keys.count).to eq 1 + expect(keys.first).to have_attributes( + email: GpgHelpers::User1.emails.first, + fingerprint: GpgHelpers::User1.fingerprint + ) + end + end +end diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 3c6ce49b48d..96af675c3f4 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -422,7 +422,7 @@ eos context 'signed commit', :gpg do it 'returns a valid signature if the public key is known' do - GPGME::Key.import(GpgHelpers::User1.public_key) + create :gpg_key, key: GpgHelpers::User1.public_key raw_commit = double(:raw_commit, signature: [ GpgHelpers::User1.signed_commit_signature, @@ -438,7 +438,7 @@ eos expect(commit.signature.valid?).to be_truthy end - it 'returns an invalid signature if the public commit is unknown', :gpg do + it 'returns an invalid signature if the public key is unknown', :gpg do raw_commit = double(:raw_commit, signature: [ GpgHelpers::User1.signed_commit_signature, GpgHelpers::User1.signed_commit_base_data -- cgit v1.2.1 From 8236b12dff3df6d223888664c820ae54b4e0eaf7 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 14 Jun 2017 09:17:34 +0200 Subject: gpg signature model for gpg verification caching --- app/models/gpg_signature.rb | 7 ++++++ db/migrate/20170613154149_create_gpg_signatures.rb | 29 ++++++++++++++++++++++ db/schema.rb | 17 +++++++++++++ spec/models/gpg_signature_spec.rb | 14 +++++++++++ 4 files changed, 67 insertions(+) create mode 100644 app/models/gpg_signature.rb create mode 100644 db/migrate/20170613154149_create_gpg_signatures.rb create mode 100644 spec/models/gpg_signature_spec.rb diff --git a/app/models/gpg_signature.rb b/app/models/gpg_signature.rb new file mode 100644 index 00000000000..03294354d91 --- /dev/null +++ b/app/models/gpg_signature.rb @@ -0,0 +1,7 @@ +class GpgSignature < ActiveRecord::Base + belongs_to :project + belongs_to :gpg_key + + validates :commit_sha, presence: true + validates :project, presence: true +end diff --git a/db/migrate/20170613154149_create_gpg_signatures.rb b/db/migrate/20170613154149_create_gpg_signatures.rb new file mode 100644 index 00000000000..72560cdb6d0 --- /dev/null +++ b/db/migrate/20170613154149_create_gpg_signatures.rb @@ -0,0 +1,29 @@ +class CreateGpgSignatures < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + create_table :gpg_signatures do |t| + t.string :commit_sha + t.references :project, index: true, foreign_key: true + t.references :gpg_key, index: true, foreign_key: true + t.string :gpg_key_primary_keyid + t.boolean :valid_signature + + t.timestamps_with_timezone null: false + end + + add_concurrent_index :gpg_signatures, :commit_sha + add_concurrent_index :gpg_signatures, :gpg_key_primary_keyid + end + + def down + remove_concurrent_index :gpg_signatures, :commit_sha if index_exists?(:gpg_signatures, :commit_sha) + remove_concurrent_index :gpg_signatures, :gpg_key_primary_keyid if index_exists?(:gpg_signatures, :gpg_key_primary_keyid) + + drop_table :gpg_signatures + end +end diff --git a/db/schema.rb b/db/schema.rb index fbf20f4eb66..53b1e83ddab 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -552,6 +552,21 @@ ActiveRecord::Schema.define(version: 20170725145659) do add_index "gpg_keys", ["primary_keyid"], name: "index_gpg_keys_on_primary_keyid", using: :btree add_index "gpg_keys", ["user_id"], name: "index_gpg_keys_on_user_id", using: :btree + create_table "gpg_signatures", force: :cascade do |t| + t.string "commit_sha" + t.integer "project_id" + t.integer "gpg_key_id" + t.string "gpg_key_primary_keyid" + t.boolean "valid_signature" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_index "gpg_signatures", ["commit_sha"], name: "index_gpg_signatures_on_commit_sha", using: :btree + add_index "gpg_signatures", ["gpg_key_id"], name: "index_gpg_signatures_on_gpg_key_id", using: :btree + add_index "gpg_signatures", ["gpg_key_primary_keyid"], name: "index_gpg_signatures_on_gpg_key_primary_keyid", using: :btree + add_index "gpg_signatures", ["project_id"], name: "index_gpg_signatures_on_project_id", using: :btree + create_table "identities", force: :cascade do |t| t.string "extern_uid" t.string "provider" @@ -1615,6 +1630,8 @@ ActiveRecord::Schema.define(version: 20170725145659) do add_foreign_key "events", "projects", name: "fk_0434b48643", on_delete: :cascade add_foreign_key "forked_project_links", "projects", column: "forked_to_project_id", name: "fk_434510edb0", on_delete: :cascade add_foreign_key "gpg_keys", "users" + add_foreign_key "gpg_signatures", "gpg_keys" + add_foreign_key "gpg_signatures", "projects" add_foreign_key "issue_assignees", "issues", name: "fk_b7d881734a", on_delete: :cascade add_foreign_key "issue_assignees", "users", name: "fk_5e0c8d9154", on_delete: :cascade add_foreign_key "issue_metrics", "issues", on_delete: :cascade diff --git a/spec/models/gpg_signature_spec.rb b/spec/models/gpg_signature_spec.rb new file mode 100644 index 00000000000..d2720c41694 --- /dev/null +++ b/spec/models/gpg_signature_spec.rb @@ -0,0 +1,14 @@ +require 'rails_helper' + +RSpec.describe GpgSignature do + describe 'associations' do + it { is_expected.to belong_to(:project) } + it { is_expected.to belong_to(:gpg_key) } + end + + describe 'validation' do + subject { described_class.new } + it { is_expected.to validate_presence_of(:commit_sha) } + it { is_expected.to validate_presence_of(:project) } + end +end -- cgit v1.2.1 From 69e511c4c2a0409fa69658cf95bf5c4072b2b2d0 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 14 Jun 2017 11:51:34 +0200 Subject: cache the gpg commit signature we store the result of the gpg commit verification in the db because the gpg verification is an expensive operation. --- app/models/commit.rb | 25 ++------ app/views/projects/commit/_signature.html.haml | 6 +- lib/gitlab/gpg/commit.rb | 51 +++++++++++++++ spec/lib/gitlab/gpg/commit_spec.rb | 53 ++++++++++++++++ spec/models/commit_spec.rb | 88 +++++++++++++++++++------- 5 files changed, 177 insertions(+), 46 deletions(-) create mode 100644 lib/gitlab/gpg/commit.rb create mode 100644 spec/lib/gitlab/gpg/commit_spec.rb diff --git a/app/models/commit.rb b/app/models/commit.rb index a6a11a2d3a5..6c5556902ec 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -239,29 +239,14 @@ class Commit @signature = nil - signature, signed_text = @raw.signature(project.repository) + cached_signature = GpgSignature.find_by(commit_sha: sha) + return cached_signature if cached_signature.present? - return unless signature && signed_text + gpg_commit = Gitlab::Gpg::Commit.new(self) - Gitlab::Gpg.using_tmp_keychain do - # first we need to get the keyid from the signature... - GPGME::Crypto.new.verify(signature, signed_text: signed_text) do |verified_signature| - @signature = verified_signature - end - - # ... then we query the gpg key belonging to the keyid. - gpg_key = GpgKey.find_by(primary_keyid: @signature.fingerprint) - - return @signature unless gpg_key - - Gitlab::Gpg::CurrentKeyChain.add(gpg_key.key) - - GPGME::Crypto.new.verify(signature, signed_text: signed_text) do |verified_signature| - @signature = verified_signature - end - end + return unless gpg_commit.has_signature? - @signature + @signature = gpg_commit.signature end def revert_branch_name diff --git a/app/views/projects/commit/_signature.html.haml b/app/views/projects/commit/_signature.html.haml index 7335b6b9597..48665ede6eb 100644 --- a/app/views/projects/commit/_signature.html.haml +++ b/app/views/projects/commit/_signature.html.haml @@ -1,4 +1,4 @@ - if signature - %a.btn.disabled.btn-xs{ class: ('btn-success' if signature.valid?) } - %i.fa.fa-key{ class: ('fa-inverse' if signature.valid?) } - = signature.valid? ? 'Verified': 'Unverified' + %a.btn.disabled.btn-xs{ class: ('btn-success' if signature.valid_signature?) } + %i.fa.fa-key{ class: ('fa-inverse' if signature.valid_signature?) } + = signature.valid_signature? ? 'Verified' : 'Unverified' diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb new file mode 100644 index 00000000000..f60e5125c13 --- /dev/null +++ b/lib/gitlab/gpg/commit.rb @@ -0,0 +1,51 @@ +module Gitlab + module Gpg + class Commit + attr_reader :commit + + def initialize(commit) + @commit = commit + + @signature_text, @signed_text = commit.raw.signature(commit.project.repository) + end + + def has_signature? + @signature_text && @signed_text + end + + def signature + Gitlab::Gpg.using_tmp_keychain do + # first we need to get the keyid from the signature to query the gpg + # key belonging to the keyid. + # This way we can add the key to the temporary keychain and extract + # the proper signature. + gpg_key = GpgKey.find_by(primary_keyid: verified_signature.fingerprint) + + if gpg_key + Gitlab::Gpg::CurrentKeyChain.add(gpg_key.key) + end + + create_cached_signature!(gpg_key) + end + end + + private + + def verified_signature + GPGME::Crypto.new.verify(@signature_text, signed_text: @signed_text) do |verified_signature| + return verified_signature + end + end + + def create_cached_signature!(gpg_key) + GpgSignature.create!( + commit_sha: commit.sha, + project: commit.project, + gpg_key: gpg_key, + gpg_key_primary_keyid: gpg_key&.primary_keyid, + valid_signature: !!(gpg_key && verified_signature&.valid?) + ) + end + end + end +end diff --git a/spec/lib/gitlab/gpg/commit_spec.rb b/spec/lib/gitlab/gpg/commit_spec.rb new file mode 100644 index 00000000000..8b1747eebcc --- /dev/null +++ b/spec/lib/gitlab/gpg/commit_spec.rb @@ -0,0 +1,53 @@ +require 'rails_helper' + +RSpec.describe Gitlab::Gpg::Commit do + describe '#signature' do + let!(:project) { create :project, :repository, path: 'sample-project' } + + context 'known public key' do + it 'returns a valid signature' do + gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key + + raw_commit = double(:raw_commit, signature: [ + GpgHelpers::User1.signed_commit_signature, + GpgHelpers::User1.signed_commit_base_data + ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') + allow(raw_commit).to receive :save! + + commit = create :commit, + git_commit: raw_commit, + project: project + + expect(described_class.new(commit).signature).to have_attributes( + commit_sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', + project: project, + gpg_key: gpg_key, + gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + valid_signature: true + ) + end + end + + context 'unknown public key' do + it 'returns an invalid signature', :gpg do + raw_commit = double(:raw_commit, signature: [ + GpgHelpers::User1.signed_commit_signature, + GpgHelpers::User1.signed_commit_base_data + ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') + allow(raw_commit).to receive :save! + + commit = create :commit, + git_commit: raw_commit, + project: project + + expect(described_class.new(commit).signature).to have_attributes( + commit_sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', + project: project, + gpg_key: nil, + gpg_key_primary_keyid: nil, + valid_signature: false + ) + end + end + end +end diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 96af675c3f4..4370c78e6fd 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -421,36 +421,78 @@ eos end context 'signed commit', :gpg do - it 'returns a valid signature if the public key is known' do - create :gpg_key, key: GpgHelpers::User1.public_key + context 'known public key' do + it 'returns a valid signature' do + create :gpg_key, key: GpgHelpers::User1.public_key - raw_commit = double(:raw_commit, signature: [ - GpgHelpers::User1.signed_commit_signature, - GpgHelpers::User1.signed_commit_base_data - ]) - allow(raw_commit).to receive :save! + raw_commit = double(:raw_commit, signature: [ + GpgHelpers::User1.signed_commit_signature, + GpgHelpers::User1.signed_commit_base_data + ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') + allow(raw_commit).to receive :save! - commit = create :commit, - git_commit: raw_commit, - project: project + commit = create :commit, + git_commit: raw_commit, + project: project - expect(commit.signature).to be_a GPGME::Signature - expect(commit.signature.valid?).to be_truthy + expect(commit.signature.valid_signature?).to be_truthy + end + + it 'returns the cached validation result on second call', :gpg do + create :gpg_key, key: GpgHelpers::User1.public_key + + raw_commit = double(:raw_commit, signature: [ + GpgHelpers::User1.signed_commit_signature, + GpgHelpers::User1.signed_commit_base_data + ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') + allow(raw_commit).to receive :save! + + commit = create :commit, + git_commit: raw_commit, + project: project + + expect(Gitlab::Gpg::Commit).to receive(:new).and_call_original + expect(commit.signature.valid_signature?).to be_truthy + + # second call returns the cache + expect(Gitlab::Gpg::Commit).not_to receive(:new).and_call_original + expect(commit.signature.valid_signature?).to be_truthy + end end - it 'returns an invalid signature if the public key is unknown', :gpg do - raw_commit = double(:raw_commit, signature: [ - GpgHelpers::User1.signed_commit_signature, - GpgHelpers::User1.signed_commit_base_data - ]) - allow(raw_commit).to receive :save! + context 'unknown public key' do + it 'returns an invalid signature if the public key is unknown', :gpg do + raw_commit = double(:raw_commit, signature: [ + GpgHelpers::User1.signed_commit_signature, + GpgHelpers::User1.signed_commit_base_data + ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') + allow(raw_commit).to receive :save! - commit = create :commit, - git_commit: raw_commit, - project: project + commit = create :commit, + git_commit: raw_commit, + project: project - expect(commit.signature).to be_a GPGME::Signature - expect(commit.signature.valid?).to be_falsey + expect(commit.signature.valid_signature?).to be_falsey + end + + it 'returns the cached validation result on second call', :gpg do + raw_commit = double(:raw_commit, signature: [ + GpgHelpers::User1.signed_commit_signature, + GpgHelpers::User1.signed_commit_base_data + ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') + allow(raw_commit).to receive :save! + + commit = create :commit, + git_commit: raw_commit, + project: project + + expect(Gitlab::Gpg::Commit).to receive(:new).and_call_original + expect(commit.signature.valid_signature?).to be_falsey + + # second call returns the cache + expect(Gitlab::Gpg::Commit).not_to receive(:new).and_call_original + expect(commit.signature.valid_signature?).to be_falsey + end end end end -- cgit v1.2.1 From 8c4b6a32fcc5786383904fa1d5cf8b317bec7a7f Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 15 Jun 2017 09:16:50 +0200 Subject: bail if the commit has no signature --- app/models/commit.rb | 6 +----- lib/gitlab/gpg/commit.rb | 6 ++++-- spec/lib/gitlab/gpg/commit_spec.rb | 6 ++++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/models/commit.rb b/app/models/commit.rb index 6c5556902ec..ed8b9a79a7a 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -242,11 +242,7 @@ class Commit cached_signature = GpgSignature.find_by(commit_sha: sha) return cached_signature if cached_signature.present? - gpg_commit = Gitlab::Gpg::Commit.new(self) - - return unless gpg_commit.has_signature? - - @signature = gpg_commit.signature + @signature = Gitlab::Gpg::Commit.new(self).signature end def revert_branch_name diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb index f60e5125c13..f363652745f 100644 --- a/lib/gitlab/gpg/commit.rb +++ b/lib/gitlab/gpg/commit.rb @@ -10,10 +10,12 @@ module Gitlab end def has_signature? - @signature_text && @signed_text + !!(@signature_text && @signed_text) end def signature + return unless has_signature? + Gitlab::Gpg.using_tmp_keychain do # first we need to get the keyid from the signature to query the gpg # key belonging to the keyid. @@ -43,7 +45,7 @@ module Gitlab project: commit.project, gpg_key: gpg_key, gpg_key_primary_keyid: gpg_key&.primary_keyid, - valid_signature: !!(gpg_key && verified_signature&.valid?) + valid_signature: !!(gpg_key && verified_signature.valid?) ) end end diff --git a/spec/lib/gitlab/gpg/commit_spec.rb b/spec/lib/gitlab/gpg/commit_spec.rb index 8b1747eebcc..c4d92b8bbbf 100644 --- a/spec/lib/gitlab/gpg/commit_spec.rb +++ b/spec/lib/gitlab/gpg/commit_spec.rb @@ -4,6 +4,12 @@ RSpec.describe Gitlab::Gpg::Commit do describe '#signature' do let!(:project) { create :project, :repository, path: 'sample-project' } + context 'unisgned commit' do + it 'returns nil' do + expect(described_class.new(project.commit).signature).to be_nil + end + end + context 'known public key' do it 'returns a valid signature' do gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key -- cgit v1.2.1 From 7b616d39efaa7cba933d17dfae010d393c18d057 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 15 Jun 2017 09:57:50 +0200 Subject: gpg signature is only valid when key is verified --- app/models/gpg_key.rb | 4 ++++ lib/gitlab/gpg/commit.rb | 2 +- spec/lib/gitlab/gpg/commit_spec.rb | 28 ++++++++++++++++++++++++++-- spec/models/gpg_key_spec.rb | 16 ++++++++++++++++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 26f9a3975c9..137abb60ddc 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -48,6 +48,10 @@ class GpgKey < ActiveRecord::Base end end + def verified? + emails_with_verified_status.any? { |_email, verified| verified } + end + private def extract_fingerprint diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb index f363652745f..d65a20f08f9 100644 --- a/lib/gitlab/gpg/commit.rb +++ b/lib/gitlab/gpg/commit.rb @@ -45,7 +45,7 @@ module Gitlab project: commit.project, gpg_key: gpg_key, gpg_key_primary_keyid: gpg_key&.primary_keyid, - valid_signature: !!(gpg_key && verified_signature.valid?) + valid_signature: !!(gpg_key && gpg_key.verified? && verified_signature.valid?) ) end end diff --git a/spec/lib/gitlab/gpg/commit_spec.rb b/spec/lib/gitlab/gpg/commit_spec.rb index c4d92b8bbbf..2a583dc1bd5 100644 --- a/spec/lib/gitlab/gpg/commit_spec.rb +++ b/spec/lib/gitlab/gpg/commit_spec.rb @@ -10,9 +10,9 @@ RSpec.describe Gitlab::Gpg::Commit do end end - context 'known public key' do + context 'known and verified public key' do it 'returns a valid signature' do - gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key + gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key, user: create(:user, email: GpgHelpers::User1.emails.first) raw_commit = double(:raw_commit, signature: [ GpgHelpers::User1.signed_commit_signature, @@ -34,6 +34,30 @@ RSpec.describe Gitlab::Gpg::Commit do end end + context 'known but unverified public key' do + it 'returns an invalid signature' do + gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key + + raw_commit = double(:raw_commit, signature: [ + GpgHelpers::User1.signed_commit_signature, + GpgHelpers::User1.signed_commit_base_data + ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') + allow(raw_commit).to receive :save! + + commit = create :commit, + git_commit: raw_commit, + project: project + + expect(described_class.new(commit).signature).to have_attributes( + commit_sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', + project: project, + gpg_key: gpg_key, + gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + valid_signature: false + ) + end + end + context 'unknown public key' do it 'returns an invalid signature', :gpg do raw_commit = double(:raw_commit, signature: [ diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index ac446fca819..3cb1723cc12 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -65,6 +65,22 @@ describe GpgKey do end end + describe '#verified?' do + it 'returns true one of the email addresses in the key belongs to the user' do + user = create :user, email: 'bette.cartwright@example.com' + gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key, user: user + + expect(gpg_key.verified?).to be_truthy + end + + it 'returns false if one of the email addresses in the key does not belong to the user' do + user = create :user, email: 'someone.else@example.com' + gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key, user: user + + expect(gpg_key.verified?).to be_falsey + end + end + describe 'notification' do include EmailHelpers -- cgit v1.2.1 From 34810acd6c3d4dd27f43f6f07e47b4e06bb95f82 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 15 Jun 2017 10:28:28 +0200 Subject: move signature cache read to Gpg::Commit as we write the cache in the gpg commit class already the read should also happen there. This also removes all logic from the main commit class, which just proxies the call to the Gpg::Commit now. --- app/models/commit.rb | 5 --- lib/gitlab/gpg/commit.rb | 3 ++ spec/lib/gitlab/gpg/commit_spec.rb | 61 ++++++++++++++++++++++------ spec/models/commit_spec.rb | 82 -------------------------------------- 4 files changed, 52 insertions(+), 99 deletions(-) diff --git a/app/models/commit.rb b/app/models/commit.rb index ed8b9a79a7a..35593d53cbc 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -237,11 +237,6 @@ class Commit def signature return @signature if defined?(@signature) - @signature = nil - - cached_signature = GpgSignature.find_by(commit_sha: sha) - return cached_signature if cached_signature.present? - @signature = Gitlab::Gpg::Commit.new(self).signature end diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb index d65a20f08f9..2b61caaebb5 100644 --- a/lib/gitlab/gpg/commit.rb +++ b/lib/gitlab/gpg/commit.rb @@ -16,6 +16,9 @@ module Gitlab def signature return unless has_signature? + cached_signature = GpgSignature.find_by(commit_sha: commit.sha) + return cached_signature if cached_signature.present? + Gitlab::Gpg.using_tmp_keychain do # first we need to get the keyid from the signature to query the gpg # key belonging to the keyid. diff --git a/spec/lib/gitlab/gpg/commit_spec.rb b/spec/lib/gitlab/gpg/commit_spec.rb index 2a583dc1bd5..539e6d4641f 100644 --- a/spec/lib/gitlab/gpg/commit_spec.rb +++ b/spec/lib/gitlab/gpg/commit_spec.rb @@ -11,19 +11,21 @@ RSpec.describe Gitlab::Gpg::Commit do end context 'known and verified public key' do - it 'returns a valid signature' do - gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key, user: create(:user, email: GpgHelpers::User1.emails.first) + let!(:gpg_key) do + create :gpg_key, key: GpgHelpers::User1.public_key, user: create(:user, email: GpgHelpers::User1.emails.first) + end + let!(:commit) do raw_commit = double(:raw_commit, signature: [ GpgHelpers::User1.signed_commit_signature, GpgHelpers::User1.signed_commit_base_data ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') allow(raw_commit).to receive :save! - commit = create :commit, - git_commit: raw_commit, - project: project + create :commit, git_commit: raw_commit, project: project + end + it 'returns a valid signature' do expect(described_class.new(commit).signature).to have_attributes( commit_sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', project: project, @@ -32,22 +34,33 @@ RSpec.describe Gitlab::Gpg::Commit do valid_signature: true ) end + + it 'returns the cached signature on second call' do + gpg_commit = described_class.new(commit) + + expect(gpg_commit).to receive(:verified_signature).twice.and_call_original + gpg_commit.signature + + # consecutive call + expect(gpg_commit).not_to receive(:verified_signature).and_call_original + gpg_commit.signature + end end context 'known but unverified public key' do - it 'returns an invalid signature' do - gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key + let!(:gpg_key) { create :gpg_key, key: GpgHelpers::User1.public_key } + let!(:commit) do raw_commit = double(:raw_commit, signature: [ GpgHelpers::User1.signed_commit_signature, GpgHelpers::User1.signed_commit_base_data ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') allow(raw_commit).to receive :save! - commit = create :commit, - git_commit: raw_commit, - project: project + create :commit, git_commit: raw_commit, project: project + end + it 'returns an invalid signature' do expect(described_class.new(commit).signature).to have_attributes( commit_sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', project: project, @@ -56,20 +69,33 @@ RSpec.describe Gitlab::Gpg::Commit do valid_signature: false ) end + + it 'returns the cached signature on second call' do + gpg_commit = described_class.new(commit) + + expect(gpg_commit).to receive(:verified_signature).and_call_original + gpg_commit.signature + + # consecutive call + expect(gpg_commit).not_to receive(:verified_signature).and_call_original + gpg_commit.signature + end end context 'unknown public key' do - it 'returns an invalid signature', :gpg do + let!(:commit) do raw_commit = double(:raw_commit, signature: [ GpgHelpers::User1.signed_commit_signature, GpgHelpers::User1.signed_commit_base_data ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') allow(raw_commit).to receive :save! - commit = create :commit, + create :commit, git_commit: raw_commit, project: project + end + it 'returns an invalid signature' do expect(described_class.new(commit).signature).to have_attributes( commit_sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', project: project, @@ -78,6 +104,17 @@ RSpec.describe Gitlab::Gpg::Commit do valid_signature: false ) end + + it 'returns the cached signature on second call' do + gpg_commit = described_class.new(commit) + + expect(gpg_commit).to receive(:verified_signature).and_call_original + gpg_commit.signature + + # consecutive call + expect(gpg_commit).not_to receive(:verified_signature).and_call_original + gpg_commit.signature + end end end end diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 4370c78e6fd..528b211c9d6 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -414,86 +414,4 @@ eos expect(described_class.valid_hash?('a' * 41)).to be false end end - - describe '#signature' do - it 'returns nil if the commit is not signed' do - expect(commit.signature).to be_nil - end - - context 'signed commit', :gpg do - context 'known public key' do - it 'returns a valid signature' do - create :gpg_key, key: GpgHelpers::User1.public_key - - raw_commit = double(:raw_commit, signature: [ - GpgHelpers::User1.signed_commit_signature, - GpgHelpers::User1.signed_commit_base_data - ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') - allow(raw_commit).to receive :save! - - commit = create :commit, - git_commit: raw_commit, - project: project - - expect(commit.signature.valid_signature?).to be_truthy - end - - it 'returns the cached validation result on second call', :gpg do - create :gpg_key, key: GpgHelpers::User1.public_key - - raw_commit = double(:raw_commit, signature: [ - GpgHelpers::User1.signed_commit_signature, - GpgHelpers::User1.signed_commit_base_data - ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') - allow(raw_commit).to receive :save! - - commit = create :commit, - git_commit: raw_commit, - project: project - - expect(Gitlab::Gpg::Commit).to receive(:new).and_call_original - expect(commit.signature.valid_signature?).to be_truthy - - # second call returns the cache - expect(Gitlab::Gpg::Commit).not_to receive(:new).and_call_original - expect(commit.signature.valid_signature?).to be_truthy - end - end - - context 'unknown public key' do - it 'returns an invalid signature if the public key is unknown', :gpg do - raw_commit = double(:raw_commit, signature: [ - GpgHelpers::User1.signed_commit_signature, - GpgHelpers::User1.signed_commit_base_data - ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') - allow(raw_commit).to receive :save! - - commit = create :commit, - git_commit: raw_commit, - project: project - - expect(commit.signature.valid_signature?).to be_falsey - end - - it 'returns the cached validation result on second call', :gpg do - raw_commit = double(:raw_commit, signature: [ - GpgHelpers::User1.signed_commit_signature, - GpgHelpers::User1.signed_commit_base_data - ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') - allow(raw_commit).to receive :save! - - commit = create :commit, - git_commit: raw_commit, - project: project - - expect(Gitlab::Gpg::Commit).to receive(:new).and_call_original - expect(commit.signature.valid_signature?).to be_falsey - - # second call returns the cache - expect(Gitlab::Gpg::Commit).not_to receive(:new).and_call_original - expect(commit.signature.valid_signature?).to be_falsey - end - end - end - end end -- cgit v1.2.1 From 5d5fd4babe4cb75c7f8f9f18cc86c63a0fa58d16 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 15 Jun 2017 12:43:04 +0200 Subject: store gpg_key_primary_keyid for unknown gpg keys we need to store the keyid to be able to update the signature later in case the missing key is added later. --- app/models/gpg_signature.rb | 1 + lib/gitlab/gpg/commit.rb | 6 ++++-- spec/lib/gitlab/gpg/commit_spec.rb | 2 +- spec/models/gpg_signature_spec.rb | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/models/gpg_signature.rb b/app/models/gpg_signature.rb index 03294354d91..4fe9c3210ff 100644 --- a/app/models/gpg_signature.rb +++ b/app/models/gpg_signature.rb @@ -4,4 +4,5 @@ class GpgSignature < ActiveRecord::Base validates :commit_sha, presence: true validates :project, presence: true + validates :gpg_key_primary_keyid, presence: true end diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb index 2b61caaebb5..8d2e6269618 100644 --- a/lib/gitlab/gpg/commit.rb +++ b/lib/gitlab/gpg/commit.rb @@ -43,12 +43,14 @@ module Gitlab end def create_cached_signature!(gpg_key) + verified_signature_result = verified_signature + GpgSignature.create!( commit_sha: commit.sha, project: commit.project, gpg_key: gpg_key, - gpg_key_primary_keyid: gpg_key&.primary_keyid, - valid_signature: !!(gpg_key && gpg_key.verified? && verified_signature.valid?) + gpg_key_primary_keyid: gpg_key&.primary_keyid || verified_signature_result.fingerprint, + valid_signature: !!(gpg_key && gpg_key.verified? && verified_signature_result.valid?) ) end end diff --git a/spec/lib/gitlab/gpg/commit_spec.rb b/spec/lib/gitlab/gpg/commit_spec.rb index 539e6d4641f..448b16a656e 100644 --- a/spec/lib/gitlab/gpg/commit_spec.rb +++ b/spec/lib/gitlab/gpg/commit_spec.rb @@ -100,7 +100,7 @@ RSpec.describe Gitlab::Gpg::Commit do commit_sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', project: project, gpg_key: nil, - gpg_key_primary_keyid: nil, + gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, valid_signature: false ) end diff --git a/spec/models/gpg_signature_spec.rb b/spec/models/gpg_signature_spec.rb index d2720c41694..b3f84262874 100644 --- a/spec/models/gpg_signature_spec.rb +++ b/spec/models/gpg_signature_spec.rb @@ -10,5 +10,6 @@ RSpec.describe GpgSignature do subject { described_class.new } it { is_expected.to validate_presence_of(:commit_sha) } it { is_expected.to validate_presence_of(:project) } + it { is_expected.to validate_presence_of(:gpg_key_primary_keyid) } end end -- cgit v1.2.1 From 502e31bec9af080bcb483b0d57c8b52aeb507f93 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 15 Jun 2017 13:37:03 +0200 Subject: memoize verified_signature call --- lib/gitlab/gpg/commit.rb | 25 +++++++++++++++++-------- spec/lib/gitlab/gpg/commit_spec.rb | 12 ++++++------ 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb index 8d2e6269618..8bc430db715 100644 --- a/lib/gitlab/gpg/commit.rb +++ b/lib/gitlab/gpg/commit.rb @@ -19,6 +19,19 @@ module Gitlab cached_signature = GpgSignature.find_by(commit_sha: commit.sha) return cached_signature if cached_signature.present? + using_keychain do |gpg_key| + if gpg_key + Gitlab::Gpg::CurrentKeyChain.add(gpg_key.key) + @verified_signature = nil + end + + create_cached_signature!(gpg_key) + end + end + + private + + def using_keychain Gitlab::Gpg.using_tmp_keychain do # first we need to get the keyid from the signature to query the gpg # key belonging to the keyid. @@ -30,27 +43,23 @@ module Gitlab Gitlab::Gpg::CurrentKeyChain.add(gpg_key.key) end - create_cached_signature!(gpg_key) + yield gpg_key end end - private - def verified_signature - GPGME::Crypto.new.verify(@signature_text, signed_text: @signed_text) do |verified_signature| + @verified_signature ||= GPGME::Crypto.new.verify(@signature_text, signed_text: @signed_text) do |verified_signature| return verified_signature end end def create_cached_signature!(gpg_key) - verified_signature_result = verified_signature - GpgSignature.create!( commit_sha: commit.sha, project: commit.project, gpg_key: gpg_key, - gpg_key_primary_keyid: gpg_key&.primary_keyid || verified_signature_result.fingerprint, - valid_signature: !!(gpg_key && gpg_key.verified? && verified_signature_result.valid?) + gpg_key_primary_keyid: gpg_key&.primary_keyid || verified_signature.fingerprint, + valid_signature: !!(gpg_key && gpg_key.verified? && verified_signature.valid?) ) end end diff --git a/spec/lib/gitlab/gpg/commit_spec.rb b/spec/lib/gitlab/gpg/commit_spec.rb index 448b16a656e..387ce8f74b4 100644 --- a/spec/lib/gitlab/gpg/commit_spec.rb +++ b/spec/lib/gitlab/gpg/commit_spec.rb @@ -38,11 +38,11 @@ RSpec.describe Gitlab::Gpg::Commit do it 'returns the cached signature on second call' do gpg_commit = described_class.new(commit) - expect(gpg_commit).to receive(:verified_signature).twice.and_call_original + expect(gpg_commit).to receive(:using_keychain).and_call_original gpg_commit.signature # consecutive call - expect(gpg_commit).not_to receive(:verified_signature).and_call_original + expect(gpg_commit).not_to receive(:using_keychain).and_call_original gpg_commit.signature end end @@ -73,11 +73,11 @@ RSpec.describe Gitlab::Gpg::Commit do it 'returns the cached signature on second call' do gpg_commit = described_class.new(commit) - expect(gpg_commit).to receive(:verified_signature).and_call_original + expect(gpg_commit).to receive(:using_keychain).and_call_original gpg_commit.signature # consecutive call - expect(gpg_commit).not_to receive(:verified_signature).and_call_original + expect(gpg_commit).not_to receive(:using_keychain).and_call_original gpg_commit.signature end end @@ -108,11 +108,11 @@ RSpec.describe Gitlab::Gpg::Commit do it 'returns the cached signature on second call' do gpg_commit = described_class.new(commit) - expect(gpg_commit).to receive(:verified_signature).and_call_original + expect(gpg_commit).to receive(:using_keychain).and_call_original gpg_commit.signature # consecutive call - expect(gpg_commit).not_to receive(:verified_signature).and_call_original + expect(gpg_commit).not_to receive(:using_keychain).and_call_original gpg_commit.signature end end -- cgit v1.2.1 From d48eb77a96d29260c214391c5b8979ee17250452 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 15 Jun 2017 14:18:00 +0200 Subject: allow updating of gpg signature through gpg commit --- lib/gitlab/gpg/commit.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb index 8bc430db715..6e3f7c28eba 100644 --- a/lib/gitlab/gpg/commit.rb +++ b/lib/gitlab/gpg/commit.rb @@ -29,6 +29,14 @@ module Gitlab end end + def update_signature!(cached_signature) + using_keychain do |gpg_key| + cached_signature.update_attributes!( + valid_signature: self.class.gpg_signature_valid_signature_value(gpg_key, verified_signature) + ) + end + end + private def using_keychain @@ -59,9 +67,13 @@ module Gitlab project: commit.project, gpg_key: gpg_key, gpg_key_primary_keyid: gpg_key&.primary_keyid || verified_signature.fingerprint, - valid_signature: !!(gpg_key && gpg_key.verified? && verified_signature.valid?) + valid_signature: self.class.gpg_signature_valid_signature_value(gpg_key, verified_signature) ) end + + def self.gpg_signature_valid_signature_value(gpg_key, verified_signature_) + !!(gpg_key && gpg_key.verified? && verified_signature_.valid?) + end end end end -- cgit v1.2.1 From 24671cd601e93133787ff9746fcacc3cf5d3fbf4 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 15 Jun 2017 14:22:37 +0200 Subject: update invalid gpg signatures when key is created --- app/models/gpg_key.rb | 5 +++ lib/gitlab/gpg/invalid_gpg_signature_updater.rb | 19 ++++++++ spec/factories/gpg_signature.rb | 11 +++++ .../gpg/invalid_gpg_signature_updater_spec.rb | 50 ++++++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 lib/gitlab/gpg/invalid_gpg_signature_updater.rb create mode 100644 spec/factories/gpg_signature.rb create mode 100644 spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 137abb60ddc..6ca108d6b87 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -28,6 +28,7 @@ class GpgKey < ActiveRecord::Base unless: -> { errors.has_key?(:key) } before_validation :extract_fingerprint, :extract_primary_keyid + after_create :update_invalid_gpg_signatures after_create :notify_user def key=(value) @@ -66,6 +67,10 @@ class GpgKey < ActiveRecord::Base self.primary_keyid = Gitlab::Gpg.primary_keyids_from_key(key).first end + def update_invalid_gpg_signatures + run_after_commit { Gitlab::Gpg::InvalidGpgSignatureUpdater.new(self).run } + end + def notify_user run_after_commit { NotificationService.new.new_gpg_key(self) } end diff --git a/lib/gitlab/gpg/invalid_gpg_signature_updater.rb b/lib/gitlab/gpg/invalid_gpg_signature_updater.rb new file mode 100644 index 00000000000..6511a8f8285 --- /dev/null +++ b/lib/gitlab/gpg/invalid_gpg_signature_updater.rb @@ -0,0 +1,19 @@ +module Gitlab + module Gpg + class InvalidGpgSignatureUpdater + def initialize(gpg_key) + @gpg_key = gpg_key + end + + def run + GpgSignature + .where(valid_signature: false) + .where(gpg_key_primary_keyid: @gpg_key.primary_keyid) + .find_each do |gpg_signature| + commit = Gitlab::Git::Commit.find(gpg_signature.project.repository, gpg_signature.commit_sha) + Gitlab::Gpg::Commit.new(commit).update_signature!(gpg_signature) + end + end + end + end +end diff --git a/spec/factories/gpg_signature.rb b/spec/factories/gpg_signature.rb new file mode 100644 index 00000000000..a5aeffbe12d --- /dev/null +++ b/spec/factories/gpg_signature.rb @@ -0,0 +1,11 @@ +require_relative '../support/gpg_helpers' + +FactoryGirl.define do + factory :gpg_signature do + commit_sha { Digest::SHA1.hexdigest(SecureRandom.hex) } + project + gpg_key + gpg_key_primary_keyid { gpg_key.primary_keyid } + valid_signature true + end +end diff --git a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb new file mode 100644 index 00000000000..48f8fa285aa --- /dev/null +++ b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb @@ -0,0 +1,50 @@ +require 'rails_helper' + +RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do + describe '#run' do + context 'gpg signature did not have an associated gpg key' do + let!(:commit_sha) { '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' } + let!(:project) { create :project, :repository, path: 'sample-project' } + let!(:commit) do + raw_commit = double(:raw_commit, signature: [ + GpgHelpers::User1.signed_commit_signature, + GpgHelpers::User1.signed_commit_base_data + ], sha: commit_sha) + allow(raw_commit).to receive :save! + + create :commit, git_commit: raw_commit, project: project + end + + let!(:gpg_signature) do + create :gpg_signature, + project: project, + commit_sha: commit_sha, + gpg_key: nil, + gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + valid_signature: false + end + + before do + allow(Gitlab::Git::Commit).to receive(:find).with(kind_of(Repository), commit_sha).and_return(commit) + end + + it 'updates the signature to being valid when the missing gpg key is added' do + # InvalidGpgSignatureUpdater is called by the after_create hook + create :gpg_key, + key: GpgHelpers::User1.public_key, + user: create(:user, email: GpgHelpers::User1.emails.first) + + expect(gpg_signature.reload.valid_signature).to be_truthy + end + + it 'keeps the signature at being invalid when an unrelated gpg key is added' do + # InvalidGpgSignatureUpdater is called by the after_create hook + create :gpg_key, + key: GpgHelpers::User2.public_key, + user: create(:user, email: GpgHelpers::User2.emails.first) + + expect(gpg_signature.reload.valid_signature).to be_falsey + end + end + end +end -- cgit v1.2.1 From e75ab064302bcec45a5953a636cc9f3295f2690c Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 15 Jun 2017 15:07:44 +0200 Subject: update invalid gpg signatures when email changes --- app/models/gpg_key.rb | 8 +- app/models/user.rb | 5 ++ .../gpg/invalid_gpg_signature_updater_spec.rb | 86 +++++++++++++++------- spec/models/user_spec.rb | 20 +++++ 4 files changed, 90 insertions(+), 29 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 6ca108d6b87..ec30658e7ea 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -53,6 +53,10 @@ class GpgKey < ActiveRecord::Base emails_with_verified_status.any? { |_email, verified| verified } end + def update_invalid_gpg_signatures + Gitlab::Gpg::InvalidGpgSignatureUpdater.new(self).run + end + private def extract_fingerprint @@ -67,10 +71,6 @@ class GpgKey < ActiveRecord::Base self.primary_keyid = Gitlab::Gpg.primary_keyids_from_key(key).first end - def update_invalid_gpg_signatures - run_after_commit { Gitlab::Gpg::InvalidGpgSignatureUpdater.new(self).run } - end - def notify_user run_after_commit { NotificationService.new.new_gpg_key(self) } end diff --git a/app/models/user.rb b/app/models/user.rb index 5aebd36cf8a..791d099605d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -155,6 +155,7 @@ class User < ActiveRecord::Base before_validation :set_public_email, if: :public_email_changed? after_update :update_emails_with_primary_email, if: :email_changed? + after_update :update_invalid_gpg_signatures, if: :email_changed? before_save :ensure_authentication_token, :ensure_incoming_email_token before_save :ensure_user_rights_and_limits, if: :external_changed? after_save :ensure_namespace_correct @@ -513,6 +514,10 @@ class User < ActiveRecord::Base end end + def update_invalid_gpg_signatures + gpg_keys.each(&:update_invalid_gpg_signatures) + end + # Returns the groups a user has access to def authorized_groups union = Gitlab::SQL::Union diff --git a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb index 48f8fa285aa..42348b3f2c1 100644 --- a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb +++ b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb @@ -2,37 +2,39 @@ require 'rails_helper' RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do describe '#run' do - context 'gpg signature did not have an associated gpg key' do - let!(:commit_sha) { '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' } - let!(:project) { create :project, :repository, path: 'sample-project' } - let!(:commit) do - raw_commit = double(:raw_commit, signature: [ - GpgHelpers::User1.signed_commit_signature, - GpgHelpers::User1.signed_commit_base_data - ], sha: commit_sha) - allow(raw_commit).to receive :save! - - create :commit, git_commit: raw_commit, project: project - end + let!(:commit_sha) { '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' } + let!(:project) { create :project, :repository, path: 'sample-project' } + let!(:commit) do + raw_commit = double(:raw_commit, signature: [ + GpgHelpers::User1.signed_commit_signature, + GpgHelpers::User1.signed_commit_base_data + ], sha: commit_sha) + allow(raw_commit).to receive :save! - let!(:gpg_signature) do - create :gpg_signature, - project: project, - commit_sha: commit_sha, - gpg_key: nil, - gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, - valid_signature: false - end + create :commit, git_commit: raw_commit, project: project + end - before do - allow(Gitlab::Git::Commit).to receive(:find).with(kind_of(Repository), commit_sha).and_return(commit) - end + let!(:gpg_signature) do + create :gpg_signature, + project: project, + commit_sha: commit_sha, + gpg_key: nil, + gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + valid_signature: false + end + + before do + allow(Gitlab::Git::Commit).to receive(:find).with(kind_of(Repository), commit_sha).and_return(commit) + end + + context 'gpg signature did not have an associated gpg key' do + let!(:user) { create :user, email: GpgHelpers::User1.emails.first } it 'updates the signature to being valid when the missing gpg key is added' do # InvalidGpgSignatureUpdater is called by the after_create hook create :gpg_key, key: GpgHelpers::User1.public_key, - user: create(:user, email: GpgHelpers::User1.emails.first) + user: user expect(gpg_signature.reload.valid_signature).to be_truthy end @@ -41,7 +43,41 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do # InvalidGpgSignatureUpdater is called by the after_create hook create :gpg_key, key: GpgHelpers::User2.public_key, - user: create(:user, email: GpgHelpers::User2.emails.first) + user: user + + expect(gpg_signature.reload.valid_signature).to be_falsey + end + end + + context 'gpg signature did have an associated unverified gpg key' do + let!(:user) do + create(:user, email: 'unrelated@example.com').tap do |user| + user.skip_reconfirmation! + end + end + + it 'updates the signature to being valid when the user updates the email address' do + create :gpg_key, + key: GpgHelpers::User1.public_key, + user: user + + expect(gpg_signature.reload.valid_signature).to be_falsey + + # InvalidGpgSignatureUpdater is called by the after_update hook + user.update_attributes!(email: GpgHelpers::User1.emails.first) + + expect(gpg_signature.reload.valid_signature).to be_truthy + end + + it 'keeps the signature at being invalid when the changed email address is still unrelated' do + create :gpg_key, + key: GpgHelpers::User1.public_key, + user: user + + expect(gpg_signature.reload.valid_signature).to be_falsey + + # InvalidGpgSignatureUpdater is called by the after_update hook + user.update_attributes!(email: 'still.unrelated@example.com') expect(gpg_signature.reload.valid_signature).to be_falsey end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 20bdb7e37da..14b0440af9c 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -350,6 +350,26 @@ describe User, models: true do end end + describe 'after update hook' do + describe '.update_invalid_gpg_signatures' do + let(:user) do + create(:user, email: 'tula.torphy@abshire.ca').tap do |user| + user.skip_reconfirmation! + end + end + + it 'does nothing when the name is updated' do + expect(user).not_to receive(:update_invalid_gpg_signatures) + user.update_attributes!(name: 'Bette') + end + + it 'synchronizes the gpg keys when the email is updated' do + expect(user).to receive(:update_invalid_gpg_signatures) + user.update_attributes!(email: 'shawnee.ritchie@denesik.com') + end + end + end + describe '#update_tracked_fields!', :clean_gitlab_redis_shared_state do let(:request) { OpenStruct.new(remote_ip: "127.0.0.1") } let(:user) { create(:user) } -- cgit v1.2.1 From d7f42643681ad1cc634a502ef25acab6b111c6e5 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Fri, 16 Jun 2017 14:37:28 +0200 Subject: no need for passing parameter we introduced memoizing, so it's safe to call the method multiple times. --- lib/gitlab/gpg/commit.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb index 6e3f7c28eba..437f13ef311 100644 --- a/lib/gitlab/gpg/commit.rb +++ b/lib/gitlab/gpg/commit.rb @@ -32,7 +32,7 @@ module Gitlab def update_signature!(cached_signature) using_keychain do |gpg_key| cached_signature.update_attributes!( - valid_signature: self.class.gpg_signature_valid_signature_value(gpg_key, verified_signature) + valid_signature: gpg_signature_valid_signature_value(gpg_key) ) end end @@ -67,12 +67,12 @@ module Gitlab project: commit.project, gpg_key: gpg_key, gpg_key_primary_keyid: gpg_key&.primary_keyid || verified_signature.fingerprint, - valid_signature: self.class.gpg_signature_valid_signature_value(gpg_key, verified_signature) + valid_signature: gpg_signature_valid_signature_value(gpg_key) ) end - def self.gpg_signature_valid_signature_value(gpg_key, verified_signature_) - !!(gpg_key && gpg_key.verified? && verified_signature_.valid?) + def gpg_signature_valid_signature_value(gpg_key) + !!(gpg_key && gpg_key.verified? && verified_signature.valid?) end end end -- cgit v1.2.1 From 028ecb081b7ed71d5123ded535d5b7f87db7cc67 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Fri, 16 Jun 2017 14:43:01 +0200 Subject: need to wrap the raw commit in a commit model --- lib/gitlab/gpg/invalid_gpg_signature_updater.rb | 3 ++- spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/gitlab/gpg/invalid_gpg_signature_updater.rb b/lib/gitlab/gpg/invalid_gpg_signature_updater.rb index 6511a8f8285..06e4823de32 100644 --- a/lib/gitlab/gpg/invalid_gpg_signature_updater.rb +++ b/lib/gitlab/gpg/invalid_gpg_signature_updater.rb @@ -10,7 +10,8 @@ module Gitlab .where(valid_signature: false) .where(gpg_key_primary_keyid: @gpg_key.primary_keyid) .find_each do |gpg_signature| - commit = Gitlab::Git::Commit.find(gpg_signature.project.repository, gpg_signature.commit_sha) + raw_commit = Gitlab::Git::Commit.find(gpg_signature.project.repository, gpg_signature.commit_sha) + commit = ::Commit.new(raw_commit, gpg_signature.project) Gitlab::Gpg::Commit.new(commit).update_signature!(gpg_signature) end end diff --git a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb index 42348b3f2c1..8b60b36452b 100644 --- a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb +++ b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb @@ -4,13 +4,18 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do describe '#run' do let!(:commit_sha) { '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' } let!(:project) { create :project, :repository, path: 'sample-project' } - let!(:commit) do + let!(:raw_commit) do raw_commit = double(:raw_commit, signature: [ GpgHelpers::User1.signed_commit_signature, GpgHelpers::User1.signed_commit_base_data ], sha: commit_sha) + allow(raw_commit).to receive :save! + raw_commit + end + + let!(:commit) do create :commit, git_commit: raw_commit, project: project end @@ -24,7 +29,7 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do end before do - allow(Gitlab::Git::Commit).to receive(:find).with(kind_of(Repository), commit_sha).and_return(commit) + allow(Gitlab::Git::Commit).to receive(:find).with(kind_of(Repository), commit_sha).and_return(raw_commit) end context 'gpg signature did not have an associated gpg key' do -- cgit v1.2.1 From a01eabc19f0d5b73f6216edc10d19a7765c73b53 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 21 Jun 2017 21:54:16 +0200 Subject: update rugged the rugged versions up to 0.26.0b3 had a bug concerning the signature extraction. The extracted signature was not always the same, probably due to a buffer (overflow) issue in libgit. see https://github.com/libgit2/rugged/issues/608 --- Gemfile | 2 +- Gemfile.lock | 4 ++-- lib/gitlab/git/commit.rb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 93934d03e42..d41d75b250a 100644 --- a/Gemfile +++ b/Gemfile @@ -15,7 +15,7 @@ gem 'default_value_for', '~> 3.0.0' gem 'mysql2', '~> 0.4.5', group: :mysql gem 'pg', '~> 0.18.2', group: :postgres -gem 'rugged', '~> 0.25.1.1' +gem 'rugged', '~> 0.26.0' gem 'grape-route-helpers', '~> 2.0.0' gem 'faraday', '~> 0.12' diff --git a/Gemfile.lock b/Gemfile.lock index 77e87e2885f..2483b0bf35c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -751,7 +751,7 @@ GEM rubyzip (1.2.1) rufus-scheduler (3.4.0) et-orbi (~> 1.0) - rugged (0.25.1.1) + rugged (0.26.0) safe_yaml (1.0.4) sanitize (2.1.0) nokogiri (>= 1.4.4) @@ -1084,7 +1084,7 @@ DEPENDENCIES ruby-prof (~> 0.16.2) ruby_parser (~> 3.8) rufus-scheduler (~> 3.4) - rugged (~> 0.25.1.1) + rugged (~> 0.26.0) sanitize (~> 2.0) sass-rails (~> 5.0.6) scss_lint (~> 0.54.0) diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index 4dcaff5e0a0..ca7e3a7c4be 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -336,7 +336,7 @@ module Gitlab begin raw_commit.to_mbox(options) rescue Rugged::InvalidError => ex - if ex.message =~ /Commit \w+ is a merge commit/ + if ex.message =~ /commit \w+ is a merge commit/i 'Patch format is not currently supported for merge commits.' end end -- cgit v1.2.1 From 9d30a80d24a583aad267a8a11f685058eab2c864 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 22 Jun 2017 08:47:11 +0200 Subject: update features specs for gpg commits --- spec/features/commits_spec.rb | 51 ++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 1dbcf09d4a0..8f89b465160 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -206,36 +206,51 @@ describe 'Commits' do end describe 'GPG signed commits' do - let!(:user) { create :user, email: GpgHelpers::User1.emails.first } - let!(:gpg_key) { create :gpg_key, key: GpgHelpers::User1.public_key, user: user } - before do - project.team << [user, :master] - login_with(user) - end - - it 'shows the signed status', :gpg do # FIXME: add this to the test repository directly remote_path = project.repository.path_to_repo Dir.mktmpdir do |dir| FileUtils.cd dir do `git clone --quiet #{remote_path} .` - `git commit --quiet -S#{GpgHelpers::User1.primary_keyid} --allow-empty -m "signed commit, verified key/email"` - `git commit --quiet -S#{GpgHelpers::User2.primary_keyid} --allow-empty -m "signed commit, unverified key/email"` + `git commit --quiet -S#{GpgHelpers::User1.primary_keyid} --allow-empty -m "signed commit by nannie bernhard"` + `git commit --quiet -S#{GpgHelpers::User2.primary_keyid} --allow-empty -m "signed commit by bette cartwright"` `git push --quiet` end end + end + + it 'changes from unverified to verified when the user changes his email to match the gpg key' do + user = create :user, email: 'unrelated.user@example.org' + project.team << [user, :master] + + create :gpg_key, key: GpgHelpers::User1.public_key, user: user + + login_with(user) visit namespace_project_commits_path(project.namespace, project, :master) within '#commits-list' do expect(page).to have_content 'Unverified' - expect(page).to have_content 'Verified' + expect(page).not_to have_content 'Verified' end - # user changes his email which makes the gpg key unverified + # user changes his email which makes the gpg key verified user.skip_reconfirmation! - user.update_attributes!(email: 'bette.cartwright@example.org') + user.update_attributes!(email: GpgHelpers::User1.emails.first) + + visit namespace_project_commits_path(project.namespace, project, :master) + + within '#commits-list' do + expect(page).to have_content 'Unverified' + expect(page).to have_content 'Verified' + end + end + + it 'changes from unverified to verified when the user adds the missing gpg key' do + user = create :user, email: GpgHelpers::User1.emails.first + project.team << [user, :master] + + login_with(user) visit namespace_project_commits_path(project.namespace, project, :master) @@ -243,6 +258,16 @@ describe 'Commits' do expect(page).to have_content 'Unverified' expect(page).not_to have_content 'Verified' end + + # user adds the gpg key which makes the signature valid + create :gpg_key, key: GpgHelpers::User1.public_key, user: user + + visit namespace_project_commits_path(project.namespace, project, :master) + + within '#commits-list' do + expect(page).to have_content 'Unverified' + expect(page).to have_content 'Verified' + end end end end -- cgit v1.2.1 From 9816856d055b33de9c47d9e3b73c4acb99c5b5e6 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 22 Jun 2017 14:18:01 +0200 Subject: perform signature update in sidekiq worker --- app/models/gpg_key.rb | 8 +++-- app/models/user.rb | 3 +- app/workers/invalid_gpg_signature_update_worker.rb | 12 ++++++++ config/sidekiq_queues.yml | 1 + spec/features/commits_spec.rb | 14 ++++++--- .../invalid_gpg_signature_update_worker_spec.rb | 36 ++++++++++++++++++++++ 6 files changed, 67 insertions(+), 7 deletions(-) create mode 100644 app/workers/invalid_gpg_signature_update_worker.rb create mode 100644 spec/workers/invalid_gpg_signature_update_worker_spec.rb diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index ec30658e7ea..a444792581a 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -28,7 +28,7 @@ class GpgKey < ActiveRecord::Base unless: -> { errors.has_key?(:key) } before_validation :extract_fingerprint, :extract_primary_keyid - after_create :update_invalid_gpg_signatures + after_create :update_invalid_gpg_signatures_after_create after_create :notify_user def key=(value) @@ -54,7 +54,7 @@ class GpgKey < ActiveRecord::Base end def update_invalid_gpg_signatures - Gitlab::Gpg::InvalidGpgSignatureUpdater.new(self).run + InvalidGpgSignatureUpdateWorker.perform_async(self.id) end private @@ -74,4 +74,8 @@ class GpgKey < ActiveRecord::Base def notify_user run_after_commit { NotificationService.new.new_gpg_key(self) } end + + def update_invalid_gpg_signatures_after_create + run_after_commit { update_invalid_gpg_signatures } + end end diff --git a/app/models/user.rb b/app/models/user.rb index 791d099605d..931b760df34 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -13,6 +13,7 @@ class User < ActiveRecord::Base include IgnorableColumn include FeatureGate include CreatedAtFilterable + include AfterCommitQueue DEFAULT_NOTIFICATION_LEVEL = :participating @@ -515,7 +516,7 @@ class User < ActiveRecord::Base end def update_invalid_gpg_signatures - gpg_keys.each(&:update_invalid_gpg_signatures) + run_after_commit { gpg_keys.each(&:update_invalid_gpg_signatures) } end # Returns the groups a user has access to diff --git a/app/workers/invalid_gpg_signature_update_worker.rb b/app/workers/invalid_gpg_signature_update_worker.rb new file mode 100644 index 00000000000..277dd604aa8 --- /dev/null +++ b/app/workers/invalid_gpg_signature_update_worker.rb @@ -0,0 +1,12 @@ +class InvalidGpgSignatureUpdateWorker + include Sidekiq::Worker + include DedicatedSidekiqQueue + + def perform(gpg_key_id) + if gpg_key = GpgKey.find_by(id: gpg_key_id) + Gitlab::Gpg::InvalidGpgSignatureUpdater.new(gpg_key).run + else + Rails.logger.error("InvalidGpgSignatureUpdateWorker: couldn't find gpg_key with ID=#{gpg_key_id}, skipping job") + end + end +end diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml index 1d9e69a2408..cf0f5719683 100644 --- a/config/sidekiq_queues.yml +++ b/config/sidekiq_queues.yml @@ -29,6 +29,7 @@ - [email_receiver, 2] - [emails_on_push, 2] - [mailers, 2] + - [invalid_gpg_signature_update, 2] - [upload_checksum, 1] - [use_key, 1] - [repository_fork, 1] diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 8f89b465160..7635e87e838 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -223,7 +223,9 @@ describe 'Commits' do user = create :user, email: 'unrelated.user@example.org' project.team << [user, :master] - create :gpg_key, key: GpgHelpers::User1.public_key, user: user + Sidekiq::Testing.inline! do + create :gpg_key, key: GpgHelpers::User1.public_key, user: user + end login_with(user) @@ -235,8 +237,10 @@ describe 'Commits' do end # user changes his email which makes the gpg key verified - user.skip_reconfirmation! - user.update_attributes!(email: GpgHelpers::User1.emails.first) + Sidekiq::Testing.inline! do + user.skip_reconfirmation! + user.update_attributes!(email: GpgHelpers::User1.emails.first) + end visit namespace_project_commits_path(project.namespace, project, :master) @@ -260,7 +264,9 @@ describe 'Commits' do end # user adds the gpg key which makes the signature valid - create :gpg_key, key: GpgHelpers::User1.public_key, user: user + Sidekiq::Testing.inline! do + create :gpg_key, key: GpgHelpers::User1.public_key, user: user + end visit namespace_project_commits_path(project.namespace, project, :master) diff --git a/spec/workers/invalid_gpg_signature_update_worker_spec.rb b/spec/workers/invalid_gpg_signature_update_worker_spec.rb new file mode 100644 index 00000000000..8d568076e1a --- /dev/null +++ b/spec/workers/invalid_gpg_signature_update_worker_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe InvalidGpgSignatureUpdateWorker do + context 'when GpgKey is found' do + it 'calls NotificationService.new.run' do + gpg_key = create(:gpg_key) + invalid_signature_updater = double(:invalid_signature_updater) + + expect(Gitlab::Gpg::InvalidGpgSignatureUpdater).to receive(:new).with(gpg_key).and_return(invalid_signature_updater) + expect(invalid_signature_updater).to receive(:run) + + described_class.new.perform(gpg_key.id) + end + end + + context 'when GpgKey is not found' do + let(:nonexisting_gpg_key_id) { -1 } + + it 'logs InvalidGpgSignatureUpdateWorker process skipping' do + expect(Rails.logger).to receive(:error) + .with("InvalidGpgSignatureUpdateWorker: couldn't find gpg_key with ID=-1, skipping job") + + described_class.new.perform(nonexisting_gpg_key_id) + end + + it 'does not raise errors' do + expect { described_class.new.perform(nonexisting_gpg_key_id) }.not_to raise_error + end + + it 'does not call NotificationService.new.run' do + expect(Gitlab::Gpg::InvalidGpgSignatureUpdater).not_to receive(:new) + + described_class.new.perform(nonexisting_gpg_key_id) + end + end +end -- cgit v1.2.1 From 2ea951454a535ba16693c083c122218b8608329b Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 22 Jun 2017 17:21:03 +0200 Subject: allow removal of gpg key by nullifying signatures --- app/models/gpg_key.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index a444792581a..bd5d833d68c 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -4,6 +4,7 @@ class GpgKey < ActiveRecord::Base KEY_PREFIX = '-----BEGIN PGP PUBLIC KEY BLOCK-----'.freeze belongs_to :user + has_many :gpg_signatures, dependent: :nullify validates :key, presence: true, -- cgit v1.2.1 From 78b5264511a76e481110236e9c14764d9c1b953a Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Fri, 23 Jun 2017 22:52:43 +0200 Subject: add gpg commit popover badges --- app/assets/javascripts/commons/bootstrap.js | 1 + app/assets/javascripts/main.js | 6 ++ app/assets/stylesheets/pages/commits.scss | 43 ++++++++++++++ app/helpers/commits_helper.rb | 78 ++++++++++++++++++++++++++ app/views/projects/commit/_signature.html.haml | 4 +- spec/features/commits_spec.rb | 25 +++++++++ 6 files changed, 154 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/commons/bootstrap.js b/app/assets/javascripts/commons/bootstrap.js index 36bfe457be9..510bedbf641 100644 --- a/app/assets/javascripts/commons/bootstrap.js +++ b/app/assets/javascripts/commons/bootstrap.js @@ -8,6 +8,7 @@ import 'bootstrap-sass/assets/javascripts/bootstrap/modal'; import 'bootstrap-sass/assets/javascripts/bootstrap/tab'; import 'bootstrap-sass/assets/javascripts/bootstrap/transition'; import 'bootstrap-sass/assets/javascripts/bootstrap/tooltip'; +import 'bootstrap-sass/assets/javascripts/bootstrap/popover'; // custom jQuery functions $.fn.extend({ diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index e96d51de838..ecf7a677c99 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -159,6 +159,8 @@ document.addEventListener('beforeunload', function () { $(document).off('scroll'); // Close any open tooltips $('.has-tooltip, [data-toggle="tooltip"]').tooltip('destroy'); + // Close any open popover + $('[data-toggle="popover"]').popover('destroy'); }); window.addEventListener('hashchange', gl.utils.handleLocationHash); @@ -247,6 +249,10 @@ $(function () { return $(el).data('placement') || 'bottom'; } }); + // Initialize popovers + $body.popover({ + selector: '[data-toggle="popover"]' + }); $('.trigger-submit').on('change', function () { return $(this).parents('form').submit(); // Form submitter diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index fd0871ec0b8..54f6156ad8f 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -283,3 +283,46 @@ color: $gl-text-color; } } + +.gpg-badge { + &.valid { + color: $brand-success; + } + + &.invalid { + color: $gray; + } +} + +.gpg-badge-popover-title { + font-weight: normal; +} + +.gpg-badge-popover-icon { + float: left; + font-size: 35px; + line-height: 35px; + width: 32px; + margin-right: $btn-side-margin; + + &.valid { + color: $brand-success; + } + + &.invalid { + color: $gray; + } +} + +.gpg-badge-popover-avatar { + float: left; + margin-bottom: $gl-padding; + + .avatar { + margin-left: 0; + } +} + +.gpg-badge-popover-username { + font-weight: bold; +} diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index d08e346d605..34ba5694288 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -212,4 +212,82 @@ module CommitsHelper [commits, 0] end end + + def commit_gpg_signature_badge(signature) + if signature.valid_signature? + commit_gpg_valid_signature_badge(signature) + else + commit_gpg_invalid_signature_badge(signature) + end + end + + def commit_gpg_valid_signature_badge(signature) + title = capture do + concat content_tag('i', '', class: 'fa fa-check-circle gpg-badge-popover-icon valid', 'aria-hidden' => 'true') + concat 'This commit was signed with a verified signature.' + end + + content = capture do + concat( + content_tag(:div, class: 'gpg-badge-popover-avatar') do + user_avatar(user: signature.gpg_key.user, size: 32) + end + ) + + concat( + content_tag(:div, class: 'gpg-badge-popover-username') do + signature.gpg_key.user.username + end + ) + + concat( + content_tag(:div) do + signature.gpg_key.user.name + end + ) + end + + commit_gpg_signature_badge_with(signature, label: 'Verified', title: title, content: content, css_classes: ['valid']) + end + + def commit_gpg_invalid_signature_badge(signature) + title = capture do + concat content_tag('i', '', class: 'fa fa-question-circle gpg-badge-popover-icon invalid', 'aria-hidden' => 'true') + concat 'This commit was signed with an unverified signature.' + end + commit_gpg_signature_badge_with(signature, label: 'Unverified', title: title, css_classes: ['invalid']) + end + + def commit_gpg_signature_badge_with(signature, label:, title: '', content: '', css_classes: []) + css_classes = %w(btn btn-xs gpg-badge) + css_classes + + content = capture do + concat( + content_tag(:div, class: 'clearfix') do + content + end + ) + + concat "GPG key ID: #{signature.gpg_key_primary_keyid}" + end + + title = capture do + content_tag 'span', class: 'gpg-badge-popover-title' do + title + end + end + + data = { + toggle: 'popover', + html: 'true', + placement: 'auto bottom', + trigger: 'focus', + title: title, + content: content + } + + content_tag :button, class: css_classes, data: data do + label + end + end end diff --git a/app/views/projects/commit/_signature.html.haml b/app/views/projects/commit/_signature.html.haml index 48665ede6eb..00120a665c5 100644 --- a/app/views/projects/commit/_signature.html.haml +++ b/app/views/projects/commit/_signature.html.haml @@ -1,4 +1,2 @@ - if signature - %a.btn.disabled.btn-xs{ class: ('btn-success' if signature.valid_signature?) } - %i.fa.fa-key{ class: ('fa-inverse' if signature.valid_signature?) } - = signature.valid_signature? ? 'Verified' : 'Unverified' + = commit_gpg_signature_badge(signature) diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 7635e87e838..236e3089c6c 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -275,5 +275,30 @@ describe 'Commits' do expect(page).to have_content 'Verified' end end + + it 'shows popover badges', :js do + user = create :user, email: GpgHelpers::User1.emails.first, username: 'nannie.bernhard', name: 'Nannie Bernhard' + project.team << [user, :master] + Sidekiq::Testing.inline! do + create :gpg_key, key: GpgHelpers::User1.public_key, user: user + end + + login_with(user) + visit namespace_project_commits_path(project.namespace, project, :master) + + click_on 'Verified' + within '.popover' do + expect(page).to have_content 'This commit was signed with a verified signature.' + expect(page).to have_content 'nannie.bernhard' + expect(page).to have_content 'Nannie Bernhard' + expect(page).to have_content "GPG key ID: #{GpgHelpers::User1.primary_keyid}" + end + + click_on 'Unverified', match: :first + within '.popover' do + expect(page).to have_content 'This commit was signed with an unverified signature.' + expect(page).to have_content "GPG key ID: #{GpgHelpers::User2.primary_keyid}" + end + end end end -- cgit v1.2.1 From ee7468e786e434273211586df1408a3c6268e9ed Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Fri, 23 Jun 2017 22:53:41 +0200 Subject: we need to update the gpg_key as well --- lib/gitlab/gpg/commit.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb index 437f13ef311..99d112a51a3 100644 --- a/lib/gitlab/gpg/commit.rb +++ b/lib/gitlab/gpg/commit.rb @@ -32,7 +32,8 @@ module Gitlab def update_signature!(cached_signature) using_keychain do |gpg_key| cached_signature.update_attributes!( - valid_signature: gpg_signature_valid_signature_value(gpg_key) + valid_signature: gpg_signature_valid_signature_value(gpg_key), + gpg_key: gpg_key ) end end -- cgit v1.2.1 From 7fc69a7ed4acb6a583c473799b4169825dcd3777 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Sat, 24 Jun 2017 21:24:49 +0200 Subject: linkify the whole user badge part, not only avatar --- app/assets/stylesheets/pages/commits.scss | 5 +++++ app/helpers/commits_helper.rb | 36 ++++++++++++++++--------------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 54f6156ad8f..b1710eee1bf 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -314,6 +314,11 @@ } } +.gpg-badge-popover-user-link { + text-decoration: none; + color: $gl-text-color; +} + .gpg-badge-popover-avatar { float: left; margin-bottom: $gl-padding; diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 34ba5694288..e31baa52e99 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -228,23 +228,25 @@ module CommitsHelper end content = capture do - concat( - content_tag(:div, class: 'gpg-badge-popover-avatar') do - user_avatar(user: signature.gpg_key.user, size: 32) - end - ) - - concat( - content_tag(:div, class: 'gpg-badge-popover-username') do - signature.gpg_key.user.username - end - ) - - concat( - content_tag(:div) do - signature.gpg_key.user.name - end - ) + link_to user_path(signature.gpg_key.user), class: 'gpg-badge-popover-user-link' do + concat( + content_tag(:div, class: 'gpg-badge-popover-avatar') do + user_avatar_without_link(user: signature.gpg_key.user, size: 32) + end + ) + + concat( + content_tag(:div, class: 'gpg-badge-popover-username') do + signature.gpg_key.user.username + end + ) + + concat( + content_tag(:div) do + signature.gpg_key.user.name + end + ) + end end commit_gpg_signature_badge_with(signature, label: 'Verified', title: title, content: content, css_classes: ['valid']) -- cgit v1.2.1 From afd7582af6a20d72b1d941d9849f331aee8f994a Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Mon, 26 Jun 2017 09:13:36 +0200 Subject: extract variable --- spec/lib/gitlab/gpg/commit_spec.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/spec/lib/gitlab/gpg/commit_spec.rb b/spec/lib/gitlab/gpg/commit_spec.rb index 387ce8f74b4..661956b7bb7 100644 --- a/spec/lib/gitlab/gpg/commit_spec.rb +++ b/spec/lib/gitlab/gpg/commit_spec.rb @@ -3,6 +3,7 @@ require 'rails_helper' RSpec.describe Gitlab::Gpg::Commit do describe '#signature' do let!(:project) { create :project, :repository, path: 'sample-project' } + let!(:commit_sha) { '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' } context 'unisgned commit' do it 'returns nil' do @@ -19,7 +20,7 @@ RSpec.describe Gitlab::Gpg::Commit do raw_commit = double(:raw_commit, signature: [ GpgHelpers::User1.signed_commit_signature, GpgHelpers::User1.signed_commit_base_data - ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') + ], sha: commit_sha) allow(raw_commit).to receive :save! create :commit, git_commit: raw_commit, project: project @@ -27,7 +28,7 @@ RSpec.describe Gitlab::Gpg::Commit do it 'returns a valid signature' do expect(described_class.new(commit).signature).to have_attributes( - commit_sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', + commit_sha: commit_sha, project: project, gpg_key: gpg_key, gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, @@ -54,7 +55,7 @@ RSpec.describe Gitlab::Gpg::Commit do raw_commit = double(:raw_commit, signature: [ GpgHelpers::User1.signed_commit_signature, GpgHelpers::User1.signed_commit_base_data - ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') + ], sha: commit_sha) allow(raw_commit).to receive :save! create :commit, git_commit: raw_commit, project: project @@ -62,7 +63,7 @@ RSpec.describe Gitlab::Gpg::Commit do it 'returns an invalid signature' do expect(described_class.new(commit).signature).to have_attributes( - commit_sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', + commit_sha: commit_sha, project: project, gpg_key: gpg_key, gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, @@ -87,7 +88,7 @@ RSpec.describe Gitlab::Gpg::Commit do raw_commit = double(:raw_commit, signature: [ GpgHelpers::User1.signed_commit_signature, GpgHelpers::User1.signed_commit_base_data - ], sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') + ], sha: commit_sha) allow(raw_commit).to receive :save! create :commit, @@ -97,7 +98,7 @@ RSpec.describe Gitlab::Gpg::Commit do it 'returns an invalid signature' do expect(described_class.new(commit).signature).to have_attributes( - commit_sha: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33', + commit_sha: commit_sha, project: project, gpg_key: nil, gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, -- cgit v1.2.1 From 5013f3a8167bb7c665b19f44ae66e543fe0b2fce Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Mon, 26 Jun 2017 14:29:01 +0200 Subject: use updated gitlab-test repo for signed commits --- spec/features/commits_spec.rb | 24 +++++------------------- spec/support/test_env.rb | 1 + 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 236e3089c6c..274247fc4d3 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -1,5 +1,4 @@ require 'spec_helper' -require 'fileutils' describe 'Commits' do include CiStatusHelper @@ -206,19 +205,6 @@ describe 'Commits' do end describe 'GPG signed commits' do - before do - # FIXME: add this to the test repository directly - remote_path = project.repository.path_to_repo - Dir.mktmpdir do |dir| - FileUtils.cd dir do - `git clone --quiet #{remote_path} .` - `git commit --quiet -S#{GpgHelpers::User1.primary_keyid} --allow-empty -m "signed commit by nannie bernhard"` - `git commit --quiet -S#{GpgHelpers::User2.primary_keyid} --allow-empty -m "signed commit by bette cartwright"` - `git push --quiet` - end - end - end - it 'changes from unverified to verified when the user changes his email to match the gpg key' do user = create :user, email: 'unrelated.user@example.org' project.team << [user, :master] @@ -229,7 +215,7 @@ describe 'Commits' do login_with(user) - visit namespace_project_commits_path(project.namespace, project, :master) + visit namespace_project_commits_path(project.namespace, project, :'signed-commits') within '#commits-list' do expect(page).to have_content 'Unverified' @@ -242,7 +228,7 @@ describe 'Commits' do user.update_attributes!(email: GpgHelpers::User1.emails.first) end - visit namespace_project_commits_path(project.namespace, project, :master) + visit namespace_project_commits_path(project.namespace, project, :'signed-commits') within '#commits-list' do expect(page).to have_content 'Unverified' @@ -256,7 +242,7 @@ describe 'Commits' do login_with(user) - visit namespace_project_commits_path(project.namespace, project, :master) + visit namespace_project_commits_path(project.namespace, project, :'signed-commits') within '#commits-list' do expect(page).to have_content 'Unverified' @@ -268,7 +254,7 @@ describe 'Commits' do create :gpg_key, key: GpgHelpers::User1.public_key, user: user end - visit namespace_project_commits_path(project.namespace, project, :master) + visit namespace_project_commits_path(project.namespace, project, :'signed-commits') within '#commits-list' do expect(page).to have_content 'Unverified' @@ -284,7 +270,7 @@ describe 'Commits' do end login_with(user) - visit namespace_project_commits_path(project.namespace, project, :master) + visit namespace_project_commits_path(project.namespace, project, :'signed-commits') click_on 'Verified' within '.popover' do diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index c32c05b03e2..7682bdf8cd0 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -5,6 +5,7 @@ module TestEnv # When developing the seed repository, comment out the branch you will modify. BRANCH_SHA = { + 'signed-commits' => '5d4a1cb', 'not-merged-branch' => 'b83d6e3', 'branch-merged' => '498214d', 'empty-branch' => '7efb185', -- cgit v1.2.1 From 4648d0016f67c9b780e3fff475e458fc28825daf Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Mon, 26 Jun 2017 14:41:17 +0200 Subject: popover trigger needs to be defined in js init According to https://github.com/twbs/bootstrap/issues/10547 it's not possible to have the trigger defined on the delegated element, i.e. not defined as a data attribute. --- app/assets/javascripts/main.js | 3 ++- app/helpers/commits_helper.rb | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index ecf7a677c99..d039ca9e47c 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -251,7 +251,8 @@ $(function () { }); // Initialize popovers $body.popover({ - selector: '[data-toggle="popover"]' + selector: '[data-toggle="popover"]', + trigger: 'focus' }); $('.trigger-submit').on('change', function () { return $(this).parents('form').submit(); diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index e31baa52e99..42e9379d1f4 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -283,7 +283,6 @@ module CommitsHelper toggle: 'popover', html: 'true', placement: 'auto bottom', - trigger: 'focus', title: title, content: content } -- cgit v1.2.1 From 9a759c620179c72821fa6217c138036b57ea3695 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 28 Jun 2017 12:51:18 +0200 Subject: add changelog --- changelogs/unreleased/feature-gpg-signed-commits.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/feature-gpg-signed-commits.yml diff --git a/changelogs/unreleased/feature-gpg-signed-commits.yml b/changelogs/unreleased/feature-gpg-signed-commits.yml new file mode 100644 index 00000000000..99bc5a309ef --- /dev/null +++ b/changelogs/unreleased/feature-gpg-signed-commits.yml @@ -0,0 +1,4 @@ +--- +title: GPG signed commits integration +merge_request: 9546 +author: Alexis Reigel -- cgit v1.2.1 From e9515dff845dfbbb51e556e4e6a4f9cf951cf239 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 28 Jun 2017 13:08:29 +0200 Subject: remove the :gpg rspec tag since everything (except the CurrentKeyChain method) operates on a tempoary keychain anyway we don't need this anymore. --- spec/features/profiles/gpg_keys_spec.rb | 2 +- spec/lib/gitlab/gpg_spec.rb | 10 ++++++++-- spec/models/gpg_key_spec.rb | 6 +++--- spec/spec_helper.rb | 6 ------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/spec/features/profiles/gpg_keys_spec.rb b/spec/features/profiles/gpg_keys_spec.rb index 552cca4a84e..350126523b0 100644 --- a/spec/features/profiles/gpg_keys_spec.rb +++ b/spec/features/profiles/gpg_keys_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Profile > GPG Keys', :gpg do +feature 'Profile > GPG Keys' do let(:user) { create(:user, email: GpgHelpers::User2.emails.first) } before do diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index edf7405d7f1..497fbeab5d5 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -44,8 +44,14 @@ describe Gitlab::Gpg do end end -describe Gitlab::Gpg::CurrentKeyChain, :gpg do - describe '.add', :gpg do +describe Gitlab::Gpg::CurrentKeyChain do + around do |example| + Gitlab::Gpg.using_tmp_keychain do + example.run + end + end + + describe '.add' do it 'stores the key in the keychain' do expect(GPGME::Key.find(:public, GpgHelpers::User1.fingerprint)).to eq [] diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 3cb1723cc12..312e026a78e 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -13,7 +13,7 @@ describe GpgKey do it { is_expected.not_to allow_value('BEGIN PGP').for(:key) } end - context 'callbacks', :gpg do + context 'callbacks' do describe 'extract_fingerprint' do it 'extracts the fingerprint from the gpg key' do gpg_key = described_class.new(key: GpgHelpers::User1.public_key) @@ -45,7 +45,7 @@ describe GpgKey do end end - describe '#emails', :gpg do + describe '#emails' do it 'returns the emails from the gpg key' do gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key @@ -53,7 +53,7 @@ describe GpgKey do end end - describe '#emails_with_verified_status', :gpg do + describe '#emails_with_verified_status' do it 'email is verified if the user has the matching email' do user = create :user, email: 'bette.cartwright@example.com' gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key, user: user diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a0df233507b..e7329210896 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -141,12 +141,6 @@ RSpec.configure do |config| config.around(:each, :postgresql) do |example| example.run if Gitlab::Database.postgresql? end - - config.around(:each, :gpg) do |example| - Gitlab::Gpg.using_tmp_keychain do - example.run - end - end end FactoryGirl::SyntaxRunner.class_eval do -- cgit v1.2.1 From bd476c1b4cd3399e684cc833a350b1f34c20b115 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 28 Jun 2017 13:24:52 +0200 Subject: use sign_in instead of login_with --- spec/features/commits_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 274247fc4d3..709df6336fe 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -213,7 +213,7 @@ describe 'Commits' do create :gpg_key, key: GpgHelpers::User1.public_key, user: user end - login_with(user) + sign_in(user) visit namespace_project_commits_path(project.namespace, project, :'signed-commits') @@ -240,7 +240,7 @@ describe 'Commits' do user = create :user, email: GpgHelpers::User1.emails.first project.team << [user, :master] - login_with(user) + sign_in(user) visit namespace_project_commits_path(project.namespace, project, :'signed-commits') @@ -269,7 +269,7 @@ describe 'Commits' do create :gpg_key, key: GpgHelpers::User1.public_key, user: user end - login_with(user) + sign_in(user) visit namespace_project_commits_path(project.namespace, project, :'signed-commits') click_on 'Verified' -- cgit v1.2.1 From 28c75fc1a87f8190c89666f8b6e3436311d024ce Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 29 Jun 2017 14:31:55 +0200 Subject: documentation for gpg signed commits --- doc/README.md | 1 + .../img/profile_settings_gpg_keys.png | Bin 0 -> 32699 bytes .../img/profile_settings_gpg_keys_paste_pub.png | Bin 0 -> 24514 bytes .../img/profile_settings_gpg_keys_single_key.png | Bin 0 -> 10331 bytes .../img/project_signed_and_unsigned_commits.png | Bin 0 -> 112812 bytes .../project_signed_commit_unverified_signature.png | Bin 0 -> 9542 bytes .../project_signed_commit_verified_signature.png | Bin 0 -> 14029 bytes doc/workflow/gpg_signed_commits/index.md | 55 +++++++++++++++++++++ 8 files changed, 56 insertions(+) create mode 100644 doc/workflow/gpg_signed_commits/img/profile_settings_gpg_keys.png create mode 100644 doc/workflow/gpg_signed_commits/img/profile_settings_gpg_keys_paste_pub.png create mode 100644 doc/workflow/gpg_signed_commits/img/profile_settings_gpg_keys_single_key.png create mode 100644 doc/workflow/gpg_signed_commits/img/project_signed_and_unsigned_commits.png create mode 100644 doc/workflow/gpg_signed_commits/img/project_signed_commit_unverified_signature.png create mode 100644 doc/workflow/gpg_signed_commits/img/project_signed_commit_verified_signature.png create mode 100644 doc/workflow/gpg_signed_commits/index.md diff --git a/doc/README.md b/doc/README.md index ac7311a8c13..5537f54ab2b 100644 --- a/doc/README.md +++ b/doc/README.md @@ -89,6 +89,7 @@ Manage files and branches from the UI (user interface): - [Git](topics/git/index.md): Getting started with Git, branching strategies, Git LFS, advanced use. - [Git cheatsheet](https://gitlab.com/gitlab-com/marketing/raw/master/design/print/git-cheatsheet/print-pdf/git-cheatsheet.pdf): Download a PDF describing the most used Git operations. - [GitLab Flow](workflow/gitlab_flow.md): explore the best of Git with the GitLab Flow strategy. +- [Signing commits](workflow/gpg_signed_commits/index.md): use GPG to sign your commits. ### Migrate and import your projects from other platforms diff --git a/doc/workflow/gpg_signed_commits/img/profile_settings_gpg_keys.png b/doc/workflow/gpg_signed_commits/img/profile_settings_gpg_keys.png new file mode 100644 index 00000000000..e525083918b Binary files /dev/null and b/doc/workflow/gpg_signed_commits/img/profile_settings_gpg_keys.png differ diff --git a/doc/workflow/gpg_signed_commits/img/profile_settings_gpg_keys_paste_pub.png b/doc/workflow/gpg_signed_commits/img/profile_settings_gpg_keys_paste_pub.png new file mode 100644 index 00000000000..8e26d98f1b0 Binary files /dev/null and b/doc/workflow/gpg_signed_commits/img/profile_settings_gpg_keys_paste_pub.png differ diff --git a/doc/workflow/gpg_signed_commits/img/profile_settings_gpg_keys_single_key.png b/doc/workflow/gpg_signed_commits/img/profile_settings_gpg_keys_single_key.png new file mode 100644 index 00000000000..f715c46adc3 Binary files /dev/null and b/doc/workflow/gpg_signed_commits/img/profile_settings_gpg_keys_single_key.png differ diff --git a/doc/workflow/gpg_signed_commits/img/project_signed_and_unsigned_commits.png b/doc/workflow/gpg_signed_commits/img/project_signed_and_unsigned_commits.png new file mode 100644 index 00000000000..16ec2d031ae Binary files /dev/null and b/doc/workflow/gpg_signed_commits/img/project_signed_and_unsigned_commits.png differ diff --git a/doc/workflow/gpg_signed_commits/img/project_signed_commit_unverified_signature.png b/doc/workflow/gpg_signed_commits/img/project_signed_commit_unverified_signature.png new file mode 100644 index 00000000000..22565cf7c7e Binary files /dev/null and b/doc/workflow/gpg_signed_commits/img/project_signed_commit_unverified_signature.png differ diff --git a/doc/workflow/gpg_signed_commits/img/project_signed_commit_verified_signature.png b/doc/workflow/gpg_signed_commits/img/project_signed_commit_verified_signature.png new file mode 100644 index 00000000000..1778b2ddf2b Binary files /dev/null and b/doc/workflow/gpg_signed_commits/img/project_signed_commit_verified_signature.png differ diff --git a/doc/workflow/gpg_signed_commits/index.md b/doc/workflow/gpg_signed_commits/index.md new file mode 100644 index 00000000000..041c681ba63 --- /dev/null +++ b/doc/workflow/gpg_signed_commits/index.md @@ -0,0 +1,55 @@ +# Signing commits with GPG + +## Getting started + +- [Git Tools - Signing Your Work](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work) + +## How GitLab handles GPG + +GitLab uses its own keyring to verify the GPG signature. It does not access any +public key server. + +In order to have a commit verified on GitLab the corresponding public key needs +to be uploaded to GitLab. + +For a signature to be verified two prerequisites need to be met: + +1. The public key needs to be added to GitLab +1. One of the emails in the GPG key matches your **primary** email + +## Add a GPG key + +1. On the upper right corner, click on your avatar and go to your **Settings**. + + ![Settings dropdown](../../gitlab-basics/img/profile_settings.png) + +1. Navigate to the **GPG keys** tab. + + ![GPG Keys](img/profile_settings_gpg_keys.png) + +1. Paste your **public** key in the 'Key' box. + + ![Paste GPG public key](img/profile_settings_gpg_keys_paste_pub.png) + +1. Finally, click on **Add key** to add it to GitLab. You will be able to see + its fingerprint, the corresponding email address and creation date. + + ![GPG key single page](img/profile_settings_gpg_keys_single_key.png) + +>**Note:** +Once you add a key, you cannot edit it, only remove it. In case the paste +didn't work, you will have to remove the offending key and re-add it. + +## Verifying commits + +1. Within a project navigate to the **Commits** tag. Signed commits will show a + badge containing either "Verified" or "Unverified", depending on the + verification status of the GPG signature. + + ![Signed and unsigned commits](img/project_signed_and_unsigned_commits.png) + +1. By clicking on the GPG badge details of the signature are displayed. + + ![Signed commit with verified signature](img/project_signed_commit_verified_signature.png) + + ![Signed commit with verified signature](img/project_signed_commit_unverified_signature.png) -- cgit v1.2.1 From 3b7ac360cff04a5c1be83ee13b1354f07021c80d Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Fri, 30 Jun 2017 12:48:08 +0200 Subject: position gpg badge first on commit line --- app/views/projects/commit/_commit_box.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml index 1a0c70ef803..419fbe99af8 100644 --- a/app/views/projects/commit/_commit_box.html.haml +++ b/app/views/projects/commit/_commit_box.html.haml @@ -1,12 +1,12 @@ .page-content-header .header-main-content + = render partial: 'signature', object: @commit.signature %strong #{ s_('CommitBoxTitle|Commit') } %span.commit-sha= @commit.short_id = clipboard_button(text: @commit.id, title: _("Copy commit SHA to clipboard")) %span.hidden-xs authored #{time_ago_with_tooltip(@commit.authored_date)} - = render partial: 'signature', object: @commit.signature %span= s_('ByAuthor|by') = author_avatar(@commit, size: 24) %strong -- cgit v1.2.1 From ade54803a7f8b1470320fc6fa5871f2ec208eb0f Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Mon, 3 Jul 2017 09:41:32 +0200 Subject: add help links to gpg commits / gpg settings --- app/assets/stylesheets/pages/commits.scss | 5 +++++ app/helpers/commits_helper.rb | 7 +++++++ app/views/profiles/gpg_keys/index.html.haml | 5 ++++- doc/workflow/gpg_signed_commits/index.md | 2 ++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index b1710eee1bf..5de98cfc7af 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -331,3 +331,8 @@ .gpg-badge-popover-username { font-weight: bold; } + +.commit .gpg-badge-popover-help-link { + display: block; + color: $link-color; +} diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 42e9379d1f4..60acc1e2f82 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -271,6 +271,13 @@ module CommitsHelper ) concat "GPG key ID: #{signature.gpg_key_primary_keyid}" + concat( + link_to( + 'Learn about signing commits', + help_page_path('workflow/gpg_signed_commits/index.md'), + class: 'gpg-badge-popover-help-link' + ) + ) end title = capture do diff --git a/app/views/profiles/gpg_keys/index.html.haml b/app/views/profiles/gpg_keys/index.html.haml index 30066522766..8331daeeb75 100644 --- a/app/views/profiles/gpg_keys/index.html.haml +++ b/app/views/profiles/gpg_keys/index.html.haml @@ -9,7 +9,10 @@ GPG keys allow you to verify signed commits. .col-lg-9 %h5.prepend-top-0 - Add an GPG key + Add a GPG key + %p.profile-settings-content + Before you can add a GPG key you need to + = link_to 'generate it.', help_page_path('workflow/gpg_signed_commits/index.md') = render 'form' %hr %h5 diff --git a/doc/workflow/gpg_signed_commits/index.md b/doc/workflow/gpg_signed_commits/index.md index 041c681ba63..f7f5492c35a 100644 --- a/doc/workflow/gpg_signed_commits/index.md +++ b/doc/workflow/gpg_signed_commits/index.md @@ -3,6 +3,8 @@ ## Getting started - [Git Tools - Signing Your Work](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work) +- [Git Tools - Signing Your Work: GPG introduction](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work#_gpg_introduction) +- [Git Tools - Signing Your Work: Signing commits](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work#_signing_commits) ## How GitLab handles GPG -- cgit v1.2.1 From a06494bf71b589d2b9f5c80710b6c8e0749fc210 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 4 Jul 2017 13:46:33 +0200 Subject: no need for html_safe --- app/views/profiles/gpg_keys/_key.html.haml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/profiles/gpg_keys/_key.html.haml b/app/views/profiles/gpg_keys/_key.html.haml index d7450a22f4c..b4b9aa07190 100644 --- a/app/views/profiles/gpg_keys/_key.html.haml +++ b/app/views/profiles/gpg_keys/_key.html.haml @@ -2,7 +2,9 @@ .pull-left.append-right-10 = icon 'key', class: "settings-list-icon hidden-xs" .key-list-item-info - = key.emails_with_verified_status.map { |email, verified| verified_email_badge(email, verified) }.join(' ').html_safe + - key.emails_with_verified_status.map do |email, verified| + = verified_email_badge(email, verified) + .description = key.fingerprint .pull-right -- cgit v1.2.1 From 075dae65b1a5b57788e4823b09bdcb8fa6eeaf8a Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 5 Jul 2017 13:11:18 +0200 Subject: find_by_id -> find_by(:id, ...) --- app/mailers/emails/profile.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/mailers/emails/profile.rb b/app/mailers/emails/profile.rb index 4580e1c83bd..c401030e34a 100644 --- a/app/mailers/emails/profile.rb +++ b/app/mailers/emails/profile.rb @@ -14,7 +14,7 @@ module Emails end def new_ssh_key_email(key_id) - @key = Key.find_by_id(key_id) + @key = Key.find_by(id: key_id) return unless @key @@ -24,7 +24,7 @@ module Emails end def new_gpg_key_email(gpg_key_id) - @gpg_key = GpgKey.find_by_id(gpg_key_id) + @gpg_key = GpgKey.find_by(id: gpg_key_id) return unless @gpg_key -- cgit v1.2.1 From d9fd3709abb7897785ac111c217b532663313abd Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 5 Jul 2017 13:16:50 +0200 Subject: use hash instead of 2d array --- app/models/gpg_key.rb | 2 +- spec/models/gpg_key_spec.rb | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index bd5d833d68c..8cfccef0854 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -47,7 +47,7 @@ class GpgKey < ActiveRecord::Base email, email == user.email ] - end + end.to_h end def verified? diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 312e026a78e..88b5eb79b59 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -58,10 +58,10 @@ describe GpgKey do user = create :user, email: 'bette.cartwright@example.com' gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key, user: user - expect(gpg_key.emails_with_verified_status).to match_array [ - ['bette.cartwright@example.com', true], - ['bette.cartwright@example.net', false] - ] + expect(gpg_key.emails_with_verified_status).to eq( + 'bette.cartwright@example.com' => true, + 'bette.cartwright@example.net' => false + ) end end -- cgit v1.2.1 From e79e2ae1f4b671488b31428f7a6506a245a7bddc Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 5 Jul 2017 14:03:36 +0200 Subject: validate presence of user on gpg_key --- app/models/gpg_key.rb | 2 ++ spec/models/gpg_key_spec.rb | 1 + 2 files changed, 3 insertions(+) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 8cfccef0854..612d954b1c5 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -6,6 +6,8 @@ class GpgKey < ActiveRecord::Base belongs_to :user has_many :gpg_signatures, dependent: :nullify + validates :user, presence: true + validates :key, presence: true, uniqueness: true, diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 88b5eb79b59..ffbf8760e86 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -6,6 +6,7 @@ describe GpgKey do end describe "validation" do + it { is_expected.to validate_presence_of(:user) } it { is_expected.to validate_presence_of(:key) } it { is_expected.to validate_uniqueness_of(:key) } it { is_expected.to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----\nkey").for(:key) } -- cgit v1.2.1 From 084cc718f759a37c8fc5535930daeee5e819c30f Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 5 Jul 2017 14:23:23 +0200 Subject: use after_commit instead of AfterCommitQueue --- app/models/gpg_key.rb | 12 +++--------- app/models/user.rb | 5 ++--- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 612d954b1c5..050245bd502 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -1,6 +1,4 @@ class GpgKey < ActiveRecord::Base - include AfterCommitQueue - KEY_PREFIX = '-----BEGIN PGP PUBLIC KEY BLOCK-----'.freeze belongs_to :user @@ -31,8 +29,8 @@ class GpgKey < ActiveRecord::Base unless: -> { errors.has_key?(:key) } before_validation :extract_fingerprint, :extract_primary_keyid - after_create :update_invalid_gpg_signatures_after_create - after_create :notify_user + after_commit :update_invalid_gpg_signatures, on: :create + after_commit :notify_user, on: :create def key=(value) value.strip! unless value.blank? @@ -75,10 +73,6 @@ class GpgKey < ActiveRecord::Base end def notify_user - run_after_commit { NotificationService.new.new_gpg_key(self) } - end - - def update_invalid_gpg_signatures_after_create - run_after_commit { update_invalid_gpg_signatures } + NotificationService.new.new_gpg_key(self) end end diff --git a/app/models/user.rb b/app/models/user.rb index 931b760df34..03a76f4fa23 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -13,7 +13,6 @@ class User < ActiveRecord::Base include IgnorableColumn include FeatureGate include CreatedAtFilterable - include AfterCommitQueue DEFAULT_NOTIFICATION_LEVEL = :participating @@ -156,10 +155,10 @@ class User < ActiveRecord::Base before_validation :set_public_email, if: :public_email_changed? after_update :update_emails_with_primary_email, if: :email_changed? - after_update :update_invalid_gpg_signatures, if: :email_changed? before_save :ensure_authentication_token, :ensure_incoming_email_token before_save :ensure_user_rights_and_limits, if: :external_changed? after_save :ensure_namespace_correct + after_commit :update_invalid_gpg_signatures, on: :update, if: -> { previous_changes.key?('email') } after_initialize :set_projects_limit after_destroy :post_destroy_hook @@ -516,7 +515,7 @@ class User < ActiveRecord::Base end def update_invalid_gpg_signatures - run_after_commit { gpg_keys.each(&:update_invalid_gpg_signatures) } + gpg_keys.each(&:update_invalid_gpg_signatures) end # Returns the groups a user has access to -- cgit v1.2.1 From 36c05b311c830aef25ecb7ad4416ac77a5c98651 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 5 Jul 2017 20:59:17 +0200 Subject: convert gpg badge helper methods to partials --- app/assets/stylesheets/pages/commits.scss | 1 + app/helpers/commits_helper.rb | 86 ---------------------- .../commit/_invalid_signature_badge.html.haml | 7 ++ app/views/projects/commit/_signature.html.haml | 5 +- .../projects/commit/_signature_badge.html.haml | 17 +++++ .../commit/_valid_signature_badge.html.haml | 19 +++++ 6 files changed, 48 insertions(+), 87 deletions(-) create mode 100644 app/views/projects/commit/_invalid_signature_badge.html.haml create mode 100644 app/views/projects/commit/_signature_badge.html.haml create mode 100644 app/views/projects/commit/_valid_signature_badge.html.haml diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 5de98cfc7af..b6e9053fbce 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -295,6 +295,7 @@ } .gpg-badge-popover-title { + display: inline; font-weight: normal; } diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 60acc1e2f82..d08e346d605 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -212,90 +212,4 @@ module CommitsHelper [commits, 0] end end - - def commit_gpg_signature_badge(signature) - if signature.valid_signature? - commit_gpg_valid_signature_badge(signature) - else - commit_gpg_invalid_signature_badge(signature) - end - end - - def commit_gpg_valid_signature_badge(signature) - title = capture do - concat content_tag('i', '', class: 'fa fa-check-circle gpg-badge-popover-icon valid', 'aria-hidden' => 'true') - concat 'This commit was signed with a verified signature.' - end - - content = capture do - link_to user_path(signature.gpg_key.user), class: 'gpg-badge-popover-user-link' do - concat( - content_tag(:div, class: 'gpg-badge-popover-avatar') do - user_avatar_without_link(user: signature.gpg_key.user, size: 32) - end - ) - - concat( - content_tag(:div, class: 'gpg-badge-popover-username') do - signature.gpg_key.user.username - end - ) - - concat( - content_tag(:div) do - signature.gpg_key.user.name - end - ) - end - end - - commit_gpg_signature_badge_with(signature, label: 'Verified', title: title, content: content, css_classes: ['valid']) - end - - def commit_gpg_invalid_signature_badge(signature) - title = capture do - concat content_tag('i', '', class: 'fa fa-question-circle gpg-badge-popover-icon invalid', 'aria-hidden' => 'true') - concat 'This commit was signed with an unverified signature.' - end - commit_gpg_signature_badge_with(signature, label: 'Unverified', title: title, css_classes: ['invalid']) - end - - def commit_gpg_signature_badge_with(signature, label:, title: '', content: '', css_classes: []) - css_classes = %w(btn btn-xs gpg-badge) + css_classes - - content = capture do - concat( - content_tag(:div, class: 'clearfix') do - content - end - ) - - concat "GPG key ID: #{signature.gpg_key_primary_keyid}" - concat( - link_to( - 'Learn about signing commits', - help_page_path('workflow/gpg_signed_commits/index.md'), - class: 'gpg-badge-popover-help-link' - ) - ) - end - - title = capture do - content_tag 'span', class: 'gpg-badge-popover-title' do - title - end - end - - data = { - toggle: 'popover', - html: 'true', - placement: 'auto bottom', - title: title, - content: content - } - - content_tag :button, class: css_classes, data: data do - label - end - end end diff --git a/app/views/projects/commit/_invalid_signature_badge.html.haml b/app/views/projects/commit/_invalid_signature_badge.html.haml new file mode 100644 index 00000000000..29c787bd324 --- /dev/null +++ b/app/views/projects/commit/_invalid_signature_badge.html.haml @@ -0,0 +1,7 @@ +- title = capture do + %i{ class: 'fa fa-question-circle gpg-badge-popover-icon invalid', 'aria-hidden' => 'true' } + This commit was signed with an unverified signature. + +- locals = { signature: signature, title: title, label: 'Unverified', css_classes: ['invalid'] } + += render partial: 'projects/commit/signature_badge', locals: locals diff --git a/app/views/projects/commit/_signature.html.haml b/app/views/projects/commit/_signature.html.haml index 00120a665c5..60fa52557ef 100644 --- a/app/views/projects/commit/_signature.html.haml +++ b/app/views/projects/commit/_signature.html.haml @@ -1,2 +1,5 @@ - if signature - = commit_gpg_signature_badge(signature) + - if signature.valid_signature? + = render partial: 'projects/commit/valid_signature_badge', locals: { signature: signature } + - else + = render partial: 'projects/commit/invalid_signature_badge', locals: { signature: signature } diff --git a/app/views/projects/commit/_signature_badge.html.haml b/app/views/projects/commit/_signature_badge.html.haml new file mode 100644 index 00000000000..2e046c1f684 --- /dev/null +++ b/app/views/projects/commit/_signature_badge.html.haml @@ -0,0 +1,17 @@ +- css_classes = %w(btn btn-xs gpg-badge) + css_classes + +- title = capture do + .gpg-badge-popover-title + = title + +- content = capture do + .clearfix + = content + + GPG key ID: + = signature.gpg_key_primary_keyid + + = link_to('Learn about signing commits', help_page_path('workflow/gpg_signed_commits/index.md'), class: 'gpg-badge-popover-help-link') + +%button{ class: css_classes, data: { toggle: 'popover', html: 'true', placement: 'auto bottom', title: title, content: content } } + = label diff --git a/app/views/projects/commit/_valid_signature_badge.html.haml b/app/views/projects/commit/_valid_signature_badge.html.haml new file mode 100644 index 00000000000..47226466b85 --- /dev/null +++ b/app/views/projects/commit/_valid_signature_badge.html.haml @@ -0,0 +1,19 @@ +- title = capture do + %i{ class: 'fa fa-check-circle gpg-badge-popover-icon valid', 'aria-hidden' => 'true' } + This commit was signed with a verified signature. + +- content = capture do + - gpg_key = signature.gpg_key + + = link_to user_path(gpg_key.user), class: 'gpg-badge-popover-user-link' do + .gpg-badge-popover-avatar + = user_avatar_without_link(user: signature.gpg_key.user, size: 32) + + .gpg-badge-popover-username + = gpg_key.user.username + + %div= gpg_key.user.name + +- locals = { signature: signature, title: title, content: content, label: 'Verified', css_classes: ['valid'] } + += render partial: 'projects/commit/signature_badge', locals: locals -- cgit v1.2.1 From 4f7ba8f2861b39d3a7697eb99e3fbaaf39f32643 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 6 Jul 2017 08:03:16 +0200 Subject: fix memoization --- lib/gitlab/gpg/commit.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb index 99d112a51a3..718e77ecadc 100644 --- a/lib/gitlab/gpg/commit.rb +++ b/lib/gitlab/gpg/commit.rb @@ -22,7 +22,6 @@ module Gitlab using_keychain do |gpg_key| if gpg_key Gitlab::Gpg::CurrentKeyChain.add(gpg_key.key) - @verified_signature = nil end create_cached_signature!(gpg_key) @@ -50,6 +49,7 @@ module Gitlab if gpg_key Gitlab::Gpg::CurrentKeyChain.add(gpg_key.key) + @verified_signature = nil end yield gpg_key @@ -58,7 +58,7 @@ module Gitlab def verified_signature @verified_signature ||= GPGME::Crypto.new.verify(@signature_text, signed_text: @signed_text) do |verified_signature| - return verified_signature + break verified_signature end end -- cgit v1.2.1 From a7d2ebe508b6dde3b3ae37c5a54fc78719b199b3 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 6 Jul 2017 10:17:09 +0200 Subject: simplify fetching of commit --- app/models/gpg_signature.rb | 4 ++++ lib/gitlab/gpg/invalid_gpg_signature_updater.rb | 4 +--- spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb | 2 +- spec/models/gpg_signature_spec.rb | 13 +++++++++++++ 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/app/models/gpg_signature.rb b/app/models/gpg_signature.rb index 4fe9c3210ff..0ef335bf8a9 100644 --- a/app/models/gpg_signature.rb +++ b/app/models/gpg_signature.rb @@ -5,4 +5,8 @@ class GpgSignature < ActiveRecord::Base validates :commit_sha, presence: true validates :project, presence: true validates :gpg_key_primary_keyid, presence: true + + def commit + project.commit(commit_sha) + end end diff --git a/lib/gitlab/gpg/invalid_gpg_signature_updater.rb b/lib/gitlab/gpg/invalid_gpg_signature_updater.rb index 06e4823de32..860e1e1035c 100644 --- a/lib/gitlab/gpg/invalid_gpg_signature_updater.rb +++ b/lib/gitlab/gpg/invalid_gpg_signature_updater.rb @@ -10,9 +10,7 @@ module Gitlab .where(valid_signature: false) .where(gpg_key_primary_keyid: @gpg_key.primary_keyid) .find_each do |gpg_signature| - raw_commit = Gitlab::Git::Commit.find(gpg_signature.project.repository, gpg_signature.commit_sha) - commit = ::Commit.new(raw_commit, gpg_signature.project) - Gitlab::Gpg::Commit.new(commit).update_signature!(gpg_signature) + Gitlab::Gpg::Commit.new(gpg_signature.commit).update_signature!(gpg_signature) end end end diff --git a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb index 8b60b36452b..c16f15bf4bf 100644 --- a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb +++ b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb @@ -29,7 +29,7 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do end before do - allow(Gitlab::Git::Commit).to receive(:find).with(kind_of(Repository), commit_sha).and_return(raw_commit) + allow_any_instance_of(GpgSignature).to receive(:commit).and_return(commit) end context 'gpg signature did not have an associated gpg key' do diff --git a/spec/models/gpg_signature_spec.rb b/spec/models/gpg_signature_spec.rb index b3f84262874..b6f256e61ee 100644 --- a/spec/models/gpg_signature_spec.rb +++ b/spec/models/gpg_signature_spec.rb @@ -12,4 +12,17 @@ RSpec.describe GpgSignature do it { is_expected.to validate_presence_of(:project) } it { is_expected.to validate_presence_of(:gpg_key_primary_keyid) } end + + describe '#commit' do + it 'fetches the commit through the project' do + commit_sha = '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' + project = create :project + commit = create :commit, project: project + gpg_signature = create :gpg_signature, commit_sha: commit_sha + + expect_any_instance_of(Project).to receive(:commit).with(commit_sha).and_return(commit) + + gpg_signature.commit + end + end end -- cgit v1.2.1 From 7f03282f0ff45948d3d27efe007ba77e24e19fa5 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 6 Jul 2017 10:26:31 +0200 Subject: remove duplicate statement --- lib/gitlab/gpg/commit.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb index 718e77ecadc..50e8d71bb13 100644 --- a/lib/gitlab/gpg/commit.rb +++ b/lib/gitlab/gpg/commit.rb @@ -20,10 +20,6 @@ module Gitlab return cached_signature if cached_signature.present? using_keychain do |gpg_key| - if gpg_key - Gitlab::Gpg::CurrentKeyChain.add(gpg_key.key) - end - create_cached_signature!(gpg_key) end end -- cgit v1.2.1 From b66e3726dc377c2bb5c92983db4ec4c8d27237c4 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 6 Jul 2017 11:15:31 +0200 Subject: also update gpg_signatures when gpg_key is null --- lib/gitlab/gpg/invalid_gpg_signature_updater.rb | 2 +- .../gpg/invalid_gpg_signature_updater_spec.rb | 70 +++++++++++++++++----- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/lib/gitlab/gpg/invalid_gpg_signature_updater.rb b/lib/gitlab/gpg/invalid_gpg_signature_updater.rb index 860e1e1035c..1782e20dcab 100644 --- a/lib/gitlab/gpg/invalid_gpg_signature_updater.rb +++ b/lib/gitlab/gpg/invalid_gpg_signature_updater.rb @@ -7,7 +7,7 @@ module Gitlab def run GpgSignature - .where(valid_signature: false) + .where('gpg_key_id IS NULL OR valid_signature = ?', false) .where(gpg_key_primary_keyid: @gpg_key.primary_keyid) .find_each do |gpg_signature| Gitlab::Gpg::Commit.new(gpg_signature.commit).update_signature!(gpg_signature) diff --git a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb index c16f15bf4bf..5a81a86b93c 100644 --- a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb +++ b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb @@ -19,29 +19,60 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do create :commit, git_commit: raw_commit, project: project end - let!(:gpg_signature) do - create :gpg_signature, - project: project, - commit_sha: commit_sha, - gpg_key: nil, - gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, - valid_signature: false - end - before do allow_any_instance_of(GpgSignature).to receive(:commit).and_return(commit) end + context 'gpg signature did have an associated gpg key which was removed later' do + let!(:user) { create :user, email: GpgHelpers::User1.emails.first } + + let!(:valid_gpg_signature) do + create :gpg_signature, + project: project, + commit_sha: commit_sha, + gpg_key: nil, + gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + valid_signature: true + end + + it 'assigns the gpg key to the signature when the missing gpg key is added' do + # InvalidGpgSignatureUpdater is called by the after_create hook + gpg_key = create :gpg_key, + key: GpgHelpers::User1.public_key, + user: user + + expect(valid_gpg_signature.reload.gpg_key).to eq gpg_key + end + + it 'does not assign the gpg key when an unrelated gpg key is added' do + # InvalidGpgSignatureUpdater is called by the after_create hook + create :gpg_key, + key: GpgHelpers::User2.public_key, + user: user + + expect(valid_gpg_signature.reload.gpg_key).to be_nil + end + end + context 'gpg signature did not have an associated gpg key' do let!(:user) { create :user, email: GpgHelpers::User1.emails.first } + let!(:invalid_gpg_signature) do + create :gpg_signature, + project: project, + commit_sha: commit_sha, + gpg_key: nil, + gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + valid_signature: false + end + it 'updates the signature to being valid when the missing gpg key is added' do # InvalidGpgSignatureUpdater is called by the after_create hook create :gpg_key, key: GpgHelpers::User1.public_key, user: user - expect(gpg_signature.reload.valid_signature).to be_truthy + expect(invalid_gpg_signature.reload.valid_signature).to be_truthy end it 'keeps the signature at being invalid when an unrelated gpg key is added' do @@ -50,7 +81,7 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do key: GpgHelpers::User2.public_key, user: user - expect(gpg_signature.reload.valid_signature).to be_falsey + expect(invalid_gpg_signature.reload.valid_signature).to be_falsey end end @@ -61,17 +92,26 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do end end + let!(:invalid_gpg_signature) do + create :gpg_signature, + project: project, + commit_sha: commit_sha, + gpg_key: nil, + gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + valid_signature: false + end + it 'updates the signature to being valid when the user updates the email address' do create :gpg_key, key: GpgHelpers::User1.public_key, user: user - expect(gpg_signature.reload.valid_signature).to be_falsey + expect(invalid_gpg_signature.reload.valid_signature).to be_falsey # InvalidGpgSignatureUpdater is called by the after_update hook user.update_attributes!(email: GpgHelpers::User1.emails.first) - expect(gpg_signature.reload.valid_signature).to be_truthy + expect(invalid_gpg_signature.reload.valid_signature).to be_truthy end it 'keeps the signature at being invalid when the changed email address is still unrelated' do @@ -79,12 +119,12 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do key: GpgHelpers::User1.public_key, user: user - expect(gpg_signature.reload.valid_signature).to be_falsey + expect(invalid_gpg_signature.reload.valid_signature).to be_falsey # InvalidGpgSignatureUpdater is called by the after_update hook user.update_attributes!(email: 'still.unrelated@example.com') - expect(gpg_signature.reload.valid_signature).to be_falsey + expect(invalid_gpg_signature.reload.valid_signature).to be_falsey end end end -- cgit v1.2.1 From deb474b4137c8ab4ce16f4d46e011be593f0de60 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 6 Jul 2017 11:55:56 +0200 Subject: extract common method --- lib/gitlab/gpg.rb | 22 +++++++++------------- spec/lib/gitlab/gpg_spec.rb | 29 +++++++++++++++++++++-------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/lib/gitlab/gpg.rb b/lib/gitlab/gpg.rb index 258901bb238..582347019e5 100644 --- a/lib/gitlab/gpg.rb +++ b/lib/gitlab/gpg.rb @@ -8,10 +8,8 @@ module Gitlab def add(key) GPGME::Key.import(key) end - end - def fingerprints_from_key(key) - using_tmp_keychain do + def fingerprints_from_key(key) import = GPGME::Key.import(key) return [] if import.imported == 0 @@ -20,13 +18,15 @@ module Gitlab end end - def primary_keyids_from_key(key) + def fingerprints_from_key(key) using_tmp_keychain do - import = GPGME::Key.import(key) - - return [] if import.imported == 0 + CurrentKeyChain.fingerprints_from_key(key) + end + end - fingerprints = import.imports.map(&:fingerprint) + def primary_keyids_from_key(key) + using_tmp_keychain do + fingerprints = CurrentKeyChain.fingerprints_from_key(key) GPGME::Key.find(:public, fingerprints).map { |raw_key| raw_key.primary_subkey.keyid } end @@ -34,11 +34,7 @@ module Gitlab def emails_from_key(key) using_tmp_keychain do - import = GPGME::Key.import(key) - - return [] if import.imported == 0 - - fingerprints = import.imports.map(&:fingerprint) + fingerprints = CurrentKeyChain.fingerprints_from_key(key) GPGME::Key.find(:public, fingerprints).flat_map { |raw_key| raw_key.uids.map(&:email) } end diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index 497fbeab5d5..ebb7720eaea 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -2,16 +2,15 @@ require 'rails_helper' describe Gitlab::Gpg do describe '.fingerprints_from_key' do - it 'returns the fingerprint' do - expect( - described_class.fingerprints_from_key(GpgHelpers::User1.public_key) - ).to eq [GpgHelpers::User1.fingerprint] + before do + # make sure that each method is using the temporary keychain + expect(described_class).to receive(:using_tmp_keychain).and_call_original end - it 'returns an empty array when the key is invalid' do - expect( - described_class.fingerprints_from_key('bogus') - ).to eq [] + it 'returns CurrentKeyChain.fingerprints_from_key' do + expect(Gitlab::Gpg::CurrentKeyChain).to receive(:fingerprints_from_key).with(GpgHelpers::User1.public_key) + + described_class.fingerprints_from_key(GpgHelpers::User1.public_key) end end @@ -65,4 +64,18 @@ describe Gitlab::Gpg::CurrentKeyChain do ) end end + + describe '.fingerprints_from_key' do + it 'returns the fingerprint' do + expect( + described_class.fingerprints_from_key(GpgHelpers::User1.public_key) + ).to eq [GpgHelpers::User1.fingerprint] + end + + it 'returns an empty array when the key is invalid' do + expect( + described_class.fingerprints_from_key('bogus') + ).to eq [] + end + end end -- cgit v1.2.1 From 3729c3a7c7cdfeed7a0fc363d18a67e9956bdf07 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 6 Jul 2017 16:30:43 +0200 Subject: use the correct flex classes on the commits list --- app/views/projects/commits/_commit.html.haml | 4 ++-- app/views/projects/commits/_commits.html.haml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index 5f67727514a..b7f18d44838 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -9,7 +9,7 @@ - cache_key.push(commit.status(ref)) if commit.status(ref) = cache(cache_key, expires_in: 1.day) do - %li.commit.flex-list.js-toggle-container{ id: "commit-#{commit.short_id}" } + %li.commit.flex-row.js-toggle-container{ id: "commit-#{commit.short_id}" } .avatar-cell.hidden-xs = author_avatar(commit, size: 36) @@ -36,7 +36,7 @@ #{ commit_text.html_safe } - .commit-actions.flex-row.hidden-xs + .commit-actions.hidden-xs - if commit.status(ref) = render_commit_status(commit, ref: ref) = render partial: 'projects/commit/signature', object: commit.signature diff --git a/app/views/projects/commits/_commits.html.haml b/app/views/projects/commits/_commits.html.haml index c764e35dd2a..d14897428d0 100644 --- a/app/views/projects/commits/_commits.html.haml +++ b/app/views/projects/commits/_commits.html.haml @@ -7,7 +7,7 @@ %span.commits-count= n_("%d commit", "%d commits", commits.count) % commits.count %li.commits-row{ data: { day: day } } - %ul.content-list.commit-list + %ul.content-list.commit-list.flex-list = render partial: 'projects/commits/commit', collection: commits, locals: { project: project, ref: ref } - if hidden > 0 -- cgit v1.2.1 From 8ccce9d54541de5cbc8e5ce4a33fcefd402bdda4 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 6 Jul 2017 16:36:57 +0200 Subject: use existing status-box css class for gpg badge --- app/assets/stylesheets/pages/commits.scss | 16 +++++++++------- .../projects/commit/_invalid_signature_badge.html.haml | 2 +- app/views/projects/commit/_signature_badge.html.haml | 6 +++--- .../projects/commit/_valid_signature_badge.html.haml | 8 ++++---- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index b6e9053fbce..16a8c399bc6 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -284,22 +284,24 @@ } } -.gpg-badge { +.gpg-status-box { &.valid { color: $brand-success; + border: 1px solid $brand-success; } &.invalid { color: $gray; + border: 1px solid $gray; } } -.gpg-badge-popover-title { +.gpg-popover-title { display: inline; font-weight: normal; } -.gpg-badge-popover-icon { +.gpg-popover-icon { float: left; font-size: 35px; line-height: 35px; @@ -315,12 +317,12 @@ } } -.gpg-badge-popover-user-link { +.gpg-popover-user-link { text-decoration: none; color: $gl-text-color; } -.gpg-badge-popover-avatar { +.gpg-popover-avatar { float: left; margin-bottom: $gl-padding; @@ -329,11 +331,11 @@ } } -.gpg-badge-popover-username { +.gpg-popover-username { font-weight: bold; } -.commit .gpg-badge-popover-help-link { +.commit .gpg-popover-help-link { display: block; color: $link-color; } diff --git a/app/views/projects/commit/_invalid_signature_badge.html.haml b/app/views/projects/commit/_invalid_signature_badge.html.haml index 29c787bd324..24b6040dcbb 100644 --- a/app/views/projects/commit/_invalid_signature_badge.html.haml +++ b/app/views/projects/commit/_invalid_signature_badge.html.haml @@ -1,5 +1,5 @@ - title = capture do - %i{ class: 'fa fa-question-circle gpg-badge-popover-icon invalid', 'aria-hidden' => 'true' } + %i{ class: 'fa fa-question-circle gpg-popover-icon invalid', 'aria-hidden' => 'true' } This commit was signed with an unverified signature. - locals = { signature: signature, title: title, label: 'Unverified', css_classes: ['invalid'] } diff --git a/app/views/projects/commit/_signature_badge.html.haml b/app/views/projects/commit/_signature_badge.html.haml index 2e046c1f684..88eb0505424 100644 --- a/app/views/projects/commit/_signature_badge.html.haml +++ b/app/views/projects/commit/_signature_badge.html.haml @@ -1,7 +1,7 @@ -- css_classes = %w(btn btn-xs gpg-badge) + css_classes +- css_classes = %w(btn status-box gpg-status-box) + css_classes - title = capture do - .gpg-badge-popover-title + .gpg-popover-title = title - content = capture do @@ -11,7 +11,7 @@ GPG key ID: = signature.gpg_key_primary_keyid - = link_to('Learn about signing commits', help_page_path('workflow/gpg_signed_commits/index.md'), class: 'gpg-badge-popover-help-link') + = link_to('Learn about signing commits', help_page_path('workflow/gpg_signed_commits/index.md'), class: 'gpg-popover-help-link') %button{ class: css_classes, data: { toggle: 'popover', html: 'true', placement: 'auto bottom', title: title, content: content } } = label diff --git a/app/views/projects/commit/_valid_signature_badge.html.haml b/app/views/projects/commit/_valid_signature_badge.html.haml index 47226466b85..a94fe9ef9a1 100644 --- a/app/views/projects/commit/_valid_signature_badge.html.haml +++ b/app/views/projects/commit/_valid_signature_badge.html.haml @@ -1,15 +1,15 @@ - title = capture do - %i{ class: 'fa fa-check-circle gpg-badge-popover-icon valid', 'aria-hidden' => 'true' } + %i{ class: 'fa fa-check-circle gpg-popover-icon valid', 'aria-hidden' => 'true' } This commit was signed with a verified signature. - content = capture do - gpg_key = signature.gpg_key - = link_to user_path(gpg_key.user), class: 'gpg-badge-popover-user-link' do - .gpg-badge-popover-avatar + = link_to user_path(gpg_key.user), class: 'gpg-popover-user-link' do + .gpg-popover-avatar = user_avatar_without_link(user: signature.gpg_key.user, size: 32) - .gpg-badge-popover-username + .gpg-popover-username = gpg_key.user.username %div= gpg_key.user.name -- cgit v1.2.1 From 4c5d4a69f0b5a813d2cb53e6f9af925cd3f9e8cb Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Mon, 10 Jul 2017 10:02:41 +0200 Subject: improve spacing / alignments in gpg popup --- app/assets/stylesheets/pages/commits.scss | 26 +++++++--------------- .../commit/_invalid_signature_badge.html.haml | 3 ++- .../projects/commit/_signature_badge.html.haml | 8 +++---- .../commit/_valid_signature_badge.html.haml | 12 +++++----- spec/features/commits_spec.rb | 14 ++++++------ 5 files changed, 27 insertions(+), 36 deletions(-) diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 16a8c399bc6..62a1296f77e 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -296,16 +296,16 @@ } } -.gpg-popover-title { - display: inline; +.gpg-popover-status { + display: flex; + align-items: center; font-weight: normal; + line-height: 1.5; } .gpg-popover-icon { - float: left; font-size: 35px; - line-height: 35px; - width: 32px; + // same margin as .s32.avatar margin-right: $btn-side-margin; &.valid { @@ -318,23 +318,13 @@ } .gpg-popover-user-link { + display: flex; + align-items: center; + margin-bottom: $gl-padding / 2; text-decoration: none; color: $gl-text-color; } -.gpg-popover-avatar { - float: left; - margin-bottom: $gl-padding; - - .avatar { - margin-left: 0; - } -} - -.gpg-popover-username { - font-weight: bold; -} - .commit .gpg-popover-help-link { display: block; color: $link-color; diff --git a/app/views/projects/commit/_invalid_signature_badge.html.haml b/app/views/projects/commit/_invalid_signature_badge.html.haml index 24b6040dcbb..0e94d0b2d59 100644 --- a/app/views/projects/commit/_invalid_signature_badge.html.haml +++ b/app/views/projects/commit/_invalid_signature_badge.html.haml @@ -1,6 +1,7 @@ - title = capture do %i{ class: 'fa fa-question-circle gpg-popover-icon invalid', 'aria-hidden' => 'true' } - This commit was signed with an unverified signature. + %div + This commit was signed with an unverified signature. - locals = { signature: signature, title: title, label: 'Unverified', css_classes: ['invalid'] } diff --git a/app/views/projects/commit/_signature_badge.html.haml b/app/views/projects/commit/_signature_badge.html.haml index 88eb0505424..8e09a9333aa 100644 --- a/app/views/projects/commit/_signature_badge.html.haml +++ b/app/views/projects/commit/_signature_badge.html.haml @@ -1,17 +1,17 @@ - css_classes = %w(btn status-box gpg-status-box) + css_classes - title = capture do - .gpg-popover-title + .gpg-popover-status = title - content = capture do .clearfix = content - GPG key ID: + GPG Key ID: = signature.gpg_key_primary_keyid - = link_to('Learn about signing commits', help_page_path('workflow/gpg_signed_commits/index.md'), class: 'gpg-popover-help-link') + = link_to('Learn more about signing commits', help_page_path('workflow/gpg_signed_commits/index.md'), class: 'gpg-popover-help-link') -%button{ class: css_classes, data: { toggle: 'popover', html: 'true', placement: 'auto bottom', title: title, content: content } } +%button{ class: css_classes, data: { toggle: 'popover', html: 'true', placement: 'auto top', title: title, content: content } } = label diff --git a/app/views/projects/commit/_valid_signature_badge.html.haml b/app/views/projects/commit/_valid_signature_badge.html.haml index a94fe9ef9a1..d51b99fe591 100644 --- a/app/views/projects/commit/_valid_signature_badge.html.haml +++ b/app/views/projects/commit/_valid_signature_badge.html.haml @@ -1,18 +1,18 @@ - title = capture do %i{ class: 'fa fa-check-circle gpg-popover-icon valid', 'aria-hidden' => 'true' } - This commit was signed with a verified signature. + %div + This commit was signed with a verified signature. - content = capture do - gpg_key = signature.gpg_key = link_to user_path(gpg_key.user), class: 'gpg-popover-user-link' do - .gpg-popover-avatar + %div = user_avatar_without_link(user: signature.gpg_key.user, size: 32) - .gpg-popover-username - = gpg_key.user.username - - %div= gpg_key.user.name + %div + %strong= gpg_key.user.username + %div= gpg_key.user.name - locals = { signature: signature, title: title, content: content, label: 'Verified', css_classes: ['valid'] } diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 709df6336fe..74eaafc9000 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -272,18 +272,18 @@ describe 'Commits' do sign_in(user) visit namespace_project_commits_path(project.namespace, project, :'signed-commits') + click_on 'Unverified', match: :first + within '.popover' do + expect(page).to have_content 'This commit was signed with an unverified signature.' + expect(page).to have_content "GPG Key ID: #{GpgHelpers::User2.primary_keyid}" + end + click_on 'Verified' within '.popover' do expect(page).to have_content 'This commit was signed with a verified signature.' expect(page).to have_content 'nannie.bernhard' expect(page).to have_content 'Nannie Bernhard' - expect(page).to have_content "GPG key ID: #{GpgHelpers::User1.primary_keyid}" - end - - click_on 'Unverified', match: :first - within '.popover' do - expect(page).to have_content 'This commit was signed with an unverified signature.' - expect(page).to have_content "GPG key ID: #{GpgHelpers::User2.primary_keyid}" + expect(page).to have_content "GPG Key ID: #{GpgHelpers::User1.primary_keyid}" end end end -- cgit v1.2.1 From e63b693f28bf752f617bd0aa2f375db701d1600a Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Mon, 10 Jul 2017 13:19:50 +0200 Subject: generate gpg signature on push --- app/services/git_push_service.rb | 8 ++++ app/workers/create_gpg_signature_worker.rb | 20 ++++++++ config/sidekiq_queues.yml | 1 + spec/services/git_push_service_spec.rb | 18 +++++++ spec/workers/create_gpg_signature_worker_spec.rb | 61 ++++++++++++++++++++++++ 5 files changed, 108 insertions(+) create mode 100644 app/workers/create_gpg_signature_worker.rb create mode 100644 spec/workers/create_gpg_signature_worker_spec.rb diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index 20d1fb29289..bb7680c5054 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -56,6 +56,8 @@ class GitPushService < BaseService perform_housekeeping update_caches + + update_signatures end def update_gitattributes @@ -80,6 +82,12 @@ class GitPushService < BaseService ProjectCacheWorker.perform_async(@project.id, types, [:commit_count, :repository_size]) end + def update_signatures + @push_commits.each do |commit| + CreateGpgSignatureWorker.perform_async(commit.sha, @project.id) + end + end + # Schedules processing of commit messages. def process_commit_messages default = is_default_branch? diff --git a/app/workers/create_gpg_signature_worker.rb b/app/workers/create_gpg_signature_worker.rb new file mode 100644 index 00000000000..6fbd6e1a3f3 --- /dev/null +++ b/app/workers/create_gpg_signature_worker.rb @@ -0,0 +1,20 @@ +class CreateGpgSignatureWorker + include Sidekiq::Worker + include DedicatedSidekiqQueue + + def perform(commit_sha, project_id) + project = Project.find_by(id: project_id) + + unless project + return Rails.logger.error("CreateGpgSignatureWorker: couldn't find project with ID=#{project_id}, skipping job") + end + + commit = project.commit(commit_sha) + + unless commit + return Rails.logger.error("CreateGpgSignatureWorker: couldn't find commit with commit_sha=#{commit_sha}, skipping job") + end + + commit.signature + end +end diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml index cf0f5719683..7496bfa4fbb 100644 --- a/config/sidekiq_queues.yml +++ b/config/sidekiq_queues.yml @@ -30,6 +30,7 @@ - [emails_on_push, 2] - [mailers, 2] - [invalid_gpg_signature_update, 2] + - [create_gpg_signature, 2] - [upload_checksum, 1] - [use_key, 1] - [repository_fork, 1] diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index f801506f1b6..34cd44460c6 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -681,6 +681,24 @@ describe GitPushService, services: true do end end + describe '#update_signatures' do + let(:service) do + described_class.new( + project, + user, + oldrev: sample_commit.parent_id, + newrev: sample_commit.id, + ref: 'refs/heads/master' + ) + end + + it 'calls CreateGpgSignatureWorker.perform_async for each commit' do + expect(CreateGpgSignatureWorker).to receive(:perform_async).with(sample_commit.id, project.id) + + execute_service(project, user, @oldrev, @newrev, @ref) + end + end + def execute_service(project, user, oldrev, newrev, ref) service = described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref ) service.execute diff --git a/spec/workers/create_gpg_signature_worker_spec.rb b/spec/workers/create_gpg_signature_worker_spec.rb new file mode 100644 index 00000000000..a23f0d6c34a --- /dev/null +++ b/spec/workers/create_gpg_signature_worker_spec.rb @@ -0,0 +1,61 @@ +require 'spec_helper' + +describe CreateGpgSignatureWorker do + context 'when GpgKey is found' do + it 'calls Commit#signature' do + commit_sha = '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' + project = create :project + commit = instance_double(Commit) + + allow(Project).to receive(:find_by).with(id: project.id).and_return(project) + allow(project).to receive(:commit).with(commit_sha).and_return(commit) + + expect(commit).to receive(:signature) + + described_class.new.perform(commit_sha, project.id) + end + end + + context 'when Commit is not found' do + let(:nonexisting_commit_sha) { 'bogus' } + let(:project) { create :project } + + it 'logs CreateGpgSignatureWorker process skipping' do + expect(Rails.logger).to receive(:error) + .with("CreateGpgSignatureWorker: couldn't find commit with commit_sha=bogus, skipping job") + + described_class.new.perform(nonexisting_commit_sha, project.id) + end + + it 'does not raise errors' do + expect { described_class.new.perform(nonexisting_commit_sha, project.id) }.not_to raise_error + end + + it 'does not call Commit#signature' do + expect_any_instance_of(Commit).not_to receive(:signature) + + described_class.new.perform(nonexisting_commit_sha, project.id) + end + end + + context 'when Project is not found' do + let(:nonexisting_project_id) { -1 } + + it 'logs CreateGpgSignatureWorker process skipping' do + expect(Rails.logger).to receive(:error) + .with("CreateGpgSignatureWorker: couldn't find project with ID=-1, skipping job") + + described_class.new.perform(anything, nonexisting_project_id) + end + + it 'does not raise errors' do + expect { described_class.new.perform(anything, nonexisting_project_id) }.not_to raise_error + end + + it 'does not call Commit#signature' do + expect_any_instance_of(Commit).not_to receive(:signature) + + described_class.new.perform(anything, nonexisting_project_id) + end + end +end -- cgit v1.2.1 From 71d884ad2d6eb4a877d2bfe163baeae0b7ddbac6 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 11 Jul 2017 13:35:57 +0200 Subject: don't use assignment in if condition --- app/workers/invalid_gpg_signature_update_worker.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/workers/invalid_gpg_signature_update_worker.rb b/app/workers/invalid_gpg_signature_update_worker.rb index 277dd604aa8..c0bec3c9689 100644 --- a/app/workers/invalid_gpg_signature_update_worker.rb +++ b/app/workers/invalid_gpg_signature_update_worker.rb @@ -3,10 +3,12 @@ class InvalidGpgSignatureUpdateWorker include DedicatedSidekiqQueue def perform(gpg_key_id) - if gpg_key = GpgKey.find_by(id: gpg_key_id) - Gitlab::Gpg::InvalidGpgSignatureUpdater.new(gpg_key).run - else - Rails.logger.error("InvalidGpgSignatureUpdateWorker: couldn't find gpg_key with ID=#{gpg_key_id}, skipping job") + gpg_key = GpgKey.find_by(id: gpg_key_id) + + unless gpg_key + return Rails.logger.error("InvalidGpgSignatureUpdateWorker: couldn't find gpg_key with ID=#{gpg_key_id}, skipping job") end + + Gitlab::Gpg::InvalidGpgSignatureUpdater.new(gpg_key).run end end -- cgit v1.2.1 From e5c9c714bd932ebb8d458c2d52535582eb48b9ee Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 11 Jul 2017 13:47:31 +0200 Subject: add notfound icon (question mark) --- app/views/shared/icons/_icon_status_notfound_borderless.svg | 1 + 1 file changed, 1 insertion(+) create mode 100644 app/views/shared/icons/_icon_status_notfound_borderless.svg diff --git a/app/views/shared/icons/_icon_status_notfound_borderless.svg b/app/views/shared/icons/_icon_status_notfound_borderless.svg new file mode 100644 index 00000000000..e58bd264ef8 --- /dev/null +++ b/app/views/shared/icons/_icon_status_notfound_borderless.svg @@ -0,0 +1 @@ + -- cgit v1.2.1 From f1e6a9c8323ec0a918aa9a170903d1d6ac7af5e6 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 11 Jul 2017 14:12:06 +0200 Subject: use svg icons for gpg popovers --- app/assets/stylesheets/pages/commits.scss | 20 +++++++++++++++++--- .../commit/_invalid_signature_badge.html.haml | 3 ++- .../projects/commit/_valid_signature_badge.html.haml | 3 ++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 62a1296f77e..4c66515581a 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -304,16 +304,30 @@ } .gpg-popover-icon { - font-size: 35px; // same margin as .s32.avatar margin-right: $btn-side-margin; &.valid { - color: $brand-success; + svg { + border: 1px solid $brand-success; + + fill: $brand-success; + } } &.invalid { - color: $gray; + svg { + border: 1px solid $gray; + + fill: $gray; + } + } + + svg { + width: 32px; + height: 32px; + border-radius: 50%; + vertical-align: middle; } } diff --git a/app/views/projects/commit/_invalid_signature_badge.html.haml b/app/views/projects/commit/_invalid_signature_badge.html.haml index 0e94d0b2d59..3a73aae9d95 100644 --- a/app/views/projects/commit/_invalid_signature_badge.html.haml +++ b/app/views/projects/commit/_invalid_signature_badge.html.haml @@ -1,5 +1,6 @@ - title = capture do - %i{ class: 'fa fa-question-circle gpg-popover-icon invalid', 'aria-hidden' => 'true' } + .gpg-popover-icon.invalid + = render 'shared/icons/icon_status_notfound_borderless.svg' %div This commit was signed with an unverified signature. diff --git a/app/views/projects/commit/_valid_signature_badge.html.haml b/app/views/projects/commit/_valid_signature_badge.html.haml index d51b99fe591..4db62418d0d 100644 --- a/app/views/projects/commit/_valid_signature_badge.html.haml +++ b/app/views/projects/commit/_valid_signature_badge.html.haml @@ -1,5 +1,6 @@ - title = capture do - %i{ class: 'fa fa-check-circle gpg-popover-icon valid', 'aria-hidden' => 'true' } + .gpg-popover-icon.valid + = render 'shared/icons/icon_status_success_borderless.svg' %div This commit was signed with a verified signature. -- cgit v1.2.1 From 111edaa9f75f402cc18c2bec5cab9aa6615d9c4d Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 11 Jul 2017 14:25:16 +0200 Subject: use lighter gray for unverified gpg signature --- app/assets/stylesheets/pages/commits.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 4c66515581a..41c44a8560d 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -292,7 +292,7 @@ &.invalid { color: $gray; - border: 1px solid $gray; + border: 1px solid $common-gray-light; } } @@ -317,9 +317,9 @@ &.invalid { svg { - border: 1px solid $gray; + border: 1px solid $common-gray-light; - fill: $gray; + fill: $common-gray-light; } } -- cgit v1.2.1 From 027309eb2ae54614a2ee1a0ca9e4cea76a86b94b Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 12 Jul 2017 07:59:28 +0200 Subject: user may now revoke a gpg key other than just removing a key, which doesn't affect the verified state of a commit, revoking a key unverifies all signed commits. --- app/controllers/profiles/gpg_keys_controller.rb | 10 +++++++++ app/models/gpg_key.rb | 11 ++++++++++ app/views/profiles/gpg_keys/_key.html.haml | 8 ++++++-- config/routes/profile.rb | 6 +++++- doc/workflow/gpg_signed_commits/index.md | 27 +++++++++++++++++++++++++ spec/features/profiles/gpg_keys_spec.rb | 16 +++++++++++++++ spec/models/gpg_key_spec.rb | 27 +++++++++++++++++++++++++ 7 files changed, 102 insertions(+), 3 deletions(-) diff --git a/app/controllers/profiles/gpg_keys_controller.rb b/app/controllers/profiles/gpg_keys_controller.rb index b04c14a6993..3e75247769d 100644 --- a/app/controllers/profiles/gpg_keys_controller.rb +++ b/app/controllers/profiles/gpg_keys_controller.rb @@ -25,6 +25,16 @@ class Profiles::GpgKeysController < Profiles::ApplicationController end end + def revoke + @gpp_key = current_user.gpg_keys.find(params[:id]) + @gpp_key.revoke + + respond_to do |format| + format.html { redirect_to profile_gpg_keys_url, status: 302 } + format.js { head :ok } + end + end + private def gpg_key_params diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 050245bd502..1977023536e 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -58,6 +58,17 @@ class GpgKey < ActiveRecord::Base InvalidGpgSignatureUpdateWorker.perform_async(self.id) end + def revoke + GpgSignature.where(gpg_key: self, valid_signature: true).find_each do |gpg_signature| + gpg_signature.update_attributes!( + gpg_key: nil, + valid_signature: false + ) + end + + destroy + end + private def extract_fingerprint diff --git a/app/views/profiles/gpg_keys/_key.html.haml b/app/views/profiles/gpg_keys/_key.html.haml index b4b9aa07190..86e2510d22f 100644 --- a/app/views/profiles/gpg_keys/_key.html.haml +++ b/app/views/profiles/gpg_keys/_key.html.haml @@ -3,13 +3,17 @@ = icon 'key', class: "settings-list-icon hidden-xs" .key-list-item-info - key.emails_with_verified_status.map do |email, verified| + = email = verified_email_badge(email, verified) .description - = key.fingerprint + %code= key.fingerprint .pull-right %span.key-created-at created #{time_ago_with_tooltip(key.created_at)} - = link_to profile_gpg_key_path(key), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-transparent prepend-left-10" do + = link_to profile_gpg_key_path(key), data: { confirm: 'Are you sure? Removing this GPG key does not affect already signed commits.' }, method: :delete, class: "btn btn-danger prepend-left-10" do %span.sr-only Remove = icon('trash') + = link_to revoke_profile_gpg_key_path(key), data: { confirm: 'Are you sure? All commits that were signed with this GPG key will be unverified.' }, method: :put, class: "btn btn-danger prepend-left-10" do + %span.sr-only Revoke + Revoke diff --git a/config/routes/profile.rb b/config/routes/profile.rb index 00388b9c0cd..3e4e6111ab8 100644 --- a/config/routes/profile.rb +++ b/config/routes/profile.rb @@ -23,7 +23,11 @@ resource :profile, only: [:show, :update] do end resource :preferences, only: [:show, :update] resources :keys, only: [:index, :show, :create, :destroy] - resources :gpg_keys, only: [:index, :create, :destroy] + resources :gpg_keys, only: [:index, :create, :destroy] do + member do + put :revoke + end + end resources :emails, only: [:index, :create, :destroy] resources :chat_names, only: [:index, :new, :create, :destroy] do collection do diff --git a/doc/workflow/gpg_signed_commits/index.md b/doc/workflow/gpg_signed_commits/index.md index f7f5492c35a..7d5762d2b9d 100644 --- a/doc/workflow/gpg_signed_commits/index.md +++ b/doc/workflow/gpg_signed_commits/index.md @@ -42,6 +42,33 @@ For a signature to be verified two prerequisites need to be met: Once you add a key, you cannot edit it, only remove it. In case the paste didn't work, you will have to remove the offending key and re-add it. +## Remove a GPG key + +1. On the upper right corner, click on your avatar and go to your **Settings**. + +1. Navigate to the **GPG keys** tab. + +1. Click on the trash icon besides the GPG key you want to delete. + +>**Note:** +Removing a key **does not unverify** already signed commits. Commits that were +verified by using this key will stay verified. Only unpushed commits will stay +unverified once you remove this key. + +## Revoke a GPG key + +1. On the upper right corner, click on your avatar and go to your **Settings**. + +1. Navigate to the **GPG keys** tab. + +1. Click on **Revoke** besides the GPG key you want to delete. + +>**Note:** +Revoking a key **unverifies** already signed commits. Commits that were +verified by using this key will change to an unverified state. Future commits +will also stay unverified once you revoke this key. This action should be used +in case your key has been compromised. + ## Verifying commits 1. Within a project navigate to the **Commits** tag. Signed commits will show a diff --git a/spec/features/profiles/gpg_keys_spec.rb b/spec/features/profiles/gpg_keys_spec.rb index 350126523b0..6edc482b47e 100644 --- a/spec/features/profiles/gpg_keys_spec.rb +++ b/spec/features/profiles/gpg_keys_spec.rb @@ -39,4 +39,20 @@ feature 'Profile > GPG Keys' do expect(page).to have_content('Your GPG keys (0)') end + + scenario 'User revokes a key via the key index' do + gpg_key = create :gpg_key, user: user, key: GpgHelpers::User2.public_key + gpg_signature = create :gpg_signature, gpg_key: gpg_key, valid_signature: true + + visit profile_gpg_keys_path + + click_link('Revoke') + + expect(page).to have_content('Your GPG keys (0)') + + expect(gpg_signature.reload).to have_attributes( + valid_signature: false, + gpg_key: nil + ) + end end diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index ffbf8760e86..ddd0bbfb9ba 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -95,4 +95,31 @@ describe GpgKey do should_email(user) end end + + describe '#revoke' do + it 'invalidates all associated gpg signatures and destroys the key' do + gpg_key = create :gpg_key + gpg_signature = create :gpg_signature, valid_signature: true, gpg_key: gpg_key + + unrelated_gpg_key = create :gpg_key, key: GpgHelpers::User2.public_key + unrelated_gpg_signature = create :gpg_signature, valid_signature: true, gpg_key: unrelated_gpg_key + + gpg_key.revoke + + expect(gpg_signature.reload).to have_attributes( + valid_signature: false, + gpg_key: nil + ) + + expect(gpg_key.destroyed?).to be true + + # unrelated signature is left untouched + expect(unrelated_gpg_signature.reload).to have_attributes( + valid_signature: true, + gpg_key: unrelated_gpg_key + ) + + expect(unrelated_gpg_key.destroyed?).to be false + end + end end -- cgit v1.2.1 From 506836a695ae40ff200add21c639f3d13aaee9e9 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 13 Jul 2017 10:53:19 +0200 Subject: unify commit signature colors with pipeline status --- app/assets/stylesheets/framework/mixins.scss | 26 ++++++++++++++++++++++++++ app/assets/stylesheets/pages/commits.scss | 8 ++++---- app/assets/stylesheets/pages/status.scss | 21 +-------------------- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss index 3a98332e46c..6f91d11b369 100644 --- a/app/assets/stylesheets/framework/mixins.scss +++ b/app/assets/stylesheets/framework/mixins.scss @@ -118,3 +118,29 @@ @content; } } + +/* + * Mixin for status badges, as used for pipelines and commit signatures + */ +@mixin status-color($color-light, $color-main, $color-dark) { + color: $color-main; + border-color: $color-main; + + &:not(span):hover { + background-color: $color-light; + color: $color-dark; + border-color: $color-dark; + + svg { + fill: $color-dark; + } + } + + svg { + fill: $color-main; + } +} + +@mixin green-status-color { + @include status-color($green-50, $green-500, $green-700); +} diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 41c44a8560d..cd9f2d787c5 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -284,15 +284,15 @@ } } + .gpg-status-box { &.valid { - color: $brand-success; - border: 1px solid $brand-success; + @include green-status-color; } &.invalid { - color: $gray; - border: 1px solid $common-gray-light; + @include status-color($gray-dark, $gray, $common-gray-dark); + border-color: $common-gray-light; } } diff --git a/app/assets/stylesheets/pages/status.scss b/app/assets/stylesheets/pages/status.scss index 67ad1ae60af..36f622db136 100644 --- a/app/assets/stylesheets/pages/status.scss +++ b/app/assets/stylesheets/pages/status.scss @@ -1,22 +1,3 @@ -@mixin status-color($color-light, $color-main, $color-dark) { - color: $color-main; - border-color: $color-main; - - &:not(span):hover { - background-color: $color-light; - color: $color-dark; - border-color: $color-dark; - - svg { - fill: $color-dark; - } - } - - svg { - fill: $color-main; - } -} - .ci-status { padding: 2px 7px 4px; border: 1px solid $gray-darker; @@ -41,7 +22,7 @@ } &.ci-success { - @include status-color($green-50, $green-500, $green-700); + @include green-status-color; } &.ci-canceled, -- cgit v1.2.1 From 9be17322961775ce9ae4aad8cece6db672f059ce Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Thu, 27 Jul 2017 15:44:13 +0200 Subject: add comment explaining use of shell commands and file operations in the same methods --- lib/gitlab/health_checks/fs_shards_check.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/gitlab/health_checks/fs_shards_check.rb b/lib/gitlab/health_checks/fs_shards_check.rb index a4740e9e9b7..9e91c135956 100644 --- a/lib/gitlab/health_checks/fs_shards_check.rb +++ b/lib/gitlab/health_checks/fs_shards_check.rb @@ -77,6 +77,13 @@ module Gitlab storages_paths&.dig(storage_name, 'path') end + # All below test methods use shell commands to perform actions on storage volumes. + # In case a storage volume have connectivity problems causing pure Ruby IO operation to wait indefinitely, + # we can rely on shell commands to be terminated once `timeout` kills them. + # + # However we also fallback to pure Ruby file operations in case a specific shell command is missing + # so we are still able to perform healthchecks and gather metrics from such system. + def delete_test_file(tmp_path) _, status = exec_with_timeout(%W{ rm -f #{tmp_path} }) status.zero? -- cgit v1.2.1 From cd01e82873b3cd471203dbf557c71571fd683d16 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 13 Jul 2017 15:22:15 +0200 Subject: store gpg user name and email on the signature --- app/models/gpg_key.rb | 16 ++++++++----- ...4235_add_gpg_key_user_info_to_gpg_signatures.rb | 11 +++++++++ db/schema.rb | 2 ++ lib/gitlab/gpg.rb | 6 +++-- lib/gitlab/gpg/commit.rb | 21 ++++++++++++----- spec/lib/gitlab/gpg/commit_spec.rb | 6 +++++ spec/lib/gitlab/gpg_spec.rb | 14 +++++++----- spec/models/gpg_key_spec.rb | 26 +++++++++++++++++++--- spec/support/gpg_helpers.rb | 8 +++++++ 9 files changed, 88 insertions(+), 22 deletions(-) create mode 100644 db/migrate/20170713104235_add_gpg_key_user_info_to_gpg_signatures.rb diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 1977023536e..31a25f3e2f0 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -37,15 +37,21 @@ class GpgKey < ActiveRecord::Base write_attribute(:key, value) end - def emails - @emails ||= Gitlab::Gpg.emails_from_key(key) + def user_infos + @user_infos ||= Gitlab::Gpg.user_infos_from_key(key) + end + + def verified_user_infos + user_infos.select do |user_info| + user_info[:email] == user.email + end end def emails_with_verified_status - emails.map do |email| + user_infos.map do |user_info| [ - email, - email == user.email + user_info[:email], + user_info[:email] == user.email ] end.to_h end diff --git a/db/migrate/20170713104235_add_gpg_key_user_info_to_gpg_signatures.rb b/db/migrate/20170713104235_add_gpg_key_user_info_to_gpg_signatures.rb new file mode 100644 index 00000000000..0e51a86e64c --- /dev/null +++ b/db/migrate/20170713104235_add_gpg_key_user_info_to_gpg_signatures.rb @@ -0,0 +1,11 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddGpgKeyUserInfoToGpgSignatures < ActiveRecord::Migration + DOWNTIME = false + + def change + add_column :gpg_signatures, :gpg_key_user_name, :string + add_column :gpg_signatures, :gpg_key_user_email, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 53b1e83ddab..b76a5efbbd7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -560,6 +560,8 @@ ActiveRecord::Schema.define(version: 20170725145659) do t.boolean "valid_signature" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.string "gpg_key_user_name" + t.string "gpg_key_user_email" end add_index "gpg_signatures", ["commit_sha"], name: "index_gpg_signatures_on_commit_sha", using: :btree diff --git a/lib/gitlab/gpg.rb b/lib/gitlab/gpg.rb index 582347019e5..e1d1724295a 100644 --- a/lib/gitlab/gpg.rb +++ b/lib/gitlab/gpg.rb @@ -32,11 +32,13 @@ module Gitlab end end - def emails_from_key(key) + def user_infos_from_key(key) using_tmp_keychain do fingerprints = CurrentKeyChain.fingerprints_from_key(key) - GPGME::Key.find(:public, fingerprints).flat_map { |raw_key| raw_key.uids.map(&:email) } + GPGME::Key.find(:public, fingerprints).flat_map do |raw_key| + raw_key.uids.map { |uid| { name: uid.name, email: uid.email } } + end end end diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb index 50e8d71bb13..55428b85207 100644 --- a/lib/gitlab/gpg/commit.rb +++ b/lib/gitlab/gpg/commit.rb @@ -26,10 +26,7 @@ module Gitlab def update_signature!(cached_signature) using_keychain do |gpg_key| - cached_signature.update_attributes!( - valid_signature: gpg_signature_valid_signature_value(gpg_key), - gpg_key: gpg_key - ) + cached_signature.update_attributes!(attributes(gpg_key)) end end @@ -59,18 +56,30 @@ module Gitlab end def create_cached_signature!(gpg_key) - GpgSignature.create!( + GpgSignature.create!(attributes(gpg_key)) + end + + def attributes(gpg_key) + user_infos = user_infos(gpg_key) + + { commit_sha: commit.sha, project: commit.project, gpg_key: gpg_key, gpg_key_primary_keyid: gpg_key&.primary_keyid || verified_signature.fingerprint, + gpg_key_user_name: user_infos[:name], + gpg_key_user_email: user_infos[:email], valid_signature: gpg_signature_valid_signature_value(gpg_key) - ) + } end def gpg_signature_valid_signature_value(gpg_key) !!(gpg_key && gpg_key.verified? && verified_signature.valid?) end + + def user_infos(gpg_key) + gpg_key&.verified_user_infos&.first || gpg_key&.user_infos&.first || {} + end end end end diff --git a/spec/lib/gitlab/gpg/commit_spec.rb b/spec/lib/gitlab/gpg/commit_spec.rb index 661956b7bb7..ddb8dd9f0f4 100644 --- a/spec/lib/gitlab/gpg/commit_spec.rb +++ b/spec/lib/gitlab/gpg/commit_spec.rb @@ -32,6 +32,8 @@ RSpec.describe Gitlab::Gpg::Commit do project: project, gpg_key: gpg_key, gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + gpg_key_user_name: GpgHelpers::User1.names.first, + gpg_key_user_email: GpgHelpers::User1.emails.first, valid_signature: true ) end @@ -67,6 +69,8 @@ RSpec.describe Gitlab::Gpg::Commit do project: project, gpg_key: gpg_key, gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + gpg_key_user_name: GpgHelpers::User1.names.first, + gpg_key_user_email: GpgHelpers::User1.emails.first, valid_signature: false ) end @@ -102,6 +106,8 @@ RSpec.describe Gitlab::Gpg::Commit do project: project, gpg_key: nil, gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + gpg_key_user_name: nil, + gpg_key_user_email: nil, valid_signature: false ) end diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index ebb7720eaea..8041518117d 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -28,16 +28,18 @@ describe Gitlab::Gpg do end end - describe '.emails_from_key' do - it 'returns the emails' do - expect( - described_class.emails_from_key(GpgHelpers::User1.public_key) - ).to eq GpgHelpers::User1.emails + describe '.user_infos_from_key' do + it 'returns the names and emails' do + user_infos = described_class.user_infos_from_key(GpgHelpers::User1.public_key) + expect(user_infos).to eq([{ + name: GpgHelpers::User1.names.first, + email: GpgHelpers::User1.emails.first + }]) end it 'returns an empty array when the key is invalid' do expect( - described_class.emails_from_key('bogus') + described_class.user_infos_from_key('bogus') ).to eq [] end end diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index ddd0bbfb9ba..06bdbb59a11 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -46,11 +46,31 @@ describe GpgKey do end end - describe '#emails' do - it 'returns the emails from the gpg key' do + describe '#user_infos' do + it 'returns the user infos from the gpg key' do gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key + expect(Gitlab::Gpg).to receive(:user_infos_from_key).with(gpg_key.key) - expect(gpg_key.emails).to eq GpgHelpers::User1.emails + gpg_key.user_infos + end + end + + describe '#verified_user_infos' do + it 'returns the user infos if it is verified' do + user = create :user, email: GpgHelpers::User1.emails.first + gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key, user: user + + expect(gpg_key.verified_user_infos).to eq([{ + name: GpgHelpers::User1.names.first, + email: GpgHelpers::User1.emails.first + }]) + end + + it 'returns an empty array if the user info is not verified' do + user = create :user, email: 'unrelated@example.com' + gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key, user: user + + expect(gpg_key.verified_user_infos).to eq([]) end end diff --git a/spec/support/gpg_helpers.rb b/spec/support/gpg_helpers.rb index f9128a629f2..96ea6f28b30 100644 --- a/spec/support/gpg_helpers.rb +++ b/spec/support/gpg_helpers.rb @@ -98,6 +98,10 @@ module GpgHelpers '5F7EA3981A5845B141ABD522CCFBE19F00AC8B1D' end + def names + ['Nannie Bernhard'] + end + def emails ['nannie.bernhard@example.com'] end @@ -187,6 +191,10 @@ module GpgHelpers '6D494CA6FC90C0CAE0910E42BF9D925F911EFD65' end + def names + ['Bette Cartwright', 'Bette Cartwright'] + end + def emails ['bette.cartwright@example.com', 'bette.cartwright@example.net'] end -- cgit v1.2.1 From c52718332cb723cc4b3035c17eec9eeb9926c8cf Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 13 Jul 2017 16:04:19 +0200 Subject: show gpg key's user info when no profile exists --- .../commit/_valid_signature_badge.html.haml | 24 ++++++++++++++++------ spec/features/commits_spec.rb | 23 ++++++++++++++++++--- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/app/views/projects/commit/_valid_signature_badge.html.haml b/app/views/projects/commit/_valid_signature_badge.html.haml index 4db62418d0d..5a451cb4055 100644 --- a/app/views/projects/commit/_valid_signature_badge.html.haml +++ b/app/views/projects/commit/_valid_signature_badge.html.haml @@ -6,14 +6,26 @@ - content = capture do - gpg_key = signature.gpg_key + - user = gpg_key&.user + - user_name = signature.gpg_key_user_name + - user_email = signature.gpg_key_user_email - = link_to user_path(gpg_key.user), class: 'gpg-popover-user-link' do - %div - = user_avatar_without_link(user: signature.gpg_key.user, size: 32) + - if user + = link_to user_path(user), class: 'gpg-popover-user-link' do + %div + = user_avatar_without_link(user: user, size: 32) - %div - %strong= gpg_key.user.username - %div= gpg_key.user.name + %div + %strong= gpg_key.user.username + %div= gpg_key.user.name + - else + = mail_to user_email do + %div + = user_avatar_without_link(user_name: user_name, user_email: user_email, size: 32) + + %div + %strong= user_name + %div= user_email - locals = { signature: signature, title: title, content: content, label: 'Verified', css_classes: ['valid'] } diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 74eaafc9000..b6b0cc7e1d3 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -263,21 +263,25 @@ describe 'Commits' do end it 'shows popover badges', :js do - user = create :user, email: GpgHelpers::User1.emails.first, username: 'nannie.bernhard', name: 'Nannie Bernhard' - project.team << [user, :master] + gpg_user = create :user, email: GpgHelpers::User1.emails.first, username: 'nannie.bernhard', name: 'Nannie Bernhard' Sidekiq::Testing.inline! do - create :gpg_key, key: GpgHelpers::User1.public_key, user: user + create :gpg_key, key: GpgHelpers::User1.public_key, user: gpg_user end + user = create :user + project.team << [user, :master] + sign_in(user) visit namespace_project_commits_path(project.namespace, project, :'signed-commits') + # unverified signature click_on 'Unverified', match: :first within '.popover' do expect(page).to have_content 'This commit was signed with an unverified signature.' expect(page).to have_content "GPG Key ID: #{GpgHelpers::User2.primary_keyid}" end + # verified and the gpg user has a gitlab profile click_on 'Verified' within '.popover' do expect(page).to have_content 'This commit was signed with a verified signature.' @@ -285,6 +289,19 @@ describe 'Commits' do expect(page).to have_content 'Nannie Bernhard' expect(page).to have_content "GPG Key ID: #{GpgHelpers::User1.primary_keyid}" end + + # verified and the gpg user's profile doesn't exist anymore + gpg_user.destroy! + + visit namespace_project_commits_path(project.namespace, project, :'signed-commits') + + click_on 'Verified' + within '.popover' do + expect(page).to have_content 'This commit was signed with a verified signature.' + expect(page).to have_content 'Nannie Bernhard' + expect(page).to have_content 'nannie.bernhard@example.com' + expect(page).to have_content "GPG Key ID: #{GpgHelpers::User1.primary_keyid}" + end end end end -- cgit v1.2.1 From ccf3ed4351ce45204035169c67ee7f3c01b05e81 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 13 Jul 2017 16:08:14 +0200 Subject: swap user's name and the user's username --- app/views/projects/commit/_valid_signature_badge.html.haml | 4 ++-- spec/features/commits_spec.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/projects/commit/_valid_signature_badge.html.haml b/app/views/projects/commit/_valid_signature_badge.html.haml index 5a451cb4055..db1a41bbf64 100644 --- a/app/views/projects/commit/_valid_signature_badge.html.haml +++ b/app/views/projects/commit/_valid_signature_badge.html.haml @@ -16,8 +16,8 @@ = user_avatar_without_link(user: user, size: 32) %div - %strong= gpg_key.user.username - %div= gpg_key.user.name + %strong= gpg_key.user.name + %div @#{gpg_key.user.username} - else = mail_to user_email do %div diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index b6b0cc7e1d3..9bd4b478cce 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -285,8 +285,8 @@ describe 'Commits' do click_on 'Verified' within '.popover' do expect(page).to have_content 'This commit was signed with a verified signature.' - expect(page).to have_content 'nannie.bernhard' expect(page).to have_content 'Nannie Bernhard' + expect(page).to have_content '@nannie.bernhard' expect(page).to have_content "GPG Key ID: #{GpgHelpers::User1.primary_keyid}" end -- cgit v1.2.1 From a03a6ff326300daafbd67fd32eaaa08a4b649395 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 13 Jul 2017 16:51:16 +0200 Subject: display gpg key in the popover with monospace font --- app/views/projects/commit/_signature_badge.html.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/projects/commit/_signature_badge.html.haml b/app/views/projects/commit/_signature_badge.html.haml index 8e09a9333aa..d6ece085f18 100644 --- a/app/views/projects/commit/_signature_badge.html.haml +++ b/app/views/projects/commit/_signature_badge.html.haml @@ -9,7 +9,8 @@ = content GPG Key ID: - = signature.gpg_key_primary_keyid + %span.monospace= signature.gpg_key_primary_keyid + = link_to('Learn more about signing commits', help_page_path('workflow/gpg_signed_commits/index.md'), class: 'gpg-popover-help-link') -- cgit v1.2.1 From ef97cb54ae3c62e8bc9062c7f32901520865d754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Wed, 26 Jul 2017 18:12:20 -0500 Subject: Backport some recent changes related to LDAP from EE --- app/controllers/sessions_controller.rb | 7 +------ config/initializers/omniauth.rb | 13 ++++++++----- lib/gitlab/ldap/config.rb | 6 ++++++ 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 69513f4dadc..9e743685d60 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -23,12 +23,7 @@ class SessionsController < Devise::SessionsController def new set_minimum_password_length - @ldap_servers = - if Gitlab.config.ldap.enabled - Gitlab::LDAP::Config.servers - else - [] - end + @ldap_servers = Gitlab::LDAP::Config.available_servers super end diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index a36e59c941a..56c279ffcf4 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -1,13 +1,16 @@ if Gitlab::LDAP::Config.enabled? module OmniAuth::Strategies - server = Gitlab.config.ldap.servers.values.first - klass = server['provider_class'] - const_set(klass, Class.new(LDAP)) unless klass == 'LDAP' + Gitlab::LDAP::Config.available_servers.each do |server| + # do not redeclare LDAP + next if server['provider_name'] == 'ldap' + const_set(server['provider_class'], Class.new(LDAP)) + end end OmniauthCallbacksController.class_eval do - server = Gitlab.config.ldap.servers.values.first - alias_method server['provider_name'], :ldap + Gitlab::LDAP::Config.available_servers.each do |server| + alias_method server['provider_name'], :ldap + end end end diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb index 8eda3ea03f9..c8f19cd52d5 100644 --- a/lib/gitlab/ldap/config.rb +++ b/lib/gitlab/ldap/config.rb @@ -18,6 +18,12 @@ module Gitlab Gitlab.config.ldap.servers.values end + def self.available_servers + return [] unless enabled? + + Array.wrap(servers.first) + end + def self.providers servers.map { |server| server['provider_name'] } end -- cgit v1.2.1 From 312dc89a44642050a2224c1b780054828c819fd6 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 13 Jul 2017 16:52:34 +0200 Subject: nicer email badges on the profile gpg page --- app/assets/stylesheets/pages/profile.scss | 23 ++++++++++++++++++++++ app/helpers/badges_helper.rb | 11 ----------- .../profiles/gpg_keys/_email_with_badge.html.haml | 8 ++++++++ app/views/profiles/gpg_keys/_key.html.haml | 3 +-- 4 files changed, 32 insertions(+), 13 deletions(-) delete mode 100644 app/helpers/badges_helper.rb create mode 100644 app/views/profiles/gpg_keys/_email_with_badge.html.haml diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index 22672614e0d..14ad06b0ac2 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -391,3 +391,26 @@ table.u2f-registrations { margin-bottom: 0; } } + +.gpg-email-badge { + display: inline; + margin-right: $gl-padding / 2; + + .gpg-email-badge-email { + display: inline; + margin-right: $gl-padding / 4; + } + + .label-verification-status { + border-width: 1px; + border-style: solid; + + &.verified { + @include green-status-color; + } + + &.unverified { + @include status-color($gray-dark, $gray, $common-gray-dark); + } + } +} diff --git a/app/helpers/badges_helper.rb b/app/helpers/badges_helper.rb deleted file mode 100644 index e1c8927ab54..00000000000 --- a/app/helpers/badges_helper.rb +++ /dev/null @@ -1,11 +0,0 @@ -module BadgesHelper - def verified_email_badge(email, verified) - css_classes = %w(btn btn-xs disabled) - - css_classes << 'btn-success' if verified - - content_tag 'span', class: css_classes do - "#{email} #{verified ? 'Verified' : 'Unverified'}" - end - end -end diff --git a/app/views/profiles/gpg_keys/_email_with_badge.html.haml b/app/views/profiles/gpg_keys/_email_with_badge.html.haml new file mode 100644 index 00000000000..5f7844584e1 --- /dev/null +++ b/app/views/profiles/gpg_keys/_email_with_badge.html.haml @@ -0,0 +1,8 @@ +- css_classes = %w(label label-verification-status) +- css_classes << (verified ? 'verified': 'unverified') +- text = verified ? 'Verified' : 'Unverified' + +.gpg-email-badge + .gpg-email-badge-email= email + %div{ class: css_classes } + = text diff --git a/app/views/profiles/gpg_keys/_key.html.haml b/app/views/profiles/gpg_keys/_key.html.haml index 86e2510d22f..b04981f90e3 100644 --- a/app/views/profiles/gpg_keys/_key.html.haml +++ b/app/views/profiles/gpg_keys/_key.html.haml @@ -3,8 +3,7 @@ = icon 'key', class: "settings-list-icon hidden-xs" .key-list-item-info - key.emails_with_verified_status.map do |email, verified| - = email - = verified_email_badge(email, verified) + = render partial: 'email_with_badge', locals: { email: email, verified: verified } .description %code= key.fingerprint -- cgit v1.2.1 From 8c8a9e6d3fcb529e95d76dc9a7d4e37542a2036f Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Sat, 15 Jul 2017 15:25:21 +0200 Subject: merge migrations to 1 single create per table also: * reorder table columns * no need for `add_concurrent_index` * no need for explicit index removal on `#down` --- db/migrate/20170222111732_create_gpg_keys.rb | 9 +++++-- ...20170613103429_add_primary_keyid_to_gpg_keys.rb | 17 ------------- db/migrate/20170613154149_create_gpg_signatures.rb | 29 ++++++++-------------- ...4235_add_gpg_key_user_info_to_gpg_signatures.rb | 11 -------- db/schema.rb | 14 +++++------ 5 files changed, 25 insertions(+), 55 deletions(-) delete mode 100644 db/migrate/20170613103429_add_primary_keyid_to_gpg_keys.rb delete mode 100644 db/migrate/20170713104235_add_gpg_key_user_info_to_gpg_signatures.rb diff --git a/db/migrate/20170222111732_create_gpg_keys.rb b/db/migrate/20170222111732_create_gpg_keys.rb index 1b8b7a91fe1..55dc730e884 100644 --- a/db/migrate/20170222111732_create_gpg_keys.rb +++ b/db/migrate/20170222111732_create_gpg_keys.rb @@ -3,11 +3,16 @@ class CreateGpgKeys < ActiveRecord::Migration def change create_table :gpg_keys do |t| + t.timestamps_with_timezone null: false + + t.references :user, index: true, foreign_key: true + t.string :fingerprint + t.string :primary_keyid + t.text :key - t.references :user, index: true, foreign_key: true - t.timestamps_with_timezone null: false + t.index :primary_keyid end end end diff --git a/db/migrate/20170613103429_add_primary_keyid_to_gpg_keys.rb b/db/migrate/20170613103429_add_primary_keyid_to_gpg_keys.rb deleted file mode 100644 index 13f0500971b..00000000000 --- a/db/migrate/20170613103429_add_primary_keyid_to_gpg_keys.rb +++ /dev/null @@ -1,17 +0,0 @@ -class AddPrimaryKeyidToGpgKeys < ActiveRecord::Migration - include Gitlab::Database::MigrationHelpers - - DOWNTIME = false - - disable_ddl_transaction! - - def up - add_column :gpg_keys, :primary_keyid, :string - add_concurrent_index :gpg_keys, :primary_keyid - end - - def down - remove_concurrent_index :gpg_keys, :primary_keyid if index_exists?(:gpg_keys, :primary_keyid) - remove_column :gpg_keys, :primary_keyid, :string - end -end diff --git a/db/migrate/20170613154149_create_gpg_signatures.rb b/db/migrate/20170613154149_create_gpg_signatures.rb index 72560cdb6d0..515c1413cf4 100644 --- a/db/migrate/20170613154149_create_gpg_signatures.rb +++ b/db/migrate/20170613154149_create_gpg_signatures.rb @@ -1,29 +1,22 @@ class CreateGpgSignatures < ActiveRecord::Migration - include Gitlab::Database::MigrationHelpers - DOWNTIME = false - disable_ddl_transaction! - - def up + def change create_table :gpg_signatures do |t| - t.string :commit_sha + t.timestamps_with_timezone null: false + t.references :project, index: true, foreign_key: true t.references :gpg_key, index: true, foreign_key: true - t.string :gpg_key_primary_keyid - t.boolean :valid_signature - t.timestamps_with_timezone null: false - end - - add_concurrent_index :gpg_signatures, :commit_sha - add_concurrent_index :gpg_signatures, :gpg_key_primary_keyid - end + t.boolean :valid_signature - def down - remove_concurrent_index :gpg_signatures, :commit_sha if index_exists?(:gpg_signatures, :commit_sha) - remove_concurrent_index :gpg_signatures, :gpg_key_primary_keyid if index_exists?(:gpg_signatures, :gpg_key_primary_keyid) + t.string :commit_sha + t.string :gpg_key_primary_keyid + t.string :gpg_key_user_name + t.string :gpg_key_user_email - drop_table :gpg_signatures + t.index :commit_sha + t.index :gpg_key_primary_keyid + end end end diff --git a/db/migrate/20170713104235_add_gpg_key_user_info_to_gpg_signatures.rb b/db/migrate/20170713104235_add_gpg_key_user_info_to_gpg_signatures.rb deleted file mode 100644 index 0e51a86e64c..00000000000 --- a/db/migrate/20170713104235_add_gpg_key_user_info_to_gpg_signatures.rb +++ /dev/null @@ -1,11 +0,0 @@ -# See http://doc.gitlab.com/ce/development/migration_style_guide.html -# for more information on how to write migrations for GitLab. - -class AddGpgKeyUserInfoToGpgSignatures < ActiveRecord::Migration - DOWNTIME = false - - def change - add_column :gpg_signatures, :gpg_key_user_name, :string - add_column :gpg_signatures, :gpg_key_user_email, :string - end -end diff --git a/db/schema.rb b/db/schema.rb index b76a5efbbd7..f413aaa41cd 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -541,25 +541,25 @@ ActiveRecord::Schema.define(version: 20170725145659) do add_index "forked_project_links", ["forked_to_project_id"], name: "index_forked_project_links_on_forked_to_project_id", unique: true, using: :btree create_table "gpg_keys", force: :cascade do |t| - t.string "fingerprint" - t.text "key" - t.integer "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.integer "user_id" + t.string "fingerprint" t.string "primary_keyid" + t.text "key" end add_index "gpg_keys", ["primary_keyid"], name: "index_gpg_keys_on_primary_keyid", using: :btree add_index "gpg_keys", ["user_id"], name: "index_gpg_keys_on_user_id", using: :btree create_table "gpg_signatures", force: :cascade do |t| - t.string "commit_sha" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "project_id" t.integer "gpg_key_id" - t.string "gpg_key_primary_keyid" t.boolean "valid_signature" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.string "commit_sha" + t.string "gpg_key_primary_keyid" t.string "gpg_key_user_name" t.string "gpg_key_user_email" end -- cgit v1.2.1 From 8e0c33ed1337e3614fe87d9d0c1eb64af90cc61a Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 20 Jul 2017 15:44:15 +0200 Subject: use ShaAttribute for gpg table columns --- app/models/gpg_key.rb | 5 +++++ app/models/gpg_signature.rb | 5 +++++ app/views/profiles/gpg_keys/_key.html.haml | 2 +- app/views/projects/commit/_signature_badge.html.haml | 2 +- db/migrate/20170222111732_create_gpg_keys.rb | 4 ++-- db/migrate/20170613154149_create_gpg_signatures.rb | 5 +++-- db/migrate/limits_to_mysql.rb | 4 ++++ db/schema.rb | 8 ++++---- 8 files changed, 25 insertions(+), 10 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 31a25f3e2f0..da2875a8851 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -1,6 +1,11 @@ class GpgKey < ActiveRecord::Base KEY_PREFIX = '-----BEGIN PGP PUBLIC KEY BLOCK-----'.freeze + include ShaAttribute + + sha_attribute :primary_keyid + sha_attribute :fingerprint + belongs_to :user has_many :gpg_signatures, dependent: :nullify diff --git a/app/models/gpg_signature.rb b/app/models/gpg_signature.rb index 0ef335bf8a9..9ac89f0bbbf 100644 --- a/app/models/gpg_signature.rb +++ b/app/models/gpg_signature.rb @@ -1,4 +1,9 @@ class GpgSignature < ActiveRecord::Base + include ShaAttribute + + sha_attribute :commit_sha + sha_attribute :gpg_key_primary_keyid + belongs_to :project belongs_to :gpg_key diff --git a/app/views/profiles/gpg_keys/_key.html.haml b/app/views/profiles/gpg_keys/_key.html.haml index b04981f90e3..d625aaea467 100644 --- a/app/views/profiles/gpg_keys/_key.html.haml +++ b/app/views/profiles/gpg_keys/_key.html.haml @@ -6,7 +6,7 @@ = render partial: 'email_with_badge', locals: { email: email, verified: verified } .description - %code= key.fingerprint + %code= key.fingerprint.upcase .pull-right %span.key-created-at created #{time_ago_with_tooltip(key.created_at)} diff --git a/app/views/projects/commit/_signature_badge.html.haml b/app/views/projects/commit/_signature_badge.html.haml index d6ece085f18..e79360a36e5 100644 --- a/app/views/projects/commit/_signature_badge.html.haml +++ b/app/views/projects/commit/_signature_badge.html.haml @@ -9,7 +9,7 @@ = content GPG Key ID: - %span.monospace= signature.gpg_key_primary_keyid + %span.monospace= signature.gpg_key_primary_keyid.upcase = link_to('Learn more about signing commits', help_page_path('workflow/gpg_signed_commits/index.md'), class: 'gpg-popover-help-link') diff --git a/db/migrate/20170222111732_create_gpg_keys.rb b/db/migrate/20170222111732_create_gpg_keys.rb index 55dc730e884..7591238311f 100644 --- a/db/migrate/20170222111732_create_gpg_keys.rb +++ b/db/migrate/20170222111732_create_gpg_keys.rb @@ -7,8 +7,8 @@ class CreateGpgKeys < ActiveRecord::Migration t.references :user, index: true, foreign_key: true - t.string :fingerprint - t.string :primary_keyid + t.binary :primary_keyid, limit: Gitlab::Database.mysql? ? 20 : nil + t.binary :fingerprint, limit: Gitlab::Database.mysql? ? 20 : nil t.text :key diff --git a/db/migrate/20170613154149_create_gpg_signatures.rb b/db/migrate/20170613154149_create_gpg_signatures.rb index 515c1413cf4..c5478551e11 100644 --- a/db/migrate/20170613154149_create_gpg_signatures.rb +++ b/db/migrate/20170613154149_create_gpg_signatures.rb @@ -10,8 +10,9 @@ class CreateGpgSignatures < ActiveRecord::Migration t.boolean :valid_signature - t.string :commit_sha - t.string :gpg_key_primary_keyid + t.binary :commit_sha, limit: Gitlab::Database.mysql? ? 20 : nil + t.binary :gpg_key_primary_keyid, limit: Gitlab::Database.mysql? ? 20 : nil + t.string :gpg_key_user_name t.string :gpg_key_user_email diff --git a/db/migrate/limits_to_mysql.rb b/db/migrate/limits_to_mysql.rb index be3501c4c2e..de1288e6410 100644 --- a/db/migrate/limits_to_mysql.rb +++ b/db/migrate/limits_to_mysql.rb @@ -8,5 +8,9 @@ class LimitsToMysql < ActiveRecord::Migration change_column :snippets, :content, :text, limit: 2147483647 change_column :notes, :st_diff, :text, limit: 2147483647 change_column :events, :data, :text, limit: 2147483647 + change_column :gpg_keys, :primary_keyid, :binary, limit: 20 + change_column :gpg_keys, :fingerprint, :binary, limit: 20 + change_column :gpg_signatures, :commit_sha, :binary, limit: 20 + change_column :gpg_signatures, :gpg_key_primary_keyid, :binary, limit: 20 end end diff --git a/db/schema.rb b/db/schema.rb index f413aaa41cd..68b5963ec14 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -544,8 +544,8 @@ ActiveRecord::Schema.define(version: 20170725145659) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "user_id" - t.string "fingerprint" - t.string "primary_keyid" + t.binary "primary_keyid" + t.binary "fingerprint" t.text "key" end @@ -558,8 +558,8 @@ ActiveRecord::Schema.define(version: 20170725145659) do t.integer "project_id" t.integer "gpg_key_id" t.boolean "valid_signature" - t.string "commit_sha" - t.string "gpg_key_primary_keyid" + t.binary "commit_sha" + t.binary "gpg_key_primary_keyid" t.string "gpg_key_user_name" t.string "gpg_key_user_email" end -- cgit v1.2.1 From 895efdfbcfe6082709943767dc8b3ebf399e1283 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 20 Jul 2017 16:11:53 +0200 Subject: use text instead of string for db columns --- db/migrate/20170613154149_create_gpg_signatures.rb | 4 ++-- db/schema.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/db/migrate/20170613154149_create_gpg_signatures.rb b/db/migrate/20170613154149_create_gpg_signatures.rb index c5478551e11..d1fe4b96a40 100644 --- a/db/migrate/20170613154149_create_gpg_signatures.rb +++ b/db/migrate/20170613154149_create_gpg_signatures.rb @@ -13,8 +13,8 @@ class CreateGpgSignatures < ActiveRecord::Migration t.binary :commit_sha, limit: Gitlab::Database.mysql? ? 20 : nil t.binary :gpg_key_primary_keyid, limit: Gitlab::Database.mysql? ? 20 : nil - t.string :gpg_key_user_name - t.string :gpg_key_user_email + t.text :gpg_key_user_name + t.text :gpg_key_user_email t.index :commit_sha t.index :gpg_key_primary_keyid diff --git a/db/schema.rb b/db/schema.rb index 68b5963ec14..6fa8be79156 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -560,8 +560,8 @@ ActiveRecord::Schema.define(version: 20170725145659) do t.boolean "valid_signature" t.binary "commit_sha" t.binary "gpg_key_primary_keyid" - t.string "gpg_key_user_name" - t.string "gpg_key_user_email" + t.text "gpg_key_user_name" + t.text "gpg_key_user_email" end add_index "gpg_signatures", ["commit_sha"], name: "index_gpg_signatures_on_commit_sha", using: :btree -- cgit v1.2.1 From 786b5a5991930bb838767a4ed6eed2a67e517e82 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 20 Jul 2017 16:18:02 +0200 Subject: use short project path helpers --- spec/features/commits_spec.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 9bd4b478cce..729d83968d3 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -215,7 +215,7 @@ describe 'Commits' do sign_in(user) - visit namespace_project_commits_path(project.namespace, project, :'signed-commits') + visit project_commits_path(project, :'signed-commits') within '#commits-list' do expect(page).to have_content 'Unverified' @@ -228,7 +228,7 @@ describe 'Commits' do user.update_attributes!(email: GpgHelpers::User1.emails.first) end - visit namespace_project_commits_path(project.namespace, project, :'signed-commits') + visit project_commits_path(project, :'signed-commits') within '#commits-list' do expect(page).to have_content 'Unverified' @@ -242,7 +242,7 @@ describe 'Commits' do sign_in(user) - visit namespace_project_commits_path(project.namespace, project, :'signed-commits') + visit project_commits_path(project, :'signed-commits') within '#commits-list' do expect(page).to have_content 'Unverified' @@ -254,7 +254,7 @@ describe 'Commits' do create :gpg_key, key: GpgHelpers::User1.public_key, user: user end - visit namespace_project_commits_path(project.namespace, project, :'signed-commits') + visit project_commits_path(project, :'signed-commits') within '#commits-list' do expect(page).to have_content 'Unverified' @@ -272,7 +272,7 @@ describe 'Commits' do project.team << [user, :master] sign_in(user) - visit namespace_project_commits_path(project.namespace, project, :'signed-commits') + visit project_commits_path(project, :'signed-commits') # unverified signature click_on 'Unverified', match: :first @@ -293,7 +293,7 @@ describe 'Commits' do # verified and the gpg user's profile doesn't exist anymore gpg_user.destroy! - visit namespace_project_commits_path(project.namespace, project, :'signed-commits') + visit project_commits_path(project, :'signed-commits') click_on 'Verified' within '.popover' do -- cgit v1.2.1 From 57ccff8ea41aa2366f40b29187d3b8d1217264e0 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 20 Jul 2017 16:33:44 +0200 Subject: use db's on_delete instead of has_many :dependent --- app/models/gpg_key.rb | 2 +- app/models/user.rb | 2 +- db/migrate/20170222111732_create_gpg_keys.rb | 2 +- db/migrate/20170613154149_create_gpg_signatures.rb | 4 ++-- db/schema.rb | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index da2875a8851..47ebfc9d234 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -7,7 +7,7 @@ class GpgKey < ActiveRecord::Base sha_attribute :fingerprint belongs_to :user - has_many :gpg_signatures, dependent: :nullify + has_many :gpg_signatures validates :user, presence: true diff --git a/app/models/user.rb b/app/models/user.rb index 03a76f4fa23..6e66c587a1f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -76,7 +76,7 @@ class User < ActiveRecord::Base where(type.not_eq('DeployKey').or(type.eq(nil))) end, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_many :deploy_keys, -> { where(type: 'DeployKey') }, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent - has_many :gpg_keys, dependent: :destroy + has_many :gpg_keys has_many :emails, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_many :personal_access_tokens, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent diff --git a/db/migrate/20170222111732_create_gpg_keys.rb b/db/migrate/20170222111732_create_gpg_keys.rb index 7591238311f..072c0819b2f 100644 --- a/db/migrate/20170222111732_create_gpg_keys.rb +++ b/db/migrate/20170222111732_create_gpg_keys.rb @@ -5,7 +5,7 @@ class CreateGpgKeys < ActiveRecord::Migration create_table :gpg_keys do |t| t.timestamps_with_timezone null: false - t.references :user, index: true, foreign_key: true + t.references :user, index: true, foreign_key: { on_delete: :cascade } t.binary :primary_keyid, limit: Gitlab::Database.mysql? ? 20 : nil t.binary :fingerprint, limit: Gitlab::Database.mysql? ? 20 : nil diff --git a/db/migrate/20170613154149_create_gpg_signatures.rb b/db/migrate/20170613154149_create_gpg_signatures.rb index d1fe4b96a40..db86170776d 100644 --- a/db/migrate/20170613154149_create_gpg_signatures.rb +++ b/db/migrate/20170613154149_create_gpg_signatures.rb @@ -5,8 +5,8 @@ class CreateGpgSignatures < ActiveRecord::Migration create_table :gpg_signatures do |t| t.timestamps_with_timezone null: false - t.references :project, index: true, foreign_key: true - t.references :gpg_key, index: true, foreign_key: true + t.references :project, index: true, foreign_key: { on_delete: :cascade } + t.references :gpg_key, index: true, foreign_key: { on_delete: :nullify } t.boolean :valid_signature diff --git a/db/schema.rb b/db/schema.rb index 6fa8be79156..1a7eb2ded76 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1631,9 +1631,9 @@ ActiveRecord::Schema.define(version: 20170725145659) do add_foreign_key "environments", "projects", name: "fk_d1c8c1da6a", on_delete: :cascade add_foreign_key "events", "projects", name: "fk_0434b48643", on_delete: :cascade add_foreign_key "forked_project_links", "projects", column: "forked_to_project_id", name: "fk_434510edb0", on_delete: :cascade - add_foreign_key "gpg_keys", "users" - add_foreign_key "gpg_signatures", "gpg_keys" - add_foreign_key "gpg_signatures", "projects" + add_foreign_key "gpg_keys", "users", on_delete: :cascade + add_foreign_key "gpg_signatures", "gpg_keys", on_delete: :nullify + add_foreign_key "gpg_signatures", "projects", on_delete: :cascade add_foreign_key "issue_assignees", "issues", name: "fk_b7d881734a", on_delete: :cascade add_foreign_key "issue_assignees", "users", name: "fk_5e0c8d9154", on_delete: :cascade add_foreign_key "issue_metrics", "issues", on_delete: :cascade -- cgit v1.2.1 From c4c44c6a1bb892dc17989cef3cc9b6c23fecb2c8 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 20 Jul 2017 22:07:04 +0200 Subject: length constrain on the index, not on the column we actually don't need a limit on the column itself for MySQL to work. we need to set a length on the index. --- db/migrate/20170222111732_create_gpg_keys.rb | 6 +++--- db/migrate/20170613154149_create_gpg_signatures.rb | 8 ++++---- db/migrate/limits_to_mysql.rb | 17 +++++++++++++---- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/db/migrate/20170222111732_create_gpg_keys.rb b/db/migrate/20170222111732_create_gpg_keys.rb index 072c0819b2f..ec619394f6a 100644 --- a/db/migrate/20170222111732_create_gpg_keys.rb +++ b/db/migrate/20170222111732_create_gpg_keys.rb @@ -7,12 +7,12 @@ class CreateGpgKeys < ActiveRecord::Migration t.references :user, index: true, foreign_key: { on_delete: :cascade } - t.binary :primary_keyid, limit: Gitlab::Database.mysql? ? 20 : nil - t.binary :fingerprint, limit: Gitlab::Database.mysql? ? 20 : nil + t.binary :primary_keyid + t.binary :fingerprint t.text :key - t.index :primary_keyid + t.index :primary_keyid, length: Gitlab::Database.mysql? ? 20 : nil end end end diff --git a/db/migrate/20170613154149_create_gpg_signatures.rb b/db/migrate/20170613154149_create_gpg_signatures.rb index db86170776d..775a9463914 100644 --- a/db/migrate/20170613154149_create_gpg_signatures.rb +++ b/db/migrate/20170613154149_create_gpg_signatures.rb @@ -10,14 +10,14 @@ class CreateGpgSignatures < ActiveRecord::Migration t.boolean :valid_signature - t.binary :commit_sha, limit: Gitlab::Database.mysql? ? 20 : nil - t.binary :gpg_key_primary_keyid, limit: Gitlab::Database.mysql? ? 20 : nil + t.binary :commit_sha + t.binary :gpg_key_primary_keyid t.text :gpg_key_user_name t.text :gpg_key_user_email - t.index :commit_sha - t.index :gpg_key_primary_keyid + t.index :commit_sha, length: Gitlab::Database.mysql? ? 20 : nil + t.index :gpg_key_primary_keyid, length: Gitlab::Database.mysql? ? 20 : nil end end end diff --git a/db/migrate/limits_to_mysql.rb b/db/migrate/limits_to_mysql.rb index de1288e6410..69ada782abe 100644 --- a/db/migrate/limits_to_mysql.rb +++ b/db/migrate/limits_to_mysql.rb @@ -1,5 +1,9 @@ # rubocop:disable all +require Rails.root.join('lib/gitlab/database/migration_helpers.rb') + class LimitsToMysql < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + def up return unless ActiveRecord::Base.configurations[Rails.env]['adapter'] =~ /^mysql/ @@ -8,9 +12,14 @@ class LimitsToMysql < ActiveRecord::Migration change_column :snippets, :content, :text, limit: 2147483647 change_column :notes, :st_diff, :text, limit: 2147483647 change_column :events, :data, :text, limit: 2147483647 - change_column :gpg_keys, :primary_keyid, :binary, limit: 20 - change_column :gpg_keys, :fingerprint, :binary, limit: 20 - change_column :gpg_signatures, :commit_sha, :binary, limit: 20 - change_column :gpg_signatures, :gpg_key_primary_keyid, :binary, limit: 20 + + [ + [:gpg_keys, :primary_keyid], + [:gpg_signatures, :commit_sha], + [:gpg_signatures, :gpg_key_primary_keyid] + ].each do |table_name, column_name| + remove_index table_name, column_name if index_exists?(table_name, column_name) + add_concurrent_index table_name, column_name, length: 20 + end end end -- cgit v1.2.1 From eda001565c5afbf6e2eb9b8b5cf4fa9d6525ed71 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 25 Jul 2017 09:40:23 +0200 Subject: fetch gpg signature badges by ajax --- app/assets/javascripts/dispatcher.js | 4 +++ app/assets/javascripts/gpg_badges.js | 15 ++++++++ app/controllers/projects/commits_controller.rb | 40 ++++++++++++++++------ app/helpers/commits_helper.rb | 4 +++ app/models/commit.rb | 8 ++++- .../projects/commit/_ajax_signature.html.haml | 3 ++ .../projects/commit/_signature_badge.html.haml | 2 +- app/views/projects/commits/_commit.html.haml | 7 +++- app/views/projects/commits/show.html.haml | 2 +- config/routes/repository.rb | 2 ++ spec/features/commits_spec.rb | 4 +-- 11 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 app/assets/javascripts/gpg_badges.js create mode 100644 app/views/projects/commit/_ajax_signature.html.haml diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 1dc6edacfed..f2f814b9e18 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -64,6 +64,7 @@ import initSettingsPanels from './settings_panels'; import initExperimentalFlags from './experimental_flags'; import OAuthRememberMe from './oauth_remember_me'; import PerformanceBar from './performance_bar'; +import GpgBadges from './gpg_badges'; (function() { var Dispatcher; @@ -300,6 +301,9 @@ import PerformanceBar from './performance_bar'; }).bindEvents(); break; case 'projects:commits:show': + shortcut_handler = new ShortcutsNavigation(); + GpgBadges.fetch(); + break; case 'projects:activity': shortcut_handler = new ShortcutsNavigation(); break; diff --git a/app/assets/javascripts/gpg_badges.js b/app/assets/javascripts/gpg_badges.js new file mode 100644 index 00000000000..1c379e9bb67 --- /dev/null +++ b/app/assets/javascripts/gpg_badges.js @@ -0,0 +1,15 @@ +export default class GpgBadges { + static fetch() { + const form = $('.commits-search-form'); + + $.get({ + url: form.data('signatures-path'), + data: form.serialize(), + }).done((response) => { + const badges = $('.js-loading-gpg-badge'); + response.signatures.forEach((signature) => { + badges.filter(`[data-commit-sha="${signature.commit_sha}"]`).replaceWith(signature.html); + }); + }); + } +} diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb index 37b5a6e9d48..2de9900d449 100644 --- a/app/controllers/projects/commits_controller.rb +++ b/app/controllers/projects/commits_controller.rb @@ -6,18 +6,9 @@ class Projects::CommitsController < Projects::ApplicationController before_action :require_non_empty_project before_action :assign_ref_vars before_action :authorize_download_code! + before_action :set_commits def show - @limit, @offset = (params[:limit] || 40).to_i, (params[:offset] || 0).to_i - search = params[:search] - - @commits = - if search.present? - @repository.find_commits_by_message(search, @ref, @path, @limit, @offset) - else - @repository.commits(@ref, path: @path, limit: @limit, offset: @offset) - end - @note_counts = project.notes.where(commit_id: @commits.map(&:id)) .group(:commit_id).count @@ -37,4 +28,33 @@ class Projects::CommitsController < Projects::ApplicationController end end end + + def signatures + respond_to do |format| + format.json do + render json: { + signatures: @commits.select(&:has_signature?).map do |commit| + { + commit_sha: commit.sha, + html: view_to_html_string('projects/commit/_signature', signature: commit.signature) + } + end + } + end + end + end + + private + + def set_commits + @limit, @offset = (params[:limit] || 40).to_i, (params[:offset] || 0).to_i + search = params[:search] + + @commits = + if search.present? + @repository.find_commits_by_message(search, @ref, @path, @limit, @offset) + else + @repository.commits(@ref, path: @path, limit: @limit, offset: @offset) + end + end end diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index d08e346d605..69220a1c0f6 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -113,6 +113,10 @@ module CommitsHelper commit_action_link('cherry-pick', commit, continue_to_path, btn_class: btn_class, has_tooltip: has_tooltip) end + def commit_signature_badge_classes(additional_classes) + %w(btn status-box gpg-status-box) + Array(additional_classes) + end + protected # Private: Returns a link to a person. If the person has a matching user and diff --git a/app/models/commit.rb b/app/models/commit.rb index 35593d53cbc..7940733f557 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -237,9 +237,11 @@ class Commit def signature return @signature if defined?(@signature) - @signature = Gitlab::Gpg::Commit.new(self).signature + @signature = gpg_commit.signature end + delegate :has_signature?, to: :gpg_commit + def revert_branch_name "revert-#{short_id}" end @@ -388,4 +390,8 @@ class Commit def merged_merge_request_no_cache(user) MergeRequestsFinder.new(user, project_id: project.id).find_by(merge_commit_sha: id) if merge_commit? end + + def gpg_commit + @gpg_commit ||= Gitlab::Gpg::Commit.new(self) + end end diff --git a/app/views/projects/commit/_ajax_signature.html.haml b/app/views/projects/commit/_ajax_signature.html.haml new file mode 100644 index 00000000000..22674b671c9 --- /dev/null +++ b/app/views/projects/commit/_ajax_signature.html.haml @@ -0,0 +1,3 @@ +- if commit.has_signature? + %button{ class: commit_signature_badge_classes('js-loading-gpg-badge'), data: { toggle: 'tooltip', placement: 'auto top', title: 'GPG signature (loading...)', 'commit-sha' => commit.sha } } + %i.fa.fa-spinner.fa-spin diff --git a/app/views/projects/commit/_signature_badge.html.haml b/app/views/projects/commit/_signature_badge.html.haml index e79360a36e5..51f04a11712 100644 --- a/app/views/projects/commit/_signature_badge.html.haml +++ b/app/views/projects/commit/_signature_badge.html.haml @@ -1,4 +1,4 @@ -- css_classes = %w(btn status-box gpg-status-box) + css_classes +- css_classes = commit_signature_badge_classes(css_classes) - title = capture do .gpg-popover-status diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index b7f18d44838..12b73ecdf13 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -39,7 +39,12 @@ .commit-actions.hidden-xs - if commit.status(ref) = render_commit_status(commit, ref: ref) - = render partial: 'projects/commit/signature', object: commit.signature + + - if request.xhr? + = render partial: 'projects/commit/signature', object: commit.signature + - else + = render partial: 'projects/commit/ajax_signature', locals: { commit: commit } + = link_to commit.short_id, project_commit_path(project, commit), class: "commit-sha btn btn-transparent" = clipboard_button(text: commit.id, title: _("Copy commit SHA to clipboard")) = link_to_browse_code(project, commit) diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index 844ebb65148..bd2d900997e 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -29,7 +29,7 @@ = link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' .control - = form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form') do + = form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form', data: { 'signatures-path' => namespace_project_signatures_path }) do = search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false } .control = link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do diff --git a/config/routes/repository.rb b/config/routes/repository.rb index 11911636fa7..edcf3ddf57b 100644 --- a/config/routes/repository.rb +++ b/config/routes/repository.rb @@ -76,6 +76,8 @@ scope format: false do get '/tree/*id', to: 'tree#show', as: :tree get '/raw/*id', to: 'raw#show', as: :raw get '/blame/*id', to: 'blame#show', as: :blame + + get '/commits/*id/signatures', to: 'commits#signatures', as: :signatures get '/commits/*id', to: 'commits#show', as: :commits post '/create_dir/*id', to: 'tree#create_dir', as: :create_dir diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 729d83968d3..87a0dc328a6 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -204,7 +204,7 @@ describe 'Commits' do end end - describe 'GPG signed commits' do + describe 'GPG signed commits', :js do it 'changes from unverified to verified when the user changes his email to match the gpg key' do user = create :user, email: 'unrelated.user@example.org' project.team << [user, :master] @@ -262,7 +262,7 @@ describe 'Commits' do end end - it 'shows popover badges', :js do + it 'shows popover badges' do gpg_user = create :user, email: GpgHelpers::User1.emails.first, username: 'nannie.bernhard', name: 'Nannie Bernhard' Sidekiq::Testing.inline! do create :gpg_key, key: GpgHelpers::User1.public_key, user: gpg_user -- cgit v1.2.1 From ce4e0837c4ce11ad31c7be487d08bf44d961ec6f Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 25 Jul 2017 10:02:13 +0200 Subject: mysql hack: set length for binary indexes --- .../mysql_set_length_for_binary_indexes.rb | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 config/initializers/mysql_set_length_for_binary_indexes.rb diff --git a/config/initializers/mysql_set_length_for_binary_indexes.rb b/config/initializers/mysql_set_length_for_binary_indexes.rb new file mode 100644 index 00000000000..b5c6e39f6a8 --- /dev/null +++ b/config/initializers/mysql_set_length_for_binary_indexes.rb @@ -0,0 +1,25 @@ +# This patches ActiveRecord so indexes for binary columns created using the +# MySQL adapter apply a length of 20. Otherwise MySQL can't create an index on +# binary columns. + +if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter) + module ActiveRecord + module ConnectionAdapters + class Mysql2Adapter < AbstractMysqlAdapter + alias_method :__gitlab_add_index2, :add_index + + def add_index(table_name, column_names, options = {}) + Array(column_names).each do |column_name| + column = ActiveRecord::Base.connection.columns(table_name).find { |c| c.name == column_name } + + if column&.type == :binary + options[:length] = 20 + end + end + + __gitlab_add_index2(table_name, column_names, options) + end + end + end + end +end -- cgit v1.2.1 From f86580c075f50b78517283febca012afcc8b6211 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 25 Jul 2017 16:02:30 +0200 Subject: no more more :length due to mysql set_index hack --- db/migrate/limits_to_mysql.rb | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/db/migrate/limits_to_mysql.rb b/db/migrate/limits_to_mysql.rb index 69ada782abe..be3501c4c2e 100644 --- a/db/migrate/limits_to_mysql.rb +++ b/db/migrate/limits_to_mysql.rb @@ -1,9 +1,5 @@ # rubocop:disable all -require Rails.root.join('lib/gitlab/database/migration_helpers.rb') - class LimitsToMysql < ActiveRecord::Migration - include Gitlab::Database::MigrationHelpers - def up return unless ActiveRecord::Base.configurations[Rails.env]['adapter'] =~ /^mysql/ @@ -12,14 +8,5 @@ class LimitsToMysql < ActiveRecord::Migration change_column :snippets, :content, :text, limit: 2147483647 change_column :notes, :st_diff, :text, limit: 2147483647 change_column :events, :data, :text, limit: 2147483647 - - [ - [:gpg_keys, :primary_keyid], - [:gpg_signatures, :commit_sha], - [:gpg_signatures, :gpg_key_primary_keyid] - ].each do |table_name, column_name| - remove_index table_name, column_name if index_exists?(table_name, column_name) - add_concurrent_index table_name, column_name, length: 20 - end end end -- cgit v1.2.1 From 98531fc2487f8d4d7de47fe9a1d60c10d1f1d9ba Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 25 Jul 2017 16:23:52 +0200 Subject: upcase in the model instead of in the view --- app/models/gpg_key.rb | 8 ++++++++ app/models/gpg_signature.rb | 4 ++++ app/views/profiles/gpg_keys/_key.html.haml | 2 +- app/views/projects/commit/_signature_badge.html.haml | 2 +- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 47ebfc9d234..0d35baa7ade 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -37,6 +37,14 @@ class GpgKey < ActiveRecord::Base after_commit :update_invalid_gpg_signatures, on: :create after_commit :notify_user, on: :create + def primary_keyid + super&.upcase + end + + def fingerprint + super&.upcase + end + def key=(value) value.strip! unless value.blank? write_attribute(:key, value) diff --git a/app/models/gpg_signature.rb b/app/models/gpg_signature.rb index 9ac89f0bbbf..cb69106183d 100644 --- a/app/models/gpg_signature.rb +++ b/app/models/gpg_signature.rb @@ -11,6 +11,10 @@ class GpgSignature < ActiveRecord::Base validates :project, presence: true validates :gpg_key_primary_keyid, presence: true + def gpg_key_primary_keyid + super&.upcase + end + def commit project.commit(commit_sha) end diff --git a/app/views/profiles/gpg_keys/_key.html.haml b/app/views/profiles/gpg_keys/_key.html.haml index d625aaea467..b04981f90e3 100644 --- a/app/views/profiles/gpg_keys/_key.html.haml +++ b/app/views/profiles/gpg_keys/_key.html.haml @@ -6,7 +6,7 @@ = render partial: 'email_with_badge', locals: { email: email, verified: verified } .description - %code= key.fingerprint.upcase + %code= key.fingerprint .pull-right %span.key-created-at created #{time_ago_with_tooltip(key.created_at)} diff --git a/app/views/projects/commit/_signature_badge.html.haml b/app/views/projects/commit/_signature_badge.html.haml index 51f04a11712..66f00eb5507 100644 --- a/app/views/projects/commit/_signature_badge.html.haml +++ b/app/views/projects/commit/_signature_badge.html.haml @@ -9,7 +9,7 @@ = content GPG Key ID: - %span.monospace= signature.gpg_key_primary_keyid.upcase + %span.monospace= signature.gpg_key_primary_keyid = link_to('Learn more about signing commits', help_page_path('workflow/gpg_signed_commits/index.md'), class: 'gpg-popover-help-link') -- cgit v1.2.1 From ecbc11a839f7a48402e912f1176735770c091829 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 25 Jul 2017 16:24:22 +0200 Subject: extract setter as before_action --- app/controllers/profiles/gpg_keys_controller.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/controllers/profiles/gpg_keys_controller.rb b/app/controllers/profiles/gpg_keys_controller.rb index 3e75247769d..6779cc6ddac 100644 --- a/app/controllers/profiles/gpg_keys_controller.rb +++ b/app/controllers/profiles/gpg_keys_controller.rb @@ -1,4 +1,6 @@ class Profiles::GpgKeysController < Profiles::ApplicationController + before_action :set_gpg_key, only: [:destroy, :revoke] + def index @gpg_keys = current_user.gpg_keys @gpg_key = GpgKey.new @@ -16,8 +18,7 @@ class Profiles::GpgKeysController < Profiles::ApplicationController end def destroy - @gpp_key = current_user.gpg_keys.find(params[:id]) - @gpp_key.destroy + @gpg_key.destroy respond_to do |format| format.html { redirect_to profile_gpg_keys_url, status: 302 } @@ -26,8 +27,7 @@ class Profiles::GpgKeysController < Profiles::ApplicationController end def revoke - @gpp_key = current_user.gpg_keys.find(params[:id]) - @gpp_key.revoke + @gpg_key.revoke respond_to do |format| format.html { redirect_to profile_gpg_keys_url, status: 302 } @@ -40,4 +40,8 @@ class Profiles::GpgKeysController < Profiles::ApplicationController def gpg_key_params params.require(:gpg_key).permit(:key) end + + def set_gpg_key + @gpg_key = current_user.gpg_keys.find(params[:id]) + end end -- cgit v1.2.1 From 07dbd5649ad18e4473c10ef8a1a70ea863b88cc4 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 25 Jul 2017 16:45:13 +0200 Subject: use Module#prepend instead of alias_method_chain --- .../mysql_set_length_for_binary_indexes.rb | 28 ++++++++++------------ 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/config/initializers/mysql_set_length_for_binary_indexes.rb b/config/initializers/mysql_set_length_for_binary_indexes.rb index b5c6e39f6a8..de0bc5322aa 100644 --- a/config/initializers/mysql_set_length_for_binary_indexes.rb +++ b/config/initializers/mysql_set_length_for_binary_indexes.rb @@ -2,24 +2,20 @@ # MySQL adapter apply a length of 20. Otherwise MySQL can't create an index on # binary columns. -if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter) - module ActiveRecord - module ConnectionAdapters - class Mysql2Adapter < AbstractMysqlAdapter - alias_method :__gitlab_add_index2, :add_index - - def add_index(table_name, column_names, options = {}) - Array(column_names).each do |column_name| - column = ActiveRecord::Base.connection.columns(table_name).find { |c| c.name == column_name } +module MysqlSetLengthForBinaryIndex + def add_index(table_name, column_names, options = {}) + Array(column_names).each do |column_name| + column = ActiveRecord::Base.connection.columns(table_name).find { |c| c.name == column_name } - if column&.type == :binary - options[:length] = 20 - end - end - - __gitlab_add_index2(table_name, column_names, options) - end + if column&.type == :binary + options[:length] = 20 end end + + super(table_name, column_names, options) end end + +if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter) + ActiveRecord::ConnectionAdapters::Mysql2Adapter.send(:prepend, MysqlSetLengthForBinaryIndex) +end -- cgit v1.2.1 From 14551424c9fd3a9401559e6d2da34be8d1fdd45c Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 25 Jul 2017 20:31:34 +0200 Subject: add unique indexes to gpg_keys --- db/migrate/20170222111732_create_gpg_keys.rb | 3 ++- db/schema.rb | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/db/migrate/20170222111732_create_gpg_keys.rb b/db/migrate/20170222111732_create_gpg_keys.rb index ec619394f6a..541228e8735 100644 --- a/db/migrate/20170222111732_create_gpg_keys.rb +++ b/db/migrate/20170222111732_create_gpg_keys.rb @@ -12,7 +12,8 @@ class CreateGpgKeys < ActiveRecord::Migration t.text :key - t.index :primary_keyid, length: Gitlab::Database.mysql? ? 20 : nil + t.index :primary_keyid, unique: true, length: Gitlab::Database.mysql? ? 20 : nil + t.index :fingerprint, unique: true, length: Gitlab::Database.mysql? ? 20 : nil end end end diff --git a/db/schema.rb b/db/schema.rb index 1a7eb2ded76..2cc8b1624c0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -549,7 +549,8 @@ ActiveRecord::Schema.define(version: 20170725145659) do t.text "key" end - add_index "gpg_keys", ["primary_keyid"], name: "index_gpg_keys_on_primary_keyid", using: :btree + add_index "gpg_keys", ["fingerprint"], name: "index_gpg_keys_on_fingerprint", unique: true, using: :btree + add_index "gpg_keys", ["primary_keyid"], name: "index_gpg_keys_on_primary_keyid", unique: true, using: :btree add_index "gpg_keys", ["user_id"], name: "index_gpg_keys_on_user_id", using: :btree create_table "gpg_signatures", force: :cascade do |t| -- cgit v1.2.1 From 843b1de0dec3e101b323737e4d345c4e58b2a0c3 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 25 Jul 2017 20:35:44 +0200 Subject: simplify nil handling --- app/models/gpg_key.rb | 3 +-- spec/models/gpg_key_spec.rb | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 0d35baa7ade..009a93ce1a8 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -46,8 +46,7 @@ class GpgKey < ActiveRecord::Base end def key=(value) - value.strip! unless value.blank? - write_attribute(:key, value) + super(value&.strip) end def user_infos diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 06bdbb59a11..1242f0b2e2a 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -44,6 +44,10 @@ describe GpgKey do expect(described_class.new(key: " #{key} ").key).to eq(key) end + + it 'does not strip when the key is nil' do + expect(described_class.new(key: nil).key).to be_nil + end end describe '#user_infos' do -- cgit v1.2.1 From a5f04df8d76d7c3c4318820fc3053a9823143dba Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 25 Jul 2017 21:14:14 +0200 Subject: update all records at once using `update_all` --- app/models/gpg_key.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 009a93ce1a8..535b40472b0 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -77,12 +77,11 @@ class GpgKey < ActiveRecord::Base end def revoke - GpgSignature.where(gpg_key: self, valid_signature: true).find_each do |gpg_signature| - gpg_signature.update_attributes!( - gpg_key: nil, - valid_signature: false - ) - end + GpgSignature.where(gpg_key: self, valid_signature: true).update_all( + gpg_key_id: nil, + valid_signature: false, + updated_at: Time.zone.now + ) destroy end -- cgit v1.2.1 From fef030c23dff6f3b11b0e6bfd4c9443106375de1 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 25 Jul 2017 21:20:48 +0200 Subject: validate the foreign_key instead of the relation --- app/models/gpg_signature.rb | 2 +- spec/models/gpg_signature_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/gpg_signature.rb b/app/models/gpg_signature.rb index cb69106183d..1ac0e123ff1 100644 --- a/app/models/gpg_signature.rb +++ b/app/models/gpg_signature.rb @@ -8,7 +8,7 @@ class GpgSignature < ActiveRecord::Base belongs_to :gpg_key validates :commit_sha, presence: true - validates :project, presence: true + validates :project_id, presence: true validates :gpg_key_primary_keyid, presence: true def gpg_key_primary_keyid diff --git a/spec/models/gpg_signature_spec.rb b/spec/models/gpg_signature_spec.rb index b6f256e61ee..9a9b1900aa5 100644 --- a/spec/models/gpg_signature_spec.rb +++ b/spec/models/gpg_signature_spec.rb @@ -9,7 +9,7 @@ RSpec.describe GpgSignature do describe 'validation' do subject { described_class.new } it { is_expected.to validate_presence_of(:commit_sha) } - it { is_expected.to validate_presence_of(:project) } + it { is_expected.to validate_presence_of(:project_id) } it { is_expected.to validate_presence_of(:gpg_key_primary_keyid) } end -- cgit v1.2.1 From 4e53131f7dceb001368446ef3e7eb3747cfcec02 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 26 Jul 2017 09:30:33 +0200 Subject: add unique index for gpg_signatures#commit_sha --- db/migrate/20170613154149_create_gpg_signatures.rb | 2 +- db/schema.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/db/migrate/20170613154149_create_gpg_signatures.rb b/db/migrate/20170613154149_create_gpg_signatures.rb index 775a9463914..f6b5e7ebb7b 100644 --- a/db/migrate/20170613154149_create_gpg_signatures.rb +++ b/db/migrate/20170613154149_create_gpg_signatures.rb @@ -16,7 +16,7 @@ class CreateGpgSignatures < ActiveRecord::Migration t.text :gpg_key_user_name t.text :gpg_key_user_email - t.index :commit_sha, length: Gitlab::Database.mysql? ? 20 : nil + t.index :commit_sha, unique: true, length: Gitlab::Database.mysql? ? 20 : nil t.index :gpg_key_primary_keyid, length: Gitlab::Database.mysql? ? 20 : nil end end diff --git a/db/schema.rb b/db/schema.rb index 2cc8b1624c0..63030350c5d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -565,7 +565,7 @@ ActiveRecord::Schema.define(version: 20170725145659) do t.text "gpg_key_user_email" end - add_index "gpg_signatures", ["commit_sha"], name: "index_gpg_signatures_on_commit_sha", using: :btree + add_index "gpg_signatures", ["commit_sha"], name: "index_gpg_signatures_on_commit_sha", unique: true, using: :btree add_index "gpg_signatures", ["gpg_key_id"], name: "index_gpg_signatures_on_gpg_key_id", using: :btree add_index "gpg_signatures", ["gpg_key_primary_keyid"], name: "index_gpg_signatures_on_gpg_key_primary_keyid", using: :btree add_index "gpg_signatures", ["project_id"], name: "index_gpg_signatures_on_project_id", using: :btree -- cgit v1.2.1 From 9488b7780edc57193cd1c51888478538ddc94e51 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 26 Jul 2017 10:24:46 +0200 Subject: optimize query, only select relevant db columns --- lib/gitlab/gpg/invalid_gpg_signature_updater.rb | 1 + .../gpg/invalid_gpg_signature_updater_spec.rb | 64 ++++++++++++++++++---- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/lib/gitlab/gpg/invalid_gpg_signature_updater.rb b/lib/gitlab/gpg/invalid_gpg_signature_updater.rb index 1782e20dcab..3bb491120ba 100644 --- a/lib/gitlab/gpg/invalid_gpg_signature_updater.rb +++ b/lib/gitlab/gpg/invalid_gpg_signature_updater.rb @@ -7,6 +7,7 @@ module Gitlab def run GpgSignature + .select(:id, :commit_sha, :project_id) .where('gpg_key_id IS NULL OR valid_signature = ?', false) .where(gpg_key_primary_keyid: @gpg_key.primary_keyid) .find_each do |gpg_signature| diff --git a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb index 5a81a86b93c..c4e04ee46a2 100644 --- a/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb +++ b/spec/lib/gitlab/gpg/invalid_gpg_signature_updater_spec.rb @@ -20,7 +20,7 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do end before do - allow_any_instance_of(GpgSignature).to receive(:commit).and_return(commit) + allow_any_instance_of(Project).to receive(:commit).and_return(commit) end context 'gpg signature did have an associated gpg key which was removed later' do @@ -41,7 +41,13 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do key: GpgHelpers::User1.public_key, user: user - expect(valid_gpg_signature.reload.gpg_key).to eq gpg_key + expect(valid_gpg_signature.reload).to have_attributes( + project: project, + commit_sha: commit_sha, + gpg_key: gpg_key, + gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + valid_signature: true + ) end it 'does not assign the gpg key when an unrelated gpg key is added' do @@ -50,7 +56,13 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do key: GpgHelpers::User2.public_key, user: user - expect(valid_gpg_signature.reload.gpg_key).to be_nil + expect(valid_gpg_signature.reload).to have_attributes( + project: project, + commit_sha: commit_sha, + gpg_key: nil, + gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + valid_signature: true + ) end end @@ -68,11 +80,17 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do it 'updates the signature to being valid when the missing gpg key is added' do # InvalidGpgSignatureUpdater is called by the after_create hook - create :gpg_key, + gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key, user: user - expect(invalid_gpg_signature.reload.valid_signature).to be_truthy + expect(invalid_gpg_signature.reload).to have_attributes( + project: project, + commit_sha: commit_sha, + gpg_key: gpg_key, + gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + valid_signature: true + ) end it 'keeps the signature at being invalid when an unrelated gpg key is added' do @@ -81,7 +99,13 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do key: GpgHelpers::User2.public_key, user: user - expect(invalid_gpg_signature.reload.valid_signature).to be_falsey + expect(invalid_gpg_signature.reload).to have_attributes( + project: project, + commit_sha: commit_sha, + gpg_key: nil, + gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + valid_signature: false + ) end end @@ -102,7 +126,7 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do end it 'updates the signature to being valid when the user updates the email address' do - create :gpg_key, + gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key, user: user @@ -111,20 +135,38 @@ RSpec.describe Gitlab::Gpg::InvalidGpgSignatureUpdater do # InvalidGpgSignatureUpdater is called by the after_update hook user.update_attributes!(email: GpgHelpers::User1.emails.first) - expect(invalid_gpg_signature.reload.valid_signature).to be_truthy + expect(invalid_gpg_signature.reload).to have_attributes( + project: project, + commit_sha: commit_sha, + gpg_key: gpg_key, + gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + valid_signature: true + ) end it 'keeps the signature at being invalid when the changed email address is still unrelated' do - create :gpg_key, + gpg_key = create :gpg_key, key: GpgHelpers::User1.public_key, user: user - expect(invalid_gpg_signature.reload.valid_signature).to be_falsey + expect(invalid_gpg_signature.reload).to have_attributes( + project: project, + commit_sha: commit_sha, + gpg_key: gpg_key, + gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + valid_signature: false + ) # InvalidGpgSignatureUpdater is called by the after_update hook user.update_attributes!(email: 'still.unrelated@example.com') - expect(invalid_gpg_signature.reload.valid_signature).to be_falsey + expect(invalid_gpg_signature.reload).to have_attributes( + project: project, + commit_sha: commit_sha, + gpg_key: gpg_key, + gpg_key_primary_keyid: GpgHelpers::User1.primary_keyid, + valid_signature: false + ) end end end -- cgit v1.2.1 From f1ccecc9979e3091e7cf54f98508f6bc7c01a7f5 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 26 Jul 2017 15:47:00 +0200 Subject: improve gpg key validation when omitting the end part of the key ('-----END PGP PUBLIC KEY BLOCK-----') the error message was not about the key anymore, but about the missing fingerprint and primary_keyid, which was confusing for the user. the new validation checks that the end also matches the expected format. --- app/models/gpg_key.rb | 5 +++-- spec/models/gpg_key_spec.rb | 10 +++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/app/models/gpg_key.rb b/app/models/gpg_key.rb index 535b40472b0..3df60ddc950 100644 --- a/app/models/gpg_key.rb +++ b/app/models/gpg_key.rb @@ -1,5 +1,6 @@ class GpgKey < ActiveRecord::Base KEY_PREFIX = '-----BEGIN PGP PUBLIC KEY BLOCK-----'.freeze + KEY_SUFFIX = '-----END PGP PUBLIC KEY BLOCK-----'.freeze include ShaAttribute @@ -15,8 +16,8 @@ class GpgKey < ActiveRecord::Base presence: true, uniqueness: true, format: { - with: /\A#{KEY_PREFIX}((?!#{KEY_PREFIX}).)+\Z/m, - message: "is invalid. A valid public GPG key begins with '#{KEY_PREFIX}'" + with: /\A#{KEY_PREFIX}((?!#{KEY_PREFIX})(?!#{KEY_SUFFIX}).)+#{KEY_SUFFIX}\Z/m, + message: "is invalid. A valid public GPG key begins with '#{KEY_PREFIX}' and ends with '#{KEY_SUFFIX}'" } validates :fingerprint, diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 1242f0b2e2a..59c074199db 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -7,10 +7,18 @@ describe GpgKey do describe "validation" do it { is_expected.to validate_presence_of(:user) } + it { is_expected.to validate_presence_of(:key) } it { is_expected.to validate_uniqueness_of(:key) } - it { is_expected.to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----\nkey").for(:key) } + + it { is_expected.to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----\nkey\n-----END PGP PUBLIC KEY BLOCK-----").for(:key) } + + it { is_expected.not_to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----\nkey").for(:key) } it { is_expected.not_to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----\nkey\n-----BEGIN PGP PUBLIC KEY BLOCK-----").for(:key) } + it { is_expected.not_to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK----------END PGP PUBLIC KEY BLOCK-----").for(:key) } + it { is_expected.not_to allow_value("-----BEGIN PGP PUBLIC KEY BLOCK-----").for(:key) } + it { is_expected.not_to allow_value("-----END PGP PUBLIC KEY BLOCK-----").for(:key) } + it { is_expected.not_to allow_value("key\n-----END PGP PUBLIC KEY BLOCK-----").for(:key) } it { is_expected.not_to allow_value('BEGIN PGP').for(:key) } end -- cgit v1.2.1 From 7f7e93a34471f673ac3888549c67bce4e763300e Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 26 Jul 2017 16:01:24 +0200 Subject: remove log statements from workers --- app/workers/create_gpg_signature_worker.rb | 8 ++------ app/workers/invalid_gpg_signature_update_worker.rb | 4 +--- spec/workers/create_gpg_signature_worker_spec.rb | 14 -------------- spec/workers/invalid_gpg_signature_update_worker_spec.rb | 7 ------- 4 files changed, 3 insertions(+), 30 deletions(-) diff --git a/app/workers/create_gpg_signature_worker.rb b/app/workers/create_gpg_signature_worker.rb index 6fbd6e1a3f3..4f47717ff69 100644 --- a/app/workers/create_gpg_signature_worker.rb +++ b/app/workers/create_gpg_signature_worker.rb @@ -5,15 +5,11 @@ class CreateGpgSignatureWorker def perform(commit_sha, project_id) project = Project.find_by(id: project_id) - unless project - return Rails.logger.error("CreateGpgSignatureWorker: couldn't find project with ID=#{project_id}, skipping job") - end + return unless project commit = project.commit(commit_sha) - unless commit - return Rails.logger.error("CreateGpgSignatureWorker: couldn't find commit with commit_sha=#{commit_sha}, skipping job") - end + return unless commit commit.signature end diff --git a/app/workers/invalid_gpg_signature_update_worker.rb b/app/workers/invalid_gpg_signature_update_worker.rb index c0bec3c9689..db6b1ea8e8d 100644 --- a/app/workers/invalid_gpg_signature_update_worker.rb +++ b/app/workers/invalid_gpg_signature_update_worker.rb @@ -5,9 +5,7 @@ class InvalidGpgSignatureUpdateWorker def perform(gpg_key_id) gpg_key = GpgKey.find_by(id: gpg_key_id) - unless gpg_key - return Rails.logger.error("InvalidGpgSignatureUpdateWorker: couldn't find gpg_key with ID=#{gpg_key_id}, skipping job") - end + return unless gpg_key Gitlab::Gpg::InvalidGpgSignatureUpdater.new(gpg_key).run end diff --git a/spec/workers/create_gpg_signature_worker_spec.rb b/spec/workers/create_gpg_signature_worker_spec.rb index a23f0d6c34a..c6a17d77d73 100644 --- a/spec/workers/create_gpg_signature_worker_spec.rb +++ b/spec/workers/create_gpg_signature_worker_spec.rb @@ -20,13 +20,6 @@ describe CreateGpgSignatureWorker do let(:nonexisting_commit_sha) { 'bogus' } let(:project) { create :project } - it 'logs CreateGpgSignatureWorker process skipping' do - expect(Rails.logger).to receive(:error) - .with("CreateGpgSignatureWorker: couldn't find commit with commit_sha=bogus, skipping job") - - described_class.new.perform(nonexisting_commit_sha, project.id) - end - it 'does not raise errors' do expect { described_class.new.perform(nonexisting_commit_sha, project.id) }.not_to raise_error end @@ -41,13 +34,6 @@ describe CreateGpgSignatureWorker do context 'when Project is not found' do let(:nonexisting_project_id) { -1 } - it 'logs CreateGpgSignatureWorker process skipping' do - expect(Rails.logger).to receive(:error) - .with("CreateGpgSignatureWorker: couldn't find project with ID=-1, skipping job") - - described_class.new.perform(anything, nonexisting_project_id) - end - it 'does not raise errors' do expect { described_class.new.perform(anything, nonexisting_project_id) }.not_to raise_error end diff --git a/spec/workers/invalid_gpg_signature_update_worker_spec.rb b/spec/workers/invalid_gpg_signature_update_worker_spec.rb index 8d568076e1a..5972696515b 100644 --- a/spec/workers/invalid_gpg_signature_update_worker_spec.rb +++ b/spec/workers/invalid_gpg_signature_update_worker_spec.rb @@ -16,13 +16,6 @@ describe InvalidGpgSignatureUpdateWorker do context 'when GpgKey is not found' do let(:nonexisting_gpg_key_id) { -1 } - it 'logs InvalidGpgSignatureUpdateWorker process skipping' do - expect(Rails.logger).to receive(:error) - .with("InvalidGpgSignatureUpdateWorker: couldn't find gpg_key with ID=-1, skipping job") - - described_class.new.perform(nonexisting_gpg_key_id) - end - it 'does not raise errors' do expect { described_class.new.perform(nonexisting_gpg_key_id) }.not_to raise_error end -- cgit v1.2.1 From 5ebccab1eb74f7bf9f7f9d4f2d9a56fb81754cbe Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 27 Jul 2017 16:01:24 +0200 Subject: add "GPG Keys" to new navigation --- app/views/layouts/nav/_new_profile_sidebar.html.haml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/views/layouts/nav/_new_profile_sidebar.html.haml b/app/views/layouts/nav/_new_profile_sidebar.html.haml index 239e6b949e2..6bbd569583e 100644 --- a/app/views/layouts/nav/_new_profile_sidebar.html.haml +++ b/app/views/layouts/nav/_new_profile_sidebar.html.haml @@ -47,6 +47,10 @@ = link_to profile_keys_path, title: 'SSH Keys' do %span SSH Keys + = nav_link(controller: :gpg_keys) do + = link_to profile_gpg_keys_path, title: 'GPG Keys' do + %span + GPG Keys = nav_link(controller: :preferences) do = link_to profile_preferences_path, title: 'Preferences' do %span -- cgit v1.2.1 From 1631ad02fd32f2fb620ba3fa13f0504ae5181356 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 27 Jul 2017 16:35:40 +0200 Subject: Support the fact that Gitaly uses bundler --- lib/tasks/gitlab/gitaly.rake | 2 +- spec/support/test_env.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tasks/gitlab/gitaly.rake b/lib/tasks/gitlab/gitaly.rake index a8db5701d0b..9df07ea8d83 100644 --- a/lib/tasks/gitlab/gitaly.rake +++ b/lib/tasks/gitlab/gitaly.rake @@ -19,7 +19,7 @@ namespace :gitlab do Dir.chdir(args.dir) do create_gitaly_configuration - run_command!([command]) + Bundler.with_original_env { run_command!([command]) } end end diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index c32c05b03e2..3da1b940b0d 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -146,7 +146,7 @@ module TestEnv gitaly_exec = File.join(gitaly_dir, 'gitaly') gitaly_config = File.join(gitaly_dir, 'config.toml') log_file = Rails.root.join('log/gitaly-test.log').to_s - @gitaly_pid = spawn(gitaly_exec, gitaly_config, [:out, :err] => log_file) + @gitaly_pid = Bundler.with_original_env { spawn(gitaly_exec, gitaly_config, [:out, :err] => log_file) } end def stop_gitaly -- cgit v1.2.1 From 3d83181b81b9ef54a0b310e6ce2eabc7660a0040 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Thu, 27 Jul 2017 18:14:09 +0300 Subject: Remove GitLab custom fealure app for devise --- config/initializers/devise.rb | 12 ++++++------ lib/gitlab/devise_failure.rb | 23 ----------------------- 2 files changed, 6 insertions(+), 29 deletions(-) delete mode 100644 lib/gitlab/devise_failure.rb diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 3b1317030bc..3aed2136f1b 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -192,7 +192,7 @@ Devise.setup do |config| # # The :"*/*" and "*/*" formats below is required to match Internet # Explorer requests. - # config.navigational_formats = [:"*/*", "*/*", :html] + config.navigational_formats = [:"*/*", "*/*", :html, :zip] # The default HTTP method used to sign out a resource. Default is :delete. config.sign_out_via = :delete @@ -206,11 +206,11 @@ Devise.setup do |config| # If you want to use other strategies, that are not supported by Devise, or # change the failure app, you can configure them inside the config.warden block. # - config.warden do |manager| - manager.failure_app = Gitlab::DeviseFailure - # manager.intercept_401 = false - # manager.default_strategies(scope: :user).unshift :some_external_strategy - end + # config.warden do |manager| + # manager.failure_app = Gitlab::DeviseFailure + # manager.intercept_401 = false + # manager.default_strategies(scope: :user).unshift :some_external_strategy + # end if Gitlab::LDAP::Config.enabled? Gitlab::LDAP::Config.providers.each do |provider| diff --git a/lib/gitlab/devise_failure.rb b/lib/gitlab/devise_failure.rb deleted file mode 100644 index a78fde9d782..00000000000 --- a/lib/gitlab/devise_failure.rb +++ /dev/null @@ -1,23 +0,0 @@ -module Gitlab - class DeviseFailure < Devise::FailureApp - protected - - # Override `Devise::FailureApp#request_format` to handle a special case - # - # This tells Devise to handle an unauthenticated `.zip` request as an HTML - # request (i.e., redirect to sign in). - # - # Otherwise, Devise would respond with a 401 Unauthorized with - # `Content-Type: application/zip` and a response body in plaintext, and the - # browser would freak out. - # - # See https://gitlab.com/gitlab-org/gitlab-ce/issues/12944 - def request_format - if request.format == :zip - Mime::Type.lookup_by_extension(:html).ref - else - super - end - end - end -end -- cgit v1.2.1 From c26f4a07e77786793151bd4ef6063dfcdbb3a808 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 21 Jul 2017 15:38:26 -0400 Subject: Use `empty_project` where possible in spec/features/dashboard --- spec/features/dashboard/archived_projects_spec.rb | 2 +- spec/features/dashboard/datetime_on_tooltips_spec.rb | 2 +- spec/features/dashboard/label_filter_spec.rb | 4 ++-- spec/features/dashboard/milestone_filter_spec.rb | 2 +- spec/features/dashboard/todos/target_state_spec.rb | 2 +- spec/features/dashboard/todos/todos_spec.rb | 4 ++-- spec/features/dashboard/user_filters_projects_spec.rb | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/spec/features/dashboard/archived_projects_spec.rb b/spec/features/dashboard/archived_projects_spec.rb index 814ec0e59c7..ceac6a0a27c 100644 --- a/spec/features/dashboard/archived_projects_spec.rb +++ b/spec/features/dashboard/archived_projects_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Dashboard Archived Project' do let(:user) { create :user } let(:project) { create :project} - let(:archived_project) { create(:project, :archived) } + let(:archived_project) { create(:empty_project, :archived) } before do project.team << [user, :master] diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb index b6dce1b8ec4..05dcdd93f37 100644 --- a/spec/features/dashboard/datetime_on_tooltips_spec.rb +++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Tooltips on .timeago dates', js: true do let(:user) { create(:user) } - let(:project) { create(:project, name: 'test', namespace: user.namespace) } + let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) } let(:created_date) { Date.yesterday.to_time } let(:expected_format) { created_date.in_time_zone.strftime('%b %-d, %Y %l:%M%P') } diff --git a/spec/features/dashboard/label_filter_spec.rb b/spec/features/dashboard/label_filter_spec.rb index b1a207682c3..8e19fb93665 100644 --- a/spec/features/dashboard/label_filter_spec.rb +++ b/spec/features/dashboard/label_filter_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe 'Dashboard > label filter', js: true do let(:user) { create(:user) } - let(:project) { create(:project, name: 'test', namespace: user.namespace) } - let(:project2) { create(:project, name: 'test2', path: 'test2', namespace: user.namespace) } + let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) } + let(:project2) { create(:empty_project, name: 'test2', path: 'test2', namespace: user.namespace) } let(:label) { create(:label, title: 'bug', color: '#ff0000') } let(:label2) { create(:label, title: 'bug') } diff --git a/spec/features/dashboard/milestone_filter_spec.rb b/spec/features/dashboard/milestone_filter_spec.rb index c965b565ca3..5ebef1eb097 100644 --- a/spec/features/dashboard/milestone_filter_spec.rb +++ b/spec/features/dashboard/milestone_filter_spec.rb @@ -4,7 +4,7 @@ feature 'Dashboard > milestone filter', :js do include FilterItemSelectHelper let(:user) { create(:user) } - let(:project) { create(:project, name: 'test', namespace: user.namespace) } + let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) } let(:milestone) { create(:milestone, title: 'v1.0', project: project) } let(:milestone2) { create(:milestone, title: 'v2.0', project: project) } let!(:issue) { create :issue, author: user, project: project, milestone: milestone } diff --git a/spec/features/dashboard/todos/target_state_spec.rb b/spec/features/dashboard/todos/target_state_spec.rb index 030a86d1c01..93da36c08fc 100644 --- a/spec/features/dashboard/todos/target_state_spec.rb +++ b/spec/features/dashboard/todos/target_state_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' feature 'Dashboard > Todo target states' do let(:user) { create(:user) } let(:author) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } before do sign_in(user) diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb index 30bab7eeaa7..c2a61cf5aff 100644 --- a/spec/features/dashboard/todos/todos_spec.rb +++ b/spec/features/dashboard/todos/todos_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Dashboard Todos' do let(:user) { create(:user) } let(:author) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:issue) { create(:issue, due_date: Date.today) } context 'User does not have todos' do @@ -212,7 +212,7 @@ feature 'Dashboard Todos' do note1 = create(:note_on_issue, note: "Hello #{label1.to_reference(format: :name)}", noteable_id: issue.id, noteable_type: 'Issue', project: issue.project) create(:todo, :mentioned, project: project, target: issue, user: user, note_id: note1.id) - project2 = create(:project, :public) + project2 = create(:empty_project, :public) label2 = create(:label, project: project2) issue2 = create(:issue, project: project2) note2 = create(:note_on_issue, note: "Test #{label2.to_reference(format: :name)}", noteable_id: issue2.id, noteable_type: 'Issue', project: project2) diff --git a/spec/features/dashboard/user_filters_projects_spec.rb b/spec/features/dashboard/user_filters_projects_spec.rb index c352b6ded14..a88fe207e0e 100644 --- a/spec/features/dashboard/user_filters_projects_spec.rb +++ b/spec/features/dashboard/user_filters_projects_spec.rb @@ -2,9 +2,9 @@ require 'spec_helper' describe 'Dashboard > User filters projects' do let(:user) { create(:user) } - let(:project) { create(:project, name: 'Victorialand', namespace: user.namespace) } + let(:project) { create(:empty_project, name: 'Victorialand', namespace: user.namespace) } let(:user2) { create(:user) } - let(:project2) { create(:project, name: 'Treasure', namespace: user2.namespace) } + let(:project2) { create(:empty_project, name: 'Treasure', namespace: user2.namespace) } before do project.team << [user, :master] -- cgit v1.2.1 From e561b142fa7c9dd636fd056fc0a6c84961d0cd46 Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Mon, 24 Jul 2017 17:45:12 -0300 Subject: Backport gitlab-ee!2456 --- app/controllers/admin/applications_controller.rb | 2 +- app/views/admin/applications/_form.html.haml | 8 ++++++++ app/views/admin/applications/index.html.haml | 2 ++ app/views/admin/applications/show.html.haml | 6 ++++++ .../skip-oauth-authorization-for-trusted-applications.yml | 4 ++++ config/initializers/doorkeeper.rb | 6 +++--- ...0717200542_add_trusted_column_to_oauth_applications.rb | 15 +++++++++++++++ db/schema.rb | 1 + doc/integration/oauth_provider.md | 3 +++ spec/controllers/admin/applications_controller_spec.rb | 11 ++++++++--- spec/controllers/oauth/authorizations_controller_spec.rb | 2 +- spec/features/admin/admin_manage_applications_spec.rb | 5 +++++ 12 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 changelogs/unreleased/skip-oauth-authorization-for-trusted-applications.yml create mode 100644 db/migrate/20170717200542_add_trusted_column_to_oauth_applications.rb diff --git a/app/controllers/admin/applications_controller.rb b/app/controllers/admin/applications_controller.rb index 434ff6b2a62..4cb6e63d5e3 100644 --- a/app/controllers/admin/applications_controller.rb +++ b/app/controllers/admin/applications_controller.rb @@ -50,6 +50,6 @@ class Admin::ApplicationsController < Admin::ApplicationController # Only allow a trusted parameter "white list" through. def application_params - params[:doorkeeper_application].permit(:name, :redirect_uri, :scopes) + params[:doorkeeper_application].permit(:name, :redirect_uri, :trusted, :scopes) end end diff --git a/app/views/admin/applications/_form.html.haml b/app/views/admin/applications/_form.html.haml index 061f8991b11..93827d6a1ab 100644 --- a/app/views/admin/applications/_form.html.haml +++ b/app/views/admin/applications/_form.html.haml @@ -6,6 +6,7 @@ .col-sm-10 = f.text_field :name, class: 'form-control' = doorkeeper_errors_for application, :name + = content_tag :div, class: 'form-group' do = f.label :redirect_uri, class: 'col-sm-2 control-label' .col-sm-10 @@ -19,6 +20,13 @@ %code= Doorkeeper.configuration.native_redirect_uri for local tests + = content_tag :div, class: 'form-group' do + = f.label :trusted, class: 'col-sm-2 control-label' + .col-sm-10 + = f.check_box :trusted + %span.help-block + Trusted applications are automatically authorized on GitLab OAuth flow. + .form-group = f.label :scopes, class: 'col-sm-2 control-label' .col-sm-10 diff --git a/app/views/admin/applications/index.html.haml b/app/views/admin/applications/index.html.haml index eb4293c7e37..94d33fa6489 100644 --- a/app/views/admin/applications/index.html.haml +++ b/app/views/admin/applications/index.html.haml @@ -11,6 +11,7 @@ %th Name %th Callback URL %th Clients + %th Trusted %th %th %tbody.oauth-applications @@ -19,5 +20,6 @@ %td= link_to application.name, admin_application_path(application) %td= application.redirect_uri %td= application.access_tokens.map(&:resource_owner_id).uniq.count + %td= application.trusted? ? 'Y': 'N' %td= link_to 'Edit', edit_admin_application_path(application), class: 'btn btn-link' %td= render 'delete_form', application: application diff --git a/app/views/admin/applications/show.html.haml b/app/views/admin/applications/show.html.haml index 14683cc66e9..5125aa21b06 100644 --- a/app/views/admin/applications/show.html.haml +++ b/app/views/admin/applications/show.html.haml @@ -23,6 +23,12 @@ %div %span.monospace= uri + %tr + %td + Trusted + %td + = @application.trusted? ? 'Y' : 'N' + = render "shared/tokens/scopes_list", token: @application .form-actions diff --git a/changelogs/unreleased/skip-oauth-authorization-for-trusted-applications.yml b/changelogs/unreleased/skip-oauth-authorization-for-trusted-applications.yml new file mode 100644 index 00000000000..7b4ae355978 --- /dev/null +++ b/changelogs/unreleased/skip-oauth-authorization-for-trusted-applications.yml @@ -0,0 +1,4 @@ +--- +title: Skip oAuth authorization for trusted applications +merge_request: +author: diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb index 8e2e639fc41..40e635bf2cf 100644 --- a/config/initializers/doorkeeper.rb +++ b/config/initializers/doorkeeper.rb @@ -92,9 +92,9 @@ Doorkeeper.configure do # Under some circumstances you might want to have applications auto-approved, # so that the user skips the authorization step. # For example if dealing with trusted a application. - # skip_authorization do |resource_owner, client| - # client.superapp? or resource_owner.admin? - # end + skip_authorization do |resource_owner, client| + client.application.trusted? + end # WWW-Authenticate Realm (default "Doorkeeper"). # realm "Doorkeeper" diff --git a/db/migrate/20170717200542_add_trusted_column_to_oauth_applications.rb b/db/migrate/20170717200542_add_trusted_column_to_oauth_applications.rb new file mode 100644 index 00000000000..1a013e6aefb --- /dev/null +++ b/db/migrate/20170717200542_add_trusted_column_to_oauth_applications.rb @@ -0,0 +1,15 @@ +class AddTrustedColumnToOauthApplications < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_column_with_default(:oauth_applications, :trusted, :boolean, default: false) + end + + def down + remove_column(:oauth_applications, :trusted) + end +end diff --git a/db/schema.rb b/db/schema.rb index 1ec25c7d46f..0f14f8ac0ba 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -997,6 +997,7 @@ ActiveRecord::Schema.define(version: 20170725145659) do t.datetime "updated_at" t.integer "owner_id" t.string "owner_type" + t.boolean "trusted", default: false, null: false end add_index "oauth_applications", ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type", using: :btree diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md index af8a1c4e5ed..8ba2e8731c8 100644 --- a/doc/integration/oauth_provider.md +++ b/doc/integration/oauth_provider.md @@ -63,6 +63,9 @@ it from the admin area. ![OAuth admin_applications](img/oauth_provider_admin_application.png) +You're also able to mark an application as _trusted_ when creating it through the admin area. By doing that, +the user authorization step is automatically skipped for this application. + --- ## Authorized applications diff --git a/spec/controllers/admin/applications_controller_spec.rb b/spec/controllers/admin/applications_controller_spec.rb index e311b8a63b2..7bd6c0e6117 100644 --- a/spec/controllers/admin/applications_controller_spec.rb +++ b/spec/controllers/admin/applications_controller_spec.rb @@ -28,13 +28,16 @@ describe Admin::ApplicationsController do describe 'POST #create' do it 'creates the application' do + create_params = attributes_for(:application, trusted: true) + expect do - post :create, doorkeeper_application: attributes_for(:application) + post :create, doorkeeper_application: create_params end.to change { Doorkeeper::Application.count }.by(1) application = Doorkeeper::Application.last expect(response).to redirect_to(admin_application_path(application)) + expect(application).to have_attributes(create_params.except(:uid, :owner_type)) end it 'renders the application form on errors' do @@ -49,10 +52,12 @@ describe Admin::ApplicationsController do describe 'PATCH #update' do it 'updates the application' do - patch :update, id: application.id, doorkeeper_application: { redirect_uri: 'http://example.com/' } + patch :update, id: application.id, doorkeeper_application: { redirect_uri: 'http://example.com/', trusted: true } + + application.reload expect(response).to redirect_to(admin_application_path(application)) - expect(application.reload.redirect_uri).to eq 'http://example.com/' + expect(application).to have_attributes(redirect_uri: 'http://example.com/', trusted: true) end it 'renders the application form on errors' do diff --git a/spec/controllers/oauth/authorizations_controller_spec.rb b/spec/controllers/oauth/authorizations_controller_spec.rb index d321bfcea9d..ac7f73c6e81 100644 --- a/spec/controllers/oauth/authorizations_controller_spec.rb +++ b/spec/controllers/oauth/authorizations_controller_spec.rb @@ -42,8 +42,8 @@ describe Oauth::AuthorizationsController do end it 'deletes session.user_return_to and redirects when skip authorization' do + doorkeeper.update(trusted: true) request.session['user_return_to'] = 'http://example.com' - allow(controller).to receive(:skip_authorization?).and_return(true) get :new, params diff --git a/spec/features/admin/admin_manage_applications_spec.rb b/spec/features/admin/admin_manage_applications_spec.rb index c1ece123230..f979d2f6090 100644 --- a/spec/features/admin/admin_manage_applications_spec.rb +++ b/spec/features/admin/admin_manage_applications_spec.rb @@ -13,19 +13,24 @@ RSpec.describe 'admin manage applications' do fill_in :doorkeeper_application_name, with: 'test' fill_in :doorkeeper_application_redirect_uri, with: 'https://test.com' + check :doorkeeper_application_trusted click_on 'Submit' expect(page).to have_content('Application: test') expect(page).to have_content('Application Id') expect(page).to have_content('Secret') + expect(page).to have_content('Trusted Y') click_on 'Edit' expect(page).to have_content('Edit application') fill_in :doorkeeper_application_name, with: 'test_changed' + uncheck :doorkeeper_application_trusted + click_on 'Submit' expect(page).to have_content('test_changed') expect(page).to have_content('Application Id') expect(page).to have_content('Secret') + expect(page).to have_content('Trusted N') visit admin_applications_path page.within '.oauth-applications' do -- cgit v1.2.1 From f837cd6611a39d3dd38655821f32feb2c2abba8d Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Wed, 26 Jul 2017 18:06:30 -0300 Subject: Use params#require instead params[] access --- app/controllers/admin/applications_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/admin/applications_controller.rb b/app/controllers/admin/applications_controller.rb index 4cb6e63d5e3..16590e66d61 100644 --- a/app/controllers/admin/applications_controller.rb +++ b/app/controllers/admin/applications_controller.rb @@ -50,6 +50,6 @@ class Admin::ApplicationsController < Admin::ApplicationController # Only allow a trusted parameter "white list" through. def application_params - params[:doorkeeper_application].permit(:name, :redirect_uri, :trusted, :scopes) + params.require(:doorkeeper_application).permit(:name, :redirect_uri, :trusted, :scopes) end end -- cgit v1.2.1 From df57c08ef8f243fc799e682575b87c82d2e769d5 Mon Sep 17 00:00:00 2001 From: Joshua Lambert Date: Thu, 27 Jul 2017 16:49:09 +0000 Subject: Update environments.md --- doc/ci/environments.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/ci/environments.md b/doc/ci/environments.md index df5c66a4c85..6a7f694d705 100644 --- a/doc/ci/environments.md +++ b/doc/ci/environments.md @@ -607,8 +607,7 @@ exist, you should see something like: - With GitLab 9.2, all deployments to an environment are shown directly on the monitoring dashboard -If your application is deployed on Kubernetes and you have enabled Prometheus -collecting metrics, you can monitor the performance behavior of your app +If you have enabled Prometheus for collecting metrics, you can monitor the performance behavior of your app through the environments. Once configured, GitLab will attempt to retrieve performance metrics for any -- cgit v1.2.1 From 75319d973b274e071492510688e369e8d3126b43 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 21 Jul 2017 16:55:17 -0400 Subject: Use `empty_project` where possible in spec/features/admin --- spec/features/admin/admin_hook_logs_spec.rb | 2 +- spec/features/admin/admin_hooks_spec.rb | 2 +- spec/features/admin/admin_projects_spec.rb | 19 +++++++++++-------- spec/features/admin/admin_users_spec.rb | 2 +- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/spec/features/admin/admin_hook_logs_spec.rb b/spec/features/admin/admin_hook_logs_spec.rb index 710822ac042..7910d5fb72b 100644 --- a/spec/features/admin/admin_hook_logs_spec.rb +++ b/spec/features/admin/admin_hook_logs_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Admin::HookLogs' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:system_hook) { create(:system_hook) } let(:hook_log) { create(:web_hook_log, web_hook: system_hook, internal_error_message: 'some error') } diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb index 30fcb334b60..141109fd464 100644 --- a/spec/features/admin/admin_hooks_spec.rb +++ b/spec/features/admin/admin_hooks_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Admin::Hooks' do before do - @project = create(:project) + @project = create(:empty_project) sign_in(create(:admin)) @system_hook = create(:system_hook) diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb index 9856d90bffe..4f69eafcb9d 100644 --- a/spec/features/admin/admin_projects_spec.rb +++ b/spec/features/admin/admin_projects_spec.rb @@ -4,17 +4,18 @@ describe "Admin::Projects" do include Select2Helper let(:user) { create :user } - let!(:project) { create(:project) } - let!(:current_user) { create(:admin) } + let(:project) { create(:empty_project) } + let(:current_user) { create(:admin) } before do sign_in(current_user) end describe "GET /admin/projects" do - let!(:archived_project) { create :project, :public, :archived } + let!(:archived_project) { create :empty_project, :public, :archived } before do + expect(project).to be_persisted visit admin_projects_path end @@ -39,15 +40,14 @@ describe "Admin::Projects" do describe "GET /admin/projects/:namespace_id/:id" do before do - visit admin_projects_path - click_link "#{project.name}" - end + expect(project).to be_persisted - it do - expect(current_path).to eq admin_project_path(project) + visit admin_projects_path + click_link project.name end it "has project info" do + expect(current_path).to eq admin_project_path(project) expect(page).to have_content(project.path) expect(page).to have_content(project.name) expect(page).to have_content(project.name_with_namespace) @@ -56,6 +56,9 @@ describe "Admin::Projects" do end describe 'transfer project' do + # The gitlab-shell transfer will fail for a project without a repository + let(:project) { create(:project, :repository) } + before do create(:group, name: 'Web') diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index e2e2b13cf8a..0dde8bb696c 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -257,7 +257,7 @@ describe "Admin::Users" do describe "GET /admin/users/:id/projects" do let(:group) { create(:group) } - let!(:project) { create(:project, group: group) } + let!(:project) { create(:empty_project, group: group) } before do group.add_developer(user) -- cgit v1.2.1 From 1b3681614b8851bbfc8a8d4c6fab8cf6d1c7182e Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 21 Jul 2017 17:00:42 -0400 Subject: Use `empty_project` where possible in spec/features/groups --- spec/features/groups/group_settings_spec.rb | 6 +++--- spec/features/groups/members/request_access_spec.rb | 2 +- spec/features/groups/merge_requests_spec.rb | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb index 47553922ede..121df1ec635 100644 --- a/spec/features/groups/group_settings_spec.rb +++ b/spec/features/groups/group_settings_spec.rb @@ -49,7 +49,7 @@ feature 'Edit group settings' do end context 'with a project' do - given!(:project) { create(:project, group: group, path: 'project') } + given!(:project) { create(:empty_project, group: group) } given(:old_project_full_path) { "/#{group.path}/#{project.path}" } given(:new_project_full_path) { "/#{new_group_path}/#{project.path}" } @@ -65,14 +65,14 @@ feature 'Edit group settings' do update_path(new_group_path) visit new_project_full_path expect(current_path).to eq(new_project_full_path) - expect(find('h1.project-title')).to have_content(project.name) + expect(find('h1.title')).to have_content(project.path) end scenario 'the old project path redirects to the new path' do update_path(new_group_path) visit old_project_full_path expect(current_path).to eq(new_project_full_path) - expect(find('h1.project-title')).to have_content(project.name) + expect(find('h1.title')).to have_content(project.path) end end end diff --git a/spec/features/groups/members/request_access_spec.rb b/spec/features/groups/members/request_access_spec.rb index 1f3c7fd3859..6141981023c 100644 --- a/spec/features/groups/members/request_access_spec.rb +++ b/spec/features/groups/members/request_access_spec.rb @@ -4,7 +4,7 @@ feature 'Groups > Members > Request access' do let(:user) { create(:user) } let(:owner) { create(:user) } let(:group) { create(:group, :public, :access_requestable) } - let!(:project) { create(:project, :private, namespace: group) } + let!(:project) { create(:empty_project, :private, namespace: group) } background do group.add_owner(owner) diff --git a/spec/features/groups/merge_requests_spec.rb b/spec/features/groups/merge_requests_spec.rb index cbf147b6a5c..c2241feb9f7 100644 --- a/spec/features/groups/merge_requests_spec.rb +++ b/spec/features/groups/merge_requests_spec.rb @@ -7,7 +7,7 @@ feature 'Group merge requests page' do include_examples 'project features apply to issuables', MergeRequest context 'archived issuable' do - let(:project_archived) { create(:project, :archived, :merge_requests_enabled, group: group) } + let(:project_archived) { create(:project, :archived, :merge_requests_enabled, :repository, group: group) } let(:issuable_archived) { create(:merge_request, source_project: project_archived, target_project: project_archived, title: 'issuable of an archived project') } let(:access_level) { ProjectFeature::ENABLED } let(:user) { user_in_group } -- cgit v1.2.1 From 0853dacad67e2d7e9ce92b50bf6d3ed664ace76f Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 21 Jul 2017 17:05:57 -0400 Subject: Use `empty_project` where possible in spec/features/explore --- spec/features/explore/new_menu_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/explore/new_menu_spec.rb b/spec/features/explore/new_menu_spec.rb index 2cd06258e22..b1ccf80c28e 100644 --- a/spec/features/explore/new_menu_spec.rb +++ b/spec/features/explore/new_menu_spec.rb @@ -4,7 +4,7 @@ feature 'Top Plus Menu', :js do let(:user) { create(:user) } let(:group) { create(:group) } let(:project) { create(:project, :repository, creator: user, namespace: user.namespace) } - let(:public_project) { create(:project, :public) } + let(:public_project) { create(:empty_project, :public) } before do group.add_owner(user) -- cgit v1.2.1 From f7c5c6861065126c026877a90e2e32cf02df426d Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 21 Jul 2017 17:19:12 -0400 Subject: Use `empty_project` where possible in spec/features/profiles --- spec/features/profiles/account_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/features/profiles/account_spec.rb b/spec/features/profiles/account_spec.rb index 7791047877d..56c1f7ae9c7 100644 --- a/spec/features/profiles/account_spec.rb +++ b/spec/features/profiles/account_spec.rb @@ -27,7 +27,7 @@ feature 'Profile > Account' do end context 'with a project' do - given!(:project) { create(:project, namespace: user.namespace, path: 'project') } + given!(:project) { create(:empty_project, namespace: user.namespace) } given(:new_project_path) { "/#{new_username}/#{project.path}" } given(:old_project_path) { "/#{user.username}/#{project.path}" } @@ -43,14 +43,14 @@ feature 'Profile > Account' do update_username(new_username) visit new_project_path expect(current_path).to eq(new_project_path) - expect(find('h1.project-title')).to have_content(project.name) + expect(find('h1.title')).to have_content(project.path) end scenario 'the old project path redirects to the new path' do update_username(new_username) visit old_project_path expect(current_path).to eq(new_project_path) - expect(find('h1.project-title')).to have_content(project.name) + expect(find('h1.title')).to have_content(project.path) end end end -- cgit v1.2.1 From fcc4ba16d5c59dd7c013c6894cf829892a9141c5 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 21 Jul 2017 17:23:04 -0400 Subject: Use `empty_project` where possible in spec/features/atom --- spec/features/atom/dashboard_issues_spec.rb | 4 ++-- spec/features/atom/dashboard_spec.rb | 2 +- spec/features/atom/issues_spec.rb | 2 +- spec/features/atom/users_spec.rb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/features/atom/dashboard_issues_spec.rb b/spec/features/atom/dashboard_issues_spec.rb index 5aae2dbaf91..d70da7f09e9 100644 --- a/spec/features/atom/dashboard_issues_spec.rb +++ b/spec/features/atom/dashboard_issues_spec.rb @@ -4,8 +4,8 @@ describe "Dashboard Issues Feed" do describe "GET /issues" do let!(:user) { create(:user, email: 'private1@example.com', public_email: 'public1@example.com') } let!(:assignee) { create(:user, email: 'private2@example.com', public_email: 'public2@example.com') } - let!(:project1) { create(:project) } - let!(:project2) { create(:project) } + let!(:project1) { create(:empty_project) } + let!(:project2) { create(:empty_project) } before do project1.team << [user, :master] diff --git a/spec/features/atom/dashboard_spec.rb b/spec/features/atom/dashboard_spec.rb index 321c8a2a670..a7c12853981 100644 --- a/spec/features/atom/dashboard_spec.rb +++ b/spec/features/atom/dashboard_spec.rb @@ -19,7 +19,7 @@ describe "Dashboard Feed" do end context 'feed content' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:issue) { create(:issue, project: project, author: user, description: '') } let(:note) { create(:note, noteable: issue, author: user, note: 'Bug confirmed', project: project) } diff --git a/spec/features/atom/issues_spec.rb b/spec/features/atom/issues_spec.rb index 3eeb4d35131..59e20d7e24d 100644 --- a/spec/features/atom/issues_spec.rb +++ b/spec/features/atom/issues_spec.rb @@ -5,7 +5,7 @@ describe 'Issues Feed' do let!(:user) { create(:user, email: 'private1@example.com', public_email: 'public1@example.com') } let!(:assignee) { create(:user, email: 'private2@example.com', public_email: 'public2@example.com') } let!(:group) { create(:group) } - let!(:project) { create(:project) } + let!(:project) { create(:empty_project) } let!(:issue) { create(:issue, author: user, assignees: [assignee], project: project) } before do diff --git a/spec/features/atom/users_spec.rb b/spec/features/atom/users_spec.rb index 052b07689f5..79069bbca8e 100644 --- a/spec/features/atom/users_spec.rb +++ b/spec/features/atom/users_spec.rb @@ -19,7 +19,7 @@ describe "User Feed" do end context 'feed content' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:issue) do create(:issue, project: project, -- cgit v1.2.1 From bc0d8112490e2966ffb5775815cd333f10e420a0 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 21 Jul 2017 17:55:42 -0400 Subject: Use `empty_project` where possible in spec/features/issuables (It wasn't possible.) --- spec/features/issuables/close_reopen_report_toggle_spec.rb | 4 ++-- spec/features/issuables/user_sees_sidebar_spec.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/features/issuables/close_reopen_report_toggle_spec.rb b/spec/features/issuables/close_reopen_report_toggle_spec.rb index cf1f0624140..0e43eed8699 100644 --- a/spec/features/issuables/close_reopen_report_toggle_spec.rb +++ b/spec/features/issuables/close_reopen_report_toggle_spec.rb @@ -79,7 +79,7 @@ describe 'Issuables Close/Reopen/Report toggle' do end context 'on a merge request' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:issuable) { create(:merge_request, source_project: project) } before do @@ -96,7 +96,7 @@ describe 'Issuables Close/Reopen/Report toggle' do end context 'when user doesnt have permission to update' do - let(:cant_project) { create(:project) } + let(:cant_project) { create(:project, :repository) } let(:cant_issuable) { create(:merge_request, source_project: cant_project) } before do diff --git a/spec/features/issuables/user_sees_sidebar_spec.rb b/spec/features/issuables/user_sees_sidebar_spec.rb index 948d151a517..2bd1c8aab86 100644 --- a/spec/features/issuables/user_sees_sidebar_spec.rb +++ b/spec/features/issuables/user_sees_sidebar_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe 'Issue Sidebar on Mobile' do include MobileHelpers - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } let(:issue) { create(:issue, project: project) } let!(:user) { create(:user)} -- cgit v1.2.1 From 1a0064dceb8f9b431bd4e668b1a1973522f6c2d3 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 24 Jul 2017 18:51:14 -0400 Subject: Use `empty_project` where possible in spec/features/projects --- spec/features/projects/artifacts/browse_spec.rb | 4 ++-- spec/features/projects/artifacts/download_spec.rb | 4 ++-- spec/features/projects/artifacts/file_spec.rb | 4 ++-- spec/features/projects/artifacts/raw_spec.rb | 4 ++-- spec/features/projects/badges/coverage_spec.rb | 4 ++-- spec/features/projects/badges/list_spec.rb | 2 +- spec/features/projects/blobs/blob_show_spec.rb | 2 +- spec/features/projects/branches/download_buttons_spec.rb | 2 +- .../projects/branches/new_branch_ref_dropdown_spec.rb | 2 +- spec/features/projects/branches_spec.rb | 2 +- spec/features/projects/commit/builds_spec.rb | 2 +- spec/features/projects/commit/cherry_pick_spec.rb | 2 +- spec/features/projects/commit/mini_pipeline_graph_spec.rb | 2 +- spec/features/projects/compare_spec.rb | 2 +- spec/features/projects/edit_spec.rb | 6 +++--- spec/features/projects/environments/environment_spec.rb | 2 +- spec/features/projects/environments/environments_spec.rb | 2 +- spec/features/projects/features_visibility_spec.rb | 4 ++-- spec/features/projects/files/browse_files_spec.rb | 2 +- spec/features/projects/files/creating_a_file_spec.rb | 2 +- spec/features/projects/files/dockerfile_dropdown_spec.rb | 2 +- spec/features/projects/files/download_buttons_spec.rb | 2 +- spec/features/projects/files/edit_file_soft_wrap_spec.rb | 2 +- spec/features/projects/files/editing_a_file_spec.rb | 2 +- spec/features/projects/files/find_file_keyboard_spec.rb | 2 +- spec/features/projects/files/find_files_spec.rb | 2 +- spec/features/projects/files/gitignore_dropdown_spec.rb | 2 +- spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb | 2 +- .../files/project_owner_creates_license_file_spec.rb | 2 +- spec/features/projects/files/template_type_dropdown_spec.rb | 2 +- spec/features/projects/files/undo_template_spec.rb | 2 +- spec/features/projects/gfm_autocomplete_load_spec.rb | 2 +- spec/features/projects/group_links_spec.rb | 4 ++-- spec/features/projects/import_export/import_file_spec.rb | 4 ++-- spec/features/projects/issuable_templates_spec.rb | 4 ++-- spec/features/projects/jobs_spec.rb | 2 +- .../projects/labels/issues_sorted_by_priority_spec.rb | 2 +- spec/features/projects/main/download_buttons_spec.rb | 2 +- .../members/group_member_cannot_leave_group_project_spec.rb | 2 +- ...member_cannot_request_access_to_his_group_project_spec.rb | 2 +- .../group_requester_cannot_request_access_to_project_spec.rb | 2 +- spec/features/projects/members/list_spec.rb | 2 +- .../members/master_adds_member_with_expiration_date_spec.rb | 2 +- .../member_cannot_request_access_to_his_project_spec.rb | 2 +- spec/features/projects/members/member_leaves_project_spec.rb | 2 +- .../projects/members/owner_cannot_leave_project_spec.rb | 2 +- .../owner_cannot_request_access_to_his_project_spec.rb | 2 +- spec/features/projects/members/user_requests_access_spec.rb | 2 +- spec/features/projects/merge_request_button_spec.rb | 4 ++-- spec/features/projects/merge_requests/list_spec.rb | 2 +- spec/features/projects/no_password_spec.rb | 2 +- spec/features/projects/pipeline_schedules_spec.rb | 2 +- spec/features/projects/pipelines/pipeline_spec.rb | 6 +++--- spec/features/projects/pipelines/pipelines_spec.rb | 12 ++++++------ spec/features/projects/project_settings_spec.rb | 6 ++---- spec/features/projects/ref_switcher_spec.rb | 2 +- spec/features/projects/services/slack_service_spec.rb | 2 +- spec/features/projects/services/slack_slash_command_spec.rb | 2 +- spec/features/projects/settings/visibility_settings_spec.rb | 2 +- spec/features/projects/shortcuts_spec.rb | 2 +- spec/features/projects/snippets/create_snippet_spec.rb | 2 +- spec/features/projects/user_browses_files_spec.rb | 2 +- spec/features/projects/user_creates_directory_spec.rb | 2 +- spec/features/projects/user_creates_files_spec.rb | 2 +- spec/features/projects/user_deletes_files_spec.rb | 2 +- spec/features/projects/user_edits_files_spec.rb | 2 +- spec/features/projects/user_replaces_files_spec.rb | 2 +- spec/features/projects/user_uploads_files_spec.rb | 2 +- spec/features/projects/wiki/markdown_preview_spec.rb | 2 +- spec/features/projects/wiki/user_creates_wiki_page_spec.rb | 4 ++-- .../features/projects/wiki/user_git_access_wiki_page_spec.rb | 2 +- spec/features/projects/wiki/user_updates_wiki_page_spec.rb | 4 ++-- .../projects/wiki/user_views_project_wiki_page_spec.rb | 2 +- 73 files changed, 95 insertions(+), 97 deletions(-) diff --git a/spec/features/projects/artifacts/browse_spec.rb b/spec/features/projects/artifacts/browse_spec.rb index 7dfb19f29bd..f5f7eba8e40 100644 --- a/spec/features/projects/artifacts/browse_spec.rb +++ b/spec/features/projects/artifacts/browse_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' feature 'Browse artifact', :js do - let(:project) { create(:project, :public) } - let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') } + let(:project) { create(:empty_project, :public) } + let(:pipeline) { create(:ci_empty_pipeline, project: project) } let(:job) { create(:ci_build, :artifacts, pipeline: pipeline) } def browse_path(path) diff --git a/spec/features/projects/artifacts/download_spec.rb b/spec/features/projects/artifacts/download_spec.rb index f1c210281ad..c1bba8c15c4 100644 --- a/spec/features/projects/artifacts/download_spec.rb +++ b/spec/features/projects/artifacts/download_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' feature 'Download artifact', :js do - let(:project) { create(:project, :public) } - let(:pipeline) { create(:ci_empty_pipeline, status: :success, project: project, sha: project.commit.sha, ref: 'master') } + let(:project) { create(:empty_project, :public) } + let(:pipeline) { create(:ci_empty_pipeline, status: :success, project: project) } let(:job) { create(:ci_build, :artifacts, :success, pipeline: pipeline) } shared_examples 'downloading' do diff --git a/spec/features/projects/artifacts/file_spec.rb b/spec/features/projects/artifacts/file_spec.rb index aaa98ac4851..4c268b876ea 100644 --- a/spec/features/projects/artifacts/file_spec.rb +++ b/spec/features/projects/artifacts/file_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' feature 'Artifact file', :js do - let(:project) { create(:project, :public) } - let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') } + let(:project) { create(:empty_project, :public) } + let(:pipeline) { create(:ci_empty_pipeline, project: project) } let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) } def visit_file(path) diff --git a/spec/features/projects/artifacts/raw_spec.rb b/spec/features/projects/artifacts/raw_spec.rb index 73292cb3873..128e39e7803 100644 --- a/spec/features/projects/artifacts/raw_spec.rb +++ b/spec/features/projects/artifacts/raw_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' feature 'Raw artifact', :js do - let(:project) { create(:project, :public) } - let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') } + let(:project) { create(:empty_project, :public) } + let(:pipeline) { create(:ci_empty_pipeline, project: project) } let(:job) { create(:ci_build, :artifacts, pipeline: pipeline) } def raw_path(path) diff --git a/spec/features/projects/badges/coverage_spec.rb b/spec/features/projects/badges/coverage_spec.rb index 5c5a7c96763..8cf4bfbf978 100644 --- a/spec/features/projects/badges/coverage_spec.rb +++ b/spec/features/projects/badges/coverage_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'test coverage badge' do given!(:user) { create(:user) } - given!(:project) { create(:project, :private) } + given!(:project) { create(:empty_project, :private) } context 'when user has access to view badge' do background do @@ -55,7 +55,7 @@ feature 'test coverage badge' do end def create_pipeline - opts = { project: project, ref: 'master', sha: project.commit.id } + opts = { project: project } create(:ci_pipeline, opts).tap do |pipeline| yield pipeline diff --git a/spec/features/projects/badges/list_spec.rb b/spec/features/projects/badges/list_spec.rb index fd8e9232b02..89ae891037e 100644 --- a/spec/features/projects/badges/list_spec.rb +++ b/spec/features/projects/badges/list_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'list of badges' do background do user = create(:user) - project = create(:project) + project = create(:project, :repository) project.team << [user, :master] sign_in(user) visit project_pipelines_settings_path(project) diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb index 8a32488b845..3d465e709b9 100644 --- a/spec/features/projects/blobs/blob_show_spec.rb +++ b/spec/features/projects/blobs/blob_show_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'File blob', :js do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } def visit_blob(path, anchor: nil, ref: 'master') visit project_blob_path(project, File.join(ref, path), anchor: anchor) diff --git a/spec/features/projects/branches/download_buttons_spec.rb b/spec/features/projects/branches/download_buttons_spec.rb index 47d7f27290b..ad06cee4e81 100644 --- a/spec/features/projects/branches/download_buttons_spec.rb +++ b/spec/features/projects/branches/download_buttons_spec.rb @@ -4,7 +4,7 @@ feature 'Download buttons in branches page' do given(:user) { create(:user) } given(:role) { :developer } given(:status) { 'success' } - given(:project) { create(:project) } + given(:project) { create(:project, :repository) } given(:pipeline) do create(:ci_pipeline, diff --git a/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb b/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb index 2123e96b816..0be434a567b 100644 --- a/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb +++ b/spec/features/projects/branches/new_branch_ref_dropdown_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'New Branch Ref Dropdown', :js do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:toggle) { find('.create-from .dropdown-menu-toggle') } before do diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb index 498dd8ee4bf..6e787de2dd6 100644 --- a/spec/features/projects/branches_spec.rb +++ b/spec/features/projects/branches_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Branches' do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:repository) { project.repository } def set_protected_branch_name(branch_name) diff --git a/spec/features/projects/commit/builds_spec.rb b/spec/features/projects/commit/builds_spec.rb index 257a7418f16..740331fe42a 100644 --- a/spec/features/projects/commit/builds_spec.rb +++ b/spec/features/projects/commit/builds_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'project commit pipelines', js: true do - given(:project) { create(:project) } + given(:project) { create(:project, :repository) } background do user = create(:user) diff --git a/spec/features/projects/commit/cherry_pick_spec.rb b/spec/features/projects/commit/cherry_pick_spec.rb index 2d18add82b5..7086f56bb1b 100644 --- a/spec/features/projects/commit/cherry_pick_spec.rb +++ b/spec/features/projects/commit/cherry_pick_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'Cherry-pick Commits' do let(:user) { create(:user) } let(:group) { create(:group) } - let(:project) { create(:project, namespace: group) } + let(:project) { create(:project, :repository, namespace: group) } let(:master_pickable_commit) { project.commit('7d3b0f7cff5f37573aea97cebfd5692ea1689924') } let(:master_pickable_merge) { project.commit('e56497bb5f03a90a51293fc6d516788730953899') } diff --git a/spec/features/projects/commit/mini_pipeline_graph_spec.rb b/spec/features/projects/commit/mini_pipeline_graph_spec.rb index 81a12225779..2ef74e8857c 100644 --- a/spec/features/projects/commit/mini_pipeline_graph_spec.rb +++ b/spec/features/projects/commit/mini_pipeline_graph_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Mini Pipeline Graph in Commit View', :js do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } before do sign_in(user) diff --git a/spec/features/projects/compare_spec.rb b/spec/features/projects/compare_spec.rb index 0f48751fa10..82d73fe8531 100644 --- a/spec/features/projects/compare_spec.rb +++ b/spec/features/projects/compare_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" describe "Compare", js: true do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do project.team << [user, :master] diff --git a/spec/features/projects/edit_spec.rb b/spec/features/projects/edit_spec.rb index d3b1d1f7be3..4b5436027f9 100644 --- a/spec/features/projects/edit_spec.rb +++ b/spec/features/projects/edit_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Project edit', js: true do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } before do project.team << [user, :master] @@ -20,7 +20,7 @@ feature 'Project edit', js: true do end context 'given project with merge_requests_disabled access level' do - let(:project) { create(:project, :merge_requests_disabled) } + let(:project) { create(:empty_project, :merge_requests_disabled) } it 'hides merge requests section' do expect(page).to have_selector('.merge-requests-feature', visible: false) @@ -36,7 +36,7 @@ feature 'Project edit', js: true do end context 'given project with builds_disabled access level' do - let(:project) { create(:project, :builds_disabled) } + let(:project) { create(:empty_project, :builds_disabled) } it 'hides builds select section' do expect(page).to have_selector('.builds-feature', visible: false) diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb index db29055812c..c6b7e611a5c 100644 --- a/spec/features/projects/environments/environment_spec.rb +++ b/spec/features/projects/environments/environment_spec.rb @@ -205,7 +205,7 @@ feature 'Environment' do end feature 'auto-close environment when branch is deleted' do - given(:project) { create(:project) } + given(:project) { create(:project, :repository) } given!(:environment) do create(:environment, :with_review_app, project: project, diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb index e40e0b0c871..36cf307fbe2 100644 --- a/spec/features/projects/environments/environments_spec.rb +++ b/spec/features/projects/environments/environments_spec.rb @@ -111,7 +111,7 @@ feature 'Environments page', :js do end context 'with deployments' do - given(:project) { create(:project) } + given(:project) { create(:project, :repository) } given(:deployment) do create(:deployment, environment: environment, diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb index 16b0fa6e1ae..37fa61d038e 100644 --- a/spec/features/projects/features_visibility_spec.rb +++ b/spec/features/projects/features_visibility_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Edit Project Settings' do let(:member) { create(:user) } - let!(:project) { create(:project, :public, path: 'gitlab', name: 'sample') } + let!(:project) { create(:project, :public, :repository) } let!(:issue) { create(:issue, project: project) } let(:non_member) { create(:user) } @@ -249,7 +249,7 @@ describe 'Edit Project Settings' do # Regression spec for https://gitlab.com/gitlab-org/gitlab-ce/issues/24056 describe 'project statistic visibility' do - let!(:project) { create(:project, :private) } + let!(:project) { create(:empty_project, :private) } before do project.team << [member, :guest] diff --git a/spec/features/projects/files/browse_files_spec.rb b/spec/features/projects/files/browse_files_spec.rb index 77b2fd4f80f..f62a9edd37e 100644 --- a/spec/features/projects/files/browse_files_spec.rb +++ b/spec/features/projects/files/browse_files_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'user browses project', js: true do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { create(:user) } before do diff --git a/spec/features/projects/files/creating_a_file_spec.rb b/spec/features/projects/files/creating_a_file_spec.rb index d49e1541869..e13bf4b6089 100644 --- a/spec/features/projects/files/creating_a_file_spec.rb +++ b/spec/features/projects/files/creating_a_file_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'User wants to create a file' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { create(:user) } background do diff --git a/spec/features/projects/files/dockerfile_dropdown_spec.rb b/spec/features/projects/files/dockerfile_dropdown_spec.rb index 6d44c49bb6f..cebb238dda1 100644 --- a/spec/features/projects/files/dockerfile_dropdown_spec.rb +++ b/spec/features/projects/files/dockerfile_dropdown_spec.rb @@ -4,7 +4,7 @@ require 'fileutils' feature 'User wants to add a Dockerfile file' do before do user = create(:user) - project = create(:project) + project = create(:project, :repository) project.team << [user, :master] sign_in user diff --git a/spec/features/projects/files/download_buttons_spec.rb b/spec/features/projects/files/download_buttons_spec.rb index 25168203d15..d2382d55c0b 100644 --- a/spec/features/projects/files/download_buttons_spec.rb +++ b/spec/features/projects/files/download_buttons_spec.rb @@ -4,7 +4,7 @@ feature 'Download buttons in files tree' do given(:user) { create(:user) } given(:role) { :developer } given(:status) { 'success' } - given(:project) { create(:project) } + given(:project) { create(:project, :repository) } given(:pipeline) do create(:ci_pipeline, diff --git a/spec/features/projects/files/edit_file_soft_wrap_spec.rb b/spec/features/projects/files/edit_file_soft_wrap_spec.rb index 8a4511df842..c7e3f657639 100644 --- a/spec/features/projects/files/edit_file_soft_wrap_spec.rb +++ b/spec/features/projects/files/edit_file_soft_wrap_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'User uses soft wrap whilst editing file', js: true do before do user = create(:user) - project = create(:project) + project = create(:project, :repository) project.team << [user, :master] sign_in user visit project_new_blob_path(project, 'master', file_name: 'test_file-name') diff --git a/spec/features/projects/files/editing_a_file_spec.rb b/spec/features/projects/files/editing_a_file_spec.rb index e084ab17441..20be968e89f 100644 --- a/spec/features/projects/files/editing_a_file_spec.rb +++ b/spec/features/projects/files/editing_a_file_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'User wants to edit a file' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:commit_params) do { diff --git a/spec/features/projects/files/find_file_keyboard_spec.rb b/spec/features/projects/files/find_file_keyboard_spec.rb index d7e96811e33..7f97fdb8cc9 100644 --- a/spec/features/projects/files/find_file_keyboard_spec.rb +++ b/spec/features/projects/files/find_file_keyboard_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Find file keyboard shortcuts', js: true do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do project.team << [user, :master] diff --git a/spec/features/projects/files/find_files_spec.rb b/spec/features/projects/files/find_files_spec.rb index 05003f6a4f5..57d67b28920 100644 --- a/spec/features/projects/files/find_files_spec.rb +++ b/spec/features/projects/files/find_files_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Find files button in the tree header' do given(:user) { create(:user) } - given(:project) { create(:project) } + given(:project) { create(:project, :repository) } background do sign_in(user) diff --git a/spec/features/projects/files/gitignore_dropdown_spec.rb b/spec/features/projects/files/gitignore_dropdown_spec.rb index 4340c98d0d9..e2044c9d5aa 100644 --- a/spec/features/projects/files/gitignore_dropdown_spec.rb +++ b/spec/features/projects/files/gitignore_dropdown_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'User wants to add a .gitignore file' do before do user = create(:user) - project = create(:project) + project = create(:project, :repository) project.team << [user, :master] sign_in user visit project_new_blob_path(project, 'master', file_name: '.gitignore') diff --git a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb index f42a26b6954..ab242b0b0b5 100644 --- a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb +++ b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'User wants to add a .gitlab-ci.yml file' do before do user = create(:user) - project = create(:project) + project = create(:project, :repository) project.team << [user, :master] sign_in user visit project_new_blob_path(project, 'master', file_name: '.gitlab-ci.yml') diff --git a/spec/features/projects/files/project_owner_creates_license_file_spec.rb b/spec/features/projects/files/project_owner_creates_license_file_spec.rb index 300b631a2f4..95af263bcac 100644 --- a/spec/features/projects/files/project_owner_creates_license_file_spec.rb +++ b/spec/features/projects/files/project_owner_creates_license_file_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'project owner creates a license file', js: true do let(:project_master) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } background do project.repository.delete_file(project_master, 'LICENSE', message: 'Remove LICENSE', branch_name: 'master') diff --git a/spec/features/projects/files/template_type_dropdown_spec.rb b/spec/features/projects/files/template_type_dropdown_spec.rb index a0846643269..48003eeaa87 100644 --- a/spec/features/projects/files/template_type_dropdown_spec.rb +++ b/spec/features/projects/files/template_type_dropdown_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Template type dropdown selector', js: true do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { create(:user) } before do diff --git a/spec/features/projects/files/undo_template_spec.rb b/spec/features/projects/files/undo_template_spec.rb index d50ddb1f1a9..4238d25e9ee 100644 --- a/spec/features/projects/files/undo_template_spec.rb +++ b/spec/features/projects/files/undo_template_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Template Undo Button', js: true do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { create(:user) } before do diff --git a/spec/features/projects/gfm_autocomplete_load_spec.rb b/spec/features/projects/gfm_autocomplete_load_spec.rb index 7bcd3f632a8..b63e5ae46ee 100644 --- a/spec/features/projects/gfm_autocomplete_load_spec.rb +++ b/spec/features/projects/gfm_autocomplete_load_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'GFM autocomplete loading', js: true do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } before do sign_in(create(:admin)) diff --git a/spec/features/projects/group_links_spec.rb b/spec/features/projects/group_links_spec.rb index 5195d027a9f..698baad97ff 100644 --- a/spec/features/projects/group_links_spec.rb +++ b/spec/features/projects/group_links_spec.rb @@ -4,7 +4,7 @@ feature 'Project group links', :js do include Select2Helper let(:master) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let!(:group) { create(:group) } background do @@ -35,7 +35,7 @@ feature 'Project group links', :js do context 'nested group project' do let!(:nested_group) { create(:group, parent: group) } let!(:another_group) { create(:group) } - let!(:project) { create(:project, namespace: nested_group) } + let!(:project) { create(:empty_project, namespace: nested_group) } background do group.add_master(master) diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb index c0cfb9eafe2..f924725870b 100644 --- a/spec/features/projects/import_export/import_file_spec.rb +++ b/spec/features/projects/import_export/import_file_spec.rb @@ -46,7 +46,7 @@ feature 'Import/Export - project import integration test', js: true do end scenario 'invalid project' do - project = create(:project, namespace: namespace) + project = create(:empty_project, namespace: namespace) visit new_project_path @@ -62,7 +62,7 @@ feature 'Import/Export - project import integration test', js: true do end scenario 'project with no name' do - create(:project, namespace: namespace) + create(:empty_project, namespace: namespace) visit new_project_path diff --git a/spec/features/projects/issuable_templates_spec.rb b/spec/features/projects/issuable_templates_spec.rb index 8c2e49377e7..d2789d0aa52 100644 --- a/spec/features/projects/issuable_templates_spec.rb +++ b/spec/features/projects/issuable_templates_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'issuable templates', js: true do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } before do project.team << [user, :master] @@ -120,7 +120,7 @@ feature 'issuable templates', js: true do context 'user creates a merge request from a forked project using templates' do let(:template_content) { 'this is a test "feature-proposal" template' } let(:fork_user) { create(:user) } - let(:fork_project) { create(:project, :public) } + let(:fork_project) { create(:project, :public, :repository) } let(:merge_request) { create(:merge_request, :with_diffs, source_project: fork_project, target_project: project) } background do diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index 395d68d3fb4..037ac00d39f 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -4,7 +4,7 @@ require 'tempfile' feature 'Jobs' do let(:user) { create(:user) } let(:user_access_level) { :developer } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) { create(:ci_pipeline, project: project) } let(:job) { create(:ci_build, :trace, pipeline: pipeline) } diff --git a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb index 0292a3192d8..2b0aead440c 100644 --- a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb +++ b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Issue prioritization' do let(:user) { create(:user) } - let(:project) { create(:project, name: 'test', namespace: user.namespace) } + let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) } # Labels let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) } diff --git a/spec/features/projects/main/download_buttons_spec.rb b/spec/features/projects/main/download_buttons_spec.rb index a8ae0ecbae0..3f2579bb01a 100644 --- a/spec/features/projects/main/download_buttons_spec.rb +++ b/spec/features/projects/main/download_buttons_spec.rb @@ -4,7 +4,7 @@ feature 'Download buttons in project main page' do given(:user) { create(:user) } given(:role) { :developer } given(:status) { 'success' } - given(:project) { create(:project) } + given(:project) { create(:project, :repository) } given(:pipeline) do create(:ci_pipeline, diff --git a/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb b/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb index 6b450fa4e45..1fb5e000239 100644 --- a/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb +++ b/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Projects > Members > Group member cannot leave group project' do let(:user) { create(:user) } let(:group) { create(:group) } - let(:project) { create(:project, namespace: group) } + let(:project) { create(:empty_project, namespace: group) } background do group.add_developer(user) diff --git a/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb b/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb index 296a80a3c60..8e3520f9f15 100644 --- a/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb +++ b/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Projects > Members > Group member cannot request access to his group project' do let(:user) { create(:user) } let(:group) { create(:group) } - let(:project) { create(:project, namespace: group) } + let(:project) { create(:empty_project, namespace: group) } scenario 'owner does not see the request access button' do group.add_owner(user) diff --git a/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb b/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb index c8988aa63a7..6865d721201 100644 --- a/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb +++ b/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb @@ -4,7 +4,7 @@ feature 'Projects > Members > Group requester cannot request access to project', let(:user) { create(:user) } let(:owner) { create(:user) } let(:group) { create(:group, :public, :access_requestable) } - let(:project) { create(:project, :public, :access_requestable, namespace: group) } + let(:project) { create(:empty_project, :public, :access_requestable, namespace: group) } background do group.add_owner(owner) diff --git a/spec/features/projects/members/list_spec.rb b/spec/features/projects/members/list_spec.rb index 237c059e595..f9c54d267b5 100644 --- a/spec/features/projects/members/list_spec.rb +++ b/spec/features/projects/members/list_spec.rb @@ -6,7 +6,7 @@ feature 'Project members list' do let(:user1) { create(:user, name: 'John Doe') } let(:user2) { create(:user, name: 'Mary Jane') } let(:group) { create(:group) } - let(:project) { create(:project, namespace: group) } + let(:project) { create(:empty_project, namespace: group) } background do sign_in(user1) diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb index cd621b6b3ce..b4381ea373e 100644 --- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb +++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb @@ -5,7 +5,7 @@ feature 'Projects > Members > Master adds member with expiration date', js: true include ActiveSupport::Testing::TimeHelpers let(:master) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let!(:new_member) { create(:user) } background do diff --git a/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb b/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb index 04806f8fd9e..7f39f5b2513 100644 --- a/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb +++ b/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Projects > Members > Member cannot request access to his project' do let(:member) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } background do project.team << [member, :developer] diff --git a/spec/features/projects/members/member_leaves_project_spec.rb b/spec/features/projects/members/member_leaves_project_spec.rb index e72283d3628..1bcf827d33c 100644 --- a/spec/features/projects/members/member_leaves_project_spec.rb +++ b/spec/features/projects/members/member_leaves_project_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Projects > Members > Member leaves project' do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } background do project.team << [user, :developer] diff --git a/spec/features/projects/members/owner_cannot_leave_project_spec.rb b/spec/features/projects/members/owner_cannot_leave_project_spec.rb index 15162d01c44..8b6d0aafcf8 100644 --- a/spec/features/projects/members/owner_cannot_leave_project_spec.rb +++ b/spec/features/projects/members/owner_cannot_leave_project_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Projects > Members > Owner cannot leave project' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } background do sign_in(project.owner) diff --git a/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb b/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb index c27925c8dc4..d838af6d976 100644 --- a/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb +++ b/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Projects > Members > Owner cannot request access to his project' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } background do sign_in(project.owner) diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb index 2979563f33a..24c9f708456 100644 --- a/spec/features/projects/members/user_requests_access_spec.rb +++ b/spec/features/projects/members/user_requests_access_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Projects > Members > User requests access' do let(:user) { create(:user) } - let(:project) { create(:project, :public, :access_requestable) } + let(:project) { create(:project, :public, :access_requestable, :repository) } let(:master) { project.owner } background do diff --git a/spec/features/projects/merge_request_button_spec.rb b/spec/features/projects/merge_request_button_spec.rb index 8cbd26551bc..85d518c0cc3 100644 --- a/spec/features/projects/merge_request_button_spec.rb +++ b/spec/features/projects/merge_request_button_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' feature 'Merge Request button' do shared_examples 'Merge request button only shown when allowed' do let(:user) { create(:user) } - let(:project) { create(:project, :public) } - let(:forked_project) { create(:project, :public, forked_from_project: project) } + let(:project) { create(:project, :public, :repository) } + let(:forked_project) { create(:project, :public, :repository, forked_from_project: project) } context 'not logged in' do it 'does not show Create merge request button' do diff --git a/spec/features/projects/merge_requests/list_spec.rb b/spec/features/projects/merge_requests/list_spec.rb index 6548b4b83e6..a879efef4b5 100644 --- a/spec/features/projects/merge_requests/list_spec.rb +++ b/spec/features/projects/merge_requests/list_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Merge Requests List' do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } background do project.team << [user, :developer] diff --git a/spec/features/projects/no_password_spec.rb b/spec/features/projects/no_password_spec.rb index d22a6daac08..6aff079dd39 100644 --- a/spec/features/projects/no_password_spec.rb +++ b/spec/features/projects/no_password_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'No Password Alert' do - let(:project) { create(:project, namespace: user.namespace) } + let(:project) { create(:project, :repository, namespace: user.namespace) } context 'with internal auth enabled' do before do diff --git a/spec/features/projects/pipeline_schedules_spec.rb b/spec/features/projects/pipeline_schedules_spec.rb index 47ed4c7e7c1..605415d2af4 100644 --- a/spec/features/projects/pipeline_schedules_spec.rb +++ b/spec/features/projects/pipeline_schedules_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Pipeline Schedules', :js do include PipelineSchedulesHelper - let!(:project) { create(:project) } + let!(:project) { create(:project, :repository) } let!(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project ) } let!(:pipeline) { create(:ci_pipeline, pipeline_schedule: pipeline_schedule) } let(:scope) { nil } diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index d4319bca331..0b626749275 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -42,7 +42,7 @@ describe 'Pipeline', :js do describe 'GET /:project/pipelines/:id' do include_context 'pipeline builds' - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id, user: user) } before do @@ -188,7 +188,7 @@ describe 'Pipeline', :js do describe 'GET /:project/pipelines/:id/builds' do include_context 'pipeline builds' - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) } before do @@ -262,7 +262,7 @@ describe 'Pipeline', :js do end describe 'GET /:project/pipelines/:id/failures' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) } let(:pipeline_failures_page) { failures_project_pipeline_path(project, pipeline) } let!(:failed_build) { create(:ci_build, :failed, pipeline: pipeline) } diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 6bef7317d30..59dff22eca3 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -12,7 +12,7 @@ describe 'Pipelines', :js do end describe 'GET /:project/pipelines' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let!(:pipeline) do create( @@ -385,7 +385,7 @@ describe 'Pipelines', :js do end describe 'GET /:project/pipelines/show' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) do create(:ci_empty_pipeline, @@ -437,7 +437,7 @@ describe 'Pipelines', :js do end describe 'POST /:project/pipelines' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do visit new_project_pipeline_path(project) @@ -476,7 +476,7 @@ describe 'Pipelines', :js do end describe 'Create pipelines' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do visit new_project_pipeline_path(project) @@ -512,14 +512,14 @@ describe 'Pipelines', :js do end context 'when project is public' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } it { expect(page).to have_content 'Build with confidence' } it { expect(page).to have_http_status(:success) } end context 'when project is private' do - let(:project) { create(:project, :private) } + let(:project) { create(:project, :private, :repository) } it { expect(page).to have_content 'You need to sign in' } end diff --git a/spec/features/projects/project_settings_spec.rb b/spec/features/projects/project_settings_spec.rb index 7e43ef92a72..6001bcfff0a 100644 --- a/spec/features/projects/project_settings_spec.rb +++ b/spec/features/projects/project_settings_spec.rb @@ -55,8 +55,7 @@ describe 'Edit Project Settings' do end context 'when changing project path' do - # Not using empty project because we need a repo to exist - let(:project) { create(:project, namespace: user.namespace, name: 'gitlabhq') } + let(:project) { create(:project, :repository, namespace: user.namespace, name: 'gitlabhq') } before(:context) do TestEnv.clean_test_path @@ -97,8 +96,7 @@ describe 'Edit Project Settings' do end describe 'Transfer project section', js: true do - # Not using empty project because we need a repo to exist - let!(:project) { create(:project, namespace: user.namespace, name: 'gitlabhq') } + let!(:project) { create(:project, :repository, namespace: user.namespace, name: 'gitlabhq') } let!(:group) { create(:group) } before(:context) do diff --git a/spec/features/projects/ref_switcher_spec.rb b/spec/features/projects/ref_switcher_spec.rb index 2512818b297..f0a23729220 100644 --- a/spec/features/projects/ref_switcher_spec.rb +++ b/spec/features/projects/ref_switcher_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Ref switcher', js: true do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } before do project.team << [user, :master] diff --git a/spec/features/projects/services/slack_service_spec.rb b/spec/features/projects/services/slack_service_spec.rb index c10ec5e2987..824cae261e0 100644 --- a/spec/features/projects/services/slack_service_spec.rb +++ b/spec/features/projects/services/slack_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Projects > Slack service > Setup events' do let(:user) { create(:user) } let(:service) { SlackService.new } - let(:project) { create(:project, slack_service: service) } + let(:project) { create(:empty_project, slack_service: service) } background do service.fields diff --git a/spec/features/projects/services/slack_slash_command_spec.rb b/spec/features/projects/services/slack_slash_command_spec.rb index a8baf126269..6002c589fba 100644 --- a/spec/features/projects/services/slack_slash_command_spec.rb +++ b/spec/features/projects/services/slack_slash_command_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Slack slash commands' do given(:user) { create(:user) } - given(:project) { create(:project) } + given(:project) { create(:empty_project) } given(:service) { project.create_slack_slash_commands_service } background do diff --git a/spec/features/projects/settings/visibility_settings_spec.rb b/spec/features/projects/settings/visibility_settings_spec.rb index 1756c7d00fe..1e705d211ea 100644 --- a/spec/features/projects/settings/visibility_settings_spec.rb +++ b/spec/features/projects/settings/visibility_settings_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Visibility settings', js: true do let(:user) { create(:user) } - let(:project) { create(:project, namespace: user.namespace, visibility_level: 20) } + let(:project) { create(:empty_project, namespace: user.namespace, visibility_level: 20) } context 'as owner' do before do diff --git a/spec/features/projects/shortcuts_spec.rb b/spec/features/projects/shortcuts_spec.rb index bf18c444c3d..2c6d0a56311 100644 --- a/spec/features/projects/shortcuts_spec.rb +++ b/spec/features/projects/shortcuts_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Project shortcuts' do - let(:project) { create(:project, name: 'Victorialand') } + let(:project) { create(:empty_project, name: 'Victorialand') } let(:user) { create(:user) } describe 'On a project', js: true do diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb index 23d4b9233b3..7f0e7e3116c 100644 --- a/spec/features/projects/snippets/create_snippet_spec.rb +++ b/spec/features/projects/snippets/create_snippet_spec.rb @@ -4,7 +4,7 @@ feature 'Create Snippet', :js do include DropzoneHelper let(:user) { create(:user) } - let(:project) { create(:project, :repository, :public) } + let(:project) { create(:empty_project, :public) } def fill_form fill_in 'project_snippet_title', with: 'My Snippet Title' diff --git a/spec/features/projects/user_browses_files_spec.rb b/spec/features/projects/user_browses_files_spec.rb index 263a3a29a66..b7a0b72db50 100644 --- a/spec/features/projects/user_browses_files_spec.rb +++ b/spec/features/projects/user_browses_files_spec.rb @@ -7,7 +7,7 @@ describe 'User browses files' do "You're not allowed to make changes to this project directly. "\ "A fork of this project has been created that you can make changes in, so you can submit a merge request." end - let(:project) { create(:project, name: 'Shop') } + let(:project) { create(:project, :repository, name: 'Shop') } let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') } let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) } let(:tree_path_ref_6d39438) { project_tree_path(project, '6d39438') } diff --git a/spec/features/projects/user_creates_directory_spec.rb b/spec/features/projects/user_creates_directory_spec.rb index 635bd4493dd..1ba5d83eadf 100644 --- a/spec/features/projects/user_creates_directory_spec.rb +++ b/spec/features/projects/user_creates_directory_spec.rb @@ -5,7 +5,7 @@ feature 'User creates a directory', js: true do "You're not allowed to make changes to this project directly. "\ "A fork of this project has been created that you can make changes in, so you can submit a merge request." end - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') } let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) } let(:user) { create(:user) } diff --git a/spec/features/projects/user_creates_files_spec.rb b/spec/features/projects/user_creates_files_spec.rb index 0c7f1a775c1..4b78cc4fc53 100644 --- a/spec/features/projects/user_creates_files_spec.rb +++ b/spec/features/projects/user_creates_files_spec.rb @@ -5,7 +5,7 @@ describe 'User creates files' do "You're not allowed to make changes to this project directly. "\ "A fork of this project has been created that you can make changes in, so you can submit a merge request." end - let(:project) { create(:project, name: 'Shop') } + let(:project) { create(:project, :repository, name: 'Shop') } let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') } let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) } let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) } diff --git a/spec/features/projects/user_deletes_files_spec.rb b/spec/features/projects/user_deletes_files_spec.rb index 97e60862b4f..95cd316be0e 100644 --- a/spec/features/projects/user_deletes_files_spec.rb +++ b/spec/features/projects/user_deletes_files_spec.rb @@ -5,7 +5,7 @@ describe 'User deletes files' do "You're not allowed to make changes to this project directly. "\ "A fork of this project has been created that you can make changes in, so you can submit a merge request." end - let(:project) { create(:project, name: 'Shop') } + let(:project) { create(:project, :repository, name: 'Shop') } let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') } let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) } let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) } diff --git a/spec/features/projects/user_edits_files_spec.rb b/spec/features/projects/user_edits_files_spec.rb index eb26f1bc123..8ae89c980b9 100644 --- a/spec/features/projects/user_edits_files_spec.rb +++ b/spec/features/projects/user_edits_files_spec.rb @@ -5,7 +5,7 @@ describe 'User edits files' do "You're not allowed to make changes to this project directly. "\ "A fork of this project has been created that you can make changes in, so you can submit a merge request." end - let(:project) { create(:project, name: 'Shop') } + let(:project) { create(:project, :repository, name: 'Shop') } let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') } let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) } let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) } diff --git a/spec/features/projects/user_replaces_files_spec.rb b/spec/features/projects/user_replaces_files_spec.rb index 50f2ffc4bbf..e284fdefd4f 100644 --- a/spec/features/projects/user_replaces_files_spec.rb +++ b/spec/features/projects/user_replaces_files_spec.rb @@ -7,7 +7,7 @@ describe 'User replaces files' do "You're not allowed to make changes to this project directly. "\ "A fork of this project has been created that you can make changes in, so you can submit a merge request." end - let(:project) { create(:project, name: 'Shop') } + let(:project) { create(:project, :repository, name: 'Shop') } let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') } let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) } let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) } diff --git a/spec/features/projects/user_uploads_files_spec.rb b/spec/features/projects/user_uploads_files_spec.rb index 64a1439badd..98871317ca3 100644 --- a/spec/features/projects/user_uploads_files_spec.rb +++ b/spec/features/projects/user_uploads_files_spec.rb @@ -7,7 +7,7 @@ describe 'User uploads files' do "You're not allowed to make changes to this project directly. "\ "A fork of this project has been created that you can make changes in, so you can submit a merge request." end - let(:project) { create(:project, name: 'Shop') } + let(:project) { create(:project, :repository, name: 'Shop') } let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') } let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) } let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) } diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb index 45f799ebb48..dbe98a38197 100644 --- a/spec/features/projects/wiki/markdown_preview_spec.rb +++ b/spec/features/projects/wiki/markdown_preview_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Projects > Wiki > User previews markdown changes', js: true do let(:user) { create(:user) } - let(:project) { create(:project, namespace: user.namespace) } + let(:project) { create(:empty_project, namespace: user.namespace) } let(:wiki_content) do <<-HEREDOC [regular link](regular) diff --git a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb index 9d66f482c8d..78c619f6301 100644 --- a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb @@ -11,7 +11,7 @@ feature 'Projects > Wiki > User creates wiki page', :js do end context 'in the user namespace' do - let(:project) { create(:project, namespace: user.namespace) } + let(:project) { create(:empty_project, namespace: user.namespace) } context 'when wiki is empty' do before do @@ -157,7 +157,7 @@ feature 'Projects > Wiki > User creates wiki page', :js do end context 'in a group namespace' do - let(:project) { create(:project, namespace: create(:group, :public)) } + let(:project) { create(:empty_project, namespace: create(:group, :public)) } context 'when wiki is empty' do before do diff --git a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb index 3450c91260b..9c58e336605 100644 --- a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Projects > Wiki > User views Git access wiki page' do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:wiki_page) do WikiPages::CreateService.new( project, diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb index 6ebf59cba98..251c9eac32c 100644 --- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb @@ -12,7 +12,7 @@ feature 'Projects > Wiki > User updates wiki page' do end context 'in the user namespace' do - let(:project) { create(:project, namespace: user.namespace) } + let(:project) { create(:empty_project, namespace: user.namespace) } context 'the home page' do scenario 'success when the wiki content is not empty' do @@ -54,7 +54,7 @@ feature 'Projects > Wiki > User updates wiki page' do end context 'in a group namespace' do - let(:project) { create(:project, namespace: create(:group, :public)) } + let(:project) { create(:empty_project, namespace: create(:group, :public)) } scenario 'the home page' do click_link 'Edit' diff --git a/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb b/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb index 92e96f11219..4f94ab1a609 100644 --- a/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Projects > Wiki > User views the wiki page' do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:old_page_version_id) { wiki_page.versions.last.id } let(:wiki_page) do WikiPages::CreateService.new( -- cgit v1.2.1 From 293ad11df400a60faef7ec30dcbdd7575a0be968 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 26 Jul 2017 17:49:06 -0400 Subject: Use `empty_project` where possible in spec/features/issues --- spec/features/issues/award_emoji_spec.rb | 2 +- spec/features/issues/award_spec.rb | 2 +- spec/features/issues/bulk_assignment_labels_spec.rb | 2 +- spec/features/issues/create_branch_merge_request_spec.rb | 2 +- .../create_issue_for_discussions_in_merge_request_spec.rb | 2 +- ...eate_issue_for_single_discussion_in_merge_request_spec.rb | 2 +- spec/features/issues/filtered_search/filter_issues_spec.rb | 2 +- spec/features/issues/form_spec.rb | 2 +- spec/features/issues/gfm_autocomplete_spec.rb | 2 +- spec/features/issues/issue_detail_spec.rb | 2 +- spec/features/issues/issue_sidebar_spec.rb | 2 +- spec/features/issues/markdown_toolbar_spec.rb | 4 ++-- spec/features/issues/move_spec.rb | 10 +++++----- spec/features/issues/notes_on_issues_spec.rb | 12 ++++++------ spec/features/issues/spam_issues_spec.rb | 2 +- spec/features/issues/todo_spec.rb | 6 +++--- spec/features/issues/update_issues_spec.rb | 2 +- spec/features/issues/user_uses_slash_commands_spec.rb | 2 +- 18 files changed, 30 insertions(+), 30 deletions(-) diff --git a/spec/features/issues/award_emoji_spec.rb b/spec/features/issues/award_emoji_spec.rb index 134e618feac..6cb0bf6fdfd 100644 --- a/spec/features/issues/award_emoji_spec.rb +++ b/spec/features/issues/award_emoji_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' describe 'Awards Emoji' do - let!(:project) { create(:project, :public) } + let!(:project) { create(:empty_project, :public) } let!(:user) { create(:user) } let(:issue) do create(:issue, diff --git a/spec/features/issues/award_spec.rb b/spec/features/issues/award_spec.rb index e95eb19f7d1..740281c1050 100644 --- a/spec/features/issues/award_spec.rb +++ b/spec/features/issues/award_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Issue awards', js: true do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:issue) { create(:issue, project: project) } describe 'logged in' do diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb index 847e3856ba5..5acf8fdae84 100644 --- a/spec/features/issues/bulk_assignment_labels_spec.rb +++ b/spec/features/issues/bulk_assignment_labels_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Issues > Labels bulk assignment' do let(:user) { create(:user) } - let!(:project) { create(:project) } + let!(:project) { create(:empty_project) } let!(:issue1) { create(:issue, project: project, title: "Issue 1") } let!(:issue2) { create(:issue, project: project, title: "Issue 2") } let!(:bug) { create(:label, project: project, title: 'bug') } diff --git a/spec/features/issues/create_branch_merge_request_spec.rb b/spec/features/issues/create_branch_merge_request_spec.rb index 88e81d12602..c10b99a4386 100644 --- a/spec/features/issues/create_branch_merge_request_spec.rb +++ b/spec/features/issues/create_branch_merge_request_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Create Branch/Merge Request Dropdown on issue page', js: true do let(:user) { create(:user) } - let!(:project) { create(:project) } + let!(:project) { create(:project, :repository) } let(:issue) { create(:issue, project: project, title: 'Cherry-Coloured Funk') } context 'for team members' do diff --git a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb index 3c51e8053da..80cc8d22999 100644 --- a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb +++ b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Resolving all open discussions in a merge request from an issue', js: true do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } let!(:discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion } diff --git a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb index d468c7d9c75..ad5fd0fd97b 100644 --- a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb +++ b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Resolve an open discussion in a merge request by creating an issue' do let(:user) { create(:user) } - let(:project) { create(:project, only_allow_merge_if_all_discussions_are_resolved: true) } + let(:project) { create(:project, :repository, only_allow_merge_if_all_discussions_are_resolved: true) } let(:merge_request) { create(:merge_request, source_project: project) } let!(:discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion } diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index cd2cbf4bfe7..265bcb3a8e5 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -5,7 +5,7 @@ describe 'Filter issues', js: true do include FilteredSearchHelpers let!(:group) { create(:group) } - let!(:project) { create(:project, group: group) } + let!(:project) { create(:empty_project, group: group) } let!(:user) { create(:user, username: 'joe', name: 'Joe') } let!(:user2) { create(:user, username: 'jane') } let!(:label) { create(:label, project: project) } diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb index b56b8744d7e..0ba02ba42ba 100644 --- a/spec/features/issues/form_spec.rb +++ b/spec/features/issues/form_spec.rb @@ -4,7 +4,7 @@ describe 'New/edit issue', :js do include ActionView::Helpers::JavaScriptHelper include FormHelper - let!(:project) { create(:project) } + let!(:project) { create(:empty_project) } let!(:user) { create(:user)} let!(:user2) { create(:user)} let!(:milestone) { create(:milestone, project: project) } diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb index b84635c5134..1b36f16e8b6 100644 --- a/spec/features/issues/gfm_autocomplete_spec.rb +++ b/spec/features/issues/gfm_autocomplete_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'GFM autocomplete', js: true do let(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:label) { create(:label, project: project, title: 'special+') } let(:issue) { create(:issue, project: project) } diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb index 28b636f9359..a7a7e02b59c 100644 --- a/spec/features/issues/issue_detail_spec.rb +++ b/spec/features/issues/issue_detail_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Issue Detail', :js do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:issue) { create(:issue, project: project, author: user) } context 'when user displays the issue' do diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb index 8e22441e0e8..28f93cfd971 100644 --- a/spec/features/issues/issue_sidebar_spec.rb +++ b/spec/features/issues/issue_sidebar_spec.rb @@ -4,7 +4,7 @@ feature 'Issue Sidebar' do include MobileHelpers let(:group) { create(:group, :nested) } - let(:project) { create(:project, :public, namespace: group) } + let(:project) { create(:empty_project, :public, namespace: group) } let(:issue) { create(:issue, project: project) } let!(:user) { create(:user)} let!(:label) { create(:label, project: project, title: 'bug') } diff --git a/spec/features/issues/markdown_toolbar_spec.rb b/spec/features/issues/markdown_toolbar_spec.rb index 6aed27e8790..0f869970460 100644 --- a/spec/features/issues/markdown_toolbar_spec.rb +++ b/spec/features/issues/markdown_toolbar_spec.rb @@ -1,9 +1,9 @@ require 'rails_helper' feature 'Issue markdown toolbar', js: true do - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:issue) { create(:issue, project: project) } - let(:user) { create(:user) } + let(:user) { create(:user) } before do sign_in(user) diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb index 833eb47efb2..2ab7d1a71b7 100644 --- a/spec/features/issues/move_spec.rb +++ b/spec/features/issues/move_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'issue move to another project' do let(:user) { create(:user) } - let(:old_project) { create(:project) } + let(:old_project) { create(:project, :repository) } let(:text) { 'Some issue description' } let(:issue) do @@ -25,8 +25,8 @@ feature 'issue move to another project' do context 'user has permission to move issue' do let!(:mr) { create(:merge_request, source_project: old_project) } - let(:new_project) { create(:project) } - let(:new_project_search) { create(:project) } + let(:new_project) { create(:empty_project) } + let(:new_project_search) { create(:empty_project) } let(:text) { "Text with #{mr.to_reference}" } let(:cross_reference) { old_project.to_reference(new_project) } @@ -63,8 +63,8 @@ feature 'issue move to another project' do end context 'user does not have permission to move the issue to a project', js: true do - let!(:private_project) { create(:project, :private) } - let(:another_project) { create(:project) } + let!(:private_project) { create(:empty_project, :private) } + let(:another_project) { create(:empty_project) } background { another_project.team << [user, :guest] } scenario 'browsing projects in projects select' do diff --git a/spec/features/issues/notes_on_issues_spec.rb b/spec/features/issues/notes_on_issues_spec.rb index be4c23645d9..29c9b99030a 100644 --- a/spec/features/issues/notes_on_issues_spec.rb +++ b/spec/features/issues/notes_on_issues_spec.rb @@ -35,42 +35,42 @@ describe 'Create notes on issues', :js do context 'mentioning issue on a private project' do it_behaves_like 'notes with reference' do - let(:project) { create(:project, :private) } + let(:project) { create(:empty_project, :private) } let(:mention) { create(:issue, project: project) } end end context 'mentioning issue on an internal project' do it_behaves_like 'notes with reference' do - let(:project) { create(:project, :internal) } + let(:project) { create(:empty_project, :internal) } let(:mention) { create(:issue, project: project) } end end context 'mentioning issue on a public project' do it_behaves_like 'notes with reference' do - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:mention) { create(:issue, project: project) } end end context 'mentioning merge request on a private project' do it_behaves_like 'notes with reference' do - let(:project) { create(:project, :private) } + let(:project) { create(:project, :private, :repository) } let(:mention) { create(:merge_request, source_project: project) } end end context 'mentioning merge request on an internal project' do it_behaves_like 'notes with reference' do - let(:project) { create(:project, :internal) } + let(:project) { create(:project, :internal, :repository) } let(:mention) { create(:merge_request, source_project: project) } end end context 'mentioning merge request on a public project' do it_behaves_like 'notes with reference' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:mention) { create(:merge_request, source_project: project) } end end diff --git a/spec/features/issues/spam_issues_spec.rb b/spec/features/issues/spam_issues_spec.rb index 332ce78b138..7a05e8b2ccc 100644 --- a/spec/features/issues/spam_issues_spec.rb +++ b/spec/features/issues/spam_issues_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe 'New issue', js: true do include StubENV - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:user) { create(:user)} before do diff --git a/spec/features/issues/todo_spec.rb b/spec/features/issues/todo_spec.rb index 7ca5ef4649a..2460ae817f9 100644 --- a/spec/features/issues/todo_spec.rb +++ b/spec/features/issues/todo_spec.rb @@ -1,9 +1,9 @@ require 'rails_helper' feature 'Manually create a todo item from issue', js: true do - let!(:project) { create(:project) } - let!(:issue) { create(:issue, project: project) } - let!(:user) { create(:user)} + let!(:project) { create(:empty_project) } + let!(:issue) { create(:issue, project: project) } + let!(:user) { create(:user)} before do project.team << [user, :master] diff --git a/spec/features/issues/update_issues_spec.rb b/spec/features/issues/update_issues_spec.rb index 5a7c4f54cb6..389151e63f0 100644 --- a/spec/features/issues/update_issues_spec.rb +++ b/spec/features/issues/update_issues_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' feature 'Multiple issue updating from issues#index', :js do - let!(:project) { create(:project) } + let!(:project) { create(:empty_project) } let!(:issue) { create(:issue, project: project) } let!(:user) { create(:user)} diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb index 4b63cc844f3..d28ad52ff56 100644 --- a/spec/features/issues/user_uses_slash_commands_spec.rb +++ b/spec/features/issues/user_uses_slash_commands_spec.rb @@ -9,7 +9,7 @@ feature 'Issues > User uses quick actions', js: true do describe 'issue-only commands' do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } before do project.team << [user, :master] -- cgit v1.2.1 From 56ae036e41e3234867a8d6c2b239bbce725425be Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 26 Jul 2017 17:52:10 -0400 Subject: Use `empty_project` where possible in spec/features/merge_requests --- spec/features/merge_requests/assign_issues_spec.rb | 2 +- spec/features/merge_requests/award_spec.rb | 2 +- .../check_if_mergeable_with_unresolved_discussions_spec.rb | 2 +- spec/features/merge_requests/cherry_pick_spec.rb | 2 +- spec/features/merge_requests/closes_issues_spec.rb | 2 +- spec/features/merge_requests/conflicts_spec.rb | 2 +- spec/features/merge_requests/create_new_mr_spec.rb | 6 +++--- spec/features/merge_requests/created_from_fork_spec.rb | 4 ++-- spec/features/merge_requests/diff_notes_avatars_spec.rb | 2 +- spec/features/merge_requests/diff_notes_resolve_spec.rb | 2 +- spec/features/merge_requests/diffs_spec.rb | 2 +- spec/features/merge_requests/edit_mr_spec.rb | 2 +- spec/features/merge_requests/filter_by_labels_spec.rb | 4 ++-- spec/features/merge_requests/filter_by_milestone_spec.rb | 2 +- spec/features/merge_requests/filter_merge_requests_spec.rb | 2 +- spec/features/merge_requests/form_spec.rb | 14 +++++++------- .../merge_requests/merge_commit_message_toggle_spec.rb | 2 +- .../merge_requests/merge_immediately_with_pipeline_spec.rb | 2 +- .../merge_requests/merge_when_pipeline_succeeds_spec.rb | 2 +- spec/features/merge_requests/mini_pipeline_graph_spec.rb | 2 +- spec/features/merge_requests/reset_filters_spec.rb | 2 +- spec/features/merge_requests/toggler_behavior_spec.rb | 2 +- spec/features/merge_requests/update_merge_requests_spec.rb | 2 +- .../merge_requests/user_lists_merge_requests_spec.rb | 2 +- spec/features/merge_requests/user_posts_notes_spec.rb | 2 +- .../features/merge_requests/user_sees_system_notes_spec.rb | 4 ++-- .../merge_requests/user_uses_slash_commands_spec.rb | 4 ++-- spec/features/merge_requests/widget_spec.rb | 4 ++-- spec/features/merge_requests/wip_message_spec.rb | 2 +- 29 files changed, 42 insertions(+), 42 deletions(-) diff --git a/spec/features/merge_requests/assign_issues_spec.rb b/spec/features/merge_requests/assign_issues_spec.rb index 04c2a694fff..63fa72650ac 100644 --- a/spec/features/merge_requests/assign_issues_spec.rb +++ b/spec/features/merge_requests/assign_issues_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Merge request issue assignment', js: true do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:issue1) { create(:issue, project: project) } let(:issue2) { create(:issue, project: project) } let(:merge_request) { create(:merge_request, :simple, source_project: project, author: user, description: "fixes #{issue1.to_reference} and #{issue2.to_reference}") } diff --git a/spec/features/merge_requests/award_spec.rb b/spec/features/merge_requests/award_spec.rb index 5a12d6f43f3..e886309133d 100644 --- a/spec/features/merge_requests/award_spec.rb +++ b/spec/features/merge_requests/award_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Merge request awards', js: true do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } describe 'logged in' do diff --git a/spec/features/merge_requests/check_if_mergeable_with_unresolved_discussions_spec.rb b/spec/features/merge_requests/check_if_mergeable_with_unresolved_discussions_spec.rb index c3d7d2fa23f..1f5e7b55fb0 100644 --- a/spec/features/merge_requests/check_if_mergeable_with_unresolved_discussions_spec.rb +++ b/spec/features/merge_requests/check_if_mergeable_with_unresolved_discussions_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Check if mergeable with unresolved discussions', js: true do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let!(:merge_request) { create(:merge_request_with_diff_notes, source_project: project, author: user) } before do diff --git a/spec/features/merge_requests/cherry_pick_spec.rb b/spec/features/merge_requests/cherry_pick_spec.rb index e4c33d57e8d..4b1e1b9a8d4 100644 --- a/spec/features/merge_requests/cherry_pick_spec.rb +++ b/spec/features/merge_requests/cherry_pick_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'Cherry-pick Merge Requests', js: true do let(:user) { create(:user) } let(:group) { create(:group) } - let(:project) { create(:project, namespace: group) } + let(:project) { create(:project, :repository, namespace: group) } let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user) } before do diff --git a/spec/features/merge_requests/closes_issues_spec.rb b/spec/features/merge_requests/closes_issues_spec.rb index 24000ea75d1..0e97254eada 100644 --- a/spec/features/merge_requests/closes_issues_spec.rb +++ b/spec/features/merge_requests/closes_issues_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Merge Request closing issues message', js: true do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:issue_1) { create(:issue, project: project)} let(:issue_2) { create(:issue, project: project)} let(:merge_request) do diff --git a/spec/features/merge_requests/conflicts_spec.rb b/spec/features/merge_requests/conflicts_spec.rb index 3c5ddf8396d..2c560632a1b 100644 --- a/spec/features/merge_requests/conflicts_spec.rb +++ b/spec/features/merge_requests/conflicts_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Merge request conflict resolution', js: true do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do # In order to have the diffs collapsed, we need to disable the increase feature diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb index 67322bdc8a8..11a74276898 100644 --- a/spec/features/merge_requests/create_new_mr_spec.rb +++ b/spec/features/merge_requests/create_new_mr_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Create New Merge Request', js: true do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } before do project.team << [user, :master] @@ -63,7 +63,7 @@ feature 'Create New Merge Request', js: true do context 'when target project cannot be viewed by the current user' do it 'does not leak the private project name & namespace' do - private_project = create(:project, :private) + private_project = create(:project, :private, :repository) visit project_new_merge_request_path(project, merge_request: { target_project_id: private_project.id }) @@ -74,7 +74,7 @@ feature 'Create New Merge Request', js: true do context 'when source project cannot be viewed by the current user' do it 'does not leak the private project name & namespace' do - private_project = create(:project, :private) + private_project = create(:project, :private, :repository) visit project_new_merge_request_path(project, merge_request: { source_project_id: private_project.id }) diff --git a/spec/features/merge_requests/created_from_fork_spec.rb b/spec/features/merge_requests/created_from_fork_spec.rb index 9b7795ace62..68d793ec9ba 100644 --- a/spec/features/merge_requests/created_from_fork_spec.rb +++ b/spec/features/merge_requests/created_from_fork_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' feature 'Merge request created from fork' do given(:user) { create(:user) } - given(:project) { create(:project, :public) } - given(:fork_project) { create(:project, :public) } + given(:project) { create(:project, :public, :repository) } + given(:fork_project) { create(:project, :public, :repository) } given!(:merge_request) do create(:forked_project_link, forked_to_project: fork_project, diff --git a/spec/features/merge_requests/diff_notes_avatars_spec.rb b/spec/features/merge_requests/diff_notes_avatars_spec.rb index 7f082f12d47..2d9419d6124 100644 --- a/spec/features/merge_requests/diff_notes_avatars_spec.rb +++ b/spec/features/merge_requests/diff_notes_avatars_spec.rb @@ -4,7 +4,7 @@ feature 'Diff note avatars', js: true do include NoteInteractionHelpers let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user, title: "Bug NS-04") } let(:path) { "files/ruby/popen.rb" } let(:position) do diff --git a/spec/features/merge_requests/diff_notes_resolve_spec.rb b/spec/features/merge_requests/diff_notes_resolve_spec.rb index a2f0b24d6a8..ac7f75bd308 100644 --- a/spec/features/merge_requests/diff_notes_resolve_spec.rb +++ b/spec/features/merge_requests/diff_notes_resolve_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Diff notes resolve', js: true do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user, title: "Bug NS-04") } let!(:note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request) } let(:path) { "files/ruby/popen.rb" } diff --git a/spec/features/merge_requests/diffs_spec.rb b/spec/features/merge_requests/diffs_spec.rb index 499cd38e648..201be4b9e40 100644 --- a/spec/features/merge_requests/diffs_spec.rb +++ b/spec/features/merge_requests/diffs_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Diffs URL', js: true do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } context 'when visit with */* as accept header' do diff --git a/spec/features/merge_requests/edit_mr_spec.rb b/spec/features/merge_requests/edit_mr_spec.rb index 2b0ecfc8c72..7386e78fb13 100644 --- a/spec/features/merge_requests/edit_mr_spec.rb +++ b/spec/features/merge_requests/edit_mr_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Edit Merge Request' do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:merge_request) { create(:merge_request, :simple, source_project: project) } before do diff --git a/spec/features/merge_requests/filter_by_labels_spec.rb b/spec/features/merge_requests/filter_by_labels_spec.rb index 220e0c8dc68..1d52a4659ad 100644 --- a/spec/features/merge_requests/filter_by_labels_spec.rb +++ b/spec/features/merge_requests/filter_by_labels_spec.rb @@ -1,10 +1,10 @@ require 'rails_helper' -feature 'Issue filtering by Labels', js: true do +feature 'Merge Request filtering by Labels', js: true do include FilteredSearchHelpers include MergeRequestHelpers - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let!(:user) { create(:user) } let!(:label) { create(:label, project: project) } diff --git a/spec/features/merge_requests/filter_by_milestone_spec.rb b/spec/features/merge_requests/filter_by_milestone_spec.rb index f6b9aa733a4..521fcabc881 100644 --- a/spec/features/merge_requests/filter_by_milestone_spec.rb +++ b/spec/features/merge_requests/filter_by_milestone_spec.rb @@ -4,7 +4,7 @@ feature 'Merge Request filtering by Milestone' do include FilteredSearchHelpers include MergeRequestHelpers - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let!(:user) { create(:user)} let(:milestone) { create(:milestone, project: project) } diff --git a/spec/features/merge_requests/filter_merge_requests_spec.rb b/spec/features/merge_requests/filter_merge_requests_spec.rb index 38eb158d06e..f0019be86ad 100644 --- a/spec/features/merge_requests/filter_merge_requests_spec.rb +++ b/spec/features/merge_requests/filter_merge_requests_spec.rb @@ -4,7 +4,7 @@ describe 'Filter merge requests' do include FilteredSearchHelpers include MergeRequestHelpers - let!(:project) { create(:project) } + let!(:project) { create(:project, :repository) } let!(:group) { create(:group) } let!(:user) { create(:user) } let!(:milestone) { create(:milestone, project: project) } diff --git a/spec/features/merge_requests/form_spec.rb b/spec/features/merge_requests/form_spec.rb index e06cd627b20..6ffb05c5030 100644 --- a/spec/features/merge_requests/form_spec.rb +++ b/spec/features/merge_requests/form_spec.rb @@ -1,13 +1,13 @@ require 'rails_helper' describe 'New/edit merge request', :js do - let!(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } - let(:fork_project) { create(:project, forked_from_project: project) } - let!(:user) { create(:user)} - let!(:user2) { create(:user)} - let!(:milestone) { create(:milestone, project: project) } - let!(:label) { create(:label, project: project) } - let!(:label2) { create(:label, project: project) } + let!(:project) { create(:project, :public, :repository) } + let(:fork_project) { create(:project, :repository, forked_from_project: project) } + let!(:user) { create(:user) } + let!(:user2) { create(:user) } + let!(:milestone) { create(:milestone, project: project) } + let!(:label) { create(:label, project: project) } + let!(:label2) { create(:label, project: project) } before do project.team << [user, :master] diff --git a/spec/features/merge_requests/merge_commit_message_toggle_spec.rb b/spec/features/merge_requests/merge_commit_message_toggle_spec.rb index 784f362a28f..429bc277d73 100644 --- a/spec/features/merge_requests/merge_commit_message_toggle_spec.rb +++ b/spec/features/merge_requests/merge_commit_message_toggle_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Clicking toggle commit message link', js: true do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:issue_1) { create(:issue, project: project)} let(:issue_2) { create(:issue, project: project)} let(:merge_request) do diff --git a/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb b/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb index 13142d3b3c9..0b5a595acce 100644 --- a/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb +++ b/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Merge immediately', :js do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let!(:merge_request) do create(:merge_request_with_diffs, source_project: project, diff --git a/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb b/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb index 9fbdc1b2c80..574f5fe353e 100644 --- a/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb +++ b/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Merge When Pipeline Succeeds', :js do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:merge_request) do create(:merge_request_with_diffs, source_project: project, diff --git a/spec/features/merge_requests/mini_pipeline_graph_spec.rb b/spec/features/merge_requests/mini_pipeline_graph_spec.rb index ee6e440e70d..b1215f9ba63 100644 --- a/spec/features/merge_requests/mini_pipeline_graph_spec.rb +++ b/spec/features/merge_requests/mini_pipeline_graph_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Mini Pipeline Graph', :js do let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:merge_request) { create(:merge_request, source_project: project, head_pipeline: pipeline) } let(:pipeline) { create(:ci_empty_pipeline, project: project, ref: 'master', status: 'running', sha: project.commit.id) } diff --git a/spec/features/merge_requests/reset_filters_spec.rb b/spec/features/merge_requests/reset_filters_spec.rb index 423213709a3..c1b90e5f875 100644 --- a/spec/features/merge_requests/reset_filters_spec.rb +++ b/spec/features/merge_requests/reset_filters_spec.rb @@ -5,7 +5,7 @@ feature 'Merge requests filter clear button', js: true do include MergeRequestHelpers include IssueHelpers - let!(:project) { create(:project, :public) } + let!(:project) { create(:project, :public, :repository) } let!(:user) { create(:user) } let!(:milestone) { create(:milestone, project: project) } let!(:bug) { create(:label, project: project, name: 'bug')} diff --git a/spec/features/merge_requests/toggler_behavior_spec.rb b/spec/features/merge_requests/toggler_behavior_spec.rb index 2283164ca2f..4e5ec9fbd2d 100644 --- a/spec/features/merge_requests/toggler_behavior_spec.rb +++ b/spec/features/merge_requests/toggler_behavior_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'toggler_behavior', js: true do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, source_project: project, author: user) } let(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) } let(:fragment_id) { "#note_#{note.id}" } diff --git a/spec/features/merge_requests/update_merge_requests_spec.rb b/spec/features/merge_requests/update_merge_requests_spec.rb index db2f2b523d2..cf30a687df8 100644 --- a/spec/features/merge_requests/update_merge_requests_spec.rb +++ b/spec/features/merge_requests/update_merge_requests_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Multiple merge requests updating from merge_requests#index' do let!(:user) { create(:user)} - let!(:project) { create(:project) } + let!(:project) { create(:project, :repository) } let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } before do diff --git a/spec/features/merge_requests/user_lists_merge_requests_spec.rb b/spec/features/merge_requests/user_lists_merge_requests_spec.rb index d38d2d57b35..d62b035b40b 100644 --- a/spec/features/merge_requests/user_lists_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_lists_merge_requests_spec.rb @@ -4,7 +4,7 @@ describe 'Projects > Merge requests > User lists merge requests' do include MergeRequestHelpers include SortingHelper - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:user) { create(:user) } before do diff --git a/spec/features/merge_requests/user_posts_notes_spec.rb b/spec/features/merge_requests/user_posts_notes_spec.rb index 35ed08e0a5e..74d21822a59 100644 --- a/spec/features/merge_requests/user_posts_notes_spec.rb +++ b/spec/features/merge_requests/user_posts_notes_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'Merge requests > User posts notes', :js do include NoteInteractionHelpers - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) do create(:merge_request, source_project: project, target_project: project) end diff --git a/spec/features/merge_requests/user_sees_system_notes_spec.rb b/spec/features/merge_requests/user_sees_system_notes_spec.rb index 624a425ae52..03dc61c2efa 100644 --- a/spec/features/merge_requests/user_sees_system_notes_spec.rb +++ b/spec/features/merge_requests/user_sees_system_notes_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' feature 'Merge requests > User sees system notes' do - let(:public_project) { create(:project, :public) } - let(:private_project) { create(:project, :private) } + let(:public_project) { create(:project, :public, :repository) } + let(:private_project) { create(:project, :private, :repository) } let(:issue) { create(:issue, project: private_project) } let(:merge_request) { create(:merge_request, source_project: public_project, source_branch: 'markdown') } let!(:note) { create(:note_on_merge_request, :system, noteable: merge_request, project: public_project, note: "mentioned in #{issue.to_reference(public_project)}") } diff --git a/spec/features/merge_requests/user_uses_slash_commands_spec.rb b/spec/features/merge_requests/user_uses_slash_commands_spec.rb index 881527e1501..43cab65d287 100644 --- a/spec/features/merge_requests/user_uses_slash_commands_spec.rb +++ b/spec/features/merge_requests/user_uses_slash_commands_spec.rb @@ -4,7 +4,7 @@ feature 'Merge Requests > User uses quick actions', js: true do include QuickActionsHelpers let(:user) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } let!(:milestone) { create(:milestone, project: project, title: 'ASAP') } @@ -129,7 +129,7 @@ feature 'Merge Requests > User uses quick actions', js: true do end describe '/target_branch command in merge request' do - let(:another_project) { create(:project, :public) } + let(:another_project) { create(:project, :public, :repository) } let(:new_url_opts) { { merge_request: { source_branch: 'feature' } } } before do diff --git a/spec/features/merge_requests/widget_spec.rb b/spec/features/merge_requests/widget_spec.rb index 8d7bbf14d86..69e31c7481f 100644 --- a/spec/features/merge_requests/widget_spec.rb +++ b/spec/features/merge_requests/widget_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' describe 'Merge request', :js do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } before do @@ -200,7 +200,7 @@ describe 'Merge request', :js do end context 'user can merge into source project but cannot push to fork', js: true do - let(:fork_project) { create(:project, :public) } + let(:fork_project) { create(:project, :public, :repository) } let(:user2) { create(:user) } before do diff --git a/spec/features/merge_requests/wip_message_spec.rb b/spec/features/merge_requests/wip_message_spec.rb index 5a685056bf3..b422c76249d 100644 --- a/spec/features/merge_requests/wip_message_spec.rb +++ b/spec/features/merge_requests/wip_message_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Work In Progress help message' do - let!(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } + let!(:project) { create(:project, :public, :repository) } let!(:user) { create(:user) } before do -- cgit v1.2.1 From abe396842ef10c0aad40c5ba196b947892aa50e4 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 26 Jul 2017 18:01:19 -0400 Subject: Use `empty_project` where possible in spec/features/security --- spec/features/security/group/internal_access_spec.rb | 3 ++- spec/features/security/group/private_access_spec.rb | 3 ++- spec/features/security/group/public_access_spec.rb | 3 ++- spec/features/security/project/internal_access_spec.rb | 2 +- spec/features/security/project/private_access_spec.rb | 2 +- spec/features/security/project/public_access_spec.rb | 2 +- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/spec/features/security/group/internal_access_spec.rb b/spec/features/security/group/internal_access_spec.rb index 53573043ac7..bf7be33013e 100644 --- a/spec/features/security/group/internal_access_spec.rb +++ b/spec/features/security/group/internal_access_spec.rb @@ -4,7 +4,7 @@ describe 'Internal Group access' do include AccessMatchers let(:group) { create(:group, :internal) } - let(:project) { create(:project, :internal, group: group) } + let(:project) { create(:empty_project, :internal, group: group) } let(:project_guest) do create(:user) do |user| project.add_guest(user) @@ -49,6 +49,7 @@ describe 'Internal Group access' do end describe 'GET /groups/:path/merge_requests' do + let(:project) { create(:project, :internal, :repository, group: group) } subject { merge_requests_group_path(group) } it { is_expected.to be_allowed_for(:admin) } diff --git a/spec/features/security/group/private_access_spec.rb b/spec/features/security/group/private_access_spec.rb index 76c4e2c7197..c399d7a0851 100644 --- a/spec/features/security/group/private_access_spec.rb +++ b/spec/features/security/group/private_access_spec.rb @@ -4,7 +4,7 @@ describe 'Private Group access' do include AccessMatchers let(:group) { create(:group, :private) } - let(:project) { create(:project, :private, group: group) } + let(:project) { create(:empty_project, :private, group: group) } let(:project_guest) do create(:user) do |user| project.add_guest(user) @@ -49,6 +49,7 @@ describe 'Private Group access' do end describe 'GET /groups/:path/merge_requests' do + let(:project) { create(:project, :private, :repository, group: group) } subject { merge_requests_group_path(group) } it { is_expected.to be_allowed_for(:admin) } diff --git a/spec/features/security/group/public_access_spec.rb b/spec/features/security/group/public_access_spec.rb index 52e87d8d055..63e4d7ca65c 100644 --- a/spec/features/security/group/public_access_spec.rb +++ b/spec/features/security/group/public_access_spec.rb @@ -4,7 +4,7 @@ describe 'Public Group access' do include AccessMatchers let(:group) { create(:group, :public) } - let(:project) { create(:project, :public, group: group) } + let(:project) { create(:empty_project, :public, group: group) } let(:project_guest) do create(:user) do |user| project.add_guest(user) @@ -49,6 +49,7 @@ describe 'Public Group access' do end describe 'GET /groups/:path/merge_requests' do + let(:project) { create(:project, :public, :repository, group: group) } subject { merge_requests_group_path(group) } it { is_expected.to be_allowed_for(:admin) } diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb index 290cebf511a..a7928857b7d 100644 --- a/spec/features/security/project/internal_access_spec.rb +++ b/spec/features/security/project/internal_access_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe "Internal Project Access" do include AccessMatchers - set(:project) { create(:project, :internal) } + set(:project) { create(:project, :internal, :repository) } describe "Project should be internal" do describe '#internal?' do diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb index 276d817b59c..a4396b20afd 100644 --- a/spec/features/security/project/private_access_spec.rb +++ b/spec/features/security/project/private_access_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe "Private Project Access" do include AccessMatchers - set(:project) { create(:project, :private, public_builds: false) } + set(:project) { create(:project, :private, :repository, public_builds: false) } describe "Project should be private" do describe '#private?' do diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb index 417b0894a5c..fccdeb0e5b7 100644 --- a/spec/features/security/project/public_access_spec.rb +++ b/spec/features/security/project/public_access_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe "Public Project Access" do include AccessMatchers - set(:project) { create(:project, :public) } + set(:project) { create(:project, :public, :repository) } describe "Project should be public" do describe '#public?' do -- cgit v1.2.1 From fa273263404925dc35db263091429dc0e4173107 Mon Sep 17 00:00:00 2001 From: Joshua Lambert Date: Thu, 27 Jul 2017 14:05:58 -0400 Subject: Rename the metric groups --- config/prometheus/additional_metrics.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/prometheus/additional_metrics.yml b/config/prometheus/additional_metrics.yml index 61d39e7bfcf..5eb01d62924 100644 --- a/config/prometheus/additional_metrics.yml +++ b/config/prometheus/additional_metrics.yml @@ -1,4 +1,4 @@ -- group: HA Proxy +- group: Response metrics (HA Proxy) priority: 10 metrics: - title: "Throughput" @@ -19,7 +19,7 @@ - query_range: 'sum(rate(haproxy_frontend_http_responses_total{code="5xx",%{environment_filter}}[2m])) / sum(rate(haproxy_frontend_http_responses_total{%{environment_filter}}[2m]))' label: HTTP Errors unit: "%" -- group: AWS Elastic Load Balancer +- group: Response metrics (AWS ELB) priority: 10 metrics: - title: "Throughput" @@ -50,7 +50,7 @@ - query_range: 'sum(aws_elb_httpcode_backend_5_xx_sum{%{environment_filter}}) / sum(aws_elb_request_count_sum{%{environment_filter}})' label: HTTP Errors unit: "%" -- group: NGINX +- group: Response metrics (NGINX) priority: 10 metrics: - title: "Throughput" @@ -80,7 +80,7 @@ - query_range: 'sum(rate(nginx_responses_total{status_code="5xx", %{environment_filter}}[2m])) / sum(rate(nginx_requests_total{server_zone!="*", server_zone!="_", %{environment_filter}}[2m]))' label: HTTP Errors unit: "%" -- group: Kubernetes +- group: System metrics (Kubernetes) priority: 5 metrics: - title: "Memory Usage" -- cgit v1.2.1 From cd5ae5cb2beeeff132d88805c888d1962419931f Mon Sep 17 00:00:00 2001 From: Ahmad Sherif Date: Tue, 25 Jul 2017 21:49:12 +0200 Subject: Migrate Repository#tags to Gitaly Closes gitaly#411 --- GITALY_SERVER_VERSION | 2 +- Gemfile | 2 +- Gemfile.lock | 4 ++-- lib/gitlab/git/repository.rb | 40 ++++++++++++++++++++++----------- lib/gitlab/gitaly_client/ref_service.rb | 25 +++++++++++++++++++++ spec/lib/gitlab/git/tag_spec.rb | 38 +++++++++++++++++++------------ 6 files changed, 80 insertions(+), 31 deletions(-) diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index ca222b7cf39..d21d277be51 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -0.23.0 +0.25.0 diff --git a/Gemfile b/Gemfile index aa38090e44a..afea07ee6ff 100644 --- a/Gemfile +++ b/Gemfile @@ -391,7 +391,7 @@ gem 'vmstat', '~> 2.3.0' gem 'sys-filesystem', '~> 1.1.6' # Gitaly GRPC client -gem 'gitaly', '~> 0.18.0' +gem 'gitaly', '~> 0.21.0' gem 'toml-rb', '~> 0.3.15', require: false diff --git a/Gemfile.lock b/Gemfile.lock index d124cd00ee0..627750e2c1d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -269,7 +269,7 @@ GEM po_to_json (>= 1.0.0) rails (>= 3.2.0) gherkin-ruby (0.3.2) - gitaly (0.18.0) + gitaly (0.21.0) google-protobuf (~> 3.1) grpc (~> 1.0) github-linguist (4.7.6) @@ -976,7 +976,7 @@ DEPENDENCIES gettext (~> 3.2.2) gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails_js (~> 1.2.0) - gitaly (~> 0.18.0) + gitaly (~> 0.21.0) github-linguist (~> 4.7.0) gitlab-flowdock-git-hook (~> 1.0.1) gitlab-markup (~> 1.5.1) diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 3e27fd7b682..efb4f983cfa 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -164,20 +164,13 @@ module Gitlab # # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/390 def tags - rugged.references.each("refs/tags/*").map do |ref| - message = nil - - if ref.target.is_a?(Rugged::Tag::Annotation) - tag_message = ref.target.message - - if tag_message.respond_to?(:chomp) - message = tag_message.chomp - end + gitaly_migrate(:tags) do |is_enabled| + if is_enabled + tags_from_gitaly + else + tags_from_rugged end - - target_commit = Gitlab::Git::Commit.find(self, ref.target) - Gitlab::Git::Tag.new(self, ref.name, ref.target, target_commit, message) - end.sort_by(&:name) + end end # Returns true if the given tag exists @@ -1115,6 +1108,27 @@ module Gitlab end end + def tags_from_rugged + rugged.references.each("refs/tags/*").map do |ref| + message = nil + + if ref.target.is_a?(Rugged::Tag::Annotation) + tag_message = ref.target.message + + if tag_message.respond_to?(:chomp) + message = tag_message.chomp + end + end + + target_commit = Gitlab::Git::Commit.find(self, ref.target) + Gitlab::Git::Tag.new(self, ref.name, ref.target, target_commit, message) + end.sort_by(&:name) + end + + def tags_from_gitaly + gitaly_ref_client.tags + end + def gitaly_migrate(method, &block) Gitlab::GitalyClient.migrate(method, &block) rescue GRPC::NotFound => e diff --git a/lib/gitlab/gitaly_client/ref_service.rb b/lib/gitlab/gitaly_client/ref_service.rb index 2c3d53410ac..2306fb3cbf5 100644 --- a/lib/gitlab/gitaly_client/ref_service.rb +++ b/lib/gitlab/gitaly_client/ref_service.rb @@ -52,6 +52,12 @@ module Gitlab consume_branches_response(response) end + def tags + request = Gitaly::FindAllTagsRequest.new(repository: @gitaly_repo) + response = GitalyClient.call(@storage, :ref_service, :find_all_tags, request) + consume_tags_response(response) + end + private def consume_refs_response(response) @@ -79,6 +85,25 @@ module Gitlab end end + def consume_tags_response(response) + response.flat_map do |message| + message.tags.map do |gitaly_tag| + if gitaly_tag.target_commit.present? + commit = GitalyClient::Commit.new(@repository, gitaly_tag.target_commit) + gitaly_commit = Gitlab::Git::Commit.new(commit) + end + + Gitlab::Git::Tag.new( + @repository, + encode!(gitaly_tag.name.dup), + gitaly_tag.id, + gitaly_commit, + encode!(gitaly_tag.message.chomp) + ) + end + end + end + def commit_from_local_branches_response(response) # Git messages have no encoding enforcements. However, in the UI we only # handle UTF-8, so basically we cross our fingers that the message force diff --git a/spec/lib/gitlab/git/tag_spec.rb b/spec/lib/gitlab/git/tag_spec.rb index 67a9c974298..78d1e120013 100644 --- a/spec/lib/gitlab/git/tag_spec.rb +++ b/spec/lib/gitlab/git/tag_spec.rb @@ -3,23 +3,33 @@ require "spec_helper" describe Gitlab::Git::Tag, seed_helper: true do let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH) } - describe 'first tag' do - let(:tag) { repository.tags.first } + shared_examples 'Gitlab::Git::Repository#tags' do + describe 'first tag' do + let(:tag) { repository.tags.first } - it { expect(tag.name).to eq("v1.0.0") } - it { expect(tag.target).to eq("f4e6814c3e4e7a0de82a9e7cd20c626cc963a2f8") } - it { expect(tag.dereferenced_target.sha).to eq("6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9") } - it { expect(tag.message).to eq("Release") } - end + it { expect(tag.name).to eq("v1.0.0") } + it { expect(tag.target).to eq("f4e6814c3e4e7a0de82a9e7cd20c626cc963a2f8") } + it { expect(tag.dereferenced_target.sha).to eq("6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9") } + it { expect(tag.message).to eq("Release") } + end + + describe 'last tag' do + let(:tag) { repository.tags.last } - describe 'last tag' do - let(:tag) { repository.tags.last } + it { expect(tag.name).to eq("v1.2.1") } + it { expect(tag.target).to eq("2ac1f24e253e08135507d0830508febaaccf02ee") } + it { expect(tag.dereferenced_target.sha).to eq("fa1b1e6c004a68b7d8763b86455da9e6b23e36d6") } + it { expect(tag.message).to eq("Version 1.2.1") } + end - it { expect(tag.name).to eq("v1.2.1") } - it { expect(tag.target).to eq("2ac1f24e253e08135507d0830508febaaccf02ee") } - it { expect(tag.dereferenced_target.sha).to eq("fa1b1e6c004a68b7d8763b86455da9e6b23e36d6") } - it { expect(tag.message).to eq("Version 1.2.1") } + it { expect(repository.tags.size).to eq(SeedRepo::Repo::TAGS.size) } end - it { expect(repository.tags.size).to eq(SeedRepo::Repo::TAGS.size) } + context 'when Gitaly tags feature is enabled' do + it_behaves_like 'Gitlab::Git::Repository#tags' + end + + context 'when Gitaly tags feature is disabled', skip_gitaly_mock: true do + it_behaves_like 'Gitlab::Git::Repository#tags' + end end -- cgit v1.2.1 From 8a55d2ffbc93a4c8197dfce055f6e0b7d3c98ce2 Mon Sep 17 00:00:00 2001 From: Marcia Ramos Date: Thu, 27 Jul 2017 19:12:53 +0000 Subject: Docs new topic "user/project/repository/index.md" --- doc/README.md | 2 +- doc/user/index.md | 5 + doc/user/project/issues/issues_functionalities.md | 8 +- .../project/repository/img/compare_branches.png | Bin 0 -> 35999 bytes .../project/repository/img/contributors_graph.png | Bin 0 -> 31670 bytes doc/user/project/repository/img/repo_graph.png | Bin 0 -> 52317 bytes doc/user/project/repository/index.md | 150 +++++++++++++++++++++ .../repository/reducing_the_repo_size_using_git.md | 81 +++++++++++ 8 files changed, 240 insertions(+), 6 deletions(-) create mode 100755 doc/user/project/repository/img/compare_branches.png create mode 100755 doc/user/project/repository/img/contributors_graph.png create mode 100755 doc/user/project/repository/img/repo_graph.png create mode 100644 doc/user/project/repository/index.md create mode 100644 doc/user/project/repository/reducing_the_repo_size_using_git.md diff --git a/doc/README.md b/doc/README.md index 5537f54ab2b..a2864543b39 100644 --- a/doc/README.md +++ b/doc/README.md @@ -56,7 +56,7 @@ Shortcuts to GitLab's most visited docs: ### Repository -Manage files and branches from the UI (user interface): +Manage your [repositories](user/project/repository/index.md) from the UI (user interface): - Files - [Create a file](user/project/repository/web_editor.md#create-a-file) diff --git a/doc/user/index.md b/doc/user/index.md index f545dbffde3..8e43c8d6e3b 100644 --- a/doc/user/index.md +++ b/doc/user/index.md @@ -71,6 +71,11 @@ your code, use it as an issue tracker, collaborate on code, and continuously build, test, and deploy your app with built-in GitLab CI/CD. Or, you can do it all at once, from one single project. +### Repository + +Host your codebase in [GitLab repositories](project/repository/index.md) with version control +and as part of a fully integrated platform. + ### Issues Explore the best of GitLab [Issues](project/issues/index.md). diff --git a/doc/user/project/issues/issues_functionalities.md b/doc/user/project/issues/issues_functionalities.md index 138276edf07..074b2c19c43 100644 --- a/doc/user/project/issues/issues_functionalities.md +++ b/doc/user/project/issues/issues_functionalities.md @@ -58,17 +58,15 @@ Learn more on the [Multiple Assignees documentation](https://docs.gitlab.com/ee/ - Select a [milestone](../milestones/index.md) to attribute that issue to. -#### 5. Time Tracking (EES/EEP) - -This feature is available only in [GitLab Enterprise Edition](https://about.gitlab.com/gitlab-ee/). +#### 5. Time Tracking - Estimate time: add an estimate time in which the issue will be implemented - Spend: add the time spent on the implementation of that issue > **Note:** -both estimate and spend times are set via [GitLab Quick Actions](../quick_actions.md). +Both estimate and spend times are set via [GitLab Quick Actions](../quick_actions.md). -Learn more on the [Time Tracking documentation](https://docs.gitlab.com/ee/workflow/time_tracking.html). +Learn more on the [Time Tracking documentation](../../../workflow/time_tracking.md). #### 6. Due date diff --git a/doc/user/project/repository/img/compare_branches.png b/doc/user/project/repository/img/compare_branches.png new file mode 100755 index 00000000000..353bd72ef4e Binary files /dev/null and b/doc/user/project/repository/img/compare_branches.png differ diff --git a/doc/user/project/repository/img/contributors_graph.png b/doc/user/project/repository/img/contributors_graph.png new file mode 100755 index 00000000000..c31da7aa1ff Binary files /dev/null and b/doc/user/project/repository/img/contributors_graph.png differ diff --git a/doc/user/project/repository/img/repo_graph.png b/doc/user/project/repository/img/repo_graph.png new file mode 100755 index 00000000000..28da8ad9589 Binary files /dev/null and b/doc/user/project/repository/img/repo_graph.png differ diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md new file mode 100644 index 00000000000..bb41eb41795 --- /dev/null +++ b/doc/user/project/repository/index.md @@ -0,0 +1,150 @@ +# Repository + +A [repository](https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository) +is what you use to store your codebase in GitLab and change it with version control. +A repository is part of a project, which has a lot of other features. + +## Create a repository + +To create a new repository, all you need to do is +[create a new project](../../../gitlab-basics/create-project.md). + +Once you create a new project, you can add new files via UI +(read the section below) or via command line. +To add files from the command line, follow the instructions that will +be presented on the screen when you create a new project, or read +through them in the [command line basics](../../../gitlab-basics/start-using-git.md) +documentation. + +> **Important:** +For security reasons, when using the command line, we strongly recommend +you to [connect with GitLab via SSH](../../../ssh/README.md). + +## Create and edit files + +Host your codebase in GitLab repositories by pushing your files to GitLab. +You can either use the user interface (UI), or connect your local computer +with GitLab [through the command line](../../../gitlab-basics/command-line-commands.md#start-working-on-your-project). + +To configure [GitLab CI/CD](../../../ci/README.md) to build, test, and deploy +you code, add a file called [.`gitlab-ci.yml`](../../../ci/quick_start/README.md) +to your repository's root. + +**From the user interface:** + +GitLab's UI allows you to perform lots of Git commands without having to +touch the command line. Even if you use the command line regularly, sometimes +it's easier to do so [via GitLab UI](web_editor.md): + +- [Create a file](web_editor.md#create-a-file) +- [Upload a file](web_editor.md#upload-a-file) +- [File templates](web_editor.md#template-dropdowns) +- [Create a directory](web_editor.md#create-a-directory) +- [Start a merge request](web_editor.md#tips) + +**From the command line:** + +To get started with the command line, please read through the +[command line basics documentation](../../../gitlab-basics/command-line-commands.md). + +## Branches + +When you submit changes in a new branch, you create a new version +of that project's file tree. Your branch contains all the changes +you are presenting, which are detected by Git line by line. + +To continue your workflow, once you pushed your changes to a new branch, +you can create a [merge request](../merge_requests/index.md), perform +inline code review, and [discuss](../../discussions/index.md) +your implementation with your team. +You can live preview changes submitted to a new branch with +[Review Apps](../../../ci/review_apps/index.md). + +With [GitLab Enterprise Edition](https://about.gitlab.com/gitlab-ee/) +subscriptions, you can also request +[approval](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html#merge-request-approvals) from your managers. + +To create, delete, and branches via GitLab's UI: + +- [Create a branch](web_editor.md#create-a-new-branch) +- [Protected branches](../protected_branches.md#protected-branches) +- [Delete merged branches](branches/index.md#delete-merged-branches) + +Alternatively, you can use the +[command line](../../../gitlab-basics/start-using-git.md#create-a-branch). + +To learn more about branching strategies read through the +[GitLab Flow](../../../university/training/gitlab_flow.md) documentation. + +## Commits + +When you [commit your changes](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository), +you are introducing those changes to your branch. +Via command line, you can commit multiple times before pushing. + +- **Commit message:** +A commit message is important to identity what is being changed and, +more importantly, why. In GitLab, you can add keywords to the commit +message that will perform one of the actions below: + - **Trigger a GitLab CI/CD pipeline:** + If you have your project configured with [GitLab CI/CD](../../../ci/README.md), + you will trigger a pipeline per push, not per commit. + - **Skip pipelines:** + You can add to you commit message the keyword + [`[ci skip]`](../../../ci/yaml/README.html#skipping-jobs) + and GitLab CI will skip that pipeline. + - **Cross-link issues and merge requests:** + [Cross-linking](../issues/crosslinking_issues.md#from-commit-messages) + is great to keep track of what's is somehow related in your workflow. + If you mention an issue or a merge request in a commit message, they will be shown + on their respective thread. +- **Cherry-pick a commit:** +In GitLab, you can +[cherry-pick a commit](../merge_requests/cherry_pick_changes.md#cherry-picking-a-commit) +right from the UI. +- **Revert a commit:** +Easily [revert a commit](../merge_requests/revert_changes.md#reverting-a-commit) +from the UI to a selected branch. + +## Repository size + +In GitLab.com, your repository size limit it 10GB. For other instances, +the repository size is limited by your system administrators. + +You can also [reduce a repository size using Git](reducing_the_repo_size_using_git.md). + +## Contributors + +All the contributors to your codebase are displayed under your project's **Settings > Contributors**. + +They are ordered from the collaborator with the greatest number +of commits to the fewest, and displayed on a nice graph: + +![contributors to code](img/contributors_graph.png) + +## Repository graph + +The repository graph displays visually the Git flow strategy used in that repository: + +![repository Git flow](img/repo_graph.png) + +Find it under your project's **Repository > Graph**. + +## Compare + +Select branches to compare and view the changes inline: + +![compare branches](img/compare_branches.png) + +Find it under your project's **Repository > Compare**. + +## Locked files (EEP) + +Lock your files to prevent any conflicting changes. + +[File Locking](https://docs.gitlab.com/ee/user/project/file_lock.html) is available only in +[GitLab Enterprise Edition Premium](https://about.gitlab.com/gitlab-ee/). + +## Repository's API + +You can access your repos via [repository API](../../../api/repositories.md). diff --git a/doc/user/project/repository/reducing_the_repo_size_using_git.md b/doc/user/project/repository/reducing_the_repo_size_using_git.md new file mode 100644 index 00000000000..08805a4dc99 --- /dev/null +++ b/doc/user/project/repository/reducing_the_repo_size_using_git.md @@ -0,0 +1,81 @@ +# Reducing the repository size using Git + +A GitLab Entrerprise Edition administrator can set a [repository size limit][admin-repo-size] +which will prevent you to exceed it. + +When a project has reached its size limit, you will not be able to push to it, +create a new merge request, or merge existing ones. You will still be able to +create new issues, and clone the project though. Uploading LFS objects will +also be denied. + +In order to lift these restrictions, the administrator of the GitLab instance +needs to increase the limit on the particular project that exceeded it or you +need to instruct Git to rewrite changes. + +If you exceed the repository size limit, your first thought might be to remove +some data, make a new commit and push back to the repository. Unfortunately, +it's not so easy and that workflow won't work. Deleting files in a commit doesn't +actually reduce the size of the repo since the earlier commits and blobs are +still around. What you need to do is rewrite history with Git's +[`filter-branch` option][gitscm]. + +Note that even with that method, until `git gc` runs on the GitLab side, the +"removed" commits and blobs will still be around. And if a commit was ever +included in an MR, or if a build was run for a commit, or if a user commented +on it, it will be kept around too. So, in these cases the size will not decrease. + +The only fool proof way to actually decrease the repository size is to prune all +the unneeded stuff locally, and then create a new project on GitLab and start +using that instead. + +With that being said, you can try reducing your repository size with the +following method. + +## Using `git filter-branch` to purge files + +> +**Warning:** +Make sure to first make a copy of your repository since rewriting history will +purge the files and information you are about to delete. Also make sure to +inform any collaborators to not use `pull` after your changes, but use `rebase`. + +1. Navigate to your repository: + + ``` + cd my_repository/ + ``` + +1. Change to the branch you want to remove the big file from: + + ``` + git checkout master + ``` + +1. Use `filter-branch` to remove the big file: + + ``` + git filter-branch --force --tree-filter 'rm -f path/to/big_file.mpg' HEAD + ``` + +1. Instruct Git to purge the unwanted data: + + ``` + git reflog expire --expire=now --all && git gc --prune=now --aggressive + ``` + +1. Lastly, force push to the repository: + + ``` + git push --force origin master + ``` + +Your repository should now be below the size limit. + +>**Note:** +As an alternative to `filter-branch`, you can use the `bfg` tool with a +command like: `bfg --delete-files path/to/big_file.mpg`. Read the +[BFG Repo-Cleaner][bfg] documentation for more information. + +[admin-repo-size]: https://docs.gitlab.com/ee/user/admin_area/settings/account_and_limit_settings.html#repository-size-limit +[bfg]: https://rtyley.github.io/bfg-repo-cleaner/ +[gitscm]: https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#The-Nuclear-Option:-filter-branch -- cgit v1.2.1 From 68efbff087ae03ce22a785307fb17e8f3c7c21a9 Mon Sep 17 00:00:00 2001 From: Marcia Ramos Date: Thu, 27 Jul 2017 19:23:35 +0000 Subject: Docs new topic: "user/profile/index" --- doc/README.md | 7 +++--- doc/profile/README.md | 6 +---- doc/user/index.md | 4 ++-- doc/user/profile/account/index.md | 5 +---- doc/user/profile/index.md | 47 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 55 insertions(+), 14 deletions(-) create mode 100644 doc/user/profile/index.md diff --git a/doc/README.md b/doc/README.md index a2864543b39..cc63ecb7eab 100644 --- a/doc/README.md +++ b/doc/README.md @@ -36,9 +36,10 @@ Shortcuts to GitLab's most visited docs: ### User account -- [User documentation](user/index.md) -- [Authentication](topics/authentication/index.md): Account security with two-factor authentication, setup your ssh keys and deploy keys for secure access to your projects. -- [Profile settings](profile/README.md): Manage your profile settings, two factor authentication and more. +- [User documentation](user/index.md): Learn how to use GitLab and explore its features +- [User account](user/profile/index.md): Manage your account + - [Authentication](topics/authentication/index.md): Account security with two-factor authentication, setup your ssh keys and deploy keys for secure access to your projects. + - [Profile settings](user/profile/index.md#profile-settings): Manage your profile settings, two factor authentication and more. - [User permissions](user/permissions.md): Learn what each role in a project (external/guest/reporter/developer/master/owner) can do. ### Projects and groups diff --git a/doc/profile/README.md b/doc/profile/README.md index aed64ac1228..fda6d85a84c 100644 --- a/doc/profile/README.md +++ b/doc/profile/README.md @@ -1,5 +1 @@ -# Profile settings - -- [Preferences](../user/profile/preferences.md) -- [Two-factor Authentication (2FA)](../user/profile/account/two_factor_authentication.md) -- [Deleting your account](../user/profile/account/delete_account.md) +This document was moved to [user/profile/account](../user/profile/index.md). diff --git a/doc/user/index.md b/doc/user/index.md index 8e43c8d6e3b..522cf932349 100644 --- a/doc/user/index.md +++ b/doc/user/index.md @@ -126,8 +126,8 @@ Groups can also be nested in [subgroups](group/subgroups/index.md). There is a lot you can customize and configure to enjoy the best of GitLab. -Manage your user settings to change your personal info, -personal access tokens, authorized applications, integrations, etc. +[Manage your user settings](profile/index.md) to change your personal info, +personal access tokens, authorized applications, etc. ### Authentication diff --git a/doc/user/profile/account/index.md b/doc/user/profile/account/index.md index 764354e1e96..06667bfc5f1 100644 --- a/doc/user/profile/account/index.md +++ b/doc/user/profile/account/index.md @@ -1,5 +1,2 @@ -# Profile settings -## Account - -Set up [two-factor authentication](two_factor_authentication.md). +This document was moved to [../index.md#profile-settings](../index.md#profile-settings). diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md new file mode 100644 index 00000000000..0e3747817d2 --- /dev/null +++ b/doc/user/profile/index.md @@ -0,0 +1,47 @@ +# User account + +When logged into their GitLab account, users can customize their +experience according to the best approach to their cases. + +## Username + +Your `username` is a unique [`namespace`](../group/index.md#namespaces) +related to your user ID. + +You can change your `username` from your +[profile settings](#profile-settings). To avoid breaking +paths when you change your `username`, we suggest you follow +[this procedure from the GitLab Team Handbook](https://about.gitlab.com/handbook/tools-and-tips/#how-to-change-your-username-at-gitlabcom). + +## User profile + +Your profile is available from the up-right corner menu bar (user's avatar) > **Profile**, +or from `https://example.gitlab.com/username`. + +On your profile page, you will see the following information: + +- Personal information +- Activity stream: see your activity streamline and the history of your contributions +- Groups: [groups](../group/index.md) you're a member of +- Contributed projects: projects you contributed to +- Personal projects: your personal projects (respecting the project's visibility level) +- Snippets: your personal code [snippets](../snippets.md#personal-snippets) + +## Profile settings + +You can edit your account settings by navigating from the up-right corner menu bar +(user's avatar) > **Settings**, or visiting `https://example.gitlab.com/profile`. + +From there, you can: + +- Update your personal information +- Manage [private tokens](../../api/README.md#private-tokens), email tokens, [2FA](account/two_factor_authentication.md) +- Change your username and [delete your account](account/delete_account.md) +- Manage applications that can +[use GitLab as an OAuth provider](../../integration/oauth_provider.md#introduction-to-oauth) +- Manage [personal access tokens](personal_access_tokens.md) to access your account via API and authorized applications +- Add and delete emails linked to your account +- Manage [SSH keys](../../ssh/README.md#ssh) to access your account via SSH +- Manage your [preferences](preferences.md#syntax-highlighting-theme) +to customize your own GitLab experience +- Acess your audit log, a security log of important events involving your account -- cgit v1.2.1 From 432bb22308d13542821ab96e0d011847642276fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Sat, 22 Jul 2017 17:53:03 -0400 Subject: Remove unused Gitlab::Git operations --- lib/gitlab/git/repository.rb | 162 --------------------------------- spec/lib/gitlab/git/repository_spec.rb | 138 ---------------------------- 2 files changed, 300 deletions(-) diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index efb4f983cfa..90c9f6b333d 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -471,20 +471,6 @@ module Gitlab end end - # Sets HEAD to the commit specified by +ref+; +ref+ can be a branch or - # tag name or a commit SHA. Valid +reset_type+ values are: - # - # [:soft] - # the head will be moved to the commit. - # [:mixed] - # will trigger a +:soft+ reset, plus the index will be replaced - # with the content of the commit tree. - # [:hard] - # will trigger a +:mixed+ reset and the working directory will be - # replaced with the content of the index. (Untracked and ignored files - # will be left alone) - delegate :reset, to: :rugged - # Mimic the `git clean` command and recursively delete untracked files. # Valid keys that can be passed in the +options+ hash are: # @@ -509,154 +495,6 @@ module Gitlab # TODO: implement this method end - # Check out the specified ref. Valid options are: - # - # :b - Create a new branch at +start_point+ and set HEAD to the new - # branch. - # - # * These options are passed to the Rugged::Repository#checkout method: - # - # :progress :: - # A callback that will be executed for checkout progress notifications. - # Up to 3 parameters are passed on each execution: - # - # - The path to the last updated file (or +nil+ on the very first - # invocation). - # - The number of completed checkout steps. - # - The number of total checkout steps to be performed. - # - # :notify :: - # A callback that will be executed for each checkout notification - # types specified with +:notify_flags+. Up to 5 parameters are passed - # on each execution: - # - # - An array containing the +:notify_flags+ that caused the callback - # execution. - # - The path of the current file. - # - A hash describing the baseline blob (or +nil+ if it does not - # exist). - # - A hash describing the target blob (or +nil+ if it does not exist). - # - A hash describing the workdir blob (or +nil+ if it does not - # exist). - # - # :strategy :: - # A single symbol or an array of symbols representing the strategies - # to use when performing the checkout. Possible values are: - # - # :none :: - # Perform a dry run (default). - # - # :safe :: - # Allow safe updates that cannot overwrite uncommitted data. - # - # :safe_create :: - # Allow safe updates plus creation of missing files. - # - # :force :: - # Allow all updates to force working directory to look like index. - # - # :allow_conflicts :: - # Allow checkout to make safe updates even if conflicts are found. - # - # :remove_untracked :: - # Remove untracked files not in index (that are not ignored). - # - # :remove_ignored :: - # Remove ignored files not in index. - # - # :update_only :: - # Only update existing files, don't create new ones. - # - # :dont_update_index :: - # Normally checkout updates index entries as it goes; this stops - # that. - # - # :no_refresh :: - # Don't refresh index/config/etc before doing checkout. - # - # :disable_pathspec_match :: - # Treat pathspec as simple list of exact match file paths. - # - # :skip_locked_directories :: - # Ignore directories in use, they will be left empty. - # - # :skip_unmerged :: - # Allow checkout to skip unmerged files (NOT IMPLEMENTED). - # - # :use_ours :: - # For unmerged files, checkout stage 2 from index (NOT IMPLEMENTED). - # - # :use_theirs :: - # For unmerged files, checkout stage 3 from index (NOT IMPLEMENTED). - # - # :update_submodules :: - # Recursively checkout submodules with same options (NOT - # IMPLEMENTED). - # - # :update_submodules_if_changed :: - # Recursively checkout submodules if HEAD moved in super repo (NOT - # IMPLEMENTED). - # - # :disable_filters :: - # If +true+, filters like CRLF line conversion will be disabled. - # - # :dir_mode :: - # Mode for newly created directories. Default: +0755+. - # - # :file_mode :: - # Mode for newly created files. Default: +0755+ or +0644+. - # - # :file_open_flags :: - # Mode for opening files. Default: - # IO::CREAT | IO::TRUNC | IO::WRONLY. - # - # :notify_flags :: - # A single symbol or an array of symbols representing the cases in - # which the +:notify+ callback should be invoked. Possible values are: - # - # :none :: - # Do not invoke the +:notify+ callback (default). - # - # :conflict :: - # Invoke the callback for conflicting paths. - # - # :dirty :: - # Invoke the callback for "dirty" files, i.e. those that do not need - # an update but no longer match the baseline. - # - # :updated :: - # Invoke the callback for any file that was changed. - # - # :untracked :: - # Invoke the callback for untracked files. - # - # :ignored :: - # Invoke the callback for ignored files. - # - # :all :: - # Invoke the callback for all these cases. - # - # :paths :: - # A glob string or an array of glob strings specifying which paths - # should be taken into account for the checkout operation. +nil+ will - # match all files. Default: +nil+. - # - # :baseline :: - # A Rugged::Tree that represents the current, expected contents of the - # workdir. Default: +HEAD+. - # - # :target_directory :: - # A path to an alternative workdir directory in which the checkout - # should be performed. - def checkout(ref, options = {}, start_point = "HEAD") - if options[:b] - rugged.branches.create(ref, start_point) - options.delete(:b) - end - default_options = { strategy: [:recreate_missing, :safe] } - rugged.checkout(ref, default_options.merge(options)) - end - # Delete the specified branch from the repository def delete_branch(branch_name) rugged.branches.delete(branch_name) diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 83d067b2c31..45ae8c72f6a 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -378,144 +378,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end end - describe "#reset" do - change_path = File.join(SEED_STORAGE_PATH, TEST_NORMAL_REPO_PATH, "CHANGELOG") - untracked_path = File.join(SEED_STORAGE_PATH, TEST_NORMAL_REPO_PATH, "UNTRACKED") - tracked_path = File.join(SEED_STORAGE_PATH, TEST_NORMAL_REPO_PATH, "files", "ruby", "popen.rb") - - change_text = "New changelog text" - untracked_text = "This file is untracked" - - reset_commit = SeedRepo::LastCommit::ID - - context "--hard" do - before(:all) do - # Modify a tracked file - File.open(change_path, "w") do |f| - f.write(change_text) - end - - # Add an untracked file to the working directory - File.open(untracked_path, "w") do |f| - f.write(untracked_text) - end - - @normal_repo = Gitlab::Git::Repository.new('default', TEST_NORMAL_REPO_PATH) - @normal_repo.reset("HEAD", :hard) - end - - it "should replace the working directory with the content of the index" do - File.open(change_path, "r") do |f| - expect(f.each_line.first).not_to eq(change_text) - end - - File.open(tracked_path, "r") do |f| - expect(f.each_line.to_a[8]).to include('raise RuntimeError, "System commands') - end - end - - it "should not touch untracked files" do - expect(File.exist?(untracked_path)).to be_truthy - end - - it "should move the HEAD to the correct commit" do - new_head = @normal_repo.rugged.head.target.oid - expect(new_head).to eq(reset_commit) - end - - it "should move the tip of the master branch to the correct commit" do - new_tip = @normal_repo.rugged.references["refs/heads/master"] - .target.oid - - expect(new_tip).to eq(reset_commit) - end - - after(:all) do - # Fast-forward to the original HEAD - FileUtils.rm_rf(TEST_NORMAL_REPO_PATH) - ensure_seeds - end - end - end - - describe "#checkout" do - new_branch = "foo_branch" - - context "-b" do - before(:all) do - @normal_repo = Gitlab::Git::Repository.new('default', TEST_NORMAL_REPO_PATH) - @normal_repo.checkout(new_branch, { b: true }, "origin/feature") - end - - it "should create a new branch" do - expect(@normal_repo.rugged.branches[new_branch]).not_to be_nil - end - - it "should move the HEAD to the correct commit" do - expect(@normal_repo.rugged.head.target.oid).to( - eq(@normal_repo.rugged.branches["origin/feature"].target.oid) - ) - end - - it "should refresh the repo's #heads collection" do - head_names = @normal_repo.branches.map { |h| h.name } - expect(head_names).to include(new_branch) - end - - after(:all) do - FileUtils.rm_rf(TEST_NORMAL_REPO_PATH) - ensure_seeds - end - end - - context "without -b" do - context "and specifying a nonexistent branch" do - it "should not do anything" do - normal_repo = Gitlab::Git::Repository.new('default', TEST_NORMAL_REPO_PATH) - - expect { normal_repo.checkout(new_branch) }.to raise_error(Rugged::ReferenceError) - expect(normal_repo.rugged.branches[new_branch]).to be_nil - expect(normal_repo.rugged.head.target.oid).to( - eq(normal_repo.rugged.branches["master"].target.oid) - ) - - head_names = normal_repo.branches.map { |h| h.name } - expect(head_names).not_to include(new_branch) - end - - after(:all) do - FileUtils.rm_rf(TEST_NORMAL_REPO_PATH) - ensure_seeds - end - end - - context "and with a valid branch" do - before(:all) do - @normal_repo = Gitlab::Git::Repository.new('default', TEST_NORMAL_REPO_PATH) - @normal_repo.rugged.branches.create("feature", "origin/feature") - @normal_repo.checkout("feature") - end - - it "should move the HEAD to the correct commit" do - expect(@normal_repo.rugged.head.target.oid).to( - eq(@normal_repo.rugged.branches["feature"].target.oid) - ) - end - - it "should update the working directory" do - File.open(File.join(SEED_STORAGE_PATH, TEST_NORMAL_REPO_PATH, ".gitignore"), "r") do |f| - expect(f.read.each_line.to_a).not_to include(".DS_Store\n") - end - end - - after(:all) do - FileUtils.rm_rf(SEED_STORAGE_PATH, TEST_NORMAL_REPO_PATH) - ensure_seeds - end - end - end - end - describe "#delete_branch" do before(:all) do @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH) -- cgit v1.2.1 From 8065adcc1e7d69fe3c98fb951256b2514c9d28b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Sat, 22 Jul 2017 18:13:11 -0400 Subject: Improve Gitlab::Git::Repository specs for #branches --- spec/lib/gitlab/git/repository_spec.rb | 53 +++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 45ae8c72f6a..d9d95e22e3b 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -911,18 +911,43 @@ describe Gitlab::Git::Repository, seed_helper: true do end end - describe '#branches with deleted branch' do - before(:each) do - ref = double() - allow(ref).to receive(:name) { 'bad-branch' } - allow(ref).to receive(:target) { raise Rugged::ReferenceError } - branches = double() - allow(branches).to receive(:each) { [ref].each } - allow(repository.rugged).to receive(:branches) { branches } + describe '#branches' do + subject { repository.branches } + + context 'with local and remote branches' do + let(:repository) do + Gitlab::Git::Repository.new('default', File.join(TEST_MUTABLE_REPO_PATH, '.git')) + end + + before do + create_remote_branch(repository, 'joe', 'remote_branch', 'master') + repository.create_branch('local_branch', 'master') + end + + after do + FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH) + ensure_seeds + end + + it 'returns the local and remote branches' do + expect(subject.any? { |b| b.name == 'joe/remote_branch' }).to eq(true) + expect(subject.any? { |b| b.name == 'local_branch' }).to eq(true) + end end - it 'should return empty branches' do - expect(repository.branches).to eq([]) + # With Gitaly enabled, Gitaly just doesn't return deleted branches. + context 'with deleted branch with Gitaly disabled' do + before do + allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false) + ref = double() + allow(ref).to receive(:name) { 'bad-branch' } + allow(ref).to receive(:target) { raise Rugged::ReferenceError } + branches = double() + allow(branches).to receive(:each) { [ref].each } + allow(repository.rugged).to receive(:branches) { branches } + end + + it { is_expected.to eq([]) } end end @@ -1070,7 +1095,7 @@ describe Gitlab::Git::Repository, seed_helper: true do end it 'returns the local branches' do - create_remote_branch('joe', 'remote_branch', 'master') + create_remote_branch(@repo, 'joe', 'remote_branch', 'master') @repo.create_branch('local_branch', 'master') expect(@repo.local_branches.any? { |branch| branch.name == 'remote_branch' }).to eq(false) @@ -1097,9 +1122,9 @@ describe Gitlab::Git::Repository, seed_helper: true do end end - def create_remote_branch(remote_name, branch_name, source_branch_name) - source_branch = @repo.branches.find { |branch| branch.name == source_branch_name } - rugged = @repo.rugged + def create_remote_branch(repository, remote_name, branch_name, source_branch_name) + source_branch = repository.branches.find { |branch| branch.name == source_branch_name } + rugged = repository.rugged rugged.references.create("refs/remotes/#{remote_name}/#{branch_name}", source_branch.dereferenced_target.sha) end -- cgit v1.2.1 From 8e3f2ecfa9f479eca039d2223055d57617d8ba17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Sat, 22 Jul 2017 18:13:47 -0400 Subject: Incorporate RefsService.FindAllBranches Gitaly RPC --- lib/gitlab/git.rb | 2 +- lib/gitlab/git/repository.rb | 12 ++++++++---- lib/gitlab/gitaly_client/ref_service.rb | 13 +++++++++++++ spec/lib/gitlab/git/repository_spec.rb | 9 +++++++-- spec/lib/gitlab/gitaly_client/ref_service_spec.rb | 11 +++++++++++ 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb index 4175746be39..b6449f27034 100644 --- a/lib/gitlab/git.rb +++ b/lib/gitlab/git.rb @@ -10,7 +10,7 @@ module Gitlab include Gitlab::EncodingHelper def ref_name(ref) - encode! ref.sub(/\Arefs\/(tags|heads)\//, '') + encode! ref.sub(/\Arefs\/(tags|heads|remotes)\//, '') end def branch_name(ref) diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 90c9f6b333d..a3bc79109f8 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -82,10 +82,14 @@ module Gitlab end # Returns an Array of Branches - # - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/389 - def branches(sort_by: nil) - branches_filter(sort_by: sort_by) + def branches + gitaly_migrate(:branches) do |is_enabled| + if is_enabled + gitaly_ref_client.branches + else + branches_filter + end + end end def reload_rugged diff --git a/lib/gitlab/gitaly_client/ref_service.rb b/lib/gitlab/gitaly_client/ref_service.rb index 2306fb3cbf5..b0f7548b7dc 100644 --- a/lib/gitlab/gitaly_client/ref_service.rb +++ b/lib/gitlab/gitaly_client/ref_service.rb @@ -10,6 +10,19 @@ module Gitlab @storage = repository.storage end + def branches + request = Gitaly::FindAllBranchesRequest.new(repository: @gitaly_repo) + response = GitalyClient.call(@storage, :ref_service, :find_all_branches, request) + + response.flat_map do |message| + message.branches.map do |branch| + gitaly_commit = GitalyClient::Commit.new(@repository, branch.target) + target_commit = Gitlab::Git::Commit.decorate(gitaly_commit) + Gitlab::Git::Branch.new(@repository, branch.name, branch.target.id, target_commit) + end + end + end + def default_branch_name request = Gitaly::FindDefaultBranchNameRequest.new(repository: @gitaly_repo) response = GitalyClient.call(@storage, :ref_service, :find_default_branch_name, request) diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index d9d95e22e3b..50736d353ad 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -939,16 +939,21 @@ describe Gitlab::Git::Repository, seed_helper: true do context 'with deleted branch with Gitaly disabled' do before do allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false) + end + + it 'returns no results' do ref = double() allow(ref).to receive(:name) { 'bad-branch' } allow(ref).to receive(:target) { raise Rugged::ReferenceError } branches = double() allow(branches).to receive(:each) { [ref].each } allow(repository.rugged).to receive(:branches) { branches } - end - it { is_expected.to eq([]) } + expect(subject).to be_empty + end end + + it_behaves_like 'wrapping gRPC errors', Gitlab::GitalyClient::RefService, :branches end describe '#branch_count' do diff --git a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb index 1e8ed9d645b..0b1c890f956 100644 --- a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb @@ -6,6 +6,17 @@ describe Gitlab::GitalyClient::RefService do let(:relative_path) { project.path_with_namespace + '.git' } let(:client) { described_class.new(project.repository) } + describe '#branches' do + it 'sends a find_all_branches message' do + expect_any_instance_of(Gitaly::RefService::Stub) + .to receive(:find_all_branches) + .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash)) + .and_return([]) + + client.branches + end + end + describe '#branch_names' do it 'sends a find_all_branch_names message' do expect_any_instance_of(Gitaly::RefService::Stub) -- cgit v1.2.1 From 8cfc89bc9b946b6d492d29814f78b311f85f4c8c Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 27 Jul 2017 14:41:26 -0500 Subject: remove needless brackets object accessor syntax --- app/assets/javascripts/users/user_tabs.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/users/user_tabs.js b/app/assets/javascripts/users/user_tabs.js index c499c403e28..5b9f3a68138 100644 --- a/app/assets/javascripts/users/user_tabs.js +++ b/app/assets/javascripts/users/user_tabs.js @@ -154,7 +154,7 @@ export default class UserTabs { } loadActivities() { - if (this.loaded['activity']) { + if (this.loaded.activity) { return; } const $calendarWrap = this.$parentEl.find('.user-calendar'); @@ -172,7 +172,7 @@ export default class UserTabs { }); new gl.Activities(); - this.loaded['activity'] = true; + this.loaded.activity = true; } toggleLoading(status) { -- cgit v1.2.1 From a6732f59e41fdcbccc71938dc88d22763f0f1d54 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 27 Jul 2017 14:43:18 -0500 Subject: remove implied "GET" http method option --- app/assets/javascripts/users/user_tabs.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/javascripts/users/user_tabs.js b/app/assets/javascripts/users/user_tabs.js index 5b9f3a68138..ab7306c4f15 100644 --- a/app/assets/javascripts/users/user_tabs.js +++ b/app/assets/javascripts/users/user_tabs.js @@ -163,7 +163,6 @@ export default class UserTabs { $.ajax({ dataType: 'json', - type: 'GET', url: calendarPath, success: (activityData) => { $calendarWrap.html(CALENDAR_TEMPLATE); -- cgit v1.2.1 From db8d5fc2586e34dc83b8b9cd1a8fd3dbb5b6e881 Mon Sep 17 00:00:00 2001 From: Chenjerai Katanda Date: Thu, 27 Jul 2017 20:33:09 +0000 Subject: Update server terminolgy to differentiate HA setups from Geo --- doc/administration/high_availability/gitlab.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/administration/high_availability/gitlab.md b/doc/administration/high_availability/gitlab.md index e2cf281bc49..42666357faf 100644 --- a/doc/administration/high_availability/gitlab.md +++ b/doc/administration/high_availability/gitlab.md @@ -5,7 +5,7 @@ configure the GitLab application server(s) now. Complete the steps below for each GitLab application server in your environment. > **Note:** There is some additional configuration near the bottom for - secondary GitLab application servers. It's important to read and understand + additional GitLab application servers. It's important to read and understand these additional steps before proceeding with GitLab installation. 1. If necessary, install the NFS client utility packages using the following @@ -72,14 +72,14 @@ for each GitLab application server in your environment. ``` > **Note:** To maintain uniformity of links across HA clusters, the `external_url` - on the master as well as all secondary application servers should point to the - eventual url that users will use to access GitLab. In a typical HA setup, - this will be the url of the load balancer which will route traffic to all - GitLab application servers in the HA cluster. + on the first application server as well as the additional application + servers should point to the external url that users will use to access GitLab. + In a typical HA setup, this will be the url of the load balancer which will + route traffic to all GitLab application servers in the HA cluster. 1. Run `sudo gitlab-ctl reconfigure` to compile the configuration. -## Primary GitLab application server +## First GitLab application server As a final step, run the setup rake task on the first GitLab application server. It is not necessary to run this on additional application servers. @@ -95,10 +95,10 @@ It is not necessary to run this on additional application servers. [Nginx documentation](http://docs.gitlab.com/omnibus/settings/nginx.html#enable-https) for more information. -## Additional configuration for secondary GitLab application servers +## Extra configuration for additional GitLab application servers -Secondary GitLab servers (servers configured **after** the first GitLab server) -need some additional configuration. +Additional GitLab servers (servers configured **after** the first GitLab server) +need some extra configuration. 1. Configure shared secrets. These values can be obtained from the primary GitLab server in `/etc/gitlab/gitlab-secrets.json`. Add these to -- cgit v1.2.1 From d7505de8b3ff5ba9fd939b2e31c75c1a4cdde80f Mon Sep 17 00:00:00 2001 From: Toon Claes Date: Mon, 24 Jul 2017 22:07:37 +0200 Subject: Add top-level /merge_requests API endpoint And add support for additional query parameters: - `author_id`: Returns merge requests created by the given user `id` - `assignee_id`: Returns merge requests assigned to the given user `id` - `scope`: Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all` --- app/finders/merge_requests_finder.rb | 1 + .../unreleased/tc-api-root-merge-requests.yml | 4 + doc/api/merge_requests.md | 92 +++++++++++++++++++++ lib/api/merge_requests.rb | 95 +++++++++++++++------- spec/requests/api/merge_requests_spec.rb | 83 +++++++++++++++++++ 5 files changed, 244 insertions(+), 31 deletions(-) create mode 100644 changelogs/unreleased/tc-api-root-merge-requests.yml diff --git a/app/finders/merge_requests_finder.rb b/app/finders/merge_requests_finder.rb index 2fc34f186ad..771da3d441d 100644 --- a/app/finders/merge_requests_finder.rb +++ b/app/finders/merge_requests_finder.rb @@ -10,6 +10,7 @@ # group_id: integer # project_id: integer # milestone_title: string +# author_id: integer # assignee_id: integer # search: string # label_name: string diff --git a/changelogs/unreleased/tc-api-root-merge-requests.yml b/changelogs/unreleased/tc-api-root-merge-requests.yml new file mode 100644 index 00000000000..17456f943eb --- /dev/null +++ b/changelogs/unreleased/tc-api-root-merge-requests.yml @@ -0,0 +1,4 @@ +--- +title: Add top-level merge_requests API endpoint +merge_request: 13060 +author: diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index c90d95e4dd0..93b5f1c22e6 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -1,7 +1,99 @@ # Merge requests API +Every API call to merge requests must be authenticated. + ## List merge requests +Get all merge requests the authenticated user has access to. +The `state` parameter can be used to get only merge requests with a +given state (`opened`, `closed`, or `merged`) or all of them (`all`). +The pagination parameters `page` and `per_page` can be used to +restrict the list of merge requests. + +``` +GET /merge_requests +GET /merge_requests?state=opened +GET /merge_requests?state=all +GET /merge_requests?milestone=release +GET /merge_requests?labels=bug,reproduced +GET /merge_requests?author_id=5 +GET /merge_requests?scope=assigned-to-me +``` + +Parameters: + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `state` | string | no | Return all merge requests or just those that are `opened`, `closed`, or `merged`| +| `order_by`| string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | +| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | +| `milestone` | string | no | Return merge requests for a specific milestone | +| `view` | string | no | If `simple`, returns the `iid`, URL, title, description, and basic state of merge request | +| `labels` | string | no | Return merge requests matching a comma separated list of labels | +| `created_after` | datetime | no | Return merge requests created after the given time (inclusive) | +| `created_before` | datetime | no | Return merge requests created before the given time (inclusive) | +| `author_id` | integer | no | Returns merge requests created by the given user `id` | +| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id` | +| `scope` | string | no | Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all` | + +```json +[ + { + "id": 1, + "iid": 1, + "target_branch": "master", + "source_branch": "test1", + "project_id": 3, + "title": "test1", + "state": "opened", + "upvotes": 0, + "downvotes": 0, + "author": { + "id": 1, + "username": "admin", + "email": "admin@example.com", + "name": "Administrator", + "state": "active", + "created_at": "2012-04-29T08:46:00Z" + }, + "assignee": { + "id": 1, + "username": "admin", + "email": "admin@example.com", + "name": "Administrator", + "state": "active", + "created_at": "2012-04-29T08:46:00Z" + }, + "source_project_id": 2, + "target_project_id": 3, + "labels": [ ], + "description": "fixed login page css paddings", + "work_in_progress": false, + "milestone": { + "id": 5, + "iid": 1, + "project_id": 3, + "title": "v2.0", + "description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.", + "state": "closed", + "created_at": "2015-02-02T19:49:26.013Z", + "updated_at": "2015-02-02T19:49:26.013Z", + "due_date": null + }, + "merge_when_pipeline_succeeds": true, + "merge_status": "can_be_merged", + "sha": "8888888888888888888888888888888888888888", + "merge_commit_sha": null, + "user_notes_count": 1, + "should_remove_source_branch": true, + "force_remove_source_branch": false, + "web_url": "http://example.com/example/example/merge_requests/1" + } +] +``` + +## List project merge requests + Get all merge requests for this project. The `state` parameter can be used to get only merge requests with a given state (`opened`, `closed`, or `merged`) or all of them (`all`). The pagination parameters `page` and `per_page` can be used to restrict the list of merge requests. diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index f64ac659413..3b57959162e 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -4,14 +4,75 @@ module API before { authenticate! } + helpers ::Gitlab::IssuableMetadata + + helpers do + def find_merge_requests(args = {}) + args = params.merge(args) + + args[:milestone_title] = args.delete(:milestone) + args[:label_name] = args.delete(:labels) + + merge_requests = MergeRequestsFinder.new(current_user, args).execute + .reorder(args[:order_by] => args[:sort]) + merge_requests = paginate(merge_requests) + .preload(:target_project) + + return merge_requests if args[:view] == 'simple' + + merge_requests + .preload(:notes, :author, :assignee, :milestone, :merge_request_diff, :labels) + end + + params :merge_requests_params do + optional :state, type: String, values: %w[opened closed merged all], default: 'all', + desc: 'Return opened, closed, merged, or all merge requests' + optional :order_by, type: String, values: %w[created_at updated_at], default: 'created_at', + desc: 'Return merge requests ordered by `created_at` or `updated_at` fields.' + optional :sort, type: String, values: %w[asc desc], default: 'desc', + desc: 'Return merge requests sorted in `asc` or `desc` order.' + optional :milestone, type: String, desc: 'Return merge requests for a specific milestone' + optional :labels, type: String, desc: 'Comma-separated list of label names' + optional :created_after, type: DateTime, desc: 'Return merge requests created after the specified time' + optional :created_before, type: DateTime, desc: 'Return merge requests created before the specified time' + optional :view, type: String, values: %w[simple], desc: 'If simple, returns the `iid`, URL, title, description, and basic state of merge request' + optional :author_id, type: Integer, desc: 'Return merge requests which are authored by the user with the given ID' + optional :assignee_id, type: Integer, desc: 'Return merge requests which are assigned to the user with the given ID' + optional :scope, type: String, values: %w[created-by-me assigned-to-me all], default: 'all', + desc: 'Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all`' + use :pagination + end + end + + resource :merge_requests do + desc 'List merge requests' do + success Entities::MergeRequestBasic + end + params do + use :merge_requests_params + end + get do + merge_requests = find_merge_requests + + options = { with: Entities::MergeRequestBasic, + current_user: current_user } + + if params[:view] == 'simple' + options[:with] = Entities::MergeRequestSimple + else + options[:issuable_metadata] = issuable_meta_data(merge_requests, 'MergeRequest') + end + + present merge_requests, options + end + end + params do requires :id, type: String, desc: 'The ID of a project' end resource :projects, requirements: { id: %r{[^/]+} } do include TimeTrackingEndpoints - helpers ::Gitlab::IssuableMetadata - helpers do def handle_merge_request_errors!(errors) if errors[:project_access].any? @@ -29,23 +90,6 @@ module API render_api_error!(errors, 400) end - def find_merge_requests(args = {}) - args = params.merge(args) - - args[:milestone_title] = args.delete(:milestone) - args[:label_name] = args.delete(:labels) - - merge_requests = MergeRequestsFinder.new(current_user, args).execute - .reorder(args[:order_by] => args[:sort]) - merge_requests = paginate(merge_requests) - .preload(:target_project) - - return merge_requests if args[:view] == 'simple' - - merge_requests - .preload(:notes, :author, :assignee, :milestone, :merge_request_diff, :labels) - end - params :optional_params_ce do optional :description, type: String, desc: 'The description of the merge request' optional :assignee_id, type: Integer, desc: 'The ID of a user to assign the merge request' @@ -63,19 +107,8 @@ module API success Entities::MergeRequestBasic end params do - optional :state, type: String, values: %w[opened closed merged all], default: 'all', - desc: 'Return opened, closed, merged, or all merge requests' - optional :order_by, type: String, values: %w[created_at updated_at], default: 'created_at', - desc: 'Return merge requests ordered by `created_at` or `updated_at` fields.' - optional :sort, type: String, values: %w[asc desc], default: 'desc', - desc: 'Return merge requests sorted in `asc` or `desc` order.' + use :merge_requests_params optional :iids, type: Array[Integer], desc: 'The IID array of merge requests' - optional :milestone, type: String, desc: 'Return merge requests for a specific milestone' - optional :labels, type: String, desc: 'Comma-separated list of label names' - optional :created_after, type: DateTime, desc: 'Return merge requests created after the specified time' - optional :created_before, type: DateTime, desc: 'Return merge requests created before the specified time' - optional :view, type: String, values: %w[simple], desc: 'If simple, returns the `iid`, URL, title, description, and basic state of merge request' - use :pagination end get ":id/merge_requests" do authorize! :read_merge_request, user_project diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 35b6522ea98..02daca0d11d 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -26,6 +26,89 @@ describe API::MergeRequests do project.team << [user, :reporter] end + describe 'GET /merge_requests' do + context 'when unauthenticated' do + it 'returns authentication error' do + get api('/merge_requests') + + expect(response).to have_http_status(401) + end + end + + context 'when authenticated' do + let!(:project2) { create(:empty_project, :public, namespace: user.namespace) } + let!(:merge_request2) { create(:merge_request, :simple, author: user, assignee: user, source_project: project2, target_project: project2) } + let(:user2) { create(:user) } + + it 'returns an array of all merge requests' do + get api('/merge_requests', user) + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.map { |mr| mr['id'] }) + .to contain_exactly(merge_request.id, merge_request_closed.id, merge_request_merged.id, merge_request2.id) + end + + it 'does not return unauthorized merge requests' do + private_project = create(:empty_project, :private) + merge_request3 = create(:merge_request, :simple, source_project: private_project, target_project: private_project, source_branch: 'other-branch') + + get api('/merge_requests', user) + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.map { |mr| mr['id'] }) + .not_to include(merge_request3.id) + end + + it 'returns an array of merge requests authored by the given user' do + merge_request3 = create(:merge_request, :simple, author: user2, assignee: user, source_project: project2, target_project: project2, source_branch: 'other-branch') + + get api('/merge_requests', user), author_id: user2.id + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + expect(json_response.first['id']).to eq(merge_request3.id) + end + + it 'returns an array of merge requests assigned to the given user' do + merge_request3 = create(:merge_request, :simple, author: user, assignee: user2, source_project: project2, target_project: project2, source_branch: 'other-branch') + + get api('/merge_requests', user), assignee_id: user2.id + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + expect(json_response.first['id']).to eq(merge_request3.id) + end + + it 'returns an array of merge requests assigned to me' do + merge_request3 = create(:merge_request, :simple, author: user, assignee: user2, source_project: project2, target_project: project2, source_branch: 'other-branch') + + get api('/merge_requests', user2), scope: 'assigned-to-me' + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + expect(json_response.first['id']).to eq(merge_request3.id) + end + + it 'returns an array of merge requests created by me' do + merge_request3 = create(:merge_request, :simple, author: user2, assignee: user, source_project: project2, target_project: project2, source_branch: 'other-branch') + + get api('/merge_requests', user2), scope: 'created-by-me' + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + expect(json_response.first['id']).to eq(merge_request3.id) + end + end + end + describe "GET /projects/:id/merge_requests" do context "when unauthenticated" do it "returns authentication error" do -- cgit v1.2.1 From d77088bb0bcb5f77a1337af5bdb30098370f774e Mon Sep 17 00:00:00 2001 From: Toon Claes Date: Fri, 28 Jul 2017 00:07:28 +0200 Subject: Default /merge_request API endpoint to `scope=created-by-me` This matches the behavior of the /issues endpoint. --- doc/api/merge_requests.md | 16 +++++++++++++--- lib/api/merge_requests.rb | 4 +++- spec/requests/api/merge_requests_spec.rb | 19 +++++++++++++++---- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 93b5f1c22e6..d0725b5e06e 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -4,7 +4,12 @@ Every API call to merge requests must be authenticated. ## List merge requests -Get all merge requests the authenticated user has access to. +> [Introduced][ce-13060] in GitLab 9.5. + +Get all merge requests the authenticated user has access to. By +default it returns only merge requests created by the current user. To +get all merge requests, use parameter `scope=all`. + The `state` parameter can be used to get only merge requests with a given state (`opened`, `closed`, or `merged`) or all of them (`all`). The pagination parameters `page` and `per_page` can be used to @@ -32,9 +37,9 @@ Parameters: | `labels` | string | no | Return merge requests matching a comma separated list of labels | | `created_after` | datetime | no | Return merge requests created after the given time (inclusive) | | `created_before` | datetime | no | Return merge requests created before the given time (inclusive) | -| `author_id` | integer | no | Returns merge requests created by the given user `id` | +| `scope` | string | no | Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all`. Defaults to `created-by-me` | +| `author_id` | integer | no | Returns merge requests created by the given user `id`. Combine with `scope=all` or `scope=assigned-to-me` | | `assignee_id` | integer | no | Returns merge requests assigned to the given user `id` | -| `scope` | string | no | Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all` | ```json [ @@ -121,6 +126,9 @@ Parameters: | `labels` | string | no | Return merge requests matching a comma separated list of labels | | `created_after` | datetime | no | Return merge requests created after the given time (inclusive) | | `created_before` | datetime | no | Return merge requests created before the given time (inclusive) | +| `scope` | string | no | Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all` _([Introduced][ce-13060] in GitLab 9.5)_ | +| `author_id` | integer | no | Returns merge requests created by the given user `id` _([Introduced][ce-13060] in GitLab 9.5)_ | +| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id` _([Introduced][ce-13060] in GitLab 9.5)_ | ```json [ @@ -1257,3 +1265,5 @@ Example response: "total_time_spent": 3600 } ``` + +[ce-13060]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/13060 diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 3b57959162e..8810d4e441d 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -38,7 +38,7 @@ module API optional :view, type: String, values: %w[simple], desc: 'If simple, returns the `iid`, URL, title, description, and basic state of merge request' optional :author_id, type: Integer, desc: 'Return merge requests which are authored by the user with the given ID' optional :assignee_id, type: Integer, desc: 'Return merge requests which are assigned to the user with the given ID' - optional :scope, type: String, values: %w[created-by-me assigned-to-me all], default: 'all', + optional :scope, type: String, values: %w[created-by-me assigned-to-me all], desc: 'Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all`' use :pagination end @@ -50,6 +50,8 @@ module API end params do use :merge_requests_params + optional :scope, type: String, values: %w[created-by-me assigned-to-me all], default: 'created-by-me', + desc: 'Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all`' end get do merge_requests = find_merge_requests diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 02daca0d11d..2760c4ffde2 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -41,7 +41,7 @@ describe API::MergeRequests do let(:user2) { create(:user) } it 'returns an array of all merge requests' do - get api('/merge_requests', user) + get api('/merge_requests', user), scope: :all expect(response).to have_http_status(200) expect(response).to include_pagination_headers @@ -54,7 +54,7 @@ describe API::MergeRequests do private_project = create(:empty_project, :private) merge_request3 = create(:merge_request, :simple, source_project: private_project, target_project: private_project, source_branch: 'other-branch') - get api('/merge_requests', user) + get api('/merge_requests', user), scope: :all expect(response).to have_http_status(200) expect(response).to include_pagination_headers @@ -63,10 +63,21 @@ describe API::MergeRequests do .not_to include(merge_request3.id) end + it 'returns an array of merge requests created by current user if no scope is given' do + merge_request3 = create(:merge_request, :simple, author: user2, assignee: user, source_project: project2, target_project: project2, source_branch: 'other-branch') + + get api('/merge_requests', user2) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + expect(json_response.first['id']).to eq(merge_request3.id) + end + it 'returns an array of merge requests authored by the given user' do merge_request3 = create(:merge_request, :simple, author: user2, assignee: user, source_project: project2, target_project: project2, source_branch: 'other-branch') - get api('/merge_requests', user), author_id: user2.id + get api('/merge_requests', user), author_id: user2.id, scope: :all expect(response).to have_http_status(200) expect(json_response).to be_an Array @@ -77,7 +88,7 @@ describe API::MergeRequests do it 'returns an array of merge requests assigned to the given user' do merge_request3 = create(:merge_request, :simple, author: user, assignee: user2, source_project: project2, target_project: project2, source_branch: 'other-branch') - get api('/merge_requests', user), assignee_id: user2.id + get api('/merge_requests', user), assignee_id: user2.id, scope: :all expect(response).to have_http_status(200) expect(json_response).to be_an Array -- cgit v1.2.1 From 39c39ae7911bc87702a808d1e61cd68dae1506f5 Mon Sep 17 00:00:00 2001 From: Toon Claes Date: Fri, 28 Jul 2017 00:08:44 +0200 Subject: Modify/add some forgotten issues API documentation Should have been part of !13004. --- doc/api/issues.md | 40 ++++++++++++++++++++++------------------ lib/api/issues.rb | 4 ++-- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/doc/api/issues.md b/doc/api/issues.md index 6cb2eac37c2..6bac2927339 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -14,7 +14,9 @@ Read more on [pagination](README.md#pagination). ## List issues -Get all issues created by the authenticated user. +Get all issues the authenticated user has access to. By default it +returns only issues created by the current user. To get all issues, +use parameter `scope=all`. ``` GET /issues @@ -35,12 +37,12 @@ GET /issues?assignee_id=5 | `state` | string | no | Return all issues or just those that are `opened` or `closed` | | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels | | `milestone` | string | no | The milestone title | -| `scope` | string | no | Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all` | -| `author_id` | integer | no | Return issues created by the given user `id`. Combine with `scope=all` or `scope=assigned-to-me`. | -| `assignee_id` | integer | no | Return issues assigned to the given user `id` | +| `scope` | string | no | Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all`. Defaults to `created-by-me` _([Introduced][ce-13004] in GitLab 9.5)_ | +| `author_id` | integer | no | Return issues created by the given user `id`. Combine with `scope=all` or `scope=assigned-to-me`. _([Introduced][ce-13004] in GitLab 9.5)_ | +| `assignee_id` | integer | no | Return issues assigned to the given user `id` _([Introduced][ce-13004] in GitLab 9.5)_ | | `iids` | Array[integer] | no | Return only the issues having the given `iid` | -| `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | -| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | +| `order_by` | string | no | Return issues ordered by `created_at` or `updated_at` fields. Default is `created_at` | +| `sort` | string | no | Return issues sorted in `asc` or `desc` order. Default is `desc` | | `search` | string | no | Search issues against their `title` and `description` | ```bash @@ -132,12 +134,12 @@ GET /groups/:id/issues?assignee_id=5 | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels | | `iids` | Array[integer] | no | Return only the issues having the given `iid` | | `milestone` | string | no | The milestone title | -| `scope` | string | no | Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all` | -| `author_id` | integer | no | Return issues created by the given user `id`. Combine with `scope=all` or `scope=assigned-to-me`. | -| `assignee_id` | integer | no | Return issues assigned to the given user `id` | -| `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | -| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | -| `search` | string | no | Search group issues against their `title` and `description` | +| `scope` | string | no | Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all` _([Introduced][ce-13004] in GitLab 9.5)_ | +| `author_id` | integer | no | Return issues created by the given user `id` _([Introduced][ce-13004] in GitLab 9.5)_ | +| `assignee_id` | integer | no | Return issues assigned to the given user `id` _([Introduced][ce-13004] in GitLab 9.5)_ | +| `order_by` | string | no | Return issues ordered by `created_at` or `updated_at` fields. Default is `created_at` | +| `sort` | string | no | Return issues sorted in `asc` or `desc` order. Default is `desc` | +| `search` | string | no | Search group issues against their `title` and `description` | ```bash @@ -229,12 +231,12 @@ GET /projects/:id/issues?assignee_id=5 | `state` | string | no | Return all issues or just those that are `opened` or `closed` | | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `No+Label` lists all issues with no labels | | `milestone` | string | no | The milestone title | -| `scope` | string | no | Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all` | -| `author_id` | integer | no | Return issues created by the given user `id`. Combine with `scope=all` or `scope=assigned-to-me`. | -| `assignee_id` | integer | no | Return issues assigned to the given user `id` | -| `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | -| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | -| `search` | string | no | Search project issues against their `title` and `description` | +| `scope` | string | no | Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all` _([Introduced][ce-13004] in GitLab 9.5)_ | +| `author_id` | integer | no | Return issues created by the given user `id` _([Introduced][ce-13004] in GitLab 9.5)_ | +| `assignee_id` | integer | no | Return issues assigned to the given user `id` _([Introduced][ce-13004] in GitLab 9.5)_ | +| `order_by` | string | no | Return issues ordered by `created_at` or `updated_at` fields. Default is `created_at` | +| `sort` | string | no | Return issues sorted in `asc` or `desc` order. Default is `desc` | +| `search` | string | no | Search project issues against their `title` and `description` | | `created_after` | datetime | no | Return issues created after the given time (inclusive) | | `created_before` | datetime | no | Return issues created before the given time (inclusive) | @@ -1035,3 +1037,5 @@ Example response: "akismet_submitted": false } ``` + +[ce-13004]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/13004 diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 009c6d6bcd4..4cec1145f3a 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -32,7 +32,7 @@ module API optional :author_id, type: Integer, desc: 'Return issues which are authored by the user with the given ID' optional :assignee_id, type: Integer, desc: 'Return issues which are assigned to the user with the given ID' optional :scope, type: String, values: %w[created-by-me assigned-to-me all], - desc: 'Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all`' + desc: 'Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all`' use :pagination end @@ -60,7 +60,7 @@ module API desc: 'Return opened, closed, or all issues' use :issues_params optional :scope, type: String, values: %w[created-by-me assigned-to-me all], default: 'created-by-me', - desc: 'Return merge requests for the given scope: `created-by-me`, `assigned-to-me` or `all`' + desc: 'Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all`' end get do issues = find_issues -- cgit v1.2.1 From 3a200165c3ba43a6f037bcb59c97a13f33624db1 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Fri, 28 Jul 2017 00:24:35 -0500 Subject: Fix lograge exclusion in params section Without this fix, we would just see redundant entries in the `params` section: ``` {"method":"GET","path":"/-/metrics","format":"html","controller":"MetricsController","action":"index","status":404,"duration":1.42,"view":0.38,"db":0.0,"time":"2017-07-28T02:59:18.167Z","params":{"controller":"metrics","action":"index"}} ``` The intended format looks more like this: ``` {"method":"GET","path":"/-/metrics","format":"html","controller":"MetricsController","action":"index","status":404,"duration":76.32,"view":69.95,"db":0.0,"time":"2017-07-28T02:59:48.893Z","params":{}} ``` The proper form to exclude an array is to preface with an asterisk: https://apidock.com/rails/Hash/except --- config/initializers/lograge.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/lograge.rb b/config/initializers/lograge.rb index c9a515dfcd5..039b4c87b0d 100644 --- a/config/initializers/lograge.rb +++ b/config/initializers/lograge.rb @@ -14,7 +14,7 @@ unless Sidekiq.server? config.lograge.custom_options = lambda do |event| { time: event.time.utc.iso8601(3), - params: event.payload[:params].except(%w(controller action format)) + params: event.payload[:params].except(*%w(controller action format)) } end end -- cgit v1.2.1 From 9bc176b2c39f1c27ce8ed4c13cf06e53331c16c9 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Fri, 28 Jul 2017 00:48:03 -0500 Subject: Add remote IP, user ID and username to JSON lograge output This makes the logs a bit more useful to search requests by users. --- app/controllers/application_controller.rb | 10 ++++++++++ config/initializers/lograge.rb | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 43462b13903..d14b1dbecf6 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -70,6 +70,16 @@ class ApplicationController < ActionController::Base protected + def append_info_to_payload(payload) + super + payload[:remote_ip] = request.remote_ip + + if current_user.present? + payload[:user_id] = current_user.id + payload[:username] = current_user.username + end + end + # This filter handles both private tokens and personal access tokens def authenticate_user_from_private_token! token = params[:private_token].presence || request.headers['PRIVATE-TOKEN'].presence diff --git a/config/initializers/lograge.rb b/config/initializers/lograge.rb index c9a515dfcd5..21fe8d72459 100644 --- a/config/initializers/lograge.rb +++ b/config/initializers/lograge.rb @@ -14,7 +14,10 @@ unless Sidekiq.server? config.lograge.custom_options = lambda do |event| { time: event.time.utc.iso8601(3), - params: event.payload[:params].except(%w(controller action format)) + params: event.payload[:params].except(*%w(controller action format)), + remote_ip: event.payload[:remote_ip], + user_id: event.payload[:user_id], + username: event.payload[:username] } end end -- cgit v1.2.1 From 1cd43c389020bd07b24c5151a8b6f421601b2648 Mon Sep 17 00:00:00 2001 From: Tiago Botelho Date: Tue, 2 May 2017 10:58:08 +0100 Subject: refactors git push service spec code --- spec/services/git_push_service_spec.rb | 199 ++++++++++++++++----------------- 1 file changed, 99 insertions(+), 100 deletions(-) diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index 75329e9dda2..4023c33aa59 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -1,29 +1,26 @@ require 'spec_helper' -describe GitPushService do +describe GitPushService, services: true do include RepoHelpers - let(:user) { create(:user) } - let(:project) { create(:project, :repository) } + let(:user) { create(:user) } + let(:project) { create(:project, :repository) } + let(:blankrev) { Gitlab::Git::BLANK_SHA } + let(:oldrev) { sample_commit.parent_id } + let(:newrev) { sample_commit.id } + let(:ref) { 'refs/heads/master' } before do project.team << [user, :master] - @blankrev = Gitlab::Git::BLANK_SHA - @oldrev = sample_commit.parent_id - @newrev = sample_commit.id - @ref = 'refs/heads/master' end describe 'Push branches' do - let(:oldrev) { @oldrev } - let(:newrev) { @newrev } - subject do - execute_service(project, user, oldrev, newrev, @ref ) + execute_service(project, user, oldrev, newrev, ref) end context 'new branch' do - let(:oldrev) { @blankrev } + let(:oldrev) { blankrev } it { is_expected.to be_truthy } @@ -51,7 +48,7 @@ describe GitPushService do end context 'rm branch' do - let(:newrev) { @blankrev } + let(:newrev) { blankrev } it { is_expected.to be_truthy } @@ -70,24 +67,20 @@ describe GitPushService do end describe "Git Push Data" do - before do - service = execute_service(project, user, @oldrev, @newrev, @ref ) - @push_data = service.push_data - @commit = project.commit(@newrev) - end + let(:commit) { project.commit(newrev) } - subject { @push_data } + subject { push_data_from_service(project, user, oldrev, newrev, ref) } it { is_expected.to include(object_kind: 'push') } - it { is_expected.to include(before: @oldrev) } - it { is_expected.to include(after: @newrev) } - it { is_expected.to include(ref: @ref) } + it { is_expected.to include(before: oldrev) } + it { is_expected.to include(after: newrev) } + it { is_expected.to include(ref: ref) } it { is_expected.to include(user_id: user.id) } it { is_expected.to include(user_name: user.name) } it { is_expected.to include(project_id: project.id) } context "with repository data" do - subject { @push_data[:repository] } + subject { push_data_from_service(project, user, oldrev, newrev, ref)[:repository] } it { is_expected.to include(name: project.name) } it { is_expected.to include(url: project.url_to_repo) } @@ -96,7 +89,7 @@ describe GitPushService do end context "with commits" do - subject { @push_data[:commits] } + subject { push_data_from_service(project, user, oldrev, newrev, ref)[:commits] } it { is_expected.to be_an(Array) } it 'has 1 element' do @@ -104,11 +97,11 @@ describe GitPushService do end context "the commit" do - subject { @push_data[:commits].first } + subject { push_data_from_service(project, user, oldrev, newrev, ref)[:commits].first } - it { is_expected.to include(id: @commit.id) } - it { is_expected.to include(message: @commit.safe_message) } - it { expect(subject[:timestamp].in_time_zone).to eq(@commit.date.in_time_zone) } + it { is_expected.to include(id: commit.id) } + it { is_expected.to include(message: commit.safe_message) } + it { expect(subject[:timestamp].in_time_zone).to eq(commit.date.in_time_zone) } it do is_expected.to include( url: [ @@ -116,23 +109,23 @@ describe GitPushService do project.namespace.to_param, project.to_param, 'commit', - @commit.id + commit.id ].join('/') ) end context "with a author" do - subject { @push_data[:commits].first[:author] } + subject { push_data_from_service(project, user, oldrev, newrev, ref)[:commits].first[:author] } - it { is_expected.to include(name: @commit.author_name) } - it { is_expected.to include(email: @commit.author_email) } + it { is_expected.to include(name: commit.author_name) } + it { is_expected.to include(email: commit.author_email) } end end end end describe "Pipelines" do - subject { execute_service(project, user, @oldrev, @newrev, @ref) } + subject { execute_service(project, user, oldrev, newrev, ref) } before do stub_ci_pipeline_to_return_yaml_file @@ -145,29 +138,26 @@ describe GitPushService do end describe "Push Event" do - before do - service = execute_service(project, user, @oldrev, @newrev, @ref ) - @event = Event.find_by_action(Event::PUSHED) - @push_data = service.push_data - end + let!(:push_data) { push_data_from_service(project, user, oldrev, newrev, ref) } + let(:event) { Event.find_by_action(Event::PUSHED) } - it { expect(@event).not_to be_nil } - it { expect(@event.project).to eq(project) } - it { expect(@event.action).to eq(Event::PUSHED) } - it { expect(@event.data).to eq(@push_data) } + it { expect(event).not_to be_nil } + it { expect(event.project).to eq(project) } + it { expect(event.action).to eq(Event::PUSHED) } + it { expect(event.data).to eq(push_data) } context "Updates merge requests" do it "when pushing a new branch for the first time" do expect(UpdateMergeRequestsWorker).to receive(:perform_async) - .with(project.id, user.id, @blankrev, 'newrev', 'refs/heads/master') - execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' ) + .with(project.id, user.id, blankrev, 'newrev', ref) + execute_service(project, user, blankrev, 'newrev', ref ) end end context "Sends System Push data" do it "when pushing on a branch" do - expect(SystemHookPushWorker).to receive(:perform_async).with(@push_data, :push_hooks) - execute_service(project, user, @oldrev, @newrev, @ref ) + expect(SystemHookPushWorker).to receive(:perform_async).with(push_data, :push_hooks) + execute_service(project, user, oldrev, newrev, ref) end end end @@ -177,13 +167,13 @@ describe GitPushService do it "calls the copy attributes method for the first push to the default branch" do expect(project.repository).to receive(:copy_gitattributes).with('master') - execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master') + execute_service(project, user, blankrev, 'newrev', ref) end it "calls the copy attributes method for changes to the default branch" do - expect(project.repository).to receive(:copy_gitattributes).with('refs/heads/master') + expect(project.repository).to receive(:copy_gitattributes).with(ref) - execute_service(project, user, 'oldrev', 'newrev', 'refs/heads/master') + execute_service(project, user, 'oldrev', 'newrev', ref) end end @@ -196,7 +186,7 @@ describe GitPushService do it "does not call copy attributes method" do expect(project.repository).not_to receive(:copy_gitattributes) - execute_service(project, user, @oldrev, @newrev, @ref) + execute_service(project, user, oldrev, newrev, ref) end end end @@ -206,7 +196,7 @@ describe GitPushService do it "when pushing a branch for the first time" do expect(project).to receive(:execute_hooks) expect(project.default_branch).to eq("master") - execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' ) + execute_service(project, user, blankrev, 'newrev', ref) expect(project.protected_branches).not_to be_empty expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER]) expect(project.protected_branches.first.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER]) @@ -217,7 +207,7 @@ describe GitPushService do expect(project).to receive(:execute_hooks) expect(project.default_branch).to eq("master") - execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' ) + execute_service(project, user, blankrev, 'newrev', ref) expect(project.protected_branches).to be_empty end @@ -227,7 +217,7 @@ describe GitPushService do expect(project).to receive(:execute_hooks) expect(project.default_branch).to eq("master") - execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' ) + execute_service(project, user, blankrev, 'newrev', ref) expect(project.protected_branches).not_to be_empty expect(project.protected_branches.last.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::DEVELOPER]) @@ -242,7 +232,7 @@ describe GitPushService do expect(project.default_branch).to eq("master") expect_any_instance_of(ProtectedBranches::CreateService).not_to receive(:execute) - execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' ) + execute_service(project, user, blankrev, 'newrev', ref) expect(project.protected_branches).not_to be_empty expect(project.protected_branches.last.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::NO_ACCESS]) @@ -254,7 +244,7 @@ describe GitPushService do expect(project).to receive(:execute_hooks) expect(project.default_branch).to eq("master") - execute_service(project, user, @blankrev, 'newrev', 'refs/heads/master' ) + execute_service(project, user, blankrev, 'newrev', ref) expect(project.protected_branches).not_to be_empty expect(project.protected_branches.first.push_access_levels.map(&:access_level)).to eq([Gitlab::Access::MASTER]) expect(project.protected_branches.first.merge_access_levels.map(&:access_level)).to eq([Gitlab::Access::DEVELOPER]) @@ -262,7 +252,7 @@ describe GitPushService do it "when pushing new commits to existing branch" do expect(project).to receive(:execute_hooks) - execute_service(project, user, 'oldrev', 'newrev', 'refs/heads/master' ) + execute_service(project, user, 'oldrev', 'newrev', ref) end end end @@ -292,7 +282,7 @@ describe GitPushService do it "creates a note if a pushed commit mentions an issue" do expect(SystemNoteService).to receive(:cross_reference).with(issue, commit, commit_author) - execute_service(project, user, @oldrev, @newrev, @ref ) + execute_service(project, user, oldrev, newrev, ref) end it "only creates a cross-reference note if one doesn't already exist" do @@ -300,7 +290,7 @@ describe GitPushService do expect(SystemNoteService).not_to receive(:cross_reference).with(issue, commit, commit_author) - execute_service(project, user, @oldrev, @newrev, @ref ) + execute_service(project, user, oldrev, newrev, ref) end it "defaults to the pushing user if the commit's author is not known" do @@ -310,16 +300,16 @@ describe GitPushService do ) expect(SystemNoteService).to receive(:cross_reference).with(issue, commit, user) - execute_service(project, user, @oldrev, @newrev, @ref ) + execute_service(project, user, oldrev, newrev, ref) end it "finds references in the first push to a non-default branch" do - allow(project.repository).to receive(:commits_between).with(@blankrev, @newrev).and_return([]) - allow(project.repository).to receive(:commits_between).with("master", @newrev).and_return([commit]) + allow(project.repository).to receive(:commits_between).with(blankrev, newrev).and_return([]) + allow(project.repository).to receive(:commits_between).with("master", newrev).and_return([commit]) expect(SystemNoteService).to receive(:cross_reference).with(issue, commit, commit_author) - execute_service(project, user, @blankrev, @newrev, 'refs/heads/other' ) + execute_service(project, user, blankrev, newrev, 'refs/heads/other') end end @@ -349,14 +339,14 @@ describe GitPushService do context "while saving the 'first_mentioned_in_commit_at' metric for an issue" do it 'sets the metric for referenced issues' do - execute_service(project, user, @oldrev, @newrev, @ref) + execute_service(project, user, oldrev, newrev, ref) expect(issue.reload.metrics.first_mentioned_in_commit_at).to be_like_time(commit_time) end it 'does not set the metric for non-referenced issues' do non_referenced_issue = create(:issue, project: project) - execute_service(project, user, @oldrev, @newrev, @ref) + execute_service(project, user, oldrev, newrev, ref) expect(non_referenced_issue.reload.metrics.first_mentioned_in_commit_at).to be_nil end @@ -388,18 +378,18 @@ describe GitPushService do context "to default branches" do it "closes issues" do - execute_service(project, commit_author, @oldrev, @newrev, @ref ) + execute_service(project, commit_author, oldrev, newrev, ref) expect(Issue.find(issue.id)).to be_closed end it "adds a note indicating that the issue is now closed" do expect(SystemNoteService).to receive(:change_status).with(issue, project, commit_author, "closed", closing_commit) - execute_service(project, commit_author, @oldrev, @newrev, @ref ) + execute_service(project, commit_author, oldrev, newrev, ref) end it "doesn't create additional cross-reference notes" do expect(SystemNoteService).not_to receive(:cross_reference) - execute_service(project, commit_author, @oldrev, @newrev, @ref ) + execute_service(project, commit_author, oldrev, newrev, ref) end end @@ -411,11 +401,11 @@ describe GitPushService do it "creates cross-reference notes" do expect(SystemNoteService).to receive(:cross_reference).with(issue, closing_commit, commit_author) - execute_service(project, user, @oldrev, @newrev, @ref ) + execute_service(project, user, oldrev, newrev, ref) end it "doesn't close issues" do - execute_service(project, user, @oldrev, @newrev, @ref ) + execute_service(project, user, oldrev, newrev, ref) expect(Issue.find(issue.id)).to be_opened end end @@ -432,11 +422,12 @@ describe GitPushService do stub_jira_urls("JIRA-1") allow(closing_commit).to receive_messages({ - issue_closing_regex: Regexp.new(Gitlab.config.gitlab.issue_closing_pattern), - safe_message: message, - author_name: commit_author.name, - author_email: commit_author.email - }) + issue_closing_regex: Regexp.new(Gitlab.config.gitlab.issue_closing_pattern), + safe_message: message, + author_name: commit_author.name, + author_email: commit_author.email + }) + allow(JIRA::Resource::Remotelink).to receive(:all).and_return([]) allow(project.repository).to receive_messages(commits_between: [closing_commit]) @@ -450,7 +441,7 @@ describe GitPushService do let(:message) { "this is some work.\n\nrelated to JIRA-1" } it "initiates one api call to jira server to mention the issue" do - execute_service(project, user, @oldrev, @newrev, @ref) + execute_service(project, user, oldrev, newrev, ref) expect(WebMock).to have_requested(:post, jira_api_comment_url('JIRA-1')).with( body: /mentioned this issue in/ @@ -460,7 +451,11 @@ describe GitPushService do context "closing an issue" do let(:message) { "this is some work.\n\ncloses JIRA-1" } - let(:comment_body) { { body: "Issue solved with [#{closing_commit.id}|http://#{Gitlab.config.gitlab.host}/#{project.path_with_namespace}/commit/#{closing_commit.id}]." }.to_json } + let(:comment_body) do + { + body: "Issue solved with [#{closing_commit.id}|http://#{Gitlab.config.gitlab.host}/#{project.path_with_namespace}/commit/#{closing_commit.id}]." + }.to_json + end before do open_issue = JIRA::Resource::Issue.new(jira_tracker.client, attrs: { "id" => "JIRA-1" }) @@ -474,13 +469,13 @@ describe GitPushService do context "using right markdown" do it "initiates one api call to jira server to close the issue" do - execute_service(project, commit_author, @oldrev, @newrev, @ref ) + execute_service(project, commit_author, oldrev, newrev, ref) expect(WebMock).to have_requested(:post, jira_api_transition_url('JIRA-1')).once end it "initiates one api call to jira server to comment on the issue" do - execute_service(project, commit_author, @oldrev, @newrev, @ref ) + execute_service(project, commit_author, oldrev, newrev, ref) expect(WebMock).to have_requested(:post, jira_api_comment_url('JIRA-1')).with( body: comment_body @@ -497,13 +492,13 @@ describe GitPushService do let(:message) { "this is some work.\n\ncloses #1" } it "does not initiates one api call to jira server to close the issue" do - execute_service(project, commit_author, @oldrev, @newrev, @ref ) + execute_service(project, commit_author, oldrev, newrev, ref) expect(WebMock).not_to have_requested(:post, jira_api_transition_url('JIRA-1')) end it "does not initiates one api call to jira server to comment on the issue" do - execute_service(project, commit_author, @oldrev, @newrev, @ref ) + execute_service(project, commit_author, oldrev, newrev, ref) expect(WebMock).not_to have_requested(:post, jira_api_comment_url('JIRA-1')).with( body: comment_body @@ -516,13 +511,13 @@ describe GitPushService do let(:message) { "this is some work.\n\ncloses JIRA-1 \n\n closes #{issue.to_reference}" } it "initiates one api call to jira server to close the jira issue" do - execute_service(project, commit_author, @oldrev, @newrev, @ref ) + execute_service(project, commit_author, oldrev, newrev, ref) expect(WebMock).to have_requested(:post, jira_api_transition_url('JIRA-1')).once end it "initiates one api call to jira server to comment on the jira issue" do - execute_service(project, commit_author, @oldrev, @newrev, @ref ) + execute_service(project, commit_author, oldrev, newrev, ref) expect(WebMock).to have_requested(:post, jira_api_comment_url('JIRA-1')).with( body: comment_body @@ -530,14 +525,14 @@ describe GitPushService do end it "closes the internal issue" do - execute_service(project, commit_author, @oldrev, @newrev, @ref ) + execute_service(project, commit_author, oldrev, newrev, ref) expect(issue.reload).to be_closed end it "adds a note indicating that the issue is now closed" do expect(SystemNoteService).to receive(:change_status) .with(issue, project, commit_author, "closed", closing_commit) - execute_service(project, commit_author, @oldrev, @newrev, @ref ) + execute_service(project, commit_author, oldrev, newrev, ref) end end end @@ -547,7 +542,7 @@ describe GitPushService do describe "empty project" do let(:project) { create(:project_empty_repo) } - let(:new_ref) { 'refs/heads/feature'} + let(:new_ref) { 'refs/heads/feature' } before do allow(project).to receive(:default_branch).and_return('feature') @@ -555,7 +550,7 @@ describe GitPushService do end it 'push to first branch updates HEAD' do - execute_service(project, user, @blankrev, @newrev, new_ref ) + execute_service(project, user, blankrev, newrev, new_ref) end end @@ -580,7 +575,7 @@ describe GitPushService do it 'does not perform housekeeping when not needed' do expect(housekeeping).not_to receive(:execute) - execute_service(project, user, @oldrev, @newrev, @ref) + execute_service(project, user, oldrev, newrev, ref) end context 'when housekeeping is needed' do @@ -591,20 +586,20 @@ describe GitPushService do it 'performs housekeeping' do expect(housekeeping).to receive(:execute) - execute_service(project, user, @oldrev, @newrev, @ref) + execute_service(project, user, oldrev, newrev, ref) end it 'does not raise an exception' do allow(housekeeping).to receive(:try_obtain_lease).and_return(false) - execute_service(project, user, @oldrev, @newrev, @ref) + execute_service(project, user, oldrev, newrev, ref) end end it 'increments the push counter' do expect(housekeeping).to receive(:increment!) - execute_service(project, user, @oldrev, @newrev, @ref) + execute_service(project, user, oldrev, newrev, ref) end end @@ -612,9 +607,9 @@ describe GitPushService do let(:service) do described_class.new(project, user, - oldrev: sample_commit.parent_id, - newrev: sample_commit.id, - ref: 'refs/heads/master') + oldrev: oldrev, + newrev: newrev, + ref: ref) end context 'on the default branch' do @@ -657,9 +652,9 @@ describe GitPushService do let(:service) do described_class.new(project, user, - oldrev: sample_commit.parent_id, - newrev: sample_commit.id, - ref: 'refs/heads/master') + oldrev: oldrev, + newrev: newrev, + ref: ref) end it 'only schedules a limited number of commits' do @@ -686,8 +681,8 @@ describe GitPushService do described_class.new( project, user, - oldrev: sample_commit.parent_id, - newrev: sample_commit.id, + oldrev: oldrev, + newrev: newrev, ref: 'refs/heads/master' ) end @@ -695,13 +690,17 @@ describe GitPushService do it 'calls CreateGpgSignatureWorker.perform_async for each commit' do expect(CreateGpgSignatureWorker).to receive(:perform_async).with(sample_commit.id, project.id) - execute_service(project, user, @oldrev, @newrev, @ref) + execute_service(project, user, oldrev, newrev, ref) end end def execute_service(project, user, oldrev, newrev, ref) - service = described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref ) + service = described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref) service.execute service end + + def push_data_from_service(project, user, oldrev, newrev, ref) + execute_service(project, user, oldrev, newrev, ref).push_data + end end -- cgit v1.2.1 From ffa4cedab6e6286490c30b8176519609378c8ca7 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 27 Jul 2017 14:58:21 -0500 Subject: fix all eslint violations in user_tabs.js --- app/assets/javascripts/users/user_tabs.js | 153 ++++++++++++++---------------- 1 file changed, 73 insertions(+), 80 deletions(-) diff --git a/app/assets/javascripts/users/user_tabs.js b/app/assets/javascripts/users/user_tabs.js index ab7306c4f15..fd9fe597303 100644 --- a/app/assets/javascripts/users/user_tabs.js +++ b/app/assets/javascripts/users/user_tabs.js @@ -1,66 +1,59 @@ -/* eslint-disable max-len, space-before-function-paren, no-underscore-dangle, consistent-return, comma-dangle, no-unused-vars, dot-notation, no-new, no-return-assign, camelcase, no-param-reassign, class-methods-use-this */ - import ActivityCalendar from './activity_calendar'; -/* -UserTabs - -Handles persisting and restoring the current tab selection and lazily-loading -content on the Users#show page. - -### Example Markup - -

- -
-
- Activity Content -
-
- Groups Content -
-
- Contributed projects content -
-
- Projects content -
-
- Snippets content -
-
- -
-
- Loading Animation -
-
-*/ +/** + * UserTabs + * + * Handles persisting and restoring the current tab selection and lazily-loading + * content on the Users#show page. + * + * ### Example Markup + * + * + * + *
+ *
+ * Activity Content + *
+ *
+ * Groups Content + *
+ *
+ * Contributed projects content + *
+ *
+ * Projects content + *
+ *
+ * Snippets content + *
+ *
+ * + *
+ *
+ * Loading Animation + *
+ *
+ */ const CALENDAR_TEMPLATE = `
@@ -72,12 +65,12 @@ const CALENDAR_TEMPLATE = ` `; export default class UserTabs { - constructor ({ defaultAction, action, parentEl }) { + constructor({ defaultAction, action, parentEl }) { this.loaded = {}; this.defaultAction = defaultAction || 'activity'; this.action = action || this.defaultAction; this.$parentEl = $(parentEl) || $(document); - this._location = window.location; + this.windowLocation = window.location; this.$parentEl.find('.nav-links a') .each((i, navLink) => { this.loaded[$(navLink).attr('data-action')] = false; @@ -93,12 +86,10 @@ export default class UserTabs { } bindEvents() { - this.changeProjectsPageWrapper = this.changeProjectsPage.bind(this); - - this.$parentEl.off('shown.bs.tab', '.nav-links a[data-toggle="tab"]') - .on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', event => this.tabShown(event)); - - this.$parentEl.on('click', '.gl-pagination a', this.changeProjectsPageWrapper); + this.$parentEl + .off('shown.bs.tab', '.nav-links a[data-toggle="tab"]') + .on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', event => this.tabShown(event)) + .on('click', '.gl-pagination a', event => this.changeProjectsPage(event)); } changeProjectsPage(e) { @@ -133,7 +124,7 @@ export default class UserTabs { const loadableActions = ['groups', 'contributed', 'projects', 'snippets']; if (loadableActions.indexOf(action) > -1) { - return this.loadTab(action, endpoint); + this.loadTab(action, endpoint); } } @@ -142,14 +133,13 @@ export default class UserTabs { beforeSend: () => this.toggleLoading(true), complete: () => this.toggleLoading(false), dataType: 'json', - type: 'GET', url: endpoint, success: (data) => { const tabSelector = `div#${action}`; this.$parentEl.find(tabSelector).html(data.html); this.loaded[action] = true; - return gl.utils.localTimeAgo($('.js-timeago', tabSelector)); - } + gl.utils.localTimeAgo($('.js-timeago', tabSelector)); + }, }); } @@ -166,10 +156,13 @@ export default class UserTabs { url: calendarPath, success: (activityData) => { $calendarWrap.html(CALENDAR_TEMPLATE); + + // eslint-disable-next-line no-new new ActivityCalendar(activityData, calendarActivitiesPath); - } + }, }); + // eslint-disable-next-line no-new new gl.Activities(); this.loaded.activity = true; } @@ -180,13 +173,13 @@ export default class UserTabs { } setCurrentAction(source) { - let new_state = source; - new_state = new_state.replace(/\/+$/, ''); - new_state += this._location.search + this._location.hash; + let newState = source; + newState = newState.replace(/\/+$/, ''); + newState += this.windowLocation.search + this.windowLocation.hash; history.replaceState({ - url: new_state - }, document.title, new_state); - return new_state; + url: newState, + }, document.title, newState); + return newState; } getCurrentAction() { -- cgit v1.2.1 From c4fae77e899d181346792566f381f9049f542910 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 27 Jul 2017 15:17:11 -0500 Subject: remove janky function binding in activity calendar class --- app/assets/javascripts/users/activity_calendar.js | 100 ++++++++++++---------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/app/assets/javascripts/users/activity_calendar.js b/app/assets/javascripts/users/activity_calendar.js index b7f50cfd083..9f1ac3ebf31 100644 --- a/app/assets/javascripts/users/activity_calendar.js +++ b/app/assets/javascripts/users/activity_calendar.js @@ -1,7 +1,13 @@ -/* eslint-disable func-names, space-before-function-paren, no-var, wrap-iife, camelcase, vars-on-top, object-shorthand, comma-dangle, eqeqeq, no-mixed-operators, no-return-assign, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, no-else-return, max-len, class-methods-use-this */ +/* eslint-disable no-var, camelcase, vars-on-top, object-shorthand, comma-dangle, eqeqeq, no-mixed-operators, no-return-assign, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, no-else-return, max-len, class-methods-use-this */ import d3 from 'd3'; +const LOADING_HTML = ` +
+ +
+`; + export default class ActivityCalendar { constructor(timestamps, calendar_activities_path) { this.calendar_activities_path = calendar_activities_path; @@ -79,40 +85,41 @@ export default class ActivityCalendar { } renderDays() { - return this.svg.selectAll('g').data(this.timestampsTmp).enter().append('g').attr('transform', (function(_this) { - return function(group, i) { - _.each(group, function(stamp, a) { + this.svg.selectAll('g').data(this.timestampsTmp).enter().append('g') + .attr('transform', (group, i) => { + _.each(group, (stamp, a) => { var lastMonth, lastMonthX, month, x; if (a === 0 && stamp.day === 0) { month = stamp.date.getMonth(); - x = (_this.daySizeWithSpace * i + 1) + _this.daySizeWithSpace; - lastMonth = _.last(_this.months); + x = (this.daySizeWithSpace * i + 1) + this.daySizeWithSpace; + lastMonth = _.last(this.months); if (lastMonth != null) { lastMonthX = lastMonth.x; } if (lastMonth == null) { - return _this.months.push({ + return this.months.push({ month: month, x: x }); - } else if (month !== lastMonth.month && x - _this.daySizeWithSpace !== lastMonthX) { - return _this.months.push({ + } else if (month !== lastMonth.month && x - this.daySizeWithSpace !== lastMonthX) { + return this.months.push({ month: month, x: x }); } } }); - return "translate(" + ((_this.daySizeWithSpace * i + 1) + _this.daySizeWithSpace) + ", 18)"; - }; - })(this)).selectAll('rect').data(function(stamp) { - return stamp; - }).enter().append('rect').attr('x', '0').attr('y', (function(_this) { - return function(stamp, i) { - return _this.daySizeWithSpace * stamp.day; - }; - })(this)).attr('width', this.daySize).attr('height', this.daySize).attr('title', (function(_this) { - return function(stamp) { + return "translate(" + ((this.daySizeWithSpace * i + 1) + this.daySizeWithSpace) + ", 18)"; + }) + .selectAll('rect') + .data(stamp => stamp) + .enter() + .append('rect') + .attr('x', '0') + .attr('y', stamp => this.daySizeWithSpace * stamp.day) + .attr('width', this.daySize) + .attr('height', this.daySize) + .attr('title', (stamp) => { var contribText, date, dateText; date = new Date(stamp.date); contribText = 'No contributions'; @@ -121,21 +128,20 @@ export default class ActivityCalendar { } dateText = date.format('mmm d, yyyy'); return contribText + "
" + (gl.utils.getDayName(date)) + " " + dateText; - }; - })(this)).attr('class', 'user-contrib-cell js-tooltip').attr('fill', (function(_this) { - return function(stamp) { + }) + .attr('class', 'user-contrib-cell js-tooltip').attr('fill', (stamp) => { if (stamp.count !== 0) { - return _this.color(Math.min(stamp.count, 40)); + return this.color(Math.min(stamp.count, 40)); } else { return '#ededed'; } - }; - })(this)).attr('data-container', 'body').on('click', this.clickDay); + }) + .attr('data-container', 'body') + .on('click', this.clickDay); } renderDayTitles() { - var days; - days = [ + const days = [ { text: 'M', y: 29 + (this.daySizeWithSpace * 1) @@ -147,21 +153,29 @@ export default class ActivityCalendar { y: 29 + (this.daySizeWithSpace * 5) } ]; - return this.svg.append('g').selectAll('text').data(days).enter().append('text').attr('text-anchor', 'middle').attr('x', 8).attr('y', function(day) { - return day.y; - }).text(function(day) { - return day.text; - }).attr('class', 'user-contrib-text'); + this.svg.append('g') + .selectAll('text') + .data(days) + .enter() + .append('text') + .attr('text-anchor', 'middle') + .attr('x', 8) + .attr('y', day => day.y) + .text(day => day.text) + .attr('class', 'user-contrib-text'); } renderMonths() { - return this.svg.append('g').attr('direction', 'ltr').selectAll('text').data(this.months).enter().append('text').attr('x', function(date) { - return date.x; - }).attr('y', 10).attr('class', 'user-contrib-text').text((function(_this) { - return function(date) { - return _this.monthNames[date.month]; - }; - })(this)); + this.svg.append('g') + .attr('direction', 'ltr') + .selectAll('text') + .data(this.months) + .enter() + .append('text') + .attr('x', date => date.x) + .attr('y', 10) + .attr('class', 'user-contrib-text') + .text(date => this.monthNames[date.month]); } renderKey() { @@ -206,12 +220,8 @@ export default class ActivityCalendar { }, cache: false, dataType: 'html', - beforeSend: function() { - return $('.user-calendar-activities').html('
'); - }, - success: function(data) { - return $('.user-calendar-activities').html(data); - } + beforeSend: () => $('.user-calendar-activities').html(LOADING_HTML), + success: data => $('.user-calendar-activities').html(data), }); } else { this.currentSelectedDate = ''; -- cgit v1.2.1 From 6902145716d80a13db08d4d72cb4dc5b195fe1ef Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 27 Jul 2017 15:19:59 -0500 Subject: resolve camelcase violations --- app/assets/javascripts/users/activity_calendar.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/users/activity_calendar.js b/app/assets/javascripts/users/activity_calendar.js index 9f1ac3ebf31..56f3014c983 100644 --- a/app/assets/javascripts/users/activity_calendar.js +++ b/app/assets/javascripts/users/activity_calendar.js @@ -1,4 +1,4 @@ -/* eslint-disable no-var, camelcase, vars-on-top, object-shorthand, comma-dangle, eqeqeq, no-mixed-operators, no-return-assign, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, no-else-return, max-len, class-methods-use-this */ +/* eslint-disable no-var, vars-on-top, object-shorthand, comma-dangle, eqeqeq, no-mixed-operators, no-return-assign, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, no-else-return, max-len, class-methods-use-this */ import d3 from 'd3'; @@ -9,8 +9,8 @@ const LOADING_HTML = ` `; export default class ActivityCalendar { - constructor(timestamps, calendar_activities_path) { - this.calendar_activities_path = calendar_activities_path; + constructor(timestamps, calendarActivitiesPath) { + this.calendarActivitiesPath = calendarActivitiesPath; this.clickDay = this.clickDay.bind(this); this.currentSelectedDate = ''; this.daySpace = 1; @@ -209,15 +209,12 @@ export default class ActivityCalendar { } clickDay(stamp) { - var formatted_date; if (this.currentSelectedDate !== stamp.date) { this.currentSelectedDate = stamp.date; - formatted_date = this.currentSelectedDate.getFullYear() + "-" + (this.currentSelectedDate.getMonth() + 1) + "-" + this.currentSelectedDate.getDate(); + const date = this.currentSelectedDate.getFullYear() + "-" + (this.currentSelectedDate.getMonth() + 1) + "-" + this.currentSelectedDate.getDate(); return $.ajax({ - url: this.calendar_activities_path, - data: { - date: formatted_date - }, + url: this.calendarActivitiesPath, + data: { date }, cache: false, dataType: 'html', beforeSend: () => $('.user-calendar-activities').html(LOADING_HTML), -- cgit v1.2.1 From 45a446ea9475a658631b83e7c7b42838fe2de3b4 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 27 Jul 2017 15:25:13 -0500 Subject: resolve comma-dangle and object-shorthand eslint violations --- app/assets/javascripts/users/activity_calendar.js | 35 ++++++++--------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/app/assets/javascripts/users/activity_calendar.js b/app/assets/javascripts/users/activity_calendar.js index 56f3014c983..b2c3b3d70ca 100644 --- a/app/assets/javascripts/users/activity_calendar.js +++ b/app/assets/javascripts/users/activity_calendar.js @@ -1,4 +1,4 @@ -/* eslint-disable no-var, vars-on-top, object-shorthand, comma-dangle, eqeqeq, no-mixed-operators, no-return-assign, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, no-else-return, max-len, class-methods-use-this */ +/* eslint-disable no-var, vars-on-top, eqeqeq, no-mixed-operators, no-return-assign, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, no-else-return, max-len, class-methods-use-this */ import d3 from 'd3'; @@ -18,6 +18,7 @@ export default class ActivityCalendar { this.daySizeWithSpace = this.daySize + (this.daySpace * 2); this.monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; this.months = []; + // Loop through the timestamps to create a group of objects // The group of objects will be grouped based on the day of the week they are this.timestampsTmp = []; @@ -36,7 +37,7 @@ export default class ActivityCalendar { date.setDate(date.getDate() + i); var day = date.getDay(); - var count = timestamps[date.format('yyyy-mm-dd')]; + var count = timestamps[date.format('yyyy-mm-dd')] || 0; // Create a new group array if this is the first day of the week // or if is first object @@ -45,13 +46,9 @@ export default class ActivityCalendar { group += 1; } - var innerArray = this.timestampsTmp[group - 1]; // Push to the inner array the values that will be used to render map - innerArray.push({ - count: count || 0, - date: date, - day: day - }); + var innerArray = this.timestampsTmp[group - 1]; + innerArray.push({ count, date, day }); } // Init color functions @@ -97,15 +94,9 @@ export default class ActivityCalendar { lastMonthX = lastMonth.x; } if (lastMonth == null) { - return this.months.push({ - month: month, - x: x - }); + return this.months.push({ month, x }); } else if (month !== lastMonth.month && x - this.daySizeWithSpace !== lastMonthX) { - return this.months.push({ - month: month, - x: x - }); + return this.months.push({ month, x }); } } }); @@ -144,14 +135,14 @@ export default class ActivityCalendar { const days = [ { text: 'M', - y: 29 + (this.daySizeWithSpace * 1) + y: 29 + (this.daySizeWithSpace * 1), }, { text: 'W', - y: 29 + (this.daySizeWithSpace * 3) + y: 29 + (this.daySizeWithSpace * 3), }, { text: 'F', - y: 29 + (this.daySizeWithSpace * 5) - } + y: 29 + (this.daySizeWithSpace * 5), + }, ]; this.svg.append('g') .selectAll('text') @@ -227,8 +218,6 @@ export default class ActivityCalendar { } initTooltips() { - return $('.js-contrib-calendar .js-tooltip').tooltip({ - html: true - }); + $('.js-contrib-calendar .js-tooltip').tooltip({ html: true }); } } -- cgit v1.2.1 From ce4e891065368901da214b689f929d4cc7ce5b94 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 27 Jul 2017 15:27:42 -0500 Subject: resolve no-mixed-operators and no-return-assign eslint violations --- app/assets/javascripts/users/activity_calendar.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/users/activity_calendar.js b/app/assets/javascripts/users/activity_calendar.js index b2c3b3d70ca..c345f2ae1ce 100644 --- a/app/assets/javascripts/users/activity_calendar.js +++ b/app/assets/javascripts/users/activity_calendar.js @@ -1,4 +1,4 @@ -/* eslint-disable no-var, vars-on-top, eqeqeq, no-mixed-operators, no-return-assign, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, no-else-return, max-len, class-methods-use-this */ +/* eslint-disable no-var, vars-on-top, eqeqeq, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, no-else-return, max-len, class-methods-use-this */ import d3 from 'd3'; @@ -77,8 +77,8 @@ export default class ActivityCalendar { } renderSvg(group) { - var width = (group + 1) * this.daySizeWithSpace + this.getExtraWidthPadding(group); - return this.svg = d3.select('.js-contrib-calendar').append('svg').attr('width', width).attr('height', 167).attr('class', 'contrib-calendar'); + var width = ((group + 1) * this.daySizeWithSpace) + this.getExtraWidthPadding(group); + this.svg = d3.select('.js-contrib-calendar').append('svg').attr('width', width).attr('height', 167).attr('class', 'contrib-calendar'); } renderDays() { @@ -88,7 +88,7 @@ export default class ActivityCalendar { var lastMonth, lastMonthX, month, x; if (a === 0 && stamp.day === 0) { month = stamp.date.getMonth(); - x = (this.daySizeWithSpace * i + 1) + this.daySizeWithSpace; + x = (this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace; lastMonth = _.last(this.months); if (lastMonth != null) { lastMonthX = lastMonth.x; @@ -100,7 +100,7 @@ export default class ActivityCalendar { } } }); - return "translate(" + ((this.daySizeWithSpace * i + 1) + this.daySizeWithSpace) + ", 18)"; + return "translate(" + ((this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace) + ", 18)"; }) .selectAll('rect') .data(stamp => stamp) @@ -174,7 +174,7 @@ export default class ActivityCalendar { const keyColors = ['#ededed', this.colorKey(0), this.colorKey(1), this.colorKey(2), this.colorKey(3)]; this.svg.append('g') - .attr('transform', `translate(18, ${this.daySizeWithSpace * 8 + 16})`) + .attr('transform', `translate(18, ${(this.daySizeWithSpace * 8) + 16})`) .selectAll('rect') .data(keyColors) .enter() -- cgit v1.2.1 From 9d5bdb5d313f42197cfa8c57da314ea423e8d8a1 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 27 Jul 2017 15:35:25 -0500 Subject: resolve prefer-template and quotes eslint violations --- app/assets/javascripts/users/activity_calendar.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/users/activity_calendar.js b/app/assets/javascripts/users/activity_calendar.js index c345f2ae1ce..79b31227b77 100644 --- a/app/assets/javascripts/users/activity_calendar.js +++ b/app/assets/javascripts/users/activity_calendar.js @@ -1,4 +1,4 @@ -/* eslint-disable no-var, vars-on-top, eqeqeq, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, no-else-return, max-len, class-methods-use-this */ +/* eslint-disable no-var, vars-on-top, eqeqeq, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, no-unused-vars, no-else-return, max-len, class-methods-use-this */ import d3 from 'd3'; @@ -54,6 +54,7 @@ export default class ActivityCalendar { // Init color functions this.colorKey = this.initColorKey(); this.color = this.initColor(); + // Init the svg element this.renderSvg(group); this.renderDays(); @@ -100,7 +101,7 @@ export default class ActivityCalendar { } } }); - return "translate(" + ((this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace) + ", 18)"; + return `translate(${(this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace}, 18)`; }) .selectAll('rect') .data(stamp => stamp) @@ -115,10 +116,10 @@ export default class ActivityCalendar { date = new Date(stamp.date); contribText = 'No contributions'; if (stamp.count > 0) { - contribText = stamp.count + " contribution" + (stamp.count > 1 ? 's' : ''); + contribText = `${stamp.count} contribution${stamp.count > 1 ? 's' : ''}`; } dateText = date.format('mmm d, yyyy'); - return contribText + "
" + (gl.utils.getDayName(date)) + " " + dateText; + return `${contribText}
${gl.utils.getDayName(date)} ${dateText}`; }) .attr('class', 'user-contrib-cell js-tooltip').attr('fill', (stamp) => { if (stamp.count !== 0) { @@ -202,8 +203,14 @@ export default class ActivityCalendar { clickDay(stamp) { if (this.currentSelectedDate !== stamp.date) { this.currentSelectedDate = stamp.date; - const date = this.currentSelectedDate.getFullYear() + "-" + (this.currentSelectedDate.getMonth() + 1) + "-" + this.currentSelectedDate.getDate(); - return $.ajax({ + + const date = [ + this.currentSelectedDate.getFullYear(), + this.currentSelectedDate.getMonth() + 1, + this.currentSelectedDate.getDate(), + ].join('-'); + + $.ajax({ url: this.calendarActivitiesPath, data: { date }, cache: false, @@ -213,7 +220,7 @@ export default class ActivityCalendar { }); } else { this.currentSelectedDate = ''; - return $('.user-calendar-activities').html(''); + $('.user-calendar-activities').html(''); } } -- cgit v1.2.1 From c4718a5f2f443c78a78ad144098ee049d9f70128 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 27 Jul 2017 15:37:50 -0500 Subject: resolve consistent-return eslint violation [ci-skip] --- app/assets/javascripts/users/activity_calendar.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/users/activity_calendar.js b/app/assets/javascripts/users/activity_calendar.js index 79b31227b77..2efb10860d5 100644 --- a/app/assets/javascripts/users/activity_calendar.js +++ b/app/assets/javascripts/users/activity_calendar.js @@ -1,4 +1,4 @@ -/* eslint-disable no-var, vars-on-top, eqeqeq, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, no-unused-vars, no-else-return, max-len, class-methods-use-this */ +/* eslint-disable no-var, vars-on-top, eqeqeq, newline-per-chained-call, one-var, one-var-declaration-per-line, no-unused-vars, no-else-return, max-len, class-methods-use-this */ import d3 from 'd3'; @@ -94,10 +94,8 @@ export default class ActivityCalendar { if (lastMonth != null) { lastMonthX = lastMonth.x; } - if (lastMonth == null) { - return this.months.push({ month, x }); - } else if (month !== lastMonth.month && x - this.daySizeWithSpace !== lastMonthX) { - return this.months.push({ month, x }); + if (lastMonth == null || (month !== lastMonth.month && x - this.daySizeWithSpace !== lastMonthX)) { + this.months.push({ month, x }); } } }); -- cgit v1.2.1 From 17b43cd4a1df2bbe8e4d59b015cbae741849317f Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 27 Jul 2017 15:43:12 -0500 Subject: resolve eqeqeq, newline-per-chained-call, no-unused-vars, and no-else-return eslint violations --- app/assets/javascripts/users/activity_calendar.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/users/activity_calendar.js b/app/assets/javascripts/users/activity_calendar.js index 2efb10860d5..b109eb2b223 100644 --- a/app/assets/javascripts/users/activity_calendar.js +++ b/app/assets/javascripts/users/activity_calendar.js @@ -1,4 +1,4 @@ -/* eslint-disable no-var, vars-on-top, eqeqeq, newline-per-chained-call, one-var, one-var-declaration-per-line, no-unused-vars, no-else-return, max-len, class-methods-use-this */ +/* eslint-disable no-var, vars-on-top, one-var, one-var-declaration-per-line, max-len, class-methods-use-this */ import d3 from 'd3'; @@ -70,7 +70,7 @@ export default class ActivityCalendar { var lastColMonth = this.timestampsTmp[group - 1][0].date.getMonth(); var secondLastColMonth = this.timestampsTmp[group - 2][0].date.getMonth(); - if (lastColMonth != secondLastColMonth) { + if (lastColMonth !== secondLastColMonth) { extraWidthPadding = 3; } @@ -79,7 +79,11 @@ export default class ActivityCalendar { renderSvg(group) { var width = ((group + 1) * this.daySizeWithSpace) + this.getExtraWidthPadding(group); - this.svg = d3.select('.js-contrib-calendar').append('svg').attr('width', width).attr('height', 167).attr('class', 'contrib-calendar'); + this.svg = d3.select('.js-contrib-calendar') + .append('svg') + .attr('width', width) + .attr('height', 167) + .attr('class', 'contrib-calendar'); } renderDays() { @@ -119,13 +123,10 @@ export default class ActivityCalendar { dateText = date.format('mmm d, yyyy'); return `${contribText}
${gl.utils.getDayName(date)} ${dateText}`; }) - .attr('class', 'user-contrib-cell js-tooltip').attr('fill', (stamp) => { - if (stamp.count !== 0) { - return this.color(Math.min(stamp.count, 40)); - } else { - return '#ededed'; - } - }) + .attr('class', 'user-contrib-cell js-tooltip') + .attr('fill', stamp => ( + stamp.count !== 0 ? this.color(Math.min(stamp.count, 40)) : '#ededed' + )) .attr('data-container', 'body') .on('click', this.clickDay); } -- cgit v1.2.1 From 288e8ea1e77d46197f6c93ae1f5d0f5cc810625f Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 27 Jul 2017 16:36:48 -0500 Subject: resolve remaining eslint violations --- app/assets/javascripts/users/activity_calendar.js | 119 +++++++++++----------- app/assets/javascripts/users/user_tabs.js | 2 +- 2 files changed, 58 insertions(+), 63 deletions(-) diff --git a/app/assets/javascripts/users/activity_calendar.js b/app/assets/javascripts/users/activity_calendar.js index b109eb2b223..f091e319f44 100644 --- a/app/assets/javascripts/users/activity_calendar.js +++ b/app/assets/javascripts/users/activity_calendar.js @@ -1,5 +1,3 @@ -/* eslint-disable no-var, vars-on-top, one-var, one-var-declaration-per-line, max-len, class-methods-use-this */ - import d3 from 'd3'; const LOADING_HTML = ` @@ -8,8 +6,22 @@ const LOADING_HTML = `
`; +function formatTooltipText({ date, count }) { + const dateObject = new Date(date); + const dateDayName = gl.utils.getDayName(dateObject); + const dateText = dateObject.format('mmm d, yyyy'); + + let contribText = 'No contributions'; + if (count > 0) { + contribText = `${count} contribution${count > 1 ? 's' : ''}`; + } + return `${contribText}
${dateDayName} ${dateText}`; +} + +const initColorKey = () => d3.scale.linear().range(['#acd5f2', '#254e77']).domain([0, 3]); + export default class ActivityCalendar { - constructor(timestamps, calendarActivitiesPath) { + constructor(container, timestamps, calendarActivitiesPath) { this.calendarActivitiesPath = calendarActivitiesPath; this.clickDay = this.clickDay.bind(this); this.currentSelectedDate = ''; @@ -22,22 +34,22 @@ export default class ActivityCalendar { // Loop through the timestamps to create a group of objects // The group of objects will be grouped based on the day of the week they are this.timestampsTmp = []; - var group = 0; + let group = 0; - var today = new Date(); + const today = new Date(); today.setHours(0, 0, 0, 0, 0); - var oneYearAgo = new Date(today); + const oneYearAgo = new Date(today); oneYearAgo.setFullYear(today.getFullYear() - 1); - var days = gl.utils.getDayDifference(oneYearAgo, today); + const days = gl.utils.getDayDifference(oneYearAgo, today); - for (var i = 0; i <= days; i += 1) { - var date = new Date(oneYearAgo); + for (let i = 0; i <= days; i += 1) { + const date = new Date(oneYearAgo); date.setDate(date.getDate() + i); - var day = date.getDay(); - var count = timestamps[date.format('yyyy-mm-dd')] || 0; + const day = date.getDay(); + const count = timestamps[date.format('yyyy-mm-dd')] || 0; // Create a new group array if this is the first day of the week // or if is first object @@ -47,28 +59,30 @@ export default class ActivityCalendar { } // Push to the inner array the values that will be used to render map - var innerArray = this.timestampsTmp[group - 1]; + const innerArray = this.timestampsTmp[group - 1]; innerArray.push({ count, date, day }); } // Init color functions - this.colorKey = this.initColorKey(); + this.colorKey = initColorKey(); this.color = this.initColor(); // Init the svg element - this.renderSvg(group); + this.svg = this.renderSvg(container, group); this.renderDays(); this.renderMonths(); this.renderDayTitles(); this.renderKey(); - this.initTooltips(); + + // Init tooltips + $(`${container} .js-tooltip`).tooltip({ html: true }); } // Add extra padding for the last month label if it is also the last column getExtraWidthPadding(group) { - var extraWidthPadding = 0; - var lastColMonth = this.timestampsTmp[group - 1][0].date.getMonth(); - var secondLastColMonth = this.timestampsTmp[group - 2][0].date.getMonth(); + let extraWidthPadding = 0; + const lastColMonth = this.timestampsTmp[group - 1][0].date.getMonth(); + const secondLastColMonth = this.timestampsTmp[group - 2][0].date.getMonth(); if (lastColMonth !== secondLastColMonth) { extraWidthPadding = 3; @@ -77,9 +91,9 @@ export default class ActivityCalendar { return extraWidthPadding; } - renderSvg(group) { - var width = ((group + 1) * this.daySizeWithSpace) + this.getExtraWidthPadding(group); - this.svg = d3.select('.js-contrib-calendar') + renderSvg(container, group) { + const width = ((group + 1) * this.daySizeWithSpace) + this.getExtraWidthPadding(group); + return d3.select(container) .append('svg') .attr('width', width) .attr('height', 167) @@ -90,15 +104,14 @@ export default class ActivityCalendar { this.svg.selectAll('g').data(this.timestampsTmp).enter().append('g') .attr('transform', (group, i) => { _.each(group, (stamp, a) => { - var lastMonth, lastMonthX, month, x; if (a === 0 && stamp.day === 0) { - month = stamp.date.getMonth(); - x = (this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace; - lastMonth = _.last(this.months); - if (lastMonth != null) { - lastMonthX = lastMonth.x; - } - if (lastMonth == null || (month !== lastMonth.month && x - this.daySizeWithSpace !== lastMonthX)) { + const month = stamp.date.getMonth(); + const x = (this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace; + const lastMonth = _.last(this.months); + if ( + lastMonth == null || + (month !== lastMonth.month && x - this.daySizeWithSpace !== lastMonth.x) + ) { this.months.push({ month, x }); } } @@ -106,29 +119,20 @@ export default class ActivityCalendar { return `translate(${(this.daySizeWithSpace * i) + 1 + this.daySizeWithSpace}, 18)`; }) .selectAll('rect') - .data(stamp => stamp) - .enter() - .append('rect') - .attr('x', '0') - .attr('y', stamp => this.daySizeWithSpace * stamp.day) - .attr('width', this.daySize) - .attr('height', this.daySize) - .attr('title', (stamp) => { - var contribText, date, dateText; - date = new Date(stamp.date); - contribText = 'No contributions'; - if (stamp.count > 0) { - contribText = `${stamp.count} contribution${stamp.count > 1 ? 's' : ''}`; - } - dateText = date.format('mmm d, yyyy'); - return `${contribText}
${gl.utils.getDayName(date)} ${dateText}`; - }) - .attr('class', 'user-contrib-cell js-tooltip') - .attr('fill', stamp => ( - stamp.count !== 0 ? this.color(Math.min(stamp.count, 40)) : '#ededed' - )) - .attr('data-container', 'body') - .on('click', this.clickDay); + .data(stamp => stamp) + .enter() + .append('rect') + .attr('x', '0') + .attr('y', stamp => this.daySizeWithSpace * stamp.day) + .attr('width', this.daySize) + .attr('height', this.daySize) + .attr('fill', stamp => ( + stamp.count !== 0 ? this.color(Math.min(stamp.count, 40)) : '#ededed' + )) + .attr('title', stamp => formatTooltipText(stamp)) + .attr('class', 'user-contrib-cell js-tooltip') + .attr('data-container', 'body') + .on('click', this.clickDay); } renderDayTitles() { @@ -190,15 +194,10 @@ export default class ActivityCalendar { } initColor() { - var colorRange; - colorRange = ['#ededed', this.colorKey(0), this.colorKey(1), this.colorKey(2), this.colorKey(3)]; + const colorRange = ['#ededed', this.colorKey(0), this.colorKey(1), this.colorKey(2), this.colorKey(3)]; return d3.scale.threshold().domain([0, 10, 20, 30]).range(colorRange); } - initColorKey() { - return d3.scale.linear().range(['#acd5f2', '#254e77']).domain([0, 3]); - } - clickDay(stamp) { if (this.currentSelectedDate !== stamp.date) { this.currentSelectedDate = stamp.date; @@ -222,8 +221,4 @@ export default class ActivityCalendar { $('.user-calendar-activities').html(''); } } - - initTooltips() { - $('.js-contrib-calendar .js-tooltip').tooltip({ html: true }); - } } diff --git a/app/assets/javascripts/users/user_tabs.js b/app/assets/javascripts/users/user_tabs.js index fd9fe597303..5fe6603ce7b 100644 --- a/app/assets/javascripts/users/user_tabs.js +++ b/app/assets/javascripts/users/user_tabs.js @@ -158,7 +158,7 @@ export default class UserTabs { $calendarWrap.html(CALENDAR_TEMPLATE); // eslint-disable-next-line no-new - new ActivityCalendar(activityData, calendarActivitiesPath); + new ActivityCalendar('.js-contrib-calendar', activityData, calendarActivitiesPath); }, }); -- cgit v1.2.1 From c4938045062a1aea90d29ffb3ac38e6cdd40780e Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Thu, 27 Jul 2017 18:44:03 +0300 Subject: Explain all possible values of 'only' and 'except' --- doc/ci/yaml/README.md | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index e12ef6e2685..1869782fe6e 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -441,13 +441,25 @@ There are a few rules that apply to the usage of refs policy: * `only` and `except` are inclusive. If both `only` and `except` are defined in a job specification, the ref is filtered by `only` and `except`. * `only` and `except` allow the use of regular expressions. -* `only` and `except` allow the use of special keywords: -`api`, `branches`, `external`, `tags`, `pushes`, `schedules`, `triggers`, and `web` * `only` and `except` allow to specify a repository path to filter jobs for forks. +In addition, `only` and `except` allow the use of special keywords: + +| **Value** | **Description** | +| --------- | ---------------- | +| `branches` | When a branch is pushed. | +| `tags` | When a tag is pushed. | +| `api` | When pipeline has been triggered by a second pipelines API (not triggers API). | +| `external` | When using CI services other than GitLab. | +| `pipelines` | For multi-project triggers, created using the API with `CI_JOB_TOKEN`. | +| `pushes` | Pipeline is triggered by a `git push` by the user. | +| `schedules` | For [scheduled pipelines][schedules]. | +| `triggers` | For pipelines created using a trigger token. | +| `web` | For pipelines created using **Run pipeline** button in GitLab UI (under your project's **Pipelines**). | + In the example below, `job` will run only for refs that start with `issue-`, -whereas all branches will be skipped. +whereas all branches will be skipped: ```yaml job: @@ -460,7 +472,7 @@ job: ``` In this example, `job` will run only for refs that are tagged, or if a build is -explicitly requested via an API trigger or a [Pipeline Schedule](../../user/project/pipelines/schedules.md). +explicitly requested via an API trigger or a [Pipeline Schedule][schedules]: ```yaml job: @@ -1532,3 +1544,4 @@ CI with various languages. [ce-7983]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7983 [ce-7447]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7447 [ce-3442]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3442 +[schedules]: ../../user/project/pipelines/schedules.md -- cgit v1.2.1 From d7062dd042f7dd773900ecf6ea79e1ca26592eb5 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Sun, 14 May 2017 12:57:08 +0200 Subject: Remove Mattermost team with GitLab group When destroying a group, now an API call is made to the Mattermost server to request the deletion of the project. Actual team deletion on the Mattermost side happens async, so the runtime shouldn't increase by more than a second. --- app/models/chat_team.rb | 9 +++++++++ app/services/groups/destroy_service.rb | 2 ++ changelogs/unreleased/zj-delete-mm-team.yml | 4 ++++ lib/mattermost/client.rb | 10 ++++++++++ lib/mattermost/team.rb | 7 +++++++ spec/services/groups/destroy_service_spec.rb | 10 ++++++++++ 6 files changed, 42 insertions(+) create mode 100644 changelogs/unreleased/zj-delete-mm-team.yml diff --git a/app/models/chat_team.rb b/app/models/chat_team.rb index c52b6f15913..25ecf2d5937 100644 --- a/app/models/chat_team.rb +++ b/app/models/chat_team.rb @@ -3,4 +3,13 @@ class ChatTeam < ActiveRecord::Base validates :namespace, uniqueness: true belongs_to :namespace + + def remove_mattermost_team(current_user) + Mattermost::Team.new(current_user).destroy(team_id: team_id) + rescue Mattermost::ClientError => e + # Either the group is not found, or the user doesn't have the proper + # access on the mattermost instance. In the first case, we're done either way + # in the latter case, we can't recover by retrying, so we just log what happened + Rails.logger.error("Mattermost team deletion failed: #{e}") + end end diff --git a/app/services/groups/destroy_service.rb b/app/services/groups/destroy_service.rb index 80c51cb5a72..f565612a89d 100644 --- a/app/services/groups/destroy_service.rb +++ b/app/services/groups/destroy_service.rb @@ -21,6 +21,8 @@ module Groups DestroyService.new(group, current_user).execute end + group.chat_team&.remove_mattermost_team(current_user) + group.really_destroy! end end diff --git a/changelogs/unreleased/zj-delete-mm-team.yml b/changelogs/unreleased/zj-delete-mm-team.yml new file mode 100644 index 00000000000..f0c782c4566 --- /dev/null +++ b/changelogs/unreleased/zj-delete-mm-team.yml @@ -0,0 +1,4 @@ +--- +title: Remove Mattermost team when deleting a group +merge_request: 11362 +author: diff --git a/lib/mattermost/client.rb b/lib/mattermost/client.rb index 3d60618006c..d80cd7d2a4e 100644 --- a/lib/mattermost/client.rb +++ b/lib/mattermost/client.rb @@ -24,6 +24,10 @@ module Mattermost json_response session.post(path, options) end + def delete(session, path, options) + json_response session.delete(path, options) + end + def session_get(path, options = {}) with_session do |session| get(session, path, options) @@ -36,6 +40,12 @@ module Mattermost end end + def session_delete(path, options = {}) + with_session do |session| + delete(session, path, options) + end + end + def json_response(response) json_response = JSON.parse(response.body) diff --git a/lib/mattermost/team.rb b/lib/mattermost/team.rb index 2cdbbdece16..b2511f3af1d 100644 --- a/lib/mattermost/team.rb +++ b/lib/mattermost/team.rb @@ -14,5 +14,12 @@ module Mattermost type: type }.to_json) end + + # The deletion is done async, so the response is fast. + # On the mattermost side, this triggers an soft deletion first, after which + # the actuall data is removed + def destroy(team_id:) + session_delete("/api/v4/teams/#{team_id}?permanent=true") + end end end diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb index d59b37bee36..449fb33e0dc 100644 --- a/spec/services/groups/destroy_service_spec.rb +++ b/spec/services/groups/destroy_service_spec.rb @@ -35,6 +35,16 @@ describe Groups::DestroyService, services: true do it { expect(NotificationSetting.unscoped.all).not_to include(notification_setting) } end + context 'mattermost team' do + let!(:chat_team) { create(:chat_team, namespace: group) } + + it 'destroys the team too' do + expect_any_instance_of(Mattermost::Team).to receive(:destroy) + + destroy_group(group, user, async) + end + end + context 'file system' do context 'Sidekiq inline' do before do -- cgit v1.2.1 From 795a63d83fa086a1785cfba3d50cc00f08c70967 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 28 Jul 2017 09:00:09 +0100 Subject: fixed form action not submitting the correct URL --- app/assets/javascripts/main.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index ca126217bda..cd45091c211 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -355,7 +355,12 @@ $(function () { $(document).trigger('init.scrolling-tabs'); $('form.filter-form').on('submit', function (event) { + const link = document.createElement('a'); + link.href = this.action; + + const action = `${this.action}${link.search === '' ? '?' : '&'}`; + event.preventDefault(); - gl.utils.visitUrl(`${this.action}&${$(this).serialize()}`); + gl.utils.visitUrl(`${action}${$(this).serialize()}`); }); }); -- cgit v1.2.1 From 29a8827752b884f5e4cad4ec78cf5b655aa5c769 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 28 Jul 2017 10:56:50 +0200 Subject: Improve deploy environment chatops slash command We now match deployment actions better. If there is more than one deployment action matched, we check if there is an action which name equals to environment name, instead of raising an error about too many actions defined. --- lib/gitlab/slash_commands/deploy.rb | 33 +++++++------ lib/gitlab/slash_commands/presenters/deploy.rb | 11 ++--- spec/lib/gitlab/slash_commands/deploy_spec.rb | 56 +++++++++++++++++----- .../slash_commands/presenters/deploy_spec.rb | 20 ++------ 4 files changed, 69 insertions(+), 51 deletions(-) diff --git a/lib/gitlab/slash_commands/deploy.rb b/lib/gitlab/slash_commands/deploy.rb index e71eb15d604..93e00ab75a1 100644 --- a/lib/gitlab/slash_commands/deploy.rb +++ b/lib/gitlab/slash_commands/deploy.rb @@ -21,29 +21,34 @@ module Gitlab from = match[:from] to = match[:to] - actions = find_actions(from, to) + action = find_action(from, to) - if actions.none? - Gitlab::SlashCommands::Presenters::Deploy.new(nil).no_actions - elsif actions.one? - action = play!(from, to, actions.first) - Gitlab::SlashCommands::Presenters::Deploy.new(action).present(from, to) + if action.nil? + Gitlab::SlashCommands::Presenters::Deploy + .new(action).action_not_found else - Gitlab::SlashCommands::Presenters::Deploy.new(actions).too_many_actions + deployment = action.play(current_user) + + Gitlab::SlashCommands::Presenters::Deploy + .new(deployment).present(from, to) end end private - def play!(from, to, action) - action.play(current_user) - end - - def find_actions(from, to) + def find_action(from, to) environment = project.environments.find_by(name: from) - return [] unless environment + return unless environment - environment.actions_for(to).select(&:starts_environment?) + actions = environment.actions_for(to).select do |action| + action.starts_environment? + end + + if actions.many? + actions.find { |action| action.name == to.to_s } + else + actions.first + end end end end diff --git a/lib/gitlab/slash_commands/presenters/deploy.rb b/lib/gitlab/slash_commands/presenters/deploy.rb index b8dc77bd37b..b72586394bc 100644 --- a/lib/gitlab/slash_commands/presenters/deploy.rb +++ b/lib/gitlab/slash_commands/presenters/deploy.rb @@ -3,17 +3,14 @@ module Gitlab module Presenters class Deploy < Presenters::Base def present(from, to) - message = "Deployment started from #{from} to #{to}. [Follow its progress](#{resource_url})." + message = "Deployment started from #{from} to #{to}. " \ + "[Follow its progress](#{resource_url})." in_channel_response(text: message) end - def no_actions - ephemeral_response(text: "No action found to be executed") - end - - def too_many_actions - ephemeral_response(text: "Too many actions defined") + def action_not_found + ephemeral_response(text: "Couldn't find a deployment action.") end end end diff --git a/spec/lib/gitlab/slash_commands/deploy_spec.rb b/spec/lib/gitlab/slash_commands/deploy_spec.rb index e52aaed7328..17ebd088936 100644 --- a/spec/lib/gitlab/slash_commands/deploy_spec.rb +++ b/spec/lib/gitlab/slash_commands/deploy_spec.rb @@ -22,7 +22,7 @@ describe Gitlab::SlashCommands::Deploy do context 'if no environment is defined' do it 'does not execute an action' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to eq("No action found to be executed") + expect(subject[:text]).to eq "Couldn't find a deployment action." end end @@ -35,12 +35,12 @@ describe Gitlab::SlashCommands::Deploy do context 'without actions' do it 'does not execute an action' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to eq("No action found to be executed") + expect(subject[:text]).to eq "Couldn't find a deployment action." end end - context 'with action' do - let!(:manual1) do + context 'when single action has been matched' do + before do create(:ci_build, :manual, pipeline: pipeline, name: 'first', environment: 'production') @@ -48,31 +48,61 @@ describe Gitlab::SlashCommands::Deploy do it 'returns success result' do expect(subject[:response_type]).to be(:in_channel) - expect(subject[:text]).to start_with('Deployment started from staging to production') + expect(subject[:text]) + .to start_with('Deployment started from staging to production') end + end + + context 'when more than one action has been matched' do + context 'when there is no specific actions with a environment name' do + before do + create(:ci_build, :manual, pipeline: pipeline, + name: 'first', + environment: 'production') - context 'when duplicate action exists' do - let!(:manual2) do create(:ci_build, :manual, pipeline: pipeline, name: 'second', environment: 'production') end - it 'returns error' do + it 'returns error about too many actions defined' do + expect(subject[:text]).to eq("Couldn't find a deployment action.") expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to eq('Too many actions defined') end end - context 'when teardown action exists' do - let!(:teardown) do + context 'when one of the actions is environement specific action' do + before do + create(:ci_build, :manual, pipeline: pipeline, + name: 'first', + environment: 'production') + + create(:ci_build, :manual, pipeline: pipeline, + name: 'production', + environment: 'production') + end + + it 'deploys to production' do + expect(subject[:text]) + .to start_with('Deployment started from staging to production') + expect(subject[:response_type]).to be(:in_channel) + end + end + + context 'when one of the actions is a teardown action' do + before do + create(:ci_build, :manual, pipeline: pipeline, + name: 'first', + environment: 'production') + create(:ci_build, :manual, :teardown_environment, pipeline: pipeline, name: 'teardown', environment: 'production') end - it 'returns the success message' do + it 'deploys to production' do + expect(subject[:text]) + .to start_with('Deployment started from staging to production') expect(subject[:response_type]).to be(:in_channel) - expect(subject[:text]).to start_with('Deployment started from staging to production') end end end diff --git a/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb b/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb index dee3c77db27..eb94578c8e7 100644 --- a/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb +++ b/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb @@ -17,8 +17,8 @@ describe Gitlab::SlashCommands::Presenters::Deploy do end end - describe '#no_actions' do - subject { described_class.new(nil).no_actions } + describe '#action_not_found' do + subject { described_class.new(nil).action_not_found } it { is_expected.to have_key(:text) } it { is_expected.to have_key(:response_type) } @@ -27,21 +27,7 @@ describe Gitlab::SlashCommands::Presenters::Deploy do it 'tells the user there is no action' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to eq("No action found to be executed") - end - end - - describe '#too_many_actions' do - subject { described_class.new([]).too_many_actions } - - it { is_expected.to have_key(:text) } - it { is_expected.to have_key(:response_type) } - it { is_expected.to have_key(:status) } - it { is_expected.not_to have_key(:attachments) } - - it 'tells the user there is no action' do - expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to eq("Too many actions defined") + expect(subject[:text]).to eq "Couldn't find a deployment action." end end end -- cgit v1.2.1 From 8663b63af34f7b79930ad94c39e128c4c28e2a1d Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Fri, 28 Jul 2017 10:57:11 +0200 Subject: Updated Event Handlers based on MR discussion --- app/assets/javascripts/projects/project_new.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js index e3fcf218cfb..2091b275c3d 100644 --- a/app/assets/javascripts/projects/project_new.js +++ b/app/assets/javascripts/projects/project_new.js @@ -2,30 +2,30 @@ document.addEventListener('DOMContentLoaded', () => { const importBtnTooltip = 'Please enter a valid project name.'; const $importBtnWrapper = $('.import_gitlab_project'); - $('.how_to_import_link').bind('click', (e) => { + $('.how_to_import_link').on('click', (e) => { e.preventDefault(); $('.how_to_import_link').next('.modal').show(); }); - $('.modal-header .close').bind('click', () => { + $('.modal-header .close').on('click', () => { $('.modal').hide(); }); - $('.btn_import_gitlab_project').bind('click', () => { + $('.btn_import_gitlab_project').on('click', () => { const importHref = $('a.btn_import_gitlab_project').attr('href'); $('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$('#project_path').val()}`); }); - $('.btn_import_gitlab_project').attr('disabled', $('#project_path').val().trim().length === 0); + $('.btn_import_gitlab_project').attr('disabled', !$('#project_path').val().trim().length); $importBtnWrapper.attr('title', importBtnTooltip); - $('#new_project').submit(() => { + $('#new_project').on('submit', () => { const $path = $('#project_path'); $path.val($path.val().trim()); }); - $('#project_path').keyup(() => { - if ($('#project_path').val().trim().length !== 0) { + $('#project_path').on('keyup', () => { + if ($('#project_path').val().trim().length) { $('.btn_import_gitlab_project').attr('disabled', false); $importBtnWrapper.attr('title', ''); $importBtnWrapper.removeClass('has-tooltip'); @@ -36,7 +36,7 @@ document.addEventListener('DOMContentLoaded', () => { }); $('#project_import_url').disable(); - $('.import_git').click(() => { + $('.import_git').on('click', () => { const $projectImportUrl = $('#project_import_url'); $projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled')); }); -- cgit v1.2.1 From bc75215875b8176aff12c8a0399e211f94aea3ec Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 28 Jul 2017 09:57:30 +0100 Subject: Fixed the breadcrumb title for help pages Closes #35679 --- app/views/layouts/help.html.haml | 1 + changelogs/unreleased/help-page-breadcrumb-title-fix.yml | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 changelogs/unreleased/help-page-breadcrumb-title-fix.yml diff --git a/app/views/layouts/help.html.haml b/app/views/layouts/help.html.haml index 224b24befbe..78927bfffcd 100644 --- a/app/views/layouts/help.html.haml +++ b/app/views/layouts/help.html.haml @@ -1,3 +1,4 @@ +- @breadcrumb_title = "Help" - page_title "Help" - header_title "Help", help_path diff --git a/changelogs/unreleased/help-page-breadcrumb-title-fix.yml b/changelogs/unreleased/help-page-breadcrumb-title-fix.yml new file mode 100644 index 00000000000..040fe4b9916 --- /dev/null +++ b/changelogs/unreleased/help-page-breadcrumb-title-fix.yml @@ -0,0 +1,4 @@ +--- +title: Fixed new navigation breadcrumb title on help pages +merge_request: +author: -- cgit v1.2.1 From 712aa2a81c5764c91ca2d2d3d877c975beed6121 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 28 Jul 2017 11:02:10 +0200 Subject: Add changelog entry for deploy chatops command fix --- .../fix-gb-fix-chatops-deploy-multiple-actions-matching.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/fix-gb-fix-chatops-deploy-multiple-actions-matching.yml diff --git a/changelogs/unreleased/fix-gb-fix-chatops-deploy-multiple-actions-matching.yml b/changelogs/unreleased/fix-gb-fix-chatops-deploy-multiple-actions-matching.yml new file mode 100644 index 00000000000..62488a0a2e3 --- /dev/null +++ b/changelogs/unreleased/fix-gb-fix-chatops-deploy-multiple-actions-matching.yml @@ -0,0 +1,4 @@ +--- +title: Improve deploy environment chatops slash command +merge_request: 13150 +author: -- cgit v1.2.1 From 08a241d606633fa2b2c7c32c84b3d846dece035b Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Fri, 28 Jul 2017 11:07:57 +0200 Subject: Moved the duplicate Available Refs to a default in RefSelectDropdown --- app/assets/javascripts/dispatcher.js | 4 ++-- app/assets/javascripts/ref_select_dropdown.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index bb15b14bb98..29dcd460e93 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -251,7 +251,7 @@ import PerformanceBar from './performance_bar'; case 'projects:tags:new': new ZenMode(); new gl.GLForm($('.tag-form'), true); - new RefSelectDropdown($('.js-branch-select'), JSON.parse(document.getElementById('availableRefs').innerHTML)); + new RefSelectDropdown($('.js-branch-select')); break; case 'projects:snippets:new': case 'projects:snippets:edit': @@ -318,7 +318,7 @@ import PerformanceBar from './performance_bar'; setupProjectEdit(); break; case 'projects:pipelines:new': - new NewBranchForm($('.js-new-pipeline-form'), JSON.parse(document.getElementById('availableRefs').innerHTML)); + new NewBranchForm($('.js-new-pipeline-form')); break; case 'projects:pipelines:builds': case 'projects:pipelines:failures': diff --git a/app/assets/javascripts/ref_select_dropdown.js b/app/assets/javascripts/ref_select_dropdown.js index 215cd6fbdfd..65e4101352c 100644 --- a/app/assets/javascripts/ref_select_dropdown.js +++ b/app/assets/javascripts/ref_select_dropdown.js @@ -1,7 +1,8 @@ class RefSelectDropdown { constructor($dropdownButton, availableRefs) { + const availableRefsValue = availableRefs || JSON.parse(document.getElementById('availableRefs').innerHTML); $dropdownButton.glDropdown({ - data: availableRefs, + data: availableRefsValue, filterable: true, filterByText: true, remote: false, -- cgit v1.2.1 From e2f73c8685cc73066553adc25013b4125cccc849 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 28 Jul 2017 11:09:12 +0200 Subject: Update docs regarding deploy chatops slash command --- doc/integration/slash_commands.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/doc/integration/slash_commands.md b/doc/integration/slash_commands.md index 5d880ba785c..288ad1f7f5e 100644 --- a/doc/integration/slash_commands.md +++ b/doc/integration/slash_commands.md @@ -2,7 +2,11 @@ Slash commands in Mattermost and Slack allow you to control GitLab and view GitLab content right inside your chat client, without having to leave it. For Slack, this requires a [project service configuration](../user/project/integrations/slack_slash_commands.md). Simply type the command as a message in your chat client to activate it. -Commands are scoped to a project, with a trigger term that is specified during configuration. (We suggest you use the project name as the trigger term for simplicty and clarity.) Taking the trigger term as `project-name`, the commands are: +Commands are scoped to a project, with a trigger term that is specified during configuration. + +We suggest you use the project name as the trigger term for simplicity and clarity. + +Taking the trigger term as `project-name`, the commands are: | Command | Effect | @@ -12,3 +16,18 @@ Commands are scoped to a project, with a trigger term that is specified during c | `/project-name issue show ` | Shows the issue with id `` | | `/project-name issue search ` | Shows up to 5 issues matching `` | | `/project-name deploy to ` | Deploy from the `` environment to the `` environment | + +## Issue commands + +It is possible to create new issue, display issue details and search up to 5 issues. + +## Deploy command + +In order to deploy to an environment, GitLab will try to find a deployment +action in the pipeline. + +If there is only one action for a given environment, it is going to be triggered. +If there is more than one action defined, GitLab will try to find an action +which name equals the environment name we want to deploy to. + +Command will return an error when no matching action has been found. -- cgit v1.2.1 From 56418e85ac6b667d19495665860092ce4d74f55d Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 26 Jul 2017 18:31:09 +0900 Subject: init --- app/models/ci/build.rb | 1 + app/models/ci/pipeline.rb | 3 +- app/models/ci/pipeline_variable.rb | 10 +++ app/services/ci/create_pipeline_service.rb | 18 +++-- app/services/ci/create_trigger_request_service.rb | 5 ++ app/services/ci/pipeline_trigger_service.rb | 44 ++++++++++++ .../20170720130522_create_ci_pipeline_variables.rb | 20 ++++++ ...749_add_foreign_key_to_ci_pipeline_variables.rb | 15 ++++ db/schema.rb | 12 ++++ lib/api/triggers.rb | 23 +++---- spec/factories/ci/pipeline_variable_variables.rb | 8 +++ spec/lib/gitlab/import_export/all_models.yml | 3 + spec/models/ci/build_spec.rb | 6 ++ spec/models/ci/pipeline_spec.rb | 5 +- spec/models/ci/pipeline_variable_spec.rb | 8 +++ spec/requests/api/triggers_spec.rb | 19 +++--- spec/services/ci/pipeline_trigger_service_spec.rb | 79 ++++++++++++++++++++++ 17 files changed, 247 insertions(+), 32 deletions(-) create mode 100644 app/models/ci/pipeline_variable.rb create mode 100644 app/services/ci/pipeline_trigger_service.rb create mode 100644 db/migrate/20170720130522_create_ci_pipeline_variables.rb create mode 100644 db/migrate/20170720130749_add_foreign_key_to_ci_pipeline_variables.rb create mode 100644 spec/factories/ci/pipeline_variable_variables.rb create mode 100644 spec/models/ci/pipeline_variable_spec.rb create mode 100644 spec/services/ci/pipeline_trigger_service_spec.rb diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 416a2a33378..d9029e5fbca 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -219,6 +219,7 @@ module Ci variables += project.group.secret_variables_for(ref, project).map(&:to_runner_variable) if project.group variables += secret_variables(environment: environment) variables += trigger_request.user_variables if trigger_request + variables += pipeline.variables.map(&:to_runner_variable) if pipeline.variables variables += pipeline.pipeline_schedule.job_variables if pipeline.pipeline_schedule variables += persisted_environment_variables if environment diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index e5b615a7cc0..148ff6d025a 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -15,13 +15,14 @@ module Ci has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id has_many :builds, foreign_key: :commit_id has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent + has_many :variables, class_name: 'Ci::PipelineVariable' # Merge requests for which the current pipeline is running against # the merge request's latest commit. has_many :merge_requests, foreign_key: "head_pipeline_id" has_many :pending_builds, -> { pending }, foreign_key: :commit_id, class_name: 'Ci::Build' - has_many :retryable_builds, -> { latest.failed_or_canceled.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build' + has_many :retryable_builds, -> { latest.failed_or_canceled }, foreign_key: :commit_id, class_name: 'Ci::Build' has_many :cancelable_statuses, -> { cancelable }, foreign_key: :commit_id, class_name: 'CommitStatus' has_many :manual_actions, -> { latest.manual_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build' has_many :artifacts, -> { latest.with_artifacts_not_expired.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build' diff --git a/app/models/ci/pipeline_variable.rb b/app/models/ci/pipeline_variable.rb new file mode 100644 index 00000000000..00b419c3efa --- /dev/null +++ b/app/models/ci/pipeline_variable.rb @@ -0,0 +1,10 @@ +module Ci + class PipelineVariable < ActiveRecord::Base + extend Ci::Model + include HasVariable + + belongs_to :pipeline + + validates :key, uniqueness: { scope: :pipeline_id } + end +end diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 21e2ef153de..884b681ff81 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -21,14 +21,22 @@ module Ci return result if result - Ci::Pipeline.transaction do - update_merge_requests_head_pipeline if pipeline.save + begin + Ci::Pipeline.transaction do + pipeline.save! - Ci::CreatePipelineStagesService - .new(project, current_user) - .execute(pipeline) + yield(pipeline) if block_given? + + Ci::CreatePipelineStagesService + .new(project, current_user) + .execute(pipeline) + end + rescue ActiveRecord::RecordInvalid => e + return error("Failed to persist the pipeline: #{e}") end + update_merge_requests_head_pipeline + cancel_pending_pipelines if project.auto_cancel_pending_pipelines? pipeline_created_counter.increment(source: source) diff --git a/app/services/ci/create_trigger_request_service.rb b/app/services/ci/create_trigger_request_service.rb index a43d0e4593c..b2aa457bbd5 100644 --- a/app/services/ci/create_trigger_request_service.rb +++ b/app/services/ci/create_trigger_request_service.rb @@ -1,3 +1,8 @@ +# This class is deprecated because we're closing Ci::TriggerRequest. +# New class is PipelineTriggerService (app/services/ci/pipeline_trigger_service.rb) +# which is integrated with Ci::PipelineVariable instaed of Ci::TriggerRequest. +# We remove this class after we removed v1 and v3 API. This class is still being +# referred by such legacy code. module Ci module CreateTriggerRequestService Result = Struct.new(:trigger_request, :pipeline) diff --git a/app/services/ci/pipeline_trigger_service.rb b/app/services/ci/pipeline_trigger_service.rb new file mode 100644 index 00000000000..af680d2f953 --- /dev/null +++ b/app/services/ci/pipeline_trigger_service.rb @@ -0,0 +1,44 @@ +module Ci + class PipelineTriggerService < BaseService + def execute + if trigger_from_token + create_pipeline_from_trigger(trigger_from_token) + end + end + + private + + def create_pipeline_from_trigger(trigger) + # this check is to not leak the presence of the project if user cannot read it + return unless trigger.project == project + + pipeline = Ci::CreatePipelineService.new(project, trigger.owner, ref: params[:ref]) + .execute(:trigger, ignore_skip_ci: true) do |pipeline| + trigger.trigger_requests.create(pipeline: pipeline) + create_pipeline_variables!(pipeline) + end + + if pipeline.persisted? + success(pipeline: pipeline) + else + error(pipeline.errors.messages, 400) + end + end + + def trigger_from_token + return @trigger if defined?(@trigger) + + @trigger = Ci::Trigger.find_by_token(params[:token].to_s) + end + + def create_pipeline_variables!(pipeline) + return unless params[:variables].is_a?(Hash) + + variables = params[:variables].map do |key, value| + { key: key, value: value } + end + + pipeline.variables.create!(variables) + end + end +end diff --git a/db/migrate/20170720130522_create_ci_pipeline_variables.rb b/db/migrate/20170720130522_create_ci_pipeline_variables.rb new file mode 100644 index 00000000000..a784f5dd142 --- /dev/null +++ b/db/migrate/20170720130522_create_ci_pipeline_variables.rb @@ -0,0 +1,20 @@ +class CreateCiPipelineVariables < ActiveRecord::Migration + DOWNTIME = false + + def up + create_table :ci_pipeline_variables do |t| + t.string :key, null: false + t.text :value + t.text :encrypted_value + t.string :encrypted_value_salt + t.string :encrypted_value_iv + t.integer :pipeline_id, null: false + end + + add_index :ci_pipeline_variables, [:pipeline_id, :key], unique: true + end + + def down + drop_table :ci_pipeline_variables + end +end diff --git a/db/migrate/20170720130749_add_foreign_key_to_ci_pipeline_variables.rb b/db/migrate/20170720130749_add_foreign_key_to_ci_pipeline_variables.rb new file mode 100644 index 00000000000..550b8a88f02 --- /dev/null +++ b/db/migrate/20170720130749_add_foreign_key_to_ci_pipeline_variables.rb @@ -0,0 +1,15 @@ +class AddForeignKeyToCiPipelineVariables < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_foreign_key(:ci_pipeline_variables, :ci_pipelines, column: :pipeline_id) + end + + def down + remove_foreign_key(:ci_pipeline_variables, column: :pipeline_id) + end +end diff --git a/db/schema.rb b/db/schema.rb index 93ab79e14e0..0abdb987b77 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -298,6 +298,17 @@ ActiveRecord::Schema.define(version: 20170725145659) do add_index "ci_pipeline_schedules", ["next_run_at", "active"], name: "index_ci_pipeline_schedules_on_next_run_at_and_active", using: :btree add_index "ci_pipeline_schedules", ["project_id"], name: "index_ci_pipeline_schedules_on_project_id", using: :btree + create_table "ci_pipeline_variables", force: :cascade do |t| + t.string "key", null: false + t.text "value" + t.text "encrypted_value" + t.string "encrypted_value_salt" + t.string "encrypted_value_iv" + t.integer "pipeline_id", null: false + end + + add_index "ci_pipeline_variables", ["pipeline_id", "key"], name: "index_ci_pipeline_variables_on_pipeline_id_and_key", unique: true, using: :btree + create_table "ci_pipelines", force: :cascade do |t| t.string "ref" t.string "sha" @@ -1617,6 +1628,7 @@ ActiveRecord::Schema.define(version: 20170725145659) do add_foreign_key "ci_group_variables", "namespaces", column: "group_id", name: "fk_33ae4d58d8", on_delete: :cascade add_foreign_key "ci_pipeline_schedules", "projects", name: "fk_8ead60fcc4", on_delete: :cascade add_foreign_key "ci_pipeline_schedules", "users", column: "owner_id", name: "fk_9ea99f58d2", on_delete: :nullify + add_foreign_key "ci_pipeline_variables", "ci_pipelines", column: "pipeline_id", name: "fk_f29c5f4380", on_delete: :cascade add_foreign_key "ci_pipelines", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_3d34ab2e06", on_delete: :nullify add_foreign_key "ci_pipelines", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_262d4c2d19", on_delete: :nullify add_foreign_key "ci_pipelines", "projects", name: "fk_86635dbd80", on_delete: :cascade diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb index 9375e7eb768..edfdb63d183 100644 --- a/lib/api/triggers.rb +++ b/lib/api/triggers.rb @@ -15,25 +15,22 @@ module API optional :variables, type: Hash, desc: 'The list of variables to be injected into build' end post ":id/(ref/:ref/)trigger/pipeline", requirements: { ref: /.+/ } do - project = find_project(params[:id]) - trigger = Ci::Trigger.find_by_token(params[:token].to_s) - not_found! unless project && trigger - unauthorized! unless trigger.project == project - # validate variables - variables = params[:variables].to_h - unless variables.all? { |key, value| key.is_a?(String) && value.is_a?(String) } + params[:variables] = params[:variables].to_h + unless params[:variables].all? { |key, value| key.is_a?(String) && value.is_a?(String) } render_api_error!('variables needs to be a map of key-valued strings', 400) end - # create request and trigger builds - result = Ci::CreateTriggerRequestService.execute(project, trigger, params[:ref].to_s, variables) - pipeline = result.pipeline + project = find_project(params[:id]) + not_found! unless project + + result = Ci::PipelineTriggerService.new(project, nil, params).execute + not_found! unless result - if pipeline.persisted? - present pipeline, with: Entities::Pipeline + if result[:http_status] + render_api_error!(result[:message], result[:http_status]) else - render_validation_error!(pipeline) + present result[:pipeline], with: Entities::Pipeline end end diff --git a/spec/factories/ci/pipeline_variable_variables.rb b/spec/factories/ci/pipeline_variable_variables.rb new file mode 100644 index 00000000000..7c1a7faec08 --- /dev/null +++ b/spec/factories/ci/pipeline_variable_variables.rb @@ -0,0 +1,8 @@ +FactoryGirl.define do + factory :ci_pipeline_variable, class: Ci::PipelineVariable do + sequence(:key) { |n| "VARIABLE_#{n}" } + value 'VARIABLE_VALUE' + + pipeline factory: :ci_empty_pipeline + end +end diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 977174a5fd2..6a41afe0c25 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -102,6 +102,7 @@ pipelines: - statuses - builds - trigger_requests +- variables - auto_canceled_by - auto_canceled_pipelines - auto_canceled_jobs @@ -112,6 +113,8 @@ pipelines: - artifacts - pipeline_schedule - merge_requests +pipeline_variables: +- pipeline stages: - project - pipeline diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index a18da3768d5..86afa856ea7 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1468,6 +1468,12 @@ describe Ci::Build do it { is_expected.to include(predefined_trigger_variable) } end + context 'when pipeline has a variable' do + let!(:pipeline_variable) { create(:ci_pipeline_variable, pipeline: pipeline) } + + it { is_expected.to include(pipeline_variable.to_runner_variable) } + end + context 'when a job was triggered by a pipeline schedule' do let(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project) } diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 9461905c787..406608256e0 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -17,6 +17,7 @@ describe Ci::Pipeline do it { is_expected.to have_many(:statuses) } it { is_expected.to have_many(:trigger_requests) } + it { is_expected.to have_many(:variables) } it { is_expected.to have_many(:builds) } it { is_expected.to have_many(:auto_canceled_pipelines) } it { is_expected.to have_many(:auto_canceled_jobs) } @@ -734,8 +735,6 @@ describe Ci::Pipeline do context 'on failure and build retry' do before do - stub_not_protect_default_branch - build.drop project.add_developer(user) @@ -1001,8 +1000,6 @@ describe Ci::Pipeline do let(:latest_status) { pipeline.statuses.latest.pluck(:status) } before do - stub_not_protect_default_branch - project.add_developer(user) end diff --git a/spec/models/ci/pipeline_variable_spec.rb b/spec/models/ci/pipeline_variable_spec.rb new file mode 100644 index 00000000000..2ce78e34b0c --- /dev/null +++ b/spec/models/ci/pipeline_variable_spec.rb @@ -0,0 +1,8 @@ +require 'spec_helper' + +describe Ci::PipelineVariable, models: true do + subject { build(:ci_pipeline_variable) } + + it { is_expected.to include_module(HasVariable) } + it { is_expected.to validate_uniqueness_of(:key).scoped_to(:pipeline_id) } +end diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index c2636b6614e..0b42a603885 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -22,6 +22,7 @@ describe API::Triggers do before do stub_ci_pipeline_to_return_yaml_file + trigger.update(owner: user) end context 'Handles errors' do @@ -36,12 +37,6 @@ describe API::Triggers do expect(response).to have_http_status(404) end - - it 'returns unauthorized if token is for different project' do - post api("/projects/#{project2.id}/trigger/pipeline"), options.merge(ref: 'master') - - expect(response).to have_http_status(401) - end end context 'Have a commit' do @@ -61,8 +56,7 @@ describe API::Triggers do post api("/projects/#{project.id}/trigger/pipeline"), options.merge(ref: 'other-branch') expect(response).to have_http_status(400) - expect(json_response['message']['base']) - .to contain_exactly('Reference not found') + expect(json_response['message']).to eq('base' => ["Reference not found"]) end context 'Validates variables' do @@ -88,12 +82,19 @@ describe API::Triggers do post api("/projects/#{project.id}/trigger/pipeline"), options.merge(variables: variables, ref: 'master') expect(response).to have_http_status(201) - expect(pipeline.builds.reload.first.trigger_request.variables).to eq(variables) + expect(Ci::Pipeline.last.variables.first.key).to eq(variables.keys.first) + expect(Ci::Pipeline.last.variables.first.value).to eq(variables.values.first) end end end context 'when triggering a pipeline from a trigger token' do + it 'does not leak the presence of project when token is for different project' do + post api("/projects/#{project2.id}/ref/master/trigger/pipeline?token=#{trigger_token}"), { ref: 'refs/heads/other-branch' } + + expect(response).to have_http_status(404) + end + it 'creates builds from the ref given in the URL, not in the body' do expect do post api("/projects/#{project.id}/ref/master/trigger/pipeline?token=#{trigger_token}"), { ref: 'refs/heads/other-branch' } diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb new file mode 100644 index 00000000000..914ec4844d0 --- /dev/null +++ b/spec/services/ci/pipeline_trigger_service_spec.rb @@ -0,0 +1,79 @@ +require 'spec_helper' + +describe Ci::PipelineTriggerService, services: true do + let(:project) { create(:project, :repository) } + + before do + stub_ci_pipeline_to_return_yaml_file + end + + describe '#execute' do + let(:user) { create(:user) } + + before do + project.add_developer(user) + end + + let(:result) { described_class.new(project, user, params).execute } + let(:trigger) { create(:ci_trigger, project: project, owner: user) } + + context 'when params have an existsed trigger token' do + let(:token) { trigger.token } + + context 'when params have an existsed ref' do + let(:ref) { 'master' } + + it 'triggers a pipeline' do + expect { result }.to change { Ci::Pipeline.count }.by(1) + expect(result[:pipeline].ref).to eq(ref) + expect(result[:pipeline].project).to eq(project) + expect(result[:pipeline].user).to eq(trigger.owner) + expect(result[:status]).to eq(:success) + end + + context 'when params have a variable' do + let(:variables) { { 'AAA' => 'AAA123' } } + + it 'has a variable' do + expect { result }.to change { Ci::PipelineVariable.count }.by(1) + expect(result[:pipeline].variables.first.key).to eq(variables.keys.first) + expect(result[:pipeline].variables.first.value).to eq(variables.values.first) + end + end + + context 'when params have two variables and keys are duplicated' do + let(:variables) { [{ key: 'AAA', value: 'AAA123' }, { key: 'AAA', value: 'BBB123' }] } + + it 'returns error' do + expect { result }.not_to change { Ci::Pipeline.count } + expect(result[:http_status]).to eq(400) + end + end + end + + context 'when params have a non-existsed ref' do + let(:ref) { 'invalid-ref' } + + it 'does not trigger a pipeline' do + expect { result }.not_to change { Ci::Pipeline.count } + expect(result[:http_status]).to eq(400) + end + end + end + + context 'when params have a non-existsed trigger token' do + let(:token) { 'invalid-token' } + + it 'does not trigger a pipeline' do + expect { result }.not_to change { Ci::Pipeline.count } + expect(result).to be_nil + end + end + end + + def params + { token: defined?(token) ? token : nil, + ref: defined?(ref) ? ref : nil, + variables: defined?(variables) ? variables : nil } + end +end -- cgit v1.2.1 From 1ad4efe64e1f51e17f9e03e01cb85908de139f93 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 26 Jul 2017 18:44:49 +0900 Subject: fix merge miss --- app/models/ci/pipeline.rb | 2 +- spec/models/ci/pipeline_spec.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 148ff6d025a..d2abcf30034 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -22,7 +22,7 @@ module Ci has_many :merge_requests, foreign_key: "head_pipeline_id" has_many :pending_builds, -> { pending }, foreign_key: :commit_id, class_name: 'Ci::Build' - has_many :retryable_builds, -> { latest.failed_or_canceled }, foreign_key: :commit_id, class_name: 'Ci::Build' + has_many :retryable_builds, -> { latest.failed_or_canceled.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build' has_many :cancelable_statuses, -> { cancelable }, foreign_key: :commit_id, class_name: 'CommitStatus' has_many :manual_actions, -> { latest.manual_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build' has_many :artifacts, -> { latest.with_artifacts_not_expired.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build' diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 406608256e0..b0efa689a07 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -735,6 +735,8 @@ describe Ci::Pipeline do context 'on failure and build retry' do before do + stub_not_protect_default_branch + build.drop project.add_developer(user) @@ -1000,6 +1002,8 @@ describe Ci::Pipeline do let(:latest_status) { pipeline.statuses.latest.pluck(:status) } before do + stub_not_protect_default_branch + project.add_developer(user) end -- cgit v1.2.1 From 19789154d3b900febdf8cff9991d3806e84065f4 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 26 Jul 2017 22:58:31 +0900 Subject: Move validate to begin/rescue block --- app/services/ci/create_pipeline_service.rb | 33 +++++++++++++++++------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 884b681ff81..9c6035601fd 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -1,5 +1,7 @@ module Ci class CreatePipelineService < BaseService + class ParameterValidationError < StandardError end + attr_reader :pipeline def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil) @@ -15,13 +17,11 @@ module Ci pipeline_schedule: schedule ) - result = validate(current_user || trigger_request.trigger.owner, - ignore_skip_ci: ignore_skip_ci, - save_on_errors: save_on_errors) - - return result if result - begin + validate(current_user || trigger_request.trigger.owner, + ignore_skip_ci: ignore_skip_ci, + save_on_errors: save_on_errors) + Ci::Pipeline.transaction do pipeline.save! @@ -31,8 +31,13 @@ module Ci .new(project, current_user) .execute(pipeline) end + + rescue ParameterValidationError => e + return e + rescue ActiveRecord::RecordInvalid => e return error("Failed to persist the pipeline: #{e}") + end update_merge_requests_head_pipeline @@ -48,30 +53,30 @@ module Ci def validate(triggering_user, ignore_skip_ci:, save_on_errors:) unless project.builds_enabled? - return error('Pipeline is disabled') + raise ParameterValidationError, error('Pipeline is disabled') end unless allowed_to_trigger_pipeline?(triggering_user) if can?(triggering_user, :create_pipeline, project) - return error("Insufficient permissions for protected ref '#{ref}'") + raise ParameterValidationError, error("Insufficient permissions for protected ref '#{ref}'") else - return error('Insufficient permissions to create a new pipeline') + raise ParameterValidationError, error('Insufficient permissions to create a new pipeline') end end unless branch? || tag? - return error('Reference not found') + raise ParameterValidationError, error('Reference not found') end unless commit - return error('Commit not found') + raise ParameterValidationError, error('Commit not found') end unless pipeline.config_processor unless pipeline.ci_yaml_file - return error("Missing #{pipeline.ci_yaml_file_path} file") + raise ParameterValidationError, error("Missing #{pipeline.ci_yaml_file_path} file") end - return error(pipeline.yaml_errors, save: save_on_errors) + raise ParameterValidationError, error(pipeline.yaml_errors, save: save_on_errors) end if !ignore_skip_ci && skip_ci? @@ -80,7 +85,7 @@ module Ci end unless pipeline.has_stage_seeds? - return error('No stages / jobs for this pipeline.') + raise ParameterValidationError, error('No stages / jobs for this pipeline.') end end -- cgit v1.2.1 From 48389e9944d7914ca2027df379a523b493ca4245 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Jul 2017 15:52:55 +0900 Subject: Fix pipeline --- app/services/ci/create_pipeline_service.rb | 30 ++++++++++++++--------- spec/services/ci/pipeline_trigger_service_spec.rb | 9 ------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 9c6035601fd..4c16d42f8bd 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -1,6 +1,12 @@ module Ci class CreatePipelineService < BaseService - class ParameterValidationError < StandardError end + class InsufficientConditionError < StandardError + attr_reader :pipeline + + def initialize(pipeline) + @pipeline = pipeline + end + end attr_reader :pipeline @@ -32,8 +38,8 @@ module Ci .execute(pipeline) end - rescue ParameterValidationError => e - return e + rescue InsufficientConditionError => e + return e.pipeline rescue ActiveRecord::RecordInvalid => e return error("Failed to persist the pipeline: #{e}") @@ -53,39 +59,39 @@ module Ci def validate(triggering_user, ignore_skip_ci:, save_on_errors:) unless project.builds_enabled? - raise ParameterValidationError, error('Pipeline is disabled') + raise InsufficientConditionError, error('Pipeline is disabled') end unless allowed_to_trigger_pipeline?(triggering_user) if can?(triggering_user, :create_pipeline, project) - raise ParameterValidationError, error("Insufficient permissions for protected ref '#{ref}'") + raise InsufficientConditionError, error("Insufficient permissions for protected ref '#{ref}'") else - raise ParameterValidationError, error('Insufficient permissions to create a new pipeline') + raise InsufficientConditionError, error('Insufficient permissions to create a new pipeline') end end unless branch? || tag? - raise ParameterValidationError, error('Reference not found') + raise InsufficientConditionError, error('Reference not found') end unless commit - raise ParameterValidationError, error('Commit not found') + raise InsufficientConditionError, error('Commit not found') end unless pipeline.config_processor unless pipeline.ci_yaml_file - raise ParameterValidationError, error("Missing #{pipeline.ci_yaml_file_path} file") + raise InsufficientConditionError, error("Missing #{pipeline.ci_yaml_file_path} file") end - raise ParameterValidationError, error(pipeline.yaml_errors, save: save_on_errors) + raise InsufficientConditionError, error(pipeline.yaml_errors, save: save_on_errors) end if !ignore_skip_ci && skip_ci? pipeline.skip if save_on_errors - return pipeline + raise InsufficientConditionError, pipeline end unless pipeline.has_stage_seeds? - raise ParameterValidationError, error('No stages / jobs for this pipeline.') + raise InsufficientConditionError, error('No stages / jobs for this pipeline.') end end diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb index 914ec4844d0..af1c9f9f10a 100644 --- a/spec/services/ci/pipeline_trigger_service_spec.rb +++ b/spec/services/ci/pipeline_trigger_service_spec.rb @@ -40,15 +40,6 @@ describe Ci::PipelineTriggerService, services: true do expect(result[:pipeline].variables.first.value).to eq(variables.values.first) end end - - context 'when params have two variables and keys are duplicated' do - let(:variables) { [{ key: 'AAA', value: 'AAA123' }, { key: 'AAA', value: 'BBB123' }] } - - it 'returns error' do - expect { result }.not_to change { Ci::Pipeline.count } - expect(result[:http_status]).to eq(400) - end - end end context 'when params have a non-existsed ref' do -- cgit v1.2.1 From b3b8b595a1a7762c5090c92b3247d82d686bbeff Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Jul 2017 22:41:21 +0900 Subject: Remove if pipeline.variables in Ci::Build#variables --- app/models/ci/build.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index d9029e5fbca..8be2dee6479 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -219,7 +219,7 @@ module Ci variables += project.group.secret_variables_for(ref, project).map(&:to_runner_variable) if project.group variables += secret_variables(environment: environment) variables += trigger_request.user_variables if trigger_request - variables += pipeline.variables.map(&:to_runner_variable) if pipeline.variables + variables += pipeline.variables.map(&:to_runner_variable) variables += pipeline.pipeline_schedule.job_variables if pipeline.pipeline_schedule variables += persisted_environment_variables if environment -- cgit v1.2.1 From 445f213527789b5500913fdf8ff5f34f9a1b6677 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Jul 2017 22:44:53 +0900 Subject: Use bang for trigger.trigger_requests.create --- app/services/ci/pipeline_trigger_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/ci/pipeline_trigger_service.rb b/app/services/ci/pipeline_trigger_service.rb index af680d2f953..70d56718cdd 100644 --- a/app/services/ci/pipeline_trigger_service.rb +++ b/app/services/ci/pipeline_trigger_service.rb @@ -14,7 +14,7 @@ module Ci pipeline = Ci::CreatePipelineService.new(project, trigger.owner, ref: params[:ref]) .execute(:trigger, ignore_skip_ci: true) do |pipeline| - trigger.trigger_requests.create(pipeline: pipeline) + trigger.trigger_requests.create!(pipeline: pipeline) create_pipeline_variables!(pipeline) end -- cgit v1.2.1 From a2a7fc1f9ecb61eb1f2e11b21795f64b8161ec7e Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Jul 2017 22:47:18 +0900 Subject: Remove is_a?(Hash) from unless params[:variables] in create_pipeline_variables --- app/services/ci/pipeline_trigger_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/ci/pipeline_trigger_service.rb b/app/services/ci/pipeline_trigger_service.rb index 70d56718cdd..1e5ad28ba57 100644 --- a/app/services/ci/pipeline_trigger_service.rb +++ b/app/services/ci/pipeline_trigger_service.rb @@ -32,7 +32,7 @@ module Ci end def create_pipeline_variables!(pipeline) - return unless params[:variables].is_a?(Hash) + return unless params[:variables] variables = params[:variables].map do |key, value| { key: key, value: value } -- cgit v1.2.1 From 34d2b8e702da63ea6d79cbfe498a5bfcb3938e11 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 27 Jul 2017 23:09:30 +0900 Subject: Use let(:pipeline) for variables spec in triggers_spec.rb --- spec/requests/api/triggers_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index 0b42a603885..91507bf0e23 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -82,8 +82,7 @@ describe API::Triggers do post api("/projects/#{project.id}/trigger/pipeline"), options.merge(variables: variables, ref: 'master') expect(response).to have_http_status(201) - expect(Ci::Pipeline.last.variables.first.key).to eq(variables.keys.first) - expect(Ci::Pipeline.last.variables.first.value).to eq(variables.values.first) + expect(pipeline.variables.map { |v| {v.key => v.value} }.last).to eq(variables) end end end -- cgit v1.2.1 From b59abf5b4495f00767c574c46e0cfed569204a85 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 28 Jul 2017 00:31:24 +0900 Subject: Use let(:params) instead of def param --- spec/services/ci/pipeline_trigger_service_spec.rb | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb index af1c9f9f10a..9e60d04738c 100644 --- a/spec/services/ci/pipeline_trigger_service_spec.rb +++ b/spec/services/ci/pipeline_trigger_service_spec.rb @@ -9,19 +9,23 @@ describe Ci::PipelineTriggerService, services: true do describe '#execute' do let(:user) { create(:user) } + let(:trigger) { create(:ci_trigger, project: project, owner: user) } + let(:result) { described_class.new(project, user, params).execute } + + let(:params) do + { token: token, ref: ref, variables: variables } + end before do project.add_developer(user) end - let(:result) { described_class.new(project, user, params).execute } - let(:trigger) { create(:ci_trigger, project: project, owner: user) } - context 'when params have an existsed trigger token' do let(:token) { trigger.token } context 'when params have an existsed ref' do let(:ref) { 'master' } + let(:variables) {} it 'triggers a pipeline' do expect { result }.to change { Ci::Pipeline.count }.by(1) @@ -44,6 +48,7 @@ describe Ci::PipelineTriggerService, services: true do context 'when params have a non-existsed ref' do let(:ref) { 'invalid-ref' } + let(:variables) {} it 'does not trigger a pipeline' do expect { result }.not_to change { Ci::Pipeline.count } @@ -54,6 +59,8 @@ describe Ci::PipelineTriggerService, services: true do context 'when params have a non-existsed trigger token' do let(:token) { 'invalid-token' } + let(:ref) {} + let(:variables) {} it 'does not trigger a pipeline' do expect { result }.not_to change { Ci::Pipeline.count } @@ -61,10 +68,4 @@ describe Ci::PipelineTriggerService, services: true do end end end - - def params - { token: defined?(token) ? token : nil, - ref: defined?(ref) ? ref : nil, - variables: defined?(variables) ? variables : nil } - end end -- cgit v1.2.1 From 8c4c310d86d2481c6bb94b62a64ec56acd7e4735 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 28 Jul 2017 00:33:41 +0900 Subject: Revert "Move validate to begin/rescue block" This reverts commit 5ec3b63bfc6f341df040ae08be4858c7181bcacf. --- app/services/ci/create_pipeline_service.rb | 39 +++++++++++------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 4c16d42f8bd..780331d0b4e 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -1,13 +1,5 @@ module Ci class CreatePipelineService < BaseService - class InsufficientConditionError < StandardError - attr_reader :pipeline - - def initialize(pipeline) - @pipeline = pipeline - end - end - attr_reader :pipeline def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil) @@ -23,11 +15,13 @@ module Ci pipeline_schedule: schedule ) - begin - validate(current_user || trigger_request.trigger.owner, - ignore_skip_ci: ignore_skip_ci, - save_on_errors: save_on_errors) + result = validate(current_user || trigger_request.trigger.owner, + ignore_skip_ci: ignore_skip_ci, + save_on_errors: save_on_errors) + return result if result + + begin Ci::Pipeline.transaction do pipeline.save! @@ -37,13 +31,8 @@ module Ci .new(project, current_user) .execute(pipeline) end - - rescue InsufficientConditionError => e - return e.pipeline - rescue ActiveRecord::RecordInvalid => e return error("Failed to persist the pipeline: #{e}") - end update_merge_requests_head_pipeline @@ -59,30 +48,30 @@ module Ci def validate(triggering_user, ignore_skip_ci:, save_on_errors:) unless project.builds_enabled? - raise InsufficientConditionError, error('Pipeline is disabled') + return error('Pipeline is disabled') end unless allowed_to_trigger_pipeline?(triggering_user) if can?(triggering_user, :create_pipeline, project) - raise InsufficientConditionError, error("Insufficient permissions for protected ref '#{ref}'") + return error("Insufficient permissions for protected ref '#{ref}'") else - raise InsufficientConditionError, error('Insufficient permissions to create a new pipeline') + return error('Insufficient permissions to create a new pipeline') end end unless branch? || tag? - raise InsufficientConditionError, error('Reference not found') + return error('Reference not found') end unless commit - raise InsufficientConditionError, error('Commit not found') + return error('Commit not found') end unless pipeline.config_processor unless pipeline.ci_yaml_file - raise InsufficientConditionError, error("Missing #{pipeline.ci_yaml_file_path} file") + return error("Missing #{pipeline.ci_yaml_file_path} file") end - raise InsufficientConditionError, error(pipeline.yaml_errors, save: save_on_errors) + return error(pipeline.yaml_errors, save: save_on_errors) end if !ignore_skip_ci && skip_ci? @@ -91,7 +80,7 @@ module Ci end unless pipeline.has_stage_seeds? - raise InsufficientConditionError, error('No stages / jobs for this pipeline.') + return error('No stages / jobs for this pipeline.') end end -- cgit v1.2.1 From 276c44bf273a4517eaa1a8a7b8d2f6d96bda0929 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 28 Jul 2017 00:38:26 +0900 Subject: Fix static snalysys --- spec/requests/api/triggers_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index 91507bf0e23..153596c2975 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -82,7 +82,7 @@ describe API::Triggers do post api("/projects/#{project.id}/trigger/pipeline"), options.merge(variables: variables, ref: 'master') expect(response).to have_http_status(201) - expect(pipeline.variables.map { |v| {v.key => v.value} }.last).to eq(variables) + expect(pipeline.variables.map { |v| { v.key => v.value } }.last).to eq(variables) end end end -- cgit v1.2.1 From 2ea6915ed8a9bac8da0aeb1558a2e8981c4409d0 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 28 Jul 2017 18:16:46 +0900 Subject: Fix revert miss --- app/services/ci/create_pipeline_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb index 780331d0b4e..884b681ff81 100644 --- a/app/services/ci/create_pipeline_service.rb +++ b/app/services/ci/create_pipeline_service.rb @@ -76,7 +76,7 @@ module Ci if !ignore_skip_ci && skip_ci? pipeline.skip if save_on_errors - raise InsufficientConditionError, pipeline + return pipeline end unless pipeline.has_stage_seeds? -- cgit v1.2.1 From cc25e2ba1daa4f413e73658a7d960cbf5ba93344 Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Fri, 28 Jul 2017 09:25:19 +0000 Subject: Global nav (9.0) UI improvement --- app/assets/stylesheets/framework/dropdowns.scss | 12 +++++------- app/assets/stylesheets/framework/filters.scss | 3 ++- app/assets/stylesheets/pages/projects.scss | 1 + .../unreleased/34921-global-dropdown-ui-improvement.yml | 4 ++++ 4 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 changelogs/unreleased/34921-global-dropdown-ui-improvement.yml diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index 5e410cbf563..3f934403147 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -148,7 +148,6 @@ padding: 5px 8px; color: $gl-text-color; line-height: initial; - text-overflow: ellipsis; border-radius: 2px; white-space: nowrap; overflow: hidden; @@ -203,11 +202,6 @@ border-radius: $border-radius-base; box-shadow: 0 2px 4px $dropdown-shadow-color; - @media (max-width: $screen-sm-min) { - width: 100%; - min-width: 180px; - } - &.dropdown-open-left { right: 0; left: auto; @@ -289,6 +283,11 @@ padding: 5px 8px; color: $gl-text-color-secondary; } + + .badge + span:not(.badge) { + // Expects up to 3 digits on the badge + margin-right: 40px; + } } .droplab-dropdown { @@ -373,7 +372,6 @@ .dropdown-menu, .dropdown-menu-nav { max-width: 280px; - width: auto; } } diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss index 41184907abb..ab2abaca33a 100644 --- a/app/assets/stylesheets/framework/filters.scss +++ b/app/assets/stylesheets/framework/filters.scss @@ -393,7 +393,8 @@ @media (max-width: $screen-xs) { .filter-dropdown-container { .dropdown-toggle, - .dropdown { + .dropdown, + .dropdown-menu { width: 100%; } diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index a3e07a36c33..b3a90dff89a 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -707,6 +707,7 @@ pre.light-well { background-color: transparent; border: 0; text-align: left; + text-overflow: ellipsis; } .protected-branches-list, diff --git a/changelogs/unreleased/34921-global-dropdown-ui-improvement.yml b/changelogs/unreleased/34921-global-dropdown-ui-improvement.yml new file mode 100644 index 00000000000..6a17353ba3f --- /dev/null +++ b/changelogs/unreleased/34921-global-dropdown-ui-improvement.yml @@ -0,0 +1,4 @@ +--- +title: Improve CSS for global nav dropdown UI +merge_request: 12772 +author: Takuya Noguchi -- cgit v1.2.1 From dca9bd9e6978cc240565e09de34c1387d7249294 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 28 Jul 2017 18:46:04 +0900 Subject: Expand pipeline_trigger_service_spec by godfat request --- spec/services/ci/pipeline_trigger_service_spec.rb | 44 ++++++++++++++--------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb index 9e60d04738c..945a2fe1a6b 100644 --- a/spec/services/ci/pipeline_trigger_service_spec.rb +++ b/spec/services/ci/pipeline_trigger_service_spec.rb @@ -12,43 +12,57 @@ describe Ci::PipelineTriggerService, services: true do let(:trigger) { create(:ci_trigger, project: project, owner: user) } let(:result) { described_class.new(project, user, params).execute } - let(:params) do - { token: token, ref: ref, variables: variables } - end - before do project.add_developer(user) end - context 'when params have an existsed trigger token' do - let(:token) { trigger.token } + context 'when trigger belongs to a different project' do + let(:params) { { token: trigger.token, ref: 'master', variables: nil } } + let(:trigger) { create(:ci_trigger, project: create(:empty_project), owner: user) } + + it 'does nothing' do + expect { result }.not_to change { Ci::Pipeline.count } + end + end + context 'when params have an existsed trigger token' do context 'when params have an existsed ref' do - let(:ref) { 'master' } - let(:variables) {} + let(:params) { { token: trigger.token, ref: 'master', variables: nil } } it 'triggers a pipeline' do expect { result }.to change { Ci::Pipeline.count }.by(1) - expect(result[:pipeline].ref).to eq(ref) + expect(result[:pipeline].ref).to eq('master') expect(result[:pipeline].project).to eq(project) expect(result[:pipeline].user).to eq(trigger.owner) expect(result[:status]).to eq(:success) end + context 'when commit message has [ci skip]' do + before do + allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { '[ci skip]' } + end + + it 'ignores [ci skip] and create as general' do + expect { result }.to change { Ci::Pipeline.count }.by(1) + expect(result[:status]).to eq(:success) + end + end + context 'when params have a variable' do + let(:params) { { token: trigger.token, ref: 'master', variables: variables } } let(:variables) { { 'AAA' => 'AAA123' } } it 'has a variable' do expect { result }.to change { Ci::PipelineVariable.count }.by(1) - expect(result[:pipeline].variables.first.key).to eq(variables.keys.first) - expect(result[:pipeline].variables.first.value).to eq(variables.values.first) + .and change { Ci::TriggerRequest.count }.by(1) + expect(result[:pipeline].variables.map { |v| { v.key => v.value } }.first).to eq(variables) + expect(result[:pipeline].trigger_requests.last.variables).to be_nil end end end context 'when params have a non-existsed ref' do - let(:ref) { 'invalid-ref' } - let(:variables) {} + let(:params) { { token: trigger.token, ref: 'invalid-ref', variables: nil } } it 'does not trigger a pipeline' do expect { result }.not_to change { Ci::Pipeline.count } @@ -58,9 +72,7 @@ describe Ci::PipelineTriggerService, services: true do end context 'when params have a non-existsed trigger token' do - let(:token) { 'invalid-token' } - let(:ref) {} - let(:variables) {} + let(:params) { { token: 'invalid-token', ref: nil, variables: nil } } it 'does not trigger a pipeline' do expect { result }.not_to change { Ci::Pipeline.count } -- cgit v1.2.1 From 07bcabb305f62e445c77ca8081b473adf21f56da Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 28 Jul 2017 12:16:07 +0200 Subject: Improve wording related to deploy chatops command --- doc/integration/slash_commands.md | 2 +- lib/gitlab/slash_commands/presenters/deploy.rb | 2 +- spec/lib/gitlab/slash_commands/command_spec.rb | 2 +- spec/lib/gitlab/slash_commands/deploy_spec.rb | 6 +++--- spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/integration/slash_commands.md b/doc/integration/slash_commands.md index 288ad1f7f5e..aa52b5415cf 100644 --- a/doc/integration/slash_commands.md +++ b/doc/integration/slash_commands.md @@ -24,7 +24,7 @@ It is possible to create new issue, display issue details and search up to 5 iss ## Deploy command In order to deploy to an environment, GitLab will try to find a deployment -action in the pipeline. +manual action in the pipeline. If there is only one action for a given environment, it is going to be triggered. If there is more than one action defined, GitLab will try to find an action diff --git a/lib/gitlab/slash_commands/presenters/deploy.rb b/lib/gitlab/slash_commands/presenters/deploy.rb index b72586394bc..ebae0f57f9b 100644 --- a/lib/gitlab/slash_commands/presenters/deploy.rb +++ b/lib/gitlab/slash_commands/presenters/deploy.rb @@ -10,7 +10,7 @@ module Gitlab end def action_not_found - ephemeral_response(text: "Couldn't find a deployment action.") + ephemeral_response(text: "Couldn't find a deployment manual action.") end end end diff --git a/spec/lib/gitlab/slash_commands/command_spec.rb b/spec/lib/gitlab/slash_commands/command_spec.rb index f0ecf59406a..88f73bf90cd 100644 --- a/spec/lib/gitlab/slash_commands/command_spec.rb +++ b/spec/lib/gitlab/slash_commands/command_spec.rb @@ -80,7 +80,7 @@ describe Gitlab::SlashCommands::Command do it 'returns error' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to include('Too many actions defined') + expect(subject[:text]).to include("Couldn't find a deployment manual action.") end end end diff --git a/spec/lib/gitlab/slash_commands/deploy_spec.rb b/spec/lib/gitlab/slash_commands/deploy_spec.rb index 17ebd088936..c3fb7d5adea 100644 --- a/spec/lib/gitlab/slash_commands/deploy_spec.rb +++ b/spec/lib/gitlab/slash_commands/deploy_spec.rb @@ -22,7 +22,7 @@ describe Gitlab::SlashCommands::Deploy do context 'if no environment is defined' do it 'does not execute an action' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to eq "Couldn't find a deployment action." + expect(subject[:text]).to eq "Couldn't find a deployment manual action." end end @@ -35,7 +35,7 @@ describe Gitlab::SlashCommands::Deploy do context 'without actions' do it 'does not execute an action' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to eq "Couldn't find a deployment action." + expect(subject[:text]).to eq "Couldn't find a deployment manual action." end end @@ -66,7 +66,7 @@ describe Gitlab::SlashCommands::Deploy do end it 'returns error about too many actions defined' do - expect(subject[:text]).to eq("Couldn't find a deployment action.") + expect(subject[:text]).to eq("Couldn't find a deployment manual action.") expect(subject[:response_type]).to be(:ephemeral) end end diff --git a/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb b/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb index eb94578c8e7..d16d122c64e 100644 --- a/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb +++ b/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb @@ -27,7 +27,7 @@ describe Gitlab::SlashCommands::Presenters::Deploy do it 'tells the user there is no action' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to eq "Couldn't find a deployment action." + expect(subject[:text]).to eq "Couldn't find a deployment manual action." end end end -- cgit v1.2.1 From 5899294583219c34c8fd5afea02587f80b5c4c48 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Fri, 28 Jul 2017 13:47:41 +0300 Subject: Add link to JIRA article in docs --- doc/user/project/integrations/jira.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/doc/user/project/integrations/jira.md b/doc/user/project/integrations/jira.md index cfa4c8a93f8..4f583879a4e 100644 --- a/doc/user/project/integrations/jira.md +++ b/doc/user/project/integrations/jira.md @@ -1,18 +1,22 @@ # GitLab JIRA integration -GitLab can be configured to interact with JIRA. Configuration happens via -user name and password. Connecting to a JIRA server via CAS is not possible. +GitLab can be configured to interact with [JIRA], a project management platform. -Each project can be configured to connect to a different JIRA instance, see the -[configuration](#configuration) section. If you have one JIRA instance you can -pre-fill the settings page with a default template. To configure the template -see the [Services Templates][services-templates] document. +Once your GitLab project is connected to JIRA, you can reference and close the +issues in JIRA directly from GitLab. -Once the project is connected to JIRA, you can reference and close the issues -in JIRA directly from GitLab. +For a use case, check out this article of [How and why to integrate GitLab with +JIRA](https://www.programmableweb.com/news/how-and-why-to-integrate-gitlab-jira/how-to/2017/04/25). ## Configuration +Each GitLab project can be configured to connect to a different JIRA instance. +If you have one JIRA instance you can pre-fill the settings page with a default +template, see the [Services Templates][services-templates] docs. + +Configuration happens via user name and password. Connecting to a JIRA server +via CAS is not possible. + In order to enable the JIRA service in GitLab, you need to first configure the project in JIRA and then enter the correct values in GitLab. @@ -213,3 +217,4 @@ your project needs to close a ticket. [services-templates]: services_templates.md [jira-repo-old-docs]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-13-stable/doc/project_services/jira.md +[jira]: https://www.atlassian.com/software/jira -- cgit v1.2.1 From f35563b2385b6c1261d4150a14671367b3631615 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 27 Jul 2017 21:45:17 +0800 Subject: Make access level more compatible with EE So the behaviour would be similar in CE and EE --- spec/factories/protected_branches.rb | 50 +++++++++++++++++++++++++++++------- spec/factories/protected_tags.rb | 36 +++++++++++++++++++++----- 2 files changed, 71 insertions(+), 15 deletions(-) diff --git a/spec/factories/protected_branches.rb b/spec/factories/protected_branches.rb index b2695e0482a..3dbace4b38a 100644 --- a/spec/factories/protected_branches.rb +++ b/spec/factories/protected_branches.rb @@ -3,26 +3,58 @@ FactoryGirl.define do name project - after(:build) do |protected_branch| - protected_branch.push_access_levels.new(access_level: Gitlab::Access::MASTER) - protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MASTER) + transient do + default_push_level true + default_merge_level true + default_access_level true end trait :developers_can_push do - after(:create) do |protected_branch| - protected_branch.push_access_levels.first.update!(access_level: Gitlab::Access::DEVELOPER) + transient do + default_push_level false + end + + after(:build) do |protected_branch| + protected_branch.push_access_levels.new(access_level: Gitlab::Access::DEVELOPER) end end trait :developers_can_merge do - after(:create) do |protected_branch| - protected_branch.merge_access_levels.first.update!(access_level: Gitlab::Access::DEVELOPER) + transient do + default_merge_level false + end + + after(:build) do |protected_branch| + protected_branch.merge_access_levels.new(access_level: Gitlab::Access::DEVELOPER) end end trait :no_one_can_push do - after(:create) do |protected_branch| - protected_branch.push_access_levels.first.update!(access_level: Gitlab::Access::NO_ACCESS) + transient do + default_push_level false + end + + after(:build) do |protected_branch| + protected_branch.push_access_levels.new(access_level: Gitlab::Access::NO_ACCESS) + end + end + + trait :masters_can_push do + transient do + default_push_level false + end + + after(:build) do |protected_branch| + protected_branch.push_access_levels.new(access_level: Gitlab::Access::MASTER) + end + end + + after(:build) do |protected_branch, evaluator| + if evaluator.default_access_level && evaluator.default_push_level + protected_branch.push_access_levels.new(access_level: Gitlab::Access::MASTER) + end + if evaluator.default_access_level && evaluator.default_merge_level + protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MASTER) end end end diff --git a/spec/factories/protected_tags.rb b/spec/factories/protected_tags.rb index d8e90ae1ee1..225588b23cc 100644 --- a/spec/factories/protected_tags.rb +++ b/spec/factories/protected_tags.rb @@ -3,19 +3,43 @@ FactoryGirl.define do name project - after(:build) do |protected_tag| - protected_tag.create_access_levels.new(access_level: Gitlab::Access::MASTER) + transient do + default_access_level true end trait :developers_can_create do - after(:create) do |protected_tag| - protected_tag.create_access_levels.first.update!(access_level: Gitlab::Access::DEVELOPER) + transient do + default_access_level false + end + + after(:build) do |protected_tag| + protected_tag.create_access_levels.new(access_level: Gitlab::Access::DEVELOPER) end end trait :no_one_can_create do - after(:create) do |protected_tag| - protected_tag.create_access_levels.first.update!(access_level: Gitlab::Access::NO_ACCESS) + transient do + default_access_level false + end + + after(:build) do |protected_tag| + protected_tag.create_access_levels.new(access_level: Gitlab::Access::NO_ACCESS) + end + end + + trait :masters_can_create do + transient do + default_access_level false + end + + after(:build) do |protected_tag| + protected_tag.create_access_levels.new(access_level: Gitlab::Access::MASTER) + end + end + + after(:build) do |protected_tag, evaluator| + if evaluator.default_access_level + protected_tag.create_access_levels.new(access_level: Gitlab::Access::MASTER) end end end -- cgit v1.2.1 From 6ef87a20832d1a2581cb85e60eda46f999c55a81 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 19 Jul 2017 16:03:50 +0200 Subject: Merge issuable "reopened" state into "opened" Having two states that essentially mean the same thing is very much like having a boolean "true" and boolean "mostly-true": it's rather silly. This commit merges the "reopened" state into the "opened" state while taking care of system notes still showing messages along the lines of "Alice reopened this issue". A big benefit from having only two states (opened and closed) is that indexing and querying becomes simpler and more performant. For example, to get all the opened queries we no longer have to query both states: SELECT * FROM issues WHERE project_id = 2 AND state IN ('opened', 'reopened'); Instead we can query a single state directly, which can be much faster: SELECT * FROM issues WHERE project_id = 2 AND state = 'opened'; Further, only having two states makes indexing easier as we will only ever filter (and thus scan an index) using a single value. Partial indexes could help but aren't supported on MySQL, complicating the development process and not being helpful for MySQL. --- .../stores/mr_widget_store.js | 2 +- app/finders/issuable_finder.rb | 1 - app/models/concerns/issuable.rb | 5 ++-- app/models/issue.rb | 5 ++-- app/models/merge_request.rb | 13 ++++----- app/models/project_services/drone_ci_service.rb | 2 +- app/services/issues/reopen_service.rb | 6 ++-- app/services/merge_requests/base_service.rb | 6 ++-- app/services/merge_requests/reopen_service.rb | 2 +- .../merge-issuable-reopened-into-opened-state.yml | 4 +++ ...01_merge_issuable_reopened_into_opened_state.rb | 32 ++++++++++++++++++++++ spec/factories/issues.rb | 6 +--- spec/factories/merge_requests.rb | 6 +--- .../banzai/filter/issuable_state_filter_spec.rb | 10 +------ spec/requests/api/issues_spec.rb | 2 +- spec/requests/api/v3/issues_spec.rb | 2 +- spec/services/boards/issues/list_service_spec.rb | 2 +- spec/services/boards/issues/move_service_spec.rb | 2 +- .../delete_merged_branches_service_spec.rb | 2 +- .../merge_requests/get_urls_service_spec.rb | 2 +- .../services/merge_requests/reopen_service_spec.rb | 2 +- 21 files changed, 65 insertions(+), 49 deletions(-) create mode 100644 changelogs/unreleased/merge-issuable-reopened-into-opened-state.yml create mode 100644 db/post_migrate/20170719150301_merge_issuable_reopened_into_opened_state.rb diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js index 72a13108404..fddafb0ddfa 100644 --- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js +++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js @@ -65,7 +65,7 @@ export default class MergeRequestStore { this.mergeCheckPath = data.merge_check_path; this.mergeActionsContentPath = data.commit_change_content_path; this.isRemovingSourceBranch = this.isRemovingSourceBranch || false; - this.isOpen = data.state === 'opened' || data.state === 'reopened' || false; + this.isOpen = data.state === 'opened'; this.hasMergeableDiscussionsState = data.mergeable_discussions_state === false; this.canRemoveSourceBranch = currentUser.can_remove_source_branch || false; this.canMerge = !!data.merge_path; diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index 6fe17a2b99d..08a843ada97 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -81,7 +81,6 @@ class IssuableFinder end counts[:all] = counts.values.sum - counts[:opened] += counts[:reopened] counts end diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 13fe9d09c69..935ffe343ff 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -71,9 +71,8 @@ module Issuable scope :of_projects, ->(ids) { where(project_id: ids) } scope :of_milestones, ->(ids) { where(milestone_id: ids) } scope :with_milestone, ->(title) { left_joins_milestones.where(milestones: { title: title }) } - scope :opened, -> { with_state(:opened, :reopened) } + scope :opened, -> { with_state(:opened) } scope :only_opened, -> { with_state(:opened) } - scope :only_reopened, -> { with_state(:reopened) } scope :closed, -> { with_state(:closed) } scope :left_joins_milestones, -> { joins("LEFT OUTER JOIN milestones ON #{table_name}.milestone_id = milestones.id") } @@ -234,7 +233,7 @@ module Issuable end def open? - opened? || reopened? + opened? end def user_notes_count diff --git a/app/models/issue.rb b/app/models/issue.rb index 400bb55d2f0..1c948c8957e 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -62,15 +62,14 @@ class Issue < ActiveRecord::Base state_machine :state, initial: :opened do event :close do - transition [:reopened, :opened] => :closed + transition [:opened] => :closed end event :reopen do - transition closed: :reopened + transition closed: :opened end state :opened - state :reopened state :closed before_transition any => :closed do |issue| diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index a910099b4c1..81e0776e79c 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -42,23 +42,23 @@ class MergeRequest < ActiveRecord::Base state_machine :state, initial: :opened do event :close do - transition [:reopened, :opened] => :closed + transition [:opened] => :closed end event :mark_as_merged do - transition [:reopened, :opened, :locked] => :merged + transition [:opened, :locked] => :merged end event :reopen do - transition closed: :reopened + transition closed: :opened end event :lock_mr do - transition [:reopened, :opened] => :locked + transition [:opened] => :locked end event :unlock_mr do - transition locked: :reopened + transition locked: :opened end after_transition any => :locked do |merge_request, transition| @@ -72,7 +72,6 @@ class MergeRequest < ActiveRecord::Base end state :opened - state :reopened state :closed state :merged state :locked @@ -368,7 +367,7 @@ class MergeRequest < ActiveRecord::Base errors.add :branch_conflict, "You can not use same project/branch for source and target" end - if opened? || reopened? + if opened? similar_mrs = self.target_project.merge_requests.where(source_branch: source_branch, target_branch: target_branch, source_project_id: source_project.try(:id)).opened similar_mrs = similar_mrs.where('id not in (?)', self.id) if self.id if similar_mrs.any? diff --git a/app/models/project_services/drone_ci_service.rb b/app/models/project_services/drone_ci_service.rb index f6cade9c290..c93f1632652 100644 --- a/app/models/project_services/drone_ci_service.rb +++ b/app/models/project_services/drone_ci_service.rb @@ -114,7 +114,7 @@ class DroneCiService < CiService end def merge_request_valid?(data) - %w(opened reopened).include?(data[:object_attributes][:state]) && + data[:object_attributes][:state] == 'opened' && data[:object_attributes][:merge_status] == 'unchecked' end end diff --git a/app/services/issues/reopen_service.rb b/app/services/issues/reopen_service.rb index 73b2e85cba3..35de4337b15 100644 --- a/app/services/issues/reopen_service.rb +++ b/app/services/issues/reopen_service.rb @@ -5,7 +5,7 @@ module Issues if issue.reopen event_service.reopen_issue(issue, current_user) - create_note(issue) + create_note(issue, 'reopened') notification_service.reopen_issue(issue, current_user) execute_hooks(issue, 'reopen') invalidate_cache_counts(issue, users: issue.assignees) @@ -16,8 +16,8 @@ module Issues private - def create_note(issue) - SystemNoteService.change_status(issue, issue.project, current_user, issue.state, nil) + def create_note(issue, state = issue.state) + SystemNoteService.change_status(issue, issue.project, current_user, state, nil) end end end diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb index 3542a41ac83..35ccff26262 100644 --- a/app/services/merge_requests/base_service.rb +++ b/app/services/merge_requests/base_service.rb @@ -1,7 +1,7 @@ module MergeRequests class BaseService < ::IssuableBaseService - def create_note(merge_request) - SystemNoteService.change_status(merge_request, merge_request.target_project, current_user, merge_request.state, nil) + def create_note(merge_request, state = merge_request.state) + SystemNoteService.change_status(merge_request, merge_request.target_project, current_user, state, nil) end def create_title_change_note(issuable, old_title) @@ -44,7 +44,7 @@ module MergeRequests end # Returns all origin and fork merge requests from `@project` satisfying passed arguments. - def merge_requests_for(source_branch, mr_states: [:opened, :reopened]) + def merge_requests_for(source_branch, mr_states: [:opened]) MergeRequest .with_state(mr_states) .where(source_branch: source_branch, source_project_id: @project.id) diff --git a/app/services/merge_requests/reopen_service.rb b/app/services/merge_requests/reopen_service.rb index 52f6d511f98..b9c65be36ec 100644 --- a/app/services/merge_requests/reopen_service.rb +++ b/app/services/merge_requests/reopen_service.rb @@ -5,7 +5,7 @@ module MergeRequests if merge_request.reopen event_service.reopen_mr(merge_request, current_user) - create_note(merge_request) + create_note(merge_request, 'reopened') notification_service.reopen_mr(merge_request, current_user) execute_hooks(merge_request, 'reopen') merge_request.reload_diff(current_user) diff --git a/changelogs/unreleased/merge-issuable-reopened-into-opened-state.yml b/changelogs/unreleased/merge-issuable-reopened-into-opened-state.yml new file mode 100644 index 00000000000..5d7af8971e5 --- /dev/null +++ b/changelogs/unreleased/merge-issuable-reopened-into-opened-state.yml @@ -0,0 +1,4 @@ +--- +title: Merge issuable "reopened" state into "opened" +merge_request: +author: diff --git a/db/post_migrate/20170719150301_merge_issuable_reopened_into_opened_state.rb b/db/post_migrate/20170719150301_merge_issuable_reopened_into_opened_state.rb new file mode 100644 index 00000000000..acc0fc7a0ac --- /dev/null +++ b/db/post_migrate/20170719150301_merge_issuable_reopened_into_opened_state.rb @@ -0,0 +1,32 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class MergeIssuableReopenedIntoOpenedState < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + class Issue < ActiveRecord::Base + self.table_name = 'issues' + + include EachBatch + end + + class MergeRequest < ActiveRecord::Base + self.table_name = 'merge_requests' + + include EachBatch + end + + def up + [Issue, MergeRequest].each do |model| + say "Changing #{model.table_name}.state from 'reopened' to 'opened'" + + model.where(state: 'reopened').each_batch do |batch| + batch.update_all(state: 'opened') + end + end + end +end diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb index f1fd1fd7f73..a16695cb7c1 100644 --- a/spec/factories/issues.rb +++ b/spec/factories/issues.rb @@ -16,12 +16,8 @@ FactoryGirl.define do state :closed end - trait :reopened do - state :reopened - end - factory :closed_issue, traits: [:closed] - factory :reopened_issue, traits: [:reopened] + factory :reopened_issue, traits: [:opened] factory :labeled_issue do transient do diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index 253a025af48..1bc530d06db 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -44,10 +44,6 @@ FactoryGirl.define do state :opened end - trait :reopened do - state :reopened - end - trait :locked do state :locked end @@ -74,7 +70,7 @@ FactoryGirl.define do factory :merged_merge_request, traits: [:merged] factory :closed_merge_request, traits: [:closed] - factory :reopened_merge_request, traits: [:reopened] + factory :reopened_merge_request, traits: [:opened] factory :merge_request_with_diffs, traits: [:with_diffs] factory :merge_request_with_diff_notes do after(:create) do |mr| diff --git a/spec/lib/banzai/filter/issuable_state_filter_spec.rb b/spec/lib/banzai/filter/issuable_state_filter_spec.rb index 7cf2f4282f8..bc7cae1df8d 100644 --- a/spec/lib/banzai/filter/issuable_state_filter_spec.rb +++ b/spec/lib/banzai/filter/issuable_state_filter_spec.rb @@ -107,14 +107,6 @@ describe Banzai::Filter::IssuableStateFilter do expect(doc.css('a').last.text).to eq(issue.to_reference) end - it 'ignores reopened issue references' do - issue = create_issue(:reopened) - link = create_link(issue.to_reference, issue: issue.id, reference_type: 'issue') - doc = filter(link, context) - - expect(doc.css('a').last.text).to eq(issue.to_reference) - end - it 'appends state to closed issue references' do link = create_link(closed_issue.to_reference, issue: closed_issue.id, reference_type: 'issue') doc = filter(link, context) @@ -139,7 +131,7 @@ describe Banzai::Filter::IssuableStateFilter do end it 'ignores reopened merge request references' do - merge_request = create_merge_request(:reopened) + merge_request = create_merge_request(:opened) link = create_link( merge_request.to_reference, diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 33cea02153e..2c44be4e447 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -1259,7 +1259,7 @@ describe API::Issues do put api("/projects/#{project.id}/issues/#{closed_issue.iid}", user), state_event: 'reopen' expect(response).to have_http_status(200) - expect(json_response['state']).to eq 'reopened' + expect(json_response['state']).to eq 'opened' end context 'when an admin or owner makes the request' do diff --git a/spec/requests/api/v3/issues_spec.rb b/spec/requests/api/v3/issues_spec.rb index cc81922697a..4dff09b6df8 100644 --- a/spec/requests/api/v3/issues_spec.rb +++ b/spec/requests/api/v3/issues_spec.rb @@ -1114,7 +1114,7 @@ describe API::V3::Issues do put v3_api("/projects/#{project.id}/issues/#{closed_issue.id}", user), state_event: 'reopen' expect(response).to have_http_status(200) - expect(json_response['state']).to eq 'reopened' + expect(json_response['state']).to eq 'opened' end context 'when an admin or owner makes the request' do diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb index 2c293088097..b1b5d807a78 100644 --- a/spec/services/boards/issues/list_service_spec.rb +++ b/spec/services/boards/issues/list_service_spec.rb @@ -20,7 +20,7 @@ describe Boards::Issues::ListService do let!(:opened_issue1) { create(:labeled_issue, project: project, labels: [bug]) } let!(:opened_issue2) { create(:labeled_issue, project: project, labels: [p2]) } - let!(:reopened_issue1) { create(:issue, :reopened, project: project) } + let!(:reopened_issue1) { create(:issue, :opened, project: project) } let!(:list1_issue1) { create(:labeled_issue, project: project, labels: [p2, development]) } let!(:list1_issue2) { create(:labeled_issue, project: project, labels: [development]) } diff --git a/spec/services/boards/issues/move_service_spec.rb b/spec/services/boards/issues/move_service_spec.rb index 7dd1a601700..15a32350ae2 100644 --- a/spec/services/boards/issues/move_service_spec.rb +++ b/spec/services/boards/issues/move_service_spec.rb @@ -73,7 +73,7 @@ describe Boards::Issues::MoveService do issue.reload expect(issue.labels).to contain_exactly(bug, testing) - expect(issue).to be_reopened + expect(issue).to be_opened end end diff --git a/spec/services/delete_merged_branches_service_spec.rb b/spec/services/delete_merged_branches_service_spec.rb index 954c5d3ab73..4b872d667cf 100644 --- a/spec/services/delete_merged_branches_service_spec.rb +++ b/spec/services/delete_merged_branches_service_spec.rb @@ -43,7 +43,7 @@ describe DeleteMergedBranchesService do context 'open merge requests' do it 'does not delete branches from open merge requests' do fork_link = create(:forked_project_link, forked_from_project: project) - create(:merge_request, :reopened, source_project: project, target_project: project, source_branch: 'branch-merged', target_branch: 'master') + create(:merge_request, :opened, source_project: project, target_project: project, source_branch: 'branch-merged', target_branch: 'master') create(:merge_request, :opened, source_project: fork_link.forked_to_project, target_project: project, target_branch: 'improve/awesome', source_branch: 'master') service.execute diff --git a/spec/services/merge_requests/get_urls_service_spec.rb b/spec/services/merge_requests/get_urls_service_spec.rb index 4a7d8ab4c6c..672d86e4028 100644 --- a/spec/services/merge_requests/get_urls_service_spec.rb +++ b/spec/services/merge_requests/get_urls_service_spec.rb @@ -78,7 +78,7 @@ describe MergeRequests::GetUrlsService do end context 'pushing to existing branch and merge request is reopened' do - let!(:merge_request) { create(:merge_request, :reopened, source_project: project, source_branch: source_branch) } + let!(:merge_request) { create(:merge_request, :opened, source_project: project, source_branch: source_branch) } let(:changes) { existing_branch_changes } it_behaves_like 'show_merge_request_url' end diff --git a/spec/services/merge_requests/reopen_service_spec.rb b/spec/services/merge_requests/reopen_service_spec.rb index ce1e9f2ff45..f02af0c582e 100644 --- a/spec/services/merge_requests/reopen_service_spec.rb +++ b/spec/services/merge_requests/reopen_service_spec.rb @@ -28,7 +28,7 @@ describe MergeRequests::ReopenService do end it { expect(merge_request).to be_valid } - it { expect(merge_request).to be_reopened } + it { expect(merge_request).to be_opened } it 'executes hooks with reopen action' do expect(service).to have_received(:execute_hooks) -- cgit v1.2.1 From e1c432d84812cbcaa5bca1d43cc4dab902ae2360 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Fri, 28 Jul 2017 13:34:58 +0200 Subject: none is not a CSS Value for sizes ;-) --- app/assets/stylesheets/framework/typography.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index befd8133be0..bf5f124d142 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -19,9 +19,9 @@ } img.js-lazy-loaded { - min-width: none; - min-height: none; - background-color: none; + min-width: inherit; + min-height: inherit; + background-color: inherit; } p a:not(.no-attachment-icon) img { -- cgit v1.2.1 From 20d7b04639c38e3216b115484e36446c3465b1bf Mon Sep 17 00:00:00 2001 From: James Edwards-Jones Date: Fri, 28 Jul 2017 13:46:01 +0100 Subject: Update CHANGELOG.md for 9.4.2 [ci skip] --- CHANGELOG.md | 15 +++++++++++++++ changelogs/unreleased/2971-multiproject-grah-ce-port.yml | 4 ---- changelogs/unreleased/34729-blob.yml | 4 ---- ...eploy-keys-should-not-show-pending-delete-projects.yml | 4 ---- ...nding-delete-projects-error-in-admin-dashboard-fix.yml | 4 ---- .../unreleased/35478-allow-admin-to-read-user-list.yml | 4 ---- ...containing-a-binary-file-with-non-utf-8-characters.yml | 5 ----- .../unreleased/add-instrumentation-to-link-to-gfm.yml | 4 ---- ...ix-gb-fix-build-merge-request-link-to-fork-project.yml | 4 ---- .../mk-add-ldap-ssl-certificate-verification.yml | 4 ---- .../mk-add-lower-path-index-to-redirect-routes.yml | 4 ---- changelogs/unreleased/new-navigation-custom-logo.yml | 4 ---- 12 files changed, 15 insertions(+), 45 deletions(-) delete mode 100644 changelogs/unreleased/2971-multiproject-grah-ce-port.yml delete mode 100644 changelogs/unreleased/34729-blob.yml delete mode 100644 changelogs/unreleased/35338-deploy-keys-should-not-show-pending-delete-projects.yml delete mode 100644 changelogs/unreleased/35453-pending-delete-projects-error-in-admin-dashboard-fix.yml delete mode 100644 changelogs/unreleased/35478-allow-admin-to-read-user-list.yml delete mode 100644 changelogs/unreleased/35539-can-t-create-a-merge-request-containing-a-binary-file-with-non-utf-8-characters.yml delete mode 100644 changelogs/unreleased/add-instrumentation-to-link-to-gfm.yml delete mode 100644 changelogs/unreleased/fix-gb-fix-build-merge-request-link-to-fork-project.yml delete mode 100644 changelogs/unreleased/mk-add-ldap-ssl-certificate-verification.yml delete mode 100644 changelogs/unreleased/mk-add-lower-path-index-to-redirect-routes.yml delete mode 100644 changelogs/unreleased/new-navigation-custom-logo.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 580d2357512..412cd86bad6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 9.4.2 (2017-07-28) + +- Fix job merge request link to a forked source project. !12965 +- Improve redirect route query performance. !13062 +- Allow admin to read_users_list even if it's restricted. !13066 +- Fixes 500 error caused by pending delete projects in admin dashboard. !13067 +- Add instrumentation to MarkupHelper#link_to_gfm. !13069 +- Pending delete projects should not show in deploy keys. !13088 +- Fix sizing of custom header logo in new navigation. +- Fix crash on /help/ui. +- Fix creating merge request diffs when diff contains bytes that are invalid in UTF-8. +- fix vertical alignment of New Project button. +- Add LDAP SSL certificate verification option. +- Fix vertical alignment in firefox and safari for pipeline mini graph. + ## 9.4.1 (2017-07-25) - Fix pipeline_schedules pages throwing error 500 (when ref is empty). !12983 diff --git a/changelogs/unreleased/2971-multiproject-grah-ce-port.yml b/changelogs/unreleased/2971-multiproject-grah-ce-port.yml deleted file mode 100644 index 37584cac6ab..00000000000 --- a/changelogs/unreleased/2971-multiproject-grah-ce-port.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix vertical alignment in firefox and safari for pipeline mini graph -merge_request: -author: diff --git a/changelogs/unreleased/34729-blob.yml b/changelogs/unreleased/34729-blob.yml deleted file mode 100644 index 15a469d3af0..00000000000 --- a/changelogs/unreleased/34729-blob.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix crash on /help/ui -merge_request: -author: diff --git a/changelogs/unreleased/35338-deploy-keys-should-not-show-pending-delete-projects.yml b/changelogs/unreleased/35338-deploy-keys-should-not-show-pending-delete-projects.yml deleted file mode 100644 index 73808030f4c..00000000000 --- a/changelogs/unreleased/35338-deploy-keys-should-not-show-pending-delete-projects.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Pending delete projects should not show in deploy keys. -merge_request: 13088 -author: diff --git a/changelogs/unreleased/35453-pending-delete-projects-error-in-admin-dashboard-fix.yml b/changelogs/unreleased/35453-pending-delete-projects-error-in-admin-dashboard-fix.yml deleted file mode 100644 index fa906accbb8..00000000000 --- a/changelogs/unreleased/35453-pending-delete-projects-error-in-admin-dashboard-fix.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixes 500 error caused by pending delete projects in admin dashboard -merge_request: 13067 -author: diff --git a/changelogs/unreleased/35478-allow-admin-to-read-user-list.yml b/changelogs/unreleased/35478-allow-admin-to-read-user-list.yml deleted file mode 100644 index da4b730f0ca..00000000000 --- a/changelogs/unreleased/35478-allow-admin-to-read-user-list.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Allow admin to read_users_list even if it's restricted -merge_request: 13066 -author: diff --git a/changelogs/unreleased/35539-can-t-create-a-merge-request-containing-a-binary-file-with-non-utf-8-characters.yml b/changelogs/unreleased/35539-can-t-create-a-merge-request-containing-a-binary-file-with-non-utf-8-characters.yml deleted file mode 100644 index 8d92aacc9ef..00000000000 --- a/changelogs/unreleased/35539-can-t-create-a-merge-request-containing-a-binary-file-with-non-utf-8-characters.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix creating merge request diffs when diff contains bytes that are invalid - in UTF-8 -merge_request: -author: diff --git a/changelogs/unreleased/add-instrumentation-to-link-to-gfm.yml b/changelogs/unreleased/add-instrumentation-to-link-to-gfm.yml deleted file mode 100644 index b5cf521561a..00000000000 --- a/changelogs/unreleased/add-instrumentation-to-link-to-gfm.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add instrumentation to MarkupHelper#link_to_gfm -merge_request: 13069 -author: diff --git a/changelogs/unreleased/fix-gb-fix-build-merge-request-link-to-fork-project.yml b/changelogs/unreleased/fix-gb-fix-build-merge-request-link-to-fork-project.yml deleted file mode 100644 index 7a68e91c6d3..00000000000 --- a/changelogs/unreleased/fix-gb-fix-build-merge-request-link-to-fork-project.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix job merge request link to a forked source project -merge_request: 12965 -author: diff --git a/changelogs/unreleased/mk-add-ldap-ssl-certificate-verification.yml b/changelogs/unreleased/mk-add-ldap-ssl-certificate-verification.yml deleted file mode 100644 index 80e6c50d5b3..00000000000 --- a/changelogs/unreleased/mk-add-ldap-ssl-certificate-verification.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add LDAP SSL certificate verification option -merge_request: -author: diff --git a/changelogs/unreleased/mk-add-lower-path-index-to-redirect-routes.yml b/changelogs/unreleased/mk-add-lower-path-index-to-redirect-routes.yml deleted file mode 100644 index 37a5fa66d13..00000000000 --- a/changelogs/unreleased/mk-add-lower-path-index-to-redirect-routes.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Improve redirect route query performance -merge_request: 13062 -author: diff --git a/changelogs/unreleased/new-navigation-custom-logo.yml b/changelogs/unreleased/new-navigation-custom-logo.yml deleted file mode 100644 index 22e6c5dc7e5..00000000000 --- a/changelogs/unreleased/new-navigation-custom-logo.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix sizing of custom header logo in new navigation -merge_request: -author: -- cgit v1.2.1 From fdfb4bbe5c659e02734258615b57b5f012afb2b4 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Fri, 28 Jul 2017 13:59:57 +0100 Subject: Fix diff commenting results just after changing view When you change the diff view (inline / side-by-side), we set a cookie based on that new view. When you add a comment, we choose the style to use in the response based on that cookie. However, when you have just changed diff style, the request cookie will contain the old value, so we should use the view param instead. --- app/helpers/diff_helper.rb | 2 +- ...a-wrong-place-after-changing-diff-view-to-inline.yml | 4 ++++ spec/helpers/diff_helper_spec.rb | 17 +++++++++++++++-- 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/35695-comment-appears-in-a-wrong-place-after-changing-diff-view-to-inline.yml diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index 926502bf239..91ddd73fac1 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -15,7 +15,7 @@ module DiffHelper def diff_view @diff_view ||= begin diff_views = %w(inline parallel) - diff_view = cookies[:diff_view] + diff_view = params[:view] || cookies[:diff_view] diff_view = diff_views.first unless diff_views.include?(diff_view) diff_view.to_sym end diff --git a/changelogs/unreleased/35695-comment-appears-in-a-wrong-place-after-changing-diff-view-to-inline.yml b/changelogs/unreleased/35695-comment-appears-in-a-wrong-place-after-changing-diff-view-to-inline.yml new file mode 100644 index 00000000000..1c9ad20bc95 --- /dev/null +++ b/changelogs/unreleased/35695-comment-appears-in-a-wrong-place-after-changing-diff-view-to-inline.yml @@ -0,0 +1,4 @@ +--- +title: Fix display of new diff comments after changing b between diff views +merge_request: +author: diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb index 0d909e6e140..060c112e20d 100644 --- a/spec/helpers/diff_helper_spec.rb +++ b/spec/helpers/diff_helper_spec.rb @@ -12,19 +12,32 @@ describe DiffHelper do let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: diff_refs, repository: repository) } describe 'diff_view' do + it 'uses the view param over the cookie' do + controller.params[:view] = 'parallel' + helper.request.cookies[:diff_view] = 'inline' + + expect(helper.diff_view).to eq :parallel + end + + it 'returns the default value when the view param is invalid' do + controller.params[:view] = 'invalid' + + expect(helper.diff_view).to eq :inline + end + it 'returns a valid value when cookie is set' do helper.request.cookies[:diff_view] = 'parallel' expect(helper.diff_view).to eq :parallel end - it 'returns a default value when cookie is invalid' do + it 'returns the default value when cookie is invalid' do helper.request.cookies[:diff_view] = 'invalid' expect(helper.diff_view).to eq :inline end - it 'returns a default value when cookie is nil' do + it 'returns the default value when cookie is nil' do expect(helper.request.cookies).to be_empty expect(helper.diff_view).to eq :inline -- cgit v1.2.1 From 329391ced723a62b20d0ce9bb4746e0f4074f395 Mon Sep 17 00:00:00 2001 From: bart Date: Fri, 28 Jul 2017 13:28:47 +0000 Subject: Update gitlab_flow.md, Teatro seems to be completely dead, see also https://forum.gitlab.com/t/gitlab-flow-documentation-teatro/7774 --- doc/workflow/gitlab_flow.md | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/workflow/gitlab_flow.md b/doc/workflow/gitlab_flow.md index ea28968fbb2..9d466ae1971 100644 --- a/doc/workflow/gitlab_flow.md +++ b/doc/workflow/gitlab_flow.md @@ -91,7 +91,6 @@ This workflow where commits only flow downstream ensures that everything has bee If you need to cherry-pick a commit with a hotfix it is common to develop it on a feature branch and merge it into master with a merge request, do not delete the feature branch. If master is good to go (it should be if you are practicing [continuous delivery](http://martinfowler.com/bliki/ContinuousDelivery.html)) you then merge it to the other branches. If this is not possible because more manual testing is required you can send merge requests from the feature branch to the downstream branches. -An 'extreme' version of environment branches are setting up an environment for each feature branch as done by [Teatro](https://teatro.io/). ## Release branches with GitLab flow -- cgit v1.2.1 From d020eabf2938858830125ace467b13695eb85962 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 28 Jul 2017 15:39:39 +0200 Subject: Add log messages to clarify log messages about API CSRF token verification failure --- lib/gitlab/request_forgery_protection.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/gitlab/request_forgery_protection.rb b/lib/gitlab/request_forgery_protection.rb index 48dd0487790..ccfe0d6bed3 100644 --- a/lib/gitlab/request_forgery_protection.rb +++ b/lib/gitlab/request_forgery_protection.rb @@ -7,6 +7,14 @@ module Gitlab class Controller < ActionController::Base protect_from_forgery with: :exception + rescue_from ActionController::InvalidAuthenticityToken do |e| + logger.warn "This CSRF token verification failure is handled internally by `GitLab::RequestForgeryProtection`" + logger.warn "Unlike the logs may suggest, this does not result in an actual 422 response to the user" + logger.warn "For API requests, the only effect is that `current_user` will be `nil` for the duration of the request" + + raise e + end + def index head :ok end -- cgit v1.2.1 From 60797a42b419841e14f50f85bf8daa2a115a72f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 27 Jul 2017 11:15:57 +0200 Subject: Ensure Gitlab::Application.routes.default_url_options are set correctly in Capybara + :js specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- config/initializers/1_settings.rb | 2 +- lib/api/helpers/related_resources_helpers.rb | 2 +- spec/features/dashboard/issues_spec.rb | 12 +----------- spec/models/project_wiki_spec.rb | 2 +- spec/spec_helper.rb | 1 + spec/support/capybara.rb | 9 ++++++++- 6 files changed, 13 insertions(+), 15 deletions(-) diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 02d3161f769..63f4c8c9e0a 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -223,7 +223,7 @@ Settings.gitlab['default_can_create_group'] = true if Settings.gitlab['default_c Settings.gitlab['host'] ||= ENV['GITLAB_HOST'] || 'localhost' Settings.gitlab['ssh_host'] ||= Settings.gitlab.host Settings.gitlab['https'] = false if Settings.gitlab['https'].nil? -Settings.gitlab['port'] ||= Settings.gitlab.https ? 443 : 80 +Settings.gitlab['port'] ||= ENV['GITLAB_PORT'] || (Settings.gitlab.https ? 443 : 80) Settings.gitlab['relative_url_root'] ||= ENV['RAILS_RELATIVE_URL_ROOT'] || '' Settings.gitlab['protocol'] ||= Settings.gitlab.https ? "https" : "http" Settings.gitlab['email_enabled'] ||= true if Settings.gitlab['email_enabled'].nil? diff --git a/lib/api/helpers/related_resources_helpers.rb b/lib/api/helpers/related_resources_helpers.rb index 769cc1457fc..1f677529b07 100644 --- a/lib/api/helpers/related_resources_helpers.rb +++ b/lib/api/helpers/related_resources_helpers.rb @@ -12,7 +12,7 @@ module API end def expose_url(path) - url_options = Rails.application.routes.default_url_options + url_options = Gitlab::Application.routes.default_url_options protocol, host, port = url_options.slice(:protocol, :host, :port).values URI::HTTP.build(scheme: protocol, host: host, port: port, path: path).to_s diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb index 7c0bf8de14c..82adde6258f 100644 --- a/spec/features/dashboard/issues_spec.rb +++ b/spec/features/dashboard/issues_spec.rb @@ -79,15 +79,7 @@ RSpec.describe 'Dashboard Issues' do end end - it 'shows the new issue page', js: true do - original_defaults = Gitlab::Application.routes.default_url_options - - Gitlab::Application.routes.default_url_options = { - host: Capybara.current_session.server.host, - port: Capybara.current_session.server.port, - protocol: 'http' - } - + it 'shows the new issue page', :js do find('.new-project-item-select-button').trigger('click') wait_for_requests find('.select2-results li').click @@ -97,8 +89,6 @@ RSpec.describe 'Dashboard Issues' do page.within('#content-body') do expect(page).to have_selector('.issue-form') end - - Gitlab::Application.routes.default_url_options = original_defaults end end end diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index 7fcbeb459e0..c6ceb092810 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -21,7 +21,7 @@ describe ProjectWiki do describe '#web_url' do it 'returns the full web URL to the wiki' do - expect(subject.web_url).to match("https?://[^\/]+/#{project.path_with_namespace}/wikis/home") + expect(subject.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/wikis/home") end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e7329210896..85335643921 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -59,6 +59,7 @@ RSpec.configure do |config| config.include Gitlab::Routing, type: :routing config.include MigrationsHelpers, :migration config.include StubFeatureFlags + config.include StubENV config.infer_spec_type_from_file_location! diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index 3e5d6cf1364..c45c4a4310d 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -36,7 +36,14 @@ RSpec.configure do |config| $capybara_server_already_started = true end - config.after(:each, :js) do |example| + config.before(:example, :js) do + allow(Gitlab::Application.routes).to receive(:default_url_options).and_return( + host: Capybara.current_session.server.host, + port: Capybara.current_session.server.port, + protocol: 'http') + end + + config.after(:example, :js) do |example| # capybara/rspec already calls Capybara.reset_sessions! in an `after` hook, # but `block_and_wait_for_requests_complete` is called before it so by # calling it explicitely here, we prevent any new requests from being fired -- cgit v1.2.1 From 0e355e5c9293c712b5df65896371af0ba71c19b2 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 27 Jul 2017 14:58:02 +0200 Subject: Load and process at most 100 commits when pushing into default branch --- app/services/git_push_service.rb | 31 +++++++++++++++------- .../unreleased/dm-large-push-performance.yml | 4 +++ lib/gitlab/data_builder/push.rb | 4 +-- spec/services/git_push_service_spec.rb | 6 ++--- 4 files changed, 29 insertions(+), 16 deletions(-) create mode 100644 changelogs/unreleased/dm-large-push-performance.yml diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index 20d1fb29289..57ce2a472aa 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -45,6 +45,7 @@ class GitPushService < BaseService elsif push_to_existing_branch? # Collect data for this git push @push_commits = @project.repository.commits_between(params[:oldrev], params[:newrev]) + process_commit_messages # Update the bare repositories info/attributes file using the contents of the default branches @@ -64,15 +65,21 @@ class GitPushService < BaseService def update_caches if is_default_branch? - paths = Set.new + if push_to_new_branch? + # If this is the initial push into the default branch, the file type caches + # will already be reset as a result of `Project#change_head`. + types = [] + else + paths = Set.new - @push_commits.each do |commit| - commit.raw_deltas.each do |diff| - paths << diff.new_path + @push_commits.last(PROCESS_COMMIT_LIMIT).each do |commit| + commit.raw_deltas.each do |diff| + paths << diff.new_path + end end - end - types = Gitlab::FileDetector.types_in_paths(paths.to_a) + types = Gitlab::FileDetector.types_in_paths(paths.to_a) + end else types = [] end @@ -84,7 +91,7 @@ class GitPushService < BaseService def process_commit_messages default = is_default_branch? - push_commits.last(PROCESS_COMMIT_LIMIT).each do |commit| + @push_commits.last(PROCESS_COMMIT_LIMIT).each do |commit| if commit.matches_cross_reference_regex? ProcessCommitWorker .perform_async(project.id, current_user.id, commit.to_hash, default) @@ -103,7 +110,7 @@ class GitPushService < BaseService EventCreateService.new.push(@project, current_user, build_push_data) Ci::CreatePipelineService.new(@project, current_user, build_push_data).execute(:push) - + SystemHookPushWorker.perform_async(build_push_data.dup, :push_hooks) @project.execute_hooks(build_push_data.dup, :push_hooks) @project.execute_services(build_push_data.dup, :push_hooks) @@ -123,7 +130,10 @@ class GitPushService < BaseService end def process_default_branch - @push_commits = project.repository.commits(params[:newrev]) + @push_commits_count = project.repository.commit_count_for_ref(params[:ref]) + + offset = [@push_commits_count - PROCESS_COMMIT_LIMIT, 0].max + @push_commits = project.repository.commits(params[:newrev], offset: offset, limit: PROCESS_COMMIT_LIMIT) # Ensure HEAD points to the default branch in case it is not master project.change_head(branch_name) @@ -152,7 +162,8 @@ class GitPushService < BaseService params[:oldrev], params[:newrev], params[:ref], - push_commits) + @push_commits, + commits_count: @push_commits_count) end def push_to_existing_branch? diff --git a/changelogs/unreleased/dm-large-push-performance.yml b/changelogs/unreleased/dm-large-push-performance.yml new file mode 100644 index 00000000000..f5fe1bd3b28 --- /dev/null +++ b/changelogs/unreleased/dm-large-push-performance.yml @@ -0,0 +1,4 @@ +--- +title: Improve performance of large (initial) push into default branch +merge_request: +author: diff --git a/lib/gitlab/data_builder/push.rb b/lib/gitlab/data_builder/push.rb index 8c8729b6557..5c5f507d44d 100644 --- a/lib/gitlab/data_builder/push.rb +++ b/lib/gitlab/data_builder/push.rb @@ -24,11 +24,11 @@ module Gitlab # total_commits_count: Fixnum # } # - def build(project, user, oldrev, newrev, ref, commits = [], message = nil) + def build(project, user, oldrev, newrev, ref, commits = [], message = nil, commits_count: nil) commits = Array(commits) # Total commits count - commits_count = commits.size + commits_count ||= commits.size # Get latest 20 commits ASC commits_limited = commits.last(20) diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index f801506f1b6..cf9e63676b7 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -663,8 +663,7 @@ describe GitPushService, services: true do end it 'only schedules a limited number of commits' do - allow(service).to receive(:push_commits) - .and_return(Array.new(1000, double(:commit, to_hash: {}, matches_cross_reference_regex?: true))) + service.push_commits = Array.new(1000, double(:commit, to_hash: {}, matches_cross_reference_regex?: true)) expect(ProcessCommitWorker).to receive(:perform_async).exactly(100).times @@ -672,8 +671,7 @@ describe GitPushService, services: true do end it "skips commits which don't include cross-references" do - allow(service).to receive(:push_commits) - .and_return([double(:commit, to_hash: {}, matches_cross_reference_regex?: false)]) + service.push_commits = [double(:commit, to_hash: {}, matches_cross_reference_regex?: false)] expect(ProcessCommitWorker).not_to receive(:perform_async) -- cgit v1.2.1 From 9442c33584d9667551447aa2d579aec03fb18d50 Mon Sep 17 00:00:00 2001 From: Athar Hameed Date: Fri, 28 Jul 2017 15:23:40 +0000 Subject: Fix 500 error when rendering avatar for deleted project creator --- app/views/shared/projects/_project.html.haml | 2 +- ...n-rendering-avatar-for-deleted-project-creator.yml | 4 ++++ spec/views/shared/projects/_project.html.haml_spec.rb | 19 +++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/fix-500-error-when-rendering-avatar-for-deleted-project-creator.yml create mode 100644 spec/views/shared/projects/_project.html.haml_spec.rb diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml index 4bdbc26a4c3..f4f155c8d94 100644 --- a/app/views/shared/projects/_project.html.haml +++ b/app/views/shared/projects/_project.html.haml @@ -14,7 +14,7 @@ - if avatar .avatar-container.s40 = link_to project_path(project), class: dom_class(project) do - - if use_creator_avatar + - if project.creator && use_creator_avatar = image_tag avatar_icon(project.creator.email, 40), class: "avatar s40", alt:'' - else = project_icon(project, alt: '', class: 'avatar project-avatar s40') diff --git a/changelogs/unreleased/fix-500-error-when-rendering-avatar-for-deleted-project-creator.yml b/changelogs/unreleased/fix-500-error-when-rendering-avatar-for-deleted-project-creator.yml new file mode 100644 index 00000000000..be6f1ea00fb --- /dev/null +++ b/changelogs/unreleased/fix-500-error-when-rendering-avatar-for-deleted-project-creator.yml @@ -0,0 +1,4 @@ +--- +title: Modify if condition to be more readable +merge_request: +author: diff --git a/spec/views/shared/projects/_project.html.haml_spec.rb b/spec/views/shared/projects/_project.html.haml_spec.rb new file mode 100644 index 00000000000..43334c2c236 --- /dev/null +++ b/spec/views/shared/projects/_project.html.haml_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe 'shared/projects/_project.html.haml' do + let(:project) { create(:empty_project) } + + it 'should render creator avatar if project has a creator' do + render 'shared/projects/project', use_creator_avatar: true, project: project + + expect(rendered).to have_selector('img.avatar') + end + + it 'should render a generic avatar if project does not have a creator' do + project.creator = nil + + render 'shared/projects/project', use_creator_avatar: true, project: project + + expect(rendered).to have_selector('.project-avatar') + end +end -- cgit v1.2.1 From 75d04f6a29a5506ffd53c227517411febdc54910 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 27 Jul 2017 15:36:39 +0100 Subject: Fix replying to commit comments on MRs from forks A commit comment shows in the MR, but if the MR is from a fork, it will have a different project ID to the MR's target project. In that case, add an note_project_id param so that we can pick the correct project for the note. --- app/assets/javascripts/notes.js | 4 ++ app/controllers/concerns/notes_actions.rb | 22 +++++++- app/helpers/notes_helper.rb | 6 ++- app/views/shared/notes/_form.html.haml | 1 + ...-replying-to-commit-comment-in-mr-from-fork.yml | 4 ++ spec/controllers/projects/notes_controller_spec.rb | 62 +++++++++++++++++++++- .../merge_requests/created_from_fork_spec.rb | 27 ++++++++++ 7 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/fix-replying-to-commit-comment-in-mr-from-fork.yml diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index b2c503d1656..dfa07a2def4 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -529,6 +529,7 @@ export default class Notes { form.find('#note_line_code').remove(); form.find('#note_position').remove(); form.find('#note_type').val(''); + form.find('#note_project_id').remove(); form.find('#in_reply_to_discussion_id').remove(); form.find('.js-comment-resolve-button').closest('comment-and-resolve-btn').remove(); this.parentTimeline = form.parents('.timeline'); @@ -556,6 +557,7 @@ export default class Notes { form.find('#note_noteable_id').val(), form.find('#note_commit_id').val(), form.find('#note_type').val(), + form.find('#note_project_id').val(), form.find('#in_reply_to_discussion_id').val(), // LegacyDiffNote @@ -848,6 +850,8 @@ export default class Notes { form.find('#in_reply_to_discussion_id').val(discussionID); } + form.find('#note_project_id').val(dataHolder.data('discussionProjectId')); + form.attr('data-line-code', dataHolder.data('lineCode')); form.find('#line_type').val(dataHolder.data('lineType')); diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb index a57d9e6e6c0..af5f683bab5 100644 --- a/app/controllers/concerns/notes_actions.rb +++ b/app/controllers/concerns/notes_actions.rb @@ -4,6 +4,7 @@ module NotesActions included do before_action :authorize_admin_note!, only: [:update, :destroy] + before_action :note_project, only: [:create] end def index @@ -28,7 +29,8 @@ module NotesActions merge_request_diff_head_sha: params[:merge_request_diff_head_sha], in_reply_to_discussion_id: params[:in_reply_to_discussion_id] ) - @note = Notes::CreateService.new(project, current_user, create_params).execute + + @note = Notes::CreateService.new(note_project, current_user, create_params).execute if @note.is_a?(Note) Banzai::NoteRenderer.render([@note], @project, current_user) @@ -177,4 +179,22 @@ module NotesActions def notes_finder @notes_finder ||= NotesFinder.new(project, current_user, finder_params) end + + def note_project + return @note_project if defined?(@note_project) + return nil unless project + + note_project_id = params[:note_project_id] + + @note_project = + if note_project_id.present? + Project.find(note_project_id) + else + project + end + + return access_denied! unless can?(current_user, :create_note, @note_project) + + @note_project + end end diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 0a0881d95cf..8f4e39b8b23 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -62,7 +62,11 @@ module NotesHelper def link_to_reply_discussion(discussion, line_type = nil) return unless current_user - data = { discussion_id: discussion.reply_id, line_type: line_type } + data = { + discussion_id: discussion.reply_id, + discussion_project_id: discussion.project&.id, + line_type: line_type + } button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button', data: data, title: 'Add a reply' diff --git a/app/views/shared/notes/_form.html.haml b/app/views/shared/notes/_form.html.haml index c6b5dcc3647..725bf916592 100644 --- a/app/views/shared/notes/_form.html.haml +++ b/app/views/shared/notes/_form.html.haml @@ -10,6 +10,7 @@ = hidden_field_tag :line_type = hidden_field_tag :merge_request_diff_head_sha, @note.noteable.try(:diff_head_sha) = hidden_field_tag :in_reply_to_discussion_id + = hidden_field_tag :note_project_id = note_target_fields(@note) = f.hidden_field :noteable_type diff --git a/changelogs/unreleased/fix-replying-to-commit-comment-in-mr-from-fork.yml b/changelogs/unreleased/fix-replying-to-commit-comment-in-mr-from-fork.yml new file mode 100644 index 00000000000..f4136460626 --- /dev/null +++ b/changelogs/unreleased/fix-replying-to-commit-comment-in-mr-from-fork.yml @@ -0,0 +1,4 @@ +--- +title: Fix replying to commit comments on merge requests created from forks +merge_request: +author: diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb index 45f4cf9180d..3b88d5b0d7d 100644 --- a/spec/controllers/projects/notes_controller_spec.rb +++ b/spec/controllers/projects/notes_controller_spec.rb @@ -131,7 +131,7 @@ describe Projects::NotesController do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end it "returns status 302 for html" do @@ -165,6 +165,66 @@ describe Projects::NotesController do expect(response).to have_http_status(302) end end + + context 'when creating a commit comment from an MR fork' do + let(:project) { create(:project) } + + let(:fork_project) do + create(:project).tap do |fork| + create(:forked_project_link, forked_to_project: fork, forked_from_project: project) + end + end + + let(:merge_request) do + create(:merge_request, source_project: fork_project, target_project: project, source_branch: 'feature', target_branch: 'master') + end + + let(:existing_comment) do + create(:note_on_commit, note: 'a note', project: fork_project, commit_id: merge_request.commit_shas.first) + end + + def post_create(extra_params = {}) + post :create, { + note: { note: 'some other note' }, + namespace_id: project.namespace, + project_id: project, + target_type: 'merge_request', + target_id: merge_request.id, + note_project_id: fork_project.id, + in_reply_to_discussion_id: existing_comment.discussion_id + }.merge(extra_params) + end + + context 'when the note_project_id is not correct' do + it 'returns a 404' do + post_create(note_project_id: Project.maximum(:id).succ) + + expect(response).to have_http_status(404) + end + end + + context 'when the user has no access to the fork' do + it 'returns a 404' do + post_create + + expect(response).to have_http_status(404) + end + end + + context 'when the user has access to the fork' do + let(:discussion) { fork_project.notes.find_discussion(existing_comment.discussion_id) } + + before do + fork_project.add_developer(user) + + existing_comment + end + + it 'creates the note' do + expect { post_create }.to change { fork_project.notes.count }.by(1) + end + end + end end describe 'DELETE destroy' do diff --git a/spec/features/merge_requests/created_from_fork_spec.rb b/spec/features/merge_requests/created_from_fork_spec.rb index 9b7795ace62..d706d01dde0 100644 --- a/spec/features/merge_requests/created_from_fork_spec.rb +++ b/spec/features/merge_requests/created_from_fork_spec.rb @@ -25,6 +25,33 @@ feature 'Merge request created from fork' do expect(page).to have_content 'Test merge request' end + context 'when a commit comment exists on the merge request' do + given(:comment) { 'A commit comment' } + given(:reply) { 'A reply comment' } + + background do + create(:note_on_commit, note: comment, + project: fork_project, + commit_id: merge_request.commit_shas.first) + end + + scenario 'user can reply to the comment', js: true do + visit_merge_request(merge_request) + + expect(page).to have_content(comment) + + page.within('.discussion-notes') do + find('.btn-text-field').click + find('#note_note').send_keys(reply) + find('.comment-btn').click + end + + wait_for_requests + + expect(page).to have_content(reply) + end + end + context 'source project is deleted' do background do MergeRequests::MergeService.new(project, user).execute(merge_request) -- cgit v1.2.1 From 05f90b861fbc60cba1912e6a74cb7a4c126e6b7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kim=20=22BKC=22=20Carlb=C3=A4cker?= Date: Wed, 19 Jul 2017 17:34:14 +0200 Subject: Migrate GitGarbageCollectWorker to Gitaly --- app/workers/git_garbage_collect_worker.rb | 39 ++++++++++++++++++- lib/gitlab/gitaly_client/repository_service.rb | 18 ++++++++- spec/workers/git_garbage_collect_worker_spec.rb | 52 ++++++++++++++++++++----- 3 files changed, 97 insertions(+), 12 deletions(-) diff --git a/app/workers/git_garbage_collect_worker.rb b/app/workers/git_garbage_collect_worker.rb index d369b639ae9..c95497dfaba 100644 --- a/app/workers/git_garbage_collect_worker.rb +++ b/app/workers/git_garbage_collect_worker.rb @@ -5,6 +5,12 @@ class GitGarbageCollectWorker sidekiq_options retry: false + GITALY_MIGRATED_TASKS = { + gc: :garbage_collect, + full_repack: :repack_full, + incremental_repack: :repack_incremental + }.freeze + def perform(project_id, task = :gc, lease_key = nil, lease_uuid = nil) project = Project.find(project_id) task = task.to_sym @@ -15,8 +21,14 @@ class GitGarbageCollectWorker Gitlab::GitLogger.info(description) - output, status = Gitlab::Popen.popen(cmd, repo_path) - Gitlab::GitLogger.error("#{description} failed:\n#{output}") unless status.zero? + gitaly_migrate(GITALY_MIGRATED_TASKS[task]) do |is_enabled| + if is_enabled + gitaly_call(task, project.repository.raw_repository) + else + output, status = Gitlab::Popen.popen(cmd, repo_path) + Gitlab::GitLogger.error("#{description} failed:\n#{output}") unless status.zero? + end + end # Refresh the branch cache in case garbage collection caused a ref lookup to fail flush_ref_caches(project) if task == :gc @@ -26,6 +38,19 @@ class GitGarbageCollectWorker private + ## `repository` has to be a Gitlab::Git::Repository + def gitaly_call(task, repository) + client = Gitlab::GitalyClient::RepositoryService.new(repository) + case task + when :gc + client.garbage_collect(bitmaps_enabled?) + when :full_repack + client.repack_full(bitmaps_enabled?) + when :incremental_repack + client.repack_incremental + end + end + def command(task) case task when :gc @@ -55,4 +80,14 @@ class GitGarbageCollectWorker config_value = write_bitmaps ? 'true' : 'false' %W[git -c repack.writeBitmaps=#{config_value}] end + + def gitaly_migrate(method, &block) + Gitlab::GitalyClient.migrate(method, &block) + rescue GRPC::NotFound => e + Gitlab::GitLogger.error("#{method} failed:\nRepository not found") + raise Gitlab::Git::Repository::NoRepository.new(e) + rescue GRPC::BadStatus => e + Gitlab::GitLogger.error("#{method} failed:\n#{e}") + raise Gitlab::Git::CommandError.new(e) + end end diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb index f5d84ea8762..13e75b256a7 100644 --- a/lib/gitlab/gitaly_client/repository_service.rb +++ b/lib/gitlab/gitaly_client/repository_service.rb @@ -4,12 +4,28 @@ module Gitlab def initialize(repository) @repository = repository @gitaly_repo = repository.gitaly_repository + @storage = repository.storage end def exists? request = Gitaly::RepositoryExistsRequest.new(repository: @gitaly_repo) - GitalyClient.call(@repository.storage, :repository_service, :exists, request).exists + GitalyClient.call(@storage, :repository_service, :exists, request).exists + end + + def garbage_collect(create_bitmap) + request = Gitaly::GarbageCollectRequest.new(repository: @gitaly_repo, create_bitmap: create_bitmap) + GitalyClient.call(@storage, :repository_service, :garbage_collect, request) + end + + def repack_full(create_bitmap) + request = Gitaly::RepackFullRequest.new(repository: @gitaly_repo, create_bitmap: create_bitmap) + GitalyClient.call(@storage, :repository_service, :repack_full, request) + end + + def repack_incremental + request = Gitaly::RepackIncrementalRequest.new(repository: @gitaly_repo) + GitalyClient.call(@storage, :repository_service, :repack_incremental, request) end end end diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb index 309b3172da1..05f971dfd13 100644 --- a/spec/workers/git_garbage_collect_worker_spec.rb +++ b/spec/workers/git_garbage_collect_worker_spec.rb @@ -9,17 +9,51 @@ describe GitGarbageCollectWorker do subject { described_class.new } describe "#perform" do - it "flushes ref caches when the task is 'gc'" do - expect(subject).to receive(:command).with(:gc).and_return([:the, :command]) - expect(Gitlab::Popen).to receive(:popen) - .with([:the, :command], project.repository.path_to_repo).and_return(["", 0]) + shared_examples 'flushing ref caches' do |gitaly| + it "flushes ref caches when the task if 'gc'" do + expect(subject).to receive(:command).with(:gc).and_return([:the, :command]) + + if gitaly + expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:garbage_collect) + .and_return(nil) + else + expect(Gitlab::Popen).to receive(:popen) + .with([:the, :command], project.repository.path_to_repo).and_return(["", 0]) + end + + expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original + expect_any_instance_of(Repository).to receive(:branch_names).and_call_original + expect_any_instance_of(Repository).to receive(:branch_count).and_call_original + expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original + + subject.perform(project.id) + end + end + + context "with Gitaly turned on" do + it_should_behave_like 'flushing ref caches', true + end + + context "with Gitaly turned off", skip_gitaly_mock: true do + it_should_behave_like 'flushing ref caches', false + end - expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original - expect_any_instance_of(Repository).to receive(:branch_names).and_call_original - expect_any_instance_of(Repository).to receive(:branch_count).and_call_original - expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original + context "repack_full" do + it "calls Gitaly" do + expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:repack_full) + .and_return(nil) - subject.perform(project.id) + subject.perform(project.id, :full_repack) + end + end + + context "repack_incremental" do + it "calls Gitaly" do + expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:repack_incremental) + .and_return(nil) + + subject.perform(project.id, :incremental_repack) + end end shared_examples 'gc tasks' do -- cgit v1.2.1 From 04e4210785ffd088458e24f08a9f94376558c0dc Mon Sep 17 00:00:00 2001 From: Dan Dunckel Date: Fri, 28 Jul 2017 09:52:37 -0600 Subject: Update documentation of user creation by replacing the 'confirm' param with 'skip_confirmation' --- doc/api/users.md | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/doc/api/users.md b/doc/api/users.md index 6e5ec3231c5..57a13eb477d 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -241,26 +241,26 @@ POST /users Parameters: -- `email` (required) - Email -- `password` (optional) - Password -- `reset_password` (optional) - Send user password reset link - true or false(default) -- `username` (required) - Username -- `name` (required) - Name -- `skype` (optional) - Skype ID -- `linkedin` (optional) - LinkedIn -- `twitter` (optional) - Twitter account -- `website_url` (optional) - Website URL -- `organization` (optional) - Organization name -- `projects_limit` (optional) - Number of projects user can create -- `extern_uid` (optional) - External UID -- `provider` (optional) - External provider name -- `bio` (optional) - User's biography -- `location` (optional) - User's location -- `admin` (optional) - User is admin - true or false (default) -- `can_create_group` (optional) - User can create groups - true or false -- `confirm` (optional) - Require confirmation - true (default) or false -- `external` (optional) - Flags the user as external - true or false(default) -- `avatar` (optional) - Image file for user's avatar +- `email` (required) - Email +- `password` (optional) - Password +- `reset_password` (optional) - Send user password reset link - true or false(default) +- `username` (required) - Username +- `name` (required) - Name +- `skype` (optional) - Skype ID +- `linkedin` (optional) - LinkedIn +- `twitter` (optional) - Twitter account +- `website_url` (optional) - Website URL +- `organization` (optional) - Organization name +- `projects_limit` (optional) - Number of projects user can create +- `extern_uid` (optional) - External UID +- `provider` (optional) - External provider name +- `bio` (optional) - User's biography +- `location` (optional) - User's location +- `admin` (optional) - User is admin - true or false (default) +- `can_create_group` (optional) - User can create groups - true or false +- `skip_confirmation` (optional) - Skip confirmation - true or false (default) +- `external` (optional) - Flags the user as external - true or false(default) +- `avatar` (optional) - Image file for user's avatar ## User modification -- cgit v1.2.1 From c734aa8608a82a4b263042b0f4d8d71fd21562cd Mon Sep 17 00:00:00 2001 From: tauriedavis Date: Mon, 27 Mar 2017 12:49:19 -0700 Subject: Add copy about search terms to ux guide --- doc/development/ux_guide/copy.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/development/ux_guide/copy.md b/doc/development/ux_guide/copy.md index 794c8eb6bfe..12e8d0a31bb 100644 --- a/doc/development/ux_guide/copy.md +++ b/doc/development/ux_guide/copy.md @@ -106,6 +106,14 @@ When using verbs or adjectives: * If the context clearly refers to the object, use them alone. Example: `Edit` or `Closed` * If the context isn’t clear enough, use them with the object. Example: `Edit issue` or `Closed issues` +### Search + +| Term | Use | +| ---- | --- | +| Search | When using all metadata to add criteria that match/don't match. Search can also affect ordering, by ranking best results. | +| Filter | When taking a single criteria that removes items within a list that match/don't match. Filters do not affect ordering. | +| Sort | Orders a list based on a single or grouped criteria | + ### Projects and Groups | Term | Use | :no_entry_sign: Don't | -- cgit v1.2.1 From a2ba403e27183073ad9a4894cfe6c39f94e63964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 28 Jul 2017 18:19:25 +0200 Subject: Fix a spec that was assuming to be on the wrong page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/features/issues/create_branch_merge_request_spec.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/spec/features/issues/create_branch_merge_request_spec.rb b/spec/features/issues/create_branch_merge_request_spec.rb index c10b99a4386..f59f687cf51 100644 --- a/spec/features/issues/create_branch_merge_request_spec.rb +++ b/spec/features/issues/create_branch_merge_request_spec.rb @@ -15,16 +15,14 @@ feature 'Create Branch/Merge Request Dropdown on issue page', js: true do visit project_issue_path(project, issue) select_dropdown_option('create-mr') + + expect(page).to have_content('WIP: Resolve "Cherry-Coloured Funk"') + expect(current_path).to eq(project_merge_request_path(project, MergeRequest.first)) - wait_for_requests + visit project_issue_path(project, issue) expect(page).to have_content("created branch 1-cherry-coloured-funk") expect(page).to have_content("mentioned in merge request !1") - - visit project_merge_request_path(project, MergeRequest.first) - - expect(page).to have_content('WIP: Resolve "Cherry-Coloured Funk"') - expect(current_path).to eq(project_merge_request_path(project, MergeRequest.first)) end it 'allows creating a branch from the issue page' do -- cgit v1.2.1 From e77e9b0077bb49aa05a16a3d04690219b2c8205e Mon Sep 17 00:00:00 2001 From: Richard Clamp Date: Fri, 28 Jul 2017 16:27:10 +0000 Subject: Fixup POST /v3/:id/hooks and PUT /v3/:id/hooks/:hook_id --- changelogs/unreleased/12673-fix_v3_project_hooks_build_events | 4 ++++ lib/api/v3/project_hooks.rb | 8 ++++++-- spec/requests/api/v3/project_hooks_spec.rb | 6 +++--- 3 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 changelogs/unreleased/12673-fix_v3_project_hooks_build_events diff --git a/changelogs/unreleased/12673-fix_v3_project_hooks_build_events b/changelogs/unreleased/12673-fix_v3_project_hooks_build_events new file mode 100644 index 00000000000..59bc646406f --- /dev/null +++ b/changelogs/unreleased/12673-fix_v3_project_hooks_build_events @@ -0,0 +1,4 @@ +--- +title: "Fix v3 api project_hooks POST and PUT operations for build_events" +merge_request: 12673 +author: Richard Clamp diff --git a/lib/api/v3/project_hooks.rb b/lib/api/v3/project_hooks.rb index 94614bfc8b6..51014591a93 100644 --- a/lib/api/v3/project_hooks.rb +++ b/lib/api/v3/project_hooks.rb @@ -56,7 +56,9 @@ module API use :project_hook_properties end post ":id/hooks" do - hook = user_project.hooks.new(declared_params(include_missing: false)) + attrs = declared_params(include_missing: false) + attrs[:job_events] = attrs.delete(:build_events) if attrs.key?(:build_events) + hook = user_project.hooks.new(attrs) if hook.save present hook, with: ::API::V3::Entities::ProjectHook @@ -77,7 +79,9 @@ module API put ":id/hooks/:hook_id" do hook = user_project.hooks.find(params.delete(:hook_id)) - if hook.update_attributes(declared_params(include_missing: false)) + attrs = declared_params(include_missing: false) + attrs[:job_events] = attrs.delete(:build_events) if attrs.key?(:build_events) + if hook.update_attributes(attrs) present hook, with: ::API::V3::Entities::ProjectHook else error!("Invalid url given", 422) if hook.errors[:url].present? diff --git a/spec/requests/api/v3/project_hooks_spec.rb b/spec/requests/api/v3/project_hooks_spec.rb index 1969d1c7f2b..b0eddbb5dd2 100644 --- a/spec/requests/api/v3/project_hooks_spec.rb +++ b/spec/requests/api/v3/project_hooks_spec.rb @@ -87,7 +87,7 @@ describe API::ProjectHooks, 'ProjectHooks' do it "adds hook to project" do expect do post v3_api("/projects/#{project.id}/hooks", user), - url: "http://example.com", issues_events: true, wiki_page_events: true + url: "http://example.com", issues_events: true, wiki_page_events: true, build_events: true end.to change {project.hooks.count}.by(1) expect(response).to have_http_status(201) @@ -97,7 +97,7 @@ describe API::ProjectHooks, 'ProjectHooks' do expect(json_response['merge_requests_events']).to eq(false) expect(json_response['tag_push_events']).to eq(false) expect(json_response['note_events']).to eq(false) - expect(json_response['build_events']).to eq(false) + expect(json_response['build_events']).to eq(true) expect(json_response['pipeline_events']).to eq(false) expect(json_response['wiki_page_events']).to eq(true) expect(json_response['enable_ssl_verification']).to eq(true) @@ -135,7 +135,7 @@ describe API::ProjectHooks, 'ProjectHooks' do describe "PUT /projects/:id/hooks/:hook_id" do it "updates an existing project hook" do put v3_api("/projects/#{project.id}/hooks/#{hook.id}", user), - url: 'http://example.org', push_events: false + url: 'http://example.org', push_events: false, build_events: true expect(response).to have_http_status(200) expect(json_response['url']).to eq('http://example.org') expect(json_response['issues_events']).to eq(hook.issues_events) -- cgit v1.2.1 From 8aaaefa5f68914613ab02a18c20244e733930fa8 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 28 Jul 2017 12:52:40 -0400 Subject: Fix spec/features/projects/branches_spec See https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8666 --- spec/features/projects/branches_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb index 6e787de2dd6..ad4527a0b74 100644 --- a/spec/features/projects/branches_spec.rb +++ b/spec/features/projects/branches_spec.rb @@ -29,7 +29,7 @@ describe 'Branches' do it 'sorts the branches by name' do visit project_branches_path(project) - click_button "Name" # Open sorting dropdown + click_button "Last updated" # Open sorting dropdown click_link "Name" sorted = repository.branches_sorted_by(:name).first(20).map do |branch| @@ -41,7 +41,7 @@ describe 'Branches' do it 'sorts the branches by last updated' do visit project_branches_path(project) - click_button "Name" # Open sorting dropdown + click_button "Last updated" # Open sorting dropdown click_link "Last updated" sorted = repository.branches_sorted_by(:updated_desc).first(20).map do |branch| @@ -53,7 +53,7 @@ describe 'Branches' do it 'sorts the branches by oldest updated' do visit project_branches_path(project) - click_button "Name" # Open sorting dropdown + click_button "Last updated" # Open sorting dropdown click_link "Oldest updated" sorted = repository.branches_sorted_by(:updated_asc).first(20).map do |branch| -- cgit v1.2.1 From ebd5f5148894888c118e95239fc437141c8e6b41 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 28 Jul 2017 12:49:07 -0500 Subject: fix relative_url_root support for webpack chunks --- app/helpers/webpack_helper.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/helpers/webpack_helper.rb b/app/helpers/webpack_helper.rb index 0386df22374..33453dd178f 100644 --- a/app/helpers/webpack_helper.rb +++ b/app/helpers/webpack_helper.rb @@ -34,6 +34,8 @@ module WebpackHelper end def webpack_public_path - "#{webpack_public_host}/#{Rails.application.config.webpack.public_path}/" + relative_path = Rails.application.config.relative_url_root + webpack_path = Rails.application.config.webpack.public_path + File.join(webpack_public_host.to_s, relative_path.to_s, webpack_path.to_s, '') end end -- cgit v1.2.1 From 2307eb80b576b4537e96e551bd17e2eced1d04a3 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 28 Jul 2017 18:55:27 +0100 Subject: Fixed breadcrumb titles aggressively collapsing Closes #35323 --- app/assets/stylesheets/new_nav.scss | 3 ++- changelogs/unreleased/breadcrumbs-collapsed-title-width-fix.yml | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/breadcrumbs-collapsed-title-width-fix.yml diff --git a/app/assets/stylesheets/new_nav.scss b/app/assets/stylesheets/new_nav.scss index 360ffda8d71..781d4cc8833 100644 --- a/app/assets/stylesheets/new_nav.scss +++ b/app/assets/stylesheets/new_nav.scss @@ -325,6 +325,7 @@ header.navbar-gitlab-new { .breadcrumbs-links { flex: 1; + min-width: 0; align-self: center; color: $gl-text-color-quaternary; @@ -343,7 +344,7 @@ header.navbar-gitlab-new { } .title { - white-space: nowrap; + display: inline-block; > a { &:last-of-type:not(:first-child) { diff --git a/changelogs/unreleased/breadcrumbs-collapsed-title-width-fix.yml b/changelogs/unreleased/breadcrumbs-collapsed-title-width-fix.yml new file mode 100644 index 00000000000..988fdacb5fd --- /dev/null +++ b/changelogs/unreleased/breadcrumbs-collapsed-title-width-fix.yml @@ -0,0 +1,4 @@ +--- +title: Fixed breadcrumbs title aggressively collapsing +merge_request: +author: -- cgit v1.2.1 From eac8ae0fe00bcbb7e3cf04c4d0b6328cb4ddcc62 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 28 Jul 2017 12:56:43 -0500 Subject: add CHANGELOG.md entry for !13165 --- .../unreleased/35567-fix-relative-urls-in-webpack-public-path.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/35567-fix-relative-urls-in-webpack-public-path.yml diff --git a/changelogs/unreleased/35567-fix-relative-urls-in-webpack-public-path.yml b/changelogs/unreleased/35567-fix-relative-urls-in-webpack-public-path.yml new file mode 100644 index 00000000000..41b506681f9 --- /dev/null +++ b/changelogs/unreleased/35567-fix-relative-urls-in-webpack-public-path.yml @@ -0,0 +1,5 @@ +--- +title: Fix asynchronous javascript paths when GitLab is installed under a relative + URL +merge_request: 13165 +author: -- cgit v1.2.1 From b2f91602981ebeeb76e39c87c7f58f1dfa0f60dd Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 28 Jul 2017 15:20:49 -0400 Subject: De-duplicate two specs in spec/services/notification_service_spec There were two specs that were testing the exact same thing as the spec above it, but with additional expectations. So we opted to keep the "more expectations" tests and deleted the duplicates. We've also deleted one nested `before` block that was duplicating setup of its parent context. --- spec/services/notification_service_spec.rb | 47 +++++++----------------------- 1 file changed, 10 insertions(+), 37 deletions(-) diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 49d6fc7853f..5b69426cbaa 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -694,17 +694,6 @@ describe NotificationService do let!(:subscriber_to_label_1) { create(:user) { |u| label_1.toggle_subscription(u, project) } } let!(:subscriber_to_label_2) { create(:user) { |u| label_2.toggle_subscription(u, project) } } - it "emails subscribers of the issue's added labels only" do - notification.relabeled_issue(issue, [group_label_2, label_2], @u_disabled) - - should_not_email(subscriber_to_label_1) - should_not_email(subscriber_to_group_label_1) - should_not_email(subscriber_to_group_label_2_on_another_project) - should_email(subscriber_1_to_group_label_2) - should_email(subscriber_2_to_group_label_2) - should_email(subscriber_to_label_2) - end - it "emails the current user if they've opted into notifications about their activity" do subscriber_to_label_2.notified_of_own_activity = true notification.relabeled_issue(issue, [group_label_2, label_2], subscriber_to_label_2) @@ -721,6 +710,12 @@ describe NotificationService do it "doesn't send email to anyone but subscribers of the given labels" do notification.relabeled_issue(issue, [group_label_2, label_2], @u_disabled) + should_not_email(subscriber_to_label_1) + should_not_email(subscriber_to_group_label_1) + should_not_email(subscriber_to_group_label_2_on_another_project) + should_email(subscriber_1_to_group_label_2) + should_email(subscriber_2_to_group_label_2) + should_email(subscriber_to_label_2) should_not_email(issue.assignees.first) should_not_email(issue.author) should_not_email(@u_watcher) @@ -730,12 +725,6 @@ describe NotificationService do should_not_email(@watcher_and_subscriber) should_not_email(@unsubscriber) should_not_email(@u_participating) - should_not_email(subscriber_to_label_1) - should_not_email(subscriber_to_group_label_1) - should_not_email(subscriber_to_group_label_2_on_another_project) - should_email(subscriber_1_to_group_label_2) - should_email(subscriber_2_to_group_label_2) - should_email(subscriber_to_label_2) end context 'confidential issues' do @@ -878,11 +867,6 @@ describe NotificationService do end describe '#new_merge_request' do - before do - update_custom_notification(:new_merge_request, @u_guest_custom, resource: project) - update_custom_notification(:new_merge_request, @u_custom_global) - end - it do notification.new_merge_request(merge_request, @u_disabled) @@ -1008,7 +992,7 @@ describe NotificationService do let!(:subscriber_to_label_1) { create(:user) { |u| label_1.toggle_subscription(u, project) } } let!(:subscriber_to_label_2) { create(:user) { |u| label_2.toggle_subscription(u, project) } } - it "emails subscribers of the merge request's added labels only" do + it "doesn't send email to anyone but subscribers of the given labels" do notification.relabeled_merge_request(merge_request, [group_label_2, label_2], @u_disabled) should_not_email(subscriber_to_label_1) @@ -1017,11 +1001,6 @@ describe NotificationService do should_email(subscriber_1_to_group_label_2) should_email(subscriber_2_to_group_label_2) should_email(subscriber_to_label_2) - end - - it "doesn't send email to anyone but subscribers of the given labels" do - notification.relabeled_merge_request(merge_request, [group_label_2, label_2], @u_disabled) - should_not_email(merge_request.assignee) should_not_email(merge_request.author) should_not_email(@u_watcher) @@ -1031,12 +1010,6 @@ describe NotificationService do should_not_email(@unsubscriber) should_not_email(@u_participating) should_not_email(@u_lazy_participant) - should_not_email(subscriber_to_label_1) - should_not_email(subscriber_to_group_label_1) - should_not_email(subscriber_to_group_label_2_on_another_project) - should_email(subscriber_1_to_group_label_2) - should_email(subscriber_2_to_group_label_2) - should_email(subscriber_to_label_2) end end @@ -1081,12 +1054,12 @@ describe NotificationService do should_email(merge_request.assignee) should_email(@u_watcher) + should_email(@u_guest_watcher) + should_email(@u_guest_custom) + should_email(@u_custom_global) should_email(@u_participant_mentioned) should_email(@subscriber) should_email(@watcher_and_subscriber) - should_email(@u_guest_watcher) - should_email(@u_custom_global) - should_email(@u_guest_custom) should_not_email(@unsubscriber) should_not_email(@u_participating) should_not_email(@u_disabled) -- cgit v1.2.1 From a07fe9d7f8f922020472ed54b060430a6da3da69 Mon Sep 17 00:00:00 2001 From: Alex Ives Date: Mon, 24 Jul 2017 22:11:22 -0500 Subject: Fixes #29385: Add /shrug and /tableflip commands - Updated DSL to support substitution definitions - Added substitution definition, inherits from command definition - Added tabelflip and shrug substitutions to interpret service - Added support for substitution definitions to the extractor for preview mode. - Added substitution handling in the interpret service Signed-off-by: Alex Ives --- app/services/quick_actions/interpret_service.rb | 16 +++++++++ changelogs/unreleased/29385-add_shrug_command.yml | 4 +++ lib/gitlab/quick_actions/dsl.rb | 29 ++++++++++++--- lib/gitlab/quick_actions/extractor.rb | 22 ++++++++++++ .../quick_actions/substitution_definition.rb | 24 +++++++++++++ spec/lib/gitlab/quick_actions/dsl_spec.rb | 16 ++++++++- spec/lib/gitlab/quick_actions/extractor_spec.rb | 37 +++++++++++++++++++ .../quick_actions/substitution_definition_spec.rb | 42 ++++++++++++++++++++++ .../quick_actions/interpret_service_spec.rb | 42 +++++++++++++++++++++- 9 files changed, 225 insertions(+), 7 deletions(-) create mode 100644 changelogs/unreleased/29385-add_shrug_command.yml create mode 100644 lib/gitlab/quick_actions/substitution_definition.rb create mode 100644 spec/lib/gitlab/quick_actions/substitution_definition_spec.rb diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb index 5dc1b91d2c0..c22bf7498bb 100644 --- a/app/services/quick_actions/interpret_service.rb +++ b/app/services/quick_actions/interpret_service.rb @@ -4,6 +4,9 @@ module QuickActions attr_reader :issuable + SHRUG = '¯\\_(ツ)_/¯'.freeze + TABLEFLIP = '(╯°□°)╯︵ ┻━┻'.freeze + # Takes a text and interprets the commands that are extracted from it. # Returns the content without commands, and hash of changes to be applied to a record. def execute(content, issuable) @@ -14,6 +17,7 @@ module QuickActions content, commands = extractor.extract_commands(content, context) extract_updates(commands, context) + [content, @updates] end @@ -423,6 +427,18 @@ module QuickActions @updates[:spend_time] = { duration: :reset, user: current_user } end + desc "Append the comment with #{SHRUG}" + params '' + substitution :shrug do |comment| + "#{comment} #{SHRUG}" + end + + desc "Append the comment with #{TABLEFLIP}" + params '' + substitution :tableflip do |comment| + "#{comment} #{TABLEFLIP}" + end + # This is a dummy command, so that it appears in the autocomplete commands desc 'CC' params '@user' diff --git a/changelogs/unreleased/29385-add_shrug_command.yml b/changelogs/unreleased/29385-add_shrug_command.yml new file mode 100644 index 00000000000..14b8f486d5c --- /dev/null +++ b/changelogs/unreleased/29385-add_shrug_command.yml @@ -0,0 +1,4 @@ +--- +title: Add /shrug and /tableflip commands +merge_request: 10068 +author: Alex Ives diff --git a/lib/gitlab/quick_actions/dsl.rb b/lib/gitlab/quick_actions/dsl.rb index a4a97236ffc..536765305e1 100644 --- a/lib/gitlab/quick_actions/dsl.rb +++ b/lib/gitlab/quick_actions/dsl.rb @@ -105,9 +105,32 @@ module Gitlab # # Awesome code block # end def command(*command_names, &block) + define_command(CommandDefinition, *command_names, &block) + end + + # Registers a new substitution which is recognizable from body of email or + # comment. + # It accepts aliases and takes a block with the formatted content. + # + # Example: + # + # command :my_substitution, :alias_for_my_substitution do |text| + # "#{text} MY AWESOME SUBSTITUTION" + # end + def substitution(*substitution_names, &block) + define_command(SubstitutionDefinition, *substitution_names, &block) + end + + def definition_by_name(name) + command_definitions_by_name[name.to_sym] + end + + private + + def define_command(klass, *command_names, &block) name, *aliases = command_names - definition = CommandDefinition.new( + definition = klass.new( name, aliases: aliases, description: @description, @@ -130,10 +153,6 @@ module Gitlab @condition_block = nil @parse_params_block = nil end - - def definition_by_name(name) - command_definitions_by_name[name.to_sym] - end end end end diff --git a/lib/gitlab/quick_actions/extractor.rb b/lib/gitlab/quick_actions/extractor.rb index 09576be7156..3ebfa3bd4b8 100644 --- a/lib/gitlab/quick_actions/extractor.rb +++ b/lib/gitlab/quick_actions/extractor.rb @@ -46,6 +46,8 @@ module Gitlab end end + content, commands = perform_substitutions(content, commands) + [content.strip, commands] end @@ -110,6 +112,26 @@ module Gitlab }mx end + def perform_substitutions(content, commands) + return unless content + + substitution_definitions = self.command_definitions.select do |definition| + definition.is_a?(Gitlab::QuickActions::SubstitutionDefinition) + end + + substitution_definitions.each do |substitution| + match_data = substitution.match(content) + if match_data + command = [substitution.name.to_s] + command << match_data[1] unless match_data[1].empty? + commands << command + end + content = substitution.perform_substitution(self, content) + end + + [content, commands] + end + def command_names(opts) command_definitions.flat_map do |command| next if command.noop? diff --git a/lib/gitlab/quick_actions/substitution_definition.rb b/lib/gitlab/quick_actions/substitution_definition.rb new file mode 100644 index 00000000000..032c49ed159 --- /dev/null +++ b/lib/gitlab/quick_actions/substitution_definition.rb @@ -0,0 +1,24 @@ +module Gitlab + module QuickActions + class SubstitutionDefinition < CommandDefinition + # noop?=>true means these won't get extracted or removed by Gitlab::QuickActions::Extractor#extract_commands + # QuickActions::InterpretService#perform_substitutions handles them separately + def noop? + true + end + + def match(content) + content.match %r{^/#{all_names.join('|')} ?(.*)$} + end + + def perform_substitution(context, content) + return unless content + + all_names.each do |a_name| + content.gsub!(%r{/#{a_name} ?(.*)$}, execute_block(action_block, context, '\1')) + end + content + end + end + end +end diff --git a/spec/lib/gitlab/quick_actions/dsl_spec.rb b/spec/lib/gitlab/quick_actions/dsl_spec.rb index a4bb3f911d7..ff59dc48bcb 100644 --- a/spec/lib/gitlab/quick_actions/dsl_spec.rb +++ b/spec/lib/gitlab/quick_actions/dsl_spec.rb @@ -42,13 +42,18 @@ describe Gitlab::QuickActions::Dsl do command :with_params_parsing do |parsed| parsed end + + params '' + substitution :something do |text| + "#{text} Some complicated thing you want in here" + end end end describe '.command_definitions' do it 'returns an array with commands definitions' do no_args_def, explanation_with_aliases_def, dynamic_description_def, - cc_def, cond_action_def, with_params_parsing_def = + cc_def, cond_action_def, with_params_parsing_def, substitution_def = DummyClass.command_definitions expect(no_args_def.name).to eq(:no_args) @@ -104,6 +109,15 @@ describe Gitlab::QuickActions::Dsl do expect(with_params_parsing_def.condition_block).to be_nil expect(with_params_parsing_def.action_block).to be_a_kind_of(Proc) expect(with_params_parsing_def.parse_params_block).to be_a_kind_of(Proc) + + expect(substitution_def.name).to eq(:something) + expect(substitution_def.aliases).to eq([]) + expect(substitution_def.description).to eq('') + expect(substitution_def.explanation).to eq('') + expect(substitution_def.params).to eq(['']) + expect(substitution_def.condition_block).to be_nil + expect(substitution_def.action_block.call('text')).to eq('text Some complicated thing you want in here') + expect(substitution_def.parse_params_block).to be_nil end end end diff --git a/spec/lib/gitlab/quick_actions/extractor_spec.rb b/spec/lib/gitlab/quick_actions/extractor_spec.rb index 9d32938e155..f7c288f2393 100644 --- a/spec/lib/gitlab/quick_actions/extractor_spec.rb +++ b/spec/lib/gitlab/quick_actions/extractor_spec.rb @@ -9,6 +9,11 @@ describe Gitlab::QuickActions::Extractor do command(:assign) { } command(:labels) { } command(:power) { } + command(:noop_command) + substitution(:substitution) { 'foo' } + substitution :shrug do |comment| + "#{comment} SHRUG" + end end.command_definitions end @@ -177,6 +182,38 @@ describe Gitlab::QuickActions::Extractor do expect(msg).to eq "hello\nworld" end + it 'does not extract noop commands' do + msg = %(hello\nworld\n/reopen\n/noop_command) + msg, commands = extractor.extract_commands(msg) + + expect(commands).to eq [['reopen']] + expect(msg).to eq "hello\nworld\n/noop_command" + end + + it 'extracts and performs substitution commands' do + msg = %(hello\nworld\n/reopen\n/substitution) + msg, commands = extractor.extract_commands(msg) + + expect(commands).to eq [['reopen'], ['substitution']] + expect(msg).to eq "hello\nworld\nfoo" + end + + it 'extracts and performs substitution commands' do + msg = %(hello\nworld\n/reopen\n/shrug this is great?) + msg, commands = extractor.extract_commands(msg) + + expect(commands).to eq [['reopen'], ['shrug', 'this is great?']] + expect(msg).to eq "hello\nworld\nthis is great? SHRUG" + end + + it 'extracts and performs substitution commands with comments' do + msg = %(hello\nworld\n/reopen\n/substitution wow this is a thing.) + msg, commands = extractor.extract_commands(msg) + + expect(commands).to eq [['reopen'], ['substitution', 'wow this is a thing.']] + expect(msg).to eq "hello\nworld\nfoo" + end + it 'extracts multiple commands' do msg = %(hello\n/power @user.name %9.10 ~"bar baz.2" label\nworld\n/reopen) msg, commands = extractor.extract_commands(msg) diff --git a/spec/lib/gitlab/quick_actions/substitution_definition_spec.rb b/spec/lib/gitlab/quick_actions/substitution_definition_spec.rb new file mode 100644 index 00000000000..1bb8bc51c96 --- /dev/null +++ b/spec/lib/gitlab/quick_actions/substitution_definition_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe Gitlab::QuickActions::SubstitutionDefinition do + let(:content) do + < Date: Fri, 28 Jul 2017 10:07:46 +0000 Subject: Merge branch '35643-impersonate-spec' into '9-4-stable-patch-2' Resolve "Impersonation Tokens creation spec failure in admin_users_impersonation_tokens_spec.rb" See merge request !13145 --- spec/features/admin/admin_users_impersonation_tokens_spec.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb index 97ffc54415c..034682dae27 100644 --- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb +++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb @@ -32,11 +32,13 @@ describe 'Admin > Users > Impersonation Tokens', js: true do check "api" check "read_user" - expect { click_on "Create impersonation token" }.to change { PersonalAccessTokensFinder.new(impersonation: true).execute.count } + click_on "Create impersonation token" + expect(active_impersonation_tokens).to have_text(name) expect(active_impersonation_tokens).to have_text('In') expect(active_impersonation_tokens).to have_text('api') expect(active_impersonation_tokens).to have_text('read_user') + expect(PersonalAccessTokensFinder.new(impersonation: true).execute.count).to equal(1) end end -- cgit v1.2.1 From 987b53e321076a3ea53c76819ab777152938c778 Mon Sep 17 00:00:00 2001 From: Florian Lemaitre Date: Fri, 28 Jul 2017 21:41:40 +0000 Subject: Projects logo are not centered vertically on projects page --- app/assets/stylesheets/framework/avatar.scss | 4 ++++ ...044-projects-logo-are-not-centered-vertically-on-projects-page.yml | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 changelogs/unreleased/35044-projects-logo-are-not-centered-vertically-on-projects-page.yml diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss index 0dfa7a31d31..cb41df8a88d 100644 --- a/app/assets/stylesheets/framework/avatar.scss +++ b/app/assets/stylesheets/framework/avatar.scss @@ -88,6 +88,10 @@ overflow: hidden; display: flex; + a { + display: flex; + } + .avatar { border-radius: 0; border: none; diff --git a/changelogs/unreleased/35044-projects-logo-are-not-centered-vertically-on-projects-page.yml b/changelogs/unreleased/35044-projects-logo-are-not-centered-vertically-on-projects-page.yml new file mode 100644 index 00000000000..9de4dbefd35 --- /dev/null +++ b/changelogs/unreleased/35044-projects-logo-are-not-centered-vertically-on-projects-page.yml @@ -0,0 +1,4 @@ +--- +title: Fix project logos that are not centered vertically on list pages +merge_request: 13124 +author: Florian Lemaitre -- cgit v1.2.1 From bab49fdf9f27c44e830c470b749c5bc0022a25f5 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Tue, 25 Jul 2017 16:51:37 -0700 Subject: Protect backups from stale cache for repo exists --- lib/backup/repository.rb | 1 + spec/lib/gitlab/backup/repository_spec.rb | 54 +++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb index a1685c77916..02ed1e49ef8 100644 --- a/lib/backup/repository.rb +++ b/lib/backup/repository.rb @@ -189,6 +189,7 @@ module Backup end def empty_repo?(project_or_wiki) + project_or_wiki.repository.expire_exists_cache # protect backups from stale cache project_or_wiki.repository.empty_repo? rescue => e progress.puts "Ignoring repository error and continuing backing up project: #{project_or_wiki.path_with_namespace} - #{e.message}".color(:orange) diff --git a/spec/lib/gitlab/backup/repository_spec.rb b/spec/lib/gitlab/backup/repository_spec.rb index db860b01ba4..79b0b5008c5 100644 --- a/spec/lib/gitlab/backup/repository_spec.rb +++ b/spec/lib/gitlab/backup/repository_spec.rb @@ -60,4 +60,58 @@ describe Backup::Repository do end end end + + describe '#empty_repo?' do + context 'for a wiki' do + let(:wiki) { create(:project_wiki) } + + context 'wiki repo has content' do + let!(:wiki_page) { create(:wiki_page, wiki: wiki) } + + before do + wiki.repository.exists? # initial cache + end + + context '`repository.exists?` is incorrectly cached as false' do + before do + repo = wiki.repository + repo.send(:cache).expire(:exists?) + repo.send(:cache).fetch(:exists?) { false } + repo.send(:instance_variable_set, :@exists, false) + end + + it 'returns false, regardless of bad cache value' do + expect(Backup::Repository.new.send(:empty_repo?, wiki)).to be_falsey + end + end + + context '`repository.exists?` is correctly cached as true' do + it 'returns false' do + expect(Backup::Repository.new.send(:empty_repo?, wiki)).to be_falsey + end + end + end + + context 'wiki repo does not have content' do + context '`repository.exists?` is incorrectly cached as true' do + before do + repo = wiki.repository + repo.send(:cache).expire(:exists?) + repo.send(:cache).fetch(:exists?) { true } + repo.send(:instance_variable_set, :@exists, true) + end + + it 'returns true, regardless of bad cache value' do + expect(Backup::Repository.new.send(:empty_repo?, wiki)).to be_truthy + end + end + + context '`repository.exists?` is correctly cached as false' do + it 'returns true' do + expect(Backup::Repository.new.send(:empty_repo?, wiki)).to be_truthy + end + end + end + end + end end -- cgit v1.2.1 From 61239585c97f1b092e776d6f8ba0713188860f78 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Tue, 25 Jul 2017 17:04:42 -0700 Subject: Add changelog --- changelogs/unreleased/mk-fix-wiki-backup.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/mk-fix-wiki-backup.yml diff --git a/changelogs/unreleased/mk-fix-wiki-backup.yml b/changelogs/unreleased/mk-fix-wiki-backup.yml new file mode 100644 index 00000000000..ba9c1e85955 --- /dev/null +++ b/changelogs/unreleased/mk-fix-wiki-backup.yml @@ -0,0 +1,4 @@ +--- +title: Fix improperly skipped backups of wikis. +merge_request: 13096 +author: -- cgit v1.2.1 From a459e45eac290914c864616468f1527f6b1fdaab Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Fri, 28 Jul 2017 09:53:12 -0700 Subject: Fix Rubocop offense --- spec/lib/gitlab/backup/repository_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/lib/gitlab/backup/repository_spec.rb b/spec/lib/gitlab/backup/repository_spec.rb index 79b0b5008c5..3af69daa585 100644 --- a/spec/lib/gitlab/backup/repository_spec.rb +++ b/spec/lib/gitlab/backup/repository_spec.rb @@ -81,13 +81,13 @@ describe Backup::Repository do end it 'returns false, regardless of bad cache value' do - expect(Backup::Repository.new.send(:empty_repo?, wiki)).to be_falsey + expect(described_class.new.send(:empty_repo?, wiki)).to be_falsey end end context '`repository.exists?` is correctly cached as true' do it 'returns false' do - expect(Backup::Repository.new.send(:empty_repo?, wiki)).to be_falsey + expect(described_class.new.send(:empty_repo?, wiki)).to be_falsey end end end @@ -102,13 +102,13 @@ describe Backup::Repository do end it 'returns true, regardless of bad cache value' do - expect(Backup::Repository.new.send(:empty_repo?, wiki)).to be_truthy + expect(described_class.new.send(:empty_repo?, wiki)).to be_truthy end end context '`repository.exists?` is correctly cached as false' do it 'returns true' do - expect(Backup::Repository.new.send(:empty_repo?, wiki)).to be_truthy + expect(described_class.new.send(:empty_repo?, wiki)).to be_truthy end end end -- cgit v1.2.1 From f5fc912b33e0d343b8ef88b543a3b5b0b1f3cf9b Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Fri, 28 Jul 2017 09:25:13 -0700 Subject: Exclude keys linked to other projects --- app/models/project.rb | 13 ++++++- .../unreleased/mk-fix-deploy-key-deletion.yml | 4 +++ spec/models/project_spec.rb | 42 +++++++++++++++++----- 3 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 changelogs/unreleased/mk-fix-deploy-key-deletion.yml diff --git a/app/models/project.rb b/app/models/project.rb index d827bfaa806..90967a12b96 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1265,7 +1265,18 @@ class Project < ActiveRecord::Base end def remove_private_deploy_keys - deploy_keys.where(public: false).delete_all + exclude_keys_linked_to_other_projects = <<-SQL + NOT EXISTS ( + SELECT 1 + FROM deploy_keys_projects dkp2 + WHERE dkp2.deploy_key_id = deploy_keys_projects.deploy_key_id + AND dkp2.project_id != deploy_keys_projects.project_id + ) + SQL + + deploy_keys.where(public: false) + .where(exclude_keys_linked_to_other_projects) + .delete_all end def remove_pages diff --git a/changelogs/unreleased/mk-fix-deploy-key-deletion.yml b/changelogs/unreleased/mk-fix-deploy-key-deletion.yml new file mode 100644 index 00000000000..9ff2e49b14c --- /dev/null +++ b/changelogs/unreleased/mk-fix-deploy-key-deletion.yml @@ -0,0 +1,4 @@ +--- +title: Fix deletion of deploy keys linked to other projects +merge_request: 13162 +author: diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 473b7a88d61..19808e7d36a 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -2238,19 +2238,43 @@ describe Project do end describe '#remove_private_deploy_keys' do - it 'removes the private deploy keys of a project' do - project = create(:empty_project) + let!(:project) { create(:empty_project) } + + context 'for a private deploy key' do + let!(:key) { create(:deploy_key, public: false) } + let!(:deploy_keys_project) { create(:deploy_keys_project, deploy_key: key, project: project) } + + context 'when the key is not linked to another project' do + it 'removes the key' do + project.remove_private_deploy_keys + + expect(project.deploy_keys).not_to include(key) + end + end + + context 'when the key is linked to another project' do + before do + another_project = create(:empty_project) + create(:deploy_keys_project, deploy_key: key, project: another_project) + end - private_key = create(:deploy_key, public: false) - public_key = create(:deploy_key, public: true) + it 'does not remove the key' do + project.remove_private_deploy_keys - create(:deploy_keys_project, deploy_key: private_key, project: project) - create(:deploy_keys_project, deploy_key: public_key, project: project) + expect(project.deploy_keys).to include(key) + end + end + end + + context 'for a public deploy key' do + let!(:key) { create(:deploy_key, public: true) } + let!(:deploy_keys_project) { create(:deploy_keys_project, deploy_key: key, project: project) } - project.remove_private_deploy_keys + it 'does not remove the key' do + project.remove_private_deploy_keys - expect(project.deploy_keys.where(public: false).any?).to eq(false) - expect(project.deploy_keys.where(public: true).any?).to eq(true) + expect(project.deploy_keys).to include(key) + end end end end -- cgit v1.2.1 From 48fcb06c2a33c1f56f4aab76c843a41103d4ef93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 29 Jul 2017 03:01:48 +0200 Subject: Bump google-protobuf to 3.3.0 --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 627750e2c1d..05a70704513 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -323,7 +323,7 @@ GEM multi_json (~> 1.10) retriable (~> 1.4) signet (~> 0.6) - google-protobuf (3.2.0.2) + google-protobuf (3.3.0) googleauth (0.5.1) faraday (~> 0.9) jwt (~> 1.4) -- cgit v1.2.1 From 2d60d1de8d99fd80f6b1adfb90b7a275d69d000b Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Sat, 29 Jul 2017 01:14:33 +0900 Subject: fix --- db/schema.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/db/schema.rb b/db/schema.rb index 0abdb987b77..5fbbdea6eaa 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -254,32 +254,32 @@ ActiveRecord::Schema.define(version: 20170725145659) do add_index "ci_builds", ["updated_at"], name: "index_ci_builds_on_updated_at", using: :btree add_index "ci_builds", ["user_id"], name: "index_ci_builds_on_user_id", using: :btree - create_table "ci_pipeline_schedule_variables", force: :cascade do |t| + create_table "ci_group_variables", force: :cascade do |t| t.string "key", null: false t.text "value" t.text "encrypted_value" t.string "encrypted_value_salt" t.string "encrypted_value_iv" - t.integer "pipeline_schedule_id", null: false + t.integer "group_id", null: false + t.boolean "protected", default: false, null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false end - add_index "ci_pipeline_schedule_variables", ["pipeline_schedule_id", "key"], name: "index_ci_pipeline_schedule_variables_on_schedule_id_and_key", unique: true, using: :btree + add_index "ci_group_variables", ["group_id", "key"], name: "index_ci_group_variables_on_group_id_and_key", unique: true, using: :btree - create_table "ci_group_variables", force: :cascade do |t| + create_table "ci_pipeline_schedule_variables", force: :cascade do |t| t.string "key", null: false t.text "value" t.text "encrypted_value" t.string "encrypted_value_salt" t.string "encrypted_value_iv" - t.integer "group_id", null: false - t.boolean "protected", default: false, null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.integer "pipeline_schedule_id", null: false + t.datetime "created_at" + t.datetime "updated_at" end - add_index "ci_group_variables", ["group_id", "key"], name: "index_ci_group_variables_on_group_id_and_key", unique: true, using: :btree + add_index "ci_pipeline_schedule_variables", ["pipeline_schedule_id", "key"], name: "index_ci_pipeline_schedule_variables_on_schedule_id_and_key", unique: true, using: :btree create_table "ci_pipeline_schedules", force: :cascade do |t| t.string "description" @@ -1624,8 +1624,8 @@ ActiveRecord::Schema.define(version: 20170725145659) do add_foreign_key "ci_builds", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_a2141b1522", on_delete: :nullify add_foreign_key "ci_builds", "ci_stages", column: "stage_id", name: "fk_3a9eaa254d", on_delete: :cascade add_foreign_key "ci_builds", "projects", name: "fk_befce0568a", on_delete: :cascade - add_foreign_key "ci_pipeline_schedule_variables", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_41c35fda51", on_delete: :cascade add_foreign_key "ci_group_variables", "namespaces", column: "group_id", name: "fk_33ae4d58d8", on_delete: :cascade + add_foreign_key "ci_pipeline_schedule_variables", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_41c35fda51", on_delete: :cascade add_foreign_key "ci_pipeline_schedules", "projects", name: "fk_8ead60fcc4", on_delete: :cascade add_foreign_key "ci_pipeline_schedules", "users", column: "owner_id", name: "fk_9ea99f58d2", on_delete: :nullify add_foreign_key "ci_pipeline_variables", "ci_pipelines", column: "pipeline_id", name: "fk_f29c5f4380", on_delete: :cascade -- cgit v1.2.1 From 643b9274ecc84ccfb16f5e12c01f8644b1a15bb9 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Sat, 29 Jul 2017 12:14:18 +0100 Subject: Fix top bar in jobs view for microsoft edge --- app/assets/stylesheets/pages/builds.scss | 1 + changelogs/unreleased/35672-edge-top-bar.yml | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 changelogs/unreleased/35672-edge-top-bar.yml diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss index b6fc628c02b..6591b801f82 100644 --- a/app/assets/stylesheets/pages/builds.scss +++ b/app/assets/stylesheets/pages/builds.scss @@ -86,6 +86,7 @@ position: absolute; right: 0; left: 0; + top: 0; } .truncated-info { diff --git a/changelogs/unreleased/35672-edge-top-bar.yml b/changelogs/unreleased/35672-edge-top-bar.yml new file mode 100644 index 00000000000..0424dee19af --- /dev/null +++ b/changelogs/unreleased/35672-edge-top-bar.yml @@ -0,0 +1,4 @@ +--- +title: Properly affixes nav bar in job view in microsoft edge +merge_request: +author: -- cgit v1.2.1 From 06a760e1392c540318058bd30ce644b20015caaf Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 30 Jul 2017 09:51:08 -0500 Subject: Add a note about EFS and GitLab log files [ci skip] --- doc/administration/high_availability/nfs.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/administration/high_availability/nfs.md b/doc/administration/high_availability/nfs.md index bd6b7327aed..90a2e9298bf 100644 --- a/doc/administration/high_availability/nfs.md +++ b/doc/administration/high_availability/nfs.md @@ -46,6 +46,10 @@ GitLab does not recommend using EFS with GitLab. many small files are written in a serialized manner are not well-suited for EFS. EBS with an NFS server on top will perform much better. +In addition, avoid storing GitLab log files (e.g. those in `/var/log/gitlab`) +because this will also affect performance. We recommend that the log files be +stored on a local volume. + For more details on another person's experience with EFS, see [Amazon's Elastic File System: Burst Credits](https://www.rawkode.io/2017/04/amazons-elastic-file-system-burst-credits/) -- cgit v1.2.1 From acc0d8484505ed199fe8b9d2529d8f298d95bb80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 31 Jul 2017 08:07:51 +0000 Subject: Moves the Performance Bar to the top instead of being at the bottom --- app/assets/stylesheets/framework/header.scss | 4 +++ app/assets/stylesheets/framework/layout.scss | 4 +++ app/assets/stylesheets/framework/nav.scss | 20 +++++++++++++ app/assets/stylesheets/framework/sidebar.scss | 4 +++ app/assets/stylesheets/framework/variables.scss | 1 + app/assets/stylesheets/new_sidebar.scss | 12 ++++++-- app/assets/stylesheets/pages/builds.scss | 14 +++++++-- app/assets/stylesheets/pages/issuable.scss | 8 +++++ app/assets/stylesheets/pages/merge_requests.scss | 4 +++ app/assets/stylesheets/performance_bar.scss | 14 +++++++-- app/helpers/application_helper.rb | 6 +++- app/helpers/nav_helper.rb | 33 ++++++++++++++------- app/views/layouts/_page.html.haml | 4 +-- app/views/layouts/application.html.haml | 5 ++-- app/views/peek/views/_host.html.haml | 2 ++ .../monitoring/performance/img/performance_bar.png | Bin 186116 -> 170256 bytes 16 files changed, 111 insertions(+), 24 deletions(-) create mode 100644 app/views/peek/views/_host.html.haml diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index 605f4284bb5..df847094864 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -315,6 +315,10 @@ header { } } +.with-performance-bar header.navbar-gitlab { + top: $performance-bar-height; +} + .navbar-nav { li { .badge { diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss index 4a9d41b4fda..67c3287ed74 100644 --- a/app/assets/stylesheets/framework/layout.scss +++ b/app/assets/stylesheets/framework/layout.scss @@ -120,3 +120,7 @@ of the body element here, we negate cascading side effects but allow momentum sc .page-with-sidebar { -webkit-overflow-scrolling: auto; } + +.with-performance-bar .page-with-sidebar { + margin-top: $header-height + $performance-bar-height; +} diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss index 35b4d77a5ab..88e7ba117d5 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -347,6 +347,10 @@ } } +.with-performance-bar .layout-nav { + margin-top: $header-height + $performance-bar-height; +} + .scrolling-tabs-container { position: relative; @@ -441,6 +445,22 @@ } } +.with-performance-bar .page-with-layout-nav { + .right-sidebar { + top: ($header-height + 1) * 2 + $performance-bar-height; + } + + &.page-with-sub-nav { + .right-sidebar { + top: ($header-height + 1) * 3 + $performance-bar-height; + + &.affix { + top: $header-height + $performance-bar-height; + } + } + } +} + .nav-block { &.activities { border-bottom: 1px solid $border-color; diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 49b2f0e43a4..09b60ad1676 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -89,6 +89,10 @@ } } +.with-performance-bar .right-sidebar.affix { + top: $header-height + $performance-bar-height; +} + @mixin maintain-sidebar-dimensions { display: block; width: $gutter-width; diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index cf0a1ad57d0..0df6f24bfe6 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -204,6 +204,7 @@ $divergence-graph-separator-bg: #ccc; $general-hover-transition-duration: 100ms; $general-hover-transition-curve: linear; $highlight-changes-color: rgb(235, 255, 232); +$performance-bar-height: 35px; /* diff --git a/app/assets/stylesheets/new_sidebar.scss b/app/assets/stylesheets/new_sidebar.scss index ae43197a1a6..54f3e8d882c 100644 --- a/app/assets/stylesheets/new_sidebar.scss +++ b/app/assets/stylesheets/new_sidebar.scss @@ -118,7 +118,7 @@ $new-sidebar-width: 220px; z-index: 400; width: $new-sidebar-width; transition: left $sidebar-transition-duration; - top: 50px; + top: $header-height; bottom: 0; left: 0; overflow: auto; @@ -163,6 +163,10 @@ $new-sidebar-width: 220px; } } +.with-performance-bar .nav-sidebar { + top: $header-height + $performance-bar-height; +} + .sidebar-sub-level-items { display: none; padding-bottom: 8px; @@ -260,7 +264,7 @@ $new-sidebar-width: 220px; // Make issue boards full-height now that sub-nav is gone .boards-list { - height: calc(100vh - 50px); + height: calc(100vh - #{$header-height}); @media (min-width: $screen-sm-min) { height: 475px; // Needed for PhantomJS @@ -270,6 +274,10 @@ $new-sidebar-width: 220px; } } +.with-performance-bar .boards-list { + height: calc(100vh - #{$header-height} - #{$performance-bar-height}); +} + // Change color of all horizontal tabs to match the new indigo color .nav-links li.active a { diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss index b6fc628c02b..7f14c149198 100644 --- a/app/assets/stylesheets/pages/builds.scss +++ b/app/assets/stylesheets/pages/builds.scss @@ -64,10 +64,10 @@ color: $gl-text-color; position: sticky; position: -webkit-sticky; - top: 50px; + top: $header-height; &.affix { - top: 50px; + top: $header-height; } // with sidebar @@ -171,6 +171,16 @@ } } +.with-performance-bar .build-page { + .top-bar { + top: $header-height + $performance-bar-height; + + &.affix { + top: $header-height + $performance-bar-height; + } + } +} + .build-header { .ci-header-container, .header-action-buttons { diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index eb269df46fe..6da14320914 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -445,6 +445,14 @@ } } +.with-performance-bar .right-sidebar { + top: $header-height + $performance-bar-height; + + .issuable-sidebar { + height: calc(100% - #{$header-height} - #{$performance-bar-height}); + } +} + .detail-page-description { padding: 16px 0; diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 2db967547dd..4693b2434c7 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -759,6 +759,10 @@ } } +.with-performance-bar .merge-request-tabs-holder { + top: $header-height + $performance-bar-height; +} + .merge-request-tabs { display: flex; margin-bottom: 0; diff --git a/app/assets/stylesheets/performance_bar.scss b/app/assets/stylesheets/performance_bar.scss index 2890b6b1e49..6e539e39ca1 100644 --- a/app/assets/stylesheets/performance_bar.scss +++ b/app/assets/stylesheets/performance_bar.scss @@ -3,9 +3,16 @@ @import "peek/views/rblineprof"; #peek { - height: 35px; + position: fixed; + left: 0; + top: 0; + width: 100%; + z-index: 2000; + overflow-x: hidden; + + height: $performance-bar-height; background: $black; - line-height: 35px; + line-height: $performance-bar-height; color: $perf-bar-text; &.disabled { @@ -25,7 +32,8 @@ } .wrapper { - width: 1000px; + width: 80%; + height: $performance-bar-height; margin: 0 auto; } diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 1c165700b19..14dc9bd9d62 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -264,7 +264,11 @@ module ApplicationHelper end def page_class - "issue-boards-page" if current_controller?(:boards) + class_names = [] + class_names << 'issue-boards-page' if current_controller?(:boards) + class_names << 'with-performance-bar' if performance_bar_enabled? + + class_names end # Returns active css class when condition returns true diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb index b769462abc2..b1205b8529b 100644 --- a/app/helpers/nav_helper.rb +++ b/app/helpers/nav_helper.rb @@ -1,38 +1,49 @@ module NavHelper + def page_with_sidebar_class + class_name = page_gutter_class + class_name << 'page-with-new-sidebar' if defined?(@new_sidebar) && @new_sidebar + + class_name + end + def page_gutter_class if current_path?('merge_requests#show') || current_path?('projects/merge_requests/conflicts#show') || current_path?('issues#show') || current_path?('milestones#show') if cookies[:collapsed_gutter] == 'true' - "page-gutter right-sidebar-collapsed" + %w[page-gutter right-sidebar-collapsed] else - "page-gutter right-sidebar-expanded" + %w[page-gutter right-sidebar-expanded] end elsif current_path?('jobs#show') - "page-gutter build-sidebar right-sidebar-expanded" + %w[page-gutter build-sidebar right-sidebar-expanded] elsif current_path?('wikis#show') || current_path?('wikis#edit') || current_path?('wikis#update') || current_path?('wikis#history') || current_path?('wikis#git_access') - "page-gutter wiki-sidebar right-sidebar-expanded" + %w[page-gutter wiki-sidebar right-sidebar-expanded] + else + [] end end def nav_header_class - class_name = '' - class_name << " with-horizontal-nav" if defined?(nav) && nav + class_names = [] + class_names << 'with-horizontal-nav' if defined?(nav) && nav - class_name + class_names end def layout_nav_class - class_name = '' - class_name << " page-with-layout-nav" if defined?(nav) && nav - class_name << " page-with-sub-nav" if content_for?(:sub_nav) + return [] if show_new_nav? - class_name + class_names = [] + class_names << 'page-with-layout-nav' if defined?(nav) && nav + class_names << 'page-with-sub-nav' if content_for?(:sub_nav) + + class_names end def nav_control_class diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml index 873220cc73d..c4f8cd71395 100644 --- a/app/views/layouts/_page.html.haml +++ b/app/views/layouts/_page.html.haml @@ -1,4 +1,4 @@ -.page-with-sidebar{ class: "#{('page-with-new-sidebar' if defined?(@new_sidebar) && @new_sidebar)} #{page_gutter_class}" } +.page-with-sidebar{ class: page_with_sidebar_class } - if show_new_nav? - if defined?(nav) && nav = render "layouts/nav/#{nav}" @@ -9,7 +9,7 @@ = render "layouts/nav/#{nav}" - if content_for?(:sub_nav) = yield :sub_nav - .content-wrapper{ class: "#{(layout_nav_class unless show_new_nav?)}" } + .content-wrapper{ class: layout_nav_class } - if show_new_nav? .mobile-overlay .alert-wrapper diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 38b95d11fd4..b53f382fa3d 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -1,8 +1,9 @@ !!! 5 -%html{ lang: I18n.locale, class: "#{page_class}" } +%html{ lang: I18n.locale, class: page_class } = render "layouts/head" %body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}", find_file: find_file_path } } = render "layouts/init_auto_complete" if @gfm_form + = render 'peek/bar' - if show_new_nav? = render "layouts/header/new" - else @@ -10,5 +11,3 @@ = render 'layouts/page', sidebar: sidebar, nav: nav = yield :scripts_body - - = render 'peek/bar' diff --git a/app/views/peek/views/_host.html.haml b/app/views/peek/views/_host.html.haml new file mode 100644 index 00000000000..40769b5c6f6 --- /dev/null +++ b/app/views/peek/views/_host.html.haml @@ -0,0 +1,2 @@ +%span.current-host + = truncate(view.hostname) diff --git a/doc/administration/monitoring/performance/img/performance_bar.png b/doc/administration/monitoring/performance/img/performance_bar.png index d38293d2ed6..b3c6bc474e3 100644 Binary files a/doc/administration/monitoring/performance/img/performance_bar.png and b/doc/administration/monitoring/performance/img/performance_bar.png differ -- cgit v1.2.1 From 8bcfdebf650dee1aec35192bee5ab45b9d6cbd44 Mon Sep 17 00:00:00 2001 From: winh Date: Mon, 31 Jul 2017 11:02:45 +0200 Subject: Make dropdown style on repository page consistent --- app/assets/stylesheets/pages/tree.scss | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index dc88cf3e699..e0f46172769 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -202,6 +202,28 @@ } } } + + // TODO: fallback to global style + .dropdown-menu:not(.dropdown-menu-selectable) { + li { + padding: 0 1px; + + &.dropdown-header { + padding: 8px 16px; + } + + a { + border-radius: 0; + padding: 8px 16px; + + &:hover, + &:active, + &:focus { + background-color: $gray-darker; + } + } + } + } } .blob-commit-info { -- cgit v1.2.1 From ebd2ed8f644ba4f0fcaff979d4de41f773b31fdd Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Mon, 31 Jul 2017 11:42:50 +0200 Subject: Pass OmniAuth formatted options to OmniAuth::LDAP::Adaptor --- changelogs/unreleased/dm-ldap-authentication-ssl-verification.yml | 4 ++++ lib/gitlab/ldap/authentication.rb | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/dm-ldap-authentication-ssl-verification.yml diff --git a/changelogs/unreleased/dm-ldap-authentication-ssl-verification.yml b/changelogs/unreleased/dm-ldap-authentication-ssl-verification.yml new file mode 100644 index 00000000000..59462a6666d --- /dev/null +++ b/changelogs/unreleased/dm-ldap-authentication-ssl-verification.yml @@ -0,0 +1,4 @@ +--- +title: Fix LDAP authentication to Git repository or container registry +merge_request: +author: diff --git a/lib/gitlab/ldap/authentication.rb b/lib/gitlab/ldap/authentication.rb index 4745311402c..ed1de73f8c6 100644 --- a/lib/gitlab/ldap/authentication.rb +++ b/lib/gitlab/ldap/authentication.rb @@ -42,7 +42,7 @@ module Gitlab end def adapter - OmniAuth::LDAP::Adaptor.new(config.options.symbolize_keys) + OmniAuth::LDAP::Adaptor.new(config.omniauth_options) end def config -- cgit v1.2.1 From c9c0a12713461abc8d61690b7c319253eb8980de Mon Sep 17 00:00:00 2001 From: Marcia Ramos Date: Mon, 31 Jul 2017 09:44:07 +0000 Subject: New doc topic user/project/index --- doc/README.md | 13 +++-- doc/user/index.md | 2 +- doc/user/profile/index.md | 2 +- doc/user/project/index.md | 107 +++++++++++++++++++++++++++++++++++ doc/user/project/koding.md | 2 +- doc/user/project/repository/index.md | 2 +- 6 files changed, 118 insertions(+), 10 deletions(-) create mode 100644 doc/user/project/index.md diff --git a/doc/README.md b/doc/README.md index cc63ecb7eab..8bb8e147cd1 100644 --- a/doc/README.md +++ b/doc/README.md @@ -44,16 +44,17 @@ Shortcuts to GitLab's most visited docs: ### Projects and groups -- [Create a project](gitlab-basics/create-project.md) -- [Fork a project](gitlab-basics/fork-project.md) -- [Importing and exporting projects between instances](user/project/settings/import_export.md). -- [Project access](public_access/public_access.md): Setting up your project's visibility to public, internal, or private. +- [Projects](user/project/index.md): + - [Create a project](gitlab-basics/create-project.md) + - [Fork a project](gitlab-basics/fork-project.md) + - [Importing and exporting projects between instances](user/project/settings/import_export.md). + - [Project access](public_access/public_access.md): Setting up your project's visibility to public, internal, or private. + - [GitLab Pages](user/project/pages/index.md): Build, test, and deploy your static website with GitLab Pages. - [Groups](user/group/index.md): Organize your projects in groups. - - [GitLab Subgroups](user/group/subgroups/index.md) + - [Subgroups](user/group/subgroups/index.md) - [Search through GitLab](user/search/index.md): Search for issues, merge requests, projects, groups, todos, and issues in Issue Boards. - [Snippets](user/snippets.md): Snippets allow you to create little bits of code. - [Wikis](user/project/wiki/index.md): Enhance your repository documentation with built-in wikis. -- [GitLab Pages](user/project/pages/index.md): Build, test, and deploy your static website with GitLab Pages. ### Repository diff --git a/doc/user/index.md b/doc/user/index.md index 522cf932349..1281cc6e4f0 100644 --- a/doc/user/index.md +++ b/doc/user/index.md @@ -66,7 +66,7 @@ For more use cases please check our [Technical Articles](../articles/index.md). ## Projects -In GitLab, you can create projects for numerous reasons, such as, host +In GitLab, you can create [projects](project/index.md) for numerous reasons, such as, host your code, use it as an issue tracker, collaborate on code, and continuously build, test, and deploy your app with built-in GitLab CI/CD. Or, you can do it all at once, from one single project. diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md index 0e3747817d2..7d25970fcb1 100644 --- a/doc/user/profile/index.md +++ b/doc/user/profile/index.md @@ -23,7 +23,7 @@ On your profile page, you will see the following information: - Personal information - Activity stream: see your activity streamline and the history of your contributions - Groups: [groups](../group/index.md) you're a member of -- Contributed projects: projects you contributed to +- Contributed projects: [projects](../project/index.md) you contributed to - Personal projects: your personal projects (respecting the project's visibility level) - Snippets: your personal code [snippets](../snippets.md#personal-snippets) diff --git a/doc/user/project/index.md b/doc/user/project/index.md new file mode 100644 index 00000000000..91a19600951 --- /dev/null +++ b/doc/user/project/index.md @@ -0,0 +1,107 @@ +# Projects + +In GitLab, you can create projects for hosting +your codebase, use it as an issue tracker, collaborate on code, and continuously +build, test, and deploy your app with built-in GitLab CI/CD. + +Your projects can be [available](../../public_access/public_access.md) +publicly, internally, or privately, at your choice. GitLab does not limit +the number of private projects you create. + +## Project's features + +When you create a project in GitLab, you'll have access to a large number of +[features](https://about.gitlab.com/features/): + +**Issues and merge requests:** + +- [Issue tracker](issues/index.md): Discuss implementations with your team within issues + - [Issue Boards](issue_board.md): Organize and prioritize your workflow + - [Multiple Issue Boards](https://docs.gitlab.com/ee/user/project/issue_board.html#multiple-issue-boards) (**EES/EEP**): Allow your teams to create their own workflows (Issue Boards) for the same project +- [Repositories](repository/index.md): Host your code in a fully +integrated platform + - [Protected branches](protected_branches.md): Prevent collaborators + from messing with history or pushing code without review + - [Protected tags](protected_tags.md): Control over who has + permission to create tags, and prevent accidental update or deletion +- [Merge Requests](merge_requests/index.md): Apply your branching +strategy and get reviewed by your team + - [Merge Request Approvals](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html) (**EES/EEP**): Ask for approval before + implementing a change + - [Fix merge conflicts from the UI](merge_requests/resolve_conflicts.md): + Your Git diff tool right from GitLab's UI + - [Review Apps](../../ci/review_apps/index.md): Live preview the results + of the changes proposed in a merge request in a per-branch basis +- [Labels](labels.md): Organize issues and merge requests by labels +- [Time Tracking](../../workflow/time_tracking.md): Track estimate time +and time spent on + the conclusion of an issue or merge request +- [Milestones](milestones/index.md): Work towards a target date +- [Description templates](description_templates.md): Define context-specific +templates for issue and merge request description fields for your project +- [Slash commands (quick actions)](quick_actions.md): Textual shortcuts for +common actions on issues or merge requests + +**GitLab CI/CD:** + +- [GitLab CI/CD](../../ci/README.md): GitLab's built-in [Continuous Integration, Delivery, and Deployment](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) tool + - [Container Registry](container_registry.md): Build and push Docker + images out-of-the-box + - [Auto Deploy](../../ci/autodeploy/index.md): Configure GitLab CI/CD + to automatically set up your app's deployment + - [Enable and disable GitLab CI](../../ci/enable_or_disable_ci.md) + - [Pipelines](../../ci/pipelines.md#pipelines): Configure and visualize + your GitLab CI/CD pipelines from the UI + - [Scheduled Pipelines](pipelines/schedules.md): Schedule a pipeline + to start at a chosen time + - [Pipeline Graphs](../../ci/pipelines.md#pipeline-graphs): View your + entire pipeline from the UI + - [Job artifacts](pipelines/job_artifacts.md): Define, + browse, and download job artifacts + - [Pipeline settings](pipelines/settings.md): Set up Git strategy (choose the default way your repository is fetched from GitLab in a job), + timeout (defines the maximum amount of time in minutes that a job is able run), custom path for `.gitlab-ci.yml`, test coverage parsing, pipeline's visibility, and much more +- [GitLab Pages](pages/index.md): Build, test, and deploy your static +website with GitLab Pages + +**Other features:** + +- [Cycle Analytics](cycle_analytics.md): Review your development lifecycle +- [Koding integration](koding.md) (not available on GitLab.com): Integrate +with Koding to have access to a web terminal right from the GitLab UI +- [Syntax highlighting](highlighting.md): An alternative to customize +your code blocks, overriding GitLab's default choice of language + +### Project's integrations + +[Integrate your project](integrations/index.md) with Jira, Mattermost, +Kubernetes, Slack, and a lot more. + +## New project + +Learn how to [create a new project](../../gitlab-basics/create-project.md) in GitLab. + +### Fork a project + +You can [fork a project](../../gitlab-basics/fork-project.md) in order to: + +- Collaborate on code by forking a project and creating a merge request +from your fork to the upstream project +- Fork a sample project to work on the top of that + +## Import or export a project + +- Import a project from: + - [GitHub to GitLab](../../workflow/importing/import_projects_from_github.md) + - [BitBucket to GitLab](../../workflow/importing/import_projects_from_bitbucket.md) + - [Gitea to GitLab](../../workflow/importing/import_projects_from_gitea.md) + - [FogBugz to GitLab](../../workflow/importing/import_projects_from_fogbugz.md) +- [Export a project from GitLab](settings/import_export.md#exporting-a-project-and-its-data) +- [Importing and exporting projects between GitLab instances](settings/import_export.md) + +## Leave a project + +**Leave project** will only display on the project's dashboard +when a project is part of a group (under a +[group namespace](../group/index.md#namespaces)). +If you choose to leave a project you will no longer be a project +member, therefore, unable to contribute. diff --git a/doc/user/project/koding.md b/doc/user/project/koding.md index c56a1efe3c2..455e2ee47b4 100644 --- a/doc/user/project/koding.md +++ b/doc/user/project/koding.md @@ -1,4 +1,4 @@ -# Koding & GitLab +# Koding integration > [Introduced][ce-5909] in GitLab 8.11. diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md index bb41eb41795..4b2c435a120 100644 --- a/doc/user/project/repository/index.md +++ b/doc/user/project/repository/index.md @@ -2,7 +2,7 @@ A [repository](https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository) is what you use to store your codebase in GitLab and change it with version control. -A repository is part of a project, which has a lot of other features. +A repository is part of a [project](../index.md), which has a lot of other features. ## Create a repository -- cgit v1.2.1 From c468628527756884e3b25c3c7d1bcff396637cd8 Mon Sep 17 00:00:00 2001 From: winh Date: Mon, 31 Jul 2017 10:10:59 +0200 Subject: Make projects dropdown style in new navigation consistent --- app/assets/stylesheets/new_nav.scss | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/app/assets/stylesheets/new_nav.scss b/app/assets/stylesheets/new_nav.scss index 360ffda8d71..7cabf371985 100644 --- a/app/assets/stylesheets/new_nav.scss +++ b/app/assets/stylesheets/new_nav.scss @@ -309,6 +309,25 @@ header.navbar-gitlab-new { outline: 0; } } + + // TODO: fallback to global style + .dropdown-menu { + li { + padding: 0 1px; + + a { + border-radius: 0; + padding: 8px 16px; + + &.is-focused, + &:hover, + &:active, + &:focus { + background-color: $gray-darker; + } + } + } + } } .breadcrumbs-container { -- cgit v1.2.1 From 78829db98234ebe2cdf4264396352d6cc39d106d Mon Sep 17 00:00:00 2001 From: winh Date: Mon, 31 Jul 2017 12:12:16 +0200 Subject: Fix badge positioning in new navigation for Firefox --- app/views/layouts/nav/_new_admin_sidebar.html.haml | 2 +- app/views/layouts/nav/_new_group_sidebar.html.haml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/layouts/nav/_new_admin_sidebar.html.haml b/app/views/layouts/nav/_new_admin_sidebar.html.haml index 95443de40c2..8db3e69aed4 100644 --- a/app/views/layouts/nav/_new_admin_sidebar.html.haml +++ b/app/views/layouts/nav/_new_admin_sidebar.html.haml @@ -91,8 +91,8 @@ = nav_link(controller: :abuse_reports) do = link_to admin_abuse_reports_path, title: "Abuse Reports" do %span - Abuse Reports %span.badge.count= number_with_delimiter(AbuseReport.count(:all)) + Abuse Reports - if akismet_enabled? = nav_link(controller: :spam_logs) do diff --git a/app/views/layouts/nav/_new_group_sidebar.html.haml b/app/views/layouts/nav/_new_group_sidebar.html.haml index a7897c09e79..4fd9e213ead 100644 --- a/app/views/layouts/nav/_new_group_sidebar.html.haml +++ b/app/views/layouts/nav/_new_group_sidebar.html.haml @@ -28,9 +28,9 @@ = nav_link(path: ['groups#issues', 'labels#index', 'milestones#index']) do = link_to issues_group_path(@group), title: 'Issues' do %span - Issues - issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute %span.badge.count= number_with_delimiter(issues.count) + Issues %ul.sidebar-sub-level-items = nav_link(path: 'groups#issues', html_options: { class: 'home' }) do @@ -51,9 +51,9 @@ = nav_link(path: 'groups#merge_requests') do = link_to merge_requests_group_path(@group), title: 'Merge Requests' do %span - Merge Requests - merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute %span.badge.count= number_with_delimiter(merge_requests.count) + Merge Requests = nav_link(path: 'group_members#index') do = link_to group_group_members_path(@group), title: 'Members' do %span -- cgit v1.2.1 From 57a5544f883ad9687c38270519edc7914912af5d Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Fri, 28 Jul 2017 10:44:33 +0100 Subject: Remove events column from notification settings This was migrated to separate columns in 9.4, and now just needs to be removed for real. --- app/models/notification_setting.rb | 34 ++++------------------ ...20-remove-events-from-notification_settings.yml | 4 +++ ...014_remove_events_from_notification_settings.rb | 9 ++++++ db/schema.rb | 3 +- spec/factories/notification_settings.rb | 1 - spec/models/notification_setting_spec.rb | 12 +++----- spec/requests/api/notification_settings_spec.rb | 4 +-- spec/spec_helper.rb | 4 +++ 8 files changed, 29 insertions(+), 42 deletions(-) create mode 100644 changelogs/unreleased/33620-remove-events-from-notification_settings.yml create mode 100644 db/post_migrate/20170728101014_remove_events_from_notification_settings.rb diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb index 81844b1e2ca..9b1cac64c44 100644 --- a/app/models/notification_setting.rb +++ b/app/models/notification_setting.rb @@ -1,4 +1,8 @@ class NotificationSetting < ActiveRecord::Base + include IgnorableColumn + + ignore_column :events + enum level: { global: 3, watch: 2, mention: 4, participating: 1, disabled: 0, custom: 5 } default_value_for :level, NotificationSetting.levels[:global] @@ -41,9 +45,6 @@ class NotificationSetting < ActiveRecord::Base :success_pipeline ].freeze - store :events, coder: JSON - before_save :convert_events - def self.find_or_create_for(source) setting = find_or_initialize_by(source: source) @@ -54,42 +55,17 @@ class NotificationSetting < ActiveRecord::Base setting end - # 1. Check if this event has a value stored in its database column. - # 2. If it does, return that value. - # 3. If it doesn't (the value is nil), return the value from the serialized - # JSON hash in `events`. - (EMAIL_EVENTS - [:failed_pipeline]).each do |event| - define_method(event) do - bool = super() - - bool.nil? ? !!events[event] : bool - end - - alias_method :"#{event}?", event - end - # Allow people to receive failed pipeline notifications if they already have # custom notifications enabled, as these are more like mentions than the other # custom settings. def failed_pipeline bool = super - bool = events[:failed_pipeline] if bool.nil? bool.nil? || bool end alias_method :failed_pipeline?, :failed_pipeline def event_enabled?(event) - respond_to?(event) && public_send(event) - end - - def convert_events - return if events_before_type_cast.nil? - - EMAIL_EVENTS.each do |event| - write_attribute(event, public_send(event)) - end - - write_attribute(:events, nil) + respond_to?(event) && !!public_send(event) end end diff --git a/changelogs/unreleased/33620-remove-events-from-notification_settings.yml b/changelogs/unreleased/33620-remove-events-from-notification_settings.yml new file mode 100644 index 00000000000..f5f3ef3fb82 --- /dev/null +++ b/changelogs/unreleased/33620-remove-events-from-notification_settings.yml @@ -0,0 +1,4 @@ +--- +title: Remove events column from notification settings table +merge_request: +author: diff --git a/db/post_migrate/20170728101014_remove_events_from_notification_settings.rb b/db/post_migrate/20170728101014_remove_events_from_notification_settings.rb new file mode 100644 index 00000000000..cd533391d8d --- /dev/null +++ b/db/post_migrate/20170728101014_remove_events_from_notification_settings.rb @@ -0,0 +1,9 @@ +class RemoveEventsFromNotificationSettings < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def change + remove_column :notification_settings, :events, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 0abdb987b77..1a60589261a 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: 20170725145659) do +ActiveRecord::Schema.define(version: 20170728101014) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -981,7 +981,6 @@ ActiveRecord::Schema.define(version: 20170725145659) do t.integer "level", default: 0, null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.text "events" t.boolean "new_note" t.boolean "new_issue" t.boolean "reopen_issue" diff --git a/spec/factories/notification_settings.rb b/spec/factories/notification_settings.rb index b5e96d18b8f..ee41997e41a 100644 --- a/spec/factories/notification_settings.rb +++ b/spec/factories/notification_settings.rb @@ -3,6 +3,5 @@ FactoryGirl.define do source factory: :empty_project user level 3 - events [] end end diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb index 07e296424ca..2a0d102d3fe 100644 --- a/spec/models/notification_setting_spec.rb +++ b/spec/models/notification_setting_spec.rb @@ -63,24 +63,20 @@ RSpec.describe NotificationSetting do end end - describe 'event_enabled?' do + describe '#event_enabled?' do before do subject.update!(user: create(:user)) end context 'for an event with a matching column name' do - before do - subject.update!(events: { new_note: true }.to_json) - end - it 'returns the value of the column' do - subject.update!(new_note: false) + subject.update!(new_note: true) - expect(subject.event_enabled?(:new_note)).to be(false) + expect(subject.event_enabled?(:new_note)).to be(true) end context 'when the column has a nil value' do - it 'returns the value from the events hash' do + it 'returns false' do expect(subject.event_enabled?(:new_note)).to be(false) end end diff --git a/spec/requests/api/notification_settings_spec.rb b/spec/requests/api/notification_settings_spec.rb index f619b7e6eaf..d0e7a82e607 100644 --- a/spec/requests/api/notification_settings_spec.rb +++ b/spec/requests/api/notification_settings_spec.rb @@ -72,8 +72,8 @@ describe API::NotificationSettings do expect(response).to have_http_status(200) expect(json_response['level']).to eq(user.reload.notification_settings_for(project).level) - expect(json_response['events']['new_note']).to eq(true) - expect(json_response['events']['new_issue']).to eq(false) + expect(json_response['events']['new_note']).to be_truthy + expect(json_response['events']['new_issue']).to be_falsey end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 85335643921..609998d6e9c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -129,10 +129,14 @@ RSpec.configure do |config| config.before(:example, :migration) do ActiveRecord::Migrator .migrate(migrations_paths, previous_migration.version) + + ActiveRecord::Base.descendants.each(&:reset_column_information) end config.after(:example, :migration) do ActiveRecord::Migrator.migrate(migrations_paths) + + ActiveRecord::Base.descendants.each(&:reset_column_information) end config.around(:each, :nested_groups) do |example| -- cgit v1.2.1 From b535be35ae8bbb003f550e51d22a8e3b4c46b07c Mon Sep 17 00:00:00 2001 From: kushalpandya Date: Mon, 31 Jul 2017 16:03:39 +0530 Subject: Group Identicon for groups without avatars --- .../groups/components/group_identicon.vue | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 app/assets/javascripts/groups/components/group_identicon.vue diff --git a/app/assets/javascripts/groups/components/group_identicon.vue b/app/assets/javascripts/groups/components/group_identicon.vue new file mode 100644 index 00000000000..4e0898b6c44 --- /dev/null +++ b/app/assets/javascripts/groups/components/group_identicon.vue @@ -0,0 +1,44 @@ + + + -- cgit v1.2.1 From 84568997431d778644d41dd3e3a4f98eee850935 Mon Sep 17 00:00:00 2001 From: kushalpandya Date: Mon, 31 Jul 2017 16:04:25 +0530 Subject: Use GroupIdenticon for missing avatars --- app/assets/javascripts/groups/components/group_item.vue | 13 +++++++++++++ app/assets/javascripts/groups/index.js | 2 ++ 2 files changed, 15 insertions(+) diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue index b1db34b9c50..c704aa65df2 100644 --- a/app/assets/javascripts/groups/components/group_item.vue +++ b/app/assets/javascripts/groups/components/group_item.vue @@ -92,6 +92,13 @@ export default { hasGroups() { return Object.keys(this.group.subGroups).length > 0; }, + hasAvatar() { + if (this.group.avatarUrl) { + return this.group.avatarUrl.indexOf('/assets/no_group_avatar') === -1; + } else { + return false; + } + }, }, }; @@ -194,9 +201,15 @@ export default { +
{ Vue.component('groups-component', GroupsComponent); Vue.component('group-folder', GroupFolder); Vue.component('group-item', GroupItem); + Vue.component('group-identicon', GroupIdenticon); // eslint-disable-next-line no-new new Vue({ -- cgit v1.2.1 From ec0ea51f67724be9ae2a81827abeec9022cd2f46 Mon Sep 17 00:00:00 2001 From: kushalpandya Date: Mon, 31 Jul 2017 16:04:45 +0530 Subject: Add styles for Identicons for Groups --- app/assets/stylesheets/framework/lists.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index 868e65a8f46..ab754f4a492 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -369,6 +369,10 @@ ul.indent-list { background-color: $row-hover; cursor: pointer; } + + .avatar-container > a { + width: 100%; + } } } -- cgit v1.2.1 From 339469099d64e9f87cccb375cc31c0158a99480f Mon Sep 17 00:00:00 2001 From: kushalpandya Date: Mon, 31 Jul 2017 16:05:06 +0530 Subject: Update tests --- spec/javascripts/groups/groups_spec.js | 15 +++++++++++++++ spec/javascripts/groups/mock_data.js | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/spec/javascripts/groups/groups_spec.js b/spec/javascripts/groups/groups_spec.js index aaffb56fa94..7e38b49c792 100644 --- a/spec/javascripts/groups/groups_spec.js +++ b/spec/javascripts/groups/groups_spec.js @@ -2,6 +2,7 @@ import Vue from 'vue'; import eventHub from '~/groups/event_hub'; import groupFolderComponent from '~/groups/components/group_folder.vue'; import groupItemComponent from '~/groups/components/group_item.vue'; +import groupIdenticonComponent from '~/groups/components/group_identicon.vue'; import groupsComponent from '~/groups/components/groups.vue'; import GroupsStore from '~/groups/stores/groups_store'; import { groupsData } from './mock_data'; @@ -14,6 +15,7 @@ describe('Groups Component', () => { beforeEach((done) => { Vue.component('group-folder', groupFolderComponent); + Vue.component('group-identicon', groupIdenticonComponent); Vue.component('group-item', groupItemComponent); store = new GroupsStore(); @@ -64,6 +66,19 @@ describe('Groups Component', () => { expect(lists[2].querySelector('#group-1120').textContent).toContain(groups.id1119.subGroups.id1120.name); }); + it('should render group identicon when group avatar is not present', () => { + const avatar = component.$el.querySelector('#group-12 .avatar-container .avatar'); + expect(avatar.nodeName).toBe('DIV'); + expect(avatar.classList.contains('identicon')).toBeTruthy(); + expect(avatar.getAttribute('style').indexOf('background-color') > -1).toBeTruthy(); + }); + + it('should render group avatar when group avatar is present', () => { + const avatar = component.$el.querySelector('#group-1120 .avatar-container .avatar'); + expect(avatar.nodeName).toBe('IMG'); + expect(avatar.classList.contains('identicon')).toBeFalsy(); + }); + it('should remove prefix of parent group', () => { expect(component.$el.querySelector('#group-12 #group-1128 .title').textContent).toContain('level2 / level3 / level4'); }); diff --git a/spec/javascripts/groups/mock_data.js b/spec/javascripts/groups/mock_data.js index b3f5d791b89..9e1f414514a 100644 --- a/spec/javascripts/groups/mock_data.js +++ b/spec/javascripts/groups/mock_data.js @@ -71,7 +71,7 @@ const group21 = { path: 'chef', description: 'foo', visibility: 'public', - avatar_url: null, + avatar_url: '/uploads/-/system/group/avatar/2/GitLab.png', web_url: 'http://localhost:3000/groups/devops/chef', group_path: '/devops/chef', full_name: 'devops / chef', -- cgit v1.2.1 From 38dc8c0c57cb880b52d20e13deac1fa6f8393d3e Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Mon, 31 Jul 2017 13:30:34 +0100 Subject: Explain what the regression label means --- PROCESS.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/PROCESS.md b/PROCESS.md index 3b97a4e8c75..2b3d142bf77 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -128,7 +128,7 @@ information, see ### After the 7th -Once the stable branch is frozen, only fixes for regressions (bugs introduced in that same release) +Once the stable branch is frozen, only fixes for [regressions](#regressions) and security issues will be cherry-picked into the stable branch. Any merge requests cherry-picked into the stable branch for a previous release will also be picked into the latest stable branch. These fixes will be shipped in the next RC for that release if it is before the 22nd. @@ -158,6 +158,24 @@ release should have the correct milestone assigned _and_ have the label Merge requests without a milestone and this label will not be merged into any stable branches. +### Regressions + +A regression for a particular monthly release is a bug that exists in that +release, but wasn't present in the release before. This includes bugs in +features that were only added in that monthly release. Every regression **must** +have the milestone of the release it was introduced in - if a regression doesn't +have a milestone, it might be 'just' a bug! + +For instance, if 10.5.0 adds a feature, and that feature doesn't work correctly, +then this is a regression in 10.5. If 10.5.1 then fixes that, but 10.5.3 somehow +reintroduces the bug, then this bug is still a regression in 10.5. + +Because GitLab.com runs release candidates of new releases, a regression can be +reported in a release before its 'official' release date on the 22nd of the +month. When we say 'the most recent monthly release', this can refer to either +the version currently running on GitLab.com, or the most recent version +available in the package repositories. + ## Release retrospective and kickoff ### Retrospective -- cgit v1.2.1 From b720c22fb46009acda19b5cd170d3b64227c89b1 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Mon, 31 Jul 2017 20:30:18 +0800 Subject: Avoid expect_any_instance_of because it doesn't work well with prepend. We need to backport this --- spec/services/projects/transfer_service_spec.rb | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index ae32e85b2a7..36db1aab557 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -37,18 +37,18 @@ describe Projects::TransferService do end it 'executes system hooks' do - expect_any_instance_of(described_class).to receive(:execute_system_hooks) - - transfer_project(project, user, group) + transfer_project(project, user, group) do |service| + expect(service).to receive(:execute_system_hooks) + end end end context 'when transfer fails' do let!(:original_path) { project_path(project) } - def attempt_project_transfer + def attempt_project_transfer(&block) expect do - transfer_project(project, user, group) + transfer_project(project, user, group, &block) end.to raise_error(ActiveRecord::ActiveRecordError) end @@ -80,9 +80,9 @@ describe Projects::TransferService do end it "doesn't run system hooks" do - expect_any_instance_of(described_class).not_to receive(:execute_system_hooks) - - attempt_project_transfer + attempt_project_transfer do |service| + expect(service).not_to receive(:execute_system_hooks) + end end end @@ -120,7 +120,11 @@ describe Projects::TransferService do end def transfer_project(project, user, new_namespace) - Projects::TransferService.new(project, user).execute(new_namespace) + service = Projects::TransferService.new(project, user) + + yield(service) if block_given? + + service.execute(new_namespace) end context 'visibility level' do -- cgit v1.2.1 From ce83e5635d1903cfadf4e2d9a7088b505f6c28ff Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Fri, 28 Jul 2017 23:02:21 +0200 Subject: add kube_namespace and standardize common variables for additional metrics queries --- .../queries/additional_metrics_deployment_query.rb | 12 ++++++------ .../queries/additional_metrics_environment_query.rb | 12 ++++++------ lib/gitlab/prometheus/queries/query_additional_metrics.rb | 12 ++++++++++++ 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb b/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb index 67c69d9ccf3..51d934b9ae2 100644 --- a/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb +++ b/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb @@ -6,12 +6,12 @@ module Gitlab def query(deployment_id) Deployment.find_by(id: deployment_id).try do |deployment| - query_context = { - environment_slug: deployment.environment.slug, - environment_filter: %{container_name!="POD",environment="#{deployment.environment.slug}"}, - timeframe_start: (deployment.created_at - 30.minutes).to_f, - timeframe_end: (deployment.created_at + 30.minutes).to_f - } + query_context = common_query_context(deployment.environment).merge( + { + timeframe_start: (deployment.created_at - 30.minutes).to_f, + timeframe_end: (deployment.created_at + 30.minutes).to_f + } + ) query_metrics(query_context) end diff --git a/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb b/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb index b5a679ddd79..9f798f5b892 100644 --- a/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb +++ b/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb @@ -6,12 +6,12 @@ module Gitlab def query(environment_id) Environment.find_by(id: environment_id).try do |environment| - query_context = { - environment_slug: environment.slug, - environment_filter: %{container_name!="POD",environment="#{environment.slug}"}, - timeframe_start: 8.hours.ago.to_f, - timeframe_end: Time.now.to_f - } + query_context = common_query_context(environment).merge( + { + timeframe_start: 8.hours.ago.to_f, + timeframe_end: Time.now.to_f + } + ) query_metrics(query_context) end diff --git a/lib/gitlab/prometheus/queries/query_additional_metrics.rb b/lib/gitlab/prometheus/queries/query_additional_metrics.rb index e44be770544..003e6aa6c87 100644 --- a/lib/gitlab/prometheus/queries/query_additional_metrics.rb +++ b/lib/gitlab/prometheus/queries/query_additional_metrics.rb @@ -67,6 +67,18 @@ module Gitlab result.select { |group| group.metrics.any? } end + + def common_query_context(environment) + variables = { + ci_environment_slug: environment.slug, + kube_namespace: environment.project.kubernetes_service.actual_namespace, + }.flat_map { |k, v| [[k, v], [k.upcase, v]] }.to_h + + macros = { + environment_filter: %{container_name!="POD",environment="#{environment.slug}"} + } + variables.merge(macros) + end end end end -- cgit v1.2.1 From 6df5bd8b848322aa3e2ce5fd8cad0e2a20b06000 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Mon, 31 Jul 2017 13:29:00 +0200 Subject: Context handling and tests cleanup + simple test kube_namespace context test --- app/models/project_services/prometheus_service.rb | 5 ++++ .../prometheus/queries/query_additional_metrics.rb | 20 +++++++-------- .../additional_metrics_deployment_query_spec.rb | 11 +++----- .../additional_metrics_environment_query_spec.rb | 10 +++----- .../additional_metrics_shared_examples.rb | 29 ++++++++++++++++++++++ 5 files changed, 49 insertions(+), 26 deletions(-) diff --git a/app/models/project_services/prometheus_service.rb b/app/models/project_services/prometheus_service.rb index 217f753f05f..73cf4e97b56 100644 --- a/app/models/project_services/prometheus_service.rb +++ b/app/models/project_services/prometheus_service.rb @@ -75,6 +75,11 @@ class PrometheusService < MonitoringService with_reactive_cache(Gitlab::Prometheus::Queries::MatchedMetricsQuery.name, &:itself) end + def with_reactive_cache(name, *args, &block) + vals = args.map(&:to_s) + yield calculate_reactive_cache(name, *vals) + end + # Cache metrics for specific environment def calculate_reactive_cache(query_class_name, *args) return unless active? && project && !project.pending_delete? diff --git a/lib/gitlab/prometheus/queries/query_additional_metrics.rb b/lib/gitlab/prometheus/queries/query_additional_metrics.rb index 003e6aa6c87..5827c117556 100644 --- a/lib/gitlab/prometheus/queries/query_additional_metrics.rb +++ b/lib/gitlab/prometheus/queries/query_additional_metrics.rb @@ -42,15 +42,17 @@ module Gitlab end def process_query(context, query) - query_with_result = query.dup + query = query.dup result = if query.key?(:query_range) - client_query_range(query[:query_range] % context, start: context[:timeframe_start], stop: context[:timeframe_end]) + query[:query_range] %= context + client_query_range(query[:query_range], start: context[:timeframe_start], stop: context[:timeframe_end]) else - client_query(query[:query] % context, time: context[:timeframe_end]) + query[:query] %= context + client_query(query[:query], time: context[:timeframe_end]) end - query_with_result[:result] = result&.map(&:deep_symbolize_keys) - query_with_result + query[:result] = result&.map(&:deep_symbolize_keys) + query end def available_metrics @@ -69,15 +71,11 @@ module Gitlab end def common_query_context(environment) - variables = { + { ci_environment_slug: environment.slug, - kube_namespace: environment.project.kubernetes_service.actual_namespace, - }.flat_map { |k, v| [[k, v], [k.upcase, v]] }.to_h - - macros = { + kube_namespace: environment.project.kubernetes_service&.actual_namespace || '', environment_filter: %{container_name!="POD",environment="#{environment.slug}"} } - variables.merge(macros) end end end diff --git a/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb index e42e034f4fb..c7169717fc1 100644 --- a/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb +++ b/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb @@ -1,19 +1,14 @@ require 'spec_helper' describe Gitlab::Prometheus::Queries::AdditionalMetricsDeploymentQuery do - include Prometheus::MetricBuilders - - let(:client) { double('prometheus_client') } - let(:environment) { create(:environment, slug: 'environment-slug') } - let(:deployment) { create(:deployment, environment: environment) } - - subject(:query_result) { described_class.new(client).query(deployment.id) } - around do |example| Timecop.freeze(Time.local(2008, 9, 1, 12, 0, 0)) { example.run } end include_examples 'additional metrics query' do + let(:deployment) { create(:deployment, environment: environment) } + let(:query_params) { [deployment.id] } + it 'queries using specific time' do expect(client).to receive(:query_range).with(anything, start: (deployment.created_at - 30.minutes).to_f, diff --git a/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb index e9fd66d45fe..a02d2a90b97 100644 --- a/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb +++ b/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb @@ -1,18 +1,14 @@ require 'spec_helper' describe Gitlab::Prometheus::Queries::AdditionalMetricsEnvironmentQuery do - include Prometheus::MetricBuilders - - let(:client) { double('prometheus_client') } - let(:environment) { create(:environment, slug: 'environment-slug') } - - subject(:query_result) { described_class.new(client).query(environment.id) } - around do |example| Timecop.freeze { example.run } end include_examples 'additional metrics query' do + let(:query_result) { described_class.new(client).query(environment.id) } + let(:query_params) { [environment.id] } + it 'queries using specific time' do expect(client).to receive(:query_range).with(anything, start: 8.hours.ago.to_f, stop: Time.now.to_f) expect(query_result).not_to be_nil diff --git a/spec/support/prometheus/additional_metrics_shared_examples.rb b/spec/support/prometheus/additional_metrics_shared_examples.rb index 016e16fc8d4..fcb5c315b98 100644 --- a/spec/support/prometheus/additional_metrics_shared_examples.rb +++ b/spec/support/prometheus/additional_metrics_shared_examples.rb @@ -10,12 +10,39 @@ RSpec.shared_examples 'additional metrics query' do [{ 'metric': {}, 'values': [[1488758662.506, '0.00002996364761904785'], [1488758722.506, '0.00003090239047619091']] }] end + let(:client) { double('prometheus_client') } + let(:environment) { create(:environment, slug: 'environment-slug') } + before do allow(client).to receive(:label_values).and_return(metric_names) allow(metric_group_class).to receive(:all).and_return([simple_metric_group(metrics: [simple_metric])]) end + context 'metrics rendering' do + subject! { described_class.new(client) } + + before do + + end + + describe 'project has kubernetes service' do + let(:project) { create(:kubernetes_project) } + let(:environment) { create(:environment, slug: 'environment-slug', project: project) } + let(:kube_namespace) { project.kubernetes_service.actual_namespace } + + it 'query context contains kube namespace' do + expect(subject).to receive(:query_metrics).with( + hash_including( + kube_namespace: kube_namespace) + ) + subject.query(*query_params) + end + end + end + context 'with one group where two metrics is found' do + let(:query_result) { described_class.new(client).query(*query_params) } + before do allow(metric_group_class).to receive(:all).and_return([simple_metric_group]) end @@ -50,7 +77,9 @@ RSpec.shared_examples 'additional metrics query' do end context 'with two groups with one metric each' do + let(:query_result) { described_class.new(client).query(*query_params) } let(:metrics) { [simple_metric(queries: [simple_query])] } + before do allow(metric_group_class).to receive(:all).and_return( [ -- cgit v1.2.1 From 48778ac58973fa7cab09deaaf2e93806aa37113d Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Mon, 31 Jul 2017 15:26:38 +0200 Subject: Tests for query context variables --- app/models/project_services/prometheus_service.rb | 5 --- .../additional_metrics_environment_query_spec.rb | 2 +- .../additional_metrics_shared_examples.rb | 45 ++++++++++++++++------ 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/app/models/project_services/prometheus_service.rb b/app/models/project_services/prometheus_service.rb index 73cf4e97b56..217f753f05f 100644 --- a/app/models/project_services/prometheus_service.rb +++ b/app/models/project_services/prometheus_service.rb @@ -75,11 +75,6 @@ class PrometheusService < MonitoringService with_reactive_cache(Gitlab::Prometheus::Queries::MatchedMetricsQuery.name, &:itself) end - def with_reactive_cache(name, *args, &block) - vals = args.map(&:to_s) - yield calculate_reactive_cache(name, *vals) - end - # Cache metrics for specific environment def calculate_reactive_cache(query_class_name, *args) return unless active? && project && !project.pending_delete? diff --git a/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb index a02d2a90b97..5a88b23aa82 100644 --- a/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb +++ b/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb @@ -6,11 +6,11 @@ describe Gitlab::Prometheus::Queries::AdditionalMetricsEnvironmentQuery do end include_examples 'additional metrics query' do - let(:query_result) { described_class.new(client).query(environment.id) } let(:query_params) { [environment.id] } it 'queries using specific time' do expect(client).to receive(:query_range).with(anything, start: 8.hours.ago.to_f, stop: Time.now.to_f) + expect(query_result).not_to be_nil end end diff --git a/spec/support/prometheus/additional_metrics_shared_examples.rb b/spec/support/prometheus/additional_metrics_shared_examples.rb index fcb5c315b98..174297af158 100644 --- a/spec/support/prometheus/additional_metrics_shared_examples.rb +++ b/spec/support/prometheus/additional_metrics_shared_examples.rb @@ -11,6 +11,7 @@ RSpec.shared_examples 'additional metrics query' do end let(:client) { double('prometheus_client') } + let(:query_result) { described_class.new(client).query(*query_params) } let(:environment) { create(:environment, slug: 'environment-slug') } before do @@ -18,31 +19,52 @@ RSpec.shared_examples 'additional metrics query' do allow(metric_group_class).to receive(:all).and_return([simple_metric_group(metrics: [simple_metric])]) end - context 'metrics rendering' do + context 'metrics query context' do subject! { described_class.new(client) } - before do + shared_examples 'query context containing environment slug and filter' do + it 'query context contains ci_environment_slug' do + expect(subject).to receive(:query_metrics).with(hash_including(ci_environment_slug: environment.slug)) + + subject.query(*query_params) + end + it 'query context contains environment filter' do + expect(subject).to receive(:query_metrics).with( + hash_including( + environment_filter: "container_name!=\"POD\",environment=\"#{environment.slug}\"" + ) + ) + subject.query(*query_params) + end end - describe 'project has kubernetes service' do + describe 'project has Kubernetes service' do let(:project) { create(:kubernetes_project) } - let(:environment) { create(:environment, slug: 'environment-slug', project: project) } + let(:environment) { create(:environment, slug: 'environment-slug', project: project) } let(:kube_namespace) { project.kubernetes_service.actual_namespace } - it 'query context contains kube namespace' do - expect(subject).to receive(:query_metrics).with( - hash_including( - kube_namespace: kube_namespace) - ) + it_behaves_like 'query context containing environment slug and filter' + + it 'query context contains kube_namespace' do + expect(subject).to receive(:query_metrics).with(hash_including(kube_namespace: kube_namespace)) + + subject.query(*query_params) + end + end + + describe 'project without Kubernetes service' do + it_behaves_like 'query context containing environment slug and filter' + + it 'query context contains empty kube_namespace' do + expect(subject).to receive(:query_metrics).with(hash_including(kube_namespace: '')) + subject.query(*query_params) end end end context 'with one group where two metrics is found' do - let(:query_result) { described_class.new(client).query(*query_params) } - before do allow(metric_group_class).to receive(:all).and_return([simple_metric_group]) end @@ -77,7 +99,6 @@ RSpec.shared_examples 'additional metrics query' do end context 'with two groups with one metric each' do - let(:query_result) { described_class.new(client).query(*query_params) } let(:metrics) { [simple_metric(queries: [simple_query])] } before do -- cgit v1.2.1 From 6232543db3a784744e1cb03bb6a1a1648bb84b15 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Mon, 31 Jul 2017 16:31:07 +0200 Subject: Add changelog: add support for kube_namespace in Metrics queries + small whitespace fix to better separate tests --- .../pawel-add_more_variables_to_additional_metrics-35267.yml | 4 ++++ spec/support/prometheus/additional_metrics_shared_examples.rb | 1 + 2 files changed, 5 insertions(+) create mode 100644 changelogs/unreleased/pawel-add_more_variables_to_additional_metrics-35267.yml diff --git a/changelogs/unreleased/pawel-add_more_variables_to_additional_metrics-35267.yml b/changelogs/unreleased/pawel-add_more_variables_to_additional_metrics-35267.yml new file mode 100644 index 00000000000..c1e831306df --- /dev/null +++ b/changelogs/unreleased/pawel-add_more_variables_to_additional_metrics-35267.yml @@ -0,0 +1,4 @@ +--- +title: Add support for kube_namespace in Metrics queries +merge_request: 16169 +author: diff --git a/spec/support/prometheus/additional_metrics_shared_examples.rb b/spec/support/prometheus/additional_metrics_shared_examples.rb index 174297af158..18b02920104 100644 --- a/spec/support/prometheus/additional_metrics_shared_examples.rb +++ b/spec/support/prometheus/additional_metrics_shared_examples.rb @@ -35,6 +35,7 @@ RSpec.shared_examples 'additional metrics query' do environment_filter: "container_name!=\"POD\",environment=\"#{environment.slug}\"" ) ) + subject.query(*query_params) end end -- cgit v1.2.1 From 7b18c424644f98f04e527dd0c5e10b1c23f5bae4 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 31 Jul 2017 17:19:25 +0200 Subject: Remove unused (?) code --- lib/gitlab/diff/file.rb | 18 ------------------ spec/lib/gitlab/diff/file_spec.rb | 8 -------- 2 files changed, 26 deletions(-) diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index d2863a4da71..6d7de52cb80 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -79,13 +79,6 @@ module Gitlab @new_content_sha = refs&.head_sha end - def new_content_commit - return @new_content_commit if defined?(@new_content_commit) - - sha = new_content_commit - @new_content_commit = repository.commit(sha) if sha - end - def old_content_sha return if new_file? return @old_content_sha if defined?(@old_content_sha) @@ -94,13 +87,6 @@ module Gitlab @old_content_sha = refs&.base_sha end - def old_content_commit - return @old_content_commit if defined?(@old_content_commit) - - sha = old_content_sha - @old_content_commit = repository.commit(sha) if sha - end - def new_blob return @new_blob if defined?(@new_blob) @@ -123,10 +109,6 @@ module Gitlab new_content_sha || old_content_sha end - def content_commit - new_content_commit || old_content_commit - end - def blob new_blob || old_blob end diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb index cd2fa98b14c..d3d841b0668 100644 --- a/spec/lib/gitlab/diff/file_spec.rb +++ b/spec/lib/gitlab/diff/file_spec.rb @@ -47,14 +47,6 @@ describe Gitlab::Diff::File do end end - describe '#old_content_commit' do - it 'returns base commit' do - old_content_commit = diff_file.old_content_commit - - expect(old_content_commit.id).to eq('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') - end - end - describe '#old_blob' do it 'returns blob of commit of base commit' do old_data = diff_file.old_blob.data -- cgit v1.2.1 From 7b5a96b53c801d7fabef529481a525f3ab2ed2e3 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Mon, 31 Jul 2017 08:43:27 -0700 Subject: Fix LDAP documentation and example config --- config/gitlab.yml.example | 2 +- doc/administration/auth/ldap.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index e9bf2df490f..73a68c6da1b 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -282,7 +282,7 @@ production: &base # # Example: '/etc/ca.pem' # - ca_cert: '' + ca_file: '' # Specifies the SSL version for OpenSSL to use, if the OpenSSL default # is not appropriate. diff --git a/doc/administration/auth/ldap.md b/doc/administration/auth/ldap.md index a7395e03d1c..425c924cdf2 100644 --- a/doc/administration/auth/ldap.md +++ b/doc/administration/auth/ldap.md @@ -96,7 +96,7 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server # # Example: '/etc/ca.pem' # - ca_cert: '' + ca_file: '' # Specifies the SSL version for OpenSSL to use, if the OpenSSL default # is not appropriate. @@ -259,9 +259,9 @@ group you can use the following syntax: (memberOf:1.2.840.113556.1.4.1941:=CN=My Group,DC=Example,DC=com) ``` -Find more information about this "LDAP_MATCHING_RULE_IN_CHAIN" filter at +Find more information about this "LDAP_MATCHING_RULE_IN_CHAIN" filter at https://msdn.microsoft.com/en-us/library/aa746475(v=vs.85).aspx. Support for -nested members in the user filter should not be confused with +nested members in the user filter should not be confused with [group sync nested groups support (EE only)](https://docs.gitlab.com/ee/administration/auth/ldap-ee.html#supported-ldap-group-types-attributes). Please note that GitLab does not support the custom filter syntax used by -- cgit v1.2.1 From 15911ef32792b19daf192a0123a8a44ff393eb02 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Mon, 31 Jul 2017 17:33:57 +0100 Subject: Fix group milestone path on issuable sidebar --- app/helpers/gitlab_routing_helper.rb | 14 +++++- app/views/shared/issuable/_sidebar.html.haml | 2 +- ...ix-group-milestone-link-in-issuable-sidebar.yml | 4 ++ spec/factories/milestones.rb | 2 +- spec/helpers/gitlab_routing_helper_spec.rb | 53 ++++++++++++++++++---- 5 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 changelogs/unreleased/fix-group-milestone-link-in-issuable-sidebar.yml diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb index 0517a699ae0..1f7db9b2eb8 100644 --- a/app/helpers/gitlab_routing_helper.rb +++ b/app/helpers/gitlab_routing_helper.rb @@ -48,7 +48,11 @@ module GitlabRoutingHelper end def milestone_path(entity, *args) - project_milestone_path(entity.project, entity, *args) + if entity.is_group_milestone? + group_milestone_path(entity.group, entity, *args) + elsif entity.is_project_milestone? + project_milestone_path(entity.project, entity, *args) + end end def issue_url(entity, *args) @@ -63,6 +67,14 @@ module GitlabRoutingHelper project_pipeline_url(pipeline.project, pipeline.id, *args) end + def milestone_url(entity, *args) + if entity.is_group_milestone? + group_milestone_url(entity.group, entity, *args) + elsif entity.is_project_milestone? + project_milestone_url(entity.project, entity, *args) + end + end + def pipeline_job_url(pipeline, build, *args) project_job_url(pipeline.project, build.id, *args) end diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index b08267357e5..e7510c1d1ec 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -37,7 +37,7 @@ = link_to 'Edit', '#', class: 'edit-link pull-right' .value.hide-collapsed - if issuable.milestone - = link_to issuable.milestone.title, project_milestone_path(@project, issuable.milestone), class: "bold has-tooltip", title: milestone_remaining_days(issuable.milestone), data: { container: "body", html: 1 } + = link_to issuable.milestone.title, milestone_path(issuable.milestone), class: "bold has-tooltip", title: milestone_remaining_days(issuable.milestone), data: { container: "body", html: 1 } - else %span.no-value None diff --git a/changelogs/unreleased/fix-group-milestone-link-in-issuable-sidebar.yml b/changelogs/unreleased/fix-group-milestone-link-in-issuable-sidebar.yml new file mode 100644 index 00000000000..1558e575e6d --- /dev/null +++ b/changelogs/unreleased/fix-group-milestone-link-in-issuable-sidebar.yml @@ -0,0 +1,4 @@ +--- +title: Fix links to group milestones from issue and merge request sidebar +merge_request: +author: diff --git a/spec/factories/milestones.rb b/spec/factories/milestones.rb index 113665ff11b..b5e2ec60072 100644 --- a/spec/factories/milestones.rb +++ b/spec/factories/milestones.rb @@ -17,7 +17,7 @@ FactoryGirl.define do state "closed" end - after(:build) do |milestone, evaluator| + after(:build, :stub) do |milestone, evaluator| if evaluator.group milestone.group = evaluator.group elsif evaluator.group_id diff --git a/spec/helpers/gitlab_routing_helper_spec.rb b/spec/helpers/gitlab_routing_helper_spec.rb index 717ac1962d1..9aaed0edf87 100644 --- a/spec/helpers/gitlab_routing_helper_spec.rb +++ b/spec/helpers/gitlab_routing_helper_spec.rb @@ -1,6 +1,9 @@ require 'spec_helper' describe GitlabRoutingHelper do + let(:project) { build_stubbed(:empty_project) } + let(:group) { build_stubbed(:group) } + describe 'Project URL helpers' do describe '#project_member_path' do let(:project_member) { create(:project_member) } @@ -9,14 +12,10 @@ describe GitlabRoutingHelper do end describe '#request_access_project_members_path' do - let(:project) { build_stubbed(:empty_project) } - it { expect(request_access_project_members_path(project)).to eq request_access_project_project_members_path(project) } end describe '#leave_project_members_path' do - let(:project) { build_stubbed(:empty_project) } - it { expect(leave_project_members_path(project)).to eq leave_project_project_members_path(project) } end @@ -35,8 +34,6 @@ describe GitlabRoutingHelper do describe 'Group URL helpers' do describe '#group_members_url' do - let(:group) { build_stubbed(:group) } - it { expect(group_members_url(group)).to eq group_group_members_url(group) } end @@ -47,14 +44,10 @@ describe GitlabRoutingHelper do end describe '#request_access_group_members_path' do - let(:group) { build_stubbed(:group) } - it { expect(request_access_group_members_path(group)).to eq request_access_group_group_members_path(group) } end describe '#leave_group_members_path' do - let(:group) { build_stubbed(:group) } - it { expect(leave_group_members_path(group)).to eq leave_group_group_members_path(group) } end @@ -70,4 +63,44 @@ describe GitlabRoutingHelper do it { expect(resend_invite_group_member_path(group_member)).to eq resend_invite_group_group_member_path(group_member.source, group_member) } end end + + describe '#milestone_path' do + context 'for a group milestone' do + let(:milestone) { build_stubbed(:milestone, group: group, iid: 1) } + + it 'links to the group milestone page' do + expect(milestone_path(milestone)) + .to eq(group_milestone_path(group, milestone)) + end + end + + context 'for a project milestone' do + let(:milestone) { build_stubbed(:milestone, project: project, iid: 1) } + + it 'links to the project milestone page' do + expect(milestone_path(milestone)) + .to eq(project_milestone_path(project, milestone)) + end + end + end + + describe '#milestone_url' do + context 'for a group milestone' do + let(:milestone) { build_stubbed(:milestone, group: group, iid: 1) } + + it 'links to the group milestone page' do + expect(milestone_url(milestone)) + .to eq(group_milestone_url(group, milestone)) + end + end + + context 'for a project milestone' do + let(:milestone) { build_stubbed(:milestone, project: project, iid: 1) } + + it 'links to the project milestone page' do + expect(milestone_url(milestone)) + .to eq(project_milestone_url(project, milestone)) + end + end + end end -- cgit v1.2.1 From 82b5fe51eccc70eaa083822107b0aa620dab1b0b Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Mon, 31 Jul 2017 19:57:37 +0100 Subject: Uses jQuery to scroll since setting document.body.scrollTop does not work in firefox --- app/assets/javascripts/build.js | 19 ++++++++++--------- changelogs/unreleased/34492-firefox-job.yml | 4 ++++ 2 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 changelogs/unreleased/34492-firefox-job.yml diff --git a/app/assets/javascripts/build.js b/app/assets/javascripts/build.js index 1dfa064acfd..b3d3bbcf84f 100644 --- a/app/assets/javascripts/build.js +++ b/app/assets/javascripts/build.js @@ -64,7 +64,7 @@ window.Build = (function () { $(window) .off('scroll') .on('scroll', () => { - const contentHeight = this.$buildTraceOutput.prop('scrollHeight'); + const contentHeight = this.$buildTraceOutput.height(); if (contentHeight > this.windowSize) { // means the user did not scroll, the content was updated. this.windowSize = contentHeight; @@ -105,16 +105,17 @@ window.Build = (function () { }; Build.prototype.canScroll = function () { - return document.body.scrollHeight > window.innerHeight; + return $(document).height() > $(window).height(); }; Build.prototype.toggleScroll = function () { - const currentPosition = document.body.scrollTop; - const windowHeight = window.innerHeight; + const currentPosition = $(document).scrollTop(); + const scrollHeight = $(document).height(); + const windowHeight = $(window).height(); if (this.canScroll()) { if (currentPosition > 0 && - (document.body.scrollHeight - currentPosition !== windowHeight)) { + (scrollHeight - currentPosition !== windowHeight)) { // User is in the middle of the log this.toggleDisableButton(this.$scrollTopBtn, false); @@ -124,7 +125,7 @@ window.Build = (function () { this.toggleDisableButton(this.$scrollTopBtn, true); this.toggleDisableButton(this.$scrollBottomBtn, false); - } else if (document.body.scrollHeight - currentPosition === windowHeight) { + } else if (scrollHeight - currentPosition === windowHeight) { // User is at the bottom of the build log. this.toggleDisableButton(this.$scrollTopBtn, false); @@ -137,7 +138,7 @@ window.Build = (function () { }; Build.prototype.scrollDown = function () { - document.body.scrollTop = document.body.scrollHeight; + $(document).scrollTop($(document).height()); }; Build.prototype.scrollToBottom = function () { @@ -147,7 +148,7 @@ window.Build = (function () { }; Build.prototype.scrollToTop = function () { - document.body.scrollTop = 0; + $(document).scrollTop(0); this.hasBeenScrolled = true; this.toggleScroll(); }; @@ -178,7 +179,7 @@ window.Build = (function () { this.state = log.state; } - this.windowSize = this.$buildTraceOutput.prop('scrollHeight'); + this.windowSize = this.$buildTraceOutput.height(); if (log.append) { this.$buildTraceOutput.append(log.html); diff --git a/changelogs/unreleased/34492-firefox-job.yml b/changelogs/unreleased/34492-firefox-job.yml new file mode 100644 index 00000000000..881b8f649ea --- /dev/null +++ b/changelogs/unreleased/34492-firefox-job.yml @@ -0,0 +1,4 @@ +--- +title: Use jQuery to control scroll behavior in job log for cross browser consistency +merge_request: +author: -- cgit v1.2.1 From 618c3e7d2a525543f8fbc5fcfd81e9bbc8de60c1 Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Mon, 10 Jul 2017 00:05:21 +0900 Subject: Bump rubocop to 0.49.1 and rubocop-rspec to 1.15.1 --- .rubocop.yml | 452 ++++++++++++--------- .rubocop_todo.yml | 225 +++++----- Gemfile | 4 +- Gemfile.lock | 12 +- ...bocop-to-0-49-1-and-rubocop-rspec-to-1-15-1.yml | 4 + 5 files changed, 383 insertions(+), 314 deletions(-) create mode 100644 changelogs/unreleased/34869-bump-rubocop-to-0-49-1-and-rubocop-rspec-to-1-15-1.yml diff --git a/.rubocop.yml b/.rubocop.yml index f661a29d9d1..3e4275c271d 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -6,6 +6,7 @@ inherit_from: .rubocop_todo.yml AllCops: TargetRubyVersion: 2.3 + TargetRailsVersion: 4.2 # Cop names are not d§splayed in offense messages by default. Change behavior # by overriding DisplayCopNames, or by giving the -D/--display-cop-names # option. @@ -29,34 +30,230 @@ AllCops: Bundler/OrderedGems: Enabled: false -# Style ####################################################################### +# Layout ###################################################################### # Check indentation of private/protected visibility modifiers. -Style/AccessModifierIndentation: - Enabled: true - -# Check the naming of accessor methods for get_/set_. -Style/AccessorMethodName: - Enabled: false - -# Use alias_method instead of alias. -Style/Alias: - EnforcedStyle: prefer_alias_method +Layout/AccessModifierIndentation: Enabled: true # Align the elements of an array literal if they span more than one line. -Style/AlignArray: +Layout/AlignArray: Enabled: true # Align the elements of a hash literal if they span more than one line. -Style/AlignHash: +Layout/AlignHash: Enabled: true # Here we check if the parameters on a multi-line method call or # definition are aligned. -Style/AlignParameters: +Layout/AlignParameters: + Enabled: false + +# Put end statement of multiline block on its own line. +Layout/BlockEndNewline: + Enabled: true + +# Indentation of when in a case/when/[else/]end. +Layout/CaseIndentation: + Enabled: true + +# Indentation of comments. +Layout/CommentIndentation: + Enabled: true + +# Multi-line method chaining should be done with leading dots. +Layout/DotPosition: + Enabled: true + EnforcedStyle: leading + +# Align elses and elsifs correctly. +Layout/ElseAlignment: + Enabled: true + +# Add an empty line after magic comments to separate them from code. +Layout/EmptyLineAfterMagicComment: + Enabled: false + +# Use empty lines between defs. +Layout/EmptyLineBetweenDefs: + Enabled: true + +# Don't use several empty lines in a row. +Layout/EmptyLines: + Enabled: true + +# Keep blank lines around access modifiers. +Layout/EmptyLinesAroundAccessModifier: + Enabled: true + +# Keeps track of empty lines around block bodies. +Layout/EmptyLinesAroundBlockBody: + Enabled: true + +# Keeps track of empty lines around class bodies. +Layout/EmptyLinesAroundClassBody: + Enabled: true + +# Keeps track of empty lines around exception handling keywords. +Layout/EmptyLinesAroundExceptionHandlingKeywords: + Enabled: false + +# Keeps track of empty lines around method bodies. +Layout/EmptyLinesAroundMethodBody: + Enabled: true + +# Keeps track of empty lines around module bodies. +Layout/EmptyLinesAroundModuleBody: + Enabled: true + +# Use Unix-style line endings. +Layout/EndOfLine: + Enabled: true + +# Checks for a line break before the first parameter in a multi-line method +# parameter definition. +Layout/FirstMethodParameterLineBreak: + Enabled: true + +# Keep indentation straight. +Layout/IndentationConsistency: + Enabled: true + +# Use 2 spaces for indentation. +Layout/IndentationWidth: + Enabled: true + +# Checks the indentation of the first line of the right-hand-side of a +# multi-line assignment. +Layout/IndentAssignment: + Enabled: true + +# This cops checks the indentation of the here document bodies. +Layout/IndentHeredoc: + Enabled: false + +# Comments should start with a space. +Layout/LeadingCommentSpace: + Enabled: true + +# Checks that the closing brace in an array literal is either on the same line +# as the last array element, or a new line. +Layout/MultilineArrayBraceLayout: + Enabled: true + EnforcedStyle: symmetrical + +# Ensures newlines after multiline block do statements. +Layout/MultilineBlockLayout: + Enabled: true + +# Checks that the closing brace in a hash literal is either on the same line as +# the last hash element, or a new line. +Layout/MultilineHashBraceLayout: + Enabled: true + EnforcedStyle: symmetrical + +# Checks that the closing brace in a method call is either on the same line as +# the last method argument, or a new line. +Layout/MultilineMethodCallBraceLayout: + Enabled: false + EnforcedStyle: symmetrical + +# Checks indentation of method calls with the dot operator that span more than +# one line. +Layout/MultilineMethodCallIndentation: + Enabled: false + +# Checks that the closing brace in a method definition is symmetrical with +# respect to the opening brace and the method parameters. +Layout/MultilineMethodDefinitionBraceLayout: + Enabled: false + +# Checks indentation of binary operations that span more than one line. +Layout/MultilineOperationIndentation: + Enabled: true + EnforcedStyle: indented + +# Use spaces after colons. +Layout/SpaceAfterColon: + Enabled: true + +# Use spaces after commas. +Layout/SpaceAfterComma: + Enabled: true + +# Do not put a space between a method name and the opening parenthesis in a +# method definition. +Layout/SpaceAfterMethodName: + Enabled: true + +# Tracks redundant space after the ! operator. +Layout/SpaceAfterNot: + Enabled: true + +# Use spaces after semicolons. +Layout/SpaceAfterSemicolon: + Enabled: true + +# Use space around equals in parameter default +Layout/SpaceAroundEqualsInParameterDefault: + Enabled: true + +# Use a space around keywords if appropriate. +Layout/SpaceAroundKeyword: + Enabled: true + +# Use a single space around operators. +Layout/SpaceAroundOperators: + Enabled: true + +# No spaces before commas. +Layout/SpaceBeforeComma: + Enabled: true + +# Checks for missing space between code and a comment on the same line. +Layout/SpaceBeforeComment: + Enabled: true + +# No spaces before semicolons. +Layout/SpaceBeforeSemicolon: + Enabled: true + +# Checks for spaces inside square brackets. +Layout/SpaceInsideBrackets: + Enabled: true + +# Use spaces inside hash literal braces - or don't. +Layout/SpaceInsideHashLiteralBraces: + Enabled: true + +# No spaces inside range literals. +Layout/SpaceInsideRangeLiteral: + Enabled: true + +# Checks for padding/surrounding spaces inside string interpolation. +Layout/SpaceInsideStringInterpolation: + EnforcedStyle: no_space + Enabled: true + +# No hard tabs. +Layout/Tab: + Enabled: true + +# Checks trailing blank lines and final newline. +Layout/TrailingBlankLines: + Enabled: true + +# Style ####################################################################### + +# Check the naming of accessor methods for get_/set_. +Style/AccessorMethodName: Enabled: false +# Use alias_method instead of alias. +Style/Alias: + EnforcedStyle: prefer_alias_method + Enabled: true + # Whether `and` and `or` are banned only in conditionals (conditionals) # or completely (always). Style/AndOr: @@ -91,10 +288,6 @@ Style/BlockComments: Style/BlockDelimiters: Enabled: true -# Put end statement of multiline block on its own line. -Style/BlockEndNewline: - Enabled: true - # This cop checks for braces around the last parameter in a method call # if the last parameter is a hash. Style/BracesAroundHashParameters: @@ -104,10 +297,6 @@ Style/BracesAroundHashParameters: Style/CaseEquality: Enabled: false -# Indentation of when in a case/when/[else/]end. -Style/CaseIndentation: - Enabled: true - # Checks for uses of character literals. Style/CharacterLiteral: Enabled: true @@ -142,10 +331,6 @@ Style/ColonMethodCall: Style/CommentAnnotation: Enabled: false -# Indentation of comments. -Style/CommentIndentation: - Enabled: true - # Check for `if` and `case` statements where each branch is used for # assignment to the same variable when using the return of the # condition can be used instead. @@ -164,57 +349,16 @@ Style/DefWithParentheses: Style/Documentation: Enabled: false -# Multi-line method chaining should be done with leading dots. -Style/DotPosition: - Enabled: true - EnforcedStyle: leading - # This cop checks for uses of double negation (!!) to convert something # to a boolean value. As this is both cryptic and usually redundant, it # should be avoided. Style/DoubleNegation: Enabled: false -# Align elses and elsifs correctly. -Style/ElseAlignment: - Enabled: true - -# Use empty lines between defs. -Style/EmptyLineBetweenDefs: - Enabled: true - -# Don't use several empty lines in a row. -Style/EmptyLines: - Enabled: true - -# Keep blank lines around access modifiers. -Style/EmptyLinesAroundAccessModifier: - Enabled: true - -# Keeps track of empty lines around block bodies. -Style/EmptyLinesAroundBlockBody: - Enabled: true - -# Keeps track of empty lines around class bodies. -Style/EmptyLinesAroundClassBody: - Enabled: true - -# Keeps track of empty lines around method bodies. -Style/EmptyLinesAroundMethodBody: - Enabled: true - -# Keeps track of empty lines around module bodies. -Style/EmptyLinesAroundModuleBody: - Enabled: true - # Avoid the use of END blocks. Style/EndBlock: Enabled: true -# Use Unix-style line endings. -Style/EndOfLine: - Enabled: true - # Favor the use of Fixnum#even? && Fixnum#odd? Style/EvenOdd: Enabled: true @@ -223,11 +367,6 @@ Style/EvenOdd: Style/FileName: Enabled: true -# Checks for a line break before the first parameter in a multi-line method -# parameter definition. -Style/FirstMethodParameterLineBreak: - Enabled: true - # Checks for flip flops. Style/FlipFlop: Enabled: true @@ -236,6 +375,10 @@ Style/FlipFlop: Style/For: Enabled: true +# Use a consistent style for format string tokens. +Style/FormatStringToken: + Enabled: false + # Checks if there is a magic comment to enforce string literals Style/FrozenStringLiteralComment: Enabled: false @@ -261,31 +404,19 @@ Style/IdenticalConditionalBranches: Style/IfWithSemicolon: Enabled: true -# Checks the indentation of the first line of the right-hand-side of a -# multi-line assignment. -Style/IndentAssignment: - Enabled: true - -# Keep indentation straight. -Style/IndentationConsistency: - Enabled: true - -# Use 2 spaces for indentation. -Style/IndentationWidth: - Enabled: true - # Use Kernel#loop for infinite loops. Style/InfiniteLoop: Enabled: true +# Use the inverse method instead of `!.method` +# if an inverse method is defined. +Style/InverseMethods: + Enabled: false + # Use lambda.call(...) instead of lambda.(...). Style/LambdaCall: Enabled: true -# Comments should start with a space. -Style/LeadingCommentSpace: - Enabled: true - # Checks if the method definitions have or don't have parentheses. Style/MethodDefParentheses: Enabled: true @@ -298,55 +429,23 @@ Style/MethodName: Style/ModuleFunction: Enabled: false -# Checks that the closing brace in an array literal is either on the same line -# as the last array element, or a new line. -Style/MultilineArrayBraceLayout: - Enabled: true - EnforcedStyle: symmetrical - # Avoid multi-line chains of blocks. Style/MultilineBlockChain: Enabled: true -# Ensures newlines after multiline block do statements. -Style/MultilineBlockLayout: - Enabled: true - -# Checks that the closing brace in a hash literal is either on the same line as -# the last hash element, or a new line. -Style/MultilineHashBraceLayout: - Enabled: true - EnforcedStyle: symmetrical - # Do not use then for multi-line if/unless. Style/MultilineIfThen: Enabled: true -# Checks that the closing brace in a method call is either on the same line as -# the last method argument, or a new line. -Style/MultilineMethodCallBraceLayout: - Enabled: false - EnforcedStyle: symmetrical - -# Checks indentation of method calls with the dot operator that span more than -# one line. -Style/MultilineMethodCallIndentation: - Enabled: false - -# Checks that the closing brace in a method definition is symmetrical with -# respect to the opening brace and the method parameters. -Style/MultilineMethodDefinitionBraceLayout: - Enabled: false - -# Checks indentation of binary operations that span more than one line. -Style/MultilineOperationIndentation: - Enabled: true - EnforcedStyle: indented - # Avoid multi-line `? :` (the ternary operator), use if/unless instead. Style/MultilineTernaryOperator: Enabled: true +# Avoid comparing a variable with multiple items in a conditional, +# use Array#include? instead. +Style/MultipleComparison: + Enabled: false + # This cop checks whether some constant value isn't a # mutable literal (e.g. array or hash). Style/MutableConstant: @@ -421,68 +520,6 @@ Style/SignalException: EnforcedStyle: only_raise Enabled: true -# Use spaces after colons. -Style/SpaceAfterColon: - Enabled: true - -# Use spaces after commas. -Style/SpaceAfterComma: - Enabled: true - -# Do not put a space between a method name and the opening parenthesis in a -# method definition. -Style/SpaceAfterMethodName: - Enabled: true - -# Tracks redundant space after the ! operator. -Style/SpaceAfterNot: - Enabled: true - -# Use spaces after semicolons. -Style/SpaceAfterSemicolon: - Enabled: true - -# Use space around equals in parameter default -Style/SpaceAroundEqualsInParameterDefault: - Enabled: true - -# Use a space around keywords if appropriate. -Style/SpaceAroundKeyword: - Enabled: true - -# Use a single space around operators. -Style/SpaceAroundOperators: - Enabled: true - -# No spaces before commas. -Style/SpaceBeforeComma: - Enabled: true - -# Checks for missing space between code and a comment on the same line. -Style/SpaceBeforeComment: - Enabled: true - -# No spaces before semicolons. -Style/SpaceBeforeSemicolon: - Enabled: true - -# Checks for spaces inside square brackets. -Style/SpaceInsideBrackets: - Enabled: true - -# Use spaces inside hash literal braces - or don't. -Style/SpaceInsideHashLiteralBraces: - Enabled: true - -# No spaces inside range literals. -Style/SpaceInsideRangeLiteral: - Enabled: true - -# Checks for padding/surrounding spaces inside string interpolation. -Style/SpaceInsideStringInterpolation: - EnforcedStyle: no_space - Enabled: true - # Check for the usage of parentheses around stabby lambda arguments. Style/StabbyLambdaParentheses: EnforcedStyle: require_parentheses @@ -498,13 +535,9 @@ Style/StringMethods: intern: to_sym Enabled: true -# No hard tabs. -Style/Tab: - Enabled: true - -# Checks trailing blank lines and final newline. -Style/TrailingBlankLines: - Enabled: true +# Use %i or %I for arrays of symbols. +Style/SymbolArray: + Enabled: false # This cop checks for trailing comma in array and hash literals. Style/TrailingCommaInLiteral: @@ -553,6 +586,10 @@ Style/WhileUntilModifier: Style/WordArray: Enabled: true +# Do not use literals as the first operand of a comparison. +Style/YodaCondition: + Enabled: false + # Use `proc` instead of `Proc.new`. Style/Proc: Enabled: true @@ -608,6 +645,11 @@ Metrics/PerceivedComplexity: # Lint ######################################################################## +# Checks for ambiguous block association with method when param passed without +# parentheses. +Lint/AmbiguousBlockAssociation: + Enabled: false + # Checks for ambiguous operators in the first argument of a method invocation # without parentheses. Lint/AmbiguousOperator: @@ -809,6 +851,10 @@ Lint/Void: # Performance ################################################################# +# Use `caller(n..n)` instead of `caller`. +Performance/Caller: + Enabled: false + # Use `casecmp` rather than `downcase ==`. Performance/Casecmp: Enabled: true @@ -883,6 +929,14 @@ Rails/ActionFilter: Enabled: true EnforcedStyle: action +# Check that models subclass ApplicationRecord. +Rails/ApplicationRecord: + Enabled: false + +# Enforce using `blank?` and `present?`. +Rails/Blank: + Enabled: false + # Checks the correct usage of date aware methods, such as `Date.today`, # `Date.current`, etc. Rails/Date: @@ -939,10 +993,18 @@ Rails/OutputSafety: Rails/PluralizationGrammar: Enabled: true +# Enforce using `blank?` and `present?`. +Rails/Present: + Enabled: false + # Checks for `read_attribute(:attr)` and `write_attribute(:attr, val)`. Rails/ReadWriteAttribute: Enabled: false +# Do not assign relative date to constants. +Rails/RelativeDateConstant: + Enabled: false + # Checks the arguments of ActiveRecord scopes. Rails/ScopeArgs: Enabled: true diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 2ec558e274f..9caef3bde08 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,26 +1,89 @@ # This configuration was generated by # `rubocop --auto-gen-config --exclude-limit 0` -# on 2017-04-07 20:17:35 -0400 using RuboCop version 0.47.1. +# on 2017-07-10 01:48:30 +0900 using RuboCop version 0.49.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 233 +# Offense count: 181 +# Cop supports --auto-correct. +# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment. +Layout/ExtraSpacing: + Enabled: false + +# Offense count: 119 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: special_inside_parentheses, consistent, align_brackets +Layout/IndentArray: + Enabled: false + +# Offense count: 208 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# SupportedStyles: special_inside_parentheses, consistent, align_braces +Layout/IndentHash: + Enabled: false + +# Offense count: 174 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: space, no_space +Layout/SpaceBeforeBlockBraces: + Enabled: false + +# Offense count: 8 +# Cop supports --auto-correct. +# Configuration parameters: AllowForAlignment. +Layout/SpaceBeforeFirstArg: + Enabled: false + +# Offense count: 64 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles. +# SupportedStyles: require_no_space, require_space +Layout/SpaceInLambdaLiteral: + Enabled: false + +# Offense count: 256 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters. +# SupportedStyles: space, no_space +# SupportedStylesForEmptyBraces: space, no_space +Layout/SpaceInsideBlockBraces: + Enabled: false + +# Offense count: 135 +# Cop supports --auto-correct. +Layout/SpaceInsideParens: + Enabled: false + +# Offense count: 14 +# Cop supports --auto-correct. +Layout/SpaceInsidePercentLiteralDelimiters: + Enabled: false + +# Offense count: 89 +# Cop supports --auto-correct. +Layout/TrailingWhitespace: + Enabled: false + +# Offense count: 272 RSpec/EmptyLineAfterFinalLet: Enabled: false -# Offense count: 167 +# Offense count: 181 RSpec/EmptyLineAfterSubject: Enabled: false -# Offense count: 72 +# Offense count: 78 # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: implicit, each, example RSpec/HookArgument: Enabled: false -# Offense count: 11 +# Offense count: 9 # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: it_behaves_like, it_should_behave_like RSpec/ItBehavesLike: @@ -30,19 +93,19 @@ RSpec/ItBehavesLike: RSpec/IteratedExpectation: Enabled: false -# Offense count: 3 +# Offense count: 2 RSpec/OverwritingSetup: Enabled: false -# Offense count: 34 +# Offense count: 36 RSpec/RepeatedExample: Enabled: false -# Offense count: 43 +# Offense count: 86 RSpec/ScatteredLet: Enabled: false -# Offense count: 32 +# Offense count: 20 RSpec/ScatteredSetup: Enabled: false @@ -50,7 +113,7 @@ RSpec/ScatteredSetup: RSpec/SharedContext: Enabled: false -# Offense count: 150 +# Offense count: 115 Rails/FilePath: Enabled: false @@ -60,90 +123,71 @@ Rails/FilePath: Rails/ReversibleMigration: Enabled: false -# Offense count: 302 +# Offense count: 336 # Configuration parameters: Blacklist. # Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters Rails/SkipsModelValidations: Enabled: false -# Offense count: 7 +# Offense count: 11 # Cop supports --auto-correct. Security/YAMLLoad: Enabled: false -# Offense count: 59 +# Offense count: 58 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: percent_q, bare_percent Style/BarePercentLiterals: Enabled: false -# Offense count: 5 +# Offense count: 6 # Cop supports --auto-correct. Style/EachWithObject: Enabled: false -# Offense count: 28 +# Offense count: 31 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: empty, nil, both Style/EmptyElse: Enabled: false -# Offense count: 4 +# Offense count: 9 # Cop supports --auto-correct. Style/EmptyLiteral: Enabled: false -# Offense count: 59 +# Offense count: 78 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: compact, expanded Style/EmptyMethod: Enabled: false -# Offense count: 214 +# Offense count: 23 # Cop supports --auto-correct. -# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment. -Style/ExtraSpacing: - Enabled: false - -# Offense count: 9 # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: format, sprintf, percent Style/FormatString: Enabled: false -# Offense count: 285 +# Offense count: 301 # Configuration parameters: MinBodyLength. Style/GuardClause: Enabled: false -# Offense count: 16 +# Offense count: 18 Style/IfInsideElse: Enabled: false -# Offense count: 186 +# Offense count: 182 # Cop supports --auto-correct. # Configuration parameters: MaxLineLength. Style/IfUnlessModifier: Enabled: false -# Offense count: 99 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. -# SupportedStyles: special_inside_parentheses, consistent, align_brackets -Style/IndentArray: - Enabled: false - -# Offense count: 160 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. -# SupportedStyles: special_inside_parentheses, consistent, align_braces -Style/IndentHash: - Enabled: false - -# Offense count: 50 +# Offense count: 52 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: line_count_dependent, lambda, literal @@ -155,63 +199,63 @@ Style/Lambda: Style/LineEndConcatenation: Enabled: false -# Offense count: 34 +# Offense count: 40 # Cop supports --auto-correct. Style/MethodCallWithoutArgsParentheses: Enabled: false -# Offense count: 10 +# Offense count: 13 Style/MethodMissing: Enabled: false -# Offense count: 3 +# Offense count: 6 # Cop supports --auto-correct. Style/MultilineIfModifier: Enabled: false -# Offense count: 24 +# Offense count: 26 # Cop supports --auto-correct. Style/NestedParenthesizedCalls: Enabled: false -# Offense count: 18 +# Offense count: 20 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles. # SupportedStyles: skip_modifier_ifs, always Style/Next: Enabled: false -# Offense count: 37 +# Offense count: 45 # Cop supports --auto-correct. # Configuration parameters: EnforcedOctalStyle, SupportedOctalStyles. # SupportedOctalStyles: zero_with_o, zero_only Style/NumericLiteralPrefix: Enabled: false -# Offense count: 88 +# Offense count: 98 # Cop supports --auto-correct. # Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles. # SupportedStyles: predicate, comparison Style/NumericPredicate: Enabled: false -# Offense count: 36 +# Offense count: 42 # Cop supports --auto-correct. Style/ParallelAssignment: Enabled: false -# Offense count: 570 +# Offense count: 800 # Cop supports --auto-correct. # Configuration parameters: PreferredDelimiters. Style/PercentLiteralDelimiters: Enabled: false -# Offense count: 14 +# Offense count: 15 # Cop supports --auto-correct. Style/PerlBackrefs: Enabled: false -# Offense count: 83 +# Offense count: 105 # Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist. # NamePrefix: is_, has_, have_ # NamePrefixBlacklist: is_, has_, have_ @@ -219,47 +263,47 @@ Style/PerlBackrefs: Style/PredicateName: Enabled: false -# Offense count: 65 +# Offense count: 58 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: compact, exploded Style/RaiseArgs: Enabled: false -# Offense count: 5 +# Offense count: 6 # Cop supports --auto-correct. Style/RedundantBegin: Enabled: false -# Offense count: 32 +# Offense count: 37 # Cop supports --auto-correct. Style/RedundantFreeze: Enabled: false -# Offense count: 15 +# Offense count: 14 # Cop supports --auto-correct. # Configuration parameters: AllowMultipleReturnValues. Style/RedundantReturn: Enabled: false -# Offense count: 382 +# Offense count: 406 # Cop supports --auto-correct. Style/RedundantSelf: Enabled: false -# Offense count: 111 +# Offense count: 115 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes. # SupportedStyles: slashes, percent_r, mixed Style/RegexpLiteral: Enabled: false -# Offense count: 24 +# Offense count: 29 # Cop supports --auto-correct. Style/RescueModifier: Enabled: false -# Offense count: 7 +# Offense count: 8 # Cop supports --auto-correct. Style/SelfAssignment: Enabled: false @@ -270,101 +314,58 @@ Style/SelfAssignment: Style/SingleLineMethods: Enabled: false -# Offense count: 168 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: space, no_space -Style/SpaceBeforeBlockBraces: - Enabled: false - -# Offense count: 8 -# Cop supports --auto-correct. -# Configuration parameters: AllowForAlignment. -Style/SpaceBeforeFirstArg: - Enabled: false - -# Offense count: 46 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: require_no_space, require_space -Style/SpaceInLambdaLiteral: - Enabled: false - -# Offense count: 229 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters. -# SupportedStyles: space, no_space -# SupportedStylesForEmptyBraces: space, no_space -Style/SpaceInsideBlockBraces: - Enabled: false - -# Offense count: 116 -# Cop supports --auto-correct. -Style/SpaceInsideParens: - Enabled: false - -# Offense count: 12 -# Cop supports --auto-correct. -Style/SpaceInsidePercentLiteralDelimiters: - Enabled: false - -# Offense count: 57 +# Offense count: 64 # Cop supports --auto-correct. # Configuration parameters: SupportedStyles. # SupportedStyles: use_perl_names, use_english_names Style/SpecialGlobalVars: EnforcedStyle: use_perl_names -# Offense count: 42 +# Offense count: 44 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles. # SupportedStyles: single_quotes, double_quotes Style/StringLiteralsInInterpolation: Enabled: false -# Offense count: 64 +# Offense count: 84 # Cop supports --auto-correct. # Configuration parameters: IgnoredMethods. # IgnoredMethods: respond_to, define_method Style/SymbolProc: Enabled: false -# Offense count: 6 +# Offense count: 8 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SupportedStyles, AllowSafeAssignment. # SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex Style/TernaryParentheses: Enabled: false -# Offense count: 18 +# Offense count: 17 # Cop supports --auto-correct. # Configuration parameters: AllowNamedUnderscoreVariables. Style/TrailingUnderscoreVariable: Enabled: false -# Offense count: 78 -# Cop supports --auto-correct. -Style/TrailingWhitespace: - Enabled: false - -# Offense count: 3 +# Offense count: 4 # Cop supports --auto-correct. # Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist. # Whitelist: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym Style/TrivialAccessors: Enabled: false -# Offense count: 6 +# Offense count: 5 # Cop supports --auto-correct. Style/UnlessElse: Enabled: false -# Offense count: 24 +# Offense count: 28 # Cop supports --auto-correct. Style/UnneededInterpolation: Enabled: false -# Offense count: 8 +# Offense count: 11 # Cop supports --auto-correct. Style/ZeroLengthPredicate: Enabled: false diff --git a/Gemfile b/Gemfile index afea07ee6ff..a9a1cbc144d 100644 --- a/Gemfile +++ b/Gemfile @@ -339,8 +339,8 @@ group :development, :test do gem 'spring-commands-rspec', '~> 1.0.4' gem 'spring-commands-spinach', '~> 1.1.0' - gem 'rubocop', '~> 0.47.1', require: false - gem 'rubocop-rspec', '~> 1.15.0', require: false + gem 'rubocop', '~> 0.49.1', require: false + gem 'rubocop-rspec', '~> 1.15.1', require: false gem 'scss_lint', '~> 0.54.0', require: false gem 'haml_lint', '~> 0.21.0', require: false gem 'simplecov', '~> 0.14.0', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 05a70704513..5a327a14c4a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -545,6 +545,7 @@ GEM rubypants (~> 0.2) orm_adapter (0.5.0) os (0.9.6) + parallel (1.11.2) paranoia (2.3.1) activerecord (>= 4.0, < 5.2) parser (2.4.0.0) @@ -730,13 +731,14 @@ GEM pg rails sqlite3 - rubocop (0.47.1) + rubocop (0.49.1) + parallel (~> 1.10) parser (>= 2.3.3.1, < 3.0) powerpack (~> 0.1) rainbow (>= 1.99.1, < 3.0) ruby-progressbar (~> 1.7) unicode-display_width (~> 1.0, >= 1.0.1) - rubocop-rspec (1.15.0) + rubocop-rspec (1.15.1) rubocop (>= 0.42.0) ruby-fogbugz (0.2.1) crack (~> 0.4) @@ -868,7 +870,7 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.7.2) - unicode-display_width (1.1.3) + unicode-display_width (1.3.0) unicorn (5.1.0) kgio (~> 2.6) raindrops (~> 0.7) @@ -1078,8 +1080,8 @@ DEPENDENCIES rspec-retry (~> 0.4.5) rspec-set (~> 0.1.3) rspec_profiling (~> 0.0.5) - rubocop (~> 0.47.1) - rubocop-rspec (~> 1.15.0) + rubocop (~> 0.49.1) + rubocop-rspec (~> 1.15.1) ruby-fogbugz (~> 0.2.1) ruby-prof (~> 0.16.2) ruby_parser (~> 3.8) diff --git a/changelogs/unreleased/34869-bump-rubocop-to-0-49-1-and-rubocop-rspec-to-1-15-1.yml b/changelogs/unreleased/34869-bump-rubocop-to-0-49-1-and-rubocop-rspec-to-1-15-1.yml new file mode 100644 index 00000000000..0eb2d069719 --- /dev/null +++ b/changelogs/unreleased/34869-bump-rubocop-to-0-49-1-and-rubocop-rspec-to-1-15-1.yml @@ -0,0 +1,4 @@ +--- +title: Bump rubocop to 0.49.1 and rubocop-rspec to 1.15.1 +merge_request: +author: Takuya Noguchi -- cgit v1.2.1 From 547c6e8505c2fb3a0af321d20919812012008d2c Mon Sep 17 00:00:00 2001 From: John Landa Date: Tue, 1 Aug 2017 01:35:16 +0000 Subject: Fix username typo (jonh to John) --- doc/user/group/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user/group/index.md b/doc/user/group/index.md index 2691cf7d671..08da721c71d 100644 --- a/doc/user/group/index.md +++ b/doc/user/group/index.md @@ -42,7 +42,7 @@ In GitLab, a namespace is a unique name to be used as a user name, a group name, For example, consider a user called John: -1. John creates his account on GitLab.com with the username `jonh`; +1. John creates his account on GitLab.com with the username `john`; his profile will be accessed under `https://gitlab.example.com/john` 1. John creates a group for his team with the groupname `john-team`; his group and its projects will be accessed under `https://gitlab.example.com/john-team` -- cgit v1.2.1 From faa2a123911eaf84bb57163ea7af759d4632601b Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Mon, 31 Jul 2017 22:49:12 -0500 Subject: Update CHANGELOG.md for 9.4.3 [ci skip] --- CHANGELOG.md | 10 ++++++++++ .../35567-fix-relative-urls-in-webpack-public-path.yml | 5 ----- changelogs/unreleased/35672-edge-top-bar.yml | 4 ---- .../unreleased/dm-ldap-authentication-ssl-verification.yml | 4 ---- .../fix-gb-fix-chatops-deploy-multiple-actions-matching.yml | 4 ---- changelogs/unreleased/help-page-breadcrumb-title-fix.yml | 4 ---- ...pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml | 4 ---- .../unreleased/pawel-prometheus_client_pid_reuse_error.yml | 4 ---- 8 files changed, 10 insertions(+), 29 deletions(-) delete mode 100644 changelogs/unreleased/35567-fix-relative-urls-in-webpack-public-path.yml delete mode 100644 changelogs/unreleased/35672-edge-top-bar.yml delete mode 100644 changelogs/unreleased/dm-ldap-authentication-ssl-verification.yml delete mode 100644 changelogs/unreleased/fix-gb-fix-chatops-deploy-multiple-actions-matching.yml delete mode 100644 changelogs/unreleased/help-page-breadcrumb-title-fix.yml delete mode 100644 changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml delete mode 100644 changelogs/unreleased/pawel-prometheus_client_pid_reuse_error.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 412cd86bad6..706823ed693 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 9.4.3 (2017-07-31) + +- Fix Prometheus client PID reuse bug. !13130 +- Improve deploy environment chatops slash command. !13150 +- Fix asynchronous javascript paths when GitLab is installed under a relative URL. !13165 +- Fix LDAP authentication to Git repository or container registry. +- Fixed new navigation breadcrumb title on help pages. +- Ensure filesystem metrics test files are deleted. +- Properly affixes nav bar in job view in microsoft edge. + ## 9.4.2 (2017-07-28) - Fix job merge request link to a forked source project. !12965 diff --git a/changelogs/unreleased/35567-fix-relative-urls-in-webpack-public-path.yml b/changelogs/unreleased/35567-fix-relative-urls-in-webpack-public-path.yml deleted file mode 100644 index 41b506681f9..00000000000 --- a/changelogs/unreleased/35567-fix-relative-urls-in-webpack-public-path.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix asynchronous javascript paths when GitLab is installed under a relative - URL -merge_request: 13165 -author: diff --git a/changelogs/unreleased/35672-edge-top-bar.yml b/changelogs/unreleased/35672-edge-top-bar.yml deleted file mode 100644 index 0424dee19af..00000000000 --- a/changelogs/unreleased/35672-edge-top-bar.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Properly affixes nav bar in job view in microsoft edge -merge_request: -author: diff --git a/changelogs/unreleased/dm-ldap-authentication-ssl-verification.yml b/changelogs/unreleased/dm-ldap-authentication-ssl-verification.yml deleted file mode 100644 index 59462a6666d..00000000000 --- a/changelogs/unreleased/dm-ldap-authentication-ssl-verification.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix LDAP authentication to Git repository or container registry -merge_request: -author: diff --git a/changelogs/unreleased/fix-gb-fix-chatops-deploy-multiple-actions-matching.yml b/changelogs/unreleased/fix-gb-fix-chatops-deploy-multiple-actions-matching.yml deleted file mode 100644 index 62488a0a2e3..00000000000 --- a/changelogs/unreleased/fix-gb-fix-chatops-deploy-multiple-actions-matching.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Improve deploy environment chatops slash command -merge_request: 13150 -author: diff --git a/changelogs/unreleased/help-page-breadcrumb-title-fix.yml b/changelogs/unreleased/help-page-breadcrumb-title-fix.yml deleted file mode 100644 index 040fe4b9916..00000000000 --- a/changelogs/unreleased/help-page-breadcrumb-title-fix.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixed new navigation breadcrumb title on help pages -merge_request: -author: diff --git a/changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml b/changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml deleted file mode 100644 index 1186dc59dc7..00000000000 --- a/changelogs/unreleased/pawel-ensure_temp_files_are_deleted_in_fs_metrics-35457.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Ensure filesystem metrics test files are deleted -merge_request: -author: diff --git a/changelogs/unreleased/pawel-prometheus_client_pid_reuse_error.yml b/changelogs/unreleased/pawel-prometheus_client_pid_reuse_error.yml deleted file mode 100644 index dfff4c23308..00000000000 --- a/changelogs/unreleased/pawel-prometheus_client_pid_reuse_error.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix Prometheus client PID reuse bug -merge_request: 13130 -author: -- cgit v1.2.1 From 953aa380ebbbcaef8974c3cfb0e15925dbc2c9b6 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Tue, 1 Aug 2017 14:16:10 +0900 Subject: ini --- rubocop/cop/migration/add_column_with_default_to_large_table.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/rubocop/cop/migration/add_column_with_default_to_large_table.rb b/rubocop/cop/migration/add_column_with_default_to_large_table.rb index 87788b0d9c2..fb363f95b56 100644 --- a/rubocop/cop/migration/add_column_with_default_to_large_table.rb +++ b/rubocop/cop/migration/add_column_with_default_to_large_table.rb @@ -20,6 +20,7 @@ module RuboCop 'necessary'.freeze LARGE_TABLES = %i[ + ci_pipelines ci_builds events issues -- cgit v1.2.1 From b5f11ee90ca1d119160c27e5377ce812edaf5848 Mon Sep 17 00:00:00 2001 From: Semen Romanov Date: Tue, 1 Aug 2017 05:25:26 +0000 Subject: Invalid variable --- lib/support/init.d/gitlab | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/support/init.d/gitlab b/lib/support/init.d/gitlab index c5f93336346..2f2de083dc0 100755 --- a/lib/support/init.d/gitlab +++ b/lib/support/init.d/gitlab @@ -291,7 +291,7 @@ start_gitlab() { fi if [ "$gitlab_workhorse_status" = "0" ]; then - echo "The GitLab Workhorse is already running with pid $spid, not restarting" + echo "The GitLab Workhorse is already running with pid $hpid, not restarting" else # No need to remove a socket, gitlab-workhorse does this itself. # Because gitlab-workhorse has multiple executables we need to fix @@ -313,7 +313,7 @@ start_gitlab() { if [ "$gitlab_pages_enabled" = true ]; then if [ "$gitlab_pages_status" = "0" ]; then - echo "The GitLab Pages is already running with pid $spid, not restarting" + echo "The GitLab Pages is already running with pid $gppid, not restarting" else $app_root/bin/daemon_with_pidfile $gitlab_pages_pid_path \ $gitlab_pages_dir/gitlab-pages $gitlab_pages_options \ @@ -421,7 +421,7 @@ print_status() { fi if [ "$gitlab_pages_enabled" = true ]; then if [ "$gitlab_pages_status" = "0" ]; then - echo "The GitLab Pages with pid $mpid is running." + echo "The GitLab Pages with pid $gppid is running." else printf "The GitLab Pages is \033[31mnot running\033[0m.\n" fi -- cgit v1.2.1 From 98615318883e37a4c9cb201e3e65bb7b775112cd Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Wed, 5 Jul 2017 02:19:02 +0200 Subject: Move storage specific code from Namespace and Project to concerns --- app/models/concerns/storage/legacy_namespace.rb | 109 ++++++++++++++++++++++++ app/models/concerns/storage/legacy_project.rb | 76 +++++++++++++++++ app/models/namespace.rb | 104 +--------------------- app/models/project.rb | 73 ++-------------- 4 files changed, 194 insertions(+), 168 deletions(-) create mode 100644 app/models/concerns/storage/legacy_namespace.rb create mode 100644 app/models/concerns/storage/legacy_project.rb diff --git a/app/models/concerns/storage/legacy_namespace.rb b/app/models/concerns/storage/legacy_namespace.rb new file mode 100644 index 00000000000..5cbd52e5c75 --- /dev/null +++ b/app/models/concerns/storage/legacy_namespace.rb @@ -0,0 +1,109 @@ +module Storage + module LegacyNamespace + extend ActiveSupport::Concern + + def move_dir + if any_project_has_container_registry_tags? + raise Gitlab::UpdatePathError.new('Namespace cannot be moved, because at least one project has tags in container registry') + end + + # Move the namespace directory in all storages paths used by member projects + repository_storage_paths.each do |repository_storage_path| + # Ensure old directory exists before moving it + gitlab_shell.add_namespace(repository_storage_path, full_path_was) + + unless gitlab_shell.mv_namespace(repository_storage_path, full_path_was, full_path) + Rails.logger.error "Exception moving path #{repository_storage_path} from #{full_path_was} to #{full_path}" + + # if we cannot move namespace directory we should rollback + # db changes in order to prevent out of sync between db and fs + raise Gitlab::UpdatePathError.new('namespace directory cannot be moved') + end + end + + Gitlab::UploadsTransfer.new.rename_namespace(full_path_was, full_path) + Gitlab::PagesTransfer.new.rename_namespace(full_path_was, full_path) + + remove_exports! + + # If repositories moved successfully we need to + # send update instructions to users. + # However we cannot allow rollback since we moved namespace dir + # So we basically we mute exceptions in next actions + begin + send_update_instructions + true + rescue + # Returning false does not rollback after_* transaction but gives + # us information about failing some of tasks + false + end + end + + # Hooks + + # Save the storage paths before the projects are destroyed to use them on after destroy + def prepare_for_destroy + old_repository_storage_paths + end + + private + + def send_update_instructions + projects.each do |project| + project.send_move_instructions("#{full_path_was}/#{project.path}") + end + end + + def old_repository_storage_paths + @old_repository_storage_paths ||= repository_storage_paths + end + + def repository_storage_paths + # We need to get the storage paths for all the projects, even the ones that are + # pending delete. Unscoping also get rids of the default order, which causes + # problems with SELECT DISTINCT. + Project.unscoped do + all_projects.select('distinct(repository_storage)').to_a.map(&:repository_storage_path) + end + end + + def rm_dir + # Remove the namespace directory in all storages paths used by member projects + old_repository_storage_paths.each do |repository_storage_path| + # Move namespace directory into trash. + # We will remove it later async + new_path = "#{full_path}+#{id}+deleted" + + if gitlab_shell.mv_namespace(repository_storage_path, full_path, new_path) + message = "Namespace directory \"#{full_path}\" moved to \"#{new_path}\"" + Gitlab::AppLogger.info message + + # Remove namespace directroy async with delay so + # GitLab has time to remove all projects first + run_after_commit do + GitlabShellWorker.perform_in(5.minutes, :rm_namespace, repository_storage_path, new_path) + end + end + end + + remove_exports! + end + + def remove_exports! + Gitlab::Popen.popen(%W(find #{export_path} -not -path #{export_path} -delete)) + end + + def export_path + File.join(Gitlab::ImportExport.storage_path, full_path_was) + end + + def full_path_was + if parent + parent.full_path + '/' + path_was + else + path_was + end + end + end +end diff --git a/app/models/concerns/storage/legacy_project.rb b/app/models/concerns/storage/legacy_project.rb new file mode 100644 index 00000000000..b537f40548e --- /dev/null +++ b/app/models/concerns/storage/legacy_project.rb @@ -0,0 +1,76 @@ +module Storage + module LegacyProject + extend ActiveSupport::Concern + + def disk_path + full_path + end + + def ensure_dir_exist + gitlab_shell.add_namespace(repository_storage_path, namespace.full_path) + end + + def rename_repo + path_was = previous_changes['path'].first + old_path_with_namespace = File.join(namespace.full_path, path_was) + new_path_with_namespace = File.join(namespace.full_path, path) + + Rails.logger.error "Attempting to rename #{old_path_with_namespace} -> #{new_path_with_namespace}" + + if has_container_registry_tags? + Rails.logger.error "Project #{old_path_with_namespace} cannot be renamed because container registry tags are present!" + + # we currently doesn't support renaming repository if it contains images in container registry + raise StandardError.new('Project cannot be renamed, because images are present in its container registry') + end + + expire_caches_before_rename(old_path_with_namespace) + + if gitlab_shell.mv_repository(repository_storage_path, old_path_with_namespace, new_path_with_namespace) + # If repository moved successfully we need to send update instructions to users. + # However we cannot allow rollback since we moved repository + # So we basically we mute exceptions in next actions + begin + gitlab_shell.mv_repository(repository_storage_path, "#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki") + send_move_instructions(old_path_with_namespace) + expires_full_path_cache + + @old_path_with_namespace = old_path_with_namespace + + SystemHooksService.new.execute_hooks_for(self, :rename) + + @repository = nil + rescue => e + Rails.logger.error "Exception renaming #{old_path_with_namespace} -> #{new_path_with_namespace}: #{e}" + # Returning false does not rollback after_* transaction but gives + # us information about failing some of tasks + false + end + else + Rails.logger.error "Repository could not be renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}" + + # if we cannot move namespace directory we should rollback + # db changes in order to prevent out of sync between db and fs + raise StandardError.new('repository cannot be renamed') + end + + Gitlab::AppLogger.info "Project was renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}" + + Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.full_path) + Gitlab::PagesTransfer.new.rename_project(path_was, path, namespace.full_path) + end + + def create_repository(force: false) + # Forked import is handled asynchronously + return if forked? && !force + + if gitlab_shell.add_repository(repository_storage_path, path_with_namespace) + repository.after_create + true + else + errors.add(:base, 'Failed to create repository via gitlab-shell') + false + end + end + end +end diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 0bb04194bdb..010c97c507e 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -8,6 +8,7 @@ class Namespace < ActiveRecord::Base include Gitlab::VisibilityLevel include Routable include AfterCommitQueue + include Storage::LegacyNamespace # Prevent users from creating unreasonably deep level of nesting. # The number 20 was taken based on maximum nesting level of @@ -41,10 +42,11 @@ class Namespace < ActiveRecord::Base delegate :name, to: :owner, allow_nil: true, prefix: true - after_update :move_dir, if: :path_changed? after_commit :refresh_access_of_projects_invited_groups, on: :update, if: -> { previous_changes.key?('share_with_group_lock') } - # Save the storage paths before the projects are destroyed to use them on after destroy + # Legacy Storage specific hooks + + after_update :move_dir, if: :path_changed? before_destroy(prepend: true) { prepare_for_destroy } after_destroy :rm_dir @@ -118,53 +120,10 @@ class Namespace < ActiveRecord::Base owner_name end - def move_dir - if any_project_has_container_registry_tags? - raise Gitlab::UpdatePathError.new('Namespace cannot be moved, because at least one project has tags in container registry') - end - - # Move the namespace directory in all storages paths used by member projects - repository_storage_paths.each do |repository_storage_path| - # Ensure old directory exists before moving it - gitlab_shell.add_namespace(repository_storage_path, full_path_was) - - unless gitlab_shell.mv_namespace(repository_storage_path, full_path_was, full_path) - Rails.logger.error "Exception moving path #{repository_storage_path} from #{full_path_was} to #{full_path}" - - # if we cannot move namespace directory we should rollback - # db changes in order to prevent out of sync between db and fs - raise Gitlab::UpdatePathError.new('namespace directory cannot be moved') - end - end - - Gitlab::UploadsTransfer.new.rename_namespace(full_path_was, full_path) - Gitlab::PagesTransfer.new.rename_namespace(full_path_was, full_path) - - remove_exports! - - # If repositories moved successfully we need to - # send update instructions to users. - # However we cannot allow rollback since we moved namespace dir - # So we basically we mute exceptions in next actions - begin - send_update_instructions - rescue - # Returning false does not rollback after_* transaction but gives - # us information about failing some of tasks - false - end - end - def any_project_has_container_registry_tags? all_projects.any?(&:has_container_registry_tags?) end - def send_update_instructions - projects.each do |project| - project.send_move_instructions("#{full_path_was}/#{project.path}") - end - end - def kind type == 'Group' ? 'group' : 'user' end @@ -206,14 +165,6 @@ class Namespace < ActiveRecord::Base parent_id_changed? end - def prepare_for_destroy - old_repository_storage_paths - end - - def old_repository_storage_paths - @old_repository_storage_paths ||= repository_storage_paths - end - # Includes projects from this namespace and projects from all subgroups # that belongs to this namespace def all_projects @@ -232,37 +183,6 @@ class Namespace < ActiveRecord::Base private - def repository_storage_paths - # We need to get the storage paths for all the projects, even the ones that are - # pending delete. Unscoping also get rids of the default order, which causes - # problems with SELECT DISTINCT. - Project.unscoped do - all_projects.select('distinct(repository_storage)').to_a.map(&:repository_storage_path) - end - end - - def rm_dir - # Remove the namespace directory in all storages paths used by member projects - old_repository_storage_paths.each do |repository_storage_path| - # Move namespace directory into trash. - # We will remove it later async - new_path = "#{full_path}+#{id}+deleted" - - if gitlab_shell.mv_namespace(repository_storage_path, full_path, new_path) - message = "Namespace directory \"#{full_path}\" moved to \"#{new_path}\"" - Gitlab::AppLogger.info message - - # Remove namespace directroy async with delay so - # GitLab has time to remove all projects first - run_after_commit do - GitlabShellWorker.perform_in(5.minutes, :rm_namespace, repository_storage_path, new_path) - end - end - end - - remove_exports! - end - def refresh_access_of_projects_invited_groups Group .joins(project_group_links: :project) @@ -270,22 +190,6 @@ class Namespace < ActiveRecord::Base .find_each(&:refresh_members_authorized_projects) end - def remove_exports! - Gitlab::Popen.popen(%W(find #{export_path} -not -path #{export_path} -delete)) - end - - def export_path - File.join(Gitlab::ImportExport.storage_path, full_path_was) - end - - def full_path_was - if parent - parent.full_path + '/' + path_was - else - path_was - end - end - def nesting_level_allowed if ancestors.count > Group::NUMBER_OF_ANCESTORS_ALLOWED errors.add(:parent_id, "has too deep level of nesting") diff --git a/app/models/project.rb b/app/models/project.rb index d827bfaa806..39949e6dbfd 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -17,6 +17,7 @@ class Project < ActiveRecord::Base include ProjectFeaturesCompatibility include SelectForProjectAuthorization include Routable + include Storage::LegacyProject extend Gitlab::ConfigHelper @@ -45,7 +46,6 @@ class Project < ActiveRecord::Base after_create :ensure_dir_exist after_create :create_project_feature, unless: :project_feature - after_save :ensure_dir_exist, if: :namespace_id_changed? after_save :update_project_statistics, if: :namespace_id_changed? # set last_activity_at to the same as created_at @@ -67,6 +67,10 @@ class Project < ActiveRecord::Base after_validation :check_pending_delete + # Legacy Storage specific hooks + + after_save :ensure_dir_exist, if: :namespace_id_changed? + acts_as_taggable attr_accessor :new_default_branch @@ -974,56 +978,6 @@ class Project < ActiveRecord::Base !group end - def rename_repo - path_was = previous_changes['path'].first - old_path_with_namespace = File.join(namespace.full_path, path_was) - new_path_with_namespace = File.join(namespace.full_path, path) - - Rails.logger.error "Attempting to rename #{old_path_with_namespace} -> #{new_path_with_namespace}" - - if has_container_registry_tags? - Rails.logger.error "Project #{old_path_with_namespace} cannot be renamed because container registry tags are present!" - - # we currently doesn't support renaming repository if it contains images in container registry - raise StandardError.new('Project cannot be renamed, because images are present in its container registry') - end - - expire_caches_before_rename(old_path_with_namespace) - - if gitlab_shell.mv_repository(repository_storage_path, old_path_with_namespace, new_path_with_namespace) - # If repository moved successfully we need to send update instructions to users. - # However we cannot allow rollback since we moved repository - # So we basically we mute exceptions in next actions - begin - gitlab_shell.mv_repository(repository_storage_path, "#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki") - send_move_instructions(old_path_with_namespace) - expires_full_path_cache - - @old_path_with_namespace = old_path_with_namespace - - SystemHooksService.new.execute_hooks_for(self, :rename) - - @repository = nil - rescue => e - Rails.logger.error "Exception renaming #{old_path_with_namespace} -> #{new_path_with_namespace}: #{e}" - # Returning false does not rollback after_* transaction but gives - # us information about failing some of tasks - false - end - else - Rails.logger.error "Repository could not be renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}" - - # if we cannot move namespace directory we should rollback - # db changes in order to prevent out of sync between db and fs - raise StandardError.new('repository cannot be renamed') - end - - Gitlab::AppLogger.info "Project was renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}" - - Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.full_path) - Gitlab::PagesTransfer.new.rename_project(path_was, path, namespace.full_path) - end - # Expires various caches before a project is renamed. def expire_caches_before_rename(old_path) repo = Repository.new(old_path, self) @@ -1109,19 +1063,6 @@ class Project < ActiveRecord::Base merge_requests.where(source_project_id: self.id) end - def create_repository(force: false) - # Forked import is handled asynchronously - return if forked? && !force - - if gitlab_shell.add_repository(repository_storage_path, path_with_namespace) - repository.after_create - true - else - errors.add(:base, 'Failed to create repository via gitlab-shell') - false - end - end - def ensure_repository create_repository(force: true) unless repository_exists? end @@ -1327,10 +1268,6 @@ class Project < ActiveRecord::Base status.zero? end - def ensure_dir_exist - gitlab_shell.add_namespace(repository_storage_path, namespace.full_path) - end - def predefined_variables [ { key: 'CI_PROJECT_ID', value: id.to_s, public: true }, -- cgit v1.2.1 From abb878326c5cac283fff19716149211658ce25d1 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Thu, 20 Jul 2017 11:34:09 +0200 Subject: Rename many path_with_namespace -> full_path --- app/helpers/merge_requests_helper.rb | 2 +- app/helpers/projects_helper.rb | 4 +- app/mailers/notify.rb | 2 +- app/models/ci/pipeline.rb | 2 +- app/models/merge_request.rb | 4 +- app/models/project.rb | 23 ++++++----- app/models/project_services/flowdock_service.rb | 6 +-- app/models/project_services/jira_service.rb | 2 +- app/models/project_wiki.rb | 4 +- app/services/git_operation_service.rb | 2 +- app/services/projects/destroy_service.rb | 2 +- app/services/projects/import_service.rb | 2 +- app/services/projects/transfer_service.rb | 2 +- app/services/system_hooks_service.rb | 8 ++-- app/workers/irker_worker.rb | 4 +- app/workers/repository_import_worker.rb | 2 +- ...124141322_migrate_process_commit_worker_jobs.rb | 1 + features/steps/project/forked_merge_requests.rb | 12 +++--- features/steps/project/redirects.rb | 4 +- features/steps/project/wiki.rb | 2 +- lib/api/runner.rb | 4 +- lib/backup/repository.rb | 6 +-- lib/banzai/filter/abstract_reference_filter.rb | 4 +- lib/banzai/filter/upload_link_filter.rb | 2 +- lib/ci/api/builds.rb | 4 +- lib/github/import.rb | 2 +- lib/gitlab/bitbucket_import/importer.rb | 2 +- lib/gitlab/email/message/repository_push.rb | 2 +- lib/gitlab/github_import/wiki_formatter.rb | 2 +- spec/controllers/projects/blob_controller_spec.rb | 2 +- .../projects/branches_controller_spec.rb | 6 +-- .../projects/merge_requests_controller_spec.rb | 2 +- spec/controllers/projects/tree_controller_spec.rb | 6 +-- spec/features/merge_requests/create_new_mr_spec.rb | 8 ++-- .../projects/wiki/markdown_preview_spec.rb | 48 +++++++++++----------- spec/helpers/labels_helper_spec.rb | 4 +- spec/helpers/markup_helper_spec.rb | 4 +- spec/helpers/merge_requests_helper_spec.rb | 4 +- spec/helpers/projects_helper_spec.rb | 4 +- .../filter/abstract_reference_filter_spec.rb | 14 +++---- .../filter/commit_range_reference_filter_spec.rb | 10 ++--- .../banzai/filter/commit_reference_filter_spec.rb | 10 ++--- .../banzai/filter/issue_reference_filter_spec.rb | 12 +++--- .../banzai/filter/label_reference_filter_spec.rb | 10 ++--- .../filter/merge_request_reference_filter_spec.rb | 4 +- .../filter/milestone_reference_filter_spec.rb | 34 ++++++++++++--- .../lib/banzai/filter/relative_link_filter_spec.rb | 2 +- .../banzai/filter/snippet_reference_filter_spec.rb | 4 +- spec/lib/extracts_path_spec.rb | 4 +- .../gitlab/email/message/repository_push_spec.rb | 2 +- spec/lib/gitlab/gfm/uploads_rewriter_spec.rb | 4 +- spec/lib/gitlab/import_export/fork_spec.rb | 2 +- .../import_export/project_tree_saver_spec.rb | 2 +- .../lib/gitlab/import_export/repo_restorer_spec.rb | 2 +- spec/lib/gitlab/import_export/repo_saver_spec.rb | 2 +- .../gitlab/import_export/wiki_repo_saver_spec.rb | 2 +- spec/lib/gitlab/url_builder_spec.rb | 18 ++++---- .../migrate_process_commit_worker_jobs_spec.rb | 2 +- ...ed_groups_into_regular_groups_for_mysql_spec.rb | 2 +- spec/models/commit_spec.rb | 2 +- spec/models/merge_request_spec.rb | 2 +- spec/models/project_label_spec.rb | 4 +- .../gitlab_issue_tracker_service_spec.rb | 12 +++--- spec/models/project_spec.rb | 30 +++++++++++++- spec/requests/api/internal_spec.rb | 4 +- spec/services/git_push_service_spec.rb | 2 +- spec/services/projects/import_service_spec.rb | 10 ++--- spec/services/system_note_service_spec.rb | 4 +- spec/support/notify_shared_examples.rb | 2 +- spec/support/project_hook_data_shared_example.rb | 4 +- 70 files changed, 239 insertions(+), 185 deletions(-) diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index 78cf7b26a31..c31023f2d9a 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -40,7 +40,7 @@ module MergeRequestsHelper def merge_path_description(merge_request, separator) if merge_request.for_fork? - "Project:Branches: #{@merge_request.source_project_path}:#{@merge_request.source_branch} #{separator} #{@merge_request.target_project.path_with_namespace}:#{@merge_request.target_branch}" + "Project:Branches: #{@merge_request.source_project_path}:#{@merge_request.source_branch} #{separator} #{@merge_request.target_project.full_path}:#{@merge_request.target_branch}" else "Branches: #{@merge_request.source_branch} #{separator} #{@merge_request.target_branch}" end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 9a8d296d514..34ff6107eab 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -398,7 +398,7 @@ module ProjectsHelper if project import_path = "/Home/Stacks/import" - repo = project.path_with_namespace + repo = project.full_path branch ||= project.default_branch sha ||= project.commit.short_id @@ -458,7 +458,7 @@ module ProjectsHelper def readme_cache_key sha = @project.commit.try(:sha) || 'nil' - [@project.path_with_namespace, sha, "readme"].join('-') + [@project.full_path, sha, "readme"].join('-') end def current_ref diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb index eaac6fcb548..9efabe3f44e 100644 --- a/app/mailers/notify.rb +++ b/app/mailers/notify.rb @@ -165,7 +165,7 @@ class Notify < BaseMailer headers['X-GitLab-Project'] = @project.name headers['X-GitLab-Project-Id'] = @project.id - headers['X-GitLab-Project-Path'] = @project.path_with_namespace + headers['X-GitLab-Project-Path'] = @project.full_path end def add_unsubscription_headers_and_links diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index d2abcf30034..ea7331cb27f 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -317,7 +317,7 @@ module Ci return @config_processor if defined?(@config_processor) @config_processor ||= begin - Ci::GitlabCiYamlProcessor.new(ci_yaml_file, project.path_with_namespace) + Ci::GitlabCiYamlProcessor.new(ci_yaml_file, project.full_path) rescue Ci::GitlabCiYamlProcessor::ValidationError, Psych::SyntaxError => e self.yaml_errors = e.message nil diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 81e0776e79c..8ca850b6d96 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -630,7 +630,7 @@ class MergeRequest < ActiveRecord::Base def target_project_path if target_project - target_project.path_with_namespace + target_project.full_path else "(removed)" end @@ -638,7 +638,7 @@ class MergeRequest < ActiveRecord::Base def source_project_path if source_project - source_project.path_with_namespace + source_project.full_path else "(removed)" end diff --git a/app/models/project.rb b/app/models/project.rb index 39949e6dbfd..7d3c91dc1b9 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -379,7 +379,7 @@ class Project < ActiveRecord::Base begin Projects::HousekeepingService.new(project).execute rescue Projects::HousekeepingService::LeaseTaken => e - Rails.logger.info("Could not perform housekeeping for project #{project.path_with_namespace} (#{project.id}): #{e}") + Rails.logger.info("Could not perform housekeeping for project #{project.full_path} (#{project.id}): #{e}") end end end @@ -485,7 +485,7 @@ class Project < ActiveRecord::Base def container_registry_url if Gitlab.config.registry.enabled - "#{Gitlab.config.registry.host_port}/#{path_with_namespace.downcase}" + "#{Gitlab.config.registry.host_port}/#{full_path.downcase}" end end @@ -524,16 +524,16 @@ class Project < ActiveRecord::Base job_id = if forked? RepositoryForkWorker.perform_async(id, forked_from_project.repository_storage_path, - forked_from_project.path_with_namespace, + forked_from_project.full_path, self.namespace.full_path) else RepositoryImportWorker.perform_async(self.id) end if job_id - Rails.logger.info "Import job started for #{path_with_namespace} with job ID #{job_id}" + Rails.logger.info "Import job started for #{full_path} with job ID #{job_id}" else - Rails.logger.error "Import job failed to start for #{path_with_namespace}" + Rails.logger.error "Import job failed to start for #{full_path}" end end @@ -694,7 +694,7 @@ class Project < ActiveRecord::Base # `from` argument can be a Namespace or Project. def to_reference(from = nil, full: false) if full || cross_namespace_reference?(from) - path_with_namespace + full_path elsif cross_project_reference?(from) path end @@ -718,7 +718,7 @@ class Project < ActiveRecord::Base author.ensure_incoming_email_token! Gitlab::IncomingEmail.reply_address( - "#{path_with_namespace}+#{author.incoming_email_token}") + "#{full_path}+#{author.incoming_email_token}") end def build_commit_note(commit) @@ -1002,7 +1002,7 @@ class Project < ActiveRecord::Base git_http_url: http_url_to_repo, namespace: namespace.name, visibility_level: visibility_level, - path_with_namespace: path_with_namespace, + path_with_namespace: full_path, default_branch: default_branch, ci_config_path: ci_config_path } @@ -1272,8 +1272,8 @@ class Project < ActiveRecord::Base [ { key: 'CI_PROJECT_ID', value: id.to_s, public: true }, { key: 'CI_PROJECT_NAME', value: path, public: true }, - { key: 'CI_PROJECT_PATH', value: path_with_namespace, public: true }, - { key: 'CI_PROJECT_PATH_SLUG', value: path_with_namespace.parameterize, public: true }, + { key: 'CI_PROJECT_PATH', value: full_path, public: true }, + { key: 'CI_PROJECT_PATH_SLUG', value: full_path.parameterize, public: true }, { key: 'CI_PROJECT_NAMESPACE', value: namespace.full_path, public: true }, { key: 'CI_PROJECT_URL', value: web_url, public: true } ] @@ -1378,6 +1378,7 @@ class Project < ActiveRecord::Base alias_method :name_with_namespace, :full_name alias_method :human_name, :full_name + # @deprecated cannot remove yet because it has an index with its name in elasticsearch alias_method :path_with_namespace, :full_path private @@ -1432,7 +1433,7 @@ class Project < ActiveRecord::Base def pending_delete_twin return false unless path - Project.pending_delete.find_by_full_path(path_with_namespace) + Project.pending_delete.find_by_full_path(full_path) end ## diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb index 2db95b9aaa3..4d23a17a545 100644 --- a/app/models/project_services/flowdock_service.rb +++ b/app/models/project_services/flowdock_service.rb @@ -35,9 +35,9 @@ class FlowdockService < Service data[:after], token: token, repo: project.repository.path_to_repo, - repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}", - commit_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/%s", - diff_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/compare/%s...%s" + repo_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}", + commit_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/commit/%s", + diff_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/compare/%s...%s" ) end end diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 2aa19443198..c2414885368 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -140,7 +140,7 @@ class JiraService < IssueTrackerService url: resource_url(user_path(author)) }, project: { - name: project.path_with_namespace, + name: project.full_path, url: resource_url(namespace_project_path(project.namespace, project)) # rubocop:disable Cop/ProjectPathHelper }, entity: { diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb index dfca0031af8..b44ee9b1766 100644 --- a/app/models/project_wiki.rb +++ b/app/models/project_wiki.rb @@ -27,7 +27,7 @@ class ProjectWiki end def path_with_namespace - @project.path_with_namespace + ".wiki" + @project.full_path + '.wiki' end def web_url @@ -47,7 +47,7 @@ class ProjectWiki end def wiki_base_path - [Gitlab.config.gitlab.relative_url_root, "/", @project.path_with_namespace, "/wikis"].join('') + [Gitlab.config.gitlab.relative_url_root, "/", @project.full_path, "/wikis"].join('') end # Returns the Gollum::Wiki object. diff --git a/app/services/git_operation_service.rb b/app/services/git_operation_service.rb index 32925e9c1f2..545ca0742e4 100644 --- a/app/services/git_operation_service.rb +++ b/app/services/git_operation_service.rb @@ -60,7 +60,7 @@ class GitOperationService start_branch_name = nil if start_repository.empty_repo? if start_branch_name && !start_repository.branch_exists?(start_branch_name) - raise ArgumentError, "Cannot find branch #{start_branch_name} in #{start_repository.path_with_namespace}" + raise ArgumentError, "Cannot find branch #{start_branch_name} in #{start_repository.full_path}" end update_branch_with_hooks(branch_name) do diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index f6e8b6655f2..45af2f7b503 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -9,7 +9,7 @@ module Projects def async_execute project.update_attribute(:pending_delete, true) job_id = ProjectDestroyWorker.perform_async(project.id, current_user.id, params) - Rails.logger.info("User #{current_user.id} scheduled destruction of project #{project.path_with_namespace} with job ID #{job_id}") + Rails.logger.info("User #{current_user.id} scheduled destruction of project #{project.full_path} with job ID #{job_id}") end def execute diff --git a/app/services/projects/import_service.rb b/app/services/projects/import_service.rb index eea17e24903..cf6a401db2a 100644 --- a/app/services/projects/import_service.rb +++ b/app/services/projects/import_service.rb @@ -11,7 +11,7 @@ module Projects success rescue => e - error("Error importing repository #{project.import_url} into #{project.path_with_namespace} - #{e.message}") + error("Error importing repository #{project.import_url} into #{project.full_path} - #{e.message}") end private diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 4bb98e5cb4e..386d49e58e7 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -34,7 +34,7 @@ module Projects private def transfer(project) - @old_path = project.path_with_namespace + @old_path = project.full_path @old_group = project.group @new_path = File.join(@new_namespace.try(:full_path) || '', project.path) @old_namespace = project.namespace diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb index bd58a54592f..cbcd4478af6 100644 --- a/app/services/system_hooks_service.rb +++ b/app/services/system_hooks_service.rb @@ -24,7 +24,7 @@ class SystemHooksService key: model.key, id: model.id ) - + if model.user data[:username] = model.user.username end @@ -56,7 +56,7 @@ class SystemHooksService when GroupMember data.merge!(group_member_data(model)) end - + data end @@ -79,7 +79,7 @@ class SystemHooksService { name: model.name, path: model.path, - path_with_namespace: model.path_with_namespace, + path_with_namespace: model.full_path, project_id: model.id, owner_name: owner.name, owner_email: owner.respond_to?(:email) ? owner.email : "", @@ -93,7 +93,7 @@ class SystemHooksService { project_name: project.name, project_path: project.path, - project_path_with_namespace: project.path_with_namespace, + project_path_with_namespace: project.full_path, project_id: project.id, user_username: model.user.username, user_name: model.user.name, diff --git a/app/workers/irker_worker.rb b/app/workers/irker_worker.rb index 22f67fa9e9f..3dd14466994 100644 --- a/app/workers/irker_worker.rb +++ b/app/workers/irker_worker.rb @@ -66,7 +66,7 @@ class IrkerWorker end def send_new_branch(project, repo_name, committer, branch) - repo_path = project.path_with_namespace + repo_path = project.full_path newbranch = "#{Gitlab.config.gitlab.url}/#{repo_path}/branches" newbranch = "\x0302\x1f#{newbranch}\x0f" if @colors @@ -109,7 +109,7 @@ class IrkerWorker end def send_commits_count(data, project, repo, committer, branch) - url = compare_url data, project.path_with_namespace + url = compare_url data, project.full_path commits = colorize_commits data['total_commits_count'] new_commits = 'new commit' diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb index 625476b7e01..6be541abd3e 100644 --- a/app/workers/repository_import_worker.rb +++ b/app/workers/repository_import_worker.rb @@ -16,7 +16,7 @@ class RepositoryImportWorker Gitlab::Metrics.add_event(:import_repository, import_url: @project.import_url, - path: @project.path_with_namespace) + path: @project.full_path) project.update_columns(import_jid: self.jid, import_error: nil) diff --git a/db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb b/db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb index c0cb9d78748..bcdae272209 100644 --- a/db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb +++ b/db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb @@ -16,6 +16,7 @@ class MigrateProcessCommitWorkerJobs < ActiveRecord::Migration end def repository_path + # TODO: review if the change from Legacy storage needs to reflect here as well. File.join(repository_storage_path, read_attribute(:path_with_namespace) + '.git') end diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb index c6cabace25b..420ac8a695a 100644 --- a/features/steps/project/forked_merge_requests.rb +++ b/features/steps/project/forked_merge_requests.rb @@ -30,8 +30,8 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps expect(@merge_request.source_project).to eq @forked_project expect(@merge_request.source_branch).to eq "fix" expect(@merge_request.target_branch).to eq "master" - expect(page).to have_content @forked_project.path_with_namespace - expect(page).to have_content @project.path_with_namespace + expect(page).to have_content @forked_project.full_path + expect(page).to have_content @project.full_path expect(page).to have_content @merge_request.source_branch expect(page).to have_content @merge_request.target_branch @@ -43,10 +43,10 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps expect(page).to have_content('Target branch') first('.js-source-project').click - first('.dropdown-source-project a', text: @forked_project.path_with_namespace) + first('.dropdown-source-project a', text: @forked_project.full_path) first('.js-target-project').click - first('.dropdown-target-project a', text: @project.path_with_namespace) + first('.dropdown-target-project a', text: @project.full_path) first('.js-source-branch').click wait_for_requests @@ -81,8 +81,8 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps expect(@merge_request.source_project).to eq @forked_project expect(@merge_request.source_branch).to eq "fix" expect(@merge_request.target_branch).to eq "master" - expect(page).to have_content @forked_project.path_with_namespace - expect(page).to have_content @project.path_with_namespace + expect(page).to have_content @forked_project.full_path + expect(page).to have_content @project.full_path expect(page).to have_content @merge_request.source_branch expect(page).to have_content @merge_request.target_branch end diff --git a/features/steps/project/redirects.rb b/features/steps/project/redirects.rb index b2ceb8dd9a8..cbe6f93f87e 100644 --- a/features/steps/project/redirects.rb +++ b/features/steps/project/redirects.rb @@ -47,7 +47,7 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps step 'I should be redirected to "Community" page' do project = Project.find_by(name: 'Community') - expect(current_path).to eq "/#{project.path_with_namespace}" + expect(current_path).to eq "/#{project.full_path}" expect(status_code).to eq 200 end @@ -61,7 +61,7 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps step 'I should be redirected to "Enterprise" page' do project = Project.find_by(name: 'Enterprise') - expect(current_path).to eq "/#{project.path_with_namespace}" + expect(current_path).to eq "/#{project.full_path}" expect(status_code).to eq 200 end end diff --git a/features/steps/project/wiki.rb b/features/steps/project/wiki.rb index 6a478c50e5e..2b8da2a6f19 100644 --- a/features/steps/project/wiki.rb +++ b/features/steps/project/wiki.rb @@ -142,7 +142,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps end step 'I should see non-escaped link in the pages list' do - expect(page).to have_xpath("//a[@href='/#{project.path_with_namespace}/wikis/one/two/three-test']") + expect(page).to have_xpath("//a[@href='/#{project.full_path}/wikis/one/two/three-test']") end step 'I edit the Wiki page with a path' do diff --git a/lib/api/runner.rb b/lib/api/runner.rb index 405d25ca3c1..88fc62d33df 100644 --- a/lib/api/runner.rb +++ b/lib/api/runner.rb @@ -90,7 +90,7 @@ module API if result.valid? if result.build Gitlab::Metrics.add_event(:build_found, - project: result.build.project.path_with_namespace) + project: result.build.project.full_path) present result.build, with: Entities::JobRequest::Response else Gitlab::Metrics.add_event(:build_not_found) @@ -119,7 +119,7 @@ module API job.trace.set(params[:trace]) if params[:trace] Gitlab::Metrics.add_event(:update_build, - project: job.project.path_with_namespace) + project: job.project.full_path) case params[:state].to_s when 'success' diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb index 02ed1e49ef8..f8cb8f089e7 100644 --- a/lib/backup/repository.rb +++ b/lib/backup/repository.rb @@ -7,7 +7,7 @@ module Backup prepare Project.find_each(batch_size: 1000) do |project| - progress.print " * #{project.path_with_namespace} ... " + progress.print " * #{project.full_path} ... " path_to_project_repo = path_to_repo(project) path_to_project_bundle = path_to_bundle(project) @@ -71,7 +71,7 @@ module Backup end Project.find_each(batch_size: 1000) do |project| - progress.print " * #{project.path_with_namespace} ... " + progress.print " * #{project.full_path} ... " path_to_project_repo = path_to_repo(project) path_to_project_bundle = path_to_bundle(project) @@ -185,7 +185,7 @@ module Backup def progress_warn(project, cmd, output) progress.puts "[WARNING] Executing #{cmd}".color(:orange) - progress.puts "Ignoring error on #{project.path_with_namespace} - #{output}".color(:orange) + progress.puts "Ignoring error on #{project.full_path} - #{output}".color(:orange) end def empty_repo?(project_or_wiki) diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb index 7a262dd025c..685b43605ae 100644 --- a/lib/banzai/filter/abstract_reference_filter.rb +++ b/lib/banzai/filter/abstract_reference_filter.rb @@ -259,7 +259,7 @@ module Banzai found = [] projects.each do |project| - ref = project.path_with_namespace + ref = project.full_path get_or_set_cache(cache, ref) { project } found << ref end @@ -277,7 +277,7 @@ module Banzai end def current_project_path - @current_project_path ||= project.path_with_namespace + @current_project_path ||= project.full_path end def current_project_namespace_path diff --git a/lib/banzai/filter/upload_link_filter.rb b/lib/banzai/filter/upload_link_filter.rb index 45bb66dc99f..09844931be5 100644 --- a/lib/banzai/filter/upload_link_filter.rb +++ b/lib/banzai/filter/upload_link_filter.rb @@ -28,7 +28,7 @@ module Banzai end def build_url(uri) - File.join(Gitlab.config.gitlab.url, project.path_with_namespace, uri) + File.join(Gitlab.config.gitlab.url, project.full_path, uri) end def project diff --git a/lib/ci/api/builds.rb b/lib/ci/api/builds.rb index e2e91ce99cd..79058c02ce5 100644 --- a/lib/ci/api/builds.rb +++ b/lib/ci/api/builds.rb @@ -29,7 +29,7 @@ module Ci if result.valid? if result.build Gitlab::Metrics.add_event(:build_found, - project: result.build.project.path_with_namespace) + project: result.build.project.full_path) present result.build, with: Entities::BuildDetails else @@ -64,7 +64,7 @@ module Ci build.trace.set(params[:trace]) if params[:trace] Gitlab::Metrics.add_event(:update_build, - project: build.project.path_with_namespace) + project: build.project.full_path) case params[:state].to_s when 'success' diff --git a/lib/github/import.rb b/lib/github/import.rb index ff5d7db2705..cea4be5460b 100644 --- a/lib/github/import.rb +++ b/lib/github/import.rb @@ -93,7 +93,7 @@ module Github def fetch_wiki_repository wiki_url = "https://#{options.fetch(:token)}@github.com/#{repo}.wiki.git" - wiki_path = "#{project.path_with_namespace}.wiki" + wiki_path = "#{project.full_path}.wiki" unless project.wiki.repository_exists? gitlab_shell.import_repository(project.repository_storage_path, wiki_path, wiki_url) diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb index 5a6d9ae99a0..28bbf3b384e 100644 --- a/lib/gitlab/bitbucket_import/importer.rb +++ b/lib/gitlab/bitbucket_import/importer.rb @@ -61,7 +61,7 @@ module Gitlab def import_wiki return if project.wiki.repository_exists? - path_with_namespace = "#{project.path_with_namespace}.wiki" + path_with_namespace = "#{project.full_path}.wiki" import_url = project.import_url.sub(/\.git\z/, ".git/wiki") gitlab_shell.import_repository(project.repository_storage_path, path_with_namespace, import_url) rescue StandardError => e diff --git a/lib/gitlab/email/message/repository_push.rb b/lib/gitlab/email/message/repository_push.rb index dd1d9dcd555..cd9d3a6483f 100644 --- a/lib/gitlab/email/message/repository_push.rb +++ b/lib/gitlab/email/message/repository_push.rb @@ -117,7 +117,7 @@ module Gitlab def subject subject_text = '[Git]' - subject_text << "[#{project.path_with_namespace}]" + subject_text << "[#{project.full_path}]" subject_text << "[#{ref_name}]" if @action == :push subject_text << ' ' diff --git a/lib/gitlab/github_import/wiki_formatter.rb b/lib/gitlab/github_import/wiki_formatter.rb index 6c592ff469c..30cff1ba804 100644 --- a/lib/gitlab/github_import/wiki_formatter.rb +++ b/lib/gitlab/github_import/wiki_formatter.rb @@ -8,7 +8,7 @@ module Gitlab end def path_with_namespace - "#{project.path_with_namespace}.wiki" + "#{project.full_path}.wiki" end def import_url diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb index 02bbc48dc59..19ee5e3bb7e 100644 --- a/spec/controllers/projects/blob_controller_spec.rb +++ b/spec/controllers/projects/blob_controller_spec.rb @@ -48,7 +48,7 @@ describe Projects::BlobController do let(:id) { 'markdown/doc' } it 'redirects' do expect(subject) - .to redirect_to("/#{project.path_with_namespace}/tree/markdown/doc") + .to redirect_to("/#{project.full_path}/tree/markdown/doc") end end end diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb index 9cd4e9dbf84..24defb4d657 100644 --- a/spec/controllers/projects/branches_controller_spec.rb +++ b/spec/controllers/projects/branches_controller_spec.rb @@ -33,7 +33,7 @@ describe Projects::BranchesController do let(:ref) { "master" } it 'redirects' do expect(subject) - .to redirect_to("/#{project.path_with_namespace}/tree/merge_branch") + .to redirect_to("/#{project.full_path}/tree/merge_branch") end end @@ -42,7 +42,7 @@ describe Projects::BranchesController do let(:ref) { "master" } it 'redirects' do expect(subject) - .to redirect_to("/#{project.path_with_namespace}/tree/alert('merge');") + .to redirect_to("/#{project.full_path}/tree/alert('merge');") end end @@ -82,7 +82,7 @@ describe Projects::BranchesController do issue_iid: issue.iid expect(subject) - .to redirect_to("/#{project.path_with_namespace}/tree/1-feature-branch") + .to redirect_to("/#{project.full_path}/tree/1-feature-branch") end it 'posts a system note' do diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 2fce4b7a85f..0bfe83f1d98 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -609,7 +609,7 @@ describe Projects::MergeRequestsController do end it 'links to the environment on that project' do - expect(json_response.first['url']).to match /#{forked.path_with_namespace}/ + expect(json_response.first['url']).to match /#{forked.full_path}/ end end end diff --git a/spec/controllers/projects/tree_controller_spec.rb b/spec/controllers/projects/tree_controller_spec.rb index 16cd2e076e5..775f3998f5d 100644 --- a/spec/controllers/projects/tree_controller_spec.rb +++ b/spec/controllers/projects/tree_controller_spec.rb @@ -81,7 +81,7 @@ describe Projects::TreeController do context 'redirect to blob' do let(:id) { 'master/README.md' } it 'redirects' do - redirect_url = "/#{project.path_with_namespace}/blob/master/README.md" + redirect_url = "/#{project.full_path}/blob/master/README.md" expect(subject) .to redirect_to(redirect_url) end @@ -107,7 +107,7 @@ describe Projects::TreeController do it 'redirects to the new directory' do expect(subject) - .to redirect_to("/#{project.path_with_namespace}/tree/#{branch_name}/#{path}") + .to redirect_to("/#{project.full_path}/tree/#{branch_name}/#{path}") expect(flash[:notice]).to eq('The directory has been successfully created.') end end @@ -118,7 +118,7 @@ describe Projects::TreeController do it 'does not allow overwriting of existing files' do expect(subject) - .to redirect_to("/#{project.path_with_namespace}/tree/master") + .to redirect_to("/#{project.full_path}/tree/master") expect(flash[:alert]).to eq('A file with this name already exists') end end diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb index 11a74276898..d7f3d91e625 100644 --- a/spec/features/merge_requests/create_new_mr_spec.rb +++ b/spec/features/merge_requests/create_new_mr_spec.rb @@ -67,8 +67,8 @@ feature 'Create New Merge Request', js: true do visit project_new_merge_request_path(project, merge_request: { target_project_id: private_project.id }) - expect(page).not_to have_content private_project.path_with_namespace - expect(page).to have_content project.path_with_namespace + expect(page).not_to have_content private_project.full_path + expect(page).to have_content project.full_path end end @@ -78,8 +78,8 @@ feature 'Create New Merge Request', js: true do visit project_new_merge_request_path(project, merge_request: { source_project_id: private_project.id }) - expect(page).not_to have_content private_project.path_with_namespace - expect(page).to have_content project.path_with_namespace + expect(page).not_to have_content private_project.full_path + expect(page).to have_content project.full_path end end diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb index dbe98a38197..1dc89665020 100644 --- a/spec/features/projects/wiki/markdown_preview_spec.rb +++ b/spec/features/projects/wiki/markdown_preview_spec.rb @@ -38,10 +38,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do expect(page).to have_content("regular link") - expect(page.html).to include("regular link") - expect(page.html).to include("relative link 1") - expect(page.html).to include("relative link 2") - expect(page.html).to include("relative link 3") + expect(page.html).to include("regular link") + expect(page.html).to include("relative link 1") + expect(page.html).to include("relative link 2") + expect(page.html).to include("relative link 3") end end @@ -60,10 +60,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do expect(page).to have_content("regular link") - expect(page.html).to include("regular link") - expect(page.html).to include("relative link 1") - expect(page.html).to include("relative link 2") - expect(page.html).to include("relative link 3") + expect(page.html).to include("regular link") + expect(page.html).to include("relative link 1") + expect(page.html).to include("relative link 2") + expect(page.html).to include("relative link 3") end end @@ -82,10 +82,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do expect(page).to have_content("regular link") - expect(page.html).to include("regular link") - expect(page.html).to include("relative link 1") - expect(page.html).to include("relative link 2") - expect(page.html).to include("relative link 3") + expect(page.html).to include("regular link") + expect(page.html).to include("relative link 1") + expect(page.html).to include("relative link 2") + expect(page.html).to include("relative link 3") end end end @@ -115,10 +115,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do expect(page).to have_content("regular link") - expect(page.html).to include("regular link") - expect(page.html).to include("relative link 1") - expect(page.html).to include("relative link 2") - expect(page.html).to include("relative link 3") + expect(page.html).to include("regular link") + expect(page.html).to include("relative link 1") + expect(page.html).to include("relative link 2") + expect(page.html).to include("relative link 3") end end @@ -132,10 +132,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do expect(page).to have_content("regular link") - expect(page.html).to include("regular link") - expect(page.html).to include("relative link 1") - expect(page.html).to include("relative link 2") - expect(page.html).to include("relative link 3") + expect(page.html).to include("regular link") + expect(page.html).to include("relative link 1") + expect(page.html).to include("relative link 2") + expect(page.html).to include("relative link 3") end end @@ -149,10 +149,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do expect(page).to have_content("regular link") - expect(page.html).to include("regular link") - expect(page.html).to include("relative link 1") - expect(page.html).to include("relative link 2") - expect(page.html).to include("relative link 3") + expect(page.html).to include("regular link") + expect(page.html).to include("relative link 1") + expect(page.html).to include("relative link 2") + expect(page.html).to include("relative link 3") end end end diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index a8d6044fda7..8fc94ce09db 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -7,7 +7,7 @@ describe LabelsHelper do context 'without subject' do it "uses the label's project" do - expect(link_to_label(label)).to match %r{.*} + expect(link_to_label(label)).to match %r{.*} end end @@ -32,7 +32,7 @@ describe LabelsHelper do ['issue', :issue, 'merge_request', :merge_request].each do |type| context "set to #{type}" do it 'links to correct page' do - expect(link_to_label(label, type: type)).to match %r{.*} + expect(link_to_label(label, type: type)).to match %r{.*} end end end diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb index 4b6a351cf70..70eb01c9c44 100644 --- a/spec/helpers/markup_helper_spec.rb +++ b/spec/helpers/markup_helper_spec.rb @@ -210,11 +210,11 @@ describe MarkupHelper do describe '#cross_project_reference' do it 'shows the full MR reference' do - expect(helper.cross_project_reference(project, merge_request)).to include(project.path_with_namespace) + expect(helper.cross_project_reference(project, merge_request)).to include(project.full_path) end it 'shows the full issue reference' do - expect(helper.cross_project_reference(project, issue)).to include(project.path_with_namespace) + expect(helper.cross_project_reference(project, issue)).to include(project.full_path) end end end diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb index 493a4ff9a93..b2a9e277a1c 100644 --- a/spec/helpers/merge_requests_helper_spec.rb +++ b/spec/helpers/merge_requests_helper_spec.rb @@ -34,8 +34,8 @@ describe MergeRequestsHelper do let(:fork_project) { create(:empty_project, forked_from_project: project) } let(:merge_request) { create(:merge_request, source_project: fork_project, target_project: project) } subject { format_mr_branch_names(merge_request) } - let(:source_title) { "#{fork_project.path_with_namespace}:#{merge_request.source_branch}" } - let(:target_title) { "#{project.path_with_namespace}:#{merge_request.target_branch}" } + let(:source_title) { "#{fork_project.full_path}:#{merge_request.source_branch}" } + let(:target_title) { "#{project.full_path}:#{merge_request.target_branch}" } it { is_expected.to eq([source_title, target_title]) } end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 45066a60f50..faf26931efc 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -53,13 +53,13 @@ describe ProjectsHelper do end it "returns a valid cach key" do - expect(helper.send(:readme_cache_key)).to eq("#{project.path_with_namespace}-#{project.commit.id}-readme") + expect(helper.send(:readme_cache_key)).to eq("#{project.full_path}-#{project.commit.id}-readme") end it "returns a valid cache key if HEAD does not exist" do allow(project).to receive(:commit) { nil } - expect(helper.send(:readme_cache_key)).to eq("#{project.path_with_namespace}-nil-readme") + expect(helper.send(:readme_cache_key)).to eq("#{project.full_path}-nil-readme") end end diff --git a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb index 27532f96f56..32d027b026b 100644 --- a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb @@ -5,7 +5,7 @@ describe Banzai::Filter::AbstractReferenceFilter do describe '#references_per_project' do it 'returns a Hash containing references grouped per project paths' do - doc = Nokogiri::HTML.fragment("#1 #{project.path_with_namespace}#2") + doc = Nokogiri::HTML.fragment("#1 #{project.full_path}#2") filter = described_class.new(doc, project: project) expect(filter).to receive(:object_class).exactly(4).times.and_return(Issue) @@ -14,7 +14,7 @@ describe Banzai::Filter::AbstractReferenceFilter do refs = filter.references_per_project expect(refs).to be_an_instance_of(Hash) - expect(refs[project.path_with_namespace]).to eq(Set.new(%w[1 2])) + expect(refs[project.full_path]).to eq(Set.new(%w[1 2])) end end @@ -24,10 +24,10 @@ describe Banzai::Filter::AbstractReferenceFilter do filter = described_class.new(doc, project: project) expect(filter).to receive(:references_per_project) - .and_return({ project.path_with_namespace => Set.new(%w[1]) }) + .and_return({ project.full_path => Set.new(%w[1]) }) expect(filter.projects_per_reference) - .to eq({ project.path_with_namespace => project }) + .to eq({ project.full_path => project }) end end @@ -37,7 +37,7 @@ describe Banzai::Filter::AbstractReferenceFilter do context 'with RequestStore disabled' do it 'returns a list of Projects for a list of paths' do - expect(filter.find_projects_for_paths([project.path_with_namespace])) + expect(filter.find_projects_for_paths([project.full_path])) .to eq([project]) end @@ -49,7 +49,7 @@ describe Banzai::Filter::AbstractReferenceFilter do context 'with RequestStore enabled', :request_store do it 'returns a list of Projects for a list of paths' do - expect(filter.find_projects_for_paths([project.path_with_namespace])) + expect(filter.find_projects_for_paths([project.full_path])) .to eq([project]) end @@ -88,7 +88,7 @@ describe Banzai::Filter::AbstractReferenceFilter do doc = Nokogiri::HTML.fragment('') filter = described_class.new(doc, project: project) - expect(filter.current_project_path).to eq(project.path_with_namespace) + expect(filter.current_project_path).to eq(project.full_path) end end end diff --git a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb index 11d48387544..935146c17fc 100644 --- a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb @@ -100,7 +100,7 @@ describe Banzai::Filter::CommitRangeReferenceFilter do context 'cross-project / cross-namespace complete reference' do let(:project2) { create(:project, :public, :repository) } - let(:reference) { "#{project2.path_with_namespace}@#{commit1.id}...#{commit2.id}" } + let(:reference) { "#{project2.full_path}@#{commit1.id}...#{commit2.id}" } it 'links to a valid reference' do doc = reference_filter("See #{reference}") @@ -113,20 +113,20 @@ describe Banzai::Filter::CommitRangeReferenceFilter do doc = reference_filter("Fixed (#{reference}.)") expect(doc.css('a').first.text) - .to eql("#{project2.path_with_namespace}@#{commit1.short_id}...#{commit2.short_id}") + .to eql("#{project2.full_path}@#{commit1.short_id}...#{commit2.short_id}") end it 'has valid text' do doc = reference_filter("Fixed (#{reference}.)") - expect(doc.text).to eql("Fixed (#{project2.path_with_namespace}@#{commit1.short_id}...#{commit2.short_id}.)") + expect(doc.text).to eql("Fixed (#{project2.full_path}@#{commit1.short_id}...#{commit2.short_id}.)") end it 'ignores invalid commit IDs on the referenced project' do - exp = act = "Fixed #{project2.path_with_namespace}@#{commit1.id.reverse}...#{commit2.id}" + exp = act = "Fixed #{project2.full_path}@#{commit1.id.reverse}...#{commit2.id}" expect(reference_filter(act).to_html).to eq exp - exp = act = "Fixed #{project2.path_with_namespace}@#{commit1.id}...#{commit2.id.reverse}" + exp = act = "Fixed #{project2.full_path}@#{commit1.id}...#{commit2.id.reverse}" expect(reference_filter(act).to_html).to eq exp end end diff --git a/spec/lib/banzai/filter/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_reference_filter_spec.rb index fb2a36d1ba1..c7cf1c1d582 100644 --- a/spec/lib/banzai/filter/commit_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/commit_reference_filter_spec.rb @@ -98,18 +98,18 @@ describe Banzai::Filter::CommitReferenceFilter do let(:namespace) { create(:namespace) } let(:project2) { create(:project, :public, :repository, namespace: namespace) } let(:commit) { project2.commit } - let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" } + let(:reference) { "#{project2.full_path}@#{commit.short_id}" } it 'link has valid text' do doc = reference_filter("See (#{reference}.)") - expect(doc.css('a').first.text).to eql("#{project2.path_with_namespace}@#{commit.short_id}") + expect(doc.css('a').first.text).to eql("#{project2.full_path}@#{commit.short_id}") end it 'has valid text' do doc = reference_filter("See (#{reference}.)") - expect(doc.text).to eql("See (#{project2.path_with_namespace}@#{commit.short_id}.)") + expect(doc.text).to eql("See (#{project2.full_path}@#{commit.short_id}.)") end it 'ignores invalid commit IDs on the referenced project' do @@ -124,7 +124,7 @@ describe Banzai::Filter::CommitReferenceFilter do let(:project) { create(:empty_project, namespace: namespace) } let(:project2) { create(:project, :public, :repository, namespace: namespace) } let(:commit) { project2.commit } - let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" } + let(:reference) { "#{project2.full_path}@#{commit.short_id}" } it 'link has valid text' do doc = reference_filter("See (#{reference}.)") @@ -150,7 +150,7 @@ describe Banzai::Filter::CommitReferenceFilter do let(:project) { create(:empty_project, namespace: namespace) } let(:project2) { create(:project, :public, :repository, namespace: namespace) } let(:commit) { project2.commit } - let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" } + let(:reference) { "#{project2.full_path}@#{commit.short_id}" } it 'link has valid text' do doc = reference_filter("See (#{reference}.)") diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb index 045bf3e0cc9..024a5cafb41 100644 --- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb @@ -127,7 +127,7 @@ describe Banzai::Filter::IssueReferenceFilter do let(:project2) { create(:empty_project, :public) } let(:issue) { create(:issue, project: project2) } - let(:reference) { "#{project2.path_with_namespace}##{issue.iid}" } + let(:reference) { "#{project2.full_path}##{issue.iid}" } it 'ignores valid references when cross-reference project uses external tracker' do expect_any_instance_of(described_class).to receive(:find_object) @@ -148,13 +148,13 @@ describe Banzai::Filter::IssueReferenceFilter do it 'link has valid text' do doc = reference_filter("Fixed (#{reference}.)") - expect(doc.css('a').first.text).to eql("#{project2.path_with_namespace}##{issue.iid}") + expect(doc.css('a').first.text).to eql("#{project2.full_path}##{issue.iid}") end it 'has valid text' do doc = reference_filter("Fixed (#{reference}.)") - expect(doc.text).to eq("Fixed (#{project2.path_with_namespace}##{issue.iid}.)") + expect(doc.text).to eq("Fixed (#{project2.full_path}##{issue.iid}.)") end it 'ignores invalid issue IDs on the referenced project' do @@ -171,7 +171,7 @@ describe Banzai::Filter::IssueReferenceFilter do let(:project) { create(:empty_project, :public, namespace: namespace) } let(:project2) { create(:empty_project, :public, namespace: namespace) } let(:issue) { create(:issue, project: project2) } - let(:reference) { "#{project2.path_with_namespace}##{issue.iid}" } + let(:reference) { "#{project2.full_path}##{issue.iid}" } it 'ignores valid references when cross-reference project uses external tracker' do expect_any_instance_of(described_class).to receive(:find_object) @@ -324,10 +324,10 @@ describe Banzai::Filter::IssueReferenceFilter do filter = described_class.new(doc, project: project) expect(filter).to receive(:projects_per_reference) - .and_return({ project.path_with_namespace => project }) + .and_return({ project.full_path => project }) expect(filter).to receive(:references_per_project) - .and_return({ project.path_with_namespace => Set.new([issue.iid]) }) + .and_return({ project.full_path => Set.new([issue.iid]) }) expect(filter.issues_per_project) .to eq({ project => { issue.iid => issue } }) diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb index 1daa6ac7f9e..dfd4c7a7279 100644 --- a/spec/lib/banzai/filter/label_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb @@ -368,7 +368,7 @@ describe Banzai::Filter::LabelReferenceFilter do describe 'cross-project / cross-namespace complete reference' do let(:project2) { create(:empty_project) } let(:label) { create(:label, project: project2, color: '#00ff00') } - let(:reference) { "#{project2.path_with_namespace}~#{label.name}" } + let(:reference) { "#{project2.full_path}~#{label.name}" } let!(:result) { reference_filter("See #{reference}") } it 'links to a valid reference' do @@ -400,7 +400,7 @@ describe Banzai::Filter::LabelReferenceFilter do let(:project) { create(:empty_project, namespace: namespace) } let(:project2) { create(:empty_project, namespace: namespace) } let(:label) { create(:label, project: project2, color: '#00ff00') } - let(:reference) { "#{project2.path_with_namespace}~#{label.name}" } + let(:reference) { "#{project2.full_path}~#{label.name}" } let!(:result) { reference_filter("See #{reference}") } it 'links to a valid reference' do @@ -466,7 +466,7 @@ describe Banzai::Filter::LabelReferenceFilter do let(:another_group) { create(:group) } let(:another_project) { create(:empty_project, :public, namespace: another_group) } let(:group_label) { create(:group_label, group: another_group, color: '#00ff00') } - let(:reference) { "#{another_project.path_with_namespace}~#{group_label.name}" } + let(:reference) { "#{another_project.full_path}~#{group_label.name}" } let!(:result) { reference_filter("See #{reference}", project: project) } it 'points to referenced project issues page' do @@ -501,7 +501,7 @@ describe Banzai::Filter::LabelReferenceFilter do let(:project) { create(:empty_project, :public, namespace: group) } let(:another_project) { create(:empty_project, :public, namespace: group) } let(:group_label) { create(:group_label, group: group, color: '#00ff00') } - let(:reference) { "#{another_project.path_with_namespace}~#{group_label.name}" } + let(:reference) { "#{another_project.full_path}~#{group_label.name}" } let!(:result) { reference_filter("See #{reference}", project: project) } it 'points to referenced project issues page' do @@ -535,7 +535,7 @@ describe Banzai::Filter::LabelReferenceFilter do let(:group) { create(:group) } let(:project) { create(:empty_project, :public, namespace: group) } let(:group_label) { create(:group_label, group: group, color: '#00ff00') } - let(:reference) { "#{project.path_with_namespace}~#{group_label.name}" } + let(:reference) { "#{project.full_path}~#{group_label.name}" } let!(:result) { reference_filter("See #{reference}", project: project) } it 'points to referenced project issues page' do diff --git a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb index 683972a3112..b693ae3eca2 100644 --- a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb @@ -102,7 +102,7 @@ describe Banzai::Filter::MergeRequestReferenceFilter do context 'cross-project / cross-namespace complete reference' do let(:project2) { create(:empty_project, :public) } let(:merge) { create(:merge_request, source_project: project2) } - let(:reference) { "#{project2.path_with_namespace}!#{merge.iid}" } + let(:reference) { "#{project2.full_path}!#{merge.iid}" } it 'links to a valid reference' do doc = reference_filter("See #{reference}") @@ -135,7 +135,7 @@ describe Banzai::Filter::MergeRequestReferenceFilter do let(:project) { create(:empty_project, :public, namespace: namespace) } let(:project2) { create(:empty_project, :public, namespace: namespace) } let!(:merge) { create(:merge_request, source_project: project2) } - let(:reference) { "#{project2.path_with_namespace}!#{merge.iid}" } + let(:reference) { "#{project2.full_path}!#{merge.iid}" } it 'links to a valid reference' do doc = reference_filter("See #{reference}") diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb index 8fe05dc2e53..79ff9419e4b 100644 --- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb @@ -152,7 +152,7 @@ describe Banzai::Filter::MilestoneReferenceFilter do let(:namespace) { create(:namespace) } let(:another_project) { create(:empty_project, :public, namespace: namespace) } let(:milestone) { create(:milestone, project: another_project) } - let(:reference) { "#{another_project.path_with_namespace}%#{milestone.iid}" } + let(:reference) { "#{another_project.full_path}%#{milestone.iid}" } let!(:result) { reference_filter("See #{reference}") } it 'points to referenced project milestone page' do @@ -164,14 +164,14 @@ describe Banzai::Filter::MilestoneReferenceFilter do doc = reference_filter("See (#{reference}.)") expect(doc.css('a').first.text) - .to eq("#{milestone.name} in #{another_project.path_with_namespace}") + .to eq("#{milestone.name} in #{another_project.full_path}") end it 'has valid text' do doc = reference_filter("See (#{reference}.)") expect(doc.text) - .to eq("See (#{milestone.name} in #{another_project.path_with_namespace}.)") + .to eq("See (#{milestone.name} in #{another_project.full_path}.)") end it 'escapes the name attribute' do @@ -180,7 +180,7 @@ describe Banzai::Filter::MilestoneReferenceFilter do doc = reference_filter("See #{reference}") expect(doc.css('a').first.text) - .to eq "#{milestone.name} in #{another_project.path_with_namespace}" + .to eq "#{milestone.name} in #{another_project.full_path}" end end @@ -189,7 +189,7 @@ describe Banzai::Filter::MilestoneReferenceFilter do let(:project) { create(:empty_project, :public, namespace: namespace) } let(:another_project) { create(:empty_project, :public, namespace: namespace) } let(:milestone) { create(:milestone, project: another_project) } - let(:reference) { "#{another_project.path_with_namespace}%#{milestone.iid}" } + let(:reference) { "#{another_project.full_path}%#{milestone.iid}" } let!(:result) { reference_filter("See #{reference}") } it 'points to referenced project milestone page' do @@ -257,4 +257,28 @@ describe Banzai::Filter::MilestoneReferenceFilter do .to eq "#{milestone.name} in #{another_project.path}" end end + + describe 'cross project milestone references' do + let(:another_project) { create(:empty_project, :public) } + let(:project_path) { another_project.full_path } + let(:milestone) { create(:milestone, project: another_project) } + let(:reference) { milestone.to_reference(project) } + + let!(:result) { reference_filter("See #{reference}") } + + it 'points to referenced project milestone page' do + expect(result.css('a').first.attr('href')).to eq urls + .project_milestone_url(another_project, milestone) + end + + it 'contains cross project content' do + expect(result.css('a').first.text).to eq "#{milestone.name} in #{project_path}" + end + + it 'escapes the name attribute' do + allow_any_instance_of(Milestone).to receive(:title).and_return(%{">whatever Date: Fri, 21 Jul 2017 06:13:26 +0200 Subject: Rename path_with_namespace -> disk_path when dealing with the filesystem --- app/models/project.rb | 4 ++-- app/services/projects/destroy_service.rb | 2 +- app/services/projects/import_export/export_service.rb | 2 +- app/services/projects/import_service.rb | 2 +- lib/backup/repository.rb | 4 ++-- lib/gitlab/import_export/repo_restorer.rb | 2 +- spec/factories/projects.rb | 4 ++-- spec/lib/gitlab/gitaly_client/notification_service_spec.rb | 2 +- spec/lib/gitlab/gitaly_client/ref_service_spec.rb | 2 +- spec/models/project_services/jira_service_spec.rb | 6 +++--- spec/models/project_spec.rb | 12 ++++++------ spec/models/repository_spec.rb | 2 +- spec/services/projects/transfer_service_spec.rb | 2 +- spec/tasks/gitlab/backup_rake_spec.rb | 6 +++--- 14 files changed, 26 insertions(+), 26 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index 7d3c91dc1b9..776b8f4600b 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1198,7 +1198,7 @@ class Project < ActiveRecord::Base end def pages_path - File.join(Settings.pages.path, path_with_namespace) + File.join(Settings.pages.path, disk_path) end def public_pages_path @@ -1256,7 +1256,7 @@ class Project < ActiveRecord::Base end def export_path - File.join(Gitlab::ImportExport.storage_path, path_with_namespace) + File.join(Gitlab::ImportExport.storage_path, disk_path) end def export_project_path diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index 45af2f7b503..952272903f3 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -40,7 +40,7 @@ module Projects private def repo_path - project.path_with_namespace + project.disk_path end def wiki_path diff --git a/app/services/projects/import_export/export_service.rb b/app/services/projects/import_export/export_service.rb index 535da706159..fe4e8ea10bf 100644 --- a/app/services/projects/import_export/export_service.rb +++ b/app/services/projects/import_export/export_service.rb @@ -2,7 +2,7 @@ module Projects module ImportExport class ExportService < BaseService def execute(_options = {}) - @shared = Gitlab::ImportExport::Shared.new(relative_path: File.join(project.path_with_namespace, 'work')) + @shared = Gitlab::ImportExport::Shared.new(relative_path: File.join(project.disk_path, 'work')) save_all end diff --git a/app/services/projects/import_service.rb b/app/services/projects/import_service.rb index cf6a401db2a..50ec3651515 100644 --- a/app/services/projects/import_service.rb +++ b/app/services/projects/import_service.rb @@ -51,7 +51,7 @@ module Projects end def clone_repository - gitlab_shell.import_repository(project.repository_storage_path, project.path_with_namespace, project.import_url) + gitlab_shell.import_repository(project.repository_storage_path, project.disk_path, project.import_url) end def fetch_repository diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb index f8cb8f089e7..8d56b74bfd6 100644 --- a/lib/backup/repository.rb +++ b/lib/backup/repository.rb @@ -142,11 +142,11 @@ module Backup end def path_to_bundle(project) - File.join(backup_repos_path, project.path_with_namespace + '.bundle') + File.join(backup_repos_path, project.disk_path + '.bundle') end def path_to_tars(project, dir = nil) - path = File.join(backup_repos_path, project.path_with_namespace) + path = File.join(backup_repos_path, project.disk_path) if dir File.join(path, "#{dir}.tar") diff --git a/lib/gitlab/import_export/repo_restorer.rb b/lib/gitlab/import_export/repo_restorer.rb index c824d3ea9fc..32ca2809b2f 100644 --- a/lib/gitlab/import_export/repo_restorer.rb +++ b/lib/gitlab/import_export/repo_restorer.rb @@ -13,7 +13,7 @@ module Gitlab def restore return true unless File.exist?(@path_to_bundle) - gitlab_shell.import_repository(@project.repository_storage_path, @project.path_with_namespace, @path_to_bundle) + gitlab_shell.import_repository(@project.repository_storage_path, @project.disk_path, @path_to_bundle) rescue => e @shared.error(e) false diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index 485ed48d2de..a04befe809a 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -64,7 +64,7 @@ FactoryGirl.define do # We delete hooks so that gitlab-shell will not try to authenticate with # an API that isn't running - FileUtils.rm_r(File.join(project.repository_storage_path, "#{project.path_with_namespace}.git", 'hooks')) + FileUtils.rm_r(File.join(project.repository_storage_path, "#{project.disk_path}.git", 'hooks')) end end @@ -72,7 +72,7 @@ FactoryGirl.define do after(:create) do |project| raise "Failed to create repository!" unless project.create_repository - FileUtils.rm_r(File.join(project.repository_storage_path, "#{project.path_with_namespace}.git", 'refs')) + FileUtils.rm_r(File.join(project.repository_storage_path, "#{project.disk_path}.git", 'refs')) end end diff --git a/spec/lib/gitlab/gitaly_client/notification_service_spec.rb b/spec/lib/gitlab/gitaly_client/notification_service_spec.rb index d9597c4aa78..1bcdd5e5497 100644 --- a/spec/lib/gitlab/gitaly_client/notification_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/notification_service_spec.rb @@ -4,7 +4,7 @@ describe Gitlab::GitalyClient::NotificationService do describe '#post_receive' do let(:project) { create(:empty_project) } let(:storage_name) { project.repository_storage } - let(:relative_path) { project.path_with_namespace + '.git' } + let(:relative_path) { project.disk_path + '.git' } subject { described_class.new(project.repository) } it 'sends a post_receive message' do diff --git a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb index 0b1c890f956..2ad24119476 100644 --- a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::GitalyClient::RefService do let(:project) { create(:empty_project) } let(:storage_name) { project.repository_storage } - let(:relative_path) { project.path_with_namespace + '.git' } + let(:relative_path) { project.disk_path + '.git' } let(:client) { described_class.new(project.repository) } describe '#branches' do diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 8f34b44930e..bc9374d6dbb 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -135,7 +135,7 @@ describe JiraService do body: hash_including( GlobalID: "GitLab", object: { - url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/#{merge_request.diff_head_sha}", + url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/commit/#{merge_request.diff_head_sha}", title: "GitLab: Solved by commit #{merge_request.diff_head_sha}.", icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" }, status: { resolved: true } @@ -159,7 +159,7 @@ describe JiraService do @jira_service.close_issue(merge_request, ExternalIssue.new("JIRA-123", project)) expect(WebMock).to have_requested(:post, @comment_url).with( - body: /#{custom_base_url}\/#{project.path_with_namespace}\/commit\/#{merge_request.diff_head_sha}/ + body: /#{custom_base_url}\/#{project.full_path}\/commit\/#{merge_request.diff_head_sha}/ ).once end @@ -174,7 +174,7 @@ describe JiraService do @jira_service.close_issue(merge_request, ExternalIssue.new("JIRA-123", project)) expect(WebMock).to have_requested(:post, @comment_url).with( - body: /#{Gitlab.config.gitlab.url}\/#{project.path_with_namespace}\/commit\/#{merge_request.diff_head_sha}/ + body: /#{Gitlab.config.gitlab.url}\/#{project.full_path}\/commit\/#{merge_request.diff_head_sha}/ ).once end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 7a0508e8758..623d55fe525 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1369,7 +1369,7 @@ describe Project do context 'using a regular repository' do it 'creates the repository' do expect(shell).to receive(:add_repository) - .with(project.repository_storage_path, project.path_with_namespace) + .with(project.repository_storage_path, project.disk_path) .and_return(true) expect(project.repository).to receive(:after_create) @@ -1379,7 +1379,7 @@ describe Project do it 'adds an error if the repository could not be created' do expect(shell).to receive(:add_repository) - .with(project.repository_storage_path, project.path_with_namespace) + .with(project.repository_storage_path, project.disk_path) .and_return(false) expect(project.repository).not_to receive(:after_create) @@ -1412,7 +1412,7 @@ describe Project do .and_return(false) allow(shell).to receive(:add_repository) - .with(project.repository_storage_path, project.path_with_namespace) + .with(project.repository_storage_path, project.disk_path) .and_return(true) expect(project).to receive(:create_repository).with(force: true) @@ -1436,7 +1436,7 @@ describe Project do .and_return(false) expect(shell).to receive(:add_repository) - .with(project.repository_storage_path, project.path_with_namespace) + .with(project.repository_storage_path, project.disk_path) .and_return(true) project.ensure_repository @@ -1600,7 +1600,7 @@ describe Project do before do allow_any_instance_of(Gitlab::Shell).to receive(:import_repository) - .with(project.repository_storage_path, project.path_with_namespace, project.import_url) + .with(project.repository_storage_path, project.disk_path, project.import_url) .and_return(true) expect_any_instance_of(Repository).to receive(:after_import) @@ -1738,7 +1738,7 @@ describe Project do it 'schedules a RepositoryForkWorker job' do expect(RepositoryForkWorker).to receive(:perform_async) .with(project.id, forked_from_project.repository_storage_path, - forked_from_project.path_with_namespace, project.namespace.full_path) + forked_from_project.disk_path, project.namespace.full_path) project.add_import_job end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 07ed66e127a..0fd3a4d622a 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -962,7 +962,7 @@ describe Repository do end it 'returns false if no full path can be constructed' do - allow(repository).to receive(:path_with_namespace).and_return(nil) + allow(repository).to receive(:full_path).and_return(nil) expect(repository.exists?).to eq(false) end diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index 36db1aab557..2cb60cbcfc4 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -59,7 +59,7 @@ describe Projects::TransferService do end def project_path(project) - File.join(project.repository_storage_path, "#{project.path_with_namespace}.git") + File.join(project.repository_storage_path, "#{project.disk_path}.git") end def current_path diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb index 71580a788d0..fae92451b46 100644 --- a/spec/tasks/gitlab/backup_rake_spec.rb +++ b/spec/tasks/gitlab/backup_rake_spec.rb @@ -117,7 +117,7 @@ describe 'gitlab:app namespace rake task' do describe 'backup creation and deletion using custom_hooks' do let(:project) { create(:project, :repository) } - let(:user_backup_path) { "repositories/#{project.path_with_namespace}" } + let(:user_backup_path) { "repositories/#{project.disk_path}" } before(:each) do @origin_cd = Dir.pwd @@ -261,8 +261,8 @@ describe 'gitlab:app namespace rake task' do %W{tar -tvf #{@backup_tar} repositories} ) expect(exit_status).to eq(0) - expect(tar_contents).to match("repositories/#{project_a.path_with_namespace}.bundle") - expect(tar_contents).to match("repositories/#{project_b.path_with_namespace}.bundle") + expect(tar_contents).to match("repositories/#{project_a.disk_path}.bundle") + expect(tar_contents).to match("repositories/#{project_b.disk_path}.bundle") end end end # backup_create task -- cgit v1.2.1 From fb06a4d8fe7bb10c2784f323261cfde04718aec9 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Sat, 22 Jul 2017 02:37:22 +0200 Subject: Rename more path_with_namespace -> full_path or disk_path --- app/models/concerns/storage/legacy_project_wiki.rb | 9 +++++ app/models/concerns/storage/legacy_repository.rb | 7 ++++ app/models/project.rb | 10 +++--- app/models/project_wiki.rb | 24 +++++++------ app/models/repository.rb | 22 ++++++------ app/services/projects/destroy_service.rb | 2 +- app/uploaders/file_uploader.rb | 2 +- app/views/admin/groups/show.html.haml | 4 +-- app/views/import/_githubish_status.html.haml | 2 +- app/views/import/base/create.js.haml | 2 +- app/views/import/bitbucket/status.html.haml | 2 +- app/views/import/fogbugz/status.html.haml | 2 +- app/views/import/gitlab/status.html.haml | 2 +- app/views/import/google_code/status.html.haml | 2 +- app/views/projects/commits/_commit.html.haml | 2 +- .../projects/mattermosts/_team_selection.html.haml | 2 +- .../creations/_new_compare.html.haml | 2 +- .../merge_requests/dropdowns/_project.html.haml | 2 +- .../_detailed_help.html.haml | 2 +- .../services/slack_slash_commands/_help.html.haml | 2 +- app/views/projects/wikis/git_access.html.haml | 2 +- lib/backup/repository.rb | 6 ++-- lib/banzai/filter/relative_link_filter.rb | 2 +- lib/gitlab/github_import/importer.rb | 2 +- lib/gitlab/github_import/wiki_formatter.rb | 4 +-- lib/tasks/gitlab/check.rake | 2 +- lib/tasks/gitlab/list_repos.rake | 2 +- lib/tasks/gitlab/shell.rake | 2 +- .../wiki/user_git_access_wiki_page_spec.rb | 2 +- spec/lib/banzai/filter/upload_link_filter_spec.rb | 10 +++--- .../gitlab/gitaly_client/commit_service_spec.rb | 2 +- .../gitlab/github_import/wiki_formatter_spec.rb | 4 +-- spec/models/project_wiki_spec.rb | 18 ++++++---- spec/requests/git_http_spec.rb | 42 +++++++++++----------- spec/requests/lfs_http_spec.rb | 2 +- spec/requests/request_profiler_spec.rb | 2 +- ...ntainer_registry_authentication_service_spec.rb | 36 +++++++++---------- spec/services/system_note_service_spec.rb | 2 +- 38 files changed, 137 insertions(+), 109 deletions(-) create mode 100644 app/models/concerns/storage/legacy_project_wiki.rb create mode 100644 app/models/concerns/storage/legacy_repository.rb diff --git a/app/models/concerns/storage/legacy_project_wiki.rb b/app/models/concerns/storage/legacy_project_wiki.rb new file mode 100644 index 00000000000..ff82cb0ffa9 --- /dev/null +++ b/app/models/concerns/storage/legacy_project_wiki.rb @@ -0,0 +1,9 @@ +module Storage + module LegacyProjectWiki + extend ActiveSupport::Concern + + def disk_path + project.disk_path + '.wiki' + end + end +end diff --git a/app/models/concerns/storage/legacy_repository.rb b/app/models/concerns/storage/legacy_repository.rb new file mode 100644 index 00000000000..593749bf019 --- /dev/null +++ b/app/models/concerns/storage/legacy_repository.rb @@ -0,0 +1,7 @@ +module Storage + module LegacyRepository + extend ActiveSupport::Concern + + delegate :disk_path, to: :project + end +end diff --git a/app/models/project.rb b/app/models/project.rb index 776b8f4600b..fe85e3e289a 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -480,7 +480,7 @@ class Project < ActiveRecord::Base end def repository - @repository ||= Repository.new(path_with_namespace, self) + @repository ||= Repository.new(full_path, disk_path, self) end def container_registry_url @@ -945,7 +945,7 @@ class Project < ActiveRecord::Base end def url_to_repo - gitlab_shell.url_to_repo(path_with_namespace) + gitlab_shell.url_to_repo(full_path) end def repo_exists? @@ -980,8 +980,9 @@ class Project < ActiveRecord::Base # Expires various caches before a project is renamed. def expire_caches_before_rename(old_path) - repo = Repository.new(old_path, self) - wiki = Repository.new("#{old_path}.wiki", self) + # TODO: if we start using UUIDs for cache, we don't need to do this HACK anymore + repo = Repository.new(old_path, old_path, self) + wiki = Repository.new("#{old_path}.wiki", "#{old_path}.wiki", self) if repo.exists? repo.before_delete @@ -1209,6 +1210,7 @@ class Project < ActiveRecord::Base deploy_keys.where(public: false).delete_all end + # TODO: what to do here when not using Legacy Storage? Do we still need to rename and delay removal? def remove_pages ::Projects::UpdatePagesConfigurationService.new(self).execute diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb index b44ee9b1766..2dd49adc880 100644 --- a/app/models/project_wiki.rb +++ b/app/models/project_wiki.rb @@ -1,5 +1,6 @@ class ProjectWiki include Gitlab::ShellAdapter + include Storage::LegacyProjectWiki MARKUPS = { 'Markdown' => :markdown, @@ -26,16 +27,19 @@ class ProjectWiki @project.path + '.wiki' end - def path_with_namespace + def full_path @project.full_path + '.wiki' end + # @deprecated use full_path when you need it for an URL route or disk_path when you want to point to the filesystem + alias_method :path_with_namespace, :full_path + def web_url Gitlab::Routing.url_helpers.project_wiki_url(@project, :home) end def url_to_repo - gitlab_shell.url_to_repo(path_with_namespace) + gitlab_shell.url_to_repo(full_path) end def ssh_url_to_repo @@ -43,11 +47,11 @@ class ProjectWiki end def http_url_to_repo - "#{Gitlab.config.gitlab.url}/#{path_with_namespace}.git" + "#{Gitlab.config.gitlab.url}/#{full_path}.git" end def wiki_base_path - [Gitlab.config.gitlab.relative_url_root, "/", @project.full_path, "/wikis"].join('') + [Gitlab.config.gitlab.relative_url_root, '/', @project.full_path, '/wikis'].join('') end # Returns the Gollum::Wiki object. @@ -134,7 +138,7 @@ class ProjectWiki end def repository - @repository ||= Repository.new(path_with_namespace, @project) + @repository ||= Repository.new(full_path, disk_path, @project) end def default_branch @@ -142,7 +146,7 @@ class ProjectWiki end def create_repo! - if init_repo(path_with_namespace) + if init_repo(disk_path) wiki = Gollum::Wiki.new(path_to_repo) else raise CouldNotCreateWikiError @@ -162,15 +166,15 @@ class ProjectWiki web_url: web_url, git_ssh_url: ssh_url_to_repo, git_http_url: http_url_to_repo, - path_with_namespace: path_with_namespace, + path_with_namespace: full_path, default_branch: default_branch } end private - def init_repo(path_with_namespace) - gitlab_shell.add_repository(project.repository_storage_path, path_with_namespace) + def init_repo(disk_path) + gitlab_shell.add_repository(project.repository_storage_path, disk_path) end def commit_details(action, message = nil, title = nil) @@ -184,7 +188,7 @@ class ProjectWiki end def path_to_repo - @path_to_repo ||= File.join(project.repository_storage_path, "#{path_with_namespace}.git") + @path_to_repo ||= File.join(project.repository_storage_path, "#{disk_path}.git") end def update_project_activity diff --git a/app/models/repository.rb b/app/models/repository.rb index 50b7a477904..5d39e2e271d 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -4,7 +4,7 @@ class Repository include Gitlab::ShellAdapter include RepositoryMirroring - attr_accessor :path_with_namespace, :project + attr_accessor :full_path, :disk_path, :project delegate :ref_name_for_sha, to: :raw_repository @@ -52,13 +52,14 @@ class Repository end end - def initialize(path_with_namespace, project) - @path_with_namespace = path_with_namespace + def initialize(full_path, disk_path, project) + @full_path = full_path + @disk_path = disk_path @project = project end def raw_repository - return nil unless path_with_namespace + return nil unless full_path @raw_repository ||= initialize_raw_repository end @@ -66,7 +67,7 @@ class Repository # Return absolute path to repository def path_to_repo @path_to_repo ||= File.expand_path( - File.join(repository_storage_path, path_with_namespace + ".git") + File.join(repository_storage_path, disk_path + '.git') ) end @@ -469,7 +470,7 @@ class Repository # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/314 def exists? - return false unless path_with_namespace + return false unless full_path Gitlab::GitalyClient.migrate(:repository_exists) do |enabled| if enabled @@ -1005,7 +1006,7 @@ class Repository end def fetch_remote(remote, forced: false, no_tags: false) - gitlab_shell.fetch_remote(repository_storage_path, path_with_namespace, remote, forced: forced, no_tags: no_tags) + gitlab_shell.fetch_remote(repository_storage_path, disk_path, remote, forced: forced, no_tags: no_tags) end def fetch_ref(source_path, source_ref, target_ref) @@ -1104,7 +1105,8 @@ class Repository end def cache - @cache ||= RepositoryCache.new(path_with_namespace, @project.id) + # TODO: should we use UUIDs here? We could move repositories without clearing this cache + @cache ||= RepositoryCache.new(full_path, @project.id) end def tags_sorted_by_committed_date @@ -1127,7 +1129,7 @@ class Repository end def repository_event(event, tags = {}) - Gitlab::Metrics.add_event(event, { path: path_with_namespace }.merge(tags)) + Gitlab::Metrics.add_event(event, { path: full_path }.merge(tags)) end def create_commit(params = {}) @@ -1141,6 +1143,6 @@ class Repository end def initialize_raw_repository - Gitlab::Git::Repository.new(project.repository_storage, path_with_namespace + '.git') + Gitlab::Git::Repository.new(project.repository_storage, disk_path + '.git') end end diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index 952272903f3..b7f4dba08a9 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -127,7 +127,7 @@ module Projects def flush_caches(project) project.repository.before_delete - Repository.new(wiki_path, project).before_delete + Repository.new(wiki_path, repo_path, project).before_delete end end end diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb index 652277e3b78..7027ac4b5db 100644 --- a/app/uploaders/file_uploader.rb +++ b/app/uploaders/file_uploader.rb @@ -30,7 +30,7 @@ class FileUploader < GitlabUploader # # Returns a String without a trailing slash def self.dynamic_path_segment(model) - File.join(CarrierWave.root, base_dir, model.path_with_namespace) + File.join(CarrierWave.root, base_dir, model.full_path) end attr_accessor :model diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 843c71af466..2aadc071c75 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -70,7 +70,7 @@ %span.badge = storage_counter(project.statistics.storage_size) %span.pull-right.light - %span.monospace= project.path_with_namespace + ".git" + %span.monospace= project.full_path + '.git' .panel-footer = paginate @projects, param_name: 'projects_page', theme: 'gitlab' @@ -88,7 +88,7 @@ %span.badge = storage_counter(project.statistics.storage_size) %span.pull-right.light - %span.monospace= project.path_with_namespace + ".git" + %span.monospace= project.full_path + '.git' .col-md-6 - if can?(current_user, :admin_group_member, @group) diff --git a/app/views/import/_githubish_status.html.haml b/app/views/import/_githubish_status.html.haml index 0e7f0b5ed4f..e9a04e6c122 100644 --- a/app/views/import/_githubish_status.html.haml +++ b/app/views/import/_githubish_status.html.haml @@ -25,7 +25,7 @@ %td = provider_project_link(provider, project.import_source) %td - = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] + = link_to project.full_path, [project.namespace.becomes(Namespace), project] %td.job-status - if project.import_status == 'finished' %span diff --git a/app/views/import/base/create.js.haml b/app/views/import/base/create.js.haml index fde671e25a9..4dc3a4a0acf 100644 --- a/app/views/import/base/create.js.haml +++ b/app/views/import/base/create.js.haml @@ -4,7 +4,7 @@ job.attr("id", "project_#{@project.id}") target_field = job.find(".import-target") target_field.empty() - target_field.append('#{link_to @project.path_with_namespace, project_path(@project)}') + target_field.append('#{link_to @project.full_path, project_path(@project)}') $("table.import-jobs tbody").prepend(job) job.addClass("active").find(".import-actions").html(" started") - else diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml index e6058617ac9..9589e0956f4 100644 --- a/app/views/import/bitbucket/status.html.haml +++ b/app/views/import/bitbucket/status.html.haml @@ -35,7 +35,7 @@ %td = link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: '_blank', rel: 'noopener noreferrer' %td - = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] + = link_to project.full_path, [project.namespace.becomes(Namespace), project] %td.job-status - if project.import_status == 'finished' %span diff --git a/app/views/import/fogbugz/status.html.haml b/app/views/import/fogbugz/status.html.haml index 5de5da5e6a2..7b832c6a23a 100644 --- a/app/views/import/fogbugz/status.html.haml +++ b/app/views/import/fogbugz/status.html.haml @@ -33,7 +33,7 @@ %td = project.import_source %td - = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] + = link_to project.full_path, [project.namespace.becomes(Namespace), project] %td.job-status - if project.import_status == 'finished' %span diff --git a/app/views/import/gitlab/status.html.haml b/app/views/import/gitlab/status.html.haml index 7456799ca0e..37734414835 100644 --- a/app/views/import/gitlab/status.html.haml +++ b/app/views/import/gitlab/status.html.haml @@ -28,7 +28,7 @@ %td = link_to project.import_source, "https://gitlab.com/#{project.import_source}", target: "_blank" %td - = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] + = link_to project.full_path, [project.namespace.becomes(Namespace), project] %td.job-status - if project.import_status == 'finished' %span diff --git a/app/views/import/google_code/status.html.haml b/app/views/import/google_code/status.html.haml index 60de6bfe816..bc61aeece72 100644 --- a/app/views/import/google_code/status.html.haml +++ b/app/views/import/google_code/status.html.haml @@ -38,7 +38,7 @@ %td = link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank", rel: 'noopener noreferrer' %td - = link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project] + = link_to project.full_path, [project.namespace.becomes(Namespace), project] %td.job-status - if project.import_status == 'finished' %span diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index 12b73ecdf13..e7da47032be 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -5,7 +5,7 @@ - notes = commit.notes - note_count = notes.user.count -- cache_key = [project.path_with_namespace, commit.id, current_application_settings, note_count, @path.presence, current_controller?(:commits)] +- cache_key = [project.full_path, commit.id, current_application_settings, note_count, @path.presence, current_controller?(:commits)] - cache_key.push(commit.status(ref)) if commit.status(ref) = cache(cache_key, expires_in: 1.day) do diff --git a/app/views/projects/mattermosts/_team_selection.html.haml b/app/views/projects/mattermosts/_team_selection.html.haml index 3bdb5d0adc4..20acd476f73 100644 --- a/app/views/projects/mattermosts/_team_selection.html.haml +++ b/app/views/projects/mattermosts/_team_selection.html.haml @@ -33,7 +33,7 @@ Suggestions: %code= 'gitlab' %code= @project.path # Path contains no spaces, but dashes - %code= @project.path_with_namespace + %code= @project.full_path %p Reserved: = link_to 'https://docs.mattermost.com/help/messaging/executing-commands.html#built-in-commands', target: '__blank' do diff --git a/app/views/projects/merge_requests/creations/_new_compare.html.haml b/app/views/projects/merge_requests/creations/_new_compare.html.haml index 8958b2cf5e1..9d5cebdda53 100644 --- a/app/views/projects/merge_requests/creations/_new_compare.html.haml +++ b/app/views/projects/merge_requests/creations/_new_compare.html.haml @@ -41,7 +41,7 @@ - projects = target_projects(@project) .merge-request-select.dropdown = f.hidden_field :target_project_id - = dropdown_toggle f.object.target_project.path_with_namespace, { toggle: "dropdown", field_name: "#{f.object_name}[target_project_id]", disabled: @merge_request.persisted? }, { toggle_class: "js-compare-dropdown js-target-project" } + = dropdown_toggle f.object.target_project.full_path, { toggle: "dropdown", field_name: "#{f.object_name}[target_project_id]", disabled: @merge_request.persisted? }, { toggle_class: "js-compare-dropdown js-target-project" } .dropdown-menu.dropdown-menu-selectable.dropdown-target-project = dropdown_title("Select target project") = dropdown_filter("Search projects") diff --git a/app/views/projects/merge_requests/dropdowns/_project.html.haml b/app/views/projects/merge_requests/dropdowns/_project.html.haml index 25d5dc92f8a..aaf1ab00eeb 100644 --- a/app/views/projects/merge_requests/dropdowns/_project.html.haml +++ b/app/views/projects/merge_requests/dropdowns/_project.html.haml @@ -2,4 +2,4 @@ - projects.each do |project| %li %a{ href: "#", class: "#{('is-active' if selected == project.id)}", data: { id: project.id } } - = project.path_with_namespace + = project.full_path diff --git a/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml b/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml index ef3599460f1..5dbcbf7eba6 100644 --- a/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml +++ b/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml @@ -39,7 +39,7 @@ Suggestions: %code= 'gitlab' %code= @project.path # Path contains no spaces, but dashes - %code= @project.path_with_namespace + %code= @project.full_path .form-group = label_tag :request_url, 'Request URL', class: 'col-sm-2 col-xs-12 control-label' diff --git a/app/views/projects/services/slack_slash_commands/_help.html.haml b/app/views/projects/services/slack_slash_commands/_help.html.haml index 73b99453a4b..c31c95608c6 100644 --- a/app/views/projects/services/slack_slash_commands/_help.html.haml +++ b/app/views/projects/services/slack_slash_commands/_help.html.haml @@ -33,7 +33,7 @@ Suggestions: %code= 'gitlab' %code= @project.path # Path contains no spaces, but dashes - %code= @project.path_with_namespace + %code= @project.full_path .form-group = label_tag :url, 'URL', class: 'col-sm-2 col-xs-12 control-label' diff --git a/app/views/projects/wikis/git_access.html.haml b/app/views/projects/wikis/git_access.html.haml index e64dd6085fe..e740fb93ea4 100644 --- a/app/views/projects/wikis/git_access.html.haml +++ b/app/views/projects/wikis/git_access.html.haml @@ -7,7 +7,7 @@ .git-access-header Clone repository - %strong= @project_wiki.path_with_namespace + %strong= @project_wiki.full_path = render "shared/clone_panel", project: @project_wiki diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb index 8d56b74bfd6..05175d51963 100644 --- a/lib/backup/repository.rb +++ b/lib/backup/repository.rb @@ -42,7 +42,7 @@ module Backup path_to_wiki_bundle = path_to_bundle(wiki) if File.exist?(path_to_wiki_repo) - progress.print " * #{wiki.path_with_namespace} ... " + progress.print " * #{wiki.full_path} ... " if empty_repo?(wiki) progress.puts " [SKIPPED]".color(:cyan) else @@ -104,7 +104,7 @@ module Backup path_to_wiki_bundle = path_to_bundle(wiki) if File.exist?(path_to_wiki_bundle) - progress.print " * #{wiki.path_with_namespace} ... " + progress.print " * #{wiki.full_path} ... " # If a wiki bundle exists, first remove the empty repo # that was initialized with ProjectWiki.new() and then @@ -192,7 +192,7 @@ module Backup project_or_wiki.repository.expire_exists_cache # protect backups from stale cache project_or_wiki.repository.empty_repo? rescue => e - progress.puts "Ignoring repository error and continuing backing up project: #{project_or_wiki.path_with_namespace} - #{e.message}".color(:orange) + progress.puts "Ignoring repository error and continuing backing up project: #{project_or_wiki.full_path} - #{e.message}".color(:orange) false end diff --git a/lib/banzai/filter/relative_link_filter.rb b/lib/banzai/filter/relative_link_filter.rb index c2fed57a0d8..758f15c8a67 100644 --- a/lib/banzai/filter/relative_link_filter.rb +++ b/lib/banzai/filter/relative_link_filter.rb @@ -51,7 +51,7 @@ module Banzai uri.path = [ relative_url_root, - context[:project].path_with_namespace, + context[:project].full_path, uri_type(file_path), Addressable::URI.escape(ref), Addressable::URI.escape(file_path) diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index a8c0b47e786..266b1a6fece 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -254,7 +254,7 @@ module Gitlab def import_wiki unless project.wiki.repository_exists? wiki = WikiFormatter.new(project) - gitlab_shell.import_repository(project.repository_storage_path, wiki.path_with_namespace, wiki.import_url) + gitlab_shell.import_repository(project.repository_storage_path, wiki.disk_path, wiki.import_url) end rescue Gitlab::Shell::Error => e # GitHub error message when the wiki repo has not been created, diff --git a/lib/gitlab/github_import/wiki_formatter.rb b/lib/gitlab/github_import/wiki_formatter.rb index 30cff1ba804..0396122eeb9 100644 --- a/lib/gitlab/github_import/wiki_formatter.rb +++ b/lib/gitlab/github_import/wiki_formatter.rb @@ -7,8 +7,8 @@ module Gitlab @project = project end - def path_with_namespace - "#{project.full_path}.wiki" + def disk_path + "#{project.disk_path}.wiki" end def import_url diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 858f1cd7b34..dbb3b827b9a 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -527,7 +527,7 @@ namespace :gitlab do repo_dirs = user.authorized_projects.map do |p| File.join( p.repository_storage_path, - "#{p.path_with_namespace}.git" + "#{p.disk_path}.git" ) end diff --git a/lib/tasks/gitlab/list_repos.rake b/lib/tasks/gitlab/list_repos.rake index ffcc76e5498..b732db9db6e 100644 --- a/lib/tasks/gitlab/list_repos.rake +++ b/lib/tasks/gitlab/list_repos.rake @@ -9,7 +9,7 @@ namespace :gitlab do scope = scope.where('id IN (?) OR namespace_id in (?)', project_ids, namespace_ids) end scope.find_each do |project| - base = File.join(project.repository_storage_path, project.path_with_namespace) + base = File.join(project.repository_storage_path, project.disk_path) puts base + '.git' puts base + '.wiki.git' end diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake index ee2cdcdea1b..42825f29e32 100644 --- a/lib/tasks/gitlab/shell.rake +++ b/lib/tasks/gitlab/shell.rake @@ -80,7 +80,7 @@ namespace :gitlab do print '-' else if Gitlab::Shell.new.add_repository(project.repository_storage_path, - project.path_with_namespace) + project.disk_path) print '.' else print 'F' diff --git a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb index 9c58e336605..f1e7f5f2be8 100644 --- a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb @@ -20,7 +20,7 @@ describe 'Projects > Wiki > User views Git access wiki page' do visit project_wiki_path(project, wiki_page) click_link 'Clone repository' - expect(page).to have_text("Clone repository #{project.wiki.path_with_namespace}") + expect(page).to have_text("Clone repository #{project.wiki.full_path}") expect(page).to have_text(project.wiki.http_url_to_repo) end end diff --git a/spec/lib/banzai/filter/upload_link_filter_spec.rb b/spec/lib/banzai/filter/upload_link_filter_spec.rb index 3bc9635b50e..74a23a9ab5e 100644 --- a/spec/lib/banzai/filter/upload_link_filter_spec.rb +++ b/spec/lib/banzai/filter/upload_link_filter_spec.rb @@ -52,21 +52,21 @@ describe Banzai::Filter::UploadLinkFilter do it 'rebuilds relative URL for a link' do doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) expect(doc.at_css('a')['href']) - .to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" doc = filter(nested_link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) expect(doc.at_css('a')['href']) - .to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" end it 'rebuilds relative URL for an image' do doc = filter(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) expect(doc.at_css('img')['src']) - .to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" doc = filter(nested_image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) expect(doc.at_css('img')['src']) - .to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" end it 'does not modify absolute URL' do @@ -85,7 +85,7 @@ describe Banzai::Filter::UploadLinkFilter do .to receive(:image?).with(path).and_return(true) doc = filter(image(escaped)) - expect(doc.at_css('img')['src']).to match "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/%ED%95%9C%EA%B8%80.png" + expect(doc.at_css('img')['src']).to match "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/%ED%95%9C%EA%B8%80.png" end end diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb index 0868c793a33..d71e0f84c65 100644 --- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::GitalyClient::CommitService do let(:project) { create(:project, :repository) } let(:storage_name) { project.repository_storage } - let(:relative_path) { project.path_with_namespace + '.git' } + let(:relative_path) { project.disk_path + '.git' } let(:repository) { project.repository } let(:repository_message) { repository.gitaly_repository } let(:revision) { '913c66a37b4a45b9769037c55c2d238bd0942d2e' } diff --git a/spec/lib/gitlab/github_import/wiki_formatter_spec.rb b/spec/lib/gitlab/github_import/wiki_formatter_spec.rb index de50265bc14..fcd90fab547 100644 --- a/spec/lib/gitlab/github_import/wiki_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/wiki_formatter_spec.rb @@ -9,9 +9,9 @@ describe Gitlab::GithubImport::WikiFormatter do subject(:wiki) { described_class.new(project) } - describe '#path_with_namespace' do + describe '#disk_path' do it 'appends .wiki to project path' do - expect(wiki.path_with_namespace).to eq 'gitlabhq/gitlabhq.wiki' + expect(wiki.disk_path).to eq project.disk_path + '.wiki' end end diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index c6ceb092810..484fcfc88a3 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -15,19 +15,23 @@ describe ProjectWiki do describe "#path_with_namespace" do it "returns the project path with namespace with the .wiki extension" do - expect(subject.path_with_namespace).to eq(project.path_with_namespace + ".wiki") + expect(subject.path_with_namespace).to eq(project.full_path + '.wiki') + end + + it 'returns the same value as #full_path' do + expect(subject.path_with_namespace).to eq(subject.full_path) end end describe '#web_url' do it 'returns the full web URL to the wiki' do - expect(subject.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/wikis/home") + expect(subject.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.full_path}/wikis/home") end end describe "#url_to_repo" do it "returns the correct ssh url to the repo" do - expect(subject.url_to_repo).to eq(gitlab_shell.url_to_repo(subject.path_with_namespace)) + expect(subject.url_to_repo).to eq(gitlab_shell.url_to_repo(subject.full_path)) end end @@ -41,7 +45,7 @@ describe ProjectWiki do let(:project) { create :empty_project } it 'returns the full http url to the repo' do - expected_url = "#{Gitlab.config.gitlab.url}/#{subject.path_with_namespace}.git" + expected_url = "#{Gitlab.config.gitlab.url}/#{subject.full_path}.git" expect(project_wiki.http_url_to_repo).to eq(expected_url) expect(project_wiki.http_url_to_repo).not_to include('@') @@ -50,7 +54,7 @@ describe ProjectWiki do describe "#wiki_base_path" do it "returns the wiki base path" do - wiki_base_path = "#{Gitlab.config.gitlab.relative_url_root}/#{project.path_with_namespace}/wikis" + wiki_base_path = "#{Gitlab.config.gitlab.relative_url_root}/#{project.full_path}/wikis" expect(subject.wiki_base_path).to eq(wiki_base_path) end @@ -77,7 +81,7 @@ describe ProjectWiki do allow_any_instance_of(Gitlab::Shell).to receive(:add_repository) do create_temp_repo("#{Rails.root}/tmp/test-git-base-path/non-existant.wiki.git") end - allow(project).to receive(:path_with_namespace).and_return("non-existant") + allow(project).to receive(:full_path).and_return("non-existant") end describe '#empty?' do @@ -269,7 +273,7 @@ describe ProjectWiki do describe '#create_repo!' do it 'creates a repository' do expect(subject).to receive(:init_repo) - .with(subject.path_with_namespace) + .with(subject.full_path) .and_return(true) expect(subject.repository).to receive(:after_create) diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index d4a3e8b13e1..d5c16d8f601 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -123,7 +123,7 @@ describe 'Git HTTP requests' do context "when requesting the Wiki" do let(:wiki) { ProjectWiki.new(project) } - let(:path) { "/#{wiki.repository.path_with_namespace}.git" } + let(:path) { "/#{wiki.repository.full_path}.git" } context "when the project is public" do let(:project) { create(:project, :repository, :public, :wiki_enabled) } @@ -139,7 +139,7 @@ describe 'Git HTTP requests' do download(path) do |response| json_body = ActiveSupport::JSON.decode(response.body) - expect(json_body['RepoPath']).to include(wiki.repository.path_with_namespace) + expect(json_body['RepoPath']).to include(wiki.repository.full_path) end end end @@ -222,7 +222,7 @@ describe 'Git HTTP requests' do end context "when the project exists" do - let(:path) { "#{project.path_with_namespace}.git" } + let(:path) { "#{project.full_path}.git" } context "when the project is public" do let(:project) { create(:project, :repository, :public) } @@ -286,7 +286,7 @@ describe 'Git HTTP requests' do context 'when the request is not from gitlab-workhorse' do it 'raises an exception' do expect do - get("/#{project.path_with_namespace}.git/info/refs?service=git-upload-pack") + get("/#{project.full_path}.git/info/refs?service=git-upload-pack") end.to raise_error(JWT::DecodeError) end end @@ -294,7 +294,7 @@ describe 'Git HTTP requests' do context 'when the repo is public' do context 'but the repo is disabled' do let(:project) { create(:project, :public, :repository, :repository_disabled) } - let(:path) { "#{project.path_with_namespace}.git" } + let(:path) { "#{project.full_path}.git" } let(:env) { {} } it_behaves_like 'pulls require Basic HTTP Authentication' @@ -303,7 +303,7 @@ describe 'Git HTTP requests' do context 'but the repo is enabled' do let(:project) { create(:project, :public, :repository, :repository_enabled) } - let(:path) { "#{project.path_with_namespace}.git" } + let(:path) { "#{project.full_path}.git" } let(:env) { {} } it_behaves_like 'pulls are allowed' @@ -421,7 +421,7 @@ describe 'Git HTTP requests' do @token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: "api") end - let(:path) { "#{project.path_with_namespace}.git" } + let(:path) { "#{project.full_path}.git" } let(:env) { { user: 'oauth2', password: @token.token } } it_behaves_like 'pulls are allowed' @@ -431,7 +431,7 @@ describe 'Git HTTP requests' do context 'when user has 2FA enabled' do let(:user) { create(:user, :two_factor) } let(:access_token) { create(:personal_access_token, user: user) } - let(:path) { "#{project.path_with_namespace}.git" } + let(:path) { "#{project.full_path}.git" } before do project.team << [user, :master] @@ -580,7 +580,7 @@ describe 'Git HTTP requests' do end context 'when build created by system is authenticated' do - let(:path) { "#{project.path_with_namespace}.git" } + let(:path) { "#{project.full_path}.git" } let(:env) { { user: 'gitlab-ci-token', password: build.token } } it_behaves_like 'pulls are allowed' @@ -602,7 +602,7 @@ describe 'Git HTTP requests' do # We are "authenticated" as CI using a valid token here. But we are # not authorized to see any other project, so return "not found". it "rejects pulls for other project with 404 Not Found" do - clone_get("#{other_project.path_with_namespace}.git", env) + clone_get("#{other_project.full_path}.git", env) expect(response).to have_http_status(:not_found) expect(response.body).to eq(git_access_error(:project_not_found)) @@ -616,7 +616,7 @@ describe 'Git HTTP requests' do end shared_examples 'can download code only' do - let(:path) { "#{project.path_with_namespace}.git" } + let(:path) { "#{project.full_path}.git" } let(:env) { { user: 'gitlab-ci-token', password: build.token } } it_behaves_like 'pulls are allowed' @@ -646,7 +646,7 @@ describe 'Git HTTP requests' do it_behaves_like 'can download code only' it 'downloads from other project get status 403' do - clone_get "#{other_project.path_with_namespace}.git", user: 'gitlab-ci-token', password: build.token + clone_get "#{other_project.full_path}.git", user: 'gitlab-ci-token', password: build.token expect(response).to have_http_status(:forbidden) end @@ -658,7 +658,7 @@ describe 'Git HTTP requests' do it_behaves_like 'can download code only' it 'downloads from other project get status 404' do - clone_get "#{other_project.path_with_namespace}.git", user: 'gitlab-ci-token', password: build.token + clone_get "#{other_project.full_path}.git", user: 'gitlab-ci-token', password: build.token expect(response).to have_http_status(:not_found) end @@ -671,7 +671,7 @@ describe 'Git HTTP requests' do let(:project) { create(:project, :repository, :public, path: 'project.git-project') } context "GET info/refs" do - let(:path) { "/#{project.path_with_namespace}/info/refs" } + let(:path) { "/#{project.full_path}/info/refs" } context "when no params are added" do before do @@ -679,7 +679,7 @@ describe 'Git HTTP requests' do end it "redirects to the .git suffix version" do - expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs") + expect(response).to redirect_to("/#{project.full_path}.git/info/refs") end end @@ -691,7 +691,7 @@ describe 'Git HTTP requests' do end it "redirects to the .git suffix version" do - expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}") + expect(response).to redirect_to("/#{project.full_path}.git/info/refs?service=#{params[:service]}") end end @@ -703,7 +703,7 @@ describe 'Git HTTP requests' do end it "redirects to the .git suffix version" do - expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}") + expect(response).to redirect_to("/#{project.full_path}.git/info/refs?service=#{params[:service]}") end end @@ -722,13 +722,13 @@ describe 'Git HTTP requests' do context "POST git-upload-pack" do it "fails to find a route" do - expect { clone_post(project.path_with_namespace) }.to raise_error(ActionController::RoutingError) + expect { clone_post(project.full_path) }.to raise_error(ActionController::RoutingError) end end context "POST git-receive-pack" do it "fails to find a route" do - expect { push_post(project.path_with_namespace) }.to raise_error(ActionController::RoutingError) + expect { push_post(project.full_path) }.to raise_error(ActionController::RoutingError) end end end @@ -744,7 +744,7 @@ describe 'Git HTTP requests' do Blob.decorate(Gitlab::Git::Blob.find(project.repository, 'master', 'bar/branch-test.txt'), project) end - get "/#{project.path_with_namespace}/blob/master/info/refs" + get "/#{project.full_path}/blob/master/info/refs" end it "returns the file" do @@ -754,7 +754,7 @@ describe 'Git HTTP requests' do context "when the file does not exist" do before do - get "/#{project.path_with_namespace}/blob/master/info/refs" + get "/#{project.full_path}/blob/master/info/refs" end it "returns not found" do diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb index 697b150ab34..4f1a90750b3 100644 --- a/spec/requests/lfs_http_spec.rb +++ b/spec/requests/lfs_http_spec.rb @@ -701,7 +701,7 @@ describe 'Git LFS API and storage' do expect(json_response['objects']).to be_kind_of(Array) expect(json_response['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897") expect(json_response['objects'].first['size']).to eq(1575078) - expect(json_response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078") + expect(json_response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.full_path}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078") expect(json_response['objects'].first['actions']['upload']['header']).to eq('Authorization' => authorization) end end diff --git a/spec/requests/request_profiler_spec.rb b/spec/requests/request_profiler_spec.rb index 51fbfecec4b..9afeb2983b0 100644 --- a/spec/requests/request_profiler_spec.rb +++ b/spec/requests/request_profiler_spec.rb @@ -15,7 +15,7 @@ describe 'Request Profiler' do it 'creates a profile of the request' do project = create(:project, namespace: user.namespace) time = Time.now - path = "/#{project.path_with_namespace}" + path = "/#{project.full_path}" Timecop.freeze(time) do get path, nil, 'X-Profile-Token' => Gitlab::RequestProfiler.profile_token diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb index 66a8a93b168..0ae839ce0b3 100644 --- a/spec/services/auth/container_registry_authentication_service_spec.rb +++ b/spec/services/auth/container_registry_authentication_service_spec.rb @@ -46,7 +46,7 @@ describe Auth::ContainerRegistryAuthenticationService do shared_examples 'an accessible' do let(:access) do [{ 'type' => 'repository', - 'name' => project.path_with_namespace, + 'name' => project.full_path, 'actions' => actions }] end @@ -97,7 +97,7 @@ describe Auth::ContainerRegistryAuthenticationService do describe '#full_access_token' do let(:project) { create(:empty_project) } - let(:token) { described_class.full_access_token(project.path_with_namespace) } + let(:token) { described_class.full_access_token(project.full_path) } subject { { token: token } } @@ -124,7 +124,7 @@ describe Auth::ContainerRegistryAuthenticationService do end let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:push" } + { scope: "repository:#{project.full_path}:push" } end it_behaves_like 'a pushable' @@ -138,7 +138,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'when pulling from root level repository' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull" } + { scope: "repository:#{project.full_path}:pull" } end it_behaves_like 'a pullable' @@ -152,7 +152,7 @@ describe Auth::ContainerRegistryAuthenticationService do end let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:push,pull" } + { scope: "repository:#{project.full_path}:push,pull" } end it_behaves_like 'a pullable' @@ -165,7 +165,7 @@ describe Auth::ContainerRegistryAuthenticationService do end let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull,push" } + { scope: "repository:#{project.full_path}:pull,push" } end it_behaves_like 'an inaccessible' @@ -178,7 +178,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'allow anyone to pull images' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull" } + { scope: "repository:#{project.full_path}:pull" } end it_behaves_like 'a pullable' @@ -187,7 +187,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'disallow anyone to push images' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:push" } + { scope: "repository:#{project.full_path}:push" } end it_behaves_like 'an inaccessible' @@ -210,7 +210,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'for internal user' do context 'allow anyone to pull images' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull" } + { scope: "repository:#{project.full_path}:pull" } end it_behaves_like 'a pullable' @@ -219,7 +219,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'disallow anyone to push images' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:push" } + { scope: "repository:#{project.full_path}:push" } end it_behaves_like 'an inaccessible' @@ -230,7 +230,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'for external user' do let(:current_user) { create(:user, external: true) } let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull,push" } + { scope: "repository:#{project.full_path}:pull,push" } end it_behaves_like 'an inaccessible' @@ -255,7 +255,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'allow to pull and push images' do let(:current_params) do - { scope: "repository:#{current_project.path_with_namespace}:pull,push" } + { scope: "repository:#{current_project.full_path}:pull,push" } end it_behaves_like 'a pullable and pushable' do @@ -270,7 +270,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'for other projects' do context 'when pulling' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull" } + { scope: "repository:#{project.full_path}:pull" } end context 'allow for public' do @@ -337,7 +337,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'when pushing' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:push" } + { scope: "repository:#{project.full_path}:push" } end context 'disallow for all' do @@ -371,7 +371,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'disallow when pulling' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull" } + { scope: "repository:#{project.full_path}:pull" } end it_behaves_like 'an inaccessible' @@ -399,7 +399,7 @@ describe Auth::ContainerRegistryAuthenticationService do let(:project) { create(:empty_project, :private) } let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull" } + { scope: "repository:#{project.full_path}:pull" } end it_behaves_like 'a forbidden' @@ -410,7 +410,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'when pulling and pushing' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull,push" } + { scope: "repository:#{project.full_path}:pull,push" } end it_behaves_like 'a pullable' @@ -419,7 +419,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'when pushing' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:push" } + { scope: "repository:#{project.full_path}:push" } end it_behaves_like 'a forbidden' diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index 7129d282df1..5c20263a532 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -873,7 +873,7 @@ describe SystemNoteService do describe "existing reference" do before do allow(JIRA::Resource::Remotelink).to receive(:all).and_return([]) - message = "[#{author.name}|http://localhost/#{author.username}] mentioned this issue in [a commit of #{project.full_path}|http://localhost/#{project.path_with_namespace}/commit/#{commit.id}]:\n'#{commit.title.chomp}'" + message = "[#{author.name}|http://localhost/#{author.username}] mentioned this issue in [a commit of #{project.full_path}|http://localhost/#{project.full_path}/commit/#{commit.id}]:\n'#{commit.title.chomp}'" allow_any_instance_of(JIRA::Resource::Issue).to receive(:comments).and_return([OpenStruct.new(body: message)]) end -- cgit v1.2.1 From 16107364b8f0904e25a70dac29a26c435118fb29 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Sun, 23 Jul 2017 09:05:34 +0200 Subject: Make disk_path keyword argument and optional --- app/models/project.rb | 7 +++---- app/models/project_wiki.rb | 2 +- app/models/repository.rb | 4 ++-- app/services/projects/destroy_service.rb | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index fe85e3e289a..dd025f5574d 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -480,7 +480,7 @@ class Project < ActiveRecord::Base end def repository - @repository ||= Repository.new(full_path, disk_path, self) + @repository ||= Repository.new(full_path, self, disk_path: disk_path) end def container_registry_url @@ -980,9 +980,8 @@ class Project < ActiveRecord::Base # Expires various caches before a project is renamed. def expire_caches_before_rename(old_path) - # TODO: if we start using UUIDs for cache, we don't need to do this HACK anymore - repo = Repository.new(old_path, old_path, self) - wiki = Repository.new("#{old_path}.wiki", "#{old_path}.wiki", self) + repo = Repository.new(old_path, self) + wiki = Repository.new("#{old_path}.wiki", self) if repo.exists? repo.before_delete diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb index 2dd49adc880..e8929a35836 100644 --- a/app/models/project_wiki.rb +++ b/app/models/project_wiki.rb @@ -138,7 +138,7 @@ class ProjectWiki end def repository - @repository ||= Repository.new(full_path, disk_path, @project) + @repository ||= Repository.new(full_path, @project, disk_path: disk_path) end def default_branch diff --git a/app/models/repository.rb b/app/models/repository.rb index 5d39e2e271d..7ea9f1459a0 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -52,9 +52,9 @@ class Repository end end - def initialize(full_path, disk_path, project) + def initialize(full_path, project, disk_path: nil) @full_path = full_path - @disk_path = disk_path + @disk_path = disk_path || full_path @project = project end diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index b7f4dba08a9..11ad4838471 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -127,7 +127,7 @@ module Projects def flush_caches(project) project.repository.before_delete - Repository.new(wiki_path, repo_path, project).before_delete + Repository.new(wiki_path, project, disk_path: repo_path).before_delete end end end -- cgit v1.2.1 From 07b574b41cb0ff4518895ea4e6c719e453fdc4e3 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Mon, 24 Jul 2017 01:41:58 +0200 Subject: Added some extra TODOs for the Legacy Storage refactor --- app/services/projects/transfer_service.rb | 2 ++ lib/gitlab/import_export/uploads_saver.rb | 1 + 2 files changed, 3 insertions(+) diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 386d49e58e7..5957f612e84 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -61,11 +61,13 @@ module Projects project.send_move_instructions(@old_path) # Move main repository + # TODO: check storage type and NOOP when not using Legacy unless move_repo_folder(@old_path, @new_path) raise TransferError.new('Cannot move project') end # Move wiki repo also if present + # TODO: check storage type and NOOP when not using Legacy move_repo_folder("#{@old_path}.wiki", "#{@new_path}.wiki") # Move missing group labels to project diff --git a/lib/gitlab/import_export/uploads_saver.rb b/lib/gitlab/import_export/uploads_saver.rb index 62a2553675c..f9ae5079d7c 100644 --- a/lib/gitlab/import_export/uploads_saver.rb +++ b/lib/gitlab/import_export/uploads_saver.rb @@ -24,6 +24,7 @@ module Gitlab end def uploads_path + # TODO: decide what to do with uploads. We will use UUIDs here too? File.join(Rails.root.join('public/uploads'), @project.path_with_namespace) end end -- cgit v1.2.1 From 597e619080c393daa765bf6e5de74f60121d1f0e Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Tue, 1 Aug 2017 07:44:25 +0200 Subject: Rename ensure_dir_exist -> ensure_storage_path_exist --- app/models/concerns/storage/legacy_project.rb | 2 +- app/models/project.rb | 4 ++-- lib/backup/repository.rb | 2 +- spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb | 2 +- spec/workers/namespaceless_project_destroy_worker_spec.rb | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/models/concerns/storage/legacy_project.rb b/app/models/concerns/storage/legacy_project.rb index b537f40548e..815db712285 100644 --- a/app/models/concerns/storage/legacy_project.rb +++ b/app/models/concerns/storage/legacy_project.rb @@ -6,7 +6,7 @@ module Storage full_path end - def ensure_dir_exist + def ensure_storage_path_exist gitlab_shell.add_namespace(repository_storage_path, namespace.full_path) end diff --git a/app/models/project.rb b/app/models/project.rb index dd025f5574d..d7e9e2ac973 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -44,7 +44,7 @@ class Project < ActiveRecord::Base default_value_for :snippets_enabled, gitlab_config_features.snippets default_value_for :only_allow_merge_if_all_discussions_are_resolved, false - after_create :ensure_dir_exist + after_create :ensure_storage_path_exist after_create :create_project_feature, unless: :project_feature after_save :update_project_statistics, if: :namespace_id_changed? @@ -69,7 +69,7 @@ class Project < ActiveRecord::Base # Legacy Storage specific hooks - after_save :ensure_dir_exist, if: :namespace_id_changed? + after_save :ensure_storage_path_exist, if: :namespace_id_changed? acts_as_taggable diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb index 05175d51963..88821ae56e0 100644 --- a/lib/backup/repository.rb +++ b/lib/backup/repository.rb @@ -75,7 +75,7 @@ module Backup path_to_project_repo = path_to_repo(project) path_to_project_bundle = path_to_bundle(project) - project.ensure_dir_exist + project.ensure_storage_path_exist cmd = if File.exist?(path_to_project_bundle) %W(#{Gitlab.config.git.bin_path} clone --bare #{path_to_project_bundle} #{path_to_project_repo}) diff --git a/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb b/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb index 49e750a3f4d..dd634f2c024 100644 --- a/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb +++ b/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb @@ -4,7 +4,7 @@ require Rails.root.join('db', 'post_migrate', '20170502101023_cleanup_namespacel describe CleanupNamespacelessPendingDeleteProjects do before do # Stub after_save callbacks that will fail when Project has no namespace - allow_any_instance_of(Project).to receive(:ensure_dir_exist).and_return(nil) + allow_any_instance_of(Project).to receive(:ensure_storage_path_exist).and_return(nil) allow_any_instance_of(Project).to receive(:update_project_statistics).and_return(nil) end diff --git a/spec/workers/namespaceless_project_destroy_worker_spec.rb b/spec/workers/namespaceless_project_destroy_worker_spec.rb index 8533b7b85e9..f9e23d648ec 100644 --- a/spec/workers/namespaceless_project_destroy_worker_spec.rb +++ b/spec/workers/namespaceless_project_destroy_worker_spec.rb @@ -5,7 +5,7 @@ describe NamespacelessProjectDestroyWorker do before do # Stub after_save callbacks that will fail when Project has no namespace - allow_any_instance_of(Project).to receive(:ensure_dir_exist).and_return(nil) + allow_any_instance_of(Project).to receive(:ensure_storage_path_exist).and_return(nil) allow_any_instance_of(Project).to receive(:update_project_statistics).and_return(nil) end -- cgit v1.2.1 From 2c2609620356a4693ec96f988bc96cb4601be5e8 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Tue, 1 Aug 2017 07:45:04 +0200 Subject: Small refactor in LegacyNamespace and moved back send_update_instructions --- app/models/concerns/storage/legacy_namespace.rb | 11 ++--------- app/models/namespace.rb | 6 ++++++ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/app/models/concerns/storage/legacy_namespace.rb b/app/models/concerns/storage/legacy_namespace.rb index 5cbd52e5c75..5ab5c80a2f5 100644 --- a/app/models/concerns/storage/legacy_namespace.rb +++ b/app/models/concerns/storage/legacy_namespace.rb @@ -7,7 +7,7 @@ module Storage raise Gitlab::UpdatePathError.new('Namespace cannot be moved, because at least one project has tags in container registry') end - # Move the namespace directory in all storages paths used by member projects + # Move the namespace directory in all storage paths used by member projects repository_storage_paths.each do |repository_storage_path| # Ensure old directory exists before moving it gitlab_shell.add_namespace(repository_storage_path, full_path_was) @@ -49,12 +49,6 @@ module Storage private - def send_update_instructions - projects.each do |project| - project.send_move_instructions("#{full_path_was}/#{project.path}") - end - end - def old_repository_storage_paths @old_repository_storage_paths ||= repository_storage_paths end @@ -76,8 +70,7 @@ module Storage new_path = "#{full_path}+#{id}+deleted" if gitlab_shell.mv_namespace(repository_storage_path, full_path, new_path) - message = "Namespace directory \"#{full_path}\" moved to \"#{new_path}\"" - Gitlab::AppLogger.info message + Gitlab::AppLogger.info %Q(Namespace directory "#{full_path}" moved to "#{new_path}") # Remove namespace directroy async with delay so # GitLab has time to remove all projects first diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 010c97c507e..6073fb94a3f 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -124,6 +124,12 @@ class Namespace < ActiveRecord::Base all_projects.any?(&:has_container_registry_tags?) end + def send_update_instructions + projects.each do |project| + project.send_move_instructions("#{full_path_was}/#{project.path}") + end + end + def kind type == 'Group' ? 'group' : 'user' end -- cgit v1.2.1 From 0d35b0818026e9a2528b44f9e72af76b98f1a162 Mon Sep 17 00:00:00 2001 From: "Lin Jen-Shin (godfat)" Date: Tue, 1 Aug 2017 07:46:13 +0000 Subject: Allow logged in users to read user list under public restriction --- app/policies/global_policy.rb | 2 +- ...5697-allow-logged-in-user-to-read-user-list.yml | 4 +++ spec/requests/api/users_spec.rb | 40 +++++++++++++--------- 3 files changed, 28 insertions(+), 18 deletions(-) create mode 100644 changelogs/unreleased/35697-allow-logged-in-user-to-read-user-list.yml diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb index 1c91425f589..1be7bbe9953 100644 --- a/app/policies/global_policy.rb +++ b/app/policies/global_policy.rb @@ -44,7 +44,7 @@ class GlobalPolicy < BasePolicy prevent :log_in end - rule { admin | ~restricted_public_level }.policy do + rule { ~(anonymous & restricted_public_level) }.policy do enable :read_users_list end end diff --git a/changelogs/unreleased/35697-allow-logged-in-user-to-read-user-list.yml b/changelogs/unreleased/35697-allow-logged-in-user-to-read-user-list.yml new file mode 100644 index 00000000000..54b2e71bef9 --- /dev/null +++ b/changelogs/unreleased/35697-allow-logged-in-user-to-read-user-list.yml @@ -0,0 +1,4 @@ +--- +title: Allow any logged in users to read_users_list even if it's restricted +merge_request: 13201 +author: diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 66b165b438b..2dc7be22f8f 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -16,38 +16,44 @@ describe API::Users do it "returns authorization error when the `username` parameter is not passed" do get api("/users") - expect(response).to have_http_status(403) + expect(response).to have_gitlab_http_status(403) end it "returns the user when a valid `username` parameter is passed" do - user = create(:user) - get api("/users"), username: user.username - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.size).to eq(1) expect(json_response[0]['id']).to eq(user.id) expect(json_response[0]['username']).to eq(user.username) end - it "returns authorization error when the `username` parameter refers to an inaccessible user" do - user = create(:user) - - stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) - - get api("/users"), username: user.username - - expect(response).to have_http_status(403) - end - it "returns an empty response when an invalid `username` parameter is passed" do get api("/users"), username: 'invalid' - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.size).to eq(0) end + + context "when public level is restricted" do + before do + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + end + + it "returns authorization error when the `username` parameter refers to an inaccessible user" do + get api("/users"), username: user.username + + expect(response).to have_gitlab_http_status(403) + end + + it "returns authorization error when the `username` parameter is not passed" do + get api("/users") + + expect(response).to have_gitlab_http_status(403) + end + end end context "when authenticated" do @@ -58,10 +64,10 @@ describe API::Users do end context 'when authenticate as a regular user' do - it "renders 403" do + it "renders 200" do get api("/users", user) - expect(response).to have_gitlab_http_status(403) + expect(response).to have_gitlab_http_status(200) end end -- cgit v1.2.1 From d608aa5846a65edc133deeef886af111a9f580e1 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Tue, 1 Aug 2017 17:42:05 +0900 Subject: fix --- spec/services/ci/pipeline_trigger_service_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb index 945a2fe1a6b..e9188a83b89 100644 --- a/spec/services/ci/pipeline_trigger_service_spec.rb +++ b/spec/services/ci/pipeline_trigger_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::PipelineTriggerService, services: true do +describe Ci::PipelineTriggerService do let(:project) { create(:project, :repository) } before do -- cgit v1.2.1 From e99564568b2fefab8973ce571594aaa888cf8494 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 31 Jul 2017 15:17:14 +0200 Subject: CI fixes for gitaly-ruby --- .gitlab-ci.yml | 3 +++ lib/tasks/gitlab/gitaly.rake | 12 +++++++++--- scripts/gitaly-test-build | 10 ++++++++++ scripts/gitaly-test-spawn | 7 +++++++ spec/support/test_env.rb | 11 +++++++---- spec/tasks/gitlab/gitaly_rake_spec.rb | 18 ++++++++++++++---- 6 files changed, 50 insertions(+), 11 deletions(-) create mode 100755 scripts/gitaly-test-build create mode 100755 scripts/gitaly-test-spawn diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index adde3400107..27fdf6ca0b5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -96,6 +96,7 @@ stages: - export KNAPSACK_GENERATE_REPORT=true - export CACHE_CLASSES=true - cp ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH} + - scripts/gitaly-test-spawn - knapsack rspec "--color --format documentation" artifacts: expire_in: 31d @@ -221,6 +222,7 @@ setup-test-env: - bundle exec rake gettext:po_to_json - bundle exec rake gitlab:assets:compile - bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init' + - scripts/gitaly-test-build # Do not use 'bundle exec' here artifacts: expire_in: 7d paths: @@ -486,6 +488,7 @@ karma: BABEL_ENV: "coverage" CHROME_LOG_FILE: "chrome_debug.log" script: + - scripts/gitaly-test-spawn - bundle exec rake gettext:po_to_json - bundle exec rake karma coverage: '/^Statements *: (\d+\.\d+%)/' diff --git a/lib/tasks/gitlab/gitaly.rake b/lib/tasks/gitlab/gitaly.rake index 9df07ea8d83..680e76af471 100644 --- a/lib/tasks/gitlab/gitaly.rake +++ b/lib/tasks/gitlab/gitaly.rake @@ -19,7 +19,10 @@ namespace :gitlab do Dir.chdir(args.dir) do create_gitaly_configuration - Bundler.with_original_env { run_command!([command]) } + # In CI we run scripts/gitaly-test-build instead of this command + unless ENV['CI'].present? + Bundler.with_original_env { run_command!(%w[/usr/bin/env -u BUNDLE_GEMFILE] + [command]) } + end end end @@ -30,7 +33,9 @@ namespace :gitlab do puts "# Gitaly storage configuration generated from #{Gitlab.config.source} on #{Time.current.to_s(:long)}" puts "# This is in TOML format suitable for use in Gitaly's config.toml file." - puts gitaly_configuration_toml + # Exclude gitaly-ruby configuration because that depends on the gitaly + # installation directory. + puts gitaly_configuration_toml(gitaly_ruby: false) end private @@ -41,7 +46,7 @@ namespace :gitlab do # only generate a configuration for the most common and simplest case: when # we have exactly one Gitaly process and we are sure it is running locally # because it uses a Unix socket. - def gitaly_configuration_toml + def gitaly_configuration_toml(gitaly_ruby: true) storages = [] address = nil @@ -60,6 +65,7 @@ namespace :gitlab do end config = { socket_path: address.sub(%r{\Aunix:}, ''), storage: storages } config[:auth] = { token: 'secret' } if Rails.env.test? + config[:'gitaly-ruby'] = { dir: File.join(Dir.pwd, 'ruby') } if gitaly_ruby TOML.dump(config) end diff --git a/scripts/gitaly-test-build b/scripts/gitaly-test-build new file mode 100755 index 00000000000..44d314009e2 --- /dev/null +++ b/scripts/gitaly-test-build @@ -0,0 +1,10 @@ +#!/usr/bin/env ruby + +# This script assumes tmp/tests/gitaly already contains the correct +# Gitaly version. We just have to compile it and run its 'bundle +# install'. We have this separate script for that because weird things +# were happening in CI when we have a 'bundle exec' process that later +# called 'bundle install' using a different Gemfile, as happens with +# gitlab-ce and gitaly. + +abort 'gitaly build failed' unless system('make', chdir: 'tmp/tests/gitaly') diff --git a/scripts/gitaly-test-spawn b/scripts/gitaly-test-spawn new file mode 100755 index 00000000000..dd603eec7f6 --- /dev/null +++ b/scripts/gitaly-test-spawn @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby + +gitaly_dir = 'tmp/tests/gitaly' +args = %W[#{gitaly_dir}/gitaly #{gitaly_dir}/config.toml] + +# Print the PID of the spawned process +puts spawn(*args, [:out, :err] => 'log/gitaly-test.log') diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 86f9568c12e..f0603dfadde 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -144,10 +144,13 @@ module TestEnv end def start_gitaly(gitaly_dir) - gitaly_exec = File.join(gitaly_dir, 'gitaly') - gitaly_config = File.join(gitaly_dir, 'config.toml') - log_file = Rails.root.join('log/gitaly-test.log').to_s - @gitaly_pid = Bundler.with_original_env { spawn(gitaly_exec, gitaly_config, [:out, :err] => log_file) } + if ENV['CI'].present? + # Gitaly has been spawned outside this process already + return + end + + spawn_script = Rails.root.join('scripts/gitaly-test-spawn').to_s + @gitaly_pid = Bundler.with_original_env { IO.popen([spawn_script], &:read).to_i } end def stop_gitaly diff --git a/spec/tasks/gitlab/gitaly_rake_spec.rb b/spec/tasks/gitlab/gitaly_rake_spec.rb index d42d2423f15..695231c7d15 100644 --- a/spec/tasks/gitlab/gitaly_rake_spec.rb +++ b/spec/tasks/gitlab/gitaly_rake_spec.rb @@ -41,6 +41,16 @@ describe 'gitlab:gitaly namespace rake task' do end describe 'gmake/make' do + let(:command_preamble) { %w[/usr/bin/env -u BUNDLE_GEMFILE] } + + before(:all) do + @old_env_ci = ENV.delete('CI') + end + + after(:all) do + ENV['CI'] = @old_env_ci if @old_env_ci + end + before do FileUtils.mkdir_p(clone_path) expect(Dir).to receive(:chdir).with(clone_path).and_call_original @@ -49,12 +59,12 @@ describe 'gitlab:gitaly namespace rake task' do context 'gmake is available' do before do expect_any_instance_of(Object).to receive(:checkout_or_clone_version) - allow_any_instance_of(Object).to receive(:run_command!).with(['gmake']).and_return(true) + allow_any_instance_of(Object).to receive(:run_command!).with(command_preamble + ['gmake']).and_return(true) end it 'calls gmake in the gitaly directory' do expect(Gitlab::Popen).to receive(:popen).with(%w[which gmake]).and_return(['/usr/bin/gmake', 0]) - expect_any_instance_of(Object).to receive(:run_command!).with(['gmake']).and_return(true) + expect_any_instance_of(Object).to receive(:run_command!).with(command_preamble + ['gmake']).and_return(true) run_rake_task('gitlab:gitaly:install', clone_path) end @@ -63,12 +73,12 @@ describe 'gitlab:gitaly namespace rake task' do context 'gmake is not available' do before do expect_any_instance_of(Object).to receive(:checkout_or_clone_version) - allow_any_instance_of(Object).to receive(:run_command!).with(['make']).and_return(true) + allow_any_instance_of(Object).to receive(:run_command!).with(command_preamble + ['make']).and_return(true) end it 'calls make in the gitaly directory' do expect(Gitlab::Popen).to receive(:popen).with(%w[which gmake]).and_return(['', 42]) - expect_any_instance_of(Object).to receive(:run_command!).with(['make']).and_return(true) + expect_any_instance_of(Object).to receive(:run_command!).with(command_preamble + ['make']).and_return(true) run_rake_task('gitlab:gitaly:install', clone_path) end -- cgit v1.2.1 From 67de82cf5fa5a6408621cbf955c730e2825d9c39 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 31 Jul 2017 15:23:05 +0200 Subject: Add option to use CommitLanguages RPC --- GITALY_SERVER_VERSION | 2 +- app/controllers/projects/graphs_controller.rb | 18 +--------- lib/gitlab/git/repository.rb | 27 +++++++++++++++ lib/gitlab/gitaly_client/commit_service.rb | 7 ++++ .../controllers/projects/graphs_controller_spec.rb | 33 ------------------ spec/lib/gitlab/git/repository_spec.rb | 39 ++++++++++++++++++++++ 6 files changed, 75 insertions(+), 51 deletions(-) diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index d21d277be51..4e8f395fa5e 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -0.25.0 +0.26.0 diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb index 57372f9e79d..475d4c86294 100644 --- a/app/controllers/projects/graphs_controller.rb +++ b/app/controllers/projects/graphs_controller.rb @@ -43,23 +43,7 @@ class Projects::GraphsController < Projects::ApplicationController end def get_languages - @languages = Linguist::Repository.new(@repository.rugged, @repository.rugged.head.target_id).languages - total = @languages.map(&:last).sum - - @languages = @languages.map do |language| - name, share = language - color = Linguist::Language[name].color || "##{Digest::SHA256.hexdigest(name)[0...6]}" - { - value: (share.to_f * 100 / total).round(2), - label: name, - color: color, - highlight: color - } - end - - @languages.sort! do |x, y| - y[:value] <=> x[:value] - end + @languages = @project.repository.languages end def fetch_graph diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index a3bc79109f8..88529ba2c47 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -636,6 +636,33 @@ module Gitlab @attributes.attributes(path) end + def languages(ref = nil) + Gitlab::GitalyClient.migrate(:commit_languages) do |is_enabled| + if is_enabled + gitaly_commit_client.languages(ref) + else + ref ||= rugged.head.target_id + languages = Linguist::Repository.new(rugged, ref).languages + total = languages.map(&:last).sum + + languages = languages.map do |language| + name, share = language + color = Linguist::Language[name].color || "##{Digest::SHA256.hexdigest(name)[0...6]}" + { + value: (share.to_f * 100 / total).round(2), + label: name, + color: color, + highlight: color + } + end + + languages.sort do |x, y| + y[:value] <=> x[:value] + end + end + end + end + def gitaly_repository Gitlab::GitalyClient::Util.repository(@storage, @relative_path) end diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb index c6e52b530b3..a834781b1f1 100644 --- a/lib/gitlab/gitaly_client/commit_service.rb +++ b/lib/gitlab/gitaly_client/commit_service.rb @@ -118,6 +118,13 @@ module Gitlab consume_commits_response(response) end + def languages(ref = nil) + request = Gitaly::CommitLanguagesRequest.new(repository: @gitaly_repo, revision: ref || '') + response = GitalyClient.call(@repository.storage, :commit_service, :commit_languages, request) + + response.languages.map { |l| { value: l.share.round(2), label: l.name, color: l.color, highlight: l.color } } + end + private def commit_diff_request_params(commit, options = {}) diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb index e0de62e4454..5af03ae118c 100644 --- a/spec/controllers/projects/graphs_controller_spec.rb +++ b/spec/controllers/projects/graphs_controller_spec.rb @@ -24,37 +24,4 @@ describe Projects::GraphsController do expect(response).to redirect_to action: :charts end end - - describe 'GET charts' do - let(:linguist_repository) do - double(languages: { - 'Ruby' => 1000, - 'CoffeeScript' => 350, - 'NSIS' => 15 - }) - end - - let(:expected_values) do - nsis_color = "##{Digest::SHA256.hexdigest('NSIS')[0...6]}" - [ - # colors from Linguist: - { label: "Ruby", color: "#701516", highlight: "#701516" }, - { label: "CoffeeScript", color: "#244776", highlight: "#244776" }, - # colors from SHA256 fallback: - { label: "NSIS", color: nsis_color, highlight: nsis_color } - ] - end - - before do - allow(Linguist::Repository).to receive(:new).and_return(linguist_repository) - end - - it 'sets the correct colour according to language' do - get(:charts, namespace_id: project.namespace, project_id: project, id: 'master') - - expected_values.each do |val| - expect(assigns(:languages)).to include(a_hash_including(val)) - end - end - end end diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 50736d353ad..8e4a1f31ced 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -1127,6 +1127,45 @@ describe Gitlab::Git::Repository, seed_helper: true do end end + describe '#languages' do + shared_examples 'languages' do + it 'returns exactly the expected results' do + languages = repository.languages('4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6') + expected_languages = [ + { value: 66.63, label: "Ruby", color: "#701516", highlight: "#701516" }, + { value: 22.96, label: "JavaScript", color: "#f1e05a", highlight: "#f1e05a" }, + { value: 7.9, label: "HTML", color: "#e44b23", highlight: "#e44b23" }, + { value: 2.51, label: "CoffeeScript", color: "#244776", highlight: "#244776" } + ] + + expect(languages.size).to eq(expected_languages.size) + + expected_languages.size.times do |i| + a = expected_languages[i] + b = languages[i] + + expect(a.keys.sort).to eq(b.keys.sort) + expect(a[:value]).to be_within(0.1).of(b[:value]) + + non_float_keys = a.keys - [:value] + expect(a.values_at(*non_float_keys)).to eq(b.values_at(*non_float_keys)) + end + end + + it "uses the repository's HEAD when no ref is passed" do + lang = repository.languages.first + + expect(lang[:label]).to eq('Ruby') + end + end + + it_behaves_like 'languages' + + context 'with rugged', skip_gitaly_mock: true do + it_behaves_like 'languages' + end + end + def create_remote_branch(repository, remote_name, branch_name, source_branch_name) source_branch = repository.branches.find { |branch| branch.name == source_branch_name } rugged = repository.rugged -- cgit v1.2.1 From 423d31a300370c9c0acd9e8faae4d7bda2ac7d61 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Tue, 1 Aug 2017 08:50:59 +0000 Subject: Inline script cleanup globals and easy --- app/assets/javascripts/blob_edit/blob_bundle.js | 5 + app/assets/javascripts/dispatcher.js | 33 ++++- app/assets/javascripts/graphs/graphs_bundle.js | 2 - app/assets/javascripts/graphs/graphs_charts.js | 63 ++++++++ app/assets/javascripts/graphs/graphs_show.js | 21 +++ app/assets/javascripts/two_factor_auth.js | 13 ++ app/assets/javascripts/ui_development_kit.js | 22 +++ app/views/help/ui.html.haml | 25 +--- app/views/layouts/_google_analytics.html.haml | 1 + app/views/layouts/_init_auto_complete.html.haml | 1 + app/views/layouts/_piwik.html.haml | 1 + app/views/layouts/project.html.haml | 1 + app/views/layouts/snippets.html.haml | 1 + .../personal_access_tokens/index.html.haml | 8 +- app/views/profiles/two_factor_auths/show.html.haml | 163 ++++++++++----------- app/views/projects/_activity.html.haml | 6 - app/views/projects/blob/_new_dir.html.haml | 3 - app/views/projects/blob/_remove.html.haml | 3 - app/views/projects/branches/new.html.haml | 6 +- app/views/projects/commit/_commit_box.html.haml | 5 +- app/views/projects/commits/show.html.haml | 52 ++++--- app/views/projects/find_file/show.html.haml | 10 +- app/views/projects/graphs/charts.html.haml | 64 ++------ app/views/projects/graphs/show.html.haml | 28 +--- app/views/projects/imports/show.html.haml | 2 - app/views/u2f/_register.html.haml | 4 - config/webpack.config.js | 5 + spec/features/commits_spec.rb | 4 +- 28 files changed, 290 insertions(+), 262 deletions(-) create mode 100644 app/assets/javascripts/graphs/graphs_charts.js create mode 100644 app/assets/javascripts/graphs/graphs_show.js create mode 100644 app/assets/javascripts/two_factor_auth.js create mode 100644 app/assets/javascripts/ui_development_kit.js diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js index 1c64ccf536f..b5500ac116f 100644 --- a/app/assets/javascripts/blob_edit/blob_bundle.js +++ b/app/assets/javascripts/blob_edit/blob_bundle.js @@ -8,6 +8,7 @@ import BlobFileDropzone from '../blob/blob_file_dropzone'; $(() => { const editBlobForm = $('.js-edit-blob-form'); const uploadBlobForm = $('.js-upload-blob-form'); + const deleteBlobForm = $('.js-delete-blob-form'); if (editBlobForm.length) { const urlRoot = editBlobForm.data('relative-url-root'); @@ -30,4 +31,8 @@ $(() => { '.btn-upload-file', ); } + + if (deleteBlobForm.length) { + new NewCommitForm(deleteBlobForm); + } }); diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index d5923266c60..a2664c0301e 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -8,6 +8,7 @@ /* global LabelsSelect */ /* global MilestoneSelect */ /* global Commit */ +/* global CommitsList */ /* global NewBranchForm */ /* global NotificationsForm */ /* global NotificationsDropdown */ @@ -19,15 +20,20 @@ /* global Search */ /* global Admin */ /* global NamespaceSelects */ +/* global NewCommitForm */ +/* global NewBranchForm */ /* global Project */ /* global ProjectAvatar */ /* global MergeRequest */ /* global Compare */ /* global CompareAutocomplete */ +/* global ProjectFindFile */ /* global ProjectNew */ /* global ProjectShow */ +/* global ProjectImport */ /* global Labels */ /* global Shortcuts */ +/* global ShortcutsFindFile */ /* global Sidebar */ /* global ShortcutsWiki */ @@ -195,7 +201,6 @@ import GpgBadges from './gpg_badges'; break; case 'explore:groups:index': new GroupsList(); - const landingElement = document.querySelector('.js-explore-groups-landing'); if (!landingElement) break; const exploreGroupsLanding = new Landing( @@ -218,6 +223,10 @@ import GpgBadges from './gpg_badges'; case 'projects:compare:show': new gl.Diff(); break; + case 'projects:branches:new': + case 'projects:branches:create': + new NewBranchForm($('.js-create-branch-form'), JSON.parse(document.getElementById('availableRefs').innerHTML)); + break; case 'projects:branches:index': gl.AjaxLoadingSpinner.init(); new DeleteModal(); @@ -305,18 +314,23 @@ import GpgBadges from './gpg_badges'; container: '.js-commit-pipeline-graph', }).bindEvents(); initNotes(); + $('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath); break; case 'projects:commit:pipelines': new MiniPipelineGraph({ container: '.js-commit-pipeline-graph', }).bindEvents(); + $('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath); break; - case 'projects:commits:show': + case 'projects:activity': + new gl.Activities(); shortcut_handler = new ShortcutsNavigation(); - GpgBadges.fetch(); break; - case 'projects:activity': + case 'projects:commits:show': + CommitsList.init(document.querySelector('.js-project-commits-show').dataset.commitsLimit); + new gl.Activities(); shortcut_handler = new ShortcutsNavigation(); + GpgBadges.fetch(); break; case 'projects:show': shortcut_handler = new ShortcutsNavigation(); @@ -331,6 +345,9 @@ import GpgBadges from './gpg_badges'; case 'projects:edit': setupProjectEdit(); break; + case 'projects:imports:show': + new ProjectImport(); + break; case 'projects:pipelines:new': new NewBranchForm($('.js-new-pipeline-form')); break; @@ -387,11 +404,19 @@ import GpgBadges from './gpg_badges'; shortcut_handler = new ShortcutsNavigation(); new TreeView(); new BlobViewer(); + new NewCommitForm($('.js-create-dir-form')); $('#tree-slider').waitForImages(function() { gl.utils.ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath); }); break; case 'projects:find_file:show': + const findElement = document.querySelector('.js-file-finder'); + const projectFindFile = new ProjectFindFile($(".file-finder-holder"), { + url: findElement.dataset.fileFindUrl, + treeUrl: findElement.dataset.findTreeUrl, + blobUrlTemplate: findElement.dataset.blobUrlTemplate, + }); + new ShortcutsFindFile(projectFindFile); shortcut_handler = true; break; case 'projects:blob:show': diff --git a/app/assets/javascripts/graphs/graphs_bundle.js b/app/assets/javascripts/graphs/graphs_bundle.js index a433c7ba8f0..534bc535bb6 100644 --- a/app/assets/javascripts/graphs/graphs_bundle.js +++ b/app/assets/javascripts/graphs/graphs_bundle.js @@ -1,6 +1,4 @@ import Chart from 'vendor/Chart'; -import ContributorsStatGraph from './stat_graph_contributors'; // export to global scope window.Chart = Chart; -window.ContributorsStatGraph = ContributorsStatGraph; diff --git a/app/assets/javascripts/graphs/graphs_charts.js b/app/assets/javascripts/graphs/graphs_charts.js new file mode 100644 index 00000000000..279ffef770f --- /dev/null +++ b/app/assets/javascripts/graphs/graphs_charts.js @@ -0,0 +1,63 @@ +import Chart from 'vendor/Chart'; + +document.addEventListener('DOMContentLoaded', () => { + const projectChartData = JSON.parse(document.getElementById('projectChartData').innerHTML); + + const responsiveChart = (selector, data) => { + const options = { + scaleOverlay: true, + responsive: true, + pointHitDetectionRadius: 2, + maintainAspectRatio: false, + }; + // get selector by context + const ctx = selector.get(0).getContext('2d'); + // pointing parent container to make chart.js inherit its width + const container = $(selector).parent(); + const generateChart = () => { + selector.attr('width', $(container).width()); + if (window.innerWidth < 768) { + // Scale fonts if window width lower than 768px (iPad portrait) + options.scaleFontSize = 8; + } + return new Chart(ctx).Bar(data, options); + }; + // enabling auto-resizing + $(window).resize(generateChart); + return generateChart(); + }; + + const chartData = (keys, values) => { + const data = { + labels: keys, + datasets: [{ + fillColor: 'rgba(220,220,220,0.5)', + strokeColor: 'rgba(220,220,220,1)', + barStrokeWidth: 1, + barValueSpacing: 1, + barDatasetSpacing: 1, + data: values, + }], + }; + return data; + }; + + const hourData = chartData(projectChartData.hour.keys, projectChartData.hour.values); + responsiveChart($('#hour-chart'), hourData); + + const dayData = chartData(projectChartData.weekDays.keys, projectChartData.weekDays.values); + responsiveChart($('#weekday-chart'), dayData); + + const monthData = chartData(projectChartData.month.keys, projectChartData.month.values); + responsiveChart($('#month-chart'), monthData); + + const data = projectChartData.languages; + const ctx = $('#languages-chart').get(0).getContext('2d'); + const options = { + scaleOverlay: true, + responsive: true, + maintainAspectRatio: false, + }; + + new Chart(ctx).Pie(data, options); +}); diff --git a/app/assets/javascripts/graphs/graphs_show.js b/app/assets/javascripts/graphs/graphs_show.js new file mode 100644 index 00000000000..36bad6db3e1 --- /dev/null +++ b/app/assets/javascripts/graphs/graphs_show.js @@ -0,0 +1,21 @@ +import ContributorsStatGraph from './stat_graph_contributors'; + +document.addEventListener('DOMContentLoaded', () => { + $.ajax({ + type: 'GET', + url: document.querySelector('.js-graphs-show').dataset.projectGraphPath, + dataType: 'json', + success(data) { + const graph = new ContributorsStatGraph(); + graph.init(data); + + $('#brush_change').change(() => { + graph.change_date_header(); + graph.redraw_authors(); + }); + + $('.stat-graph').fadeIn(); + $('.loading-graph').hide(); + }, + }); +}); diff --git a/app/assets/javascripts/two_factor_auth.js b/app/assets/javascripts/two_factor_auth.js new file mode 100644 index 00000000000..d26f61562a5 --- /dev/null +++ b/app/assets/javascripts/two_factor_auth.js @@ -0,0 +1,13 @@ +/* global U2FRegister */ +document.addEventListener('DOMContentLoaded', () => { + const twoFactorNode = document.querySelector('.js-two-factor-auth'); + const skippable = twoFactorNode.dataset.twoFactorSkippable === 'true'; + if (skippable) { + const button = `Configure it later`; + const flashAlert = document.querySelector('.flash-alert .container-fluid'); + if (flashAlert) flashAlert.insertAdjacentHTML('beforeend', button); + } + + const u2fRegister = new U2FRegister($('#js-register-u2f'), gon.u2f); + u2fRegister.start(); +}); diff --git a/app/assets/javascripts/ui_development_kit.js b/app/assets/javascripts/ui_development_kit.js new file mode 100644 index 00000000000..f503076715c --- /dev/null +++ b/app/assets/javascripts/ui_development_kit.js @@ -0,0 +1,22 @@ +import Api from './api'; + +document.addEventListener('DOMContentLoaded', () => { + $('#js-project-dropdown').glDropdown({ + data: (term, callback) => { + Api.projects(term, { + order_by: 'last_activity_at', + }, (data) => { + callback(data); + }); + }, + text: project => (project.name_with_namespace || project.name), + selectable: true, + fieldName: 'author_id', + filterable: true, + search: { + fields: ['name_with_namespace'], + }, + id: data => data.id, + isSelected: data => (data.id === 2), + }); +}); diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml index 48edbb8c16f..f18c3a74120 100644 --- a/app/views/help/ui.html.haml +++ b/app/views/help/ui.html.haml @@ -1,5 +1,7 @@ - page_title "UI Development Kit", "Help" - lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed fermentum nisi sapien, non consequat lectus aliquam ultrices. Suspendisse sodales est euismod nunc condimentum, a consectetur diam ornare." +- content_for :page_specific_javascripts do + = webpack_bundle_tag('ui_development_kit') .gitlab-ui-dev-kit %h1 GitLab UI development kit @@ -407,29 +409,6 @@ .dropdown-content .dropdown-loading = icon('spinner spin') - :javascript - $('#js-project-dropdown').glDropdown({ - data: function (term, callback) { - Api.projects(term, { order_by: 'last_activity_at' }, function (data) { - callback(data); - }); - }, - text: function (project) { - return project.name_with_namespace || project.name; - }, - selectable: true, - fieldName: "author_id", - filterable: true, - search: { - fields: ['name_with_namespace'] - }, - id: function (data) { - return data.id; - }, - isSelected: function (data) { - return data.id === 2; - } - }) .example %div diff --git a/app/views/layouts/_google_analytics.html.haml b/app/views/layouts/_google_analytics.html.haml index 81e03c7eff2..98ea96b0b77 100644 --- a/app/views/layouts/_google_analytics.html.haml +++ b/app/views/layouts/_google_analytics.html.haml @@ -1,3 +1,4 @@ +-# haml-lint:disable InlineJavaScript :javascript var _gaq = _gaq || []; _gaq.push(['_setAccount', '#{extra_config.google_analytics_id}']); diff --git a/app/views/layouts/_init_auto_complete.html.haml b/app/views/layouts/_init_auto_complete.html.haml index 4bb0dfc73fd..9704c9ec624 100644 --- a/app/views/layouts/_init_auto_complete.html.haml +++ b/app/views/layouts/_init_auto_complete.html.haml @@ -2,6 +2,7 @@ - noteable_type = @noteable.class if @noteable.present? - if project + -# haml-lint:disable InlineJavaScript :javascript gl.GfmAutoComplete = gl.GfmAutoComplete || {}; gl.GfmAutoComplete.dataSources = { diff --git a/app/views/layouts/_piwik.html.haml b/app/views/layouts/_piwik.html.haml index 259b4f7cdfc..a888e8ae187 100644 --- a/app/views/layouts/_piwik.html.haml +++ b/app/views/layouts/_piwik.html.haml @@ -1,4 +1,5 @@ +-# haml-lint:disable InlineJavaScript :javascript var _paq = _paq || []; _paq.push(['trackPageView']); diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml index 99adb83cd1f..54d56e9b873 100644 --- a/app/views/layouts/project.html.haml +++ b/app/views/layouts/project.html.haml @@ -10,6 +10,7 @@ - content_for :project_javascripts do - project = @target_project || @project - if current_user + -# haml-lint:disable InlineJavaScript :javascript window.uploads_path = "#{project_uploads_path(project)}"; diff --git a/app/views/layouts/snippets.html.haml b/app/views/layouts/snippets.html.haml index 57971205e0e..849075a0ba5 100644 --- a/app/views/layouts/snippets.html.haml +++ b/app/views/layouts/snippets.html.haml @@ -2,6 +2,7 @@ - content_for :page_specific_javascripts do - if @snippet && current_user + -# haml-lint:disable InlineJavaScript :javascript window.uploads_path = "#{upload_path('personal_snippet', id: @snippet.id)}"; diff --git a/app/views/profiles/personal_access_tokens/index.html.haml b/app/views/profiles/personal_access_tokens/index.html.haml index cf750378e25..2216708d354 100644 --- a/app/views/profiles/personal_access_tokens/index.html.haml +++ b/app/views/profiles/personal_access_tokens/index.html.haml @@ -1,5 +1,6 @@ - page_title "Personal Access Tokens" - @content_class = "limit-container-width" unless fluid_layout + = render 'profiles/head' .row.prepend-top-default @@ -19,7 +20,7 @@ %h5.prepend-top-0 Your New Personal Access Token .form-group - = text_field_tag 'created-personal-access-token', flash[:personal_access_token], readonly: true, class: "form-control", 'aria-describedby' => "created-personal-access-token-help-block" + = text_field_tag 'created-personal-access-token', flash[:personal_access_token], readonly: true, class: "form-control js-select-on-focus", 'aria-describedby' => "created-personal-access-token-help-block" = clipboard_button(text: flash[:personal_access_token], title: "Copy personal access token to clipboard", placement: "left") %span#created-personal-access-token-help-block.help-block.text-danger Make sure you save it - you won't be able to access it again. @@ -28,8 +29,3 @@ = render "shared/personal_access_tokens_form", path: profile_personal_access_tokens_path, impersonation: false, token: @personal_access_token, scopes: @scopes = render "shared/personal_access_tokens_table", impersonation: false, active_tokens: @active_personal_access_tokens, inactive_tokens: @inactive_personal_access_tokens - -:javascript - $("#created-personal-access-token").click(function() { - this.select(); - }); diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml index 037cb30efb9..33e062c1c9c 100644 --- a/app/views/profiles/two_factor_auths/show.html.haml +++ b/app/views/profiles/two_factor_auths/show.html.haml @@ -7,97 +7,92 @@ = render 'profiles/head' -- if inject_u2f_api? - - content_for :page_specific_javascripts do +- content_for :page_specific_javascripts do + - if inject_u2f_api? = page_specific_javascript_bundle_tag('u2f') + = page_specific_javascript_bundle_tag('two_factor_auth') -.row.prepend-top-default - .col-lg-4 - %h4.prepend-top-0 - Register Two-Factor Authentication App - %p - Use an app on your mobile device to enable two-factor authentication (2FA). - .col-lg-8 - - if current_user.two_factor_otp_enabled? - = icon "check inverse", base: "circle", class: "text-success", text: "You've already enabled two-factor authentication using mobile authenticator applications. You can disable it from your account settings page." - - else +.js-two-factor-auth{ 'data-two-factor-skippable' => "#{two_factor_skippable?}", 'data-two_factor_skip_url' => skip_profile_two_factor_auth_path } + .row.prepend-top-default + .col-lg-4 + %h4.prepend-top-0 + Register Two-Factor Authentication App %p - Download the Google Authenticator application from App Store or Google Play Store and scan this code. - More information is available in the #{link_to('documentation', help_page_path('profile/two_factor_authentication'))}. - .row.append-bottom-10 - .col-md-4 - = raw @qr_code - .col-md-8 - .account-well - %p.prepend-top-0.append-bottom-0 - Can't scan the code? - %p.prepend-top-0.append-bottom-0 - To add the entry manually, provide the following details to the application on your phone. - %p.prepend-top-0.append-bottom-0 - Account: - = @account_string - %p.prepend-top-0.append-bottom-0 - Key: - = current_user.otp_secret.scan(/.{4}/).join(' ') - %p.two-factor-new-manual-content - Time based: Yes - = form_tag profile_two_factor_auth_path, method: :post do |f| - - if @error - .alert.alert-danger - = @error - .form-group - = label_tag :pin_code, nil, class: "label-light" - = text_field_tag :pin_code, nil, class: "form-control", required: true - .prepend-top-default - = submit_tag 'Register with two-factor app', class: 'btn btn-success' + Use an app on your mobile device to enable two-factor authentication (2FA). + .col-lg-8 + - if current_user.two_factor_otp_enabled? + = icon "check inverse", base: "circle", class: "text-success", text: "You've already enabled two-factor authentication using mobile authenticator applications. You can disable it from your account settings page." + - else + %p + Download the Google Authenticator application from App Store or Google Play Store and scan this code. + More information is available in the #{link_to('documentation', help_page_path('profile/two_factor_authentication'))}. + .row.append-bottom-10 + .col-md-4 + = raw @qr_code + .col-md-8 + .account-well + %p.prepend-top-0.append-bottom-0 + Can't scan the code? + %p.prepend-top-0.append-bottom-0 + To add the entry manually, provide the following details to the application on your phone. + %p.prepend-top-0.append-bottom-0 + Account: + = @account_string + %p.prepend-top-0.append-bottom-0 + Key: + = current_user.otp_secret.scan(/.{4}/).join(' ') + %p.two-factor-new-manual-content + Time based: Yes + = form_tag profile_two_factor_auth_path, method: :post do |f| + - if @error + .alert.alert-danger + = @error + .form-group + = label_tag :pin_code, nil, class: "label-light" + = text_field_tag :pin_code, nil, class: "form-control", required: true + .prepend-top-default + = submit_tag 'Register with two-factor app', class: 'btn btn-success' -%hr + %hr -.row.prepend-top-default - - .col-lg-4 - %h4.prepend-top-0 - Register Universal Two-Factor (U2F) Device - %p - Use a hardware device to add the second factor of authentication. - %p - As U2F devices are only supported by a few browsers, we require that you set up a - two-factor authentication app before a U2F device. That way you'll always be able to - log in - even when you're using an unsupported browser. - .col-lg-8 - - if @u2f_registration.errors.present? - = form_errors(@u2f_registration) - = render "u2f/register" + .row.prepend-top-default + .col-lg-4 + %h4.prepend-top-0 + Register Universal Two-Factor (U2F) Device + %p + Use a hardware device to add the second factor of authentication. + %p + As U2F devices are only supported by a few browsers, we require that you set up a + two-factor authentication app before a U2F device. That way you'll always be able to + log in - even when you're using an unsupported browser. + .col-lg-8 + - if @u2f_registration.errors.present? + = form_errors(@u2f_registration) + = render "u2f/register" - %hr + %hr - %h5 U2F Devices (#{@u2f_registrations.length}) + %h5 U2F Devices (#{@u2f_registrations.length}) - - if @u2f_registrations.present? - .table-responsive - %table.table.table-bordered.u2f-registrations - %colgroup - %col{ width: "50%" } - %col{ width: "30%" } - %col{ width: "20%" } - %thead - %tr - %th Name - %th Registered On - %th - %tbody - - @u2f_registrations.each do |registration| + - if @u2f_registrations.present? + .table-responsive + %table.table.table-bordered.u2f-registrations + %colgroup + %col{ width: "50%" } + %col{ width: "30%" } + %col{ width: "20%" } + %thead %tr - %td= registration.name.presence || "" - %td= registration.created_at.to_date.to_s(:medium) - %td= link_to "Delete", profile_u2f_registration_path(registration), method: :delete, class: "btn btn-danger pull-right", data: { confirm: "Are you sure you want to delete this device? This action cannot be undone." } - - - else - .settings-message.text-center - You don't have any U2F devices registered yet. - + %th Name + %th Registered On + %th + %tbody + - @u2f_registrations.each do |registration| + %tr + %td= registration.name.presence || "" + %td= registration.created_at.to_date.to_s(:medium) + %td= link_to "Delete", profile_u2f_registration_path(registration), method: :delete, class: "btn btn-danger pull-right", data: { confirm: "Are you sure you want to delete this device? This action cannot be undone." } -- if two_factor_skippable? - :javascript - var button = "Configure it later"; - $(".flash-alert").append(button); + - else + .settings-message.text-center + You don't have any U2F devices registered yet. diff --git a/app/views/projects/_activity.html.haml b/app/views/projects/_activity.html.haml index ecc966ed453..ad63f5e73ae 100644 --- a/app/views/projects/_activity.html.haml +++ b/app/views/projects/_activity.html.haml @@ -8,9 +8,3 @@ .content_list.project-activity{ :"data-href" => activity_project_path(@project) } = spinner - -:javascript - var activity = new gl.Activities(); - $(document).on('page:restore', function (event) { - activity.reloadActivities() - }) diff --git a/app/views/projects/blob/_new_dir.html.haml b/app/views/projects/blob/_new_dir.html.haml index b2959ef6d31..03ab1bb59e4 100644 --- a/app/views/projects/blob/_new_dir.html.haml +++ b/app/views/projects/blob/_new_dir.html.haml @@ -20,6 +20,3 @@ - unless can?(current_user, :push_code, @project) .inline.prepend-left-10 = commit_in_fork_help - -:javascript - new NewCommitForm($('.js-create-dir-form')) diff --git a/app/views/projects/blob/_remove.html.haml b/app/views/projects/blob/_remove.html.haml index 6a4a657fa8c..750bdef3308 100644 --- a/app/views/projects/blob/_remove.html.haml +++ b/app/views/projects/blob/_remove.html.haml @@ -13,6 +13,3 @@ .col-sm-offset-2.col-sm-10 = button_tag 'Delete file', class: 'btn btn-remove btn-remove-file' = link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal" - -:javascript - new NewCommitForm($('.js-delete-blob-form')) diff --git a/app/views/projects/branches/new.html.haml b/app/views/projects/branches/new.html.haml index 03eefcc2b4d..2baaaf6ac5b 100644 --- a/app/views/projects/branches/new.html.haml +++ b/app/views/projects/branches/new.html.haml @@ -28,8 +28,4 @@ .form-actions = button_tag 'Create branch', class: 'btn btn-create', tabindex: 3 = link_to 'Cancel', project_branches_path(@project), class: 'btn btn-cancel' - -:javascript - var availableRefs = #{@project.repository.ref_names.to_json}; - - new NewBranchForm($('.js-create-branch-form'), availableRefs) +%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml index 419fbe99af8..09bcd187e59 100644 --- a/app/views/projects/commit/_commit_box.html.haml +++ b/app/views/projects/commit/_commit_box.html.haml @@ -1,4 +1,4 @@ -.page-content-header +.page-content-header.js-commit-box{ 'data-commit-path' => branches_project_commit_path(@project, @commit.id) } .header-main-content = render partial: 'signature', object: @commit.signature %strong @@ -79,6 +79,3 @@ = render 'shared/mini_pipeline_graph', pipeline: last_pipeline, klass: 'js-commit-pipeline-graph' in = time_interval_in_words last_pipeline.duration - -:javascript - $(".commit-info.branches").load("#{branches_project_commit_path(@project, @commit.id)}"); diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index bd2d900997e..7ae56086177 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -11,34 +11,32 @@ = content_for :sub_nav do = render "head" -%div{ class: container_class } - .tree-holder - .nav-block - .tree-ref-container - .tree-ref-holder - = render 'shared/ref_switcher', destination: 'commits' +.js-project-commits-show{ 'data-commits-limit' => @limit } + %div{ class: container_class } + .tree-holder + .nav-block + .tree-ref-container + .tree-ref-holder + = render 'shared/ref_switcher', destination: 'commits' + + %ul.breadcrumb.repo-breadcrumb + = commits_breadcrumbs + .tree-controls.hidden-xs.hidden-sm + - if @merge_request.present? + .control + = link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'btn' + - elsif create_mr_button?(@repository.root_ref, @ref) + .control + = link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' - %ul.breadcrumb.repo-breadcrumb - = commits_breadcrumbs - .tree-controls.hidden-xs.hidden-sm - - if @merge_request.present? .control - = link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'btn' - - elsif create_mr_button?(@repository.root_ref, @ref) + = form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form', data: { 'signatures-path' => namespace_project_signatures_path }) do + = search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false } .control - = link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' + = link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do + = icon("rss") - .control - = form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form', data: { 'signatures-path' => namespace_project_signatures_path }) do - = search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false } - .control - = link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do - = icon("rss") - - %div{ id: dom_id(@project) } - %ol#commits-list.list-unstyled.content_list - = render 'commits', project: @project, ref: @ref - = spinner - -:javascript - CommitsList.init(#{@limit}); + %div{ id: dom_id(@project) } + %ol#commits-list.list-unstyled.content_list + = render 'commits', project: @project, ref: @ref + = spinner diff --git a/app/views/projects/find_file/show.html.haml b/app/views/projects/find_file/show.html.haml index e3bf48ee47f..021575160ea 100644 --- a/app/views/projects/find_file/show.html.haml +++ b/app/views/projects/find_file/show.html.haml @@ -1,7 +1,7 @@ - page_title "Find File", @ref = render "projects/commits/head" -.file-finder-holder.tree-holder.clearfix +.file-finder-holder.tree-holder.clearfix.js-file-finder{ 'data-file-find-url': "#{escape_javascript(project_files_path(@project, @ref, @options.merge(format: :json)))}", 'data-find-tree-url': escape_javascript(project_tree_path(@project, @ref)), 'data-blob-url-template': escape_javascript(project_blob_path(@project, @id || @commit.id)) } .nav-block .tree-ref-holder = render 'shared/ref_switcher', destination: 'find_file', path: @path @@ -17,11 +17,3 @@ %table.table.files-slider{ class: "table_#{@hex_path} tree-table table-striped" } %tbody = spinner nil, true - -:javascript - var projectFindFile = new ProjectFindFile($(".file-finder-holder"), { - url: "#{escape_javascript(project_files_path(@project, @ref, @options.merge(format: :json)))}", - treeUrl: "#{escape_javascript(project_tree_path(@project, @ref))}", - blobUrlTemplate: "#{escape_javascript(project_blob_path(@project, @id || @commit.id))}" - }); - new ShortcutsFindFile(projectFindFile); diff --git a/app/views/projects/graphs/charts.html.haml b/app/views/projects/graphs/charts.html.haml index 249b9d82ad9..228c8c84792 100644 --- a/app/views/projects/graphs/charts.html.haml +++ b/app/views/projects/graphs/charts.html.haml @@ -3,8 +3,9 @@ - if show_new_nav? - add_to_breadcrumbs("Repository", project_tree_path(@project)) - content_for :page_specific_javascripts do - = page_specific_javascript_bundle_tag('common_d3') - = page_specific_javascript_bundle_tag('graphs') + = webpack_bundle_tag('common_d3') + = webpack_bundle_tag('graphs') + = webpack_bundle_tag('graphs_charts') = render "projects/commits/head" .repo-charts{ class: container_class } @@ -75,55 +76,10 @@ Commits per day hour (UTC) %canvas#hour-chart -:javascript - var responsiveChart = function (selector, data) { - var options = { "scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2, maintainAspectRatio: false }; - // get selector by context - var ctx = selector.get(0).getContext("2d"); - // pointing parent container to make chart.js inherit its width - var container = $(selector).parent(); - var generateChart = function() { - selector.attr('width', $(container).width()); - if (window.innerWidth < 768) { - // Scale fonts if window width lower than 768px (iPad portrait) - options.scaleFontSize = 8 - } - return new Chart(ctx).Bar(data, options); - }; - // enabling auto-resizing - $(window).resize(generateChart); - return generateChart(); - }; - - var chartData = function (keys, values) { - var data = { - labels : keys, - datasets : [{ - fillColor : "rgba(220,220,220,0.5)", - strokeColor : "rgba(220,220,220,1)", - barStrokeWidth: 1, - barValueSpacing: 1, - barDatasetSpacing: 1, - data : values - }] - }; - return data; - }; - - var hourData = chartData(#{@commits_per_time.keys.to_json}, #{@commits_per_time.values.to_json}); - responsiveChart($('#hour-chart'), hourData); - - var dayData = chartData(#{@commits_per_week_days.keys.to_json}, #{@commits_per_week_days.values.to_json}); - responsiveChart($('#weekday-chart'), dayData); - - var monthData = chartData(#{@commits_per_month.keys.to_json}, #{@commits_per_month.values.to_json}); - responsiveChart($('#month-chart'), monthData); - - var data = #{@languages.to_json}; - var ctx = $("#languages-chart").get(0).getContext("2d"); - var options = { - scaleOverlay: true, - responsive: true, - maintainAspectRatio: false - } - var myPieChart = new Chart(ctx).Pie(data, options); +%script#projectChartData{ type: "application/json" } + - projectChartData = {}; + - projectChartData['hour'] = { 'keys' => @commits_per_time.keys, 'values' => @commits_per_time.values } + - projectChartData['weekDays'] = { 'keys' => @commits_per_week_days.keys, 'values' => @commits_per_week_days.values } + - projectChartData['month'] = { 'keys' => @commits_per_month.keys, 'values' => @commits_per_month.values } + - projectChartData['languages'] = @languages + = projectChartData.to_json.html_safe diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml index 4256a8c4d7e..f41a0d8293b 100644 --- a/app/views/projects/graphs/show.html.haml +++ b/app/views/projects/graphs/show.html.haml @@ -1,15 +1,16 @@ - @no_container = true - page_title "Contributors" - content_for :page_specific_javascripts do - = page_specific_javascript_bundle_tag('common_d3') - = page_specific_javascript_bundle_tag('graphs') + = webpack_bundle_tag('common_d3') + = webpack_bundle_tag('graphs') + = webpack_bundle_tag('graphs_show') - if show_new_nav? - add_to_breadcrumbs("Repository", project_tree_path(@project)) = render 'projects/commits/head' -%div{ class: container_class } +.js-graphs-show{ class: container_class, 'data-project-graph-path': project_graph_path(@project, current_ref, format: :json) } .sub-header-block .tree-ref-holder = render 'shared/ref_switcher', destination: 'graphs' @@ -33,24 +34,3 @@ #contributors-master #contributors.clearfix %ol.contributors-list.clearfix - - - -:javascript - $.ajax({ - type: "GET", - url: "#{project_graph_path(@project, current_ref, format: :json)}", - dataType: "json", - success: function (data) { - var graph = new ContributorsStatGraph(); - graph.init(data); - - $("#brush_change").change(function(){ - graph.change_date_header(); - graph.redraw_authors(); - }); - - $(".stat-graph").fadeIn(); - $(".loading-graph").hide(); - } - }); diff --git a/app/views/projects/imports/show.html.haml b/app/views/projects/imports/show.html.haml index c52b3860636..8c490773a56 100644 --- a/app/views/projects/imports/show.html.haml +++ b/app/views/projects/imports/show.html.haml @@ -10,5 +10,3 @@ - if @project.external_import? %p.monospace git clone --bare #{@project.safe_import_url} %p Please wait while we import the repository for you. Refresh at will. - :javascript - new ProjectImport(); diff --git a/app/views/u2f/_register.html.haml b/app/views/u2f/_register.html.haml index 00788e77b6b..093b2d82813 100644 --- a/app/views/u2f/_register.html.haml +++ b/app/views/u2f/_register.html.haml @@ -37,7 +37,3 @@ .col-md-3 = hidden_field_tag 'u2f_registration[device_response]', nil, class: 'form-control', required: true, id: "js-device-response" = submit_tag "Register U2F device", class: "btn btn-success" - -:javascript - var u2fRegister = new U2FRegister($("#js-register-u2f"), gon.u2f); - u2fRegister.start(); diff --git a/config/webpack.config.js b/config/webpack.config.js index 2f85b89d523..8b0c64f9289 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -39,6 +39,8 @@ var config = { environments_folder: './environments/folder/environments_folder_bundle.js', filtered_search: './filtered_search/filtered_search_bundle.js', graphs: './graphs/graphs_bundle.js', + graphs_charts: './graphs/graphs_charts.js', + graphs_show: './graphs/graphs_show.js', group: './group.js', groups: './groups/index.js', groups_list: './groups_list.js', @@ -70,9 +72,12 @@ var config = { stl_viewer: './blob/stl_viewer.js', terminal: './terminal/terminal_bundle.js', u2f: ['vendor/u2f'], + ui_development_kit: './ui_development_kit.js', + users: './users/index.js', raven: './raven/index.js', vue_merge_request_widget: './vue_merge_request_widget/index.js', test: './test.js', + two_factor_auth: './two_factor_auth.js', performance_bar: './performance_bar.js', webpack_runtime: './webpack.js', }, diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 15ec6f20763..0c9fcc60d30 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -282,7 +282,7 @@ describe 'Commits' do end # verified and the gpg user has a gitlab profile - click_on 'Verified' + click_on 'Verified', match: :first within '.popover' do expect(page).to have_content 'This commit was signed with a verified signature.' expect(page).to have_content 'Nannie Bernhard' @@ -295,7 +295,7 @@ describe 'Commits' do visit project_commits_path(project, :'signed-commits') - click_on 'Verified' + click_on 'Verified', match: :first within '.popover' do expect(page).to have_content 'This commit was signed with a verified signature.' expect(page).to have_content 'Nannie Bernhard' -- cgit v1.2.1 From 3f2f8916dcda0988f6640200a0ed9c8827fd454d Mon Sep 17 00:00:00 2001 From: Marcia Ramos Date: Tue, 1 Aug 2017 08:58:13 +0000 Subject: Docs add blog articles --- doc/articles/index.md | 114 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 90 insertions(+), 24 deletions(-) diff --git a/doc/articles/index.md b/doc/articles/index.md index a4e41517d83..d7e662d737f 100644 --- a/doc/articles/index.md +++ b/doc/articles/index.md @@ -7,40 +7,106 @@ to provide the community with guidance on specific processes to achieve certain They are written by members of the GitLab Team and by [Community Writers](https://about.gitlab.com/handbook/product/technical-writing/community-writers/). +Part of the articles listed below link to the [GitLab Blog](https://about.gitlab.com/blog/), +where they were originally published. + ## Authentication -- **LDAP** - - [How to configure LDAP with GitLab CE](how_to_configure_ldap_gitlab_ce/index.md) - - [How to configure LDAP with GitLab EE](https://docs.gitlab.com/ee/articles/how_to_configure_ldap_gitlab_ee/) +Learn how to explore GitLab's supported [authentications methods](../topics/authentication/index.md): + +| Article title | Category | Publishing date | +| :------------ | :------: | --------------: | +| **LDAP** | +| [How to configure LDAP with GitLab CE](how_to_configure_ldap_gitlab_ce/index.md)| Admin guide | 2017/05/03 | +| [How to configure LDAP with GitLab EE](https://docs.gitlab.com/ee/articles/how_to_configure_ldap_gitlab_ee/) | Admin guide | 2017/05/03 | + +## Build, test, and deploy with GitLab CI/CD + +Build, test, and deploy the software you develop with [GitLab CI/CD](../ci/README.md): + +| Article title | Category | Publishing date | +| :------------ | :------: | --------------: | +| [Making CI Easier with GitLab](https://about.gitlab.com/2017/07/13/making-ci-easier-with-gitlab/) | Concepts | 2017/07/13 | +| [Dockerizing GitLab Review Apps](https://about.gitlab.com/2017/07/11/dockerizing-review-apps/) | Concepts | 2017/07/11 | +| [Continuous Integration: From Jenkins to GitLab Using Docker](https://about.gitlab.com/2017/07/27/docker-my-precious/) | Concepts | 2017/07/27 | +| [Continuous Delivery of a Spring Boot application with GitLab CI and Kubernetes](https://about.gitlab.com/2016/12/14/continuous-delivery-of-a-spring-boot-application-with-gitlab-ci-and-kubernetes/) | Tutorial | 2016/12/14 | +| [Setting up GitLab CI for Android projects](https://about.gitlab.com/2016/11/30/setting-up-gitlab-ci-for-android-projects/) | Tutorial | 2016/11/30 | +| [Automated Debian Package Build with GitLab CI](https://about.gitlab.com/2016/10/12/automated-debian-package-build-with-gitlab-ci/) | Tutorial | 2016/10/12 | +| [Building an Elixir Release into a Docker image using GitLab CI](https://about.gitlab.com/2016/08/11/building-an-elixir-release-into-docker-image-using-gitlab-ci-part-1/) | Tutorial | 2016/08/11 | +| [Continuous Delivery with GitLab and Convox](https://about.gitlab.com/2016/06/09/continuous-delivery-with-gitlab-and-convox/) | Technical overview | 2016/06/09 | +| [How to use GitLab CI and MacStadium to build your macOS or iOS projects](https://about.gitlab.com/2017/05/15/how-to-use-macstadium-and-gitlab-ci-to-build-your-macos-or-ios-projects/) | Technical overview | 2017/05/15 | +| [Setting up GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/) | Tutorial | 2016/03/10 | ## Git -- [How to install Git](how_to_install_git/index.md) +Learn how to use [Git with GitLab](../topics/git/index.md): + +| Article title | Category | Publishing date | +| :------------ | :------: | --------------: | +| [Why Git is Worth the Learning Curve](https://about.gitlab.com/2017/05/17/learning-curve-is-the-biggest-challenge-developers-face-with-git/) | Concepts | 2017/05/17 | +| [How to install Git](how_to_install_git/index.md) | Tutorial | 2017/05/15 | +| [Getting Started with Git LFS](https://about.gitlab.com/2017/01/30/getting-started-with-git-lfs-tutorial/) | Tutorial | 2017/01/30 | +| [Git Tips & Tricks](https://about.gitlab.com/2016/12/08/git-tips-and-tricks/) | Technical overview | 2016/12/08 | ## GitLab Pages -- **GitLab Pages from A to Z** - - [Part 1: Static sites and GitLab Pages domains](../user/project/pages/getting_started_part_one.md) - - [Part 2: Quick start guide - Setting up GitLab Pages](../user/project/pages/getting_started_part_two.md) - - [Part 3: Setting Up Custom Domains - DNS Records and SSL/TLS Certificates](../user/project/pages/getting_started_part_three.md) - - [Part 4: Creating and tweaking `.gitlab-ci.yml` for GitLab Pages](../user/project/pages/getting_started_part_four.md) -- [Building a new GitLab Docs site with Nanoc, GitLab CI, and GitLab Pages](https://about.gitlab.com/2016/12/07/building-a-new-gitlab-docs-site-with-nanoc-gitlab-ci-and-gitlab-pages/) -- [GitLab CI: Deployment & Environments](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/) +Learn how to deploy a static website with [GitLab Pages](../user/project/pages/index.md#getting-started): -## Sofware development +| Article title | Category | Publishing date | +| :------------ | :------: | --------------: | +| **Series: GitLab Pages from A to Z:** | +| [- Part 1: Static sites and GitLab Pages domains](../user/project/pages/getting_started_part_one.md)| User guide | 2017/02/22 | +| [- Part 2: Quick start guide - Setting up GitLab Pages](../user/project/pages/getting_started_part_two.md)| User guide | 2017/02/22 | +| [- Part 3: Setting Up Custom Domains - DNS Records and SSL/TLS Certificates](../user/project/pages/getting_started_part_three.md)| User guide | 2017/02/22 | +| [- Part 4: Creating and tweaking `.gitlab-ci.yml` for GitLab Pages](../user/project/pages/getting_started_part_four.md)| User guide | 2017/02/22 | +| [Setting up GitLab Pages with CloudFlare Certificates](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/) | Tutorial | 2017/02/07 | +| [Building a new GitLab Docs site with Nanoc, GitLab CI, and GitLab Pages](https://about.gitlab.com/2016/12/07/building-a-new-gitlab-docs-site-with-nanoc-gitlab-ci-and-gitlab-pages/) | Tutorial | 2016/12/07 | +| [Publish Code Coverage Report with GitLab Pages](https://about.gitlab.com/2016/11/03/publish-code-coverage-report-with-gitlab-pages/) | Tutorial | 2016/11/03 | +| [GitLab CI: Deployment & Environments](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/) | Tutorial | 2016/08/26 | +| [Posting to your GitLab Pages blog from iOS](https://about.gitlab.com/2016/08/19/posting-to-your-gitlab-pages-blog-from-ios/) | Tutorial | 2016/08/19 | +| **Series: Static Site Generator:** | +| [- Part 1: Dynamic vs Static Websites](https://about.gitlab.com/2016/06/03/ssg-overview-gitlab-pages-part-1-dynamic-x-static/) | Tutorial | 2016/06/03 | +| [- Part 2: Modern Static Site Generators](https://about.gitlab.com/2016/06/10/ssg-overview-gitlab-pages-part-2/) | Tutorial | 2016/06/10 | +| [- Part 3: Build any SSG site with GitLab Pages](https://about.gitlab.com/2016/06/17/ssg-overview-gitlab-pages-part-3-examples-ci/) | Tutorial | 2016/06/17 | +| [Securing your GitLab Pages with TLS and Let's Encrypt](https://about.gitlab.com/2016/04/11/tutorial-securing-your-gitlab-pages-with-tls-and-letsencrypt/) | Tutorial | 2016/04/11 | +| [Hosting on GitLab.com with GitLab Pages](https://about.gitlab.com/2016/04/07/gitlab-pages-setup/) | Tutorial | 2016/04/07 | -- [In 13 minutes from Kubernetes to a complete application development tool](https://about.gitlab.com/2016/11/14/idea-to-production/) -- [Making CI Easier with GitLab](https://about.gitlab.com/2017/07/13/making-ci-easier-with-gitlab/) -- [Fast and Natural Continuous Integration with GitLab CI](https://about.gitlab.com/2017/05/22/fast-and-natural-continuous-integration-with-gitlab-ci/) -- [GitLab Workflow, an Overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/) -- [Continuous Integration, Delivery, and Deployment with GitLab](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) +## Install and maintain GitLab -## Build, test, and deploy with GitLab CI/CD +Install, upgrade, integrate, migrate to GitLab: + +| Article title | Category | Publishing date | +| :------------ | :------: | --------------: | +| [Video Tutorial: Idea to Production on Google Container Engine (GKE)](https://about.gitlab.com/2017/01/23/video-tutorial-idea-to-production-on-google-container-engine-gke/) | Tutorial | 2017/01/23 | +| [How to Setup a GitLab Instance on Microsoft Azure](https://about.gitlab.com/2016/07/13/how-to-setup-a-gitlab-instance-on-microsoft-azure/) | Tutorial | 2016/07/13 | +| [Get started with OpenShift Origin 3 and GitLab](https://about.gitlab.com/2016/06/28/get-started-with-openshift-origin-3-and-gitlab/) | Tutorial | 2016/06/28 | +| [Getting started with GitLab and DigitalOcean](https://about.gitlab.com/2016/04/27/getting-started-with-gitlab-and-digitalocean/) | Tutorial | 2016/04/27 | + +## Software development + +Learn how to explore the best of GitLab's software development's capabilities: + +| Article title | Category | Publishing date | +| :------------ | :------: | --------------: | +| [Making CI Easier with GitLab](https://about.gitlab.com/2017/07/13/making-ci-easier-with-gitlab/) | Concepts | 2017/07/13 | +| [From 2/3 of the Self-Hosted Git Market, to the Next-Generation CI System, to Auto DevOps](https://about.gitlab.com/2017/06/29/whats-next-for-gitlab-ci/)| Concepts | 2017/06/29 | +| [Fast and Natural Continuous Integration with GitLab CI](https://about.gitlab.com/2017/05/22/fast-and-natural-continuous-integration-with-gitlab-ci/) | Concepts | 2017/05/22 | +| [Demo: GitLab Service Desk](https://about.gitlab.com/2017/05/09/demo-service-desk/) | Feature highlight | 2017/05/09 | +| [Demo - Mapping Work Versus Time, With Burndown Charts](https://about.gitlab.com/2017/04/25/mapping-work-to-do-versus-time-with-burndown-charts/) | Feature highlight | 2017/04/25 | +| [Demo – Cloud Native Development with GitLab](https://about.gitlab.com/2017/04/18/cloud-native-demo/) | Feature highlight | 2017/04/18 | +| [Demo - Mastering Code Review With GitLab](https://about.gitlab.com/2017/03/17/demo-mastering-code-review-with-gitlab/) | Feature highlight | 2017/03/17 | +| [In 13 minutes from Kubernetes to a complete application development tool](https://about.gitlab.com/2016/11/14/idea-to-production/) | Technical overview | 2016/11/14 | +| [GitLab Workflow, an Overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/) | Technical overview | 2016/10/25 | +| [Trends in Version Control Land: Microservices](https://about.gitlab.com/2016/08/16/trends-in-version-control-land-microservices/) | Concepts | 2016/08/16 | +| [Continuous Integration, Delivery, and Deployment with GitLab](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) | Concepts | 2016/08/05 | +| [Trends in Version Control Land: Innersourcing](https://about.gitlab.com/2016/07/07/trends-version-control-innersourcing/) | Concepts | 2016/07/07 | +| [Tutorial: It's all connected in GitLab](https://about.gitlab.com/2016/03/08/gitlab-tutorial-its-all-connected/) | Technical overview | 2016/03/08 | + +## Technologies -**Build, test, and deploy** the software you develop with **[GitLab CI/CD](../ci/README.md)** +| Article title | Category | Publishing date | +| :------------ | :------: | --------------: | +| [Why we are not leaving the cloud](https://about.gitlab.com/2017/03/02/why-we-are-not-leaving-the-cloud/) | Concepts | 2017/03/02 | +| [Why We Chose Vue.js](https://about.gitlab.com/2016/10/20/why-we-chose-vue/) | Concepts | 2016/10/20 | +| [Markdown Kramdown Tips & Tricks](https://about.gitlab.com/2016/07/19/markdown-kramdown-tips-and-tricks/) | Technical overview | 2016/07/19 | -- [Continuous Delivery of a Spring Boot application with GitLab CI and Kubernetes](https://about.gitlab.com/2016/12/14/continuous-delivery-of-a-spring-boot-application-with-gitlab-ci-and-kubernetes/) -- [Automated Debian Package Build with GitLab CI](https://about.gitlab.com/2016/10/12/automated-debian-package-build-with-gitlab-ci/) -- [Building an Elixir Release into a Docker image using GitLab CI](https://about.gitlab.com/2016/08/11/building-an-elixir-release-into-docker-image-using-gitlab-ci-part-1/) -- [Setting up GitLab CI for Android projects](https://about.gitlab.com/2016/11/30/setting-up-gitlab-ci-for-android-projects/) -- [How to use GitLab CI and MacStadium to build your macOS or iOS projects](https://about.gitlab.com/2017/05/15/how-to-use-macstadium-and-gitlab-ci-to-build-your-macos-or-ios-projects/) -- cgit v1.2.1 From d03ea6d40a923f233c71000808e333809791bc26 Mon Sep 17 00:00:00 2001 From: kushalpandya Date: Tue, 1 Aug 2017 14:36:17 +0530 Subject: Change ID type to number --- spec/javascripts/groups/mock_data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/javascripts/groups/mock_data.js b/spec/javascripts/groups/mock_data.js index 9e1f414514a..5bb84b591f4 100644 --- a/spec/javascripts/groups/mock_data.js +++ b/spec/javascripts/groups/mock_data.js @@ -1,5 +1,5 @@ const group1 = { - id: '12', + id: 12, name: 'level1', path: 'level1', description: 'foo', -- cgit v1.2.1 From 53fb22bcc3458598de9cebd60ae64a5f96937d5e Mon Sep 17 00:00:00 2001 From: kushalpandya Date: Tue, 1 Aug 2017 14:36:30 +0530 Subject: Remove unnecessary imports --- spec/javascripts/groups/groups_spec.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/javascripts/groups/groups_spec.js b/spec/javascripts/groups/groups_spec.js index 7e38b49c792..b14153dbbfa 100644 --- a/spec/javascripts/groups/groups_spec.js +++ b/spec/javascripts/groups/groups_spec.js @@ -2,7 +2,6 @@ import Vue from 'vue'; import eventHub from '~/groups/event_hub'; import groupFolderComponent from '~/groups/components/group_folder.vue'; import groupItemComponent from '~/groups/components/group_item.vue'; -import groupIdenticonComponent from '~/groups/components/group_identicon.vue'; import groupsComponent from '~/groups/components/groups.vue'; import GroupsStore from '~/groups/stores/groups_store'; import { groupsData } from './mock_data'; @@ -15,7 +14,6 @@ describe('Groups Component', () => { beforeEach((done) => { Vue.component('group-folder', groupFolderComponent); - Vue.component('group-identicon', groupIdenticonComponent); Vue.component('group-item', groupItemComponent); store = new GroupsStore(); -- cgit v1.2.1 From 59377d54e91ba9acb309fe3cb1d4f942dbf43e54 Mon Sep 17 00:00:00 2001 From: kushalpandya Date: Tue, 1 Aug 2017 14:38:09 +0530 Subject: Tests for `group_identicon` component --- spec/javascripts/groups/group_identicon_spec.js | 82 +++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 spec/javascripts/groups/group_identicon_spec.js diff --git a/spec/javascripts/groups/group_identicon_spec.js b/spec/javascripts/groups/group_identicon_spec.js new file mode 100644 index 00000000000..d9615646982 --- /dev/null +++ b/spec/javascripts/groups/group_identicon_spec.js @@ -0,0 +1,82 @@ +import Vue from 'vue'; +import groupIdenticonComponent from '~/groups/components/group_identicon.vue'; +import GroupsStore from '~/groups/stores/groups_store'; +import { group1 } from './mock_data'; + +const createComponent = () => { + const Component = Vue.extend(groupIdenticonComponent); + const store = new GroupsStore(); + const group = store.decorateGroup(group1); + + return new Component({ + el: document.createElement('div'), + propsData: { + entityId: group.id, + entityName: group.name, + }, + }); +}; + +describe('GroupIdenticonComponent', () => { + let vm; + let el; + + beforeEach(() => { + vm = createComponent(); + el = vm.$el; + }); + + describe('props', () => { + it('should have props with defined data types', (done) => { + const identiconProps = groupIdenticonComponent.props; + const EntityIdTypeClass = identiconProps.entityId.type; + const EntityNameTypeClass = identiconProps.entityName.type; + + Vue.nextTick(() => { + expect(identiconProps.entityId).toBeDefined(); + expect(new EntityIdTypeClass() instanceof Number).toBeTruthy(); + expect(identiconProps.entityId.required).toBeTruthy(); + + expect(identiconProps.entityName).toBeDefined(); + expect(new EntityNameTypeClass() instanceof String).toBeTruthy(); + expect(identiconProps.entityName.required).toBeTruthy(); + done(); + }); + }); + }); + + describe('computed', () => { + describe('identiconStyles', () => { + it('should return styles attribute value with `background-color` property', () => { + vm.entityId = 4; + + expect(vm.identiconStyles).toBeDefined(); + expect(vm.identiconStyles.indexOf('background-color: #E0F2F1;') > -1).toBeTruthy(); + }); + + it('should return styles attribute value with `color` property', () => { + vm.entityId = 4; + + expect(vm.identiconStyles).toBeDefined(); + expect(vm.identiconStyles.indexOf('color: #555;') > -1).toBeTruthy(); + }); + }); + + describe('identiconTitle', () => { + it('should return first letter of entity title in uppercase', () => { + vm.entityName = 'dummy-group'; + + expect(vm.identiconTitle).toBeDefined(); + expect(vm.identiconTitle).toBe('D'); + }); + }); + }); + + describe('template', () => { + it('should render identicon', () => { + expect(el.nodeName).toBe('DIV'); + expect(el.classList.contains('identicon')).toBeTruthy(); + expect(el.getAttribute('style').indexOf('background-color') > -1).toBeTruthy(); + }); + }); +}); -- cgit v1.2.1 From 00226a9404d8e453a06d09ec54628a4eb66d98ec Mon Sep 17 00:00:00 2001 From: kushalpandya Date: Tue, 1 Aug 2017 14:38:40 +0530 Subject: Import `group_identicon` minor clean up and prop updates --- app/assets/javascripts/groups/components/group_item.vue | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue index c704aa65df2..41c9e5fc8b0 100644 --- a/app/assets/javascripts/groups/components/group_item.vue +++ b/app/assets/javascripts/groups/components/group_item.vue @@ -1,7 +1,11 @@ -- cgit v1.2.1 From 9f8152d84b1778c9d5c693d2cbc12b26cad596c4 Mon Sep 17 00:00:00 2001 From: kushalpandya Date: Tue, 1 Aug 2017 14:40:55 +0530 Subject: Add changelog entry --- changelogs/unreleased/35408-group-auto-avatars.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/35408-group-auto-avatars.yml diff --git a/changelogs/unreleased/35408-group-auto-avatars.yml b/changelogs/unreleased/35408-group-auto-avatars.yml new file mode 100644 index 00000000000..77b644a7f94 --- /dev/null +++ b/changelogs/unreleased/35408-group-auto-avatars.yml @@ -0,0 +1,4 @@ +--- +title: Show auto-generated avatars for Groups without avatars +merge_request: 13188 +author: -- cgit v1.2.1 From fe555e86fb54a0e21b49020b52a5e7f43beba73c Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 1 Aug 2017 10:29:55 +0100 Subject: Fixes the search losing focus This was caused by the blur & then the focus after transition end Closes #35515 --- app/assets/javascripts/gl_dropdown.js | 6 +++--- changelogs/unreleased/search-flickering.yml | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/search-flickering.yml diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js index 3babe273100..9475498e176 100644 --- a/app/assets/javascripts/gl_dropdown.js +++ b/app/assets/javascripts/gl_dropdown.js @@ -730,10 +730,10 @@ GitLabDropdown = (function() { GitLabDropdown.prototype.focusTextInput = function(triggerFocus = false) { if (this.options.filterable) { - $(':focus').blur(); - this.dropdown.one('transitionend', () => { - this.filterInput.focus(); + if (this.dropdown.is('.open')) { + this.filterInput.focus(); + } }); if (triggerFocus) { diff --git a/changelogs/unreleased/search-flickering.yml b/changelogs/unreleased/search-flickering.yml new file mode 100644 index 00000000000..951a5a0292a --- /dev/null +++ b/changelogs/unreleased/search-flickering.yml @@ -0,0 +1,4 @@ +--- +title: Fix search box losing focus when typing +merge_request: +author: -- cgit v1.2.1 From 97ef19d0660da6953fe201019a07de970d443d2c Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 1 Aug 2017 11:43:45 +0000 Subject: Fixes dropdown margin in sidebar --- app/assets/stylesheets/pages/builds.scss | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss index acf3719e9d2..28c99d8e57c 100644 --- a/app/assets/stylesheets/pages/builds.scss +++ b/app/assets/stylesheets/pages/builds.scss @@ -311,9 +311,7 @@ } .dropdown-menu { - right: $gl-padding; - left: $gl-padding; - width: auto; + margin-top: -$gl-padding; } svg { -- cgit v1.2.1 From 4fa83bbe90ea1f3d2c2d0d75f50ca732e299651f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 1 Aug 2017 13:52:44 +0200 Subject: Always fetch branches before finding the merge base, otherwise we could find an outdated merge base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/gitlab/ee_compat_check.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/gitlab/ee_compat_check.rb b/lib/gitlab/ee_compat_check.rb index 85e6db0a689..72d7d4f84d1 100644 --- a/lib/gitlab/ee_compat_check.rb +++ b/lib/gitlab/ee_compat_check.rb @@ -181,8 +181,6 @@ module Gitlab end def find_merge_base_with_master(branch:) - return if merge_base_found? - # Start with (Math.exp(3).to_i = 20) until (Math.exp(6).to_i = 403) # In total we go (20 + 54 + 148 + 403 = 625) commits deeper depth = 20 -- cgit v1.2.1 From f3569a25e493bf6b3eb9bb4f6227cc087fd179a6 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 1 Aug 2017 13:17:11 +0200 Subject: Fix bug in blob test --- spec/lib/gitlab/git/blob_spec.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb index 3c784eda4f8..18320bb23b9 100644 --- a/spec/lib/gitlab/git/blob_spec.rb +++ b/spec/lib/gitlab/git/blob_spec.rb @@ -78,12 +78,18 @@ describe Gitlab::Git::Blob, seed_helper: true do context 'large file' do let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, 'files/images/6049019_460s.jpg') } let(:blob_size) { 111803 } + let(:stub_limit) { 1000 } + + before do + stub_const('Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE', stub_limit) + end it { expect(blob.size).to eq(blob_size) } - it { expect(blob.data.length).to eq(blob_size) } + it { expect(blob.data.length).to eq(stub_limit) } it 'check that this test is sane' do - expect(blob.size).to be <= Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE + # It only makes sense to test limiting if the blob is larger than the limit. + expect(blob.size).to be > Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE end it 'can load all data' do -- cgit v1.2.1 From 913aca1db9b1bbf90f3490262c4429d95fbc517c Mon Sep 17 00:00:00 2001 From: "Lin Jen-Shin (godfat)" Date: Tue, 1 Aug 2017 12:06:56 +0000 Subject: Make sure we didn't commit conflicts --- scripts/lint-conflicts.sh | 5 +++++ scripts/static-analysis | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100755 scripts/lint-conflicts.sh diff --git a/scripts/lint-conflicts.sh b/scripts/lint-conflicts.sh new file mode 100755 index 00000000000..f3877600c8c --- /dev/null +++ b/scripts/lint-conflicts.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +output=`git ls-files -z | grep -zvE '\.(rb|js|haml)$' | xargs -0n1 grep -HEn '^<<<<<<< '` +echo $output +test -z "$output" diff --git a/scripts/static-analysis b/scripts/static-analysis index 6d35684b97f..e4f80e8fc6f 100755 --- a/scripts/static-analysis +++ b/scripts/static-analysis @@ -11,7 +11,8 @@ tasks = [ %w[bundle exec rake brakeman], %w[bundle exec license_finder], %w[yarn run eslint], - %w[bundle exec rubocop --require rubocop-rspec] + %w[bundle exec rubocop --require rubocop-rspec], + %w[scripts/lint-conflicts.sh] ] failed_tasks = tasks.reduce({}) do |failures, task| -- cgit v1.2.1 From 0c5fbaa72b8e4f032cf58758f8aa75925d57b06f Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Tue, 1 Aug 2017 21:17:46 +0900 Subject: Add 204. Remove duplicated method. --- lib/api/group_variables.rb | 1 + lib/api/helpers.rb | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/api/group_variables.rb b/lib/api/group_variables.rb index 0dd418887e0..f64da4ab77b 100644 --- a/lib/api/group_variables.rb +++ b/lib/api/group_variables.rb @@ -88,6 +88,7 @@ module API variable = user_group.variables.find_by(key: params[:key]) not_found!('GroupVariable') unless variable + status 204 variable.destroy end end diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index de58e9779a9..234825480f2 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -33,10 +33,6 @@ module API @project ||= find_project!(params[:id]) end - def user_group - @group ||= find_group!(params[:id]) - end - def available_labels @available_labels ||= LabelsFinder.new(current_user, project_id: user_project.id).execute end -- cgit v1.2.1 From 5fc985776b10ff3f601a569428d916a7a5a99793 Mon Sep 17 00:00:00 2001 From: winh Date: Thu, 27 Jul 2017 11:18:11 +0200 Subject: Make Markdown autocomplete dropdown style consistent --- .../stylesheets/framework/markdown_area.scss | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss index a2de4598167..fcd4c72b430 100644 --- a/app/assets/stylesheets/framework/markdown_area.scss +++ b/app/assets/stylesheets/framework/markdown_area.scss @@ -185,3 +185,28 @@ text-overflow: ellipsis; } } + +// TODO: fallback to global style +.atwho-view { + .atwho-view-ul { + padding: 8px 1px; + + li { + padding: 8px 16px; + border: 0; + + &.cur { + background-color: $gray-darker; + color: $gl-text-color; + + small { + color: inherit; + } + } + + strong { + color: $gl-text-color; + } + } + } +} -- cgit v1.2.1 From 7fa3dce30cd89ba152a410d51238fd1b8701bfda Mon Sep 17 00:00:00 2001 From: Marcia Ramos Date: Tue, 1 Aug 2017 10:36:30 -0300 Subject: copyedit, add article to the list --- doc/articles/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/articles/index.md b/doc/articles/index.md index d7e662d737f..260940e129b 100644 --- a/doc/articles/index.md +++ b/doc/articles/index.md @@ -12,7 +12,7 @@ where they were originally published. ## Authentication -Learn how to explore GitLab's supported [authentications methods](../topics/authentication/index.md): +Explore GitLab's supported [authentications methods](../topics/authentication/index.md): | Article title | Category | Publishing date | | :------------ | :------: | --------------: | @@ -34,6 +34,7 @@ Build, test, and deploy the software you develop with [GitLab CI/CD](../ci/READM | [Automated Debian Package Build with GitLab CI](https://about.gitlab.com/2016/10/12/automated-debian-package-build-with-gitlab-ci/) | Tutorial | 2016/10/12 | | [Building an Elixir Release into a Docker image using GitLab CI](https://about.gitlab.com/2016/08/11/building-an-elixir-release-into-docker-image-using-gitlab-ci-part-1/) | Tutorial | 2016/08/11 | | [Continuous Delivery with GitLab and Convox](https://about.gitlab.com/2016/06/09/continuous-delivery-with-gitlab-and-convox/) | Technical overview | 2016/06/09 | +| [GitLab Container Registry](https://about.gitlab.com/2016/05/23/gitlab-container-registry/) | Technical overview | 2016/05/23 | | [How to use GitLab CI and MacStadium to build your macOS or iOS projects](https://about.gitlab.com/2017/05/15/how-to-use-macstadium-and-gitlab-ci-to-build-your-macos-or-ios-projects/) | Technical overview | 2017/05/15 | | [Setting up GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/) | Tutorial | 2016/03/10 | @@ -84,7 +85,7 @@ Install, upgrade, integrate, migrate to GitLab: ## Software development -Learn how to explore the best of GitLab's software development's capabilities: +Explore the best of GitLab's software development's capabilities: | Article title | Category | Publishing date | | :------------ | :------: | --------------: | @@ -109,4 +110,3 @@ Learn how to explore the best of GitLab's software development's capabilities: | [Why we are not leaving the cloud](https://about.gitlab.com/2017/03/02/why-we-are-not-leaving-the-cloud/) | Concepts | 2017/03/02 | | [Why We Chose Vue.js](https://about.gitlab.com/2016/10/20/why-we-chose-vue/) | Concepts | 2016/10/20 | | [Markdown Kramdown Tips & Tricks](https://about.gitlab.com/2016/07/19/markdown-kramdown-tips-and-tricks/) | Technical overview | 2016/07/19 | - -- cgit v1.2.1 From 08ea9572d61f8fee19b3c013d2e4e943ce054580 Mon Sep 17 00:00:00 2001 From: Winnie Hellmann Date: Tue, 1 Aug 2017 13:38:16 +0000 Subject: Make time span dropdown style on cycle analytics page consistent --- app/assets/stylesheets/pages/cycle_analytics.scss | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/app/assets/stylesheets/pages/cycle_analytics.scss b/app/assets/stylesheets/pages/cycle_analytics.scss index eeb90759f10..87b50c7687e 100644 --- a/app/assets/stylesheets/pages/cycle_analytics.scss +++ b/app/assets/stylesheets/pages/cycle_analytics.scss @@ -110,6 +110,10 @@ .js-ca-dropdown { top: $gl-padding-top; + + .dropdown-menu-align-right { + margin-top: 2px; + } } .content-list { @@ -442,6 +446,24 @@ margin-bottom: 20px; } } + + // TODO: fallback to global style + .dropdown-menu { + li { + padding: 0 1px; + + a { + border-radius: 0; + padding: 8px 16px; + + &:hover, + &:active, + &:focus { + background-color: $gray-darker; + } + } + } + } } .cycle-analytics-overview { -- cgit v1.2.1 From 0430007ec86b7761cdaac2a0ba5d735264d63148 Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Tue, 1 Aug 2017 14:01:48 +0000 Subject: Add code review guidelines related to Build [CI skip]. --- doc/development/code_review.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/development/code_review.md b/doc/development/code_review.md index e3f37616757..64a89976300 100644 --- a/doc/development/code_review.md +++ b/doc/development/code_review.md @@ -11,6 +11,8 @@ There are a few rules to get your merge request accepted: **approved by a [frontend maintainer][projects]**. 1. If your merge request includes frontend and backend changes [^1], it must be **approved by a [frontend and a backend maintainer][projects]**. + 1. If your merge request includes a new dependency or a filesystem change, it must + be **approved by a [Build team member][team]**. See [how to work with the Build team][build handbook] for more details. 1. To lower the amount of merge requests maintainers need to review, you can ask or assign any [reviewers][projects] for a first review. 1. If you need some guidance (e.g. it's your first merge request), feel free @@ -194,3 +196,4 @@ Largely based on the [thoughtbot code review guide]. [projects]: https://about.gitlab.com/handbook/engineering/projects/ [team]: https://about.gitlab.com/team/ +[build handbook]: https://about.gitlab.com/handbook/build/handbook/build#how-to-work-with-build -- cgit v1.2.1 From f67c7a4da6eb7e363f5433df74016f234999c467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 1 Aug 2017 10:40:41 +0200 Subject: Fix Issue board when using Ruby 2.4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In Ruby 2.4, Hash#compact exists and returns a Hash, while in Ruby 2.3, Hash#compact is implemented by Rails and returns a new `ActionController::Parameters` instance in this case. Also, `ActionController::Parameters#compact` is deprecated in Rails 5.1 so we're using `reject { |_, value| value.nil? }` instead. Signed-off-by: Rémy Coutable --- app/controllers/projects/boards/issues_controller.rb | 3 ++- changelogs/unreleased/35769-fix-ruby-2-4-compatibility.yml | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/35769-fix-ruby-2-4-compatibility.yml diff --git a/app/controllers/projects/boards/issues_controller.rb b/app/controllers/projects/boards/issues_controller.rb index da9b789d617..653e7bc7e40 100644 --- a/app/controllers/projects/boards/issues_controller.rb +++ b/app/controllers/projects/boards/issues_controller.rb @@ -66,7 +66,8 @@ module Projects end def filter_params - params.merge(board_id: params[:board_id], id: params[:list_id]).compact + params.merge(board_id: params[:board_id], id: params[:list_id]) + .reject { |_, value| value.nil? } end def move_params diff --git a/changelogs/unreleased/35769-fix-ruby-2-4-compatibility.yml b/changelogs/unreleased/35769-fix-ruby-2-4-compatibility.yml new file mode 100644 index 00000000000..ac480993d85 --- /dev/null +++ b/changelogs/unreleased/35769-fix-ruby-2-4-compatibility.yml @@ -0,0 +1,4 @@ +--- +title: Fix Issue board when using Ruby 2.4 +merge_request: 13220 +author: -- cgit v1.2.1 From e7b5324b76f2cc7fe913298cde784ce6ae3d4671 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Tue, 1 Aug 2017 09:31:43 -0500 Subject: include cropper jQuery plugin as an npm module --- app/assets/javascripts/profile/gl_crop.js | 2 +- package.json | 1 + vendor/assets/javascripts/cropper.js | 2993 ----------------------------- yarn.lock | 8 +- 4 files changed, 9 insertions(+), 2995 deletions(-) delete mode 100644 vendor/assets/javascripts/cropper.js diff --git a/app/assets/javascripts/profile/gl_crop.js b/app/assets/javascripts/profile/gl_crop.js index cf1566eeb87..f32b2413725 100644 --- a/app/assets/javascripts/profile/gl_crop.js +++ b/app/assets/javascripts/profile/gl_crop.js @@ -1,6 +1,6 @@ /* eslint-disable no-useless-escape, max-len, quotes, no-var, no-underscore-dangle, func-names, space-before-function-paren, no-unused-vars, no-return-assign, object-shorthand, one-var, one-var-declaration-per-line, comma-dangle, consistent-return, class-methods-use-this, new-parens */ -import 'vendor/cropper'; +import 'cropper'; ((global) => { // Matches everything but the file name diff --git a/package.json b/package.json index fd944531a6a..6b6577ec06e 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "bootstrap-sass": "^3.3.6", "compression-webpack-plugin": "^0.3.2", "core-js": "^2.4.1", + "cropper": "^2.3.0", "css-loader": "^0.28.0", "d3": "^3.5.11", "deckar01-task_list": "^2.0.0", diff --git a/vendor/assets/javascripts/cropper.js b/vendor/assets/javascripts/cropper.js deleted file mode 100644 index 805485904a5..00000000000 --- a/vendor/assets/javascripts/cropper.js +++ /dev/null @@ -1,2993 +0,0 @@ -/*! - * Cropper v2.3.0 - * https://github.com/fengyuanchen/cropper - * - * Copyright (c) 2014-2016 Fengyuan Chen and contributors - * Released under the MIT license - * - * Date: 2016-02-22T02:13:13.332Z - */ - -(function (factory) { - if (typeof define === 'function' && define.amd) { - // AMD. Register as anonymous module. - define(['jquery'], factory); - } else if (typeof exports === 'object') { - // Node / CommonJS - factory(require('jquery')); - } else { - // Browser globals. - factory(jQuery); - } -})(function ($) { - - 'use strict'; - - // Globals - var $window = $(window); - var $document = $(document); - var location = window.location; - var navigator = window.navigator; - var ArrayBuffer = window.ArrayBuffer; - var Uint8Array = window.Uint8Array; - var DataView = window.DataView; - var btoa = window.btoa; - - // Constants - var NAMESPACE = 'cropper'; - - // Classes - var CLASS_MODAL = 'cropper-modal'; - var CLASS_HIDE = 'cropper-hide'; - var CLASS_HIDDEN = 'cropper-hidden'; - var CLASS_INVISIBLE = 'cropper-invisible'; - var CLASS_MOVE = 'cropper-move'; - var CLASS_CROP = 'cropper-crop'; - var CLASS_DISABLED = 'cropper-disabled'; - var CLASS_BG = 'cropper-bg'; - - // Events - var EVENT_MOUSE_DOWN = 'mousedown touchstart pointerdown MSPointerDown'; - var EVENT_MOUSE_MOVE = 'mousemove touchmove pointermove MSPointerMove'; - var EVENT_MOUSE_UP = 'mouseup touchend touchcancel pointerup pointercancel MSPointerUp MSPointerCancel'; - var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll'; - var EVENT_DBLCLICK = 'dblclick'; - var EVENT_LOAD = 'load.' + NAMESPACE; - var EVENT_ERROR = 'error.' + NAMESPACE; - var EVENT_RESIZE = 'resize.' + NAMESPACE; // Bind to window with namespace - var EVENT_BUILD = 'build.' + NAMESPACE; - var EVENT_BUILT = 'built.' + NAMESPACE; - var EVENT_CROP_START = 'cropstart.' + NAMESPACE; - var EVENT_CROP_MOVE = 'cropmove.' + NAMESPACE; - var EVENT_CROP_END = 'cropend.' + NAMESPACE; - var EVENT_CROP = 'crop.' + NAMESPACE; - var EVENT_ZOOM = 'zoom.' + NAMESPACE; - - // RegExps - var REGEXP_ACTIONS = /e|w|s|n|se|sw|ne|nw|all|crop|move|zoom/; - var REGEXP_DATA_URL = /^data\:/; - var REGEXP_DATA_URL_HEAD = /^data\:([^\;]+)\;base64,/; - var REGEXP_DATA_URL_JPEG = /^data\:image\/jpeg.*;base64,/; - - // Data keys - var DATA_PREVIEW = 'preview'; - var DATA_ACTION = 'action'; - - // Actions - var ACTION_EAST = 'e'; - var ACTION_WEST = 'w'; - var ACTION_SOUTH = 's'; - var ACTION_NORTH = 'n'; - var ACTION_SOUTH_EAST = 'se'; - var ACTION_SOUTH_WEST = 'sw'; - var ACTION_NORTH_EAST = 'ne'; - var ACTION_NORTH_WEST = 'nw'; - var ACTION_ALL = 'all'; - var ACTION_CROP = 'crop'; - var ACTION_MOVE = 'move'; - var ACTION_ZOOM = 'zoom'; - var ACTION_NONE = 'none'; - - // Supports - var SUPPORT_CANVAS = $.isFunction($('')[0].getContext); - var IS_SAFARI = navigator && /safari/i.test(navigator.userAgent) && /apple computer/i.test(navigator.vendor); - - // Maths - var num = Number; - var min = Math.min; - var max = Math.max; - var abs = Math.abs; - var sin = Math.sin; - var cos = Math.cos; - var sqrt = Math.sqrt; - var round = Math.round; - var floor = Math.floor; - - // Utilities - var fromCharCode = String.fromCharCode; - - function isNumber(n) { - return typeof n === 'number' && !isNaN(n); - } - - function isUndefined(n) { - return typeof n === 'undefined'; - } - - function toArray(obj, offset) { - var args = []; - - // This is necessary for IE8 - if (isNumber(offset)) { - args.push(offset); - } - - return args.slice.apply(obj, args); - } - - // Custom proxy to avoid jQuery's guid - function proxy(fn, context) { - var args = toArray(arguments, 2); - - return function () { - return fn.apply(context, args.concat(toArray(arguments))); - }; - } - - function isCrossOriginURL(url) { - var parts = url.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i); - - return parts && ( - parts[1] !== location.protocol || - parts[2] !== location.hostname || - parts[3] !== location.port - ); - } - - function addTimestamp(url) { - var timestamp = 'timestamp=' + (new Date()).getTime(); - - return (url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp); - } - - function getCrossOrigin(crossOrigin) { - return crossOrigin ? ' crossOrigin="' + crossOrigin + '"' : ''; - } - - function getImageSize(image, callback) { - var newImage; - - // Modern browsers (ignore Safari, #120 & #509) - if (image.naturalWidth && !IS_SAFARI) { - return callback(image.naturalWidth, image.naturalHeight); - } - - // IE8: Don't use `new Image()` here (#319) - newImage = document.createElement('img'); - - newImage.onload = function () { - callback(this.width, this.height); - }; - - newImage.src = image.src; - } - - function getTransform(options) { - var transforms = []; - var rotate = options.rotate; - var scaleX = options.scaleX; - var scaleY = options.scaleY; - - if (isNumber(rotate)) { - transforms.push('rotate(' + rotate + 'deg)'); - } - - if (isNumber(scaleX) && isNumber(scaleY)) { - transforms.push('scale(' + scaleX + ',' + scaleY + ')'); - } - - return transforms.length ? transforms.join(' ') : 'none'; - } - - function getRotatedSizes(data, isReversed) { - var deg = abs(data.degree) % 180; - var arc = (deg > 90 ? (180 - deg) : deg) * Math.PI / 180; - var sinArc = sin(arc); - var cosArc = cos(arc); - var width = data.width; - var height = data.height; - var aspectRatio = data.aspectRatio; - var newWidth; - var newHeight; - - if (!isReversed) { - newWidth = width * cosArc + height * sinArc; - newHeight = width * sinArc + height * cosArc; - } else { - newWidth = width / (cosArc + sinArc / aspectRatio); - newHeight = newWidth / aspectRatio; - } - - return { - width: newWidth, - height: newHeight - }; - } - - function getSourceCanvas(image, data) { - var canvas = $('')[0]; - var context = canvas.getContext('2d'); - var dstX = 0; - var dstY = 0; - var dstWidth = data.naturalWidth; - var dstHeight = data.naturalHeight; - var rotate = data.rotate; - var scaleX = data.scaleX; - var scaleY = data.scaleY; - var scalable = isNumber(scaleX) && isNumber(scaleY) && (scaleX !== 1 || scaleY !== 1); - var rotatable = isNumber(rotate) && rotate !== 0; - var advanced = rotatable || scalable; - var canvasWidth = dstWidth * abs(scaleX || 1); - var canvasHeight = dstHeight * abs(scaleY || 1); - var translateX; - var translateY; - var rotated; - - if (scalable) { - translateX = canvasWidth / 2; - translateY = canvasHeight / 2; - } - - if (rotatable) { - rotated = getRotatedSizes({ - width: canvasWidth, - height: canvasHeight, - degree: rotate - }); - - canvasWidth = rotated.width; - canvasHeight = rotated.height; - translateX = canvasWidth / 2; - translateY = canvasHeight / 2; - } - - canvas.width = canvasWidth; - canvas.height = canvasHeight; - - if (advanced) { - dstX = -dstWidth / 2; - dstY = -dstHeight / 2; - - context.save(); - context.translate(translateX, translateY); - } - - if (rotatable) { - context.rotate(rotate * Math.PI / 180); - } - - // Should call `scale` after rotated - if (scalable) { - context.scale(scaleX, scaleY); - } - - context.drawImage(image, floor(dstX), floor(dstY), floor(dstWidth), floor(dstHeight)); - - if (advanced) { - context.restore(); - } - - return canvas; - } - - function getTouchesCenter(touches) { - var length = touches.length; - var pageX = 0; - var pageY = 0; - - if (length) { - $.each(touches, function (i, touch) { - pageX += touch.pageX; - pageY += touch.pageY; - }); - - pageX /= length; - pageY /= length; - } - - return { - pageX: pageX, - pageY: pageY - }; - } - - function getStringFromCharCode(dataView, start, length) { - var str = ''; - var i; - - for (i = start, length += start; i < length; i++) { - str += fromCharCode(dataView.getUint8(i)); - } - - return str; - } - - function getOrientation(arrayBuffer) { - var dataView = new DataView(arrayBuffer); - var length = dataView.byteLength; - var orientation; - var exifIDCode; - var tiffOffset; - var firstIFDOffset; - var littleEndian; - var endianness; - var app1Start; - var ifdStart; - var offset; - var i; - - // Only handle JPEG image (start by 0xFFD8) - if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) { - offset = 2; - - while (offset < length) { - if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) { - app1Start = offset; - break; - } - - offset++; - } - } - - if (app1Start) { - exifIDCode = app1Start + 4; - tiffOffset = app1Start + 10; - - if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') { - endianness = dataView.getUint16(tiffOffset); - littleEndian = endianness === 0x4949; - - if (littleEndian || endianness === 0x4D4D /* bigEndian */) { - if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) { - firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian); - - if (firstIFDOffset >= 0x00000008) { - ifdStart = tiffOffset + firstIFDOffset; - } - } - } - } - } - - if (ifdStart) { - length = dataView.getUint16(ifdStart, littleEndian); - - for (i = 0; i < length; i++) { - offset = ifdStart + i * 12 + 2; - - if (dataView.getUint16(offset, littleEndian) === 0x0112 /* Orientation */) { - - // 8 is the offset of the current tag's value - offset += 8; - - // Get the original orientation value - orientation = dataView.getUint16(offset, littleEndian); - - // Override the orientation with its default value for Safari (#120) - if (IS_SAFARI) { - dataView.setUint16(offset, 1, littleEndian); - } - - break; - } - } - } - - return orientation; - } - - function dataURLToArrayBuffer(dataURL) { - var base64 = dataURL.replace(REGEXP_DATA_URL_HEAD, ''); - var binary = atob(base64); - var length = binary.length; - var arrayBuffer = new ArrayBuffer(length); - var dataView = new Uint8Array(arrayBuffer); - var i; - - for (i = 0; i < length; i++) { - dataView[i] = binary.charCodeAt(i); - } - - return arrayBuffer; - } - - // Only available for JPEG image - function arrayBufferToDataURL(arrayBuffer) { - var dataView = new Uint8Array(arrayBuffer); - var length = dataView.length; - var base64 = ''; - var i; - - for (i = 0; i < length; i++) { - base64 += fromCharCode(dataView[i]); - } - - return 'data:image/jpeg;base64,' + btoa(base64); - } - - function Cropper(element, options) { - this.$element = $(element); - this.options = $.extend({}, Cropper.DEFAULTS, $.isPlainObject(options) && options); - this.isLoaded = false; - this.isBuilt = false; - this.isCompleted = false; - this.isRotated = false; - this.isCropped = false; - this.isDisabled = false; - this.isReplaced = false; - this.isLimited = false; - this.wheeling = false; - this.isImg = false; - this.originalUrl = ''; - this.canvas = null; - this.cropBox = null; - this.init(); - } - - Cropper.prototype = { - constructor: Cropper, - - init: function () { - var $this = this.$element; - var url; - - if ($this.is('img')) { - this.isImg = true; - - // Should use `$.fn.attr` here. e.g.: "img/picture.jpg" - this.originalUrl = url = $this.attr('src'); - - // Stop when it's a blank image - if (!url) { - return; - } - - // Should use `$.fn.prop` here. e.g.: "http://example.com/img/picture.jpg" - url = $this.prop('src'); - } else if ($this.is('canvas') && SUPPORT_CANVAS) { - url = $this[0].toDataURL(); - } - - this.load(url); - }, - - // A shortcut for triggering custom events - trigger: function (type, data) { - var e = $.Event(type, data); - - this.$element.trigger(e); - - return e; - }, - - load: function (url) { - var options = this.options; - var $this = this.$element; - var read; - var xhr; - - if (!url) { - return; - } - - // Trigger build event first - $this.one(EVENT_BUILD, options.build); - - if (this.trigger(EVENT_BUILD).isDefaultPrevented()) { - return; - } - - this.url = url; - this.image = {}; - - if (!options.checkOrientation || !ArrayBuffer) { - return this.clone(); - } - - read = $.proxy(this.read, this); - - // XMLHttpRequest disallows to open a Data URL in some browsers like IE11 and Safari - if (REGEXP_DATA_URL.test(url)) { - return REGEXP_DATA_URL_JPEG.test(url) ? - read(dataURLToArrayBuffer(url)) : - this.clone(); - } - - xhr = new XMLHttpRequest(); - - xhr.onerror = xhr.onabort = $.proxy(function () { - this.clone(); - }, this); - - xhr.onload = function () { - read(this.response); - }; - - xhr.open('get', url); - xhr.responseType = 'arraybuffer'; - xhr.send(); - }, - - read: function (arrayBuffer) { - var options = this.options; - var orientation = getOrientation(arrayBuffer); - var image = this.image; - var rotate; - var scaleX; - var scaleY; - - if (orientation > 1) { - this.url = arrayBufferToDataURL(arrayBuffer); - - switch (orientation) { - - // flip horizontal - case 2: - scaleX = -1; - break; - - // rotate left 180° - case 3: - rotate = -180; - break; - - // flip vertical - case 4: - scaleY = -1; - break; - - // flip vertical + rotate right 90° - case 5: - rotate = 90; - scaleY = -1; - break; - - // rotate right 90° - case 6: - rotate = 90; - break; - - // flip horizontal + rotate right 90° - case 7: - rotate = 90; - scaleX = -1; - break; - - // rotate left 90° - case 8: - rotate = -90; - break; - } - } - - if (options.rotatable) { - image.rotate = rotate; - } - - if (options.scalable) { - image.scaleX = scaleX; - image.scaleY = scaleY; - } - - this.clone(); - }, - - clone: function () { - var options = this.options; - var $this = this.$element; - var url = this.url; - var crossOrigin = ''; - var crossOriginUrl; - var $clone; - - if (options.checkCrossOrigin && isCrossOriginURL(url)) { - crossOrigin = $this.prop('crossOrigin'); - - if (crossOrigin) { - crossOriginUrl = url; - } else { - crossOrigin = 'anonymous'; - - // Bust cache (#148) when there is not a "crossOrigin" property - crossOriginUrl = addTimestamp(url); - } - } - - this.crossOrigin = crossOrigin; - this.crossOriginUrl = crossOriginUrl; - this.$clone = $clone = $(''); - - if (this.isImg) { - if ($this[0].complete) { - this.start(); - } else { - $this.one(EVENT_LOAD, $.proxy(this.start, this)); - } - } else { - $clone. - one(EVENT_LOAD, $.proxy(this.start, this)). - one(EVENT_ERROR, $.proxy(this.stop, this)). - addClass(CLASS_HIDE). - insertAfter($this); - } - }, - - start: function () { - var $image = this.$element; - var $clone = this.$clone; - - if (!this.isImg) { - $clone.off(EVENT_ERROR, this.stop); - $image = $clone; - } - - getImageSize($image[0], $.proxy(function (naturalWidth, naturalHeight) { - $.extend(this.image, { - naturalWidth: naturalWidth, - naturalHeight: naturalHeight, - aspectRatio: naturalWidth / naturalHeight - }); - - this.isLoaded = true; - this.build(); - }, this)); - }, - - stop: function () { - this.$clone.remove(); - this.$clone = null; - }, - - build: function () { - var options = this.options; - var $this = this.$element; - var $clone = this.$clone; - var $cropper; - var $cropBox; - var $face; - - if (!this.isLoaded) { - return; - } - - // Unbuild first when replace - if (this.isBuilt) { - this.unbuild(); - } - - // Create cropper elements - this.$container = $this.parent(); - this.$cropper = $cropper = $(Cropper.TEMPLATE); - this.$canvas = $cropper.find('.cropper-canvas').append($clone); - this.$dragBox = $cropper.find('.cropper-drag-box'); - this.$cropBox = $cropBox = $cropper.find('.cropper-crop-box'); - this.$viewBox = $cropper.find('.cropper-view-box'); - this.$face = $face = $cropBox.find('.cropper-face'); - - // Hide the original image - $this.addClass(CLASS_HIDDEN).after($cropper); - - // Show the clone image if is hidden - if (!this.isImg) { - $clone.removeClass(CLASS_HIDE); - } - - this.initPreview(); - this.bind(); - - options.aspectRatio = max(0, options.aspectRatio) || NaN; - options.viewMode = max(0, min(3, round(options.viewMode))) || 0; - - if (options.autoCrop) { - this.isCropped = true; - - if (options.modal) { - this.$dragBox.addClass(CLASS_MODAL); - } - } else { - $cropBox.addClass(CLASS_HIDDEN); - } - - if (!options.guides) { - $cropBox.find('.cropper-dashed').addClass(CLASS_HIDDEN); - } - - if (!options.center) { - $cropBox.find('.cropper-center').addClass(CLASS_HIDDEN); - } - - if (options.cropBoxMovable) { - $face.addClass(CLASS_MOVE).data(DATA_ACTION, ACTION_ALL); - } - - if (!options.highlight) { - $face.addClass(CLASS_INVISIBLE); - } - - if (options.background) { - $cropper.addClass(CLASS_BG); - } - - if (!options.cropBoxResizable) { - $cropBox.find('.cropper-line, .cropper-point').addClass(CLASS_HIDDEN); - } - - this.setDragMode(options.dragMode); - this.render(); - this.isBuilt = true; - this.setData(options.data); - $this.one(EVENT_BUILT, options.built); - - // Trigger the built event asynchronously to keep `data('cropper')` is defined - setTimeout($.proxy(function () { - this.trigger(EVENT_BUILT); - this.isCompleted = true; - }, this), 0); - }, - - unbuild: function () { - if (!this.isBuilt) { - return; - } - - this.isBuilt = false; - this.isCompleted = false; - this.initialImage = null; - - // Clear `initialCanvas` is necessary when replace - this.initialCanvas = null; - this.initialCropBox = null; - this.container = null; - this.canvas = null; - - // Clear `cropBox` is necessary when replace - this.cropBox = null; - this.unbind(); - - this.resetPreview(); - this.$preview = null; - - this.$viewBox = null; - this.$cropBox = null; - this.$dragBox = null; - this.$canvas = null; - this.$container = null; - - this.$cropper.remove(); - this.$cropper = null; - }, - - render: function () { - this.initContainer(); - this.initCanvas(); - this.initCropBox(); - - this.renderCanvas(); - - if (this.isCropped) { - this.renderCropBox(); - } - }, - - initContainer: function () { - var options = this.options; - var $this = this.$element; - var $container = this.$container; - var $cropper = this.$cropper; - - $cropper.addClass(CLASS_HIDDEN); - $this.removeClass(CLASS_HIDDEN); - - $cropper.css((this.container = { - width: max($container.width(), num(options.minContainerWidth) || 200), - height: max($container.height(), num(options.minContainerHeight) || 100) - })); - - $this.addClass(CLASS_HIDDEN); - $cropper.removeClass(CLASS_HIDDEN); - }, - - // Canvas (image wrapper) - initCanvas: function () { - var viewMode = this.options.viewMode; - var container = this.container; - var containerWidth = container.width; - var containerHeight = container.height; - var image = this.image; - var imageNaturalWidth = image.naturalWidth; - var imageNaturalHeight = image.naturalHeight; - var is90Degree = abs(image.rotate) === 90; - var naturalWidth = is90Degree ? imageNaturalHeight : imageNaturalWidth; - var naturalHeight = is90Degree ? imageNaturalWidth : imageNaturalHeight; - var aspectRatio = naturalWidth / naturalHeight; - var canvasWidth = containerWidth; - var canvasHeight = containerHeight; - var canvas; - - if (containerHeight * aspectRatio > containerWidth) { - if (viewMode === 3) { - canvasWidth = containerHeight * aspectRatio; - } else { - canvasHeight = containerWidth / aspectRatio; - } - } else { - if (viewMode === 3) { - canvasHeight = containerWidth / aspectRatio; - } else { - canvasWidth = containerHeight * aspectRatio; - } - } - - canvas = { - naturalWidth: naturalWidth, - naturalHeight: naturalHeight, - aspectRatio: aspectRatio, - width: canvasWidth, - height: canvasHeight - }; - - canvas.oldLeft = canvas.left = (containerWidth - canvasWidth) / 2; - canvas.oldTop = canvas.top = (containerHeight - canvasHeight) / 2; - - this.canvas = canvas; - this.isLimited = (viewMode === 1 || viewMode === 2); - this.limitCanvas(true, true); - this.initialImage = $.extend({}, image); - this.initialCanvas = $.extend({}, canvas); - }, - - limitCanvas: function (isSizeLimited, isPositionLimited) { - var options = this.options; - var viewMode = options.viewMode; - var container = this.container; - var containerWidth = container.width; - var containerHeight = container.height; - var canvas = this.canvas; - var aspectRatio = canvas.aspectRatio; - var cropBox = this.cropBox; - var isCropped = this.isCropped && cropBox; - var minCanvasWidth; - var minCanvasHeight; - var newCanvasLeft; - var newCanvasTop; - - if (isSizeLimited) { - minCanvasWidth = num(options.minCanvasWidth) || 0; - minCanvasHeight = num(options.minCanvasHeight) || 0; - - if (viewMode) { - if (viewMode > 1) { - minCanvasWidth = max(minCanvasWidth, containerWidth); - minCanvasHeight = max(minCanvasHeight, containerHeight); - - if (viewMode === 3) { - if (minCanvasHeight * aspectRatio > minCanvasWidth) { - minCanvasWidth = minCanvasHeight * aspectRatio; - } else { - minCanvasHeight = minCanvasWidth / aspectRatio; - } - } - } else { - if (minCanvasWidth) { - minCanvasWidth = max(minCanvasWidth, isCropped ? cropBox.width : 0); - } else if (minCanvasHeight) { - minCanvasHeight = max(minCanvasHeight, isCropped ? cropBox.height : 0); - } else if (isCropped) { - minCanvasWidth = cropBox.width; - minCanvasHeight = cropBox.height; - - if (minCanvasHeight * aspectRatio > minCanvasWidth) { - minCanvasWidth = minCanvasHeight * aspectRatio; - } else { - minCanvasHeight = minCanvasWidth / aspectRatio; - } - } - } - } - - if (minCanvasWidth && minCanvasHeight) { - if (minCanvasHeight * aspectRatio > minCanvasWidth) { - minCanvasHeight = minCanvasWidth / aspectRatio; - } else { - minCanvasWidth = minCanvasHeight * aspectRatio; - } - } else if (minCanvasWidth) { - minCanvasHeight = minCanvasWidth / aspectRatio; - } else if (minCanvasHeight) { - minCanvasWidth = minCanvasHeight * aspectRatio; - } - - canvas.minWidth = minCanvasWidth; - canvas.minHeight = minCanvasHeight; - canvas.maxWidth = Infinity; - canvas.maxHeight = Infinity; - } - - if (isPositionLimited) { - if (viewMode) { - newCanvasLeft = containerWidth - canvas.width; - newCanvasTop = containerHeight - canvas.height; - - canvas.minLeft = min(0, newCanvasLeft); - canvas.minTop = min(0, newCanvasTop); - canvas.maxLeft = max(0, newCanvasLeft); - canvas.maxTop = max(0, newCanvasTop); - - if (isCropped && this.isLimited) { - canvas.minLeft = min( - cropBox.left, - cropBox.left + cropBox.width - canvas.width - ); - canvas.minTop = min( - cropBox.top, - cropBox.top + cropBox.height - canvas.height - ); - canvas.maxLeft = cropBox.left; - canvas.maxTop = cropBox.top; - - if (viewMode === 2) { - if (canvas.width >= containerWidth) { - canvas.minLeft = min(0, newCanvasLeft); - canvas.maxLeft = max(0, newCanvasLeft); - } - - if (canvas.height >= containerHeight) { - canvas.minTop = min(0, newCanvasTop); - canvas.maxTop = max(0, newCanvasTop); - } - } - } - } else { - canvas.minLeft = -canvas.width; - canvas.minTop = -canvas.height; - canvas.maxLeft = containerWidth; - canvas.maxTop = containerHeight; - } - } - }, - - renderCanvas: function (isChanged) { - var canvas = this.canvas; - var image = this.image; - var rotate = image.rotate; - var naturalWidth = image.naturalWidth; - var naturalHeight = image.naturalHeight; - var aspectRatio; - var rotated; - - if (this.isRotated) { - this.isRotated = false; - - // Computes rotated sizes with image sizes - rotated = getRotatedSizes({ - width: image.width, - height: image.height, - degree: rotate - }); - - aspectRatio = rotated.width / rotated.height; - - if (aspectRatio !== canvas.aspectRatio) { - canvas.left -= (rotated.width - canvas.width) / 2; - canvas.top -= (rotated.height - canvas.height) / 2; - canvas.width = rotated.width; - canvas.height = rotated.height; - canvas.aspectRatio = aspectRatio; - canvas.naturalWidth = naturalWidth; - canvas.naturalHeight = naturalHeight; - - // Computes rotated sizes with natural image sizes - if (rotate % 180) { - rotated = getRotatedSizes({ - width: naturalWidth, - height: naturalHeight, - degree: rotate - }); - - canvas.naturalWidth = rotated.width; - canvas.naturalHeight = rotated.height; - } - - this.limitCanvas(true, false); - } - } - - if (canvas.width > canvas.maxWidth || canvas.width < canvas.minWidth) { - canvas.left = canvas.oldLeft; - } - - if (canvas.height > canvas.maxHeight || canvas.height < canvas.minHeight) { - canvas.top = canvas.oldTop; - } - - canvas.width = min(max(canvas.width, canvas.minWidth), canvas.maxWidth); - canvas.height = min(max(canvas.height, canvas.minHeight), canvas.maxHeight); - - this.limitCanvas(false, true); - - canvas.oldLeft = canvas.left = min(max(canvas.left, canvas.minLeft), canvas.maxLeft); - canvas.oldTop = canvas.top = min(max(canvas.top, canvas.minTop), canvas.maxTop); - - this.$canvas.css({ - width: canvas.width, - height: canvas.height, - left: canvas.left, - top: canvas.top - }); - - this.renderImage(); - - if (this.isCropped && this.isLimited) { - this.limitCropBox(true, true); - } - - if (isChanged) { - this.output(); - } - }, - - renderImage: function (isChanged) { - var canvas = this.canvas; - var image = this.image; - var reversed; - - if (image.rotate) { - reversed = getRotatedSizes({ - width: canvas.width, - height: canvas.height, - degree: image.rotate, - aspectRatio: image.aspectRatio - }, true); - } - - $.extend(image, reversed ? { - width: reversed.width, - height: reversed.height, - left: (canvas.width - reversed.width) / 2, - top: (canvas.height - reversed.height) / 2 - } : { - width: canvas.width, - height: canvas.height, - left: 0, - top: 0 - }); - - this.$clone.css({ - width: image.width, - height: image.height, - marginLeft: image.left, - marginTop: image.top, - transform: getTransform(image) - }); - - if (isChanged) { - this.output(); - } - }, - - initCropBox: function () { - var options = this.options; - var canvas = this.canvas; - var aspectRatio = options.aspectRatio; - var autoCropArea = num(options.autoCropArea) || 0.8; - var cropBox = { - width: canvas.width, - height: canvas.height - }; - - if (aspectRatio) { - if (canvas.height * aspectRatio > canvas.width) { - cropBox.height = cropBox.width / aspectRatio; - } else { - cropBox.width = cropBox.height * aspectRatio; - } - } - - this.cropBox = cropBox; - this.limitCropBox(true, true); - - // Initialize auto crop area - cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth); - cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight); - - // The width of auto crop area must large than "minWidth", and the height too. (#164) - cropBox.width = max(cropBox.minWidth, cropBox.width * autoCropArea); - cropBox.height = max(cropBox.minHeight, cropBox.height * autoCropArea); - cropBox.oldLeft = cropBox.left = canvas.left + (canvas.width - cropBox.width) / 2; - cropBox.oldTop = cropBox.top = canvas.top + (canvas.height - cropBox.height) / 2; - - this.initialCropBox = $.extend({}, cropBox); - }, - - limitCropBox: function (isSizeLimited, isPositionLimited) { - var options = this.options; - var aspectRatio = options.aspectRatio; - var container = this.container; - var containerWidth = container.width; - var containerHeight = container.height; - var canvas = this.canvas; - var cropBox = this.cropBox; - var isLimited = this.isLimited; - var minCropBoxWidth; - var minCropBoxHeight; - var maxCropBoxWidth; - var maxCropBoxHeight; - - if (isSizeLimited) { - minCropBoxWidth = num(options.minCropBoxWidth) || 0; - minCropBoxHeight = num(options.minCropBoxHeight) || 0; - - // The min/maxCropBoxWidth/Height must be less than containerWidth/Height - minCropBoxWidth = min(minCropBoxWidth, containerWidth); - minCropBoxHeight = min(minCropBoxHeight, containerHeight); - maxCropBoxWidth = min(containerWidth, isLimited ? canvas.width : containerWidth); - maxCropBoxHeight = min(containerHeight, isLimited ? canvas.height : containerHeight); - - if (aspectRatio) { - if (minCropBoxWidth && minCropBoxHeight) { - if (minCropBoxHeight * aspectRatio > minCropBoxWidth) { - minCropBoxHeight = minCropBoxWidth / aspectRatio; - } else { - minCropBoxWidth = minCropBoxHeight * aspectRatio; - } - } else if (minCropBoxWidth) { - minCropBoxHeight = minCropBoxWidth / aspectRatio; - } else if (minCropBoxHeight) { - minCropBoxWidth = minCropBoxHeight * aspectRatio; - } - - if (maxCropBoxHeight * aspectRatio > maxCropBoxWidth) { - maxCropBoxHeight = maxCropBoxWidth / aspectRatio; - } else { - maxCropBoxWidth = maxCropBoxHeight * aspectRatio; - } - } - - // The minWidth/Height must be less than maxWidth/Height - cropBox.minWidth = min(minCropBoxWidth, maxCropBoxWidth); - cropBox.minHeight = min(minCropBoxHeight, maxCropBoxHeight); - cropBox.maxWidth = maxCropBoxWidth; - cropBox.maxHeight = maxCropBoxHeight; - } - - if (isPositionLimited) { - if (isLimited) { - cropBox.minLeft = max(0, canvas.left); - cropBox.minTop = max(0, canvas.top); - cropBox.maxLeft = min(containerWidth, canvas.left + canvas.width) - cropBox.width; - cropBox.maxTop = min(containerHeight, canvas.top + canvas.height) - cropBox.height; - } else { - cropBox.minLeft = 0; - cropBox.minTop = 0; - cropBox.maxLeft = containerWidth - cropBox.width; - cropBox.maxTop = containerHeight - cropBox.height; - } - } - }, - - renderCropBox: function () { - var options = this.options; - var container = this.container; - var containerWidth = container.width; - var containerHeight = container.height; - var cropBox = this.cropBox; - - if (cropBox.width > cropBox.maxWidth || cropBox.width < cropBox.minWidth) { - cropBox.left = cropBox.oldLeft; - } - - if (cropBox.height > cropBox.maxHeight || cropBox.height < cropBox.minHeight) { - cropBox.top = cropBox.oldTop; - } - - cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth); - cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight); - - this.limitCropBox(false, true); - - cropBox.oldLeft = cropBox.left = min(max(cropBox.left, cropBox.minLeft), cropBox.maxLeft); - cropBox.oldTop = cropBox.top = min(max(cropBox.top, cropBox.minTop), cropBox.maxTop); - - if (options.movable && options.cropBoxMovable) { - - // Turn to move the canvas when the crop box is equal to the container - this.$face.data(DATA_ACTION, (cropBox.width === containerWidth && cropBox.height === containerHeight) ? ACTION_MOVE : ACTION_ALL); - } - - this.$cropBox.css({ - width: cropBox.width, - height: cropBox.height, - left: cropBox.left, - top: cropBox.top - }); - - if (this.isCropped && this.isLimited) { - this.limitCanvas(true, true); - } - - if (!this.isDisabled) { - this.output(); - } - }, - - output: function () { - this.preview(); - - if (this.isCompleted) { - this.trigger(EVENT_CROP, this.getData()); - } else if (!this.isBuilt) { - - // Only trigger one crop event before complete - this.$element.one(EVENT_BUILT, $.proxy(function () { - this.trigger(EVENT_CROP, this.getData()); - }, this)); - } - }, - - initPreview: function () { - var crossOrigin = getCrossOrigin(this.crossOrigin); - var url = crossOrigin ? this.crossOriginUrl : this.url; - var $clone2; - - this.$preview = $(this.options.preview); - this.$clone2 = $clone2 = $(''); - this.$viewBox.html($clone2); - this.$preview.each(function () { - var $this = $(this); - - // Save the original size for recover - $this.data(DATA_PREVIEW, { - width: $this.width(), - height: $this.height(), - html: $this.html() - }); - - /** - * Override img element styles - * Add `display:block` to avoid margin top issue - * (Occur only when margin-top <= -height) - */ - $this.html( - '' - ); - }); - }, - - resetPreview: function () { - this.$preview.each(function () { - var $this = $(this); - var data = $this.data(DATA_PREVIEW); - - $this.css({ - width: data.width, - height: data.height - }).html(data.html).removeData(DATA_PREVIEW); - }); - }, - - preview: function () { - var image = this.image; - var canvas = this.canvas; - var cropBox = this.cropBox; - var cropBoxWidth = cropBox.width; - var cropBoxHeight = cropBox.height; - var width = image.width; - var height = image.height; - var left = cropBox.left - canvas.left - image.left; - var top = cropBox.top - canvas.top - image.top; - - if (!this.isCropped || this.isDisabled) { - return; - } - - this.$clone2.css({ - width: width, - height: height, - marginLeft: -left, - marginTop: -top, - transform: getTransform(image) - }); - - this.$preview.each(function () { - var $this = $(this); - var data = $this.data(DATA_PREVIEW); - var originalWidth = data.width; - var originalHeight = data.height; - var newWidth = originalWidth; - var newHeight = originalHeight; - var ratio = 1; - - if (cropBoxWidth) { - ratio = originalWidth / cropBoxWidth; - newHeight = cropBoxHeight * ratio; - } - - if (cropBoxHeight && newHeight > originalHeight) { - ratio = originalHeight / cropBoxHeight; - newWidth = cropBoxWidth * ratio; - newHeight = originalHeight; - } - - $this.css({ - width: newWidth, - height: newHeight - }).find('img').css({ - width: width * ratio, - height: height * ratio, - marginLeft: -left * ratio, - marginTop: -top * ratio, - transform: getTransform(image) - }); - }); - }, - - bind: function () { - var options = this.options; - var $this = this.$element; - var $cropper = this.$cropper; - - if ($.isFunction(options.cropstart)) { - $this.on(EVENT_CROP_START, options.cropstart); - } - - if ($.isFunction(options.cropmove)) { - $this.on(EVENT_CROP_MOVE, options.cropmove); - } - - if ($.isFunction(options.cropend)) { - $this.on(EVENT_CROP_END, options.cropend); - } - - if ($.isFunction(options.crop)) { - $this.on(EVENT_CROP, options.crop); - } - - if ($.isFunction(options.zoom)) { - $this.on(EVENT_ZOOM, options.zoom); - } - - $cropper.on(EVENT_MOUSE_DOWN, $.proxy(this.cropStart, this)); - - if (options.zoomable && options.zoomOnWheel) { - $cropper.on(EVENT_WHEEL, $.proxy(this.wheel, this)); - } - - if (options.toggleDragModeOnDblclick) { - $cropper.on(EVENT_DBLCLICK, $.proxy(this.dblclick, this)); - } - - $document. - on(EVENT_MOUSE_MOVE, (this._cropMove = proxy(this.cropMove, this))). - on(EVENT_MOUSE_UP, (this._cropEnd = proxy(this.cropEnd, this))); - - if (options.responsive) { - $window.on(EVENT_RESIZE, (this._resize = proxy(this.resize, this))); - } - }, - - unbind: function () { - var options = this.options; - var $this = this.$element; - var $cropper = this.$cropper; - - if ($.isFunction(options.cropstart)) { - $this.off(EVENT_CROP_START, options.cropstart); - } - - if ($.isFunction(options.cropmove)) { - $this.off(EVENT_CROP_MOVE, options.cropmove); - } - - if ($.isFunction(options.cropend)) { - $this.off(EVENT_CROP_END, options.cropend); - } - - if ($.isFunction(options.crop)) { - $this.off(EVENT_CROP, options.crop); - } - - if ($.isFunction(options.zoom)) { - $this.off(EVENT_ZOOM, options.zoom); - } - - $cropper.off(EVENT_MOUSE_DOWN, this.cropStart); - - if (options.zoomable && options.zoomOnWheel) { - $cropper.off(EVENT_WHEEL, this.wheel); - } - - if (options.toggleDragModeOnDblclick) { - $cropper.off(EVENT_DBLCLICK, this.dblclick); - } - - $document. - off(EVENT_MOUSE_MOVE, this._cropMove). - off(EVENT_MOUSE_UP, this._cropEnd); - - if (options.responsive) { - $window.off(EVENT_RESIZE, this._resize); - } - }, - - resize: function () { - var restore = this.options.restore; - var $container = this.$container; - var container = this.container; - var canvasData; - var cropBoxData; - var ratio; - - // Check `container` is necessary for IE8 - if (this.isDisabled || !container) { - return; - } - - ratio = $container.width() / container.width; - - // Resize when width changed or height changed - if (ratio !== 1 || $container.height() !== container.height) { - if (restore) { - canvasData = this.getCanvasData(); - cropBoxData = this.getCropBoxData(); - } - - this.render(); - - if (restore) { - this.setCanvasData($.each(canvasData, function (i, n) { - canvasData[i] = n * ratio; - })); - this.setCropBoxData($.each(cropBoxData, function (i, n) { - cropBoxData[i] = n * ratio; - })); - } - } - }, - - dblclick: function () { - if (this.isDisabled) { - return; - } - - if (this.$dragBox.hasClass(CLASS_CROP)) { - this.setDragMode(ACTION_MOVE); - } else { - this.setDragMode(ACTION_CROP); - } - }, - - wheel: function (event) { - var e = event.originalEvent || event; - var ratio = num(this.options.wheelZoomRatio) || 0.1; - var delta = 1; - - if (this.isDisabled) { - return; - } - - event.preventDefault(); - - // Limit wheel speed to prevent zoom too fast - if (this.wheeling) { - return; - } - - this.wheeling = true; - - setTimeout($.proxy(function () { - this.wheeling = false; - }, this), 50); - - if (e.deltaY) { - delta = e.deltaY > 0 ? 1 : -1; - } else if (e.wheelDelta) { - delta = -e.wheelDelta / 120; - } else if (e.detail) { - delta = e.detail > 0 ? 1 : -1; - } - - this.zoom(-delta * ratio, event); - }, - - cropStart: function (event) { - var options = this.options; - var originalEvent = event.originalEvent; - var touches = originalEvent && originalEvent.touches; - var e = event; - var touchesLength; - var action; - - if (this.isDisabled) { - return; - } - - if (touches) { - touchesLength = touches.length; - - if (touchesLength > 1) { - if (options.zoomable && options.zoomOnTouch && touchesLength === 2) { - e = touches[1]; - this.startX2 = e.pageX; - this.startY2 = e.pageY; - action = ACTION_ZOOM; - } else { - return; - } - } - - e = touches[0]; - } - - action = action || $(e.target).data(DATA_ACTION); - - if (REGEXP_ACTIONS.test(action)) { - if (this.trigger(EVENT_CROP_START, { - originalEvent: originalEvent, - action: action - }).isDefaultPrevented()) { - return; - } - - event.preventDefault(); - - this.action = action; - this.cropping = false; - - // IE8 has `event.pageX/Y`, but not `event.originalEvent.pageX/Y` - // IE10 has `event.originalEvent.pageX/Y`, but not `event.pageX/Y` - this.startX = e.pageX || originalEvent && originalEvent.pageX; - this.startY = e.pageY || originalEvent && originalEvent.pageY; - - if (action === ACTION_CROP) { - this.cropping = true; - this.$dragBox.addClass(CLASS_MODAL); - } - } - }, - - cropMove: function (event) { - var options = this.options; - var originalEvent = event.originalEvent; - var touches = originalEvent && originalEvent.touches; - var e = event; - var action = this.action; - var touchesLength; - - if (this.isDisabled) { - return; - } - - if (touches) { - touchesLength = touches.length; - - if (touchesLength > 1) { - if (options.zoomable && options.zoomOnTouch && touchesLength === 2) { - e = touches[1]; - this.endX2 = e.pageX; - this.endY2 = e.pageY; - } else { - return; - } - } - - e = touches[0]; - } - - if (action) { - if (this.trigger(EVENT_CROP_MOVE, { - originalEvent: originalEvent, - action: action - }).isDefaultPrevented()) { - return; - } - - event.preventDefault(); - - this.endX = e.pageX || originalEvent && originalEvent.pageX; - this.endY = e.pageY || originalEvent && originalEvent.pageY; - - this.change(e.shiftKey, action === ACTION_ZOOM ? event : null); - } - }, - - cropEnd: function (event) { - var originalEvent = event.originalEvent; - var action = this.action; - - if (this.isDisabled) { - return; - } - - if (action) { - event.preventDefault(); - - if (this.cropping) { - this.cropping = false; - this.$dragBox.toggleClass(CLASS_MODAL, this.isCropped && this.options.modal); - } - - this.action = ''; - - this.trigger(EVENT_CROP_END, { - originalEvent: originalEvent, - action: action - }); - } - }, - - change: function (shiftKey, event) { - var options = this.options; - var aspectRatio = options.aspectRatio; - var action = this.action; - var container = this.container; - var canvas = this.canvas; - var cropBox = this.cropBox; - var width = cropBox.width; - var height = cropBox.height; - var left = cropBox.left; - var top = cropBox.top; - var right = left + width; - var bottom = top + height; - var minLeft = 0; - var minTop = 0; - var maxWidth = container.width; - var maxHeight = container.height; - var renderable = true; - var offset; - var range; - - // Locking aspect ratio in "free mode" by holding shift key (#259) - if (!aspectRatio && shiftKey) { - aspectRatio = width && height ? width / height : 1; - } - - if (this.limited) { - minLeft = cropBox.minLeft; - minTop = cropBox.minTop; - maxWidth = minLeft + min(container.width, canvas.left + canvas.width); - maxHeight = minTop + min(container.height, canvas.top + canvas.height); - } - - range = { - x: this.endX - this.startX, - y: this.endY - this.startY - }; - - if (aspectRatio) { - range.X = range.y * aspectRatio; - range.Y = range.x / aspectRatio; - } - - switch (action) { - // Move crop box - case ACTION_ALL: - left += range.x; - top += range.y; - break; - - // Resize crop box - case ACTION_EAST: - if (range.x >= 0 && (right >= maxWidth || aspectRatio && - (top <= minTop || bottom >= maxHeight))) { - - renderable = false; - break; - } - - width += range.x; - - if (aspectRatio) { - height = width / aspectRatio; - top -= range.Y / 2; - } - - if (width < 0) { - action = ACTION_WEST; - width = 0; - } - - break; - - case ACTION_NORTH: - if (range.y <= 0 && (top <= minTop || aspectRatio && - (left <= minLeft || right >= maxWidth))) { - - renderable = false; - break; - } - - height -= range.y; - top += range.y; - - if (aspectRatio) { - width = height * aspectRatio; - left += range.X / 2; - } - - if (height < 0) { - action = ACTION_SOUTH; - height = 0; - } - - break; - - case ACTION_WEST: - if (range.x <= 0 && (left <= minLeft || aspectRatio && - (top <= minTop || bottom >= maxHeight))) { - - renderable = false; - break; - } - - width -= range.x; - left += range.x; - - if (aspectRatio) { - height = width / aspectRatio; - top += range.Y / 2; - } - - if (width < 0) { - action = ACTION_EAST; - width = 0; - } - - break; - - case ACTION_SOUTH: - if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && - (left <= minLeft || right >= maxWidth))) { - - renderable = false; - break; - } - - height += range.y; - - if (aspectRatio) { - width = height * aspectRatio; - left -= range.X / 2; - } - - if (height < 0) { - action = ACTION_NORTH; - height = 0; - } - - break; - - case ACTION_NORTH_EAST: - if (aspectRatio) { - if (range.y <= 0 && (top <= minTop || right >= maxWidth)) { - renderable = false; - break; - } - - height -= range.y; - top += range.y; - width = height * aspectRatio; - } else { - if (range.x >= 0) { - if (right < maxWidth) { - width += range.x; - } else if (range.y <= 0 && top <= minTop) { - renderable = false; - } - } else { - width += range.x; - } - - if (range.y <= 0) { - if (top > minTop) { - height -= range.y; - top += range.y; - } - } else { - height -= range.y; - top += range.y; - } - } - - if (width < 0 && height < 0) { - action = ACTION_SOUTH_WEST; - height = 0; - width = 0; - } else if (width < 0) { - action = ACTION_NORTH_WEST; - width = 0; - } else if (height < 0) { - action = ACTION_SOUTH_EAST; - height = 0; - } - - break; - - case ACTION_NORTH_WEST: - if (aspectRatio) { - if (range.y <= 0 && (top <= minTop || left <= minLeft)) { - renderable = false; - break; - } - - height -= range.y; - top += range.y; - width = height * aspectRatio; - left += range.X; - } else { - if (range.x <= 0) { - if (left > minLeft) { - width -= range.x; - left += range.x; - } else if (range.y <= 0 && top <= minTop) { - renderable = false; - } - } else { - width -= range.x; - left += range.x; - } - - if (range.y <= 0) { - if (top > minTop) { - height -= range.y; - top += range.y; - } - } else { - height -= range.y; - top += range.y; - } - } - - if (width < 0 && height < 0) { - action = ACTION_SOUTH_EAST; - height = 0; - width = 0; - } else if (width < 0) { - action = ACTION_NORTH_EAST; - width = 0; - } else if (height < 0) { - action = ACTION_SOUTH_WEST; - height = 0; - } - - break; - - case ACTION_SOUTH_WEST: - if (aspectRatio) { - if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) { - renderable = false; - break; - } - - width -= range.x; - left += range.x; - height = width / aspectRatio; - } else { - if (range.x <= 0) { - if (left > minLeft) { - width -= range.x; - left += range.x; - } else if (range.y >= 0 && bottom >= maxHeight) { - renderable = false; - } - } else { - width -= range.x; - left += range.x; - } - - if (range.y >= 0) { - if (bottom < maxHeight) { - height += range.y; - } - } else { - height += range.y; - } - } - - if (width < 0 && height < 0) { - action = ACTION_NORTH_EAST; - height = 0; - width = 0; - } else if (width < 0) { - action = ACTION_SOUTH_EAST; - width = 0; - } else if (height < 0) { - action = ACTION_NORTH_WEST; - height = 0; - } - - break; - - case ACTION_SOUTH_EAST: - if (aspectRatio) { - if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) { - renderable = false; - break; - } - - width += range.x; - height = width / aspectRatio; - } else { - if (range.x >= 0) { - if (right < maxWidth) { - width += range.x; - } else if (range.y >= 0 && bottom >= maxHeight) { - renderable = false; - } - } else { - width += range.x; - } - - if (range.y >= 0) { - if (bottom < maxHeight) { - height += range.y; - } - } else { - height += range.y; - } - } - - if (width < 0 && height < 0) { - action = ACTION_NORTH_WEST; - height = 0; - width = 0; - } else if (width < 0) { - action = ACTION_SOUTH_WEST; - width = 0; - } else if (height < 0) { - action = ACTION_NORTH_EAST; - height = 0; - } - - break; - - // Move canvas - case ACTION_MOVE: - this.move(range.x, range.y); - renderable = false; - break; - - // Zoom canvas - case ACTION_ZOOM: - this.zoom((function (x1, y1, x2, y2) { - var z1 = sqrt(x1 * x1 + y1 * y1); - var z2 = sqrt(x2 * x2 + y2 * y2); - - return (z2 - z1) / z1; - })( - abs(this.startX - this.startX2), - abs(this.startY - this.startY2), - abs(this.endX - this.endX2), - abs(this.endY - this.endY2) - ), event); - this.startX2 = this.endX2; - this.startY2 = this.endY2; - renderable = false; - break; - - // Create crop box - case ACTION_CROP: - if (!range.x || !range.y) { - renderable = false; - break; - } - - offset = this.$cropper.offset(); - left = this.startX - offset.left; - top = this.startY - offset.top; - width = cropBox.minWidth; - height = cropBox.minHeight; - - if (range.x > 0) { - action = range.y > 0 ? ACTION_SOUTH_EAST : ACTION_NORTH_EAST; - } else if (range.x < 0) { - left -= width; - action = range.y > 0 ? ACTION_SOUTH_WEST : ACTION_NORTH_WEST; - } - - if (range.y < 0) { - top -= height; - } - - // Show the crop box if is hidden - if (!this.isCropped) { - this.$cropBox.removeClass(CLASS_HIDDEN); - this.isCropped = true; - - if (this.limited) { - this.limitCropBox(true, true); - } - } - - break; - - // No default - } - - if (renderable) { - cropBox.width = width; - cropBox.height = height; - cropBox.left = left; - cropBox.top = top; - this.action = action; - - this.renderCropBox(); - } - - // Override - this.startX = this.endX; - this.startY = this.endY; - }, - - // Show the crop box manually - crop: function () { - if (!this.isBuilt || this.isDisabled) { - return; - } - - if (!this.isCropped) { - this.isCropped = true; - this.limitCropBox(true, true); - - if (this.options.modal) { - this.$dragBox.addClass(CLASS_MODAL); - } - - this.$cropBox.removeClass(CLASS_HIDDEN); - } - - this.setCropBoxData(this.initialCropBox); - }, - - // Reset the image and crop box to their initial states - reset: function () { - if (!this.isBuilt || this.isDisabled) { - return; - } - - this.image = $.extend({}, this.initialImage); - this.canvas = $.extend({}, this.initialCanvas); - this.cropBox = $.extend({}, this.initialCropBox); - - this.renderCanvas(); - - if (this.isCropped) { - this.renderCropBox(); - } - }, - - // Clear the crop box - clear: function () { - if (!this.isCropped || this.isDisabled) { - return; - } - - $.extend(this.cropBox, { - left: 0, - top: 0, - width: 0, - height: 0 - }); - - this.isCropped = false; - this.renderCropBox(); - - this.limitCanvas(true, true); - - // Render canvas after crop box rendered - this.renderCanvas(); - - this.$dragBox.removeClass(CLASS_MODAL); - this.$cropBox.addClass(CLASS_HIDDEN); - }, - - /** - * Replace the image's src and rebuild the cropper - * - * @param {String} url - * @param {Boolean} onlyColorChanged (optional) - */ - replace: function (url, onlyColorChanged) { - if (!this.isDisabled && url) { - if (this.isImg) { - this.$element.attr('src', url); - } - - if (onlyColorChanged) { - this.url = url; - this.$clone.attr('src', url); - - if (this.isBuilt) { - this.$preview.find('img').add(this.$clone2).attr('src', url); - } - } else { - if (this.isImg) { - this.isReplaced = true; - } - - // Clear previous data - this.options.data = null; - this.load(url); - } - } - }, - - // Enable (unfreeze) the cropper - enable: function () { - if (this.isBuilt) { - this.isDisabled = false; - this.$cropper.removeClass(CLASS_DISABLED); - } - }, - - // Disable (freeze) the cropper - disable: function () { - if (this.isBuilt) { - this.isDisabled = true; - this.$cropper.addClass(CLASS_DISABLED); - } - }, - - // Destroy the cropper and remove the instance from the image - destroy: function () { - var $this = this.$element; - - if (this.isLoaded) { - if (this.isImg && this.isReplaced) { - $this.attr('src', this.originalUrl); - } - - this.unbuild(); - $this.removeClass(CLASS_HIDDEN); - } else { - if (this.isImg) { - $this.off(EVENT_LOAD, this.start); - } else if (this.$clone) { - this.$clone.remove(); - } - } - - $this.removeData(NAMESPACE); - }, - - /** - * Move the canvas with relative offsets - * - * @param {Number} offsetX - * @param {Number} offsetY (optional) - */ - move: function (offsetX, offsetY) { - var canvas = this.canvas; - - this.moveTo( - isUndefined(offsetX) ? offsetX : canvas.left + num(offsetX), - isUndefined(offsetY) ? offsetY : canvas.top + num(offsetY) - ); - }, - - /** - * Move the canvas to an absolute point - * - * @param {Number} x - * @param {Number} y (optional) - */ - moveTo: function (x, y) { - var canvas = this.canvas; - var isChanged = false; - - // If "y" is not present, its default value is "x" - if (isUndefined(y)) { - y = x; - } - - x = num(x); - y = num(y); - - if (this.isBuilt && !this.isDisabled && this.options.movable) { - if (isNumber(x)) { - canvas.left = x; - isChanged = true; - } - - if (isNumber(y)) { - canvas.top = y; - isChanged = true; - } - - if (isChanged) { - this.renderCanvas(true); - } - } - }, - - /** - * Zoom the canvas with a relative ratio - * - * @param {Number} ratio - * @param {jQuery Event} _event (private) - */ - zoom: function (ratio, _event) { - var canvas = this.canvas; - - ratio = num(ratio); - - if (ratio < 0) { - ratio = 1 / (1 - ratio); - } else { - ratio = 1 + ratio; - } - - this.zoomTo(canvas.width * ratio / canvas.naturalWidth, _event); - }, - - /** - * Zoom the canvas to an absolute ratio - * - * @param {Number} ratio - * @param {jQuery Event} _event (private) - */ - zoomTo: function (ratio, _event) { - var options = this.options; - var canvas = this.canvas; - var width = canvas.width; - var height = canvas.height; - var naturalWidth = canvas.naturalWidth; - var naturalHeight = canvas.naturalHeight; - var originalEvent; - var newWidth; - var newHeight; - var offset; - var center; - - ratio = num(ratio); - - if (ratio >= 0 && this.isBuilt && !this.isDisabled && options.zoomable) { - newWidth = naturalWidth * ratio; - newHeight = naturalHeight * ratio; - - if (_event) { - originalEvent = _event.originalEvent; - } - - if (this.trigger(EVENT_ZOOM, { - originalEvent: originalEvent, - oldRatio: width / naturalWidth, - ratio: newWidth / naturalWidth - }).isDefaultPrevented()) { - return; - } - - if (originalEvent) { - offset = this.$cropper.offset(); - center = originalEvent.touches ? getTouchesCenter(originalEvent.touches) : { - pageX: _event.pageX || originalEvent.pageX || 0, - pageY: _event.pageY || originalEvent.pageY || 0 - }; - - // Zoom from the triggering point of the event - canvas.left -= (newWidth - width) * ( - ((center.pageX - offset.left) - canvas.left) / width - ); - canvas.top -= (newHeight - height) * ( - ((center.pageY - offset.top) - canvas.top) / height - ); - } else { - - // Zoom from the center of the canvas - canvas.left -= (newWidth - width) / 2; - canvas.top -= (newHeight - height) / 2; - } - - canvas.width = newWidth; - canvas.height = newHeight; - this.renderCanvas(true); - } - }, - - /** - * Rotate the canvas with a relative degree - * - * @param {Number} degree - */ - rotate: function (degree) { - this.rotateTo((this.image.rotate || 0) + num(degree)); - }, - - /** - * Rotate the canvas to an absolute degree - * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#rotate() - * - * @param {Number} degree - */ - rotateTo: function (degree) { - degree = num(degree); - - if (isNumber(degree) && this.isBuilt && !this.isDisabled && this.options.rotatable) { - this.image.rotate = degree % 360; - this.isRotated = true; - this.renderCanvas(true); - } - }, - - /** - * Scale the image - * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#scale() - * - * @param {Number} scaleX - * @param {Number} scaleY (optional) - */ - scale: function (scaleX, scaleY) { - var image = this.image; - var isChanged = false; - - // If "scaleY" is not present, its default value is "scaleX" - if (isUndefined(scaleY)) { - scaleY = scaleX; - } - - scaleX = num(scaleX); - scaleY = num(scaleY); - - if (this.isBuilt && !this.isDisabled && this.options.scalable) { - if (isNumber(scaleX)) { - image.scaleX = scaleX; - isChanged = true; - } - - if (isNumber(scaleY)) { - image.scaleY = scaleY; - isChanged = true; - } - - if (isChanged) { - this.renderImage(true); - } - } - }, - - /** - * Scale the abscissa of the image - * - * @param {Number} scaleX - */ - scaleX: function (scaleX) { - var scaleY = this.image.scaleY; - - this.scale(scaleX, isNumber(scaleY) ? scaleY : 1); - }, - - /** - * Scale the ordinate of the image - * - * @param {Number} scaleY - */ - scaleY: function (scaleY) { - var scaleX = this.image.scaleX; - - this.scale(isNumber(scaleX) ? scaleX : 1, scaleY); - }, - - /** - * Get the cropped area position and size data (base on the original image) - * - * @param {Boolean} isRounded (optional) - * @return {Object} data - */ - getData: function (isRounded) { - var options = this.options; - var image = this.image; - var canvas = this.canvas; - var cropBox = this.cropBox; - var ratio; - var data; - - if (this.isBuilt && this.isCropped) { - data = { - x: cropBox.left - canvas.left, - y: cropBox.top - canvas.top, - width: cropBox.width, - height: cropBox.height - }; - - ratio = image.width / image.naturalWidth; - - $.each(data, function (i, n) { - n = n / ratio; - data[i] = isRounded ? round(n) : n; - }); - - } else { - data = { - x: 0, - y: 0, - width: 0, - height: 0 - }; - } - - if (options.rotatable) { - data.rotate = image.rotate || 0; - } - - if (options.scalable) { - data.scaleX = image.scaleX || 1; - data.scaleY = image.scaleY || 1; - } - - return data; - }, - - /** - * Set the cropped area position and size with new data - * - * @param {Object} data - */ - setData: function (data) { - var options = this.options; - var image = this.image; - var canvas = this.canvas; - var cropBoxData = {}; - var isRotated; - var isScaled; - var ratio; - - if ($.isFunction(data)) { - data = data.call(this.element); - } - - if (this.isBuilt && !this.isDisabled && $.isPlainObject(data)) { - if (options.rotatable) { - if (isNumber(data.rotate) && data.rotate !== image.rotate) { - image.rotate = data.rotate; - this.isRotated = isRotated = true; - } - } - - if (options.scalable) { - if (isNumber(data.scaleX) && data.scaleX !== image.scaleX) { - image.scaleX = data.scaleX; - isScaled = true; - } - - if (isNumber(data.scaleY) && data.scaleY !== image.scaleY) { - image.scaleY = data.scaleY; - isScaled = true; - } - } - - if (isRotated) { - this.renderCanvas(); - } else if (isScaled) { - this.renderImage(); - } - - ratio = image.width / image.naturalWidth; - - if (isNumber(data.x)) { - cropBoxData.left = data.x * ratio + canvas.left; - } - - if (isNumber(data.y)) { - cropBoxData.top = data.y * ratio + canvas.top; - } - - if (isNumber(data.width)) { - cropBoxData.width = data.width * ratio; - } - - if (isNumber(data.height)) { - cropBoxData.height = data.height * ratio; - } - - this.setCropBoxData(cropBoxData); - } - }, - - /** - * Get the container size data - * - * @return {Object} data - */ - getContainerData: function () { - return this.isBuilt ? this.container : {}; - }, - - /** - * Get the image position and size data - * - * @return {Object} data - */ - getImageData: function () { - return this.isLoaded ? this.image : {}; - }, - - /** - * Get the canvas position and size data - * - * @return {Object} data - */ - getCanvasData: function () { - var canvas = this.canvas; - var data = {}; - - if (this.isBuilt) { - $.each([ - 'left', - 'top', - 'width', - 'height', - 'naturalWidth', - 'naturalHeight' - ], function (i, n) { - data[n] = canvas[n]; - }); - } - - return data; - }, - - /** - * Set the canvas position and size with new data - * - * @param {Object} data - */ - setCanvasData: function (data) { - var canvas = this.canvas; - var aspectRatio = canvas.aspectRatio; - - if ($.isFunction(data)) { - data = data.call(this.$element); - } - - if (this.isBuilt && !this.isDisabled && $.isPlainObject(data)) { - if (isNumber(data.left)) { - canvas.left = data.left; - } - - if (isNumber(data.top)) { - canvas.top = data.top; - } - - if (isNumber(data.width)) { - canvas.width = data.width; - canvas.height = data.width / aspectRatio; - } else if (isNumber(data.height)) { - canvas.height = data.height; - canvas.width = data.height * aspectRatio; - } - - this.renderCanvas(true); - } - }, - - /** - * Get the crop box position and size data - * - * @return {Object} data - */ - getCropBoxData: function () { - var cropBox = this.cropBox; - var data; - - if (this.isBuilt && this.isCropped) { - data = { - left: cropBox.left, - top: cropBox.top, - width: cropBox.width, - height: cropBox.height - }; - } - - return data || {}; - }, - - /** - * Set the crop box position and size with new data - * - * @param {Object} data - */ - setCropBoxData: function (data) { - var cropBox = this.cropBox; - var aspectRatio = this.options.aspectRatio; - var isWidthChanged; - var isHeightChanged; - - if ($.isFunction(data)) { - data = data.call(this.$element); - } - - if (this.isBuilt && this.isCropped && !this.isDisabled && $.isPlainObject(data)) { - - if (isNumber(data.left)) { - cropBox.left = data.left; - } - - if (isNumber(data.top)) { - cropBox.top = data.top; - } - - if (isNumber(data.width)) { - isWidthChanged = true; - cropBox.width = data.width; - } - - if (isNumber(data.height)) { - isHeightChanged = true; - cropBox.height = data.height; - } - - if (aspectRatio) { - if (isWidthChanged) { - cropBox.height = cropBox.width / aspectRatio; - } else if (isHeightChanged) { - cropBox.width = cropBox.height * aspectRatio; - } - } - - this.renderCropBox(); - } - }, - - /** - * Get a canvas drawn the cropped image - * - * @param {Object} options (optional) - * @return {HTMLCanvasElement} canvas - */ - getCroppedCanvas: function (options) { - var originalWidth; - var originalHeight; - var canvasWidth; - var canvasHeight; - var scaledWidth; - var scaledHeight; - var scaledRatio; - var aspectRatio; - var canvas; - var context; - var data; - - if (!this.isBuilt || !this.isCropped || !SUPPORT_CANVAS) { - return; - } - - if (!$.isPlainObject(options)) { - options = {}; - } - - data = this.getData(); - originalWidth = data.width; - originalHeight = data.height; - aspectRatio = originalWidth / originalHeight; - - if ($.isPlainObject(options)) { - scaledWidth = options.width; - scaledHeight = options.height; - - if (scaledWidth) { - scaledHeight = scaledWidth / aspectRatio; - scaledRatio = scaledWidth / originalWidth; - } else if (scaledHeight) { - scaledWidth = scaledHeight * aspectRatio; - scaledRatio = scaledHeight / originalHeight; - } - } - - // The canvas element will use `Math.floor` on a float number, so floor first - canvasWidth = floor(scaledWidth || originalWidth); - canvasHeight = floor(scaledHeight || originalHeight); - - canvas = $('')[0]; - canvas.width = canvasWidth; - canvas.height = canvasHeight; - context = canvas.getContext('2d'); - - if (options.fillColor) { - context.fillStyle = options.fillColor; - context.fillRect(0, 0, canvasWidth, canvasHeight); - } - - // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage - context.drawImage.apply(context, (function () { - var source = getSourceCanvas(this.$clone[0], this.image); - var sourceWidth = source.width; - var sourceHeight = source.height; - var canvas = this.canvas; - var params = [source]; - - // Source canvas - var srcX = data.x + canvas.naturalWidth * (abs(data.scaleX || 1) - 1) / 2; - var srcY = data.y + canvas.naturalHeight * (abs(data.scaleY || 1) - 1) / 2; - var srcWidth; - var srcHeight; - - // Destination canvas - var dstX; - var dstY; - var dstWidth; - var dstHeight; - - if (srcX <= -originalWidth || srcX > sourceWidth) { - srcX = srcWidth = dstX = dstWidth = 0; - } else if (srcX <= 0) { - dstX = -srcX; - srcX = 0; - srcWidth = dstWidth = min(sourceWidth, originalWidth + srcX); - } else if (srcX <= sourceWidth) { - dstX = 0; - srcWidth = dstWidth = min(originalWidth, sourceWidth - srcX); - } - - if (srcWidth <= 0 || srcY <= -originalHeight || srcY > sourceHeight) { - srcY = srcHeight = dstY = dstHeight = 0; - } else if (srcY <= 0) { - dstY = -srcY; - srcY = 0; - srcHeight = dstHeight = min(sourceHeight, originalHeight + srcY); - } else if (srcY <= sourceHeight) { - dstY = 0; - srcHeight = dstHeight = min(originalHeight, sourceHeight - srcY); - } - - // All the numerical parameters should be integer for `drawImage` (#476) - params.push(floor(srcX), floor(srcY), floor(srcWidth), floor(srcHeight)); - - // Scale destination sizes - if (scaledRatio) { - dstX *= scaledRatio; - dstY *= scaledRatio; - dstWidth *= scaledRatio; - dstHeight *= scaledRatio; - } - - // Avoid "IndexSizeError" in IE and Firefox - if (dstWidth > 0 && dstHeight > 0) { - params.push(floor(dstX), floor(dstY), floor(dstWidth), floor(dstHeight)); - } - - return params; - }).call(this)); - - return canvas; - }, - - /** - * Change the aspect ratio of the crop box - * - * @param {Number} aspectRatio - */ - setAspectRatio: function (aspectRatio) { - var options = this.options; - - if (!this.isDisabled && !isUndefined(aspectRatio)) { - - // 0 -> NaN - options.aspectRatio = max(0, aspectRatio) || NaN; - - if (this.isBuilt) { - this.initCropBox(); - - if (this.isCropped) { - this.renderCropBox(); - } - } - } - }, - - /** - * Change the drag mode - * - * @param {String} mode (optional) - */ - setDragMode: function (mode) { - var options = this.options; - var croppable; - var movable; - - if (this.isLoaded && !this.isDisabled) { - croppable = mode === ACTION_CROP; - movable = options.movable && mode === ACTION_MOVE; - mode = (croppable || movable) ? mode : ACTION_NONE; - - this.$dragBox. - data(DATA_ACTION, mode). - toggleClass(CLASS_CROP, croppable). - toggleClass(CLASS_MOVE, movable); - - if (!options.cropBoxMovable) { - - // Sync drag mode to crop box when it is not movable(#300) - this.$face. - data(DATA_ACTION, mode). - toggleClass(CLASS_CROP, croppable). - toggleClass(CLASS_MOVE, movable); - } - } - } - }; - - Cropper.DEFAULTS = { - - // Define the view mode of the cropper - viewMode: 0, // 0, 1, 2, 3 - - // Define the dragging mode of the cropper - dragMode: 'crop', // 'crop', 'move' or 'none' - - // Define the aspect ratio of the crop box - aspectRatio: NaN, - - // An object with the previous cropping result data - data: null, - - // A jQuery selector for adding extra containers to preview - preview: '', - - // Re-render the cropper when resize the window - responsive: true, - - // Restore the cropped area after resize the window - restore: true, - - // Check if the current image is a cross-origin image - checkCrossOrigin: true, - - // Check the current image's Exif Orientation information - checkOrientation: true, - - // Show the black modal - modal: true, - - // Show the dashed lines for guiding - guides: true, - - // Show the center indicator for guiding - center: true, - - // Show the white modal to highlight the crop box - highlight: true, - - // Show the grid background - background: true, - - // Enable to crop the image automatically when initialize - autoCrop: true, - - // Define the percentage of automatic cropping area when initializes - autoCropArea: 0.8, - - // Enable to move the image - movable: true, - - // Enable to rotate the image - rotatable: true, - - // Enable to scale the image - scalable: true, - - // Enable to zoom the image - zoomable: true, - - // Enable to zoom the image by dragging touch - zoomOnTouch: true, - - // Enable to zoom the image by wheeling mouse - zoomOnWheel: true, - - // Define zoom ratio when zoom the image by wheeling mouse - wheelZoomRatio: 0.1, - - // Enable to move the crop box - cropBoxMovable: true, - - // Enable to resize the crop box - cropBoxResizable: true, - - // Toggle drag mode between "crop" and "move" when click twice on the cropper - toggleDragModeOnDblclick: true, - - // Size limitation - minCanvasWidth: 0, - minCanvasHeight: 0, - minCropBoxWidth: 0, - minCropBoxHeight: 0, - minContainerWidth: 200, - minContainerHeight: 100, - - // Shortcuts of events - build: null, - built: null, - cropstart: null, - cropmove: null, - cropend: null, - crop: null, - zoom: null - }; - - Cropper.setDefaults = function (options) { - $.extend(Cropper.DEFAULTS, options); - }; - - Cropper.TEMPLATE = ( - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
' + - '
' - ); - - // Save the other cropper - Cropper.other = $.fn.cropper; - - // Register as jQuery plugin - $.fn.cropper = function (option) { - var args = toArray(arguments, 1); - var result; - - this.each(function () { - var $this = $(this); - var data = $this.data(NAMESPACE); - var options; - var fn; - - if (!data) { - if (/destroy/.test(option)) { - return; - } - - options = $.extend({}, $this.data(), $.isPlainObject(option) && option); - $this.data(NAMESPACE, (data = new Cropper(this, options))); - } - - if (typeof option === 'string' && $.isFunction(fn = data[option])) { - result = fn.apply(data, args); - } - }); - - return isUndefined(result) ? this : result; - }; - - $.fn.cropper.Constructor = Cropper; - $.fn.cropper.setDefaults = Cropper.setDefaults; - - // No conflict - $.fn.cropper.noConflict = function () { - $.fn.cropper = Cropper.other; - return this; - }; - -}); diff --git a/yarn.lock b/yarn.lock index 98da6a984d1..d56d7272fe2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1409,6 +1409,12 @@ create-hmac@^1.1.0, create-hmac@^1.1.2: create-hash "^1.1.0" inherits "^2.0.1" +cropper@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cropper/-/cropper-2.3.0.tgz#607461d4e7aa7a7fe15a26834b14b7f0c2801562" + dependencies: + jquery ">= 1.9.1" + cryptiles@2.x.x: version "2.0.5" resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" @@ -3169,7 +3175,7 @@ jquery-ujs@^1.2.1: dependencies: jquery ">=1.8.0" -jquery@>=1.8.0, jquery@^2.2.1: +"jquery@>= 1.9.1", jquery@>=1.8.0, jquery@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/jquery/-/jquery-2.2.1.tgz#3c3e16854ad3d2ac44ac65021b17426d22ad803f" -- cgit v1.2.1 From caeaa704207fa475fb3050aecddc72af4ff75390 Mon Sep 17 00:00:00 2001 From: Marcia Ramos Date: Tue, 1 Aug 2017 11:45:39 -0300 Subject: link to CI/CD Deep Dive demo for #5800 --- doc/ci/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/ci/README.md b/doc/ci/README.md index ca7266ac68f..10ea9467942 100644 --- a/doc/ci/README.md +++ b/doc/ci/README.md @@ -23,6 +23,7 @@ The first steps towards your GitLab CI journey. - [Setting up GitLab Runner For Continuous Integration](https://about.gitlab.com/2016/03/01/gitlab-runner-with-docker/) - [GitLab CI: Deployment & environments](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/) - **Videos:** + - [Demo (Streamed live on Jul 17, 2017): GitLab CI/CD Deep Dive](https://youtu.be/pBe4t1CD8Fc?t=195) - [Demo (March, 2017): how to get started using CI/CD with GitLab](https://about.gitlab.com/2017/03/13/ci-cd-demo/) - [Webcast (April, 2016): getting started with CI in GitLab](https://about.gitlab.com/2016/04/20/webcast-recording-and-slides-introduction-to-ci-in-gitlab/) - **Third-party videos:** -- cgit v1.2.1 From 51332ca02f5696ed1876c5ff1affeda67ba2d25c Mon Sep 17 00:00:00 2001 From: Marcia Ramos Date: Tue, 1 Aug 2017 11:57:23 -0300 Subject: add article to list also, trigger build --- doc/articles/index.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/articles/index.md b/doc/articles/index.md index 260940e129b..9d2e5956029 100644 --- a/doc/articles/index.md +++ b/doc/articles/index.md @@ -92,10 +92,11 @@ Explore the best of GitLab's software development's capabilities: | [Making CI Easier with GitLab](https://about.gitlab.com/2017/07/13/making-ci-easier-with-gitlab/) | Concepts | 2017/07/13 | | [From 2/3 of the Self-Hosted Git Market, to the Next-Generation CI System, to Auto DevOps](https://about.gitlab.com/2017/06/29/whats-next-for-gitlab-ci/)| Concepts | 2017/06/29 | | [Fast and Natural Continuous Integration with GitLab CI](https://about.gitlab.com/2017/05/22/fast-and-natural-continuous-integration-with-gitlab-ci/) | Concepts | 2017/05/22 | +| [Demo: Auto-Deploy from GitLab to an OpenShift Container Cluster](https://about.gitlab.com/2017/05/16/devops-containers-gitlab-openshift/) | Technical overview | 2017/05/16 | | [Demo: GitLab Service Desk](https://about.gitlab.com/2017/05/09/demo-service-desk/) | Feature highlight | 2017/05/09 | -| [Demo - Mapping Work Versus Time, With Burndown Charts](https://about.gitlab.com/2017/04/25/mapping-work-to-do-versus-time-with-burndown-charts/) | Feature highlight | 2017/04/25 | -| [Demo – Cloud Native Development with GitLab](https://about.gitlab.com/2017/04/18/cloud-native-demo/) | Feature highlight | 2017/04/18 | -| [Demo - Mastering Code Review With GitLab](https://about.gitlab.com/2017/03/17/demo-mastering-code-review-with-gitlab/) | Feature highlight | 2017/03/17 | +| [Demo: Mapping Work Versus Time, With Burndown Charts](https://about.gitlab.com/2017/04/25/mapping-work-to-do-versus-time-with-burndown-charts/) | Feature highlight | 2017/04/25 | +| [Demo: Cloud Native Development with GitLab](https://about.gitlab.com/2017/04/18/cloud-native-demo/) | Feature highlight | 2017/04/18 | +| [Demo: Mastering Code Review With GitLab](https://about.gitlab.com/2017/03/17/demo-mastering-code-review-with-gitlab/) | Feature highlight | 2017/03/17 | | [In 13 minutes from Kubernetes to a complete application development tool](https://about.gitlab.com/2016/11/14/idea-to-production/) | Technical overview | 2016/11/14 | | [GitLab Workflow, an Overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/) | Technical overview | 2016/10/25 | | [Trends in Version Control Land: Microservices](https://about.gitlab.com/2016/08/16/trends-in-version-control-land-microservices/) | Concepts | 2016/08/16 | -- cgit v1.2.1 From d3ddc69b54a70fbd2332a21d18babd55f240e5a6 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 1 Aug 2017 17:24:37 +0200 Subject: Add rugged_is_ancestor method --- app/models/repository.rb | 2 +- lib/gitlab/git/repository.rb | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 7ea9f1459a0..4e9fe759fdc 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -944,7 +944,7 @@ class Repository if is_enabled raw_repository.is_ancestor?(ancestor_id, descendant_id) else - merge_base_commit(ancestor_id, descendant_id) == ancestor_id + rugged_is_ancestor?(ancestor_id, descendant_id) end end end diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 88529ba2c47..70d793f8e4a 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -353,6 +353,13 @@ module Gitlab rugged.merge_base(from, to) end + # Gitaly note: JV: check gitlab-ee before removing this method. + def rugged_is_ancestor?(ancestor_id, descendant_id) + return false if ancestor_id.nil? || descendant_id.nil? + + merge_base_commit(ancestor_id, descendant_id) == ancestor_id + end + # Returns true is +from+ is direct ancestor to +to+, otherwise false def is_ancestor?(from, to) gitaly_commit_client.is_ancestor(from, to) -- cgit v1.2.1 From 939e9bdde144849cbc11091985bca0a27f6e75ac Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 1 Aug 2017 12:55:57 -0400 Subject: Make the 'issuables list meta-data' shared example less dangerous This shared example would take an object's database ID and create a number of objects based on it. If for some reason the ID were a high number, like 20, this would create `20 + 21 + 22` objects. Not only was this dangerous from a performance perspective, it was entirely unnecessary, as the behavior it was testing is already well-tested in the unit test for the underlying object. For a controller test, which is what's including this shared example, all we need to do is verify that the assigned object contains the correct `id => object` Hash, which is what we now test for. --- spec/controllers/projects/merge_requests_controller_spec.rb | 4 +++- spec/support/issuables_list_metadata_shared_examples.rb | 11 +++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 0bfe83f1d98..216c59d3ae9 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -106,7 +106,7 @@ describe Projects::MergeRequestsController do end describe 'GET index' do - let!(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) } + let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) } def get_merge_requests(page = nil) get :index, @@ -150,6 +150,8 @@ describe Projects::MergeRequestsController do context 'when filtering by opened state' do context 'with opened merge requests' do it 'lists those merge requests' do + expect(merge_request).to be_persisted + get_merge_requests expect(assigns(:merge_requests)).to include(merge_request) diff --git a/spec/support/issuables_list_metadata_shared_examples.rb b/spec/support/issuables_list_metadata_shared_examples.rb index 3406e4c3161..1004c895bb4 100644 --- a/spec/support/issuables_list_metadata_shared_examples.rb +++ b/spec/support/issuables_list_metadata_shared_examples.rb @@ -11,10 +11,6 @@ shared_examples 'issuables list meta-data' do |issuable_type, action = nil| end @issuable_ids << issuable.id - - issuable.id.times { create(:note, noteable: issuable, project: issuable.project) } - (issuable.id + 1).times { create(:award_emoji, :downvote, awardable: issuable) } - (issuable.id + 2).times { create(:award_emoji, :upvote, awardable: issuable) } end end @@ -27,10 +23,9 @@ shared_examples 'issuables list meta-data' do |issuable_type, action = nil| meta_data = assigns(:issuable_meta_data) - @issuable_ids.each do |id| - expect(meta_data[id].notes_count).to eq(id) - expect(meta_data[id].downvotes).to eq(id + 1) - expect(meta_data[id].upvotes).to eq(id + 2) + aggregate_failures do + expect(meta_data.keys).to match_array(@issuable_ids) + expect(meta_data.values).to all(be_kind_of(Issuable::IssuableMeta)) end end -- cgit v1.2.1 From 0135d57b017e4b044511249d534bd26ab77c063d Mon Sep 17 00:00:00 2001 From: Alexander Randa Date: Tue, 1 Aug 2017 17:30:29 +0300 Subject: Fix encoding error for WebHook logging --- app/services/web_hook_service.rb | 8 +++++++- .../unreleased/35815-webhook-log-encoding-error.yml | 4 ++++ spec/services/web_hook_service_spec.rb | 17 +++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/35815-webhook-log-encoding-error.yml diff --git a/app/services/web_hook_service.rb b/app/services/web_hook_service.rb index 27c3ba197ac..2825478926a 100644 --- a/app/services/web_hook_service.rb +++ b/app/services/web_hook_service.rb @@ -101,7 +101,7 @@ class WebHookService request_headers: build_headers(hook_name), request_data: request_data, response_headers: format_response_headers(response), - response_body: response.body, + response_body: safe_response_body(response), response_status: response.code, internal_error_message: error_message ) @@ -124,4 +124,10 @@ class WebHookService def format_response_headers(response) response.headers.each_capitalized.to_h end + + def safe_response_body(response) + return '' unless response.body + + response.body.encode('UTF-8', invalid: :replace, undef: :replace, replace: '') + end end diff --git a/changelogs/unreleased/35815-webhook-log-encoding-error.yml b/changelogs/unreleased/35815-webhook-log-encoding-error.yml new file mode 100644 index 00000000000..76ec235086c --- /dev/null +++ b/changelogs/unreleased/35815-webhook-log-encoding-error.yml @@ -0,0 +1,4 @@ +--- +title: Fix encoding error for WebHook logging +merge_request: 13230 +author: Alexander Randa (@randaalex) diff --git a/spec/services/web_hook_service_spec.rb b/spec/services/web_hook_service_spec.rb index e79c12daa1c..0d710db812c 100644 --- a/spec/services/web_hook_service_spec.rb +++ b/spec/services/web_hook_service_spec.rb @@ -112,6 +112,23 @@ describe WebHookService do end end + context 'with unsafe response body' do + before do + WebMock.stub_request(:post, project_hook.url).to_return(status: 200, body: "\xBB") + service_instance.execute + end + + it 'log successful execution' do + expect(hook_log.trigger).to eq('push_hooks') + expect(hook_log.url).to eq(project_hook.url) + expect(hook_log.request_headers).to eq(headers) + expect(hook_log.response_body).to eq('') + expect(hook_log.response_status).to eq('200') + expect(hook_log.execution_duration).to be > 0 + expect(hook_log.internal_error_message).to be_nil + end + end + context 'should not log ServiceHooks' do let(:service_hook) { create(:service_hook) } let(:service_instance) { described_class.new(service_hook, data, 'service_hook') } -- cgit v1.2.1 From 4546ecd67ab2497af51144120667737e773e2dcc Mon Sep 17 00:00:00 2001 From: Winnie Hellmann Date: Tue, 1 Aug 2017 18:06:06 +0000 Subject: Derive project path from import URL --- app/assets/javascripts/projects/project_new.js | 64 +++++++++-- changelogs/unreleased/winh-derive-project-name.yml | 4 + spec/javascripts/projects/project_new_spec.js | 127 +++++++++++++++++++++ 3 files changed, 184 insertions(+), 11 deletions(-) create mode 100644 changelogs/unreleased/winh-derive-project-name.yml create mode 100644 spec/javascripts/projects/project_new_spec.js diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js index 2091b275c3d..1dc1dbf356d 100644 --- a/app/assets/javascripts/projects/project_new.js +++ b/app/assets/javascripts/projects/project_new.js @@ -1,6 +1,40 @@ -document.addEventListener('DOMContentLoaded', () => { +let hasUserDefinedProjectPath = false; + +const deriveProjectPathFromUrl = ($projectImportUrl, $projectPath) => { + if ($projectImportUrl.attr('disabled') || hasUserDefinedProjectPath) { + return; + } + + let importUrl = $projectImportUrl.val().trim(); + if (importUrl.length === 0) { + return; + } + + /* + \/?: remove trailing slash + (\.git\/?)?: remove trailing .git (with optional trailing slash) + (\?.*)?: remove query string + (#.*)?: remove fragment identifier + */ + importUrl = importUrl.replace(/\/?(\.git\/?)?(\?.*)?(#.*)?$/, ''); + + // extract everything after the last slash + const pathMatch = /\/([^/]+)$/.exec(importUrl); + if (pathMatch) { + $projectPath.val(pathMatch[1]); + } +}; + +const bindEvents = () => { + const $newProjectForm = $('#new_project'); const importBtnTooltip = 'Please enter a valid project name.'; const $importBtnWrapper = $('.import_gitlab_project'); + const $projectImportUrl = $('#project_import_url'); + const $projectPath = $('#project_path'); + + if ($newProjectForm.length !== 1) { + return; + } $('.how_to_import_link').on('click', (e) => { e.preventDefault(); @@ -13,19 +47,19 @@ document.addEventListener('DOMContentLoaded', () => { $('.btn_import_gitlab_project').on('click', () => { const importHref = $('a.btn_import_gitlab_project').attr('href'); - $('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$('#project_path').val()}`); + $('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$projectPath.val()}`); }); - $('.btn_import_gitlab_project').attr('disabled', !$('#project_path').val().trim().length); + $('.btn_import_gitlab_project').attr('disabled', !$projectPath.val().trim().length); $importBtnWrapper.attr('title', importBtnTooltip); - $('#new_project').on('submit', () => { - const $path = $('#project_path'); - $path.val($path.val().trim()); + $newProjectForm.on('submit', () => { + $projectPath.val($projectPath.val().trim()); }); - $('#project_path').on('keyup', () => { - if ($('#project_path').val().trim().length) { + $projectPath.on('keyup', () => { + hasUserDefinedProjectPath = $projectPath.val().trim().length > 0; + if (hasUserDefinedProjectPath) { $('.btn_import_gitlab_project').attr('disabled', false); $importBtnWrapper.attr('title', ''); $importBtnWrapper.removeClass('has-tooltip'); @@ -35,9 +69,17 @@ document.addEventListener('DOMContentLoaded', () => { } }); - $('#project_import_url').disable(); + $projectImportUrl.disable(); + $projectImportUrl.keyup(() => deriveProjectPathFromUrl($projectImportUrl, $projectPath)); + $('.import_git').on('click', () => { - const $projectImportUrl = $('#project_import_url'); $projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled')); }); -}); +}; + +document.addEventListener('DOMContentLoaded', bindEvents); + +export default { + bindEvents, + deriveProjectPathFromUrl, +}; diff --git a/changelogs/unreleased/winh-derive-project-name.yml b/changelogs/unreleased/winh-derive-project-name.yml new file mode 100644 index 00000000000..2244d21d768 --- /dev/null +++ b/changelogs/unreleased/winh-derive-project-name.yml @@ -0,0 +1,4 @@ +--- +title: Derive project path from import URL +merge_request: 13131 +author: diff --git a/spec/javascripts/projects/project_new_spec.js b/spec/javascripts/projects/project_new_spec.js new file mode 100644 index 00000000000..850768f0e4f --- /dev/null +++ b/spec/javascripts/projects/project_new_spec.js @@ -0,0 +1,127 @@ +import projectNew from '~/projects/project_new'; + +describe('New Project', () => { + let $projectImportUrl; + let $projectPath; + + beforeEach(() => { + setFixtures(` + + + `); + + $projectImportUrl = $('#project_import_url'); + $projectPath = $('#project_path'); + }); + + describe('deriveProjectPathFromUrl', () => { + const dummyImportUrl = `${gl.TEST_HOST}/dummy/import/url.git`; + + beforeEach(() => { + projectNew.bindEvents(); + $projectPath.val('').keyup().val(dummyImportUrl); + }); + + it('does not change project path for disabled $projectImportUrl', () => { + $projectImportUrl.attr('disabled', true); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual(dummyImportUrl); + }); + + describe('for enabled $projectImportUrl', () => { + beforeEach(() => { + $projectImportUrl.attr('disabled', false); + }); + + it('does not change project path if it is set by user', () => { + $projectPath.keyup(); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual(dummyImportUrl); + }); + + it('does not change project path for empty $projectImportUrl', () => { + $projectImportUrl.val(''); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual(dummyImportUrl); + }); + + it('does not change project path for whitespace $projectImportUrl', () => { + $projectImportUrl.val(' '); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual(dummyImportUrl); + }); + + it('does not change project path for $projectImportUrl without slashes', () => { + $projectImportUrl.val('has-no-slash'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual(dummyImportUrl); + }); + + it('changes project path to last $projectImportUrl component', () => { + $projectImportUrl.val('/this/is/last'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual('last'); + }); + + it('ignores trailing slashes in $projectImportUrl', () => { + $projectImportUrl.val('/has/trailing/slash/'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual('slash'); + }); + + it('ignores fragment identifier in $projectImportUrl', () => { + $projectImportUrl.val('/this/has/a#fragment-identifier/'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual('a'); + }); + + it('ignores query string in $projectImportUrl', () => { + $projectImportUrl.val('/url/with?query=string'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual('with'); + }); + + it('ignores trailing .git in $projectImportUrl', () => { + $projectImportUrl.val('/repository.git'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual('repository'); + }); + + it('changes project path for HTTPS URL in $projectImportUrl', () => { + $projectImportUrl.val('https://username:password@gitlab.company.com/group/project.git'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual('project'); + }); + + it('changes project path for SSH URL in $projectImportUrl', () => { + $projectImportUrl.val('git@gitlab.com:gitlab-org/gitlab-ce.git'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual('gitlab-ce'); + }); + }); + }); +}); -- cgit v1.2.1 From b243c3ea783df5070f889abbefc918f6599a916e Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Tue, 1 Aug 2017 20:28:10 +0200 Subject: Give metric query context rspec examples correctly sounding names. + missing whitespace --- lib/gitlab/prometheus/queries/query_additional_metrics.rb | 1 + spec/support/prometheus/additional_metrics_shared_examples.rb | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/prometheus/queries/query_additional_metrics.rb b/lib/gitlab/prometheus/queries/query_additional_metrics.rb index 5827c117556..d96921a9ee7 100644 --- a/lib/gitlab/prometheus/queries/query_additional_metrics.rb +++ b/lib/gitlab/prometheus/queries/query_additional_metrics.rb @@ -51,6 +51,7 @@ module Gitlab query[:query] %= context client_query(query[:query], time: context[:timeframe_end]) end + query[:result] = result&.map(&:deep_symbolize_keys) query end diff --git a/spec/support/prometheus/additional_metrics_shared_examples.rb b/spec/support/prometheus/additional_metrics_shared_examples.rb index 18b02920104..620fa37d455 100644 --- a/spec/support/prometheus/additional_metrics_shared_examples.rb +++ b/spec/support/prometheus/additional_metrics_shared_examples.rb @@ -23,13 +23,13 @@ RSpec.shared_examples 'additional metrics query' do subject! { described_class.new(client) } shared_examples 'query context containing environment slug and filter' do - it 'query context contains ci_environment_slug' do + it 'contains ci_environment_slug' do expect(subject).to receive(:query_metrics).with(hash_including(ci_environment_slug: environment.slug)) subject.query(*query_params) end - it 'query context contains environment filter' do + it 'contains environment filter' do expect(subject).to receive(:query_metrics).with( hash_including( environment_filter: "container_name!=\"POD\",environment=\"#{environment.slug}\"" -- cgit v1.2.1 From 9513bd18c43b749c8856d6ad89635d97c8fb73b5 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 1 Aug 2017 14:51:52 -0400 Subject: Ensure all project factories use `:repository` trait or `:empty_project` --- .../admin/application_settings_controller_spec.rb | 2 +- .../controllers/admin/dashboard_controller_spec.rb | 4 +-- spec/controllers/autocomplete_controller_spec.rb | 16 ++++----- spec/controllers/dashboard_controller_spec.rb | 2 +- .../merge_requests/conflicts_controller_spec.rb | 2 +- .../merge_requests/creations_controller_spec.rb | 4 +-- .../merge_requests/diffs_controller_spec.rb | 4 +-- .../projects/merge_requests_controller_spec.rb | 8 ++--- spec/controllers/projects/notes_controller_spec.rb | 4 +-- .../projects/pipelines_controller_spec.rb | 2 +- .../projects/snippets_controller_spec.rb | 2 +- spec/controllers/projects_controller_spec.rb | 14 ++++---- spec/controllers/snippets_controller_spec.rb | 2 +- spec/factories/uploads.rb | 2 +- spec/features/dashboard/projects_spec.rb | 4 +-- spec/features/discussion_comments/commit_spec.rb | 2 +- .../discussion_comments/merge_request_spec.rb | 2 +- .../features/issuables/markdown_references_spec.rb | 2 +- spec/features/projects/blobs/edit_spec.rb | 2 +- spec/features/reportable_note/commit_spec.rb | 2 +- .../features/reportable_note/merge_request_spec.rb | 2 +- spec/finders/members_finder_spec.rb | 2 +- spec/helpers/button_helper_spec.rb | 2 +- spec/helpers/ci_status_helper_spec.rb | 2 +- spec/helpers/diff_helper_spec.rb | 2 +- spec/helpers/issuables_helper_spec.rb | 4 +-- spec/helpers/markup_helper_spec.rb | 2 +- spec/helpers/notes_helper_spec.rb | 2 +- spec/helpers/projects_helper_spec.rb | 6 ++-- spec/javascripts/fixtures/balsamiq.rb | 2 +- spec/javascripts/fixtures/dashboard.rb | 2 +- spec/javascripts/fixtures/merge_requests.rb | 2 +- spec/javascripts/fixtures/merge_requests_diffs.rb | 2 +- spec/javascripts/fixtures/pdf.rb | 2 +- spec/javascripts/fixtures/projects.rb | 2 +- spec/javascripts/fixtures/raw.rb | 2 +- spec/lib/banzai/filter/reference_filter_spec.rb | 2 +- spec/lib/container_registry/tag_spec.rb | 2 +- spec/lib/gitlab/badge/coverage/report_spec.rb | 2 +- .../cache/ci/project_pipeline_status_spec.rb | 4 +-- .../cycle_analytics/base_event_fetcher_spec.rb | 2 +- spec/lib/gitlab/cycle_analytics/events_spec.rb | 2 +- .../v1/rename_base_spec.rb | 6 ++-- .../v1/rename_namespaces_spec.rb | 12 +++---- .../v1/rename_projects_spec.rb | 2 +- spec/lib/gitlab/diff/parser_spec.rb | 2 +- spec/lib/gitlab/email/attachment_uploader_spec.rb | 2 +- .../email/handler/create_issue_handler_spec.rb | 2 +- spec/lib/gitlab/github_import/importer_spec.rb | 2 +- .../gitlab/github_import/wiki_formatter_spec.rb | 2 +- spec/lib/gitlab/gl_repository_spec.rb | 2 +- spec/lib/gitlab/import_export/fork_spec.rb | 4 +-- .../import_export/merge_request_parser_spec.rb | 4 +-- .../lib/gitlab/import_export/repo_restorer_spec.rb | 2 +- spec/lib/gitlab/issuable_sorter_spec.rb | 42 +++++++++++----------- spec/lib/gitlab/middleware/go_spec.rb | 4 +-- spec/lib/gitlab/project_search_results_spec.rb | 6 ++-- spec/lib/gitlab/repo_path_spec.rb | 2 +- spec/lib/gitlab/user_access_spec.rb | 2 +- spec/migrations/rename_system_namespaces_spec.rb | 16 ++++----- spec/models/blob_viewer/composer_json_spec.rb | 2 +- spec/models/blob_viewer/gemspec_spec.rb | 2 +- spec/models/blob_viewer/gitlab_ci_yml_spec.rb | 2 +- spec/models/blob_viewer/package_json_spec.rb | 2 +- spec/models/blob_viewer/podspec_json_spec.rb | 2 +- spec/models/blob_viewer/podspec_spec.rb | 2 +- spec/models/blob_viewer/route_map_spec.rb | 2 +- spec/models/concerns/participable_spec.rb | 6 ++-- spec/models/concerns/resolvable_note_spec.rb | 2 +- spec/models/concerns/routable_spec.rb | 2 +- spec/models/container_repository_spec.rb | 4 +-- spec/models/deployment_spec.rb | 2 +- spec/models/diff_discussion_spec.rb | 2 +- spec/models/environment_spec.rb | 2 +- spec/models/forked_project_link_spec.rb | 2 +- spec/models/gpg_signature_spec.rb | 2 +- spec/models/issue_spec.rb | 2 +- spec/models/project_group_link_spec.rb | 2 +- .../chat_notification_service_spec.rb | 2 +- .../project_services/issue_tracker_service_spec.rb | 2 +- spec/models/project_services/jira_service_spec.rb | 2 +- spec/models/project_spec.rb | 16 ++++----- spec/models/project_team_spec.rb | 2 +- spec/models/repository_spec.rb | 2 +- spec/models/sent_notification_spec.rb | 4 +-- spec/policies/ci/build_policy_spec.rb | 2 +- spec/policies/ci/pipeline_policy_spec.rb | 2 +- spec/policies/environment_policy_spec.rb | 8 ++--- spec/presenters/merge_request_presenter_spec.rb | 2 +- spec/requests/api/files_spec.rb | 4 +-- spec/requests/api/pipeline_schedules_spec.rb | 2 +- spec/requests/api/todos_spec.rb | 2 +- spec/requests/api/triggers_spec.rb | 2 +- spec/requests/api/v3/files_spec.rb | 2 +- spec/requests/api/v3/project_hooks_spec.rb | 4 +-- spec/requests/api/v3/triggers_spec.rb | 2 +- spec/requests/lfs_http_spec.rb | 6 ++-- spec/requests/request_profiler_spec.rb | 2 +- spec/services/ci/create_pipeline_service_spec.rb | 2 +- spec/services/ci/play_build_service_spec.rb | 2 +- spec/services/labels/create_service_spec.rb | 4 +-- spec/services/labels/update_service_spec.rb | 2 +- spec/services/milestones/destroy_service_spec.rb | 2 +- spec/services/users/destroy_service_spec.rb | 4 +-- .../users/migrate_to_ghost_user_service_spec.rb | 2 +- .../issuable_slash_commands_shared_examples.rb | 9 ++++- spec/support/import_export/export_file_helper.rb | 2 +- ...igrate_to_ghost_user_service_shared_examples.rb | 9 ++++- spec/uploaders/file_uploader_spec.rb | 2 +- spec/validators/dynamic_path_validator_spec.rb | 2 +- spec/views/layouts/nav/_project.html.haml_spec.rb | 2 +- .../notify/pipeline_failed_email.html.haml_spec.rb | 2 +- .../pipeline_success_email.html.haml_spec.rb | 2 +- spec/workers/create_gpg_signature_worker_spec.rb | 4 +-- spec/workers/process_commit_worker_spec.rb | 2 +- 115 files changed, 214 insertions(+), 200 deletions(-) diff --git a/spec/controllers/admin/application_settings_controller_spec.rb b/spec/controllers/admin/application_settings_controller_spec.rb index 2565622f8df..23ab2b141cf 100644 --- a/spec/controllers/admin/application_settings_controller_spec.rb +++ b/spec/controllers/admin/application_settings_controller_spec.rb @@ -4,7 +4,7 @@ describe Admin::ApplicationSettingsController do include StubENV let(:group) { create(:group) } - let(:project) { create(:project, namespace: group) } + let(:project) { create(:empty_project, namespace: group) } let(:admin) { create(:admin) } let(:user) { create(:user)} diff --git a/spec/controllers/admin/dashboard_controller_spec.rb b/spec/controllers/admin/dashboard_controller_spec.rb index 6eb9f7867d5..b290c45cdd4 100644 --- a/spec/controllers/admin/dashboard_controller_spec.rb +++ b/spec/controllers/admin/dashboard_controller_spec.rb @@ -8,8 +8,8 @@ describe Admin::DashboardController do it 'does not retrieve projects that are pending deletion' do sign_in(create(:admin)) - project = create(:project) - pending_delete_project = create(:project, pending_delete: true) + project = create(:empty_project) + pending_delete_project = create(:empty_project, pending_delete: true) get :index diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb index 58486f33229..fa5660050ec 100644 --- a/spec/controllers/autocomplete_controller_spec.rb +++ b/spec/controllers/autocomplete_controller_spec.rb @@ -65,7 +65,7 @@ describe AutocompleteController do end context 'non-member login for public project' do - let!(:project) { create(:project, :public) } + let!(:project) { create(:empty_project, :public) } before do sign_in(non_member) @@ -127,7 +127,7 @@ describe AutocompleteController do end context 'unauthenticated user' do - let(:public_project) { create(:project, :public) } + let(:public_project) { create(:empty_project, :public) } let(:body) { JSON.parse(response.body) } describe 'GET #users with public project' do @@ -231,8 +231,8 @@ describe AutocompleteController do end context 'GET projects' do - let(:authorized_project) { create(:project) } - let(:authorized_search_project) { create(:project, name: 'rugged') } + let(:authorized_project) { create(:empty_project) } + let(:authorized_search_project) { create(:empty_project, name: 'rugged') } before do sign_in(user) @@ -289,8 +289,8 @@ describe AutocompleteController do context 'authorized projects apply limit' do before do - authorized_project2 = create(:project) - authorized_project3 = create(:project) + authorized_project2 = create(:empty_project) + authorized_project3 = create(:empty_project) authorized_project.add_master(user) authorized_project2.add_master(user) @@ -315,8 +315,8 @@ describe AutocompleteController do context 'authorized projects with offset' do before do - authorized_project2 = create(:project) - authorized_project3 = create(:project) + authorized_project2 = create(:empty_project) + authorized_project3 = create(:empty_project) authorized_project.add_master(user) authorized_project2.add_master(user) diff --git a/spec/controllers/dashboard_controller_spec.rb b/spec/controllers/dashboard_controller_spec.rb index 566d8515198..05561946e9b 100644 --- a/spec/controllers/dashboard_controller_spec.rb +++ b/spec/controllers/dashboard_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe DashboardController do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } before do project.team << [user, :master] diff --git a/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb b/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb index 9278ac8edd8..393d38c6e6b 100644 --- a/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::MergeRequests::ConflictsController do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { project.owner } let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) } let(:merge_request_with_conflicts) do diff --git a/spec/controllers/projects/merge_requests/creations_controller_spec.rb b/spec/controllers/projects/merge_requests/creations_controller_spec.rb index f9d8f0f5fcf..fc4cec53374 100644 --- a/spec/controllers/projects/merge_requests/creations_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/creations_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::MergeRequests::CreationsController do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { project.owner } let(:fork_project) { create(:forked_project_with_submodules) } @@ -83,7 +83,7 @@ describe Projects::MergeRequests::CreationsController do end context 'when the source branch is in a different project to the target' do - let(:other_project) { create(:project) } + let(:other_project) { create(:project, :repository) } before do other_project.team << [user, :master] diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb index 53fe2bdb189..fd6cb3c5dbb 100644 --- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::MergeRequests::DiffsController do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { project.owner } let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) } @@ -36,7 +36,7 @@ describe Projects::MergeRequests::DiffsController do context 'with forked projects with submodules' do render_views - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:fork_project) { create(:forked_project_with_submodules) } let(:merge_request) { create(:merge_request_with_diffs, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) } diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 0bfe83f1d98..bed2d4f8c98 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::MergeRequestsController do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { project.owner } let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) } let(:merge_request_with_conflicts) do @@ -191,7 +191,7 @@ describe Projects::MergeRequestsController do end context 'there is no source project' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:fork_project) { create(:forked_project_with_submodules) } let(:merge_request) { create(:merge_request, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) } @@ -429,7 +429,7 @@ describe Projects::MergeRequestsController do context "when the user is owner" do let(:owner) { create(:user) } let(:namespace) { create(:namespace, owner: owner) } - let(:project) { create(:project, namespace: namespace) } + let(:project) { create(:project, :repository, namespace: namespace) } before do sign_in owner @@ -587,7 +587,7 @@ describe Projects::MergeRequestsController do describe 'GET ci_environments_status' do context 'the environment is from a forked project' do - let!(:forked) { create(:project) } + let!(:forked) { create(:project, :repository) } let!(:environment) { create(:environment, project: forked) } let!(:deployment) { create(:deployment, environment: environment, sha: forked.commit.id, ref: 'master') } let(:admin) { create(:admin) } diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb index 3b88d5b0d7d..4a6eb76e71f 100644 --- a/spec/controllers/projects/notes_controller_spec.rb +++ b/spec/controllers/projects/notes_controller_spec.rb @@ -167,10 +167,10 @@ describe Projects::NotesController do end context 'when creating a commit comment from an MR fork' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:fork_project) do - create(:project).tap do |fork| + create(:project, :repository).tap do |fork| create(:forked_project_link, forked_to_project: fork, forked_from_project: project) end end diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index c8de275ca3e..ed63e4dec26 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -61,7 +61,7 @@ describe Projects::PipelinesController do create_build('post deploy', 3, 'pages 0') end - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) do create(:ci_empty_pipeline, project: project, user: user, sha: project.commit.id) end diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb index cc444f31797..1f082ce7102 100644 --- a/spec/controllers/projects/snippets_controller_spec.rb +++ b/spec/controllers/projects/snippets_controller_spec.rb @@ -156,7 +156,7 @@ describe Projects::SnippetsController do end describe 'PUT #update' do - let(:project) { create :project, :public } + let(:project) { create :empty_project, :public } let(:snippet) { create :project_snippet, author: user, project: project, visibility_level: visibility_level } def update_snippet(snippet_params = {}, additional_params = {}) diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 192cca45d99..9f19cc30582 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -196,7 +196,7 @@ describe ProjectsController do context "redirection from http://someproject.git" do it 'redirects to project page (format.html)' do - project = create(:project, :public) + project = create(:empty_project, :public) get :show, namespace_id: project.namespace, id: project, format: :git @@ -254,7 +254,7 @@ describe ProjectsController do describe '#transfer' do render_views - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:admin) { create(:admin) } let(:new_namespace) { create(:namespace) } @@ -311,8 +311,8 @@ describe ProjectsController do end context "when the project is forked" do - let(:project) { create(:project) } - let(:fork_project) { create(:project, forked_from_project: project) } + let(:project) { create(:project, :repository) } + let(:fork_project) { create(:project, :repository, forked_from_project: project) } let(:merge_request) do create(:merge_request, source_project: fork_project, @@ -390,7 +390,7 @@ describe ProjectsController do end context 'with forked project' do - let(:project_fork) { create(:project, namespace: user.namespace) } + let(:project_fork) { create(:project, :repository, namespace: user.namespace) } before do create(:forked_project_link, forked_to_project: project_fork) @@ -408,7 +408,7 @@ describe ProjectsController do end context 'when project not forked' do - let(:unforked_project) { create(:project, namespace: user.namespace) } + let(:unforked_project) { create(:empty_project, namespace: user.namespace) } it 'does nothing if project was not forked' do delete(:remove_fork, @@ -430,7 +430,7 @@ describe ProjectsController do end describe "GET refs" do - let(:public_project) { create(:project, :public) } + let(:public_project) { create(:project, :public, :repository) } it "gets a list of branches and tags" do get :refs, namespace_id: public_project.namespace, id: public_project diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb index 475ceda11fe..a6edcca08f4 100644 --- a/spec/controllers/snippets_controller_spec.rb +++ b/spec/controllers/snippets_controller_spec.rb @@ -273,7 +273,7 @@ describe SnippetsController do end describe 'PUT #update' do - let(:project) { create :project } + let(:project) { create :empty_project } let(:snippet) { create :personal_snippet, author: user, project: project, visibility_level: visibility_level } def update_snippet(snippet_params = {}, additional_params = {}) diff --git a/spec/factories/uploads.rb b/spec/factories/uploads.rb index 3222c41c3d8..f49dbe6dc9e 100644 --- a/spec/factories/uploads.rb +++ b/spec/factories/uploads.rb @@ -1,6 +1,6 @@ FactoryGirl.define do factory :upload do - model { build(:project) } + model { build(:empty_project) } path { "uploads/-/system/project/avatar/avatar.jpg" } size 100.kilobytes uploader "AvatarUploader" diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb index abb9e5eef96..29ac96adc0e 100644 --- a/spec/features/dashboard/projects_spec.rb +++ b/spec/features/dashboard/projects_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' feature 'Dashboard Projects' do let(:user) { create(:user) } - let(:project) { create(:project, name: 'awesome stuff') } - let(:project2) { create(:project, :public, name: 'Community project') } + let(:project) { create(:project, :repository, name: 'awesome stuff') } + let(:project2) { create(:empty_project, :public, name: 'Community project') } before do project.team << [user, :developer] diff --git a/spec/features/discussion_comments/commit_spec.rb b/spec/features/discussion_comments/commit_spec.rb index fa83ad5d17c..0375d0bf8ff 100644 --- a/spec/features/discussion_comments/commit_spec.rb +++ b/spec/features/discussion_comments/commit_spec.rb @@ -4,7 +4,7 @@ describe 'Discussion Comments Merge Request', :js do include RepoHelpers let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } before do diff --git a/spec/features/discussion_comments/merge_request_spec.rb b/spec/features/discussion_comments/merge_request_spec.rb index 042f39f47e0..b0019c32189 100644 --- a/spec/features/discussion_comments/merge_request_spec.rb +++ b/spec/features/discussion_comments/merge_request_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Discussion Comments Merge Request', :js do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } before do diff --git a/spec/features/issuables/markdown_references_spec.rb b/spec/features/issuables/markdown_references_spec.rb index 169381d703a..04d38165a15 100644 --- a/spec/features/issuables/markdown_references_spec.rb +++ b/spec/features/issuables/markdown_references_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' describe 'Markdown References', :js do let(:user) { create(:user) } - let(:actual_project) { create(:project, :public) } + let(:actual_project) { create(:project, :public, :repository) } let(:merge_request) { create(:merge_request, target_project: actual_project, source_project: actual_project)} let(:issue_actual_project) { create(:issue, project: actual_project) } let!(:other_project) { create(:empty_project, :public) } diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb index 9855cfd85c4..62ac9fd0e95 100644 --- a/spec/features/projects/blobs/edit_spec.rb +++ b/spec/features/projects/blobs/edit_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Editing file blob', js: true do include TreeHelper - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'master') } let(:branch) { 'master' } let(:file_path) { project.repository.ls_files(project.repository.root_ref)[1] } diff --git a/spec/features/reportable_note/commit_spec.rb b/spec/features/reportable_note/commit_spec.rb index 1074eb62b33..3bf25221e36 100644 --- a/spec/features/reportable_note/commit_spec.rb +++ b/spec/features/reportable_note/commit_spec.rb @@ -4,7 +4,7 @@ describe 'Reportable note on commit', :js do include RepoHelpers let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do project.add_master(user) diff --git a/spec/features/reportable_note/merge_request_spec.rb b/spec/features/reportable_note/merge_request_spec.rb index a491abdb6cb..bb296546e06 100644 --- a/spec/features/reportable_note/merge_request_spec.rb +++ b/spec/features/reportable_note/merge_request_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Reportable note on merge request', :js do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } before do diff --git a/spec/finders/members_finder_spec.rb b/spec/finders/members_finder_spec.rb index 300ba8422e8..9fb9ffa95e7 100644 --- a/spec/finders/members_finder_spec.rb +++ b/spec/finders/members_finder_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe MembersFinder, '#execute' do let(:group) { create(:group) } let(:nested_group) { create(:group, :access_requestable, parent: group) } - let(:project) { create(:project, namespace: nested_group) } + let(:project) { create(:empty_project, namespace: nested_group) } let(:user1) { create(:user) } let(:user2) { create(:user) } let(:user3) { create(:user) } diff --git a/spec/helpers/button_helper_spec.rb b/spec/helpers/button_helper_spec.rb index 7ecb75da8ce..7c6f3b101d7 100644 --- a/spec/helpers/button_helper_spec.rb +++ b/spec/helpers/button_helper_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe ButtonHelper do describe 'http_clone_button' do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { build_stubbed(:empty_project) } let(:has_tooltip_class) { 'has-tooltip' } def element diff --git a/spec/helpers/ci_status_helper_spec.rb b/spec/helpers/ci_status_helper_spec.rb index e6bb953e9d8..3f8df388014 100644 --- a/spec/helpers/ci_status_helper_spec.rb +++ b/spec/helpers/ci_status_helper_spec.rb @@ -48,7 +48,7 @@ describe CiStatusHelper do describe "#pipeline_status_cache_key" do it "builds a cache key for pipeline status" do pipeline_status = Gitlab::Cache::Ci::ProjectPipelineStatus.new( - build(:project), + build_stubbed(:empty_project), pipeline_info: { sha: "123abc", status: "success" diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb index 060c112e20d..f81a9b6492c 100644 --- a/spec/helpers/diff_helper_spec.rb +++ b/spec/helpers/diff_helper_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe DiffHelper do include RepoHelpers - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:commit) { project.commit(sample_commit.id) } let(:diffs) { commit.raw_diffs } diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index 7789cfa3554..1aad8a85ab7 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -180,7 +180,7 @@ describe IssuablesHelper do context 'when show_full_reference falsey' do context 'when @group present' do it 'display issuable reference to @group' do - project = build_stubbed(:project) + project = build_stubbed(:empty_project) assign(:show_full_reference, nil) assign(:group, project.namespace) @@ -193,7 +193,7 @@ describe IssuablesHelper do context 'when @project present' do it 'display issuable reference to @project' do - project = build_stubbed(:project) + project = build_stubbed(:empty_project) assign(:show_full_reference, nil) assign(:group, nil) diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb index 70eb01c9c44..6dfffb7ac63 100644 --- a/spec/helpers/markup_helper_spec.rb +++ b/spec/helpers/markup_helper_spec.rb @@ -42,7 +42,7 @@ describe MarkupHelper do describe "override default project" do let(:actual) { issue.to_reference } - let(:second_project) { create(:project, :public) } + let(:second_project) { create(:empty_project, :public) } let(:second_issue) { create(:issue, project: second_project) } it 'links to the issue' do diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb index 56f252ba273..da1044cef3f 100644 --- a/spec/helpers/notes_helper_spec.rb +++ b/spec/helpers/notes_helper_spec.rb @@ -40,7 +40,7 @@ describe NotesHelper do end describe '#discussion_path' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } context 'for a merge request discusion' do let(:merge_request) { create(:merge_request, source_project: project, target_project: project, importing: true) } diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index faf26931efc..c447c061919 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -46,7 +46,7 @@ describe ProjectsHelper do end describe "readme_cache_key" do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do helper.instance_variable_set(:@project, project) @@ -64,7 +64,7 @@ describe ProjectsHelper do end describe "#project_list_cache_key", clean_gitlab_redis_shared_state: true do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } it "includes the route" do expect(helper.project_list_cache_key(project)).to include(project.route.cache_key) @@ -251,7 +251,7 @@ describe ProjectsHelper do end describe '#sanitized_import_error' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do allow(project).to receive(:repository_storage_path).and_return('/base/repo/path') diff --git a/spec/javascripts/fixtures/balsamiq.rb b/spec/javascripts/fixtures/balsamiq.rb index b5372821bf5..234e246119a 100644 --- a/spec/javascripts/fixtures/balsamiq.rb +++ b/spec/javascripts/fixtures/balsamiq.rb @@ -4,7 +4,7 @@ describe 'Balsamiq file', '(JavaScript fixtures)', type: :controller do include JavaScriptFixturesHelpers let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} - let(:project) { create(:project, namespace: namespace, path: 'balsamiq-project') } + let(:project) { create(:project, :repository, namespace: namespace, path: 'balsamiq-project') } before(:all) do clean_frontend_fixtures('blob/balsamiq/') diff --git a/spec/javascripts/fixtures/dashboard.rb b/spec/javascripts/fixtures/dashboard.rb index e83db8daaf2..b2114e65d27 100644 --- a/spec/javascripts/fixtures/dashboard.rb +++ b/spec/javascripts/fixtures/dashboard.rb @@ -5,7 +5,7 @@ describe Dashboard::ProjectsController, '(JavaScript fixtures)', type: :controll let(:admin) { create(:admin) } let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} - let(:project) { create(:project, namespace: namespace, path: 'builds-project') } + let(:project) { create(:empty_project, namespace: namespace, path: 'builds-project') } render_views diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb index 7e2f364ffa4..f9d8b5c569c 100644 --- a/spec/javascripts/fixtures/merge_requests.rb +++ b/spec/javascripts/fixtures/merge_requests.rb @@ -5,7 +5,7 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont let(:admin) { create(:admin) } let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} - let(:project) { create(:project, namespace: namespace, path: 'merge-requests-project') } + let(:project) { create(:project, :repository, namespace: namespace, path: 'merge-requests-project') } let(:merge_request) { create(:merge_request, :with_diffs, source_project: project, target_project: project, description: '- [ ] Task List Item') } let(:merged_merge_request) { create(:merge_request, :merged, source_project: project, target_project: project) } let(:pipeline) do diff --git a/spec/javascripts/fixtures/merge_requests_diffs.rb b/spec/javascripts/fixtures/merge_requests_diffs.rb index ac5b06ace6d..4481a187f63 100644 --- a/spec/javascripts/fixtures/merge_requests_diffs.rb +++ b/spec/javascripts/fixtures/merge_requests_diffs.rb @@ -6,7 +6,7 @@ describe Projects::MergeRequests::DiffsController, '(JavaScript fixtures)', type let(:admin) { create(:admin) } let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} - let(:project) { create(:project, namespace: namespace, path: 'merge-requests-project') } + let(:project) { create(:project, :repository, namespace: namespace, path: 'merge-requests-project') } let(:merge_request) { create(:merge_request, :with_diffs, source_project: project, target_project: project, description: '- [ ] Task List Item') } let(:path) { "files/ruby/popen.rb" } let(:position) do diff --git a/spec/javascripts/fixtures/pdf.rb b/spec/javascripts/fixtures/pdf.rb index 6b2422a7986..ef9976b9fd3 100644 --- a/spec/javascripts/fixtures/pdf.rb +++ b/spec/javascripts/fixtures/pdf.rb @@ -4,7 +4,7 @@ describe 'PDF file', '(JavaScript fixtures)', type: :controller do include JavaScriptFixturesHelpers let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} - let(:project) { create(:project, namespace: namespace, path: 'pdf-project') } + let(:project) { create(:project, :repository, namespace: namespace, path: 'pdf-project') } before(:all) do clean_frontend_fixtures('blob/pdf/') diff --git a/spec/javascripts/fixtures/projects.rb b/spec/javascripts/fixtures/projects.rb index 6c33b240e5c..b828eee6629 100644 --- a/spec/javascripts/fixtures/projects.rb +++ b/spec/javascripts/fixtures/projects.rb @@ -5,7 +5,7 @@ describe ProjectsController, '(JavaScript fixtures)', type: :controller do let(:admin) { create(:admin) } let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} - let(:project) { create(:project, namespace: namespace, path: 'builds-project') } + let(:project) { create(:empty_project, namespace: namespace, path: 'builds-project') } render_views diff --git a/spec/javascripts/fixtures/raw.rb b/spec/javascripts/fixtures/raw.rb index 17533443d76..25f5a3b0bb3 100644 --- a/spec/javascripts/fixtures/raw.rb +++ b/spec/javascripts/fixtures/raw.rb @@ -4,7 +4,7 @@ describe 'Raw files', '(JavaScript fixtures)', type: :controller do include JavaScriptFixturesHelpers let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} - let(:project) { create(:project, namespace: namespace, path: 'raw-project') } + let(:project) { create(:project, :repository, namespace: namespace, path: 'raw-project') } before(:all) do clean_frontend_fixtures('blob/notebook/') diff --git a/spec/lib/banzai/filter/reference_filter_spec.rb b/spec/lib/banzai/filter/reference_filter_spec.rb index b9ca68e8935..81f244a4539 100644 --- a/spec/lib/banzai/filter/reference_filter_spec.rb +++ b/spec/lib/banzai/filter/reference_filter_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Banzai::Filter::ReferenceFilter do - let(:project) { build(:project) } + let(:project) { build_stubbed(:empty_project) } describe '#each_node' do it 'iterates over the nodes in a document' do diff --git a/spec/lib/container_registry/tag_spec.rb b/spec/lib/container_registry/tag_spec.rb index cb4ae3be525..e76463b5e7c 100644 --- a/spec/lib/container_registry/tag_spec.rb +++ b/spec/lib/container_registry/tag_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe ContainerRegistry::Tag do let(:group) { create(:group, name: 'group') } - let(:project) { create(:project, path: 'test', group: group) } + let(:project) { create(:project, :repository, path: 'test', group: group) } let(:repository) do create(:container_repository, name: '', project: project) diff --git a/spec/lib/gitlab/badge/coverage/report_spec.rb b/spec/lib/gitlab/badge/coverage/report_spec.rb index 1547bd3228c..da789bf3705 100644 --- a/spec/lib/gitlab/badge/coverage/report_spec.rb +++ b/spec/lib/gitlab/badge/coverage/report_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::Badge::Coverage::Report do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:job_name) { nil } let(:badge) do diff --git a/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb b/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb index 0daf41a7c86..1fab3b29424 100644 --- a/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb +++ b/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::Cache::Ci::ProjectPipelineStatus, :clean_gitlab_redis_cache do - let!(:project) { create(:project) } + let!(:project) { create(:project, :repository) } let(:pipeline_status) { described_class.new(project) } let(:cache_key) { "projects/#{project.id}/pipeline_status" } @@ -18,7 +18,7 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :clean_gitlab_redis_cache do let(:sha) { '424d1b73bc0d3cb726eb7dc4ce17a4d48552f8c6' } let(:ref) { 'master' } let(:pipeline_info) { { sha: sha, status: status, ref: ref } } - let!(:project_without_status) { create(:project) } + let!(:project_without_status) { create(:project, :repository) } describe '.load_in_batch_for_projects' do it 'preloads pipeline_status on projects' do diff --git a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb index d8757c601ab..854aaa34c73 100644 --- a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::CycleAnalytics::BaseEventFetcher do let(:max_events) { 2 } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { create(:user, :admin) } let(:start_time_attrs) { Issue.arel_table[:created_at] } let(:end_time_attrs) { [Issue::Metrics.arel_table[:first_associated_with_milestone_at]] } diff --git a/spec/lib/gitlab/cycle_analytics/events_spec.rb b/spec/lib/gitlab/cycle_analytics/events_spec.rb index a1b3fe8509e..28ea7d4c303 100644 --- a/spec/lib/gitlab/cycle_analytics/events_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/events_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'cycle analytics events' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } let!(:context) { create(:issue, project: project, created_at: 2.days.ago) } diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb index df7d1b5d27a..254ce06381e 100644 --- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb +++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb @@ -94,7 +94,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :trunca end it "renames the route for projects of the namespace" do - project = create(:project, path: "project-path", namespace: namespace) + project = create(:project, :repository, path: "project-path", namespace: namespace) subject.rename_path_for_routable(migration_namespace(namespace)) @@ -120,7 +120,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :trunca context "the-path namespace -> subgroup -> the-path0 project" do it "updates the route of the project correctly" do subgroup = create(:group, path: "subgroup", parent: namespace) - project = create(:project, path: "the-path0", namespace: subgroup) + project = create(:project, :repository, path: "the-path0", namespace: subgroup) subject.rename_path_for_routable(migration_namespace(namespace)) @@ -165,7 +165,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :trunca it 'renames all the routes for the namespace' do child = create(:group, path: 'child', parent: namespace) - project = create(:project, namespace: child, path: 'the-project') + project = create(:project, :repository, namespace: child, path: 'the-project') other_one = create(:namespace, path: 'the-path-is-similar') subject.perform_rename(migration_namespace(namespace), 'the-path', 'renamed') diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb index 803e923b4a5..95695ca8c16 100644 --- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb +++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb @@ -94,7 +94,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, : describe '#move_repositories' do let(:namespace) { create(:group, name: 'hello-group') } it 'moves a project for a namespace' do - create(:project, namespace: namespace, path: 'hello-project') + create(:project, :repository, namespace: namespace, path: 'hello-project') expected_path = File.join(TestEnv.repos_path, 'bye-group', 'hello-project.git') subject.move_repositories(namespace, 'hello-group', 'bye-group') @@ -104,7 +104,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, : it 'moves a namespace in a subdirectory correctly' do child_namespace = create(:group, name: 'sub-group', parent: namespace) - create(:project, namespace: child_namespace, path: 'hello-project') + create(:project, :repository, namespace: child_namespace, path: 'hello-project') expected_path = File.join(TestEnv.repos_path, 'hello-group', 'renamed-sub-group', 'hello-project.git') @@ -115,7 +115,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, : it 'moves a parent namespace with subdirectories' do child_namespace = create(:group, name: 'sub-group', parent: namespace) - create(:project, namespace: child_namespace, path: 'hello-project') + create(:project, :repository, namespace: child_namespace, path: 'hello-project') expected_path = File.join(TestEnv.repos_path, 'renamed-group', 'sub-group', 'hello-project.git') subject.move_repositories(child_namespace, 'hello-group', 'renamed-group') @@ -166,7 +166,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, : describe '#rename_namespace_dependencies' do it "moves the the repository for a project in the namespace" do - create(:project, namespace: namespace, path: "the-path-project") + create(:project, :repository, namespace: namespace, path: "the-path-project") expected_repo = File.join(TestEnv.repos_path, "the-path0", "the-path-project.git") subject.rename_namespace_dependencies(namespace, 'the-path', 'the-path0') @@ -243,7 +243,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, : describe '#revert_renames', redis: true do it 'renames the routes back to the previous values' do - project = create(:project, path: 'a-project', namespace: namespace) + project = create(:project, :repository, path: 'a-project', namespace: namespace) subject.rename_namespace(namespace) expect(subject).to receive(:perform_rename) @@ -261,7 +261,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, : end it 'moves the repositories back to their original place' do - project = create(:project, path: 'a-project', namespace: namespace) + project = create(:project, :repository, path: 'a-project', namespace: namespace) project.create_repository subject.rename_namespace(namespace) diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb index 0e240a5ccf1..19e23a32bda 100644 --- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb +++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb @@ -104,7 +104,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :tr describe '#move_repository' do let(:known_parent) { create(:namespace, path: 'known-parent') } - let(:project) { create(:project, path: 'the-path', namespace: known_parent) } + let(:project) { create(:project, :repository, path: 'the-path', namespace: known_parent) } it 'moves the repository for a project' do expected_path = File.join(TestEnv.repos_path, 'known-parent', 'new-repo.git') diff --git a/spec/lib/gitlab/diff/parser_spec.rb b/spec/lib/gitlab/diff/parser_spec.rb index c71568e2a65..8af49ed50ff 100644 --- a/spec/lib/gitlab/diff/parser_spec.rb +++ b/spec/lib/gitlab/diff/parser_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::Diff::Parser do include RepoHelpers - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:commit) { project.commit(sample_commit.id) } let(:diff) { commit.raw_diffs.first } let(:parser) { described_class.new } diff --git a/spec/lib/gitlab/email/attachment_uploader_spec.rb b/spec/lib/gitlab/email/attachment_uploader_spec.rb index f61dbc67ad1..89258d2eca7 100644 --- a/spec/lib/gitlab/email/attachment_uploader_spec.rb +++ b/spec/lib/gitlab/email/attachment_uploader_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" describe Gitlab::Email::AttachmentUploader do describe "#execute" do - let(:project) { build(:project) } + let(:project) { build(:empty_project) } let(:message_raw) { fixture_file("emails/attachment.eml") } let(:message) { Mail::Message.new(message_raw) } diff --git a/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb b/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb index bd36d1d309d..6d0e715e889 100644 --- a/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb +++ b/spec/lib/gitlab/email/handler/create_issue_handler_spec.rb @@ -69,7 +69,7 @@ describe Gitlab::Email::Handler::CreateIssueHandler do end context "when project is private" do - let(:project) { create(:project, :private, namespace: namespace) } + let(:project) { create(:empty_project, :private, namespace: namespace) } it "raises a ProjectNotFound if the user is not a member" do expect { receiver.execute }.to raise_error(Gitlab::Email::ProjectNotFound) diff --git a/spec/lib/gitlab/github_import/importer_spec.rb b/spec/lib/gitlab/github_import/importer_spec.rb index d00a2deaf7b..d570f34985b 100644 --- a/spec/lib/gitlab/github_import/importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer_spec.rb @@ -207,7 +207,7 @@ describe Gitlab::GithubImport::Importer do end end - let(:project) { create(:project, :wiki_disabled, import_url: "#{repo_root}/octocat/Hello-World.git") } + let(:project) { create(:project, :repository, :wiki_disabled, import_url: "#{repo_root}/octocat/Hello-World.git") } let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') } let(:credentials) { { user: 'joe' } } diff --git a/spec/lib/gitlab/github_import/wiki_formatter_spec.rb b/spec/lib/gitlab/github_import/wiki_formatter_spec.rb index fcd90fab547..119bf2b5662 100644 --- a/spec/lib/gitlab/github_import/wiki_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/wiki_formatter_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::GithubImport::WikiFormatter do let(:project) do - create(:project, + create(:empty_project, namespace: create(:namespace, path: 'gitlabhq'), import_url: 'https://xxx@github.com/gitlabhq/sample.gitlabhq.git') end diff --git a/spec/lib/gitlab/gl_repository_spec.rb b/spec/lib/gitlab/gl_repository_spec.rb index ac3558ab386..4e09020471b 100644 --- a/spec/lib/gitlab/gl_repository_spec.rb +++ b/spec/lib/gitlab/gl_repository_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe ::Gitlab::GlRepository do describe '.parse' do - set(:project) { create(:project) } + set(:project) { create(:project, :repository) } it 'parses a project gl_repository' do expect(described_class.parse("project-#{project.id}")).to eq([project, false]) diff --git a/spec/lib/gitlab/import_export/fork_spec.rb b/spec/lib/gitlab/import_export/fork_spec.rb index 0ff64cbe880..230cc2d3006 100644 --- a/spec/lib/gitlab/import_export/fork_spec.rb +++ b/spec/lib/gitlab/import_export/fork_spec.rb @@ -2,11 +2,11 @@ require 'spec_helper' describe 'forked project import' do let(:user) { create(:user) } - let!(:project_with_repo) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') } + let!(:project_with_repo) { create(:project, :repository, name: 'test-repo-restorer', path: 'test-repo-restorer') } let!(:project) { create(:empty_project, name: 'test-repo-restorer-no-repo', path: 'test-repo-restorer-no-repo') } let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) } - let(:forked_from_project) { create(:project) } + let(:forked_from_project) { create(:project, :repository) } let(:fork_link) { create(:forked_project_link, forked_from_project: project_with_repo) } let(:repo_saver) { Gitlab::ImportExport::RepoSaver.new(project: project_with_repo, shared: shared) } let(:bundle_path) { File.join(shared.export_path, Gitlab::ImportExport.project_bundle_filename) } diff --git a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb index f2b66c4421c..4d87f27ce05 100644 --- a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb +++ b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe Gitlab::ImportExport::MergeRequestParser do let(:user) { create(:user) } - let!(:project) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') } - let(:forked_from_project) { create(:project) } + let!(:project) { create(:project, :repository, name: 'test-repo-restorer', path: 'test-repo-restorer') } + let(:forked_from_project) { create(:project, :repository) } let(:fork_link) { create(:forked_project_link, forked_from_project: project) } let!(:merge_request) do diff --git a/spec/lib/gitlab/import_export/repo_restorer_spec.rb b/spec/lib/gitlab/import_export/repo_restorer_spec.rb index 82935af2670..d57833c3fec 100644 --- a/spec/lib/gitlab/import_export/repo_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/repo_restorer_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::ImportExport::RepoRestorer do describe 'bundle a project Git repo' do let(:user) { create(:user) } - let!(:project_with_repo) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') } + let!(:project_with_repo) { create(:project, :repository, name: 'test-repo-restorer', path: 'test-repo-restorer') } let!(:project) { create(:empty_project) } let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) } diff --git a/spec/lib/gitlab/issuable_sorter_spec.rb b/spec/lib/gitlab/issuable_sorter_spec.rb index aeb32ef96d6..c4138c063c8 100644 --- a/spec/lib/gitlab/issuable_sorter_spec.rb +++ b/spec/lib/gitlab/issuable_sorter_spec.rb @@ -1,25 +1,25 @@ require 'spec_helper' describe Gitlab::IssuableSorter do - let(:namespace1) { build(:namespace, id: 1) } - let(:project1) { build(:project, id: 1, namespace: namespace1) } + let(:namespace1) { build_stubbed(:namespace, id: 1) } + let(:project1) { build_stubbed(:empty_project, id: 1, namespace: namespace1) } - let(:project2) { build(:project, id: 2, path: "a", namespace: project1.namespace) } - let(:project3) { build(:project, id: 3, path: "b", namespace: project1.namespace) } + let(:project2) { build_stubbed(:empty_project, id: 2, path: "a", namespace: project1.namespace) } + let(:project3) { build_stubbed(:empty_project, id: 3, path: "b", namespace: project1.namespace) } - let(:namespace2) { build(:namespace, id: 2, path: "a") } - let(:namespace3) { build(:namespace, id: 3, path: "b") } - let(:project4) { build(:project, id: 4, path: "a", namespace: namespace2) } - let(:project5) { build(:project, id: 5, path: "b", namespace: namespace2) } - let(:project6) { build(:project, id: 6, path: "a", namespace: namespace3) } + let(:namespace2) { build_stubbed(:namespace, id: 2, path: "a") } + let(:namespace3) { build_stubbed(:namespace, id: 3, path: "b") } + let(:project4) { build_stubbed(:empty_project, id: 4, path: "a", namespace: namespace2) } + let(:project5) { build_stubbed(:empty_project, id: 5, path: "b", namespace: namespace2) } + let(:project6) { build_stubbed(:empty_project, id: 6, path: "a", namespace: namespace3) } let(:unsorted) { [sorted[2], sorted[3], sorted[0], sorted[1]] } let(:sorted) do - [build(:issue, iid: 1, project: project1), - build(:issue, iid: 2, project: project1), - build(:issue, iid: 10, project: project1), - build(:issue, iid: 20, project: project1)] + [build_stubbed(:issue, iid: 1, project: project1), + build_stubbed(:issue, iid: 2, project: project1), + build_stubbed(:issue, iid: 10, project: project1), + build_stubbed(:issue, iid: 20, project: project1)] end it 'sorts references by a given key' do @@ -41,14 +41,14 @@ describe Gitlab::IssuableSorter do context 'for references from multiple projects and namespaces' do let(:sorted) do - [build(:issue, iid: 1, project: project1), - build(:issue, iid: 2, project: project1), - build(:issue, iid: 10, project: project1), - build(:issue, iid: 1, project: project2), - build(:issue, iid: 1, project: project3), - build(:issue, iid: 1, project: project4), - build(:issue, iid: 1, project: project5), - build(:issue, iid: 1, project: project6)] + [build_stubbed(:issue, iid: 1, project: project1), + build_stubbed(:issue, iid: 2, project: project1), + build_stubbed(:issue, iid: 10, project: project1), + build_stubbed(:issue, iid: 1, project: project2), + build_stubbed(:issue, iid: 1, project: project3), + build_stubbed(:issue, iid: 1, project: project4), + build_stubbed(:issue, iid: 1, project: project5), + build_stubbed(:issue, iid: 1, project: project6)] end let(:unsorted) do [sorted[3], sorted[1], sorted[4], sorted[2], diff --git a/spec/lib/gitlab/middleware/go_spec.rb b/spec/lib/gitlab/middleware/go_spec.rb index 6af1564da19..de4c8b68ffa 100644 --- a/spec/lib/gitlab/middleware/go_spec.rb +++ b/spec/lib/gitlab/middleware/go_spec.rb @@ -18,7 +18,7 @@ describe Gitlab::Middleware::Go do let(:current_user) { nil } context 'with simple 2-segment project path' do - let!(:project) { create(:project, :private) } + let!(:project) { create(:empty_project, :private) } context 'with subpackages' do let(:path) { "#{project.full_path}/subpackage" } @@ -39,7 +39,7 @@ describe Gitlab::Middleware::Go do context 'with a nested project path' do let(:group) { create(:group, :nested) } - let!(:project) { create(:project, :public, namespace: group) } + let!(:project) { create(:empty_project, :public, namespace: group) } shared_examples 'a nested project' do context 'when the project is public' do diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb index d17b436b910..7851beb956b 100644 --- a/spec/lib/gitlab/project_search_results_spec.rb +++ b/spec/lib/gitlab/project_search_results_spec.rb @@ -100,14 +100,14 @@ describe Gitlab::ProjectSearchResults do end describe 'wiki search' do - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:wiki) { build(:project_wiki, project: project) } let!(:wiki_page) { wiki.create_page('Title', 'Content') } subject(:results) { described_class.new(user, project, 'Content').objects('wiki_blobs') } context 'when wiki is disabled' do - let(:project) { create(:project, :public, :wiki_disabled) } + let(:project) { create(:empty_project, :public, :wiki_disabled) } it 'hides wiki blobs from members' do project.add_reporter(user) @@ -121,7 +121,7 @@ describe Gitlab::ProjectSearchResults do end context 'when wiki is internal' do - let(:project) { create(:project, :public, :wiki_private) } + let(:project) { create(:empty_project, :public, :wiki_private) } it 'finds wiki blobs for guest' do project.add_guest(user) diff --git a/spec/lib/gitlab/repo_path_spec.rb b/spec/lib/gitlab/repo_path_spec.rb index efea4f429bf..6336f4a7125 100644 --- a/spec/lib/gitlab/repo_path_spec.rb +++ b/spec/lib/gitlab/repo_path_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe ::Gitlab::RepoPath do describe '.parse' do - set(:project) { create(:project) } + set(:project) { create(:project, :repository) } context 'a repository storage path' do it 'parses a full repository path' do diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb index 5ebaf6c1507..cd97416bcc9 100644 --- a/spec/lib/gitlab/user_access_spec.rb +++ b/spec/lib/gitlab/user_access_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::UserAccess do let(:access) { described_class.new(user, project: project) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { create(:user) } describe '#can_push_to_branch?' do diff --git a/spec/migrations/rename_system_namespaces_spec.rb b/spec/migrations/rename_system_namespaces_spec.rb index 626a6005838..747694cbe33 100644 --- a/spec/migrations/rename_system_namespaces_spec.rb +++ b/spec/migrations/rename_system_namespaces_spec.rb @@ -58,7 +58,7 @@ describe RenameSystemNamespaces, truncate: true do end it "renames the route for projects of the namespace" do - project = build(:project, path: "project-path", namespace: system_namespace) + project = build(:project, :repository, path: "project-path", namespace: system_namespace) save_invalid_routable(project) migration.up @@ -68,7 +68,7 @@ describe RenameSystemNamespaces, truncate: true do it "doesn't touch routes of namespaces that look like system" do namespace = create(:group, path: 'systemlookalike') - project = create(:project, namespace: namespace, path: 'the-project') + project = create(:project, :repository, namespace: namespace, path: 'the-project') migration.up @@ -77,7 +77,7 @@ describe RenameSystemNamespaces, truncate: true do end it "moves the the repository for a project in the namespace" do - project = build(:project, namespace: system_namespace, path: "system-project") + project = build(:project, :repository, namespace: system_namespace, path: "system-project") save_invalid_routable(project) TestEnv.copy_repo(project, bare_repo: TestEnv.factory_repo_path_bare, @@ -105,7 +105,7 @@ describe RenameSystemNamespaces, truncate: true do describe "clears the markdown cache for projects in the system namespace" do let!(:project) do - project = build(:project, namespace: system_namespace) + project = build(:project, :repository, namespace: system_namespace) save_invalid_routable(project) project end @@ -161,7 +161,7 @@ describe RenameSystemNamespaces, truncate: true do it "updates the route of the project correctly" do subgroup = build(:group, path: "subgroup", parent: system_namespace) save_invalid_routable(subgroup) - project = build(:project, path: "system0", namespace: subgroup) + project = build(:project, :repository, path: "system0", namespace: subgroup) save_invalid_routable(project) migration.up @@ -174,7 +174,7 @@ describe RenameSystemNamespaces, truncate: true do describe "#move_repositories" do let(:namespace) { create(:group, name: "hello-group") } it "moves a project for a namespace" do - create(:project, namespace: namespace, path: "hello-project") + create(:project, :repository, namespace: namespace, path: "hello-project") expected_path = File.join(TestEnv.repos_path, "bye-group", "hello-project.git") migration.move_repositories(namespace, "hello-group", "bye-group") @@ -184,7 +184,7 @@ describe RenameSystemNamespaces, truncate: true do it "moves a namespace in a subdirectory correctly" do child_namespace = create(:group, name: "sub-group", parent: namespace) - create(:project, namespace: child_namespace, path: "hello-project") + create(:project, :repository, namespace: child_namespace, path: "hello-project") expected_path = File.join(TestEnv.repos_path, "hello-group", "renamed-sub-group", "hello-project.git") @@ -195,7 +195,7 @@ describe RenameSystemNamespaces, truncate: true do it "moves a parent namespace with subdirectories" do child_namespace = create(:group, name: "sub-group", parent: namespace) - create(:project, namespace: child_namespace, path: "hello-project") + create(:project, :repository, namespace: child_namespace, path: "hello-project") expected_path = File.join(TestEnv.repos_path, "renamed-group", "sub-group", "hello-project.git") migration.move_repositories(child_namespace, "hello-group", "renamed-group") diff --git a/spec/models/blob_viewer/composer_json_spec.rb b/spec/models/blob_viewer/composer_json_spec.rb index 82f6f7e5046..35e7e1805d4 100644 --- a/spec/models/blob_viewer/composer_json_spec.rb +++ b/spec/models/blob_viewer/composer_json_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::ComposerJson do include FakeBlobHelpers - let(:project) { build(:project) } + let(:project) { build_stubbed(:empty_project) } let(:data) do <<-SPEC.strip_heredoc { diff --git a/spec/models/blob_viewer/gemspec_spec.rb b/spec/models/blob_viewer/gemspec_spec.rb index 14cc5f3c0fd..5406ff552f8 100644 --- a/spec/models/blob_viewer/gemspec_spec.rb +++ b/spec/models/blob_viewer/gemspec_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::Gemspec do include FakeBlobHelpers - let(:project) { build(:project) } + let(:project) { build_stubbed(:empty_project) } let(:data) do <<-SPEC.strip_heredoc Gem::Specification.new do |s| diff --git a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb index 7a4f9866375..344fcdeb9b6 100644 --- a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb +++ b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::GitlabCiYml do include FakeBlobHelpers - let(:project) { build(:project) } + let(:project) { build_stubbed(:empty_project) } let(:data) { File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) } let(:blob) { fake_blob(path: '.gitlab-ci.yml', data: data) } subject { described_class.new(blob) } diff --git a/spec/models/blob_viewer/package_json_spec.rb b/spec/models/blob_viewer/package_json_spec.rb index 96fb1b08c99..976c2ed3639 100644 --- a/spec/models/blob_viewer/package_json_spec.rb +++ b/spec/models/blob_viewer/package_json_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::PackageJson do include FakeBlobHelpers - let(:project) { build(:project) } + let(:project) { build_stubbed(:empty_project) } let(:data) do <<-SPEC.strip_heredoc { diff --git a/spec/models/blob_viewer/podspec_json_spec.rb b/spec/models/blob_viewer/podspec_json_spec.rb index f510077a87b..b98360ea7b7 100644 --- a/spec/models/blob_viewer/podspec_json_spec.rb +++ b/spec/models/blob_viewer/podspec_json_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::PodspecJson do include FakeBlobHelpers - let(:project) { build(:project) } + let(:project) { build_stubbed(:empty_project) } let(:data) do <<-SPEC.strip_heredoc { diff --git a/spec/models/blob_viewer/podspec_spec.rb b/spec/models/blob_viewer/podspec_spec.rb index 7c38083550c..ad2bbe034ea 100644 --- a/spec/models/blob_viewer/podspec_spec.rb +++ b/spec/models/blob_viewer/podspec_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::Podspec do include FakeBlobHelpers - let(:project) { build(:project) } + let(:project) { build_stubbed(:empty_project) } let(:data) do <<-SPEC.strip_heredoc Pod::Spec.new do |spec| diff --git a/spec/models/blob_viewer/route_map_spec.rb b/spec/models/blob_viewer/route_map_spec.rb index 115731b4970..12b6519a344 100644 --- a/spec/models/blob_viewer/route_map_spec.rb +++ b/spec/models/blob_viewer/route_map_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::RouteMap do include FakeBlobHelpers - let(:project) { build(:project) } + let(:project) { build_stubbed(:empty_project) } let(:data) do <<-MAP.strip_heredoc # Team data diff --git a/spec/models/concerns/participable_spec.rb b/spec/models/concerns/participable_spec.rb index 431f1482615..6c4b5a9e9d6 100644 --- a/spec/models/concerns/participable_spec.rb +++ b/spec/models/concerns/participable_spec.rb @@ -24,7 +24,7 @@ describe Participable do user1 = build(:user) user2 = build(:user) user3 = build(:user) - project = build(:project, :public) + project = build(:empty_project, :public) instance = model.new expect(instance).to receive(:foo).and_return(user2) @@ -57,7 +57,7 @@ describe Participable do other = other_model.new user1 = build(:user) user2 = build(:user) - project = build(:project, :public) + project = build(:empty_project, :public) expect(instance).to receive(:foo).and_return(other) expect(other).to receive(:bar).and_return(user2) @@ -69,7 +69,7 @@ describe Participable do context 'when using a Proc as an attribute' do it 'calls the supplied Proc' do user1 = build(:user) - project = build(:project, :public) + project = build(:empty_project, :public) user_arg = nil ext_arg = nil diff --git a/spec/models/concerns/resolvable_note_spec.rb b/spec/models/concerns/resolvable_note_spec.rb index 53eaa6f8461..d00faa4f8be 100644 --- a/spec/models/concerns/resolvable_note_spec.rb +++ b/spec/models/concerns/resolvable_note_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Note, ResolvableNote do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } subject { create(:discussion_note_on_merge_request, noteable: merge_request, project: project) } diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb index 36aedd2f701..866a835d62a 100644 --- a/spec/models/concerns/routable_spec.rb +++ b/spec/models/concerns/routable_spec.rb @@ -27,7 +27,7 @@ describe Group, 'Routable' do it 'ensure route path uniqueness across different objects' do create(:group, parent: group, path: 'xyz') - duplicate = build(:project, namespace: group, path: 'xyz') + duplicate = build(:empty_project, namespace: group, path: 'xyz') expect { duplicate.save! }.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Route path has already been taken, Route is invalid') end diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb index eff41d85972..bae88cb1d24 100644 --- a/spec/models/container_repository_spec.rb +++ b/spec/models/container_repository_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe ContainerRepository do let(:group) { create(:group, name: 'group') } - let(:project) { create(:project, path: 'test', group: group) } + let(:project) { create(:project, :repository, path: 'test', group: group) } let(:repository) do create(:container_repository, name: 'my_image', project: project) @@ -41,7 +41,7 @@ describe ContainerRepository do end context 'when path contains uppercase letters' do - let(:project) { create(:project, path: 'MY_PROJECT', group: group) } + let(:project) { create(:project, :repository, path: 'MY_PROJECT', group: group) } it 'returns a full path without capital letters' do expect(repository.path).to eq('group/my_project/my_image') diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb index 6447095078b..c5708e70ef9 100644 --- a/spec/models/deployment_spec.rb +++ b/spec/models/deployment_spec.rb @@ -91,7 +91,7 @@ describe Deployment do end describe '#additional_metrics' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:deployment) { create(:deployment, project: project) } subject { deployment.additional_metrics } diff --git a/spec/models/diff_discussion_spec.rb b/spec/models/diff_discussion_spec.rb index 2704698f6c9..fa02434b0fd 100644 --- a/spec/models/diff_discussion_spec.rb +++ b/spec/models/diff_discussion_spec.rb @@ -5,7 +5,7 @@ describe DiffDiscussion do subject { described_class.new([diff_note]) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } let(:diff_note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) } diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index ebf2c070116..9a35213c98d 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -21,7 +21,7 @@ describe Environment do it { is_expected.to validate_uniqueness_of(:external_url).scoped_to(:project_id) } describe '.order_by_last_deployed_at' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let!(:environment1) { create(:environment, project: project) } let!(:environment2) { create(:environment, project: project) } let!(:environment3) { create(:environment, project: project) } diff --git a/spec/models/forked_project_link_spec.rb b/spec/models/forked_project_link_spec.rb index 38fbdd2536a..7dbeb4d2e74 100644 --- a/spec/models/forked_project_link_spec.rb +++ b/spec/models/forked_project_link_spec.rb @@ -41,7 +41,7 @@ describe ForkedProjectLink, "add link on fork" do end describe '#forked?' do - let(:project_to) { create(:project, forked_project_link: forked_project_link) } + let(:project_to) { create(:project, :repository, forked_project_link: forked_project_link) } let(:forked_project_link) { create(:forked_project_link) } before do diff --git a/spec/models/gpg_signature_spec.rb b/spec/models/gpg_signature_spec.rb index 9a9b1900aa5..c58fd46762a 100644 --- a/spec/models/gpg_signature_spec.rb +++ b/spec/models/gpg_signature_spec.rb @@ -16,7 +16,7 @@ RSpec.describe GpgSignature do describe '#commit' do it 'fetches the commit through the project' do commit_sha = '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' - project = create :project + project = create :project, :repository commit = create :commit, project: project gpg_signature = create :gpg_signature, commit_sha: commit_sha diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index d72790eefe5..eaf06668327 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -724,7 +724,7 @@ describe Issue do end describe '#check_for_spam' do - let(:project) { create :project, visibility_level: visibility_level } + let(:project) { create :empty_project, visibility_level: visibility_level } let(:issue) { create :issue, project: project } subject do diff --git a/spec/models/project_group_link_spec.rb b/spec/models/project_group_link_spec.rb index d68d8b719cd..0938a7b1b6d 100644 --- a/spec/models/project_group_link_spec.rb +++ b/spec/models/project_group_link_spec.rb @@ -9,7 +9,7 @@ describe ProjectGroupLink do describe "Validation" do let(:parent_group) { create(:group) } let(:group) { create(:group, parent: parent_group) } - let(:project) { create(:project, group: group) } + let(:project) { create(:empty_project, group: group) } let!(:project_group_link) { create(:project_group_link, project: project) } it { is_expected.to validate_presence_of(:project_id) } diff --git a/spec/models/project_services/chat_notification_service_spec.rb b/spec/models/project_services/chat_notification_service_spec.rb index 413ceed73bf..ae80c4ae002 100644 --- a/spec/models/project_services/chat_notification_service_spec.rb +++ b/spec/models/project_services/chat_notification_service_spec.rb @@ -20,7 +20,7 @@ describe ChatNotificationService do context 'with repository' do it 'returns true' do - subject.project = create(:project) + subject.project = create(:project, :repository) expect(subject.can_test?).to be true end diff --git a/spec/models/project_services/issue_tracker_service_spec.rb b/spec/models/project_services/issue_tracker_service_spec.rb index e6a1752576b..3ca123cb75d 100644 --- a/spec/models/project_services/issue_tracker_service_spec.rb +++ b/spec/models/project_services/issue_tracker_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe IssueTrackerService do describe 'Validations' do - let(:project) { create :project } + let(:project) { create :empty_project } describe 'only one issue tracker per project' do let(:service) { RedmineService.new(project: project, active: true) } diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index bc9374d6dbb..69bb8f1c725 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -190,7 +190,7 @@ describe JiraService do describe '#test_settings' do let(:jira_service) do described_class.new( - project: create(:project), + project: create(:empty_project), url: 'http://jira.example.com', username: 'jira_username', password: 'jira_password' diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 29cc9d35fc9..3bc6fb09778 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -261,27 +261,27 @@ describe Project do describe 'path validation' do it 'allows paths reserved on the root namespace' do - project = build(:project, path: 'api') + project = build(:empty_project, path: 'api') expect(project).to be_valid end it 'rejects paths reserved on another level' do - project = build(:project, path: 'tree') + project = build(:empty_project, path: 'tree') expect(project).not_to be_valid end it 'rejects nested paths' do parent = create(:group, :nested, path: 'environments') - project = build(:project, path: 'folders', namespace: parent) + project = build(:empty_project, path: 'folders', namespace: parent) expect(project).not_to be_valid end it 'allows a reserved group name' do parent = create(:group) - project = build(:project, path: 'avatar', namespace: parent) + project = build(:empty_project, path: 'avatar', namespace: parent) expect(project).to be_valid end @@ -2045,7 +2045,7 @@ describe Project do end describe '#route_map_for' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:route_map) do <<-MAP.strip_heredoc - source: /source/(.*)/ @@ -2082,7 +2082,7 @@ describe Project do end describe '#public_path_for_source_path' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:route_map) do Gitlab::RouteMap.new(<<-MAP.strip_heredoc) - source: /source/(.*)/ @@ -2196,7 +2196,7 @@ describe Project do end describe '#pipeline_status' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } it 'builds a pipeline status' do expect(project.pipeline_status).to be_a(Gitlab::Cache::Ci::ProjectPipelineStatus) end @@ -2207,7 +2207,7 @@ describe Project do end describe '#append_or_update_attribute' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } it 'shows full error updating an invalid MR' do error_message = 'Failed to replace merge_requests because one or more of the new records could not be saved.'\ diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 68228a038a8..9ccd366a48e 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -330,7 +330,7 @@ describe ProjectTeam do end shared_examples 'max member access for users' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:group) { create(:group) } let(:second_group) { create(:group) } diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 0fd3a4d622a..3107037925b 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -300,7 +300,7 @@ describe Repository do end context "when committing to another project" do - let(:forked_project) { create(:project) } + let(:forked_project) { create(:project, :repository) } it "creates a fork and commit to the forked project" do expect do diff --git a/spec/models/sent_notification_spec.rb b/spec/models/sent_notification_spec.rb index 8b6b02916ae..8f05deb8b15 100644 --- a/spec/models/sent_notification_spec.rb +++ b/spec/models/sent_notification_spec.rb @@ -21,7 +21,7 @@ describe SentNotification do end context "when the noteable project and discussion project match" do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:issue) { create(:issue, project: project) } let(:discussion_id) { create(:note, project: project, noteable: issue).discussion_id } subject { build(:sent_notification, project: project, noteable: issue, in_reply_to_discussion_id: discussion_id) } @@ -128,7 +128,7 @@ describe SentNotification do end context 'for commit' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:commit) { project.commit } subject { described_class.record(commit, project.creator.id) } diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb index a83a83a7349..11a4c3c742e 100644 --- a/spec/policies/ci/build_policy_spec.rb +++ b/spec/policies/ci/build_policy_spec.rb @@ -97,7 +97,7 @@ describe Ci::BuildPolicy do end describe 'rules for protected ref' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:build) { create(:ci_build, ref: 'some-ref', pipeline: pipeline) } before do diff --git a/spec/policies/ci/pipeline_policy_spec.rb b/spec/policies/ci/pipeline_policy_spec.rb index b11b06d301f..48a8064c5fc 100644 --- a/spec/policies/ci/pipeline_policy_spec.rb +++ b/spec/policies/ci/pipeline_policy_spec.rb @@ -10,7 +10,7 @@ describe Ci::PipelinePolicy, :models do describe 'rules' do describe 'rules for protected ref' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do project.add_developer(user) diff --git a/spec/policies/environment_policy_spec.rb b/spec/policies/environment_policy_spec.rb index 035e20c7452..de4cb5b30c5 100644 --- a/spec/policies/environment_policy_spec.rb +++ b/spec/policies/environment_policy_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe EnvironmentPolicy do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:environment) do create(:environment, :with_review_app, project: project) @@ -14,7 +14,7 @@ describe EnvironmentPolicy do describe '#rules' do context 'when user does not have access to the project' do - let(:project) { create(:project, :private) } + let(:project) { create(:project, :private, :repository) } it 'does not include ability to stop environment' do expect(policy).to be_disallowed :stop_environment @@ -22,7 +22,7 @@ describe EnvironmentPolicy do end context 'when anonymous user has access to the project' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } it 'does not include ability to stop environment' do expect(policy).to be_disallowed :stop_environment @@ -30,7 +30,7 @@ describe EnvironmentPolicy do end context 'when team member has access to the project' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } before do project.add_developer(user) diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb index c1a0313b13c..0dd4ede5538 100644 --- a/spec/presenters/merge_request_presenter_spec.rb +++ b/spec/presenters/merge_request_presenter_spec.rb @@ -105,7 +105,7 @@ describe MergeRequestPresenter do end context 'issues links' do - let(:project) { create(:project, :private, creator: user, namespace: user.namespace) } + let(:project) { create(:project, :private, :repository, creator: user, namespace: user.namespace) } let(:issue_a) { create(:issue, project: project) } let(:issue_b) { create(:issue, project: project) } diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index 9e268adf950..55c998b13b8 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -80,7 +80,7 @@ describe API::Files do context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository files' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:current_user) { nil } end end @@ -153,7 +153,7 @@ describe API::Files do context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository raw files' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:current_user) { nil } end end diff --git a/spec/requests/api/pipeline_schedules_spec.rb b/spec/requests/api/pipeline_schedules_spec.rb index b34555d2815..9ff2b782b52 100644 --- a/spec/requests/api/pipeline_schedules_spec.rb +++ b/spec/requests/api/pipeline_schedules_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe API::PipelineSchedules do set(:developer) { create(:user) } set(:user) { create(:user) } - set(:project) { create(:project) } + set(:project) { create(:project, :repository) } before do project.add_developer(developer) diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb index 9fc73c6e092..f5413913c1e 100644 --- a/spec/requests/api/todos_spec.rb +++ b/spec/requests/api/todos_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe API::Todos do - let(:project_1) { create(:project) } + let(:project_1) { create(:project, :repository) } let(:project_2) { create(:empty_project) } let(:author_1) { create(:user) } let(:author_2) { create(:user) } diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index 153596c2975..d5c53b703dd 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -13,7 +13,7 @@ describe API::Triggers do let!(:trigger_request) { create(:ci_trigger_request, trigger: trigger, created_at: '2015-01-01 12:13:14') } describe 'POST /projects/:project_id/trigger/pipeline' do - let!(:project2) { create(:project) } + let!(:project2) { create(:project, :repository) } let(:options) do { token: trigger_token diff --git a/spec/requests/api/v3/files_spec.rb b/spec/requests/api/v3/files_spec.rb index 8b2d165c763..4ffa5d1784e 100644 --- a/spec/requests/api/v3/files_spec.rb +++ b/spec/requests/api/v3/files_spec.rb @@ -74,7 +74,7 @@ describe API::V3::Files do context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository files' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:current_user) { nil } end end diff --git a/spec/requests/api/v3/project_hooks_spec.rb b/spec/requests/api/v3/project_hooks_spec.rb index b0eddbb5dd2..e7014458773 100644 --- a/spec/requests/api/v3/project_hooks_spec.rb +++ b/spec/requests/api/v3/project_hooks_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe API::ProjectHooks, 'ProjectHooks' do let(:user) { create(:user) } let(:user3) { create(:user) } - let!(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } + let!(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) } let!(:hook) do create(:project_hook, :all_events_enabled, @@ -204,7 +204,7 @@ describe API::ProjectHooks, 'ProjectHooks' do it "returns a 404 if a user attempts to delete project hooks he/she does not own" do test_user = create(:user) - other_project = create(:project) + other_project = create(:empty_project) other_project.team << [test_user, :master] delete v3_api("/projects/#{other_project.id}/hooks/#{hook.id}", test_user) diff --git a/spec/requests/api/v3/triggers_spec.rb b/spec/requests/api/v3/triggers_spec.rb index 60212660fb6..2a593dd8135 100644 --- a/spec/requests/api/v3/triggers_spec.rb +++ b/spec/requests/api/v3/triggers_spec.rb @@ -10,7 +10,7 @@ describe API::V3::Triggers do let!(:trigger) { create(:ci_trigger, project: project, token: trigger_token) } describe 'POST /projects/:project_id/trigger' do - let!(:project2) { create(:project) } + let!(:project2) { create(:empty_project) } let(:options) do { token: trigger_token diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb index 4f1a90750b3..ff470a6cad0 100644 --- a/spec/requests/lfs_http_spec.rb +++ b/spec/requests/lfs_http_spec.rb @@ -600,7 +600,7 @@ describe 'Git LFS API and storage' do context 'when user is not authenticated' do describe 'is accessing public project' do - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:update_lfs_permissions) do project.lfs_objects << lfs_object @@ -642,7 +642,7 @@ describe 'Git LFS API and storage' do end describe 'upload' do - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:body) do { 'operation' => 'upload', @@ -1019,7 +1019,7 @@ describe 'Git LFS API and storage' do end describe 'to a forked project' do - let(:upstream_project) { create(:project, :public) } + let(:upstream_project) { create(:empty_project, :public) } let(:project_owner) { create(:user) } let(:project) { fork_project(upstream_project, project_owner) } diff --git a/spec/requests/request_profiler_spec.rb b/spec/requests/request_profiler_spec.rb index 9afeb2983b0..1325ba37fd8 100644 --- a/spec/requests/request_profiler_spec.rb +++ b/spec/requests/request_profiler_spec.rb @@ -13,7 +13,7 @@ describe 'Request Profiler' do end it 'creates a profile of the request' do - project = create(:project, namespace: user.namespace) + project = create(:empty_project, namespace: user.namespace) time = Time.now path = "/#{project.full_path}" diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 4ec495f612e..730df4e0336 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -75,7 +75,7 @@ describe Ci::CreatePipelineService do end context 'when merge request target project is different from source project' do - let!(:target_project) { create(:project) } + let!(:target_project) { create(:project, :repository) } let!(:forked_project_link) { create(:forked_project_link, forked_to_project: project, forked_from_project: target_project) } it 'updates head pipeline for merge request' do diff --git a/spec/services/ci/play_build_service_spec.rb b/spec/services/ci/play_build_service_spec.rb index 1ced26ff98d..04f926ccb32 100644 --- a/spec/services/ci/play_build_service_spec.rb +++ b/spec/services/ci/play_build_service_spec.rb @@ -33,7 +33,7 @@ describe Ci::PlayBuildService, '#execute' do end context 'when project has repository' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } it 'allows user with developer role to play a build' do project.add_developer(user) diff --git a/spec/services/labels/create_service_spec.rb b/spec/services/labels/create_service_spec.rb index ecb88653001..9ff3a5375b9 100644 --- a/spec/services/labels/create_service_spec.rb +++ b/spec/services/labels/create_service_spec.rb @@ -2,9 +2,9 @@ require 'spec_helper' describe Labels::CreateService do describe '#execute' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:group) { create(:group) } - + let(:hex_color) { '#FF0000' } let(:named_color) { 'red' } let(:upcase_color) { 'RED' } diff --git a/spec/services/labels/update_service_spec.rb b/spec/services/labels/update_service_spec.rb index bb95fe20fbf..f0bec7e9f9c 100644 --- a/spec/services/labels/update_service_spec.rb +++ b/spec/services/labels/update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Labels::UpdateService do describe '#execute' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:hex_color) { '#FF0000' } let(:named_color) { 'red' } diff --git a/spec/services/milestones/destroy_service_spec.rb b/spec/services/milestones/destroy_service_spec.rb index 5739386dd0d..f7a6c3d323e 100644 --- a/spec/services/milestones/destroy_service_spec.rb +++ b/spec/services/milestones/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Milestones::DestroyService do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:milestone) { create(:milestone, title: 'Milestone v1.0', project: project) } let(:issue) { create(:issue, project: project, milestone: milestone) } let(:merge_request) { create(:merge_request, source_project: project, milestone: milestone) } diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb index 786335120fd..db30fe2c24e 100644 --- a/spec/services/users/destroy_service_spec.rb +++ b/spec/services/users/destroy_service_spec.rb @@ -40,7 +40,7 @@ describe Users::DestroyService do end context "a deleted user's issues" do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } before do project.add_developer(user) @@ -66,7 +66,7 @@ describe Users::DestroyService do end context "a deleted user's merge_requests" do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do project.add_developer(user) diff --git a/spec/services/users/migrate_to_ghost_user_service_spec.rb b/spec/services/users/migrate_to_ghost_user_service_spec.rb index a0030ce8809..ac3a8738cac 100644 --- a/spec/services/users/migrate_to_ghost_user_service_spec.rb +++ b/spec/services/users/migrate_to_ghost_user_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Users::MigrateToGhostUserService do let!(:user) { create(:user) } - let!(:project) { create(:project) } + let!(:project) { create(:project, :repository) } let(:service) { described_class.new(user) } context "migrating a user's associated records to the ghost user" do diff --git a/spec/support/features/issuable_slash_commands_shared_examples.rb b/spec/support/features/issuable_slash_commands_shared_examples.rb index 035428a7d9b..47a7fd0c2ea 100644 --- a/spec/support/features/issuable_slash_commands_shared_examples.rb +++ b/spec/support/features/issuable_slash_commands_shared_examples.rb @@ -5,7 +5,14 @@ shared_examples 'issuable record that supports quick actions in its description include QuickActionsHelpers let(:master) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) do + case issuable_type + when :merge_request + create(:project, :public, :repository) + when :issue + create(:empty_project, :public) + end + end let!(:milestone) { create(:milestone, project: project, title: 'ASAP') } let!(:label_bug) { create(:label, project: project, title: 'bug') } let!(:label_feature) { create(:label, project: project, title: 'feature') } diff --git a/spec/support/import_export/export_file_helper.rb b/spec/support/import_export/export_file_helper.rb index 57b6abe12b7..2011408be93 100644 --- a/spec/support/import_export/export_file_helper.rb +++ b/spec/support/import_export/export_file_helper.rb @@ -6,7 +6,7 @@ module ExportFileHelper ObjectWithParent = Struct.new(:object, :parent, :key_found) def setup_project - project = create(:project, :public) + project = create(:project, :public, :repository) create(:release, project: project) diff --git a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb index 855051921f0..bbb63a08374 100644 --- a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb +++ b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb @@ -3,7 +3,14 @@ require "spec_helper" shared_examples "migrating a deleted user's associated records to the ghost user" do |record_class, fields| record_class_name = record_class.to_s.titleize.downcase - let(:project) { create(:project) } + let(:project) do + case record_class + when MergeRequest + create(:project, :repository) + else + create(:empty_project) + end + end before do project.add_developer(user) diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb index 47e9365e13d..c2510a10286 100644 --- a/spec/uploaders/file_uploader_spec.rb +++ b/spec/uploaders/file_uploader_spec.rb @@ -5,7 +5,7 @@ describe FileUploader do describe '.absolute_path' do it 'returns the correct absolute path by building it dynamically' do - project = build_stubbed(:project) + project = build_stubbed(:empty_project) upload = double(model: project, path: 'secret/foo.jpg') dynamic_segment = project.path_with_namespace diff --git a/spec/validators/dynamic_path_validator_spec.rb b/spec/validators/dynamic_path_validator_spec.rb index 8bd5306ff98..dd90a836a78 100644 --- a/spec/validators/dynamic_path_validator_spec.rb +++ b/spec/validators/dynamic_path_validator_spec.rb @@ -28,7 +28,7 @@ describe DynamicPathValidator do describe '#path_valid_for_record?' do context 'for project' do it 'calls valid_project_path?' do - project = build(:project, path: 'activity') + project = build(:empty_project, path: 'activity') expect(described_class).to receive(:valid_project_path?).with(project.full_path).and_call_original diff --git a/spec/views/layouts/nav/_project.html.haml_spec.rb b/spec/views/layouts/nav/_project.html.haml_spec.rb index fd1637ca91b..faea2505e40 100644 --- a/spec/views/layouts/nav/_project.html.haml_spec.rb +++ b/spec/views/layouts/nav/_project.html.haml_spec.rb @@ -5,7 +5,7 @@ describe 'layouts/nav/_project' do before do stub_container_registry_config(enabled: true) - assign(:project, create(:project)) + assign(:project, create(:project, :repository)) allow(view).to receive(:current_ref).and_return('master') allow(view).to receive(:can?).and_return(true) diff --git a/spec/views/notify/pipeline_failed_email.html.haml_spec.rb b/spec/views/notify/pipeline_failed_email.html.haml_spec.rb index f627f9165fb..d9d73f789c5 100644 --- a/spec/views/notify/pipeline_failed_email.html.haml_spec.rb +++ b/spec/views/notify/pipeline_failed_email.html.haml_spec.rb @@ -4,7 +4,7 @@ describe 'notify/pipeline_failed_email.html.haml' do include Devise::Test::ControllerHelpers let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, :simple, source_project: project) } let(:pipeline) do diff --git a/spec/views/notify/pipeline_success_email.html.haml_spec.rb b/spec/views/notify/pipeline_success_email.html.haml_spec.rb index ecd096ee579..a793b37e412 100644 --- a/spec/views/notify/pipeline_success_email.html.haml_spec.rb +++ b/spec/views/notify/pipeline_success_email.html.haml_spec.rb @@ -4,7 +4,7 @@ describe 'notify/pipeline_success_email.html.haml' do include Devise::Test::ControllerHelpers let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, :simple, source_project: project) } let(:pipeline) do diff --git a/spec/workers/create_gpg_signature_worker_spec.rb b/spec/workers/create_gpg_signature_worker_spec.rb index c6a17d77d73..62ec011a3fe 100644 --- a/spec/workers/create_gpg_signature_worker_spec.rb +++ b/spec/workers/create_gpg_signature_worker_spec.rb @@ -4,7 +4,7 @@ describe CreateGpgSignatureWorker do context 'when GpgKey is found' do it 'calls Commit#signature' do commit_sha = '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' - project = create :project + project = create :empty_project commit = instance_double(Commit) allow(Project).to receive(:find_by).with(id: project.id).and_return(project) @@ -18,7 +18,7 @@ describe CreateGpgSignatureWorker do context 'when Commit is not found' do let(:nonexisting_commit_sha) { 'bogus' } - let(:project) { create :project } + let(:project) { create :empty_project } it 'does not raise errors' do expect { described_class.new.perform(nonexisting_commit_sha, project.id) }.not_to raise_error diff --git a/spec/workers/process_commit_worker_spec.rb b/spec/workers/process_commit_worker_spec.rb index 6ebc94bb544..24f8ca67594 100644 --- a/spec/workers/process_commit_worker_spec.rb +++ b/spec/workers/process_commit_worker_spec.rb @@ -33,7 +33,7 @@ describe ProcessCommitWorker do end context 'when commit already exists in upstream project' do - let(:forked) { create(:project, :public) } + let(:forked) { create(:project, :public, :repository) } it 'does not process commit message' do create(:forked_project_link, forked_to_project: forked, forked_from_project: project) -- cgit v1.2.1 From feb94e8ea3b003938f5df963d3c61757ffe27bcb Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Tue, 1 Aug 2017 21:51:53 +0200 Subject: Move timeframe_start and timeframe_end to common query context --- .../prometheus/queries/additional_metrics_deployment_query.rb | 9 ++++----- .../prometheus/queries/additional_metrics_environment_query.rb | 9 +-------- lib/gitlab/prometheus/queries/query_additional_metrics.rb | 4 +++- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb b/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb index 51d934b9ae2..69d055c901c 100644 --- a/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb +++ b/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb @@ -6,14 +6,13 @@ module Gitlab def query(deployment_id) Deployment.find_by(id: deployment_id).try do |deployment| - query_context = common_query_context(deployment.environment).merge( - { + query_metrics( + common_query_context( + deployment.environment, timeframe_start: (deployment.created_at - 30.minutes).to_f, timeframe_end: (deployment.created_at + 30.minutes).to_f - } + ) ) - - query_metrics(query_context) end end end diff --git a/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb b/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb index 9f798f5b892..580153556ea 100644 --- a/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb +++ b/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb @@ -6,14 +6,7 @@ module Gitlab def query(environment_id) Environment.find_by(id: environment_id).try do |environment| - query_context = common_query_context(environment).merge( - { - timeframe_start: 8.hours.ago.to_f, - timeframe_end: Time.now.to_f - } - ) - - query_metrics(query_context) + query_metrics(common_query_context(environment)) end end end diff --git a/lib/gitlab/prometheus/queries/query_additional_metrics.rb b/lib/gitlab/prometheus/queries/query_additional_metrics.rb index d96921a9ee7..d5f219ce6f9 100644 --- a/lib/gitlab/prometheus/queries/query_additional_metrics.rb +++ b/lib/gitlab/prometheus/queries/query_additional_metrics.rb @@ -71,8 +71,10 @@ module Gitlab result.select { |group| group.metrics.any? } end - def common_query_context(environment) + def common_query_context(environment, timeframe_start: 8.hours.ago.to_f, timeframe_end: Time.now.to_f) { + timeframe_start: timeframe_start, + timeframe_end: timeframe_end, ci_environment_slug: environment.slug, kube_namespace: environment.project.kubernetes_service&.actual_namespace || '', environment_filter: %{container_name!="POD",environment="#{environment.slug}"} -- cgit v1.2.1 From ba97a42193d85182cf0974b8aac508d40b6f368a Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Tue, 1 Aug 2017 22:11:59 +0200 Subject: Remove default arguments for common query context --- lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb | 4 +++- lib/gitlab/prometheus/queries/query_additional_metrics.rb | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb b/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb index 580153556ea..db4708b22e4 100644 --- a/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb +++ b/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb @@ -6,7 +6,9 @@ module Gitlab def query(environment_id) Environment.find_by(id: environment_id).try do |environment| - query_metrics(common_query_context(environment)) + query_metrics( + common_query_context(environment, timeframe_start: 8.hours.ago.to_f, timeframe_end: Time.now.to_f) + ) end end end diff --git a/lib/gitlab/prometheus/queries/query_additional_metrics.rb b/lib/gitlab/prometheus/queries/query_additional_metrics.rb index d5f219ce6f9..7ac6162b54d 100644 --- a/lib/gitlab/prometheus/queries/query_additional_metrics.rb +++ b/lib/gitlab/prometheus/queries/query_additional_metrics.rb @@ -71,7 +71,7 @@ module Gitlab result.select { |group| group.metrics.any? } end - def common_query_context(environment, timeframe_start: 8.hours.ago.to_f, timeframe_end: Time.now.to_f) + def common_query_context(environment, timeframe_start:, timeframe_end:) { timeframe_start: timeframe_start, timeframe_end: timeframe_end, -- cgit v1.2.1 From 9f22762dd965c0ca8345e87225a7ef6c38649ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E6=B6=9B?= Date: Wed, 2 Aug 2017 09:31:43 +0800 Subject: Synchronous zanata community contribution translation --- locale/ja/gitlab.po | 2 +- locale/pt_BR/gitlab.po | 45 +++-- locale/ru/gitlab.po | 489 +++++++++++++++++++++++++++---------------------- locale/uk/gitlab.po | 5 +- locale/zh_TW/gitlab.po | 5 +- 5 files changed, 294 insertions(+), 252 deletions(-) diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po index 04c61906c73..801674ce964 100644 --- a/locale/ja/gitlab.po +++ b/locale/ja/gitlab.po @@ -29,7 +29,7 @@ msgid_plural "%d commits" msgstr[0] "%d個のコミット" msgid "%{commit_author_link} committed %{commit_timeago}" -msgstr "%{commit_author_link}は%{commit_timeago}前、コミットしました。" +msgstr "%{commit_timeago}に%{commit_author_link}がコミットしました。" msgid "1 pipeline" msgid_plural "%d pipelines" diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po index ee00b816b84..9e3c78b6148 100644 --- a/locale/pt_BR/gitlab.po +++ b/locale/pt_BR/gitlab.po @@ -11,7 +11,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language-Team: Portuguese (Brazil) (https://translate.zanata.org/project/view/GitLab)\n" -"PO-Revision-Date: 2017-07-14 01:17-0400\n" +"PO-Revision-Date: 2017-08-01 09:47-0400\n" "Last-Translator: Huang Tao \n" "Language: pt-BR\n" "X-Generator: Zanata 3.9.6\n" @@ -42,7 +42,7 @@ msgid "A collection of graphs regarding Continuous Integration" msgstr "Uma coleção de gráficos sobre Integração Contínua" msgid "About auto deploy" -msgstr "Sobre a implantação automática" +msgstr "Sobre o deploy automático" msgid "Active" msgstr "Ativo" @@ -84,12 +84,12 @@ msgid "" "choose a GitLab CI Yaml template and commit your changes. " "%{link_to_autodeploy_doc}" msgstr "" -"O branch %{branch_name} foi criado. Para configurar a " -"implantação automática, selecione um modelo de Yaml do GitLab CI e registre " -"suas mudanças. %{link_to_autodeploy_doc}" +"O branch %{branch_name} foi criado. Para configurar o " +"deploy automático, selecione um modelo de Yaml do GitLab CI e commit suas " +"mudanças. %{link_to_autodeploy_doc}" msgid "BranchSwitcherPlaceholder|Search branches" -msgstr "BranchSwitcherPlaceholder|Procurar por branches" +msgstr "Procurar por branches" msgid "BranchSwitcherTitle|Switch branch" msgstr "BranchSwitcherTitle|Mudar de branch" @@ -113,7 +113,7 @@ msgid "ByAuthor|by" msgstr "por" msgid "CI configuration" -msgstr "Configuração da Integração Contínua" +msgstr "Configuração da IC" msgid "Cancel" msgstr "Cancelar" @@ -269,7 +269,7 @@ msgid "CreateTag|Tag" msgstr "Tag" msgid "CreateTokenToCloneLink|create a personal access token" -msgstr "CreateTokenToCloneLink|criar um token de acesso pessoal" +msgstr "criar um token de acesso pessoal" msgid "Cron Timezone" msgstr "Fuso horário do cron" @@ -419,8 +419,7 @@ msgid "From issue creation until deploy to production" msgstr "Da abertura de tarefas até a implantação para a produção" msgid "From merge request merge until deploy to production" -msgstr "" -"Do merge request até a implantação em produção" +msgstr "Do merge request até a implantação em produção" msgid "Go to your fork" msgstr "Ir para seu fork" @@ -618,19 +617,19 @@ msgid "Pipeline Schedules" msgstr "Agendamentos da Pipeline" msgid "PipelineCharts|Failed:" -msgstr "PipelineCharts|Falhou:" +msgstr "Falhou:" msgid "PipelineCharts|Overall statistics" -msgstr "PipelineCharts|Estatísticas gerais" +msgstr "Estatísticas gerais" msgid "PipelineCharts|Success ratio:" -msgstr "PipelineCharts|Taxa de sucesso:" +msgstr "Taxa de sucesso:" msgid "PipelineCharts|Successful:" -msgstr "PipelineCharts|Sucesso:" +msgstr "Sucesso:" msgid "PipelineCharts|Total:" -msgstr "PipelineCharts|Total:" +msgstr "Total:" msgid "PipelineSchedules|Activated" msgstr "Ativado" @@ -645,10 +644,10 @@ msgid "PipelineSchedules|Inactive" msgstr "Inativo" msgid "PipelineSchedules|Input variable key" -msgstr "PipelineSchedules|Chave da variável de entrada" +msgstr "Chave da variável de entrada" msgid "PipelineSchedules|Input variable value" -msgstr "PipelineSchedules|Valor da variável de entrada" +msgstr "Valor da variável de entrada" msgid "PipelineSchedules|Next Run" msgstr "Próxima Execução" @@ -660,7 +659,7 @@ msgid "PipelineSchedules|Provide a short description for this pipeline" msgstr "Digite uma descrição curta para esta pipeline" msgid "PipelineSchedules|Remove variable row" -msgstr "PipelineSchedules|Remova a linha da variável" +msgstr "Remova a linha da variável" msgid "PipelineSchedules|Take ownership" msgstr "Tornar-se proprietário" @@ -669,7 +668,7 @@ msgid "PipelineSchedules|Target" msgstr "Destino" msgid "PipelineSchedules|Variables" -msgstr "PipelineSchedules|Variáveis" +msgstr "Variáveis" msgid "PipelineSheduleIntervalPattern|Custom" msgstr "Personalizado" @@ -681,10 +680,10 @@ msgid "Pipelines charts" msgstr "Gráficos de pipelines" msgid "Pipeline|all" -msgstr "Pipeline|todos" +msgstr "todos" msgid "Pipeline|success" -msgstr "Pipeline|sucesso" +msgstr "sucesso" msgid "Pipeline|with stage" msgstr "com etapa" @@ -974,7 +973,7 @@ msgid "Time before an issue gets scheduled" msgstr "Tempo até que uma issue seja agendada" msgid "Time before an issue starts implementation" -msgstr "Tempo até que uma issue comece a ser implementada" +msgstr "Tempo até que uma issue comece a ser implementado" msgid "Time between merge request creation and merge/close" msgstr "" @@ -1136,7 +1135,7 @@ msgid "Upload file" msgstr "Enviar arquivo" msgid "UploadLink|click to upload" -msgstr "UploadLink|clique para fazer upload" +msgstr "clique para fazer upload" msgid "Use your global notification setting" msgstr "Utilizar configuração de notificação global" diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po index 4643bed98e2..f9e8dcd05e7 100644 --- a/locale/ru/gitlab.po +++ b/locale/ru/gitlab.po @@ -4,13 +4,13 @@ msgid "" msgstr "" "Project-Id-Version: gitlab 1.0.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-06-28 13:32+0200\n" +"POT-Creation-Date: 2017-07-05 08:50-0500\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2017-07-11 05:13-0400\n" -"Last-Translator: SAS \n" "Language-Team: Russian (https://translate.zanata.org/project/view/GitLab)\n" +"PO-Revision-Date: 2017-08-01 09:15-0400\n" +"Last-Translator: Андрей П. \n" "Language: ru\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " @@ -32,20 +32,20 @@ msgstr[2] "" msgid "%d commit" msgid_plural "%d commits" msgstr[0] "%d коммит" -msgstr[1] "%d коммит(а|ов)" -msgstr[2] "%d коммит(а|ов)" +msgstr[1] "%d коммитов" +msgstr[2] "%d коммитов" msgid "%{commit_author_link} committed %{commit_timeago}" -msgstr "%{commit_author_link} закоммичено %{commit_timeago}" +msgstr "%{commit_author_link} коммичено %{commit_timeago}" msgid "1 pipeline" msgid_plural "%d pipelines" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "1 конвейер" +msgstr[1] "%d конвейеры" +msgstr[2] "%d конвейеры" msgid "A collection of graphs regarding Continuous Integration" -msgstr "" +msgstr "Графики относительно непрерывной интеграции" msgid "About auto deploy" msgstr "Автоматическое развертывание" @@ -57,10 +57,10 @@ msgid "Activity" msgstr "Активность" msgid "Add Changelog" -msgstr "Добавить в журнал изменений" +msgstr "Добавить журнал изменений" msgid "Add Contribution guide" -msgstr "Добавить руководство для контрибьютеров" +msgstr "Добавить руководство" msgid "Add License" msgstr "Добавить лицензию" @@ -71,7 +71,7 @@ msgstr "" "SSH." msgid "Add new directory" -msgstr "Добавить новую директорию" +msgstr "Добавить каталог" msgid "Archived project! Repository is read-only" msgstr "Архивный проект! Репозиторий доступен только для чтения" @@ -98,16 +98,16 @@ msgstr "" "%{link_to_autodeploy_doc}" msgid "BranchSwitcherPlaceholder|Search branches" -msgstr "BranchSwitcherPlaceholder|Поиск веток" +msgstr "Поиск веток" msgid "BranchSwitcherTitle|Switch branch" -msgstr "BranchSwitcherTitle|Переключить ветку" +msgstr "Переключить ветку" msgid "Branches" msgstr "Ветки" msgid "Browse Directory" -msgstr "Просмотр директории" +msgstr "Обзор" msgid "Browse File" msgstr "Просмотр файла" @@ -119,7 +119,7 @@ msgid "Browse files" msgstr "Просмотр файлов" msgid "ByAuthor|by" -msgstr "ByAuthor|по автору" +msgstr "по автору" msgid "CI configuration" msgstr "Настройка CI" @@ -128,22 +128,22 @@ msgid "Cancel" msgstr "Отмена" msgid "ChangeTypeActionLabel|Pick into branch" -msgstr "ChangeTypeActionLabel|Выбрать в ветке" +msgstr "Выбрать в ветке" msgid "ChangeTypeActionLabel|Revert in branch" -msgstr "ChangeTypeActionLabel|Отменить в ветке" +msgstr "Отменить в ветке" msgid "ChangeTypeAction|Cherry-pick" -msgstr "ChangeTypeAction|Подобрать" +msgstr "Подобрать" msgid "ChangeTypeAction|Revert" -msgstr "ChangeTypeAction|Отменить" +msgstr "Отменить" msgid "Changelog" msgstr "Журнал изменений" msgid "Charts" -msgstr "Графики" +msgstr "Диаграммы" msgid "Cherry-pick this commit" msgstr "Подобрать в этом коммите" @@ -152,58 +152,58 @@ msgid "Cherry-pick this merge request" msgstr "Побрать в этом запросе на слияние" msgid "CiStatusLabel|canceled" -msgstr "CiStatusLabel|отменено" +msgstr "отменено" msgid "CiStatusLabel|created" -msgstr "CiStatusLabel|создано" +msgstr "создано" msgid "CiStatusLabel|failed" -msgstr "CiStatusLabel|неудачно" +msgstr "неудачно" msgid "CiStatusLabel|manual action" -msgstr "CiStatusLabel|ручное действие" +msgstr "ручное действие" msgid "CiStatusLabel|passed" -msgstr "CiStatusLabel|пройдено" +msgstr "пройдено" msgid "CiStatusLabel|passed with warnings" -msgstr "CiStatusLabel|пройдено с предупреждениями" +msgstr "пройдено с предупреждениями" msgid "CiStatusLabel|pending" -msgstr "CiStatusLabel|в ожидании" +msgstr "в ожидании" msgid "CiStatusLabel|skipped" -msgstr "CiStatusLabel|пропущено" +msgstr "пропущено" msgid "CiStatusLabel|waiting for manual action" -msgstr "CiStatusLabel|ожидание ручных действий" +msgstr "ожидание ручных действий" msgid "CiStatusText|blocked" -msgstr "CiStatusText|блокировано" +msgstr "блокировано" msgid "CiStatusText|canceled" -msgstr "CiStatusText|отменено" +msgstr "отменено" msgid "CiStatusText|created" -msgstr "CiStatusText|создано" +msgstr "создано" msgid "CiStatusText|failed" -msgstr "CiStatusText|неудачно" +msgstr "неудачно" msgid "CiStatusText|manual" -msgstr "CiStatusText|ручное" +msgstr "ручное" msgid "CiStatusText|passed" -msgstr "CiStatusText|пройдено" +msgstr "пройдено" msgid "CiStatusText|pending" -msgstr "CiStatusText|в ожидании" +msgstr "в ожидании" msgid "CiStatusText|skipped" -msgstr "CiStatusText|пропущено" +msgstr "пропущено" msgid "CiStatus|running" -msgstr "CiStatus|выполняется" +msgstr "выполняется" msgid "Commit" msgid_plural "Commits" @@ -212,13 +212,13 @@ msgstr[1] "Коммиты" msgstr[2] "Коммиты" msgid "Commit duration in minutes for last 30 commits" -msgstr "" +msgstr "Продолжительность последних 30 фиксаций(коммитов) в минутах" msgid "Commit message" msgstr "Описание коммита" msgid "CommitBoxTitle|Commit" -msgstr "CommitBoxTitle|Коммит" +msgstr "Коммит" msgid "CommitMessage|Add %{file_name}" msgstr "CommitMessage|Добавить %{file_name}" @@ -227,22 +227,22 @@ msgid "Commits" msgstr "Коммиты" msgid "Commits feed" -msgstr "" +msgstr "Фиксировать подачу" msgid "Commits|History" -msgstr "Commits|История" +msgstr "История" msgid "Committed by" -msgstr "Коммит" +msgstr "Фиксировано" msgid "Compare" -msgstr "Сравнение" +msgstr "Сравнить" msgid "Contribution guide" -msgstr "Руководство контрибьютора" +msgstr "Руководство участника" msgid "Contributors" -msgstr "Контрибьюторы" +msgstr "Участники" msgid "Copy URL to clipboard" msgstr "Копировать URL в буфер обмена" @@ -251,18 +251,20 @@ msgid "Copy commit SHA to clipboard" msgstr "Копировать SHA коммита в буфер обмена" msgid "Create New Directory" -msgstr "Создать новую директорию" +msgstr "Создать директорию" msgid "" "Create a personal access token on your account to pull or push via " "%{protocol}." msgstr "" +"Создать личный токен на аккаунте для получения или отправки через " +"%{protocol}." msgid "Create directory" msgstr "Создать директорию" msgid "Create empty bare repository" -msgstr "Создать пустой пустой репозиторий" +msgstr "Создать пустой репозиторий" msgid "Create merge request" msgstr "Создать запрос на объединение" @@ -271,13 +273,13 @@ msgid "Create new..." msgstr "Новый" msgid "CreateNewFork|Fork" -msgstr "CreateNewFork|Форк" +msgstr "Форк" msgid "CreateTag|Tag" -msgstr "CreateTag|Тэг" +msgstr "Тег" msgid "CreateTokenToCloneLink|create a personal access token" -msgstr "" +msgstr "создать персональный токен доступа" msgid "Cron Timezone" msgstr "Временная зона Cron" @@ -299,33 +301,35 @@ msgstr "" "посмотрите %{notification_link}." msgid "Cycle Analytics" -msgstr "Аналитика цикла разработки" +msgstr "Аналитический цикл" msgid "" "Cycle Analytics gives an overview of how much time it takes to go from idea " "to production in your project." msgstr "" +"Аналитический цикл дает представление о том, сколько времени требуется, " +"чтобы перейти от идеи к производству в проекте." msgid "CycleAnalyticsStage|Code" -msgstr "CycleAnalyticsStage|Код" +msgstr "Написание кода" msgid "CycleAnalyticsStage|Issue" -msgstr "CycleAnalyticsStage|Обращение" +msgstr "Обращение" msgid "CycleAnalyticsStage|Plan" -msgstr "" +msgstr "Планирование" msgid "CycleAnalyticsStage|Production" -msgstr "" +msgstr "Производство" msgid "CycleAnalyticsStage|Review" -msgstr "CycleAnalyticsStage|Ревьюв" +msgstr "Контроль" msgid "CycleAnalyticsStage|Staging" -msgstr "" +msgstr "Постановка" msgid "CycleAnalyticsStage|Test" -msgstr "" +msgstr "Тестирование" msgid "Define a custom pattern with cron syntax" msgstr "Определить настраиваемый шаблон с синтаксисом cron" @@ -335,45 +339,45 @@ msgstr "Удалить" msgid "Deploy" msgid_plural "Deploys" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "Разместить" +msgstr[1] "Размещение" +msgstr[2] "Размещение" msgid "Description" msgstr "Описание" msgid "Directory name" -msgstr "Наименование директории" +msgstr "Каталог" msgid "Don't show again" msgstr "Не показывать снова" msgid "Download" -msgstr "Загрузить" +msgstr "Скачать" msgid "Download tar" -msgstr "Загрузить tar" +msgstr "Скачать tar" msgid "Download tar.bz2" -msgstr "Загрузить tar.bz2" +msgstr "Скачать tar.bz2" msgid "Download tar.gz" -msgstr "Загрузить tar.gz" +msgstr "Скачать tar.gz" msgid "Download zip" -msgstr "Загрузить zip" +msgstr "Скачать zip" msgid "DownloadArtifacts|Download" -msgstr "DownloadArtifacts|Загрузка" +msgstr "Скачать" msgid "DownloadCommit|Email Patches" -msgstr "DownloadCommit|Email-патчи" +msgstr "Email-патчи" msgid "DownloadCommit|Plain Diff" -msgstr "DownloadCommit|Plain Diff" +msgstr "Простой Diff" msgid "DownloadSource|Download" -msgstr "DownloadSource|Загрузка" +msgstr "Скачать" msgid "Edit" msgstr "Редактировать" @@ -409,10 +413,10 @@ msgid "Find file" msgstr "Найти файл" msgid "FirstPushedBy|First" -msgstr "" +msgstr "Первый" msgid "FirstPushedBy|pushed by" -msgstr "" +msgstr "протолкнул" msgid "Fork" msgid_plural "Forks" @@ -421,22 +425,22 @@ msgstr[1] "Форки" msgstr[2] "Форки" msgid "ForkedFromProjectPath|Forked from" -msgstr "ForkedFromProjectPath|Форк от " +msgstr "Форк от " msgid "From issue creation until deploy to production" -msgstr "" +msgstr "От создания проблемы до развертывания в рабочей среде" msgid "From merge request merge until deploy to production" -msgstr "" +msgstr "От запроса на слияние до развертывания в рабочей среде" msgid "Go to your fork" msgstr "Перейти к вашему форку" msgid "GoToYourFork|Fork" -msgstr "GoToYourFork|Форк" +msgstr "Форк" msgid "Home" -msgstr "Домашняя" +msgstr "Главная" msgid "Housekeeping successfully started" msgstr "Очистка успешно запущена" @@ -448,28 +452,28 @@ msgid "Interval Pattern" msgstr "Шаблон интервала" msgid "Introducing Cycle Analytics" -msgstr "" +msgstr "Внедрение Цикла Аналитики" msgid "Jobs for last month" -msgstr "" +msgstr "Работы за прошлый месяц" msgid "Jobs for last week" -msgstr "" +msgstr "Работы за прошлую неделю" msgid "Jobs for last year" -msgstr "" +msgstr "Работы за прошлый год" msgid "LFSStatus|Disabled" -msgstr "LFSStatus|Отключено" +msgstr "Отключено" msgid "LFSStatus|Enabled" -msgstr "LFSStatus|Включено" +msgstr "Включено" msgid "Last %d day" msgid_plural "Last %d days" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "Последний %d день" +msgstr[1] "Последние %d дни" +msgstr[2] "Последние %d дни" msgid "Last Pipeline" msgstr "Последний конвейер" @@ -494,21 +498,21 @@ msgstr "Покинуть проект" msgid "Limited to showing %d event at most" msgid_plural "Limited to showing %d events at most" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "Ограничение %d события" +msgstr[1] "Ограничение %d событий" +msgstr[2] "Ограничение %d событий" msgid "Median" -msgstr "Медиана" +msgstr "Среднее" msgid "MissingSSHKeyWarningLink|add an SSH key" -msgstr "MissingSSHKeyWarningLink|добавить ключ SSH" +msgstr "добавить ключ SSH" msgid "New Issue" msgid_plural "New Issues" -msgstr[0] "Новое обращение" -msgstr[1] "Новые обращения" -msgstr[2] "Новые обращения" +msgstr[0] "Обращение" +msgstr[1] "Обращения" +msgstr[2] "Обращения" msgid "New Pipeline Schedule" msgstr "Новое расписание конвейера" @@ -535,7 +539,7 @@ msgid "New snippet" msgstr "Новый сниппет" msgid "New tag" -msgstr "Новый тэг" +msgstr "Новый тег" msgid "No repository" msgstr "Нет репозитория" @@ -544,70 +548,70 @@ msgid "No schedules" msgstr "Нет расписания" msgid "Not available" -msgstr "" +msgstr "Недоступно" msgid "Not enough data" -msgstr "" +msgstr "Нет данных" msgid "Notification events" msgstr "Уведомления о событиях" msgid "NotificationEvent|Close issue" -msgstr "NotificationEvent|Обращение закрыто" +msgstr "Обращение закрыто" msgid "NotificationEvent|Close merge request" msgstr "Запрос на объединение закрыт" msgid "NotificationEvent|Failed pipeline" -msgstr "NotificationEvent|Неудача в конвейере" +msgstr "Неудача в конвейере" msgid "NotificationEvent|Merge merge request" -msgstr "NotificationEvent|Объединить запрос на слияние" +msgstr "Объединить запрос на слияние" msgid "NotificationEvent|New issue" -msgstr "NotificationEvent|Новое обращение" +msgstr "Новое обращение" msgid "NotificationEvent|New merge request" -msgstr "NotificationEvent|Новый запрос на слияние" +msgstr "Новый запрос на слияние" msgid "NotificationEvent|New note" -msgstr "NotificationEvent|Новая заметка" +msgstr "Новая заметка" msgid "NotificationEvent|Reassign issue" -msgstr "NotificationEvent|Переназначить обращение" +msgstr "Переназначить обращение" msgid "NotificationEvent|Reassign merge request" -msgstr "NotificationEvent|Переназначить запрос на слияние" +msgstr "Переназначить запрос на слияние" msgid "NotificationEvent|Reopen issue" -msgstr "NotificationEvent|Переоткрыть обращение" +msgstr "Переоткрыть обращение" msgid "NotificationEvent|Successful pipeline" -msgstr "NotificationEvent|Успешно в конвейере" +msgstr "Успешно в конвейере" msgid "NotificationLevel|Custom" -msgstr "NotificationLevel|Настраиваемый" +msgstr "Настраиваемый" msgid "NotificationLevel|Disabled" -msgstr "NotificationLevel|Отключено" +msgstr "Отключено" msgid "NotificationLevel|Global" -msgstr "NotificationLevel|Глобальный" +msgstr "Глобальный" msgid "NotificationLevel|On mention" -msgstr "NotificationLevel|С упоминанием" +msgstr "С упоминанием" msgid "NotificationLevel|Participate" -msgstr "NotificationLevel|По участию" +msgstr "По участию" msgid "NotificationLevel|Watch" -msgstr "NotificationLevel|Отслеживать" +msgstr "Отслеживать" msgid "OfSearchInADropdown|Filter" -msgstr "OfSearchInADropdown|Фильтр" +msgstr "Фильтр" msgid "OpenedNDaysAgo|Opened" -msgstr "OpenedNDaysAgo|Открыто" +msgstr "Открыто" msgid "Options" msgstr "Настройки" @@ -619,7 +623,7 @@ msgid "Pipeline" msgstr "Конвейер" msgid "Pipeline Health" -msgstr "" +msgstr "Жизненный цикл конвейера" msgid "Pipeline Schedule" msgstr "Расписание конвейера" @@ -628,67 +632,79 @@ msgid "Pipeline Schedules" msgstr "Расписания конвейеров" msgid "PipelineCharts|Failed:" -msgstr "" +msgstr "Неудача:" msgid "PipelineCharts|Overall statistics" -msgstr "" +msgstr "Статистика" msgid "PipelineCharts|Success ratio:" -msgstr "" +msgstr "Коэффициент успеха:" msgid "PipelineCharts|Successful:" -msgstr "" +msgstr "Успех:" msgid "PipelineCharts|Total:" -msgstr "" +msgstr "Всего:" msgid "PipelineSchedules|Activated" -msgstr "PipelineSchedules|Активировано" +msgstr "Активировано" msgid "PipelineSchedules|Active" -msgstr "PipelineSchedules|Активно" +msgstr "Активно" msgid "PipelineSchedules|All" -msgstr "PipelineSchedules|Все" +msgstr "Все" msgid "PipelineSchedules|Inactive" -msgstr "PipelineSchedules|Неактивно" +msgstr "Неактивно" + +msgid "PipelineSchedules|Input variable key" +msgstr "Ввод ключевой переменной" + +msgid "PipelineSchedules|Input variable value" +msgstr "Вставить значение" msgid "PipelineSchedules|Next Run" -msgstr "PipelineSchedules|Следующий запуск" +msgstr "Следующий запуск" msgid "PipelineSchedules|None" -msgstr "PipelineSchedules|None" +msgstr "Отсутствует" msgid "PipelineSchedules|Provide a short description for this pipeline" -msgstr "PipelineSchedules|Предоставьте краткое описание этого конвейера" +msgstr "Предоставьте краткое описание этого конвейера" + +msgid "PipelineSchedules|Remove variable row" +msgstr "Удалить значение" msgid "PipelineSchedules|Take ownership" -msgstr "PipelineSchedules|Стать владельцем" +msgstr "Стать владельцем" msgid "PipelineSchedules|Target" -msgstr "PipelineSchedules|Цель" +msgstr "Цель" + +msgid "PipelineSchedules|Variables" +msgstr "Переменные" msgid "PipelineSheduleIntervalPattern|Custom" -msgstr "PipelineSheduleIntervalPattern|Настраиваемый" +msgstr "Настраиваемый" msgid "Pipelines" -msgstr "" +msgstr "Конвейер" msgid "Pipelines charts" -msgstr "" +msgstr "Диаграмма конвейера" msgid "Pipeline|all" -msgstr "" +msgstr "все" msgid "Pipeline|success" -msgstr "" +msgstr "успех" msgid "Pipeline|with stage" -msgstr "Pipeline|со стадией" +msgstr "со стадией" msgid "Pipeline|with stages" -msgstr "Pipeline|со стадиями" +msgstr "со стадиями" msgid "Project '%{project_name}' queued for deletion." msgstr "Проект '%{project_name}' добавлен в очередь на удаление." @@ -727,49 +743,49 @@ msgid "Project home" msgstr "Домашняя страница проекта" msgid "ProjectFeature|Disabled" -msgstr "ProjectFeature|Отключено" +msgstr "Отключено" msgid "ProjectFeature|Everyone with access" -msgstr "ProjectFeature|Все с доступом" +msgstr "Все с доступом" msgid "ProjectFeature|Only team members" -msgstr "ProjectFeature|Только члены команды" +msgstr "Только члены команды" msgid "ProjectFileTree|Name" -msgstr "ProjectFileTree|Имя" +msgstr "Наименование" msgid "ProjectLastActivity|Never" -msgstr "ProjectLastActivity|Никогда" +msgstr "Никогда" msgid "ProjectLifecycle|Stage" -msgstr "" +msgstr "Этап" msgid "ProjectNetworkGraph|Graph" -msgstr "ProjectNetworkGraph|Граф" +msgstr "Граф" msgid "Read more" -msgstr "" +msgstr "Подробнее" msgid "Readme" msgstr "Readme" msgid "RefSwitcher|Branches" -msgstr "RefSwitcher|Ветки" +msgstr "Ветки" msgid "RefSwitcher|Tags" -msgstr "RefSwitcher|Тэги" +msgstr "Теги" msgid "Related Commits" -msgstr "" +msgstr "Связанные коммиты" msgid "Related Deployed Jobs" -msgstr "" +msgstr "Связанные задачи выгрузки" msgid "Related Issues" -msgstr "" +msgstr "Связанные вопросы" msgid "Related Jobs" -msgstr "" +msgstr "Связанные задачи" msgid "Related Merge Requests" msgstr "Связанные запросы на слияние" @@ -802,7 +818,7 @@ msgid "Scheduling Pipelines" msgstr "Планирование конвейеров" msgid "Search branches and tags" -msgstr "Найти ветки и тэги" +msgstr "Найти ветки и теги" msgid "Select Archive Format" msgstr "Выбрать формат архива" @@ -828,34 +844,34 @@ msgid "Set up auto deploy" msgstr "Настройка автоматического развертывания" msgid "SetPasswordToCloneLink|set a password" -msgstr "SetPasswordToCloneLink|установить пароль" +msgstr "установить пароль" msgid "Showing %d event" msgid_plural "Showing %d events" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" +msgstr[0] "Показано %d событие" +msgstr[1] "Показано %d событий" +msgstr[2] "Показано %d событий" msgid "Source code" msgstr "Исходный код" msgid "StarProject|Star" -msgstr "StarProject|Отметить" +msgstr "Отметить" msgid "Start a %{new_merge_request} with these changes" msgstr "Начать %{new_merge_request} с этих изменений" msgid "Switch branch/tag" -msgstr "Переключить ветка/тэг" +msgstr "Переключить ветка/тег" msgid "Tag" msgid_plural "Tags" -msgstr[0] "Тэг" -msgstr[1] "Тэги" -msgstr[2] "Тэги" +msgstr[0] "Тег" +msgstr[1] "теги" +msgstr[2] "Теги" msgid "Tags" -msgstr "Тэги" +msgstr "Теги" msgid "Target Branch" msgstr "Целевая ветка" @@ -865,9 +881,12 @@ msgid "" "request. The data will automatically be added here once you create your " "first merge request." msgstr "" +"На этапе написания кода показывает время первого коммита до создания запроса " +"на слияние. Данные автоматически добавятся после того, как вы создать свой " +"первый запрос на слияние." msgid "The collection of events added to the data gathered for that stage." -msgstr "" +msgstr "Коллекция событий добавленных в данные собранные для этого этапа." msgid "The fork relationship has been removed." msgstr "Связь форка удалена." @@ -890,7 +909,7 @@ msgid "" "project access based on their associated user." msgstr "" "Расписание конвейеров запускает в будущем неоднократно конвейеры, для " -"определенных ветвей или тэгов. Запланированные конвейеры наследуют " +"определенных ветвей или тегов. Запланированные конвейеры наследуют " "ограничения на доступ к проекту на основе связанного с ними пользователя." msgid "" @@ -898,12 +917,18 @@ msgid "" "first commit. This time will be added automatically once you push your first " "commit." msgstr "" +"На этапе планирования показывает время от предыдущего шага до проталкивания " +"первого коммита. Добавляется автоматически, как только проталкиваете свой " +"первый коммит." msgid "" "The production stage shows the total time it takes between creating an issue " "and deploying the code to production. The data will be automatically added " "once you have completed the full idea to production cycle." msgstr "" +"Производственный этап показывает общее время между созданием задачи и " +"развертывание кода в производственной среде. Данные будут автоматически " +"добавлены после полного завершения идеи производственного цикла." msgid "The project can be accessed by any logged in user." msgstr "Доступ к проекту возможен любым зарегистрированным пользователем." @@ -919,27 +944,38 @@ msgid "" "it. The data will automatically be added after you merge your first merge " "request." msgstr "" +"Этап обзора показывает время от создания запроса слияния до его выполнения. " +"Данные будут автоматически добавлены после завершения первого запроса на " +"слияние." msgid "" "The staging stage shows the time between merging the MR and deploying code " "to the production environment. The data will be automatically added once you " "deploy to production for the first time." msgstr "" +"Этап постановки показывает время между слиянием \"MR\" и развертыванием кода " +"в производственной среде. Данные будут автоматически добавлены после " +"развертывания в производстве первый раз." msgid "" "The testing stage shows the time GitLab CI takes to run every pipeline for " "the related merge request. The data will automatically be added after your " "first pipeline finishes running." msgstr "" +"Этап тестирования показывает время, которое GitLab CI занимает для запуска " +"каждого конвейера для соответствующего запроса на слияние. Данные будут " +"автоматически добавлены после завершения работы вашего первого конвейера." msgid "The time taken by each data entry gathered by that stage." -msgstr "" +msgstr "Время, затраченное каждым элементом, собранным на этом этапе." msgid "" "The value lying at the midpoint of a series of observed values. E.g., " "between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 =" " 6." msgstr "" +"Среднее значение в ряду. Пример: между 3, 5, 9, среднее 5, между 3, 5, 7, 8, " +"среднее (5+7)/2 = 6." msgid "" "This means you can not push code until you create an empty repository or " @@ -949,139 +985,139 @@ msgstr "" "репозиторий или не импортируете существующий." msgid "Time before an issue gets scheduled" -msgstr "" +msgstr " Время до начала попадания проблемы в планировщик" msgid "Time before an issue starts implementation" -msgstr "" +msgstr "Время до начала работы над проблемой" msgid "Time between merge request creation and merge/close" msgstr "Время между созданием запроса слияния и слиянием / закрытием" msgid "Time until first merge request" -msgstr "" +msgstr "Время до первого запроса на слияние" msgid "Timeago|%s days ago" -msgstr "Timeago|%s дн(я|ей) назад" +msgstr "%s день назад" msgid "Timeago|%s days remaining" -msgstr "Timeago|Осталось %s дн(я|ей)" +msgstr "Осталось %s день" msgid "Timeago|%s hours remaining" -msgstr "Timeago|Осталось %s часов" +msgstr "Осталось %s часов" msgid "Timeago|%s minutes ago" -msgstr "Timeago|%s минут назад" +msgstr "%s минут назад" msgid "Timeago|%s minutes remaining" -msgstr "Timeago|Осталось %s минут(а|ы)" +msgstr "Осталось %s минут" msgid "Timeago|%s months ago" -msgstr "Timeago|%s минут(а|ы) назад" +msgstr "%s минут назад" msgid "Timeago|%s months remaining" -msgstr "Timeago|Осталось %s месяцев(а)" +msgstr "Осталось %s месяц" msgid "Timeago|%s seconds remaining" -msgstr "Timeago|Осталось %s секунд(ы)" +msgstr "Осталось %s секунд(ы)" msgid "Timeago|%s weeks ago" -msgstr "Timeago|%s недель(и) назад" +msgstr "%s недели назад" msgid "Timeago|%s weeks remaining" -msgstr "Timeago|Осталось %s недель(и)" +msgstr "Осталось %s недели" msgid "Timeago|%s years ago" -msgstr "Timeago|%s лет/года назад" +msgstr "%s год назад" msgid "Timeago|%s years remaining" -msgstr "Timeago|Осталось %s лет/года" +msgstr "Осталось %s год" msgid "Timeago|1 day remaining" -msgstr "Timeago|Остался день" +msgstr "Остался день" msgid "Timeago|1 hour remaining" -msgstr "Timeago|Остался час" +msgstr "Остался час" msgid "Timeago|1 minute remaining" -msgstr "Timeago|Осталась одна минута" +msgstr "Осталась одна минута" msgid "Timeago|1 month remaining" -msgstr "Timeago|Остался месяц" +msgstr "Остался месяц" msgid "Timeago|1 week remaining" -msgstr "Timeago|Осталась неделя" +msgstr "Осталась неделя" msgid "Timeago|1 year remaining" -msgstr "Timeago|Остался год" +msgstr "Остался год" msgid "Timeago|Past due" -msgstr "Timeago|Просрочено" +msgstr "Просрочено" msgid "Timeago|a day ago" -msgstr "Timeago|день назад" +msgstr "день назад" msgid "Timeago|a month ago" -msgstr "Timeago|месяц назад" +msgstr "месяц назад" msgid "Timeago|a week ago" -msgstr "Timeago|неделю назад" +msgstr "неделю назад" msgid "Timeago|a while" -msgstr "Timeago|какое-то время" +msgstr "какое-то время" msgid "Timeago|a year ago" -msgstr "Timeago|год назад" +msgstr "год назад" msgid "Timeago|about %s hours ago" -msgstr "Timeago|около %s часов назад" +msgstr "около %s часов назад" msgid "Timeago|about a minute ago" -msgstr "Timeago|около минуты назад" +msgstr "около минуты назад" msgid "Timeago|about an hour ago" -msgstr "Timeago|около часа назад" +msgstr "около часа назад" msgid "Timeago|in %s days" -msgstr "Timeago|через %s дня(ей)" +msgstr "через %s день" msgid "Timeago|in %s hours" -msgstr "Timeago|через %s часа(ов)" +msgstr "через %s час" msgid "Timeago|in %s minutes" -msgstr "Timeago|через %s минут(ы)" +msgstr "через %s минут" msgid "Timeago|in %s months" -msgstr "Timeago|через %s месяц(а|ев)" +msgstr "через %s месяц" msgid "Timeago|in %s seconds" -msgstr "Timeago|через %s секунд(ы)" +msgstr "через %s секунд(ы)" msgid "Timeago|in %s weeks" -msgstr "Timeago|через %s недели" +msgstr "через %s недели" msgid "Timeago|in %s years" -msgstr "Timeago|через %s лет/года" +msgstr "через %s год" msgid "Timeago|in 1 day" -msgstr "Timeago|через день" +msgstr "через день" msgid "Timeago|in 1 hour" -msgstr "Timeago|через час" +msgstr "через час" msgid "Timeago|in 1 minute" -msgstr "Timeago|через минуту" +msgstr "через минуту" msgid "Timeago|in 1 month" -msgstr "Timeago|через месяц" +msgstr "через месяц" msgid "Timeago|in 1 week" -msgstr "Timeago|через неделю" +msgstr "через неделю" msgid "Timeago|in 1 year" -msgstr "Timeago|через год" +msgstr "через год" msgid "Timeago|less than a minute ago" -msgstr "Timeago|менее чем минуту назад" +msgstr "менее чем минуту назад" msgid "Time|hr" msgid_plural "Time|hrs" @@ -1102,19 +1138,19 @@ msgid "Total Time" msgstr "Общее время" msgid "Total test time for all commits/merges" -msgstr "" +msgstr "Общее время тестирования фиксаций/слияний" msgid "Unstar" msgstr "Снять отметку" msgid "Upload New File" -msgstr "Выгрузить новый файл" +msgstr "Загрузить новый файл" msgid "Upload file" -msgstr "Выгрузить файл" +msgstr "Загрузить файл" msgid "UploadLink|click to upload" -msgstr "UploadLink|кликните для выгрузки" +msgstr "кликните для загрузки" msgid "Use your global notification setting" msgstr "Используются глобальный настройки уведомлений" @@ -1123,23 +1159,32 @@ msgid "View open merge request" msgstr "Просмотреть открытый запрос на слияние" msgid "VisibilityLevel|Internal" -msgstr "VisibilityLevel|Ограниченный" +msgstr "Ограниченный" msgid "VisibilityLevel|Private" -msgstr "VisibilityLevel|Приватный" +msgstr "Приватный" msgid "VisibilityLevel|Public" -msgstr "VisibilityLevel|Публичный" +msgstr "Публичный" msgid "Want to see the data? Please ask an administrator for access." -msgstr "" +msgstr "Хотите увидеть данные? Обратитесь к администратору за доступом." msgid "We don't have enough data to show this stage." -msgstr "" +msgstr "Информация по этапу отсутствует." msgid "Withdraw Access Request" msgstr "Отменить запрос доступа" +msgid "" +"You are going to remove %{group_name}.\n" +"Removed groups CANNOT be restored!\n" +"Are you ABSOLUTELY sure?" +msgstr "" +"Вы собираетесь удалить %{group_name}.\n" +"Удаленные группы НЕ МОГУТ быть восстановлены!\n" +"Вы АБСОЛЮТНО уверены?" + msgid "" "You are going to remove %{project_name_with_namespace}.\n" "Removed project CANNOT be restored!\n" diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po index 2ded61f40d7..c1b99be3433 100644 --- a/locale/uk/gitlab.po +++ b/locale/uk/gitlab.po @@ -9,7 +9,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language-Team: Ukrainian (https://translate.zanata.org/project/view/GitLab)\n" -"PO-Revision-Date: 2017-07-25 03:27-0400\n" +"PO-Revision-Date: 2017-08-01 09:15-0400\n" "Last-Translator: Андрей Витюк \n" "Language: uk\n" "X-Generator: Zanata 3.9.6\n" @@ -504,7 +504,7 @@ msgid "Median" msgstr "Медіана" msgid "MissingSSHKeyWarningLink|add an SSH key" -msgstr "додати SSH ключ" +msgstr "не додасте SSH ключ" msgid "New Issue" msgid_plural "New Issues" @@ -1254,3 +1254,4 @@ msgid_plural "parents" msgstr[0] "джерело" msgstr[1] "джерела" msgstr[2] "джерел" + diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po index 8d30a78145d..af663275602 100644 --- a/locale/zh_TW/gitlab.po +++ b/locale/zh_TW/gitlab.po @@ -1120,10 +1120,7 @@ msgid "" "You are going to remove %{project_name_with_namespace}.\n" "Removed project CANNOT be restored!\n" "Are you ABSOLUTELY sure?" -msgstr "" -"即將要刪除 %{project_name_with_namespace}。\n" -"被刪除的專案完全無法救回來喔!\n" -"真的「100%確定」要這麼做嗎?" +msgstr "即將要刪除 %{project_name_with_namespace}。被刪除的專案完全無法救回來喔!真的「100%確定」要這麼做嗎?" msgid "" "You are going to remove the fork relationship to source project " -- cgit v1.2.1 From 24704acc77ebc85d653fc22d3fe9c7e5eb2a707d Mon Sep 17 00:00:00 2001 From: sue445 Date: Wed, 2 Aug 2017 15:18:17 +0900 Subject: Expose target_iid in Events API --- changelogs/unreleased/13247-api_project_events_target_iid.yml | 4 ++++ doc/api/events.md | 2 ++ lib/api/entities.rb | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/13247-api_project_events_target_iid.yml diff --git a/changelogs/unreleased/13247-api_project_events_target_iid.yml b/changelogs/unreleased/13247-api_project_events_target_iid.yml new file mode 100644 index 00000000000..08a31039f77 --- /dev/null +++ b/changelogs/unreleased/13247-api_project_events_target_iid.yml @@ -0,0 +1,4 @@ +--- +title: Expose target_iid in Events API +merge_request: 13247 +author: sue445 diff --git a/doc/api/events.md b/doc/api/events.md index e7829c9f479..6e530317f6c 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -302,6 +302,7 @@ Example response: "project_id":1, "action_name":"opened", "target_id":160, + "target_iid":160, "target_type":"Issue", "author_id":25, "data":null, @@ -322,6 +323,7 @@ Example response: "project_id":1, "action_name":"opened", "target_id":159, + "target_iid":159, "target_type":"Issue", "author_id":21, "data":null, diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 5cdc441e8cb..0a71c976c7e 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -483,7 +483,7 @@ module API class Event < Grape::Entity expose :title, :project_id, :action_name - expose :target_id, :target_type, :author_id + expose :target_id, :target_iid, :target_type, :author_id expose :data, :target_title expose :created_at expose :note, using: Entities::Note, if: ->(event, options) { event.note? } -- cgit v1.2.1 From e7d6af729f14b487a238da3c62c3dbde3b29bbb8 Mon Sep 17 00:00:00 2001 From: kushalpandya Date: Wed, 2 Aug 2017 14:44:46 +0530 Subject: Remove unnecessary name property --- app/assets/javascripts/groups/components/group_identicon.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/javascripts/groups/components/group_identicon.vue b/app/assets/javascripts/groups/components/group_identicon.vue index ba921a177e9..0edd820743f 100644 --- a/app/assets/javascripts/groups/components/group_identicon.vue +++ b/app/assets/javascripts/groups/components/group_identicon.vue @@ -1,6 +1,5 @@