From 74bdaae6cb70f978f64792e7435621e961dd5e89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 30 Nov 2017 18:09:32 +0100 Subject: Add link to create Google account in clusters page --- app/views/projects/clusters/login.html.haml | 2 ++ spec/features/projects/clusters_spec.rb | 1 + 2 files changed, 3 insertions(+) diff --git a/app/views/projects/clusters/login.html.haml b/app/views/projects/clusters/login.html.haml index fde030b500b..e4bc58b1fab 100644 --- a/app/views/projects/clusters/login.html.haml +++ b/app/views/projects/clusters/login.html.haml @@ -11,6 +11,8 @@ - if @authorize_url = link_to @authorize_url do = image_tag('auth_buttons/signin_with_google.png', width: '191px') + = s_('ClusterIntegration|or create a new') + = link_to('Google account', 'https://accounts.google.com/signup', target: '_blank', rel: 'noopener noreferrer') - else - link = link_to(s_('ClusterIntegration|properly configured'), help_page_path("integration/google"), target: '_blank', rel: 'noopener noreferrer') = s_('Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service.').html_safe % { link_to_documentation: link } diff --git a/spec/features/projects/clusters_spec.rb b/spec/features/projects/clusters_spec.rb index 197e6df4997..018758d1bf1 100644 --- a/spec/features/projects/clusters_spec.rb +++ b/spec/features/projects/clusters_spec.rb @@ -201,6 +201,7 @@ feature 'Clusters', :js do it 'user sees a login page' do expect(page).to have_css('.signin-with-google') + expect(page).to have_link('Google account') end end end -- cgit v1.2.1 From d2ebc9b931d12cb2cb120d6f7c940744bc1be39c Mon Sep 17 00:00:00 2001 From: James Edwards-Jones Date: Thu, 19 Oct 2017 17:47:11 +0300 Subject: Prevent schema.rb reverting from datetime_with_timezone to datetime --- config/initializers/active_record_data_types.rb | 5 +++++ .../20171019141859_fix_dev_timezone_schema.rb | 25 ++++++++++++++++++++++ db/schema.rb | 8 +++---- 3 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20171019141859_fix_dev_timezone_schema.rb diff --git a/config/initializers/active_record_data_types.rb b/config/initializers/active_record_data_types.rb index fef591c397d..0359e14b232 100644 --- a/config/initializers/active_record_data_types.rb +++ b/config/initializers/active_record_data_types.rb @@ -79,3 +79,8 @@ elsif Gitlab::Database.mysql? NATIVE_DATABASE_TYPES[:datetime_with_timezone] = { name: 'timestamp' } end end + +# Ensure `datetime_with_timezone` columns are correctly written to schema.rb +if (ActiveRecord::Base.connection.active? rescue false) + ActiveRecord::Base.connection.send :reload_type_map +end diff --git a/db/migrate/20171019141859_fix_dev_timezone_schema.rb b/db/migrate/20171019141859_fix_dev_timezone_schema.rb new file mode 100644 index 00000000000..fb7c17dd747 --- /dev/null +++ b/db/migrate/20171019141859_fix_dev_timezone_schema.rb @@ -0,0 +1,25 @@ +class FixDevTimezoneSchema < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # The this migrations tries to help solve unwanted changes to `schema.rb` + # while developing GitLab. Installations created before we started using + # `datetime_with_timezone` are likely to face this problem. Updating those + # columns to the new type should help fix this. + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + TIMEZONE_TABLES = %i(appearances ci_group_variables ci_pipeline_schedule_variables events gpg_keys gpg_signatures project_auto_devops) + + def up + return unless Rails.env.development? || Rails.env.test? + + TIMEZONE_TABLES.each do |table| + change_column table, :created_at, :datetime_with_timezone + change_column table, :updated_at, :datetime_with_timezone + end + end + + def down + end +end diff --git a/db/schema.rb b/db/schema.rb index 0984ca6487f..990456648b7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -649,8 +649,8 @@ ActiveRecord::Schema.define(version: 20171124150326) do t.datetime "created_at" t.datetime "updated_at" t.string "confirmation_token" - t.datetime "confirmed_at" - t.datetime "confirmation_sent_at" + t.datetime_with_timezone "confirmed_at" + t.datetime_with_timezone "confirmation_sent_at" end add_index "emails", ["confirmation_token"], name: "index_emails_on_confirmation_token", unique: true, using: :btree @@ -1762,8 +1762,8 @@ ActiveRecord::Schema.define(version: 20171124150326) do add_index "user_agent_details", ["subject_id", "subject_type"], name: "index_user_agent_details_on_subject_id_and_subject_type", using: :btree create_table "user_custom_attributes", force: :cascade do |t| - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime_with_timezone "created_at", null: false + t.datetime_with_timezone "updated_at", null: false t.integer "user_id", null: false t.string "key", null: false t.string "value", null: false -- cgit v1.2.1 From eb9f88311b0591586c73ddb35bdb07677464748c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sun, 10 Dec 2017 18:10:51 +0100 Subject: Use special new account link * Redirects to GCP free trial signup afterwards * Adds GitLab referral info --- app/views/projects/clusters/login.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/clusters/login.html.haml b/app/views/projects/clusters/login.html.haml index e4bc58b1fab..521121111b0 100644 --- a/app/views/projects/clusters/login.html.haml +++ b/app/views/projects/clusters/login.html.haml @@ -12,7 +12,7 @@ = link_to @authorize_url do = image_tag('auth_buttons/signin_with_google.png', width: '191px') = s_('ClusterIntegration|or create a new') - = link_to('Google account', 'https://accounts.google.com/signup', target: '_blank', rel: 'noopener noreferrer') + = link_to('Google account', 'https://accounts.google.com/SignUpWithoutGmail?service=cloudconsole&continue=https%3A%2F%2Fconsole.cloud.google.com%2Ffreetrial%3Futm_campaign%3D2018_cpanel%26utm_source%3Dgitlab%26utm_medium%3Dreferral', target: '_blank', rel: 'noopener noreferrer') - else - link = link_to(s_('ClusterIntegration|properly configured'), help_page_path("integration/google"), target: '_blank', rel: 'noopener noreferrer') = s_('Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service.').html_safe % { link_to_documentation: link } -- cgit v1.2.1 From 497a0cd62ca8dff2e7b91f3366b69f4f2b2fa826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Wed, 13 Dec 2017 15:25:42 +0100 Subject: Fix cluster OAuth feature spec user flow --- spec/features/projects/clusters_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/features/projects/clusters_spec.rb b/spec/features/projects/clusters_spec.rb index dad943aac55..eae2910a8f6 100644 --- a/spec/features/projects/clusters_spec.rb +++ b/spec/features/projects/clusters_spec.rb @@ -82,6 +82,7 @@ feature 'Clusters', :js do before do visit project_clusters_path(project) + click_link 'Add cluster' click_link 'Create on GKE' end -- cgit v1.2.1 From 596ea9e3688537131fb918c1e9177d085a938d19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 15 Dec 2017 19:39:15 +0100 Subject: Add Google Cloud client project list --- lib/google_api/cloud_platform/client.rb | 10 ++++++++++ spec/lib/google_api/cloud_platform/client_spec.rb | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/lib/google_api/cloud_platform/client.rb b/lib/google_api/cloud_platform/client.rb index b0563fb2d69..f0dabcb1c5d 100644 --- a/lib/google_api/cloud_platform/client.rb +++ b/lib/google_api/cloud_platform/client.rb @@ -1,4 +1,5 @@ require 'google/apis/container_v1' +require 'google/apis/cloudresourcemanager_v1' module GoogleApi module CloudPlatform @@ -40,6 +41,15 @@ module GoogleApi true end + def projects_list + service = Google::Apis::CloudresourcemanagerV1::CloudResourceManagerService.new + service.authorization = access_token + + service.fetch_all(items: :projects) do |token| + service.list_projects(page_token: token) + end + end + def projects_zones_clusters_get(project_id, zone, cluster_id) service = Google::Apis::ContainerV1::ContainerService.new service.authorization = access_token diff --git a/spec/lib/google_api/cloud_platform/client_spec.rb b/spec/lib/google_api/cloud_platform/client_spec.rb index ecb4034ec8b..0383b1080dc 100644 --- a/spec/lib/google_api/cloud_platform/client_spec.rb +++ b/spec/lib/google_api/cloud_platform/client_spec.rb @@ -50,6 +50,18 @@ describe GoogleApi::CloudPlatform::Client do end end + describe '#projects_list' do + subject { client.projects_list } + let(:projects) { double } + + before do + allow_any_instance_of(Google::Apis::CloudresourcemanagerV1::CloudResourceManagerService) + .to receive(:fetch_all).and_return(projects) + end + + it { is_expected.to eq(projects) } + end + describe '#projects_zones_clusters_get' do subject { client.projects_zones_clusters_get(spy, spy, spy) } let(:gke_cluster) { double } -- cgit v1.2.1 From 957bedb1c345644f633fdfd3440491810c5cb75c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 15 Dec 2017 23:54:50 +0100 Subject: Add Google Cloud client project billing info --- lib/google_api/cloud_platform/client.rb | 8 ++++++++ spec/lib/google_api/cloud_platform/client_spec.rb | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/lib/google_api/cloud_platform/client.rb b/lib/google_api/cloud_platform/client.rb index f0dabcb1c5d..c107d001bec 100644 --- a/lib/google_api/cloud_platform/client.rb +++ b/lib/google_api/cloud_platform/client.rb @@ -1,4 +1,5 @@ require 'google/apis/container_v1' +require 'google/apis/cloudbilling_v1' require 'google/apis/cloudresourcemanager_v1' module GoogleApi @@ -50,6 +51,13 @@ module GoogleApi end end + def projects_get_billing_info(project_name) + service = Google::Apis::CloudbillingV1::CloudbillingService.new + service.authorization = access_token + + service.get_project_billing_info(project_name) + end + def projects_zones_clusters_get(project_id, zone, cluster_id) service = Google::Apis::ContainerV1::ContainerService.new service.authorization = access_token diff --git a/spec/lib/google_api/cloud_platform/client_spec.rb b/spec/lib/google_api/cloud_platform/client_spec.rb index 0383b1080dc..2d14c3b1a3a 100644 --- a/spec/lib/google_api/cloud_platform/client_spec.rb +++ b/spec/lib/google_api/cloud_platform/client_spec.rb @@ -62,6 +62,18 @@ describe GoogleApi::CloudPlatform::Client do it { is_expected.to eq(projects) } end + def projects_get_billing_info + subject { client.projects_get_billing_info } + let(:billing_info) { double } + + before do + allow_any_instance_of(Google::Apis::CloudbillingV1::CloudbillingService) + .to receive(:get_project_billing_info).and_return(billing_info) + end + + it { is_expected.to eq(billing_info) } + end + describe '#projects_zones_clusters_get' do subject { client.projects_zones_clusters_get(spy, spy, spy) } let(:gke_cluster) { double } -- cgit v1.2.1 From 84d8ca1171faf8ab6df0c256381b8afbf5aeb099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 16 Dec 2017 00:05:46 +0100 Subject: Change link for creating a new Google account --- app/views/projects/clusters/gcp/login.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/clusters/gcp/login.html.haml b/app/views/projects/clusters/gcp/login.html.haml index 5ef80ccf8f7..878ebaded88 100644 --- a/app/views/projects/clusters/gcp/login.html.haml +++ b/app/views/projects/clusters/gcp/login.html.haml @@ -12,8 +12,8 @@ - if @authorize_url = link_to @authorize_url do = image_tag('auth_buttons/signin_with_google.png', width: '191px') - = s_('ClusterIntegration|or create a new') - = link_to('Google account', 'https://accounts.google.com/SignUpWithoutGmail?service=cloudconsole&continue=https%3A%2F%2Fconsole.cloud.google.com%2Ffreetrial%3Futm_campaign%3D2018_cpanel%26utm_source%3Dgitlab%26utm_medium%3Dreferral', target: '_blank', rel: 'noopener noreferrer') + = _('or') + = link_to('create a new Google account', 'https://accounts.google.com/SignUpWithoutGmail?service=cloudconsole&continue=https%3A%2F%2Fconsole.cloud.google.com%2Ffreetrial%3Futm_campaign%3D2018_cpanel%26utm_source%3Dgitlab%26utm_medium%3Dreferral', target: '_blank', rel: 'noopener noreferrer') - else - link = link_to(s_('ClusterIntegration|properly configured'), help_page_path("integration/google"), target: '_blank', rel: 'noopener noreferrer') = s_('Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service.').html_safe % { link_to_documentation: link } -- cgit v1.2.1 From 87f01506cb0f0ba9ee2d7153157b0a07d628a559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 16 Dec 2017 01:44:36 +0100 Subject: Add CheckGCPProjectBillingService --- app/services/check_gcp_project_billing_service.rb | 8 ++++++ .../check_gcp_project_billing_service_spec.rb | 30 ++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 app/services/check_gcp_project_billing_service.rb create mode 100644 spec/services/check_gcp_project_billing_service_spec.rb diff --git a/app/services/check_gcp_project_billing_service.rb b/app/services/check_gcp_project_billing_service.rb new file mode 100644 index 00000000000..45192a167eb --- /dev/null +++ b/app/services/check_gcp_project_billing_service.rb @@ -0,0 +1,8 @@ +class CheckGCPProjectBillingService + def execute(token) + client = GoogleApi::CloudPlatform::Client.new(token, nil) + client.projects_list.any? do |project| + client.projects_get_billing_info(project.name).billingEnabled + end + end +end diff --git a/spec/services/check_gcp_project_billing_service_spec.rb b/spec/services/check_gcp_project_billing_service_spec.rb new file mode 100644 index 00000000000..b7c42fcace1 --- /dev/null +++ b/spec/services/check_gcp_project_billing_service_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +describe CheckGCPProjectBillingService do + let(:service) { described_class.new } + + describe '#execute' do + before do + expect_any_instance_of(GoogleApi::CloudPlatform::Client) + .to receive(:projects_list).and_return([double(name: 'project_name')]) + + expect_any_instance_of(GoogleApi::CloudPlatform::Client) + .to receive_message_chain(:projects_get_billing_info, :billingEnabled) + .and_return(project_billing_enabled) + end + + subject { service.execute('bogustoken') } + + context 'google account has a billing enabled gcp project' do + let(:project_billing_enabled) { true } + + it { is_expected.to eq(true) } + end + + context 'google account does not have a billing enabled gcp project' do + let(:project_billing_enabled) { false } + + it { is_expected.to eq(false) } + end + end +end -- cgit v1.2.1 From 291480f5e17fea424692f979db91d2ec62d24dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 16 Dec 2017 02:12:44 +0100 Subject: Properly CamelCase service name --- app/services/check_gcp_project_billing_service.rb | 2 +- spec/lib/google_api/cloud_platform/client_spec.rb | 4 ++-- spec/services/check_gcp_project_billing_service_spec.rb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/services/check_gcp_project_billing_service.rb b/app/services/check_gcp_project_billing_service.rb index 45192a167eb..88e9d7de8de 100644 --- a/app/services/check_gcp_project_billing_service.rb +++ b/app/services/check_gcp_project_billing_service.rb @@ -1,4 +1,4 @@ -class CheckGCPProjectBillingService +class CheckGcpProjectBillingService def execute(token) client = GoogleApi::CloudPlatform::Client.new(token, nil) client.projects_list.any? do |project| diff --git a/spec/lib/google_api/cloud_platform/client_spec.rb b/spec/lib/google_api/cloud_platform/client_spec.rb index 2d14c3b1a3a..f65e41dfea3 100644 --- a/spec/lib/google_api/cloud_platform/client_spec.rb +++ b/spec/lib/google_api/cloud_platform/client_spec.rb @@ -62,8 +62,8 @@ describe GoogleApi::CloudPlatform::Client do it { is_expected.to eq(projects) } end - def projects_get_billing_info - subject { client.projects_get_billing_info } + describe '#projects_get_billing_info' do + subject { client.projects_get_billing_info('project') } let(:billing_info) { double } before do diff --git a/spec/services/check_gcp_project_billing_service_spec.rb b/spec/services/check_gcp_project_billing_service_spec.rb index b7c42fcace1..1b23b43b0d5 100644 --- a/spec/services/check_gcp_project_billing_service_spec.rb +++ b/spec/services/check_gcp_project_billing_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe CheckGCPProjectBillingService do +describe CheckGcpProjectBillingService do let(:service) { described_class.new } describe '#execute' do -- cgit v1.2.1 From 68b95cd01e674cd2dbce45c49f5be04c223b718d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 16 Dec 2017 02:39:55 +0100 Subject: Add CheckGcpProjectBillingWorker --- app/workers/check_gcp_project_billing_worker.rb | 16 +++++++++++++++ .../check_gcp_project_billing_worker_spec.rb | 23 ++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 app/workers/check_gcp_project_billing_worker.rb create mode 100644 spec/workers/check_gcp_project_billing_worker_spec.rb diff --git a/app/workers/check_gcp_project_billing_worker.rb b/app/workers/check_gcp_project_billing_worker.rb new file mode 100644 index 00000000000..97638f65e8d --- /dev/null +++ b/app/workers/check_gcp_project_billing_worker.rb @@ -0,0 +1,16 @@ +class CheckGcpProjectBillingWorker + include ApplicationWorker + + def self.redis_shared_state_key_for(token) + "gitlab:gcp:#{token}:billing_enabled" + end + + def perform(token) + return unless token + + billing_enabled = CheckGcpProjectBillingService.new.execute(token) + Gitlab::Redis::SharedState.with do |redis| + redis.set(self.class.redis_shared_state_key_for(token), billing_enabled) + end + end +end diff --git a/spec/workers/check_gcp_project_billing_worker_spec.rb b/spec/workers/check_gcp_project_billing_worker_spec.rb new file mode 100644 index 00000000000..c6e624f65be --- /dev/null +++ b/spec/workers/check_gcp_project_billing_worker_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe CheckGcpProjectBillingWorker do + describe '.perform' do + let(:token) { 'bogustoken' } + subject { described_class.new.perform(token) } + + it 'calls the service' do + expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute) + + subject + end + + it 'stores billing status in redis' do + expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute).and_return(true) + subject + + Gitlab::Redis::SharedState.with do |redis| + expect(redis.get("gitlab:gcp:#{token}:billing_enabled")).to eq('true') + end + end + end +end -- cgit v1.2.1 From 1de0261d5ec9385405291426f56b190148707700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 16 Dec 2017 04:00:54 +0100 Subject: Isolate CheckGcpProjectBillingWorker specreturns --- spec/workers/check_gcp_project_billing_worker_spec.rb | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/spec/workers/check_gcp_project_billing_worker_spec.rb b/spec/workers/check_gcp_project_billing_worker_spec.rb index c6e624f65be..70738f36324 100644 --- a/spec/workers/check_gcp_project_billing_worker_spec.rb +++ b/spec/workers/check_gcp_project_billing_worker_spec.rb @@ -12,12 +12,13 @@ describe CheckGcpProjectBillingWorker do end it 'stores billing status in redis' do + redis_double = double + expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute).and_return(true) - subject + expect(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) + expect(redis_double).to receive(:set).with(CheckGcpProjectBillingWorker.redis_shared_state_key_for(token), anything) - Gitlab::Redis::SharedState.with do |redis| - expect(redis.get("gitlab:gcp:#{token}:billing_enabled")).to eq('true') - end + subject end end end -- cgit v1.2.1 From 78f85f3fd3a6743948f044c332cd1243547ef0a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 16 Dec 2017 04:11:44 +0100 Subject: Add check step for creating GCP clusters --- .../projects/clusters/gcp_controller.rb | 25 +++++++- app/views/projects/clusters/gcp/check.html.haml | 1 + app/views/projects/clusters/new.html.haml | 2 +- config/routes/project.rb | 1 + .../projects/clusters/gcp_controller_spec.rb | 71 +++++++++++++++++++++- 5 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 app/views/projects/clusters/gcp/check.html.haml diff --git a/app/controllers/projects/clusters/gcp_controller.rb b/app/controllers/projects/clusters/gcp_controller.rb index b64f7a2a6bd..558dae8e228 100644 --- a/app/controllers/projects/clusters/gcp_controller.rb +++ b/app/controllers/projects/clusters/gcp_controller.rb @@ -1,11 +1,14 @@ class Projects::Clusters::GcpController < Projects::ApplicationController before_action :authorize_read_cluster! before_action :authorize_google_api, except: [:login] + before_action :authorize_google_project_billing, only: [:check] before_action :authorize_create_cluster!, only: [:new, :create] + STATUS_POLLING_INTERVAL = 10_000 + def login begin - state = generate_session_key_redirect(gcp_new_namespace_project_clusters_path.to_s) + state = generate_session_key_redirect(gcp_check_namespace_project_clusters_path.to_s) @authorize_url = GoogleApi::CloudPlatform::Client.new( nil, callback_google_api_auth_url, @@ -15,6 +18,18 @@ class Projects::Clusters::GcpController < Projects::ApplicationController end end + def check + respond_to do |format| + format.json do + Gitlab::PollingInterval.set_header(response, interval: STATUS_POLLING_INTERVAL) + + Gitlab::Redis::SharedState.with do |redis| + render json: { billing: redis.get(CheckGcpProjectBillingWorker.redis_shared_state_key_for(token_in_session)) } + end + end + end + end + def new @cluster = ::Clusters::Cluster.new.tap do |cluster| cluster.build_provider_gcp @@ -57,6 +72,14 @@ class Projects::Clusters::GcpController < Projects::ApplicationController end end + def authorize_google_project_billing + Gitlab::Redis::SharedState.with do |redis| + unless redis.get(CheckGcpProjectBillingWorker.redis_shared_state_key_for(token_in_session)) == 'true' + CheckGcpProjectBillingWorker.perform_async(token_in_session) + end + end + end + def token_in_session @token_in_session ||= session[GoogleApi::CloudPlatform::Client.session_key_for_token] diff --git a/app/views/projects/clusters/gcp/check.html.haml b/app/views/projects/clusters/gcp/check.html.haml new file mode 100644 index 00000000000..e965047ad7c --- /dev/null +++ b/app/views/projects/clusters/gcp/check.html.haml @@ -0,0 +1 @@ +Hello diff --git a/app/views/projects/clusters/new.html.haml b/app/views/projects/clusters/new.html.haml index ddd13f8ea96..22014c49677 100644 --- a/app/views/projects/clusters/new.html.haml +++ b/app/views/projects/clusters/new.html.haml @@ -8,6 +8,6 @@ %h4.prepend-top-0= s_('ClusterIntegration|Choose how to set up cluster integration') %p= s_('ClusterIntegration|Create a new cluster on Google Kubernetes Engine right from GitLab') - = link_to s_('ClusterIntegration|Create on GKE'), gcp_new_namespace_project_clusters_path(@project.namespace, @project), class: 'btn append-bottom-20' + = link_to s_('ClusterIntegration|Create on GKE'), gcp_check_namespace_project_clusters_path(@project.namespace, @project), class: 'btn append-bottom-20' %p= s_('ClusterIntegration|Enter the details for an existing Kubernetes cluster') = link_to s_('ClusterIntegration|Add an existing cluster'), user_new_namespace_project_clusters_path(@project.namespace, @project), class: 'btn append-bottom-20' diff --git a/config/routes/project.rb b/config/routes/project.rb index 093da10f57f..26eb4fbeda3 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -189,6 +189,7 @@ constraints(ProjectUrlConstrainer.new) do get '/user/new', to: 'clusters/user#new' post '/user', to: 'clusters/user#create' + get '/gcp/check', to: 'clusters/gcp#check' get '/gcp/new', to: 'clusters/gcp#new' get '/gcp/login', to: 'clusters/gcp#login' post '/gcp', to: 'clusters/gcp#create' diff --git a/spec/controllers/projects/clusters/gcp_controller_spec.rb b/spec/controllers/projects/clusters/gcp_controller_spec.rb index ee7928beb7e..be4b8c1f8dc 100644 --- a/spec/controllers/projects/clusters/gcp_controller_spec.rb +++ b/spec/controllers/projects/clusters/gcp_controller_spec.rb @@ -30,7 +30,7 @@ describe Projects::Clusters::GcpController do go expect(assigns(:authorize_url)).to include(key) - expect(session[session_key_for_redirect_uri]).to eq(gcp_new_project_clusters_path(project)) + expect(session[session_key_for_redirect_uri]).to eq(gcp_check_project_clusters_path(project)) end end @@ -63,6 +63,75 @@ describe Projects::Clusters::GcpController do end end + describe 'GET check' do + let(:user) { create(:user) } + + before do + project.add_master(user) + sign_in(user) + end + + describe 'functionality' do + context 'when redis has wanted billing status' do + let(:token) { 'bogustoken' } + before do + redis_double = double + allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) + allow(redis_double).to receive(:get).and_return('true') + end + + it 'should render json with billing status' do + go + + expect(response).to have_http_status(:ok) + expect(response.body).to include_json(billing: 'true') + end + + it 'should not start worker' do + expect(CheckGcpProjectBillingWorker).not_to receive(:perform_async) + + go + end + end + + context 'when redis does not have billing status' do + before do + redis_double = double + allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) + allow(redis_double).to receive(:get).and_return(nil) + end + + it 'should render json with null billing status' do + go + + expect(response).to have_http_status(:ok) + expect(response.body).to include_json(billing: nil) + end + + it 'should start worker' do + expect(CheckGcpProjectBillingWorker).to receive(:perform_async) + + go + end + end + end + + describe 'security' do + it { expect { go }.to be_allowed_for(:admin) } + it { expect { go }.to be_allowed_for(:owner).of(project) } + it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_denied_for(:developer).of(project) } + it { expect { go }.to be_denied_for(:reporter).of(project) } + it { expect { go }.to be_denied_for(:guest).of(project) } + it { expect { go }.to be_denied_for(:user) } + it { expect { go }.to be_denied_for(:external) } + end + + def go + get :check, namespace_id: project.namespace, project_id: project, format: :json + end + end + describe 'GET new' do describe 'functionality' do let(:user) { create(:user) } -- cgit v1.2.1 From 99043d244c4d579f27382f003df9e3243287df2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 16 Dec 2017 04:21:13 +0100 Subject: Add lease to CheckGcpProjectBillingWorker --- app/workers/check_gcp_project_billing_worker.rb | 11 +++++++ .../check_gcp_project_billing_worker_spec.rb | 36 ++++++++++++++++------ 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/app/workers/check_gcp_project_billing_worker.rb b/app/workers/check_gcp_project_billing_worker.rb index 97638f65e8d..254b0959063 100644 --- a/app/workers/check_gcp_project_billing_worker.rb +++ b/app/workers/check_gcp_project_billing_worker.rb @@ -1,16 +1,27 @@ class CheckGcpProjectBillingWorker include ApplicationWorker + LEASE_TIMEOUT = 1.minute.to_i + def self.redis_shared_state_key_for(token) "gitlab:gcp:#{token}:billing_enabled" end def perform(token) return unless token + return unless try_obtain_lease_for(token) billing_enabled = CheckGcpProjectBillingService.new.execute(token) Gitlab::Redis::SharedState.with do |redis| redis.set(self.class.redis_shared_state_key_for(token), billing_enabled) end end + + private + + def try_obtain_lease_for(token) + Gitlab::ExclusiveLease + .new("check_gcp_project_billing_worker:#{token}", timeout: LEASE_TIMEOUT) + .try_obtain + end end diff --git a/spec/workers/check_gcp_project_billing_worker_spec.rb b/spec/workers/check_gcp_project_billing_worker_spec.rb index 70738f36324..ce9632549b6 100644 --- a/spec/workers/check_gcp_project_billing_worker_spec.rb +++ b/spec/workers/check_gcp_project_billing_worker_spec.rb @@ -5,20 +5,38 @@ describe CheckGcpProjectBillingWorker do let(:token) { 'bogustoken' } subject { described_class.new.perform(token) } - it 'calls the service' do - expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute) + context 'when there is no lease' do + before do + allow_any_instance_of(CheckGcpProjectBillingWorker).to receive(:try_obtain_lease_for).and_return('randomuuid') + end - subject + it 'calls the service' do + expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute) + + subject + end + + it 'stores billing status in redis' do + redis_double = double + + expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute).and_return(true) + expect(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) + expect(redis_double).to receive(:set).with(CheckGcpProjectBillingWorker.redis_shared_state_key_for(token), anything) + + subject + end end - it 'stores billing status in redis' do - redis_double = double + context 'when there is a lease' do + before do + allow_any_instance_of(CheckGcpProjectBillingWorker).to receive(:try_obtain_lease_for).and_return(false) + end - expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute).and_return(true) - expect(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) - expect(redis_double).to receive(:set).with(CheckGcpProjectBillingWorker.redis_shared_state_key_for(token), anything) + it 'does not call the service' do + expect(CheckGcpProjectBillingService).not_to receive(:new) - subject + subject + end end end end -- cgit v1.2.1 From 935a27cfef3c5a4dd9291c21af69b41a7169817d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 16 Dec 2017 04:22:16 +0100 Subject: Use 1 minute for status polling interval --- app/controllers/projects/clusters/gcp_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/projects/clusters/gcp_controller.rb b/app/controllers/projects/clusters/gcp_controller.rb index 558dae8e228..940c2a5d84f 100644 --- a/app/controllers/projects/clusters/gcp_controller.rb +++ b/app/controllers/projects/clusters/gcp_controller.rb @@ -4,7 +4,7 @@ class Projects::Clusters::GcpController < Projects::ApplicationController before_action :authorize_google_project_billing, only: [:check] before_action :authorize_create_cluster!, only: [:new, :create] - STATUS_POLLING_INTERVAL = 10_000 + STATUS_POLLING_INTERVAL = 1.minute.to_i def login begin -- cgit v1.2.1 From 914260930f800342c495114f507947ae35471e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 16 Dec 2017 05:26:07 +0100 Subject: Expand controller test suite matrix --- .../projects/clusters/gcp_controller.rb | 5 +- app/views/projects/clusters/new.html.haml | 2 +- .../projects/clusters/gcp_controller_spec.rb | 138 +++++++++++++++------ spec/support/google_api/cloud_platform_helpers.rb | 6 + .../check_gcp_project_billing_worker_spec.rb | 6 +- 5 files changed, 111 insertions(+), 46 deletions(-) diff --git a/app/controllers/projects/clusters/gcp_controller.rb b/app/controllers/projects/clusters/gcp_controller.rb index 940c2a5d84f..95c947001a3 100644 --- a/app/controllers/projects/clusters/gcp_controller.rb +++ b/app/controllers/projects/clusters/gcp_controller.rb @@ -1,14 +1,14 @@ class Projects::Clusters::GcpController < Projects::ApplicationController before_action :authorize_read_cluster! before_action :authorize_google_api, except: [:login] - before_action :authorize_google_project_billing, only: [:check] + before_action :authorize_google_project_billing, except: [:login, :check] before_action :authorize_create_cluster!, only: [:new, :create] STATUS_POLLING_INTERVAL = 1.minute.to_i def login begin - state = generate_session_key_redirect(gcp_check_namespace_project_clusters_path.to_s) + state = generate_session_key_redirect(gcp_new_namespace_project_clusters_path.to_s) @authorize_url = GoogleApi::CloudPlatform::Client.new( nil, callback_google_api_auth_url, @@ -76,6 +76,7 @@ class Projects::Clusters::GcpController < Projects::ApplicationController Gitlab::Redis::SharedState.with do |redis| unless redis.get(CheckGcpProjectBillingWorker.redis_shared_state_key_for(token_in_session)) == 'true' CheckGcpProjectBillingWorker.perform_async(token_in_session) + redirect_to action: 'check' end end end diff --git a/app/views/projects/clusters/new.html.haml b/app/views/projects/clusters/new.html.haml index 22014c49677..ddd13f8ea96 100644 --- a/app/views/projects/clusters/new.html.haml +++ b/app/views/projects/clusters/new.html.haml @@ -8,6 +8,6 @@ %h4.prepend-top-0= s_('ClusterIntegration|Choose how to set up cluster integration') %p= s_('ClusterIntegration|Create a new cluster on Google Kubernetes Engine right from GitLab') - = link_to s_('ClusterIntegration|Create on GKE'), gcp_check_namespace_project_clusters_path(@project.namespace, @project), class: 'btn append-bottom-20' + = link_to s_('ClusterIntegration|Create on GKE'), gcp_new_namespace_project_clusters_path(@project.namespace, @project), class: 'btn append-bottom-20' %p= s_('ClusterIntegration|Enter the details for an existing Kubernetes cluster') = link_to s_('ClusterIntegration|Add an existing cluster'), user_new_namespace_project_clusters_path(@project.namespace, @project), class: 'btn append-bottom-20' diff --git a/spec/controllers/projects/clusters/gcp_controller_spec.rb b/spec/controllers/projects/clusters/gcp_controller_spec.rb index be4b8c1f8dc..852f3efe793 100644 --- a/spec/controllers/projects/clusters/gcp_controller_spec.rb +++ b/spec/controllers/projects/clusters/gcp_controller_spec.rb @@ -17,7 +17,6 @@ describe Projects::Clusters::GcpController do context 'when omniauth has been configured' do let(:key) { 'secret-key' } - let(:session_key_for_redirect_uri) do GoogleApi::CloudPlatform::Client.session_key_for_redirect_uri(key) end @@ -30,7 +29,7 @@ describe Projects::Clusters::GcpController do go expect(assigns(:authorize_url)).to include(key) - expect(session[session_key_for_redirect_uri]).to eq(gcp_check_project_clusters_path(project)) + expect(session[session_key_for_redirect_uri]).to eq(gcp_new_project_clusters_path(project)) end end @@ -72,47 +71,54 @@ describe Projects::Clusters::GcpController do end describe 'functionality' do - context 'when redis has wanted billing status' do - let(:token) { 'bogustoken' } + context 'when access token is valid' do before do - redis_double = double - allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) - allow(redis_double).to receive(:get).and_return('true') + stub_google_api_validate_token end - it 'should render json with billing status' do - go + context 'when redis has wanted billing status' do + let(:token) { 'bogustoken' } + + before do + redis_double = double + allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) + allow(redis_double).to receive(:get).and_return('true') + end - expect(response).to have_http_status(:ok) - expect(response.body).to include_json(billing: 'true') + it 'should render json with billing status' do + go + + expect(response).to have_http_status(:ok) + expect(JSON.parse(response.body)).to include('billing' => 'true') + end end - it 'should not start worker' do - expect(CheckGcpProjectBillingWorker).not_to receive(:perform_async) + context 'when redis does not have billing status' do + before do + redis_double = double + allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) + allow(redis_double).to receive(:get).and_return(nil) + end + + it 'should render json with null billing status' do + go - go + expect(response).to have_http_status(:ok) + expect(JSON.parse(response.body)).to include('billing' => nil) + end end end - context 'when redis does not have billing status' do + context 'when access token is expired' do before do - redis_double = double - allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) - allow(redis_double).to receive(:get).and_return(nil) - end - - it 'should render json with null billing status' do - go - - expect(response).to have_http_status(:ok) - expect(response.body).to include_json(billing: nil) + stub_google_api_expired_token end - it 'should start worker' do - expect(CheckGcpProjectBillingWorker).to receive(:perform_async) + it { expect(go).to redirect_to(gcp_login_project_clusters_path(project)) } + end - go - end + context 'when access token is not stored in session' do + it { expect(go).to redirect_to(gcp_login_project_clusters_path(project)) } end end @@ -146,10 +152,36 @@ describe Projects::Clusters::GcpController do stub_google_api_validate_token end - it 'has new object' do - go + context 'when google project billing status is true' do + before do + stub_google_project_billing_status + end + + it 'has new object' do + go + + expect(assigns(:cluster)).to be_an_instance_of(Clusters::Cluster) + end + end + + context 'when google project billing status is not true' do + before do + redis_double = double + allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) + allow(redis_double).to receive(:get).and_return(nil) + end + + it 'redirects to check page' do + allow(CheckGcpProjectBillingWorker).to receive(:perform_async) + + expect(go).to redirect_to(gcp_check_project_clusters_path(project)) + end + + it 'calls gcp project billing check worker' do + expect(CheckGcpProjectBillingWorker).to receive(:perform_async) - expect(assigns(:cluster)).to be_an_instance_of(Clusters::Cluster) + go + end end end @@ -207,14 +239,40 @@ describe Projects::Clusters::GcpController do stub_google_api_validate_token end - context 'when creates a cluster on gke' do - it 'creates a new cluster' do - expect(ClusterProvisionWorker).to receive(:perform_async) - expect { go }.to change { Clusters::Cluster.count } - .and change { Clusters::Providers::Gcp.count } - expect(response).to redirect_to(project_cluster_path(project, project.clusters.first)) - expect(project.clusters.first).to be_gcp - expect(project.clusters.first).to be_kubernetes + context 'when google project billing status is true' do + before do + stub_google_project_billing_status + end + + context 'when creates a cluster on gke' do + it 'creates a new cluster' do + expect(ClusterProvisionWorker).to receive(:perform_async) + expect { go }.to change { Clusters::Cluster.count } + .and change { Clusters::Providers::Gcp.count } + expect(response).to redirect_to(project_cluster_path(project, project.clusters.first)) + expect(project.clusters.first).to be_gcp + expect(project.clusters.first).to be_kubernetes + end + end + end + + context 'when google project billing status is not true' do + before do + redis_double = double + allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) + allow(redis_double).to receive(:get).and_return(nil) + end + + it 'redirects to check page' do + allow(CheckGcpProjectBillingWorker).to receive(:perform_async) + + expect(go).to redirect_to(gcp_check_project_clusters_path(project)) + end + + it 'calls gcp project billing check worker' do + expect(CheckGcpProjectBillingWorker).to receive(:perform_async) + + go end end end diff --git a/spec/support/google_api/cloud_platform_helpers.rb b/spec/support/google_api/cloud_platform_helpers.rb index 8a073e58db8..9f9289fa580 100644 --- a/spec/support/google_api/cloud_platform_helpers.rb +++ b/spec/support/google_api/cloud_platform_helpers.rb @@ -10,6 +10,12 @@ module GoogleApi request.session[GoogleApi::CloudPlatform::Client.session_key_for_expires_at] = 1.hour.ago.to_i.to_s end + def stub_google_project_billing_status + redis_double = double + allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) + allow(redis_double).to receive(:get).and_return('true') + end + def stub_cloud_platform_get_zone_cluster(project_id, zone, cluster_id, **options) WebMock.stub_request(:get, cloud_platform_get_zone_cluster_url(project_id, zone, cluster_id)) .to_return(cloud_platform_response(cloud_platform_cluster_body(options))) diff --git a/spec/workers/check_gcp_project_billing_worker_spec.rb b/spec/workers/check_gcp_project_billing_worker_spec.rb index ce9632549b6..d7984ad0c1b 100644 --- a/spec/workers/check_gcp_project_billing_worker_spec.rb +++ b/spec/workers/check_gcp_project_billing_worker_spec.rb @@ -7,7 +7,7 @@ describe CheckGcpProjectBillingWorker do context 'when there is no lease' do before do - allow_any_instance_of(CheckGcpProjectBillingWorker).to receive(:try_obtain_lease_for).and_return('randomuuid') + allow_any_instance_of(described_class).to receive(:try_obtain_lease_for).and_return('randomuuid') end it 'calls the service' do @@ -21,7 +21,7 @@ describe CheckGcpProjectBillingWorker do expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute).and_return(true) expect(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) - expect(redis_double).to receive(:set).with(CheckGcpProjectBillingWorker.redis_shared_state_key_for(token), anything) + expect(redis_double).to receive(:set).with(described_class.redis_shared_state_key_for(token), anything) subject end @@ -29,7 +29,7 @@ describe CheckGcpProjectBillingWorker do context 'when there is a lease' do before do - allow_any_instance_of(CheckGcpProjectBillingWorker).to receive(:try_obtain_lease_for).and_return(false) + allow_any_instance_of(described_class).to receive(:try_obtain_lease_for).and_return(false) end it 'does not call the service' do -- cgit v1.2.1 From 6c0fd3c22dc767d8d4d90fa0a008874098a6f22c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 16 Dec 2017 05:31:53 +0100 Subject: Handle html format in addition to json --- app/controllers/projects/clusters/gcp_controller.rb | 2 ++ config/routes/project.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/controllers/projects/clusters/gcp_controller.rb b/app/controllers/projects/clusters/gcp_controller.rb index 95c947001a3..34d4fd7d7ca 100644 --- a/app/controllers/projects/clusters/gcp_controller.rb +++ b/app/controllers/projects/clusters/gcp_controller.rb @@ -27,6 +27,8 @@ class Projects::Clusters::GcpController < Projects::ApplicationController render json: { billing: redis.get(CheckGcpProjectBillingWorker.redis_shared_state_key_for(token_in_session)) } end end + + format.html { render :check } end end diff --git a/config/routes/project.rb b/config/routes/project.rb index 26eb4fbeda3..9fbd0476bb8 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -189,9 +189,9 @@ constraints(ProjectUrlConstrainer.new) do get '/user/new', to: 'clusters/user#new' post '/user', to: 'clusters/user#create' - get '/gcp/check', to: 'clusters/gcp#check' get '/gcp/new', to: 'clusters/gcp#new' get '/gcp/login', to: 'clusters/gcp#login' + get '/gcp/check', to: 'clusters/gcp#check' post '/gcp', to: 'clusters/gcp#create' end end -- cgit v1.2.1 From c98238f18ac8aa68c971f0742b881e24daf258aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 16 Dec 2017 06:07:28 +0100 Subject: Inluce projects namespace when checking billing --- lib/google_api/cloud_platform/client.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/google_api/cloud_platform/client.rb b/lib/google_api/cloud_platform/client.rb index c107d001bec..f05d001fd02 100644 --- a/lib/google_api/cloud_platform/client.rb +++ b/lib/google_api/cloud_platform/client.rb @@ -55,7 +55,7 @@ module GoogleApi service = Google::Apis::CloudbillingV1::CloudbillingService.new service.authorization = access_token - service.get_project_billing_info(project_name) + service.get_project_billing_info("projects/#{project_name}") end def projects_zones_clusters_get(project_id, zone, cluster_id) -- cgit v1.2.1 From 63859419b284ff9c4eba0a1f0df6d8d72764fc50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 16 Dec 2017 16:07:44 +0100 Subject: Add CheckGcpProjectBillingWorker to sidekiq queue --- config/sidekiq_queues.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml index bc7c431731a..0a7b4b7c101 100644 --- a/config/sidekiq_queues.yml +++ b/config/sidekiq_queues.yml @@ -66,5 +66,6 @@ - [propagate_service_template, 1] - [background_migration, 1] - [gcp_cluster, 1] + - [check_gcp_project_billing, 1] - [project_migrate_hashed_storage, 1] - [storage_migrator, 1] -- cgit v1.2.1 From 886fd13fceda053533a382d1652f9fcce475d0e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 16 Dec 2017 17:02:26 +0100 Subject: Add Worker rerun action to GcpController --- .../projects/clusters/gcp_controller.rb | 11 ++++- config/routes/project.rb | 1 + .../projects/clusters/gcp_controller_spec.rb | 50 ++++++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/app/controllers/projects/clusters/gcp_controller.rb b/app/controllers/projects/clusters/gcp_controller.rb index 34d4fd7d7ca..c965a055fdd 100644 --- a/app/controllers/projects/clusters/gcp_controller.rb +++ b/app/controllers/projects/clusters/gcp_controller.rb @@ -1,7 +1,7 @@ class Projects::Clusters::GcpController < Projects::ApplicationController before_action :authorize_read_cluster! before_action :authorize_google_api, except: [:login] - before_action :authorize_google_project_billing, except: [:login, :check] + before_action :authorize_google_project_billing, except: [:login, :check, :run_check] before_action :authorize_create_cluster!, only: [:new, :create] STATUS_POLLING_INTERVAL = 1.minute.to_i @@ -32,6 +32,15 @@ class Projects::Clusters::GcpController < Projects::ApplicationController end end + def run_check + respond_to do |format| + format.json do + CheckGcpProjectBillingWorker.perform_async(token_in_session) + head :no_content + end + end + end + def new @cluster = ::Clusters::Cluster.new.tap do |cluster| cluster.build_provider_gcp diff --git a/config/routes/project.rb b/config/routes/project.rb index 9fbd0476bb8..d1e8c0ee267 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -192,6 +192,7 @@ constraints(ProjectUrlConstrainer.new) do get '/gcp/new', to: 'clusters/gcp#new' get '/gcp/login', to: 'clusters/gcp#login' get '/gcp/check', to: 'clusters/gcp#check' + post '/gcp/check', to: 'clusters/gcp#run_check' post '/gcp', to: 'clusters/gcp#create' end end diff --git a/spec/controllers/projects/clusters/gcp_controller_spec.rb b/spec/controllers/projects/clusters/gcp_controller_spec.rb index 852f3efe793..4fa798c5856 100644 --- a/spec/controllers/projects/clusters/gcp_controller_spec.rb +++ b/spec/controllers/projects/clusters/gcp_controller_spec.rb @@ -138,6 +138,56 @@ describe Projects::Clusters::GcpController do end end + describe 'POST check' do + let(:user) { create(:user) } + + before do + project.add_master(user) + sign_in(user) + end + + describe 'functionality' do + context 'when access token is valid' do + before do + stub_google_api_validate_token + end + + it 'calls check worker asynchronously' do + expect(CheckGcpProjectBillingWorker).to receive(:perform_async) + + expect(go).to have_http_status(:no_content) + end + end + + context 'when access token is expired' do + before do + stub_google_api_expired_token + end + + it { expect(go).to redirect_to(gcp_login_project_clusters_path(project)) } + end + + context 'when access token is not stored in session' do + it { expect(go).to redirect_to(gcp_login_project_clusters_path(project)) } + end + end + + describe 'security' do + it { expect { go }.to be_allowed_for(:admin) } + it { expect { go }.to be_allowed_for(:owner).of(project) } + it { expect { go }.to be_allowed_for(:master).of(project) } + it { expect { go }.to be_denied_for(:developer).of(project) } + it { expect { go }.to be_denied_for(:reporter).of(project) } + it { expect { go }.to be_denied_for(:guest).of(project) } + it { expect { go }.to be_denied_for(:user) } + it { expect { go }.to be_denied_for(:external) } + end + + def go + post :run_check, namespace_id: project.namespace, project_id: project, format: :json + end + end + describe 'GET new' do describe 'functionality' do let(:user) { create(:user) } -- cgit v1.2.1 From 614c0e0bf9c404ba43f835166183a2f1883071d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 16 Dec 2017 18:55:47 +0100 Subject: Update GCP feature spec with check page flow --- spec/features/projects/clusters/gcp_spec.rb | 153 ++++++++++++++++------------ 1 file changed, 86 insertions(+), 67 deletions(-) diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index 67b8901f8fb..4b682acd47e 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -20,105 +20,124 @@ feature 'Gcp Cluster', :js do .to receive(:expires_at_in_session).and_return(1.hour.since.to_i.to_s) end - context 'when user does not have a cluster and visits cluster index page' do + context 'when user has a GCP project with billing enabled' do before do - visit project_clusters_path(project) - - click_link 'Add cluster' - click_link 'Create on GKE' + stub_google_project_billing_status end - context 'when user filled form with valid parameters' do + context 'when user does not have a cluster and visits cluster index page' do before do - allow_any_instance_of(GoogleApi::CloudPlatform::Client) - .to receive(:projects_zones_clusters_create) do - OpenStruct.new( - self_link: 'projects/gcp-project-12345/zones/us-central1-a/operations/ope-123', - status: 'RUNNING' - ) + visit project_clusters_path(project) + + click_link 'Add cluster' + click_link 'Create on GKE' + end + + context 'when user filled form with valid parameters' do + before do + allow_any_instance_of(GoogleApi::CloudPlatform::Client) + .to receive(:projects_zones_clusters_create) do + OpenStruct.new( + self_link: 'projects/gcp-project-12345/zones/us-central1-a/operations/ope-123', + status: 'RUNNING' + ) + end + + allow(WaitForClusterCreationWorker).to receive(:perform_in).and_return(nil) + + fill_in 'cluster_provider_gcp_attributes_gcp_project_id', with: 'gcp-project-123' + fill_in 'cluster_name', with: 'dev-cluster' + click_button 'Create cluster' end - allow(WaitForClusterCreationWorker).to receive(:perform_in).and_return(nil) + it 'user sees a cluster details page and creation status' do + expect(page).to have_content('Cluster is being created on Google Kubernetes Engine...') - fill_in 'cluster_provider_gcp_attributes_gcp_project_id', with: 'gcp-project-123' - fill_in 'cluster_name', with: 'dev-cluster' - click_button 'Create cluster' - end + Clusters::Cluster.last.provider.make_created! - it 'user sees a cluster details page and creation status' do - expect(page).to have_content('Cluster is being created on Google Kubernetes Engine...') + expect(page).to have_content('Cluster was successfully created on Google Kubernetes Engine') + end - Clusters::Cluster.last.provider.make_created! + it 'user sees a error if something worng during creation' do + expect(page).to have_content('Cluster is being created on Google Kubernetes Engine...') - expect(page).to have_content('Cluster was successfully created on Google Kubernetes Engine') - end + Clusters::Cluster.last.provider.make_errored!('Something wrong!') - it 'user sees a error if something worng during creation' do - expect(page).to have_content('Cluster is being created on Google Kubernetes Engine...') + expect(page).to have_content('Something wrong!') + end + end - Clusters::Cluster.last.provider.make_errored!('Something wrong!') + context 'when user filled form with invalid parameters' do + before do + click_button 'Create cluster' + end - expect(page).to have_content('Something wrong!') + it 'user sees a validation error' do + expect(page).to have_css('#error_explanation') + end end end - context 'when user filled form with invalid parameters' do + context 'when user does have a cluster and visits cluster page' do + let(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } + before do - click_button 'Create cluster' + visit project_cluster_path(project, cluster) end - it 'user sees a validation error' do - expect(page).to have_css('#error_explanation') + it 'user sees a cluster details page' do + expect(page).to have_button('Save') + expect(page.find(:css, '.cluster-name').value).to eq(cluster.name) end - end - end - context 'when user does have a cluster and visits cluster page' do - let(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } + context 'when user disables the cluster' do + before do + page.find(:css, '.js-toggle-cluster').click + click_button 'Save' + end - before do - visit project_cluster_path(project, cluster) - end + it 'user sees the successful message' do + expect(page).to have_content('Cluster was successfully updated.') + end + end - it 'user sees a cluster details page' do - expect(page).to have_button('Save') - expect(page.find(:css, '.cluster-name').value).to eq(cluster.name) - end + context 'when user changes cluster parameters' do + before do + fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace' + click_button 'Save changes' + end - context 'when user disables the cluster' do - before do - page.find(:css, '.js-toggle-cluster').click - click_button 'Save' + it 'user sees the successful message' do + expect(page).to have_content('Cluster was successfully updated.') + expect(cluster.reload.platform_kubernetes.namespace).to eq('my-namespace') + end end - it 'user sees the successful message' do - expect(page).to have_content('Cluster was successfully updated.') + context 'when user destroy the cluster' do + before do + page.accept_confirm do + click_link 'Remove integration' + end + end + + it 'user sees creation form with the successful message' do + expect(page).to have_content('Cluster integration was successfully removed.') + expect(page).to have_link('Add cluster') + end end end + end - context 'when user changes cluster parameters' do - before do - fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace' - click_button 'Save changes' - end + context 'when user does not have a GCP project with billing enabled' do + before do + visit project_clusters_path(project) - it 'user sees the successful message' do - expect(page).to have_content('Cluster was successfully updated.') - expect(cluster.reload.platform_kubernetes.namespace).to eq('my-namespace') - end + click_link 'Add cluster' + click_link 'Create on GKE' end - context 'when user destroy the cluster' do - before do - page.accept_confirm do - click_link 'Remove integration' - end - end - - it 'user sees creation form with the successful message' do - expect(page).to have_content('Cluster integration was successfully removed.') - expect(page).to have_link('Add cluster') - end + it 'user sees a check page' do + expect(page).to have_link('Continue') end end end -- cgit v1.2.1 From b7f59772b16b39baca7dbe2cb5dd830b7382c038 Mon Sep 17 00:00:00 2001 From: Christiaan Van den Poel Date: Sun, 17 Dec 2017 21:07:29 +0100 Subject: remove the label --- app/assets/javascripts/boards/boards_bundle.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/javascripts/boards/boards_bundle.js b/app/assets/javascripts/boards/boards_bundle.js index 20d23162940..0c1cff1da7a 100644 --- a/app/assets/javascripts/boards/boards_bundle.js +++ b/app/assets/javascripts/boards/boards_bundle.js @@ -102,7 +102,6 @@ $(() => { if (list.type === 'closed') { list.position = Infinity; - list.label = { description: 'Shows all closed issues. Moving an issue to this list closes it' }; } else if (list.type === 'backlog') { list.position = -1; } -- cgit v1.2.1 From 148c7533d701490eb5cd8aebc4fa033e0f0f6ec4 Mon Sep 17 00:00:00 2001 From: Christiaan Van den Poel Date: Sun, 17 Dec 2017 21:09:57 +0100 Subject: added changelog --- ...how_proper_labels_in_board_issue_sidebar_when_issue_is_closed.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/show_proper_labels_in_board_issue_sidebar_when_issue_is_closed.yml diff --git a/changelogs/unreleased/show_proper_labels_in_board_issue_sidebar_when_issue_is_closed.yml b/changelogs/unreleased/show_proper_labels_in_board_issue_sidebar_when_issue_is_closed.yml new file mode 100644 index 00000000000..c2ab34b20a5 --- /dev/null +++ b/changelogs/unreleased/show_proper_labels_in_board_issue_sidebar_when_issue_is_closed.yml @@ -0,0 +1,5 @@ +--- +title: show None when issue is in closed list and no labels assigned +merge_request: 15976 +author: Christiaan Van den Poel +type: fixed -- cgit v1.2.1 From 572de0c1c2788d8d434a967f6ef0cb144f7f668f Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 19 Dec 2017 11:04:04 +0000 Subject: Adds illustrations for manual actions and non triggered jobs --- app/assets/images/icons.json | 2 +- app/assets/images/icons.svg | 2 +- .../images/illustrations/job_not_triggered.svg | 1 + app/assets/images/illustrations/manual_action.svg | 1 + .../images/illustrations/service_desk_callout.svg | 1 + .../images/illustrations/service_desk_empty.svg | 1 + app/assets/javascripts/jobs/components/header.vue | 6 +- .../vue_shared/components/header_ci_component.vue | 12 +++- app/serializers/job_entity.rb | 2 + app/views/projects/jobs/show.html.haml | 78 ++++++++++++--------- spec/features/projects/jobs_spec.rb | 28 ++++++++ spec/javascripts/jobs/header_spec.js | 3 +- .../components/header_ci_component_spec.js | 81 ++++++++++++---------- 13 files changed, 146 insertions(+), 72 deletions(-) create mode 100644 app/assets/images/illustrations/job_not_triggered.svg create mode 100644 app/assets/images/illustrations/manual_action.svg create mode 100644 app/assets/images/illustrations/service_desk_callout.svg create mode 100644 app/assets/images/illustrations/service_desk_empty.svg diff --git a/app/assets/images/icons.json b/app/assets/images/icons.json index 68d6528758b..1e06ef42b45 100644 --- a/app/assets/images/icons.json +++ b/app/assets/images/icons.json @@ -1 +1 @@ -{"iconCount":181,"spriteSize":81482,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]} \ No newline at end of file +{"iconCount":184,"spriteSize":83050,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o","folder-open","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]} \ No newline at end of file diff --git a/app/assets/images/icons.svg b/app/assets/images/icons.svg index fd8f7862911..d5b2f597b4d 100644 --- a/app/assets/images/icons.svg +++ b/app/assets/images/icons.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/assets/images/illustrations/job_not_triggered.svg b/app/assets/images/illustrations/job_not_triggered.svg new file mode 100644 index 00000000000..e13c1cb0a7d --- /dev/null +++ b/app/assets/images/illustrations/job_not_triggered.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/illustrations/manual_action.svg b/app/assets/images/illustrations/manual_action.svg new file mode 100644 index 00000000000..85735855b46 --- /dev/null +++ b/app/assets/images/illustrations/manual_action.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/illustrations/service_desk_callout.svg b/app/assets/images/illustrations/service_desk_callout.svg new file mode 100644 index 00000000000..2886388279e --- /dev/null +++ b/app/assets/images/illustrations/service_desk_callout.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/illustrations/service_desk_empty.svg b/app/assets/images/illustrations/service_desk_empty.svg new file mode 100644 index 00000000000..daaaeae6a17 --- /dev/null +++ b/app/assets/images/illustrations/service_desk_empty.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/javascripts/jobs/components/header.vue b/app/assets/javascripts/jobs/components/header.vue index 6d671845f8e..0de823831d9 100644 --- a/app/assets/javascripts/jobs/components/header.vue +++ b/app/assets/javascripts/jobs/components/header.vue @@ -30,6 +30,9 @@ shouldRenderContent() { return !this.isLoading && Object.keys(this.job).length; }, + wasTriggered() { + return this.job.started; + }, }, methods: { getActions() { @@ -63,7 +66,8 @@ :time="job.created_at" :user="job.user" :actions="actions" - :hasSidebarButton="true" + :has-sidebar-button="true" + :triggered="wasTriggered" /> - triggered + + diff --git a/app/serializers/job_entity.rb b/app/serializers/job_entity.rb index 72e56a2c77f..523b522d449 100644 --- a/app/serializers/job_entity.rb +++ b/app/serializers/job_entity.rb @@ -4,6 +4,8 @@ class JobEntity < Grape::Entity expose :id expose :name + expose :started?, as: :started + expose :build_path do |build| build.target_url || path_to(:namespace_project_job, build) end diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml index 1d0aaa47b60..f7d06d8ceb9 100644 --- a/app/views/projects/jobs/show.html.haml +++ b/app/views/projects/jobs/show.html.haml @@ -54,41 +54,55 @@ Job has been erased by #{link_to(@build.erased_by_name, user_path(@build.erased_by))} #{time_ago_with_tooltip(@build.erased_at)} - else Job has been erased #{time_ago_with_tooltip(@build.erased_at)} + - if @build.started? + .build-trace-container.prepend-top-default + .top-bar.js-top-bar + .js-truncated-info.truncated-info.hidden-xs.pull-left.hidden< + Showing last + %span.js-truncated-info-size.truncated-info-size>< + KiB of log - + %a.js-raw-link.raw-link{ href: raw_project_job_path(@project, @build) }>< Complete Raw - .build-trace-container.prepend-top-default - .top-bar.js-top-bar - .js-truncated-info.truncated-info.hidden-xs.pull-left.hidden< - Showing last - %span.js-truncated-info-size.truncated-info-size>< - KiB of log - - %a.js-raw-link.raw-link{ href: raw_project_job_path(@project, @build) }>< Complete Raw + .controllers.pull-right + - if @build.has_trace? + = link_to raw_project_job_path(@project, @build), + title: 'Show complete raw', + data: { placement: 'top', container: 'body' }, + class: 'js-raw-link-controller has-tooltip controllers-buttons' do + = icon('file-text-o') - .controllers.pull-right - - if @build.has_trace? - = link_to raw_project_job_path(@project, @build), - title: 'Show complete raw', - data: { placement: 'top', container: 'body' }, - class: 'js-raw-link-controller has-tooltip controllers-buttons' do - = icon('file-text-o') - - - if @build.erasable? && can?(current_user, :erase_build, @build) - = link_to erase_project_job_path(@project, @build), - method: :post, - data: { confirm: 'Are you sure you want to erase this build?', placement: 'top', container: 'body' }, - title: 'Erase job log', - class: 'has-tooltip js-erase-link controllers-buttons' do - = icon('trash') - .has-tooltip.controllers-buttons{ title: 'Scroll to top', data: { placement: 'top', container: 'body'} } - %button.js-scroll-up.btn-scroll.btn-transparent.btn-blank{ type: 'button', disabled: true } - = custom_icon('scroll_up') - .has-tooltip.controllers-buttons{ title: 'Scroll to bottom', data: { placement: 'top', container: 'body'} } - %button.js-scroll-down.btn-scroll.btn-transparent.btn-blank{ type: 'button', disabled: true } - = custom_icon('scroll_down') - - %pre.build-trace#build-trace - %code.bash.js-build-output - .build-loader-animation.js-build-refresh + - if @build.erasable? && can?(current_user, :erase_build, @build) + = link_to erase_project_job_path(@project, @build), + method: :post, + data: { confirm: 'Are you sure you want to erase this build?', placement: 'top', container: 'body' }, + title: 'Erase job log', + class: 'has-tooltip js-erase-link controllers-buttons' do + = icon('trash') + .has-tooltip.controllers-buttons{ title: 'Scroll to top', data: { placement: 'top', container: 'body'} } + %button.js-scroll-up.btn-scroll.btn-transparent.btn-blank{ type: 'button', disabled: true } + = custom_icon('scroll_up') + .has-tooltip.controllers-buttons{ title: 'Scroll to bottom', data: { placement: 'top', container: 'body'} } + %button.js-scroll-down.btn-scroll.btn-transparent.btn-blank{ type: 'button', disabled: true } + = custom_icon('scroll_down') + %pre.build-trace#build-trace + %code.bash.js-build-output + .build-loader-animation.js-build-refresh + - else + - illustration = @build.playable? ? 'illustrations/manual_action.svg' : 'illustrations/job_not_triggered.svg' + - title = @build.playable? ? _('This job requires a manual action') : _('This job has not been triggered yet') + - content = @build.playable? ? _('This job depends on a user to trigger its process. Often they are used to deploy code to production environments.') : _('This job depends on upstream jobs that need to succeed in order for this job to be triggered.') + .row.empty-state + .col-xs-12 + .svg-content + = image_tag illustration + .col-xs-12 + .text-content + %h4.text-center= title + %p= content + - if @build.playable? + .text-center + = link_to _('Trigger this manual action'), play_project_job_path(@project, @build), class: 'btn btn-primary', title: _('Trigger this manual action') = render "sidebar" diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index 0b0d5a2dce8..a3b8a1c387f 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -369,6 +369,34 @@ feature 'Jobs' do end end end + + context 'Playable manual action' do + let(:build) { create(:ci_build, :playable, pipeline: pipeline) } + + before do + project.add_developer(user) + visit project_job_path(project, job) + end + + it 'shows manual action empty state' do + expect(page).to have_content('This job requires a manual action') + expect(page).to have_content('This job depends on a user to trigger its process. Often they are used to deploy code to production environments.') + expect(page).to have_link('Trigger this manual action') + end + end + + context 'Non triggered job' do + let(:job) { create(:ci_build, :created, pipeline: pipeline) } + + before do + visit project_job_path(project, job) + end + + it 'shows manual action empty state' do + expect(page).to have_content('This job has not been triggered yet') + expect(page).to have_content('This job depends on upstream jobs that need to succeed in order for this job to be triggered.') + end + end end describe "POST /:project/jobs/:id/cancel", :js do diff --git a/spec/javascripts/jobs/header_spec.js b/spec/javascripts/jobs/header_spec.js index 4a210faa017..83395ea451e 100644 --- a/spec/javascripts/jobs/header_spec.js +++ b/spec/javascripts/jobs/header_spec.js @@ -1,5 +1,6 @@ import Vue from 'vue'; import headerComponent from '~/jobs/components/header.vue'; +import mountComponent from '../helpers/vue_mount_component_helper'; describe('Job details header', () => { let HeaderComponent; @@ -35,7 +36,7 @@ describe('Job details header', () => { isLoading: false, }; - vm = new HeaderComponent({ propsData: props }).$mount(); + vm = mountComponent(HeaderComponent, props); }); afterEach(() => { diff --git a/spec/javascripts/vue_shared/components/header_ci_component_spec.js b/spec/javascripts/vue_shared/components/header_ci_component_spec.js index b4553acb341..66c6f70a667 100644 --- a/spec/javascripts/vue_shared/components/header_ci_component_spec.js +++ b/spec/javascripts/vue_shared/components/header_ci_component_spec.js @@ -1,5 +1,6 @@ import Vue from 'vue'; import headerCi from '~/vue_shared/components/header_ci_component.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; describe('Header CI Component', () => { let HeaderCi; @@ -8,7 +9,6 @@ describe('Header CI Component', () => { beforeEach(() => { HeaderCi = Vue.extend(headerCi); - props = { status: { group: 'failed', @@ -45,54 +45,65 @@ describe('Header CI Component', () => { ], hasSidebarButton: true, }; - - vm = new HeaderCi({ - propsData: props, - }).$mount(); }); afterEach(() => { vm.$destroy(); }); - it('should render status badge', () => { - expect(vm.$el.querySelector('.ci-failed')).toBeDefined(); - expect(vm.$el.querySelector('.ci-status-icon-failed svg')).toBeDefined(); - expect( - vm.$el.querySelector('.ci-failed').getAttribute('href'), - ).toEqual(props.status.details_path); - }); + describe('render', () => { + beforeEach(() => { + vm = mountComponent(HeaderCi, props); + }); - it('should render item name and id', () => { - expect(vm.$el.querySelector('strong').textContent.trim()).toEqual('job #123'); - }); + it('should render status badge', () => { + expect(vm.$el.querySelector('.ci-failed')).toBeDefined(); + expect(vm.$el.querySelector('.ci-status-icon-failed svg')).toBeDefined(); + expect( + vm.$el.querySelector('.ci-failed').getAttribute('href'), + ).toEqual(props.status.details_path); + }); - it('should render timeago date', () => { - expect(vm.$el.querySelector('time')).toBeDefined(); - }); + it('should render item name and id', () => { + expect(vm.$el.querySelector('strong').textContent.trim()).toEqual('job #123'); + }); - it('should render user icon and name', () => { - expect(vm.$el.querySelector('.js-user-link').textContent.trim()).toEqual(props.user.name); - }); + it('should render timeago date', () => { + expect(vm.$el.querySelector('time')).toBeDefined(); + }); - it('should render provided actions', () => { - expect(vm.$el.querySelector('.btn').tagName).toEqual('BUTTON'); - expect(vm.$el.querySelector('.btn').textContent.trim()).toEqual(props.actions[0].label); - expect(vm.$el.querySelector('.link').tagName).toEqual('A'); - expect(vm.$el.querySelector('.link').textContent.trim()).toEqual(props.actions[1].label); - expect(vm.$el.querySelector('.link').getAttribute('href')).toEqual(props.actions[0].path); - }); + it('should render user icon and name', () => { + expect(vm.$el.querySelector('.js-user-link').textContent.trim()).toEqual(props.user.name); + }); + + it('should render provided actions', () => { + expect(vm.$el.querySelector('.btn').tagName).toEqual('BUTTON'); + expect(vm.$el.querySelector('.btn').textContent.trim()).toEqual(props.actions[0].label); + expect(vm.$el.querySelector('.link').tagName).toEqual('A'); + expect(vm.$el.querySelector('.link').textContent.trim()).toEqual(props.actions[1].label); + expect(vm.$el.querySelector('.link').getAttribute('href')).toEqual(props.actions[0].path); + }); - it('should show loading icon', (done) => { - vm.actions[0].isLoading = true; + it('should show loading icon', (done) => { + vm.actions[0].isLoading = true; - Vue.nextTick(() => { - expect(vm.$el.querySelector('.btn .fa-spinner').getAttribute('style')).toBeFalsy(); - done(); + Vue.nextTick(() => { + expect(vm.$el.querySelector('.btn .fa-spinner').getAttribute('style')).toBeFalsy(); + done(); + }); + }); + + it('should render sidebar toggle button', () => { + expect(vm.$el.querySelector('.js-sidebar-build-toggle')).toBeDefined(); }); }); - it('should render sidebar toggle button', () => { - expect(vm.$el.querySelector('.js-sidebar-build-toggle')).toBeDefined(); + describe('triggered', () => { + it('should rendered created keyword when the triggered is false', () => { + vm = mountComponent(HeaderCi, { ...props, triggered: false }); + + expect(vm.$el.textContent).toContain('created'); + expect(vm.$el.textContent).not.toContain('triggered'); + }); }); }); -- cgit v1.2.1 From a623ddb0dcdc42b0bd4f9d20c79e82387d9b5547 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Thu, 16 Nov 2017 13:34:15 -0600 Subject: replaced download icon for the sprite based one --- .../javascripts/pipelines/components/pipelines_artifacts.vue | 11 +++++++---- .../vue_merge_request_widget/components/mr_widget_header.js | 7 +++++-- app/helpers/blob_helper.rb | 2 +- app/views/projects/artifacts/browse.html.haml | 2 +- app/views/projects/blob/viewers/_download.html.haml | 2 +- app/views/projects/buttons/_download.html.haml | 2 +- app/views/projects/ci/builds/_build.html.haml | 2 +- 7 files changed, 17 insertions(+), 11 deletions(-) diff --git a/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue index 751a20991af..fada8fd90df 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue @@ -1,5 +1,6 @@ diff --git a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue index 5d95ddcd90e..508a411e599 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue +++ b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue @@ -3,6 +3,7 @@ import iconBranch from '../svg/icon_branch.svg'; import limitWarning from './limit_warning_component.vue'; import totalTime from './total_time_component.vue'; + import icon from '../../vue_shared/components/icon.vue'; export default { props: { @@ -13,6 +14,7 @@ userAvatarImage, totalTime, limitWarning, + icon, }, computed: { iconBranch() { @@ -37,7 +39,10 @@
#{{ build.id }} - + + {{ build.branch.name }} {{ build.shortSha }} diff --git a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue index 04d5440b77b..88fa6b073ca 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue +++ b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue @@ -3,6 +3,7 @@ import iconBranch from '../svg/icon_branch.svg'; import limitWarning from './limit_warning_component.vue'; import totalTime from './total_time_component.vue'; + import icon from '../../vue_shared/components/icon.vue'; export default { props: { @@ -12,6 +13,7 @@ components: { totalTime, limitWarning, + icon, }, computed: { iconBuildStatus() { @@ -40,7 +42,10 @@ {{ build.name }} · #{{ build.id }} - + + {{ build.branch.name }} {{ build.shortSha }} diff --git a/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue index fada8fd90df..831aa92ac4f 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_artifacts.vue @@ -1,6 +1,6 @@ diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js index 38c3ec874c6..85bfd03a3cf 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.js @@ -1,6 +1,6 @@ import tooltip from '../../vue_shared/directives/tooltip'; import { pluralize } from '../../lib/utils/text_utility'; -import Icon from '../../vue_shared/components/icon.vue'; +import icon from '../../vue_shared/components/icon.vue'; export default { name: 'MRWidgetHeader', @@ -11,7 +11,7 @@ export default { tooltip, }, components: { - Icon, + icon, }, computed: { shouldShowCommitsBehindText() { diff --git a/app/assets/stylesheets/framework/wells.scss b/app/assets/stylesheets/framework/wells.scss index 735fc4babd7..2f3a80daa90 100644 --- a/app/assets/stylesheets/framework/wells.scss +++ b/app/assets/stylesheets/framework/wells.scss @@ -16,6 +16,10 @@ .commit-sha, .commit-info { margin-left: 4px; + + .fork-svg { + margin-right: 4px; + } } .ref-name { @@ -79,7 +83,7 @@ } .limit-icon { - margin: 0 8px; + margin: 0 4px; } .limit-message { diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 373e01931ad..f887a11004f 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -725,7 +725,5 @@ } .fork-sprite { - width: 12px; - height: 12px; margin-right: -5px; } diff --git a/app/assets/stylesheets/pages/pipeline_schedules.scss b/app/assets/stylesheets/pages/pipeline_schedules.scss index 7e2297c283f..b698a4f9afa 100644 --- a/app/assets/stylesheets/pages/pipeline_schedules.scss +++ b/app/assets/stylesheets/pages/pipeline_schedules.scss @@ -39,6 +39,10 @@ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + + svg { + vertical-align: middle; + } } .next-run-cell { diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 2d304f7eb91..0333c29e2fd 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -63,7 +63,7 @@ module CommitsHelper # Returns a link formatted as a commit branch link def commit_branch_link(url, text) link_to(url, class: 'label label-gray ref-name branch-link') do - icon('code-fork', class: 'append-right-5') + "#{text}" + sprite_icon('fork', size: 16, css_class: 'fork-svg') + "#{text}" end end diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml index 8a8011c27b4..acf67b83890 100644 --- a/app/views/projects/branches/_branch.html.haml +++ b/app/views/projects/branches/_branch.html.haml @@ -8,7 +8,7 @@ %li{ class: "js-branch-#{branch.name}" } %div = link_to project_tree_path(@project, branch.name), class: 'item-title str-truncated ref-name' do - = sprite_icon('fork', size: 8) + = sprite_icon('fork', size: 12) = branch.name   - if branch.name == @repository.root_ref diff --git a/app/views/projects/commit/_limit_exceeded_message.html.haml b/app/views/projects/commit/_limit_exceeded_message.html.haml index 84a52d49487..a264f3517c4 100644 --- a/app/views/projects/commit/_limit_exceeded_message.html.haml +++ b/app/views/projects/commit/_limit_exceeded_message.html.haml @@ -1,7 +1,7 @@ .has-tooltip{ class: "limit-box limit-box-#{objects} prepend-left-5", data: { title: "Project has too many #{label_for_message} to search"} } .limit-icon - if objects == :branch - = icon('code-fork') + = sprite_icon('fork', size: 12) - else = icon('tag') .limit-message diff --git a/app/views/projects/deployments/_commit.html.haml b/app/views/projects/deployments/_commit.html.haml index 014486be868..c7ac687e4a6 100644 --- a/app/views/projects/deployments/_commit.html.haml +++ b/app/views/projects/deployments/_commit.html.haml @@ -2,7 +2,7 @@ .branch-commit - if deployment.ref %span.icon-container - = deployment.tag? ? icon('tag') : icon('code-fork') + = deployment.tag? ? icon('tag') : sprite_icon('fork', css_class: 'sprite') = link_to deployment.ref, project_ref_path(@project, deployment.ref), class: "ref-name" .icon-container.commit-icon = custom_icon("icon_commit") diff --git a/app/views/projects/forks/error.html.haml b/app/views/projects/forks/error.html.haml index d365bcd4ecc..e8a89b8c6fc 100644 --- a/app/views/projects/forks/error.html.haml +++ b/app/views/projects/forks/error.html.haml @@ -2,7 +2,7 @@ - if @forked_project && !@forked_project.saved? .alert.alert-danger.alert-block %h4 - %i.fa.fa-code-fork + = sprite_icon('fork', size: 16) Fork Error! %p You tried to fork @@ -21,5 +21,4 @@ %p = link_to new_project_fork_path(@project), title: "Fork", class: "btn" do - %i.fa.fa-code-fork Try to fork again diff --git a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml index b98dc09534f..2599ce5c4b8 100644 --- a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml +++ b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml @@ -19,7 +19,7 @@ - if ref - if generic_commit_status.ref .icon-container - = generic_commit_status.tags.any? ? icon('tag') : icon('code-fork') + = generic_commit_status.tags.any? ? icon('tag') : sprite_icon('fork', size: 10) = link_to generic_commit_status.ref, project_commits_path(generic_commit_status.project, generic_commit_status.ref) - else .light none diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml index 591da3b6638..f45a000833b 100644 --- a/app/views/projects/merge_requests/_merge_request.html.haml +++ b/app/views/projects/merge_requests/_merge_request.html.haml @@ -30,7 +30,7 @@ %span.project-ref-path   = link_to project_ref_path(merge_request.project, merge_request.target_branch), class: 'ref-name' do - = sprite_icon('fork', css_class: 'fork-sprite') + = sprite_icon('fork', size: 12, css_class: 'fork-sprite') = merge_request.target_branch - if merge_request.labels.any?   diff --git a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml index f8c4005a9e0..800e234275c 100644 --- a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml +++ b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml @@ -3,7 +3,7 @@ %td = pipeline_schedule.description %td.branch-name-cell - = icon('code-fork') + = sprite_icon('fork', size: 12) - if pipeline_schedule.ref.present? = link_to pipeline_schedule.ref, project_ref_path(@project, pipeline_schedule.ref), class: "ref-name" %td diff --git a/spec/javascripts/vue_shared/components/commit_spec.js b/spec/javascripts/vue_shared/components/commit_spec.js index d5754aaa9e7..fdead874209 100644 --- a/spec/javascripts/vue_shared/components/commit_spec.js +++ b/spec/javascripts/vue_shared/components/commit_spec.js @@ -10,7 +10,7 @@ describe('Commit component', () => { CommitComponent = Vue.extend(commitComp); }); - it('should render a code-fork icon if it does not represent a tag', () => { + it('should render a fork icon if it does not represent a tag', () => { component = new CommitComponent({ propsData: { tag: false, @@ -30,7 +30,7 @@ describe('Commit component', () => { }, }).$mount(); - expect(component.$el.querySelector('.icon-container i').classList).toContain('fa-code-fork'); + expect(component.$el.querySelector('.icon-container').children).toContain('svg'); }); describe('Given all the props', () => { -- cgit v1.2.1 From ce8b53ea89b40e16c8da2e3b90c7ef3f1b148920 Mon Sep 17 00:00:00 2001 From: asaparov Date: Tue, 19 Dec 2017 19:10:14 -0500 Subject: Bumped mysql2 gem version from 0.4.5 to 0.4.10. --- Gemfile | 2 +- Gemfile.lock | 4 ++-- changelogs/unreleased/bump_mysql_gem.yml | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/bump_mysql_gem.yml diff --git a/Gemfile b/Gemfile index b6ffaf80f24..cc39714295e 100644 --- a/Gemfile +++ b/Gemfile @@ -12,7 +12,7 @@ gem 'sprockets', '~> 3.7.0' gem 'default_value_for', '~> 3.0.0' # Supported DBs -gem 'mysql2', '~> 0.4.5', group: :mysql +gem 'mysql2', '~> 0.4.10', group: :mysql gem 'pg', '~> 0.18.2', group: :postgres gem 'rugged', '~> 0.26.0' diff --git a/Gemfile.lock b/Gemfile.lock index a6e3c9e27cc..d11cadeec30 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -501,7 +501,7 @@ GEM mustermann (1.0.0) mustermann-grape (1.0.0) mustermann (~> 1.0.0) - mysql2 (0.4.5) + mysql2 (0.4.10) net-ldap (0.16.0) net-ssh (4.1.0) netrc (0.11.0) @@ -1082,7 +1082,7 @@ DEPENDENCIES method_source (~> 0.8) minitest (~> 5.7.0) mousetrap-rails (~> 1.4.6) - mysql2 (~> 0.4.5) + mysql2 (~> 0.4.10) net-ldap net-ssh (~> 4.1.0) nokogiri (~> 1.8.1) diff --git a/changelogs/unreleased/bump_mysql_gem.yml b/changelogs/unreleased/bump_mysql_gem.yml new file mode 100644 index 00000000000..58166949d72 --- /dev/null +++ b/changelogs/unreleased/bump_mysql_gem.yml @@ -0,0 +1,5 @@ +--- +title: Bump mysql2 gem version from 0.4.5 to 0.4.10 +merge_request: +author: asaparov +type: other -- cgit v1.2.1 From a331a06aa8da542afa985d61370b9518cc44b1e9 Mon Sep 17 00:00:00 2001 From: julien MILLAU Date: Wed, 20 Dec 2017 08:11:13 +0000 Subject: Ignore "lost+found" folder during backup on a volume --- lib/backup/files.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/backup/files.rb b/lib/backup/files.rb index 30a91647b77..287d591e88d 100644 --- a/lib/backup/files.rb +++ b/lib/backup/files.rb @@ -18,7 +18,7 @@ module Backup FileUtils.rm_f(backup_tarball) if ENV['STRATEGY'] == 'copy' - cmd = %W(cp -a #{app_files_dir} #{Gitlab.config.backup.path}) + cmd = %W(rsync -a --exclude=lost+found #{app_files_dir} #{Gitlab.config.backup.path}) output, status = Gitlab::Popen.popen(cmd) unless status.zero? @@ -26,10 +26,10 @@ module Backup abort 'Backup failed' end - run_pipeline!([%W(tar -C #{@backup_files_dir} -cf - .), %w(gzip -c -1)], out: [backup_tarball, 'w', 0600]) + run_pipeline!([%W(tar --exclude=lost+found -C #{@backup_files_dir} -cf - .), %w(gzip -c -1)], out: [backup_tarball, 'w', 0600]) FileUtils.rm_rf(@backup_files_dir) else - run_pipeline!([%W(tar -C #{app_files_dir} -cf - .), %w(gzip -c -1)], out: [backup_tarball, 'w', 0600]) + run_pipeline!([%W(tar --exclude=lost+found -C #{app_files_dir} -cf - .), %w(gzip -c -1)], out: [backup_tarball, 'w', 0600]) end end -- cgit v1.2.1 From 091c4989b3c1e18723aef2b28475866b1a89e282 Mon Sep 17 00:00:00 2001 From: julien MILLAU Date: Wed, 20 Dec 2017 08:55:15 +0000 Subject: Add changelog --- .../16036-ignore-lost-found-folder-during-backup-on-a-volume.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/16036-ignore-lost-found-folder-during-backup-on-a-volume.yml diff --git a/changelogs/unreleased/16036-ignore-lost-found-folder-during-backup-on-a-volume.yml b/changelogs/unreleased/16036-ignore-lost-found-folder-during-backup-on-a-volume.yml new file mode 100644 index 00000000000..833650559a3 --- /dev/null +++ b/changelogs/unreleased/16036-ignore-lost-found-folder-during-backup-on-a-volume.yml @@ -0,0 +1,5 @@ +--- +title: "Ignore lost+found folder during backup on a volume" +merge_request: 16036 +author: Julien Millau +type: fixed \ No newline at end of file -- cgit v1.2.1 From e7b0fe36d78a4462baf623bda5d34089a19e6c23 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Wed, 20 Dec 2017 17:26:21 +0800 Subject: It should escape spaces to %20 rather than + `CGI.escape` would escape spaces to +, which is fine in some cases, but doesn't work for git clone. --- qa/qa/git/repository.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/qa/git/repository.rb b/qa/qa/git/repository.rb index 59cd147e055..8f999511d58 100644 --- a/qa/qa/git/repository.rb +++ b/qa/qa/git/repository.rb @@ -23,7 +23,7 @@ module QA def password=(pass) @password = pass - @uri.password = CGI.escape(pass) + @uri.password = CGI.escape(pass).gsub('+', '%20') end def use_default_credentials -- cgit v1.2.1 From 2c4174028d4fb150fb1adbc7ec920007b72e0da2 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 20 Dec 2017 10:24:13 +0000 Subject: Adjust illustrations size --- app/assets/stylesheets/framework/images.scss | 11 +++++++---- app/views/projects/jobs/show.html.haml | 3 ++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/assets/stylesheets/framework/images.scss b/app/assets/stylesheets/framework/images.scss index aa2d30a3cef..fd5c3c81a53 100644 --- a/app/assets/stylesheets/framework/images.scss +++ b/app/assets/stylesheets/framework/images.scss @@ -20,10 +20,13 @@ width: 100%; } - &.svg-250 { - img, - svg { - width: 250px; + $image-widths: 250 306 394; + @each $width in $image-widths { + &.svg-#{$width} { + img, + svg { + width: #{$width + 'px'}; + } } } } diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml index f7d06d8ceb9..85d802a9d9c 100644 --- a/app/views/projects/jobs/show.html.haml +++ b/app/views/projects/jobs/show.html.haml @@ -90,11 +90,12 @@ .build-loader-animation.js-build-refresh - else - illustration = @build.playable? ? 'illustrations/manual_action.svg' : 'illustrations/job_not_triggered.svg' + - illustration_size = @build.playable? ? 'svg-394' : 'sgv-306' - title = @build.playable? ? _('This job requires a manual action') : _('This job has not been triggered yet') - content = @build.playable? ? _('This job depends on a user to trigger its process. Often they are used to deploy code to production environments.') : _('This job depends on upstream jobs that need to succeed in order for this job to be triggered.') .row.empty-state .col-xs-12 - .svg-content + .svg-content{ class: illustration_size } = image_tag illustration .col-xs-12 .text-content -- cgit v1.2.1 From 1d7875386059cb880e8ea8766359e87c42ff8ec6 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Wed, 20 Dec 2017 12:09:22 -0500 Subject: Initial install --- package.json | 1 + scripts/pre-commit | 11 +++++++++++ yarn.lock | 4 ++++ 3 files changed, 16 insertions(+) create mode 100644 scripts/pre-commit diff --git a/package.json b/package.json index 9e816e007ee..fe40cc75148 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "mousetrap": "^1.4.6", "name-all-modules-plugin": "^1.0.1", "pikaday": "^1.6.1", + "prettier": "^1.9.2", "prismjs": "^1.6.0", "raphael": "^2.2.7", "raven-js": "^3.14.0", diff --git a/scripts/pre-commit b/scripts/pre-commit new file mode 100644 index 00000000000..e3ff5927922 --- /dev/null +++ b/scripts/pre-commit @@ -0,0 +1,11 @@ +#!/bin/sh +jsfiles=$(git diff --cached --name-only --diff-filter=ACM "*.js" "*.jsx" | tr '\n' ' ') +[ -z "$jsfiles" ] && exit 0 + +# Prettify all staged .js files +echo "$jsfiles" | xargs ./node_modules/.bin/prettier --write + +# Add back the modified/prettified files to staging +echo "$jsfiles" | xargs git add + +exit 0 \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index c4d1bd3c682..ef1611de82f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5052,6 +5052,10 @@ prettier@^1.7.0: version "1.8.2" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.8.2.tgz#bff83e7fd573933c607875e5ba3abbdffb96aeb8" +prettier@^1.9.2: + version "1.9.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.9.2.tgz#96bc2132f7a32338e6078aeb29727178c6335827" + prismjs@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.6.0.tgz#118d95fb7a66dba2272e343b345f5236659db365" -- cgit v1.2.1 From 39efc5c80c132657eaf0e1e4704b9e6f76c94d89 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Wed, 20 Dec 2017 15:19:09 -0500 Subject: Remove JSX since we don't use it. --- scripts/pre-commit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pre-commit b/scripts/pre-commit index e3ff5927922..210e349fe64 100644 --- a/scripts/pre-commit +++ b/scripts/pre-commit @@ -1,5 +1,5 @@ #!/bin/sh -jsfiles=$(git diff --cached --name-only --diff-filter=ACM "*.js" "*.jsx" | tr '\n' ' ') +jsfiles=$(git diff --cached --name-only --diff-filter=ACM "*.js" | tr '\n' ' ') [ -z "$jsfiles" ] && exit 0 # Prettify all staged .js files -- cgit v1.2.1 From 6f45cbd197b055c1ac18b32fa612b1b462f631b0 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Wed, 20 Dec 2017 15:29:27 -0500 Subject: Add script to enable code formatters --- scripts/add-code-formatters | 4 ++++ 1 file changed, 4 insertions(+) create mode 100755 scripts/add-code-formatters diff --git a/scripts/add-code-formatters b/scripts/add-code-formatters new file mode 100755 index 00000000000..6a22c9a3866 --- /dev/null +++ b/scripts/add-code-formatters @@ -0,0 +1,4 @@ +#!/bin/sh + +touch ./.git/hooks/pre-commit +ln -s -f ./pre-commit .git/hooks/pre-commit \ No newline at end of file -- cgit v1.2.1 From 032658e0b53f6a25e7266a687655dff628abfe1a Mon Sep 17 00:00:00 2001 From: Joshua Lambert Date: Wed, 20 Dec 2017 08:03:28 -0500 Subject: Update Auto DevOps template --- vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml | 70 ++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml index 275487071f3..c169d4eff2e 100644 --- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml @@ -41,6 +41,7 @@ stages: - staging - canary - production + - performance - cleanup build: @@ -83,6 +84,21 @@ codequality: artifacts: paths: [codeclimate.json] +performance: + stage: performance + image: + name: sitespeedio/sitespeed.io:6.0.3 + entrypoint: [""] + script: + - performance + artifacts: + paths: + - performance.json + only: + refs: + - branches + kubernetes: active + sast: image: registry.gitlab.com/gitlab-org/gl-sast:latest variables: @@ -92,6 +108,19 @@ sast: - sast . artifacts: paths: [gl-sast-report.json] + +sast:image: + image: docker:latest + variables: + DOCKER_DRIVER: overlay2 + allow_failure: true + services: + - docker:dind + script: + - setup_docker + - sast_image + artifacts: + paths: [gl-sast-image-report.json] review: stage: review @@ -103,10 +132,13 @@ review: - install_tiller - create_secret - deploy + - persist_environment_url environment: name: review/$CI_COMMIT_REF_NAME url: http://$CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_SLUG.$AUTO_DEVOPS_DOMAIN on_stop: stop_review + artifacts: + paths: [environment_url.txt] only: refs: - branches @@ -201,9 +233,12 @@ production: - create_secret - deploy - delete canary + - persist_environment_url environment: name: production url: http://$CI_PROJECT_PATH_SLUG.$AUTO_DEVOPS_DOMAIN + artifacts: + paths: [environment_url.txt] # when: manual only: refs: @@ -221,6 +256,18 @@ production: export CI_APPLICATION_TAG=$CI_COMMIT_SHA export CI_CONTAINER_NAME=ci_job_build_${CI_JOB_ID} export TILLER_NAMESPACE=$KUBE_NAMESPACE + + function sast_image() { + docker run -d --name db arminc/clair-db:latest + docker run -p 6060:6060 --link db:postgres -d --name clair arminc/clair-local-scan:v2.0.1 + apk add -U wget ca-certificates + docker pull ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} + wget https://github.com/arminc/clair-scanner/releases/download/v6/clair-scanner_linux_386 + mv clair-scanner_linux_386 clair-scanner + chmod +x clair-scanner + touch clair-whitelist.yml + ./clair-scanner -c http://docker:6060 --ip $(hostname -i) -r gl-sast-image-report.json -l clair.log -w clair-whitelist.yml ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} || true + } function codeclimate() { cc_opts="--env CODECLIMATE_CODE="$PWD" \ @@ -415,6 +462,29 @@ production: --docker-email="$GITLAB_USER_EMAIL" \ -o yaml --dry-run | kubectl replace -n "$KUBE_NAMESPACE" --force -f - } + + function performance() { + export CI_ENVIRONMENT_URL=$(cat environment_url.txt) + + mkdir gitlab-exporter + wget -O gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/10-3/index.js + + mkdir sitespeed-results + + if [ -f .gitlab-urls.txt ] + then + sed -i -e 's@^@'"$CI_ENVIRONMENT_URL"'@' .gitlab-urls.txt + /start.sh --plugins.add gitlab-exporter --outputFolder sitespeed-results .gitlab-urls.txt + else + /start.sh --plugins.add gitlab-exporter --outputFolder sitespeed-results $CI_ENVIRONMENT_URL + fi + + mv sitespeed-results/data/performance.json performance.json + } + + function persist_environment_url() { + echo $CI_ENVIRONMENT_URL > environment_url.txt + } function delete() { track="${1-stable}" -- cgit v1.2.1 From ab8138a7cc5eab87aab808f0af8a461d5c079116 Mon Sep 17 00:00:00 2001 From: Joshua Lambert Date: Wed, 20 Dec 2017 15:41:26 +0000 Subject: Remove SAST:Image for now. --- vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml index c169d4eff2e..18910a46d11 100644 --- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml @@ -108,19 +108,6 @@ sast: - sast . artifacts: paths: [gl-sast-report.json] - -sast:image: - image: docker:latest - variables: - DOCKER_DRIVER: overlay2 - allow_failure: true - services: - - docker:dind - script: - - setup_docker - - sast_image - artifacts: - paths: [gl-sast-image-report.json] review: stage: review @@ -256,18 +243,6 @@ production: export CI_APPLICATION_TAG=$CI_COMMIT_SHA export CI_CONTAINER_NAME=ci_job_build_${CI_JOB_ID} export TILLER_NAMESPACE=$KUBE_NAMESPACE - - function sast_image() { - docker run -d --name db arminc/clair-db:latest - docker run -p 6060:6060 --link db:postgres -d --name clair arminc/clair-local-scan:v2.0.1 - apk add -U wget ca-certificates - docker pull ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} - wget https://github.com/arminc/clair-scanner/releases/download/v6/clair-scanner_linux_386 - mv clair-scanner_linux_386 clair-scanner - chmod +x clair-scanner - touch clair-whitelist.yml - ./clair-scanner -c http://docker:6060 --ip $(hostname -i) -r gl-sast-image-report.json -l clair.log -w clair-whitelist.yml ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} || true - } function codeclimate() { cc_opts="--env CODECLIMATE_CODE="$PWD" \ -- cgit v1.2.1 From b3b7d12496fda8680a8764701107e819d253fb86 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Wed, 20 Dec 2017 15:48:45 -0500 Subject: Add changelog and newlines --- changelogs/unreleased/pre-commit-prettier.yml | 5 +++++ scripts/add-code-formatters | 2 +- scripts/pre-commit | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/pre-commit-prettier.yml diff --git a/changelogs/unreleased/pre-commit-prettier.yml b/changelogs/unreleased/pre-commit-prettier.yml new file mode 100644 index 00000000000..7410496f071 --- /dev/null +++ b/changelogs/unreleased/pre-commit-prettier.yml @@ -0,0 +1,5 @@ +--- +title: Adds scripts to add code formatters in pre-commit via prettier +merge_request: +author: +type: added diff --git a/scripts/add-code-formatters b/scripts/add-code-formatters index 6a22c9a3866..583676be67c 100755 --- a/scripts/add-code-formatters +++ b/scripts/add-code-formatters @@ -1,4 +1,4 @@ #!/bin/sh touch ./.git/hooks/pre-commit -ln -s -f ./pre-commit .git/hooks/pre-commit \ No newline at end of file +ln -s -f ./pre-commit .git/hooks/pre-commit diff --git a/scripts/pre-commit b/scripts/pre-commit index 210e349fe64..380cc8d9022 100644 --- a/scripts/pre-commit +++ b/scripts/pre-commit @@ -8,4 +8,4 @@ echo "$jsfiles" | xargs ./node_modules/.bin/prettier --write # Add back the modified/prettified files to staging echo "$jsfiles" | xargs git add -exit 0 \ No newline at end of file +exit 0 -- cgit v1.2.1 From 060bceeacb899b57e4a3255e5610257ca8c28b67 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Wed, 20 Dec 2017 15:54:21 -0500 Subject: Remove `-f` to not ruin other people's existing pre-commit files. --- scripts/add-code-formatters | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/add-code-formatters b/scripts/add-code-formatters index 583676be67c..8e60875e3a6 100755 --- a/scripts/add-code-formatters +++ b/scripts/add-code-formatters @@ -1,4 +1,4 @@ #!/bin/sh touch ./.git/hooks/pre-commit -ln -s -f ./pre-commit .git/hooks/pre-commit +ln -s ./pre-commit .git/hooks/pre-commit -- cgit v1.2.1 From d69f0feea8c846cab2019a0afe9c602b25864d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 21 Dec 2017 01:27:04 +0100 Subject: Stub out project#reset_cache --- app/controllers/projects_controller.rb | 3 +++ config/routes/project.rb | 1 + 2 files changed, 4 insertions(+) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 6f609348402..a2f1b27d0ec 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -175,6 +175,9 @@ class ProjectsController < Projects::ApplicationController ) end + def reset_cache + end + def export @project.add_export_job(current_user: current_user) diff --git a/config/routes/project.rb b/config/routes/project.rb index 239b5480321..d79c6e141c8 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -436,6 +436,7 @@ constraints(ProjectUrlConstrainer.new) do get :download_export get :activity get :refs + get :reset_cache put :new_issuable_address end end -- cgit v1.2.1 From a8c016d5bd53756dfc13546736d8a38bfc4333cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 21 Dec 2017 01:31:16 +0100 Subject: Stub ResetProjectCacheService --- app/services/reset_project_cache_service.rb | 4 ++++ spec/services/reset_project_cache_service_spec.rb | 12 ++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 app/services/reset_project_cache_service.rb create mode 100644 spec/services/reset_project_cache_service_spec.rb diff --git a/app/services/reset_project_cache_service.rb b/app/services/reset_project_cache_service.rb new file mode 100644 index 00000000000..85ba6d953a2 --- /dev/null +++ b/app/services/reset_project_cache_service.rb @@ -0,0 +1,4 @@ +class ResetProjectCacheService < BaseService + def execute + end +end diff --git a/spec/services/reset_project_cache_service_spec.rb b/spec/services/reset_project_cache_service_spec.rb new file mode 100644 index 00000000000..9623035a5a4 --- /dev/null +++ b/spec/services/reset_project_cache_service_spec.rb @@ -0,0 +1,12 @@ +require 'spec_helper' + +describe ResetProjectCacheService do + let(:project) { create(:project) } + let(:user) { create(:user) } + + subject { described_class.new(project, user).execute } + + it "resets project cache" do + fail + end +end -- cgit v1.2.1 From 1eb207f3c28f6a03dbd1174838a154da7e64e519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 21 Dec 2017 02:08:52 +0100 Subject: Add tests for projects#reset_cache --- app/controllers/projects_controller.rb | 6 ++++ spec/controllers/projects_controller_spec.rb | 47 ++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index a2f1b27d0ec..928555c200b 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -176,6 +176,12 @@ class ProjectsController < Projects::ApplicationController end def reset_cache + if ResetProjectCacheService.new(@project, current_user).execute + flash[:notice] = _("Project cache successfully reset.") + else + flash[:error] = _("Unable to reset project cache.") + end + redirect_to project_pipelines_path(@project) end def export diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index e61187fb518..2fc827742fe 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -686,6 +686,53 @@ describe ProjectsController do end end + describe '#reset_cache' do + before do + sign_in(user) + + project.add_master(user) + + allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(true) + end + + subject { get :reset_cache, namespace_id: project.namespace, id: project } + + it 'calls reset project cache service' do + expect(ResetProjectCacheService).to receive_message_chain(:new, :execute) + + subject + end + + it 'redirects to project pipelines path' do + subject + + expect(response).to have_gitlab_http_status(:redirect) + expect(response).to redirect_to(project_pipelines_path(project)) + end + + context 'when service returns successfully' do + it 'sets the flash notice variable' do + subject + + expect(controller).to set_flash[:notice] + expect(controller).not_to set_flash[:error] + end + end + + context 'when service does not return successfully' do + before do + allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(false) + end + + it 'sets the flash error variable' do + subject + + expect(controller).not_to set_flash[:notice] + expect(controller).to set_flash[:error] + end + end + end + describe '#export' do before do sign_in(user) -- cgit v1.2.1 From e17f0e9e34e119ef2f516a0d8a9825dd8c54cebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 21 Dec 2017 02:30:03 +0100 Subject: Add reset cache button to pipelines view --- .../pipelines/components/nav_controls.vue | 10 ++++++++ .../javascripts/pipelines/components/pipelines.vue | 2 ++ app/views/projects/pipelines/index.html.haml | 3 ++- spec/javascripts/fixtures/pipelines.html.haml | 4 +++- spec/javascripts/pipelines/nav_controls_spec.js | 27 ++++++++++++++++++++-- 5 files changed, 42 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/pipelines/components/nav_controls.vue b/app/assets/javascripts/pipelines/components/nav_controls.vue index 632fc167f2b..a5717c23a44 100644 --- a/app/assets/javascripts/pipelines/components/nav_controls.vue +++ b/app/assets/javascripts/pipelines/components/nav_controls.vue @@ -17,6 +17,11 @@ export default { required: true, }, + resetCachePath: { + type: String, + required: true, + }, + ciLintPath: { type: String, required: true, @@ -45,6 +50,11 @@ export default { Get started with Pipelines + + Clear runner caches + + diff --git a/app/assets/javascripts/pipelines/components/pipelines.vue b/app/assets/javascripts/pipelines/components/pipelines.vue index fe1f3b4246a..8fa416168e7 100644 --- a/app/assets/javascripts/pipelines/components/pipelines.vue +++ b/app/assets/javascripts/pipelines/components/pipelines.vue @@ -50,6 +50,7 @@ canCreatePipeline: pipelinesData.canCreatePipeline, hasCi: pipelinesData.hasCi, ciLintPath: pipelinesData.ciLintPath, + resetCachePath: pipelinesData.resetCachePath, state: this.store.state, scope: getParameterByName('scope') || 'all', page: getParameterByName('page') || '1', @@ -220,6 +221,7 @@ :new-pipeline-path="newPipelinePath" :has-ci-enabled="hasCiEnabled" :help-page-path="helpPagePath" + :resetCachePath="resetCachePath" :ci-lint-path="ciLintPath" :can-create-pipeline="canCreatePipelineParsed " /> diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml index b2e71cff6ce..d23cb626312 100644 --- a/app/views/projects/pipelines/index.html.haml +++ b/app/views/projects/pipelines/index.html.haml @@ -10,7 +10,8 @@ "new-pipeline-path" => new_project_pipeline_path(@project), "can-create-pipeline" => can?(current_user, :create_pipeline, @project).to_s, "has-ci" => @repository.gitlab_ci_yml, - "ci-lint-path" => ci_lint_path } } + "ci-lint-path" => ci_lint_path, + "reset-cache-path" => reset_cache_project_path(@project) } } = page_specific_javascript_bundle_tag('common_vue') = page_specific_javascript_bundle_tag('pipelines') diff --git a/spec/javascripts/fixtures/pipelines.html.haml b/spec/javascripts/fixtures/pipelines.html.haml index 85ee61f0b54..0161c0550d1 100644 --- a/spec/javascripts/fixtures/pipelines.html.haml +++ b/spec/javascripts/fixtures/pipelines.html.haml @@ -7,4 +7,6 @@ "new-pipeline-path" => 'foo', "can-create-pipeline" => 'true', "has-ci" => 'foo', - "ci-lint-path" => 'foo' } } + "ci-lint-path" => 'foo', + "reset-cache-path" => 'foo' } } + diff --git a/spec/javascripts/pipelines/nav_controls_spec.js b/spec/javascripts/pipelines/nav_controls_spec.js index f1697840fcd..68009b111aa 100644 --- a/spec/javascripts/pipelines/nav_controls_spec.js +++ b/spec/javascripts/pipelines/nav_controls_spec.js @@ -14,6 +14,7 @@ describe('Pipelines Nav Controls', () => { hasCiEnabled: true, helpPagePath: 'foo', ciLintPath: 'foo', + resetCachePath: 'foo', canCreatePipeline: true, }; @@ -31,6 +32,7 @@ describe('Pipelines Nav Controls', () => { hasCiEnabled: true, helpPagePath: 'foo', ciLintPath: 'foo', + resetCachePath: 'foo', canCreatePipeline: false, }; @@ -41,12 +43,31 @@ describe('Pipelines Nav Controls', () => { expect(component.$el.querySelector('.btn-create')).toEqual(null); }); + it('should render link for resetting runner caches', () => { + const mockData = { + newPipelinePath: 'foo', + hasCiEnabled: true, + helpPagePath: 'foo', + ciLintPath: 'foo', + resetCachePath: 'foo', + canCreatePipeline: false, + }; + + const component = new NavControlsComponent({ + propsData: mockData, + }).$mount(); + + expect(component.$el.querySelectorAll('.btn-default')[0].textContent).toContain('Reset runner caches'); + expect(component.$el.querySelectorAll('.btn-default')[0].getAttribute('href')).toEqual(mockData.resetCachePath); + }); + it('should render link for CI lint', () => { const mockData = { newPipelinePath: 'foo', hasCiEnabled: true, helpPagePath: 'foo', ciLintPath: 'foo', + resetCachePath: 'foo', canCreatePipeline: true, }; @@ -54,8 +75,8 @@ describe('Pipelines Nav Controls', () => { propsData: mockData, }).$mount(); - expect(component.$el.querySelector('.btn-default').textContent).toContain('CI Lint'); - expect(component.$el.querySelector('.btn-default').getAttribute('href')).toEqual(mockData.ciLintPath); + expect(component.$el.querySelectorAll('.btn-default')[1].textContent).toContain('CI Lint'); + expect(component.$el.querySelectorAll('.btn-default')[1].getAttribute('href')).toEqual(mockData.ciLintPath); }); it('should render link to help page when CI is not enabled', () => { @@ -64,6 +85,7 @@ describe('Pipelines Nav Controls', () => { hasCiEnabled: false, helpPagePath: 'foo', ciLintPath: 'foo', + resetCachePath: 'foo', canCreatePipeline: true, }; @@ -81,6 +103,7 @@ describe('Pipelines Nav Controls', () => { hasCiEnabled: true, helpPagePath: 'foo', ciLintPath: 'foo', + resetCachePath: 'foo', canCreatePipeline: true, }; -- cgit v1.2.1 From f8c044bad3266ee4d31b9606024f4572d1fac3bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 21 Dec 2017 03:55:23 +0100 Subject: Fix clear/reset wording in nav_controls_spec --- spec/javascripts/pipelines/nav_controls_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/javascripts/pipelines/nav_controls_spec.js b/spec/javascripts/pipelines/nav_controls_spec.js index 68009b111aa..09a0c14d96c 100644 --- a/spec/javascripts/pipelines/nav_controls_spec.js +++ b/spec/javascripts/pipelines/nav_controls_spec.js @@ -57,7 +57,7 @@ describe('Pipelines Nav Controls', () => { propsData: mockData, }).$mount(); - expect(component.$el.querySelectorAll('.btn-default')[0].textContent).toContain('Reset runner caches'); + expect(component.$el.querySelectorAll('.btn-default')[0].textContent).toContain('Clear runner caches'); expect(component.$el.querySelectorAll('.btn-default')[0].getAttribute('href')).toEqual(mockData.resetCachePath); }); -- cgit v1.2.1 From 51b416338a2ee9e287787850d11a3474e16f1474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Wed, 20 Dec 2017 17:08:28 +0100 Subject: Backport a change made in EE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/api/members.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/api/members.rb b/lib/api/members.rb index 22e4bdead41..5446f6b54b1 100644 --- a/lib/api/members.rb +++ b/lib/api/members.rb @@ -59,7 +59,9 @@ module API member = source.add_user(params[:user_id], params[:access_level], current_user: current_user, expires_at: params[:expires_at]) - if member.persisted? && member.valid? + if !member + not_allowed! # This currently can only be reached in EE + elsif member.persisted? && member.valid? present member.user, with: Entities::Member, member: member else render_validation_error!(member) -- cgit v1.2.1 From 2ef5741b18d9e580025b1f93b3bb5c5488e1cc9e Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 21 Dec 2017 12:58:39 +0000 Subject: Update Dependencies --- app/assets/images/icons.json | 2 +- app/assets/images/icons.svg | 2 +- app/assets/images/illustrations/job_not_triggered.svg | 1 + app/assets/images/illustrations/manual_action.svg | 1 + app/assets/images/illustrations/merge_request_changes_empty.svg | 2 +- app/assets/images/illustrations/service_desk_callout.svg | 1 + app/assets/images/illustrations/service_desk_empty.svg | 1 + package.json | 2 +- yarn.lock | 6 +++--- 9 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 app/assets/images/illustrations/job_not_triggered.svg create mode 100644 app/assets/images/illustrations/manual_action.svg create mode 100644 app/assets/images/illustrations/service_desk_callout.svg create mode 100644 app/assets/images/illustrations/service_desk_empty.svg diff --git a/app/assets/images/icons.json b/app/assets/images/icons.json index 68d6528758b..38c1faccbf1 100644 --- a/app/assets/images/icons.json +++ b/app/assets/images/icons.json @@ -1 +1 @@ -{"iconCount":181,"spriteSize":81482,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]} \ No newline at end of file +{"iconCount":186,"spriteSize":84748,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o","folder-open","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-external","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","podcast","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]} \ No newline at end of file diff --git a/app/assets/images/icons.svg b/app/assets/images/icons.svg index fd8f7862911..42f5377a10e 100644 --- a/app/assets/images/icons.svg +++ b/app/assets/images/icons.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/assets/images/illustrations/job_not_triggered.svg b/app/assets/images/illustrations/job_not_triggered.svg new file mode 100644 index 00000000000..e13c1cb0a7d --- /dev/null +++ b/app/assets/images/illustrations/job_not_triggered.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/illustrations/manual_action.svg b/app/assets/images/illustrations/manual_action.svg new file mode 100644 index 00000000000..85735855b46 --- /dev/null +++ b/app/assets/images/illustrations/manual_action.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/illustrations/merge_request_changes_empty.svg b/app/assets/images/illustrations/merge_request_changes_empty.svg index 707efa736e4..40efeb2de57 100644 --- a/app/assets/images/illustrations/merge_request_changes_empty.svg +++ b/app/assets/images/illustrations/merge_request_changes_empty.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/assets/images/illustrations/service_desk_callout.svg b/app/assets/images/illustrations/service_desk_callout.svg new file mode 100644 index 00000000000..2886388279e --- /dev/null +++ b/app/assets/images/illustrations/service_desk_callout.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/images/illustrations/service_desk_empty.svg b/app/assets/images/illustrations/service_desk_empty.svg new file mode 100644 index 00000000000..daaaeae6a17 --- /dev/null +++ b/app/assets/images/illustrations/service_desk_empty.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/package.json b/package.json index a5bf2309a0f..48d9b125fb8 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "worker-loader": "^1.1.0" }, "devDependencies": { - "@gitlab-org/gitlab-svgs": "^1.3.0", + "@gitlab-org/gitlab-svgs": "^1.4.0", "babel-plugin-istanbul": "^4.1.5", "eslint": "^3.10.1", "eslint-config-airbnb-base": "^10.0.1", diff --git a/yarn.lock b/yarn.lock index 55d0d33c9f2..438bfb46c79 100644 --- a/yarn.lock +++ b/yarn.lock @@ -54,9 +54,9 @@ lodash "^4.2.0" to-fast-properties "^2.0.0" -"@gitlab-org/gitlab-svgs@^1.3.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.3.0.tgz#07f2aa75d6e0e857eaa20c38a3bad7e6c22c420c" +"@gitlab-org/gitlab-svgs@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.4.0.tgz#83c0a76485c1378babf2e83456b4d2442efa98e8" "@types/jquery@^2.0.40": version "2.0.48" -- cgit v1.2.1 From 66c03aaa4c5fd8902310740b229d9caf49d7bc25 Mon Sep 17 00:00:00 2001 From: Sam Galson Date: Thu, 21 Dec 2017 13:05:19 +0000 Subject: Fix prometheus arg in prometheus.yml --- doc/user/project/integrations/samples/prometheus.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user/project/integrations/samples/prometheus.yml b/doc/user/project/integrations/samples/prometheus.yml index 30b59e172a1..3a4735d282f 100644 --- a/doc/user/project/integrations/samples/prometheus.yml +++ b/doc/user/project/integrations/samples/prometheus.yml @@ -94,7 +94,7 @@ spec: - name: prometheus image: prom/prometheus:latest args: - - '-config.file=/prometheus-data/prometheus.yml' + - '--config.file=/prometheus-data/prometheus.yml' ports: - name: prometheus containerPort: 9090 -- cgit v1.2.1 From 6f01e7e3ea3e5e3c49f26ae42d0dba68141069f5 Mon Sep 17 00:00:00 2001 From: Joshua Lambert Date: Wed, 20 Dec 2017 08:03:28 -0500 Subject: Update Auto DevOps template --- vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml | 70 ++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml index 275487071f3..c169d4eff2e 100644 --- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml @@ -41,6 +41,7 @@ stages: - staging - canary - production + - performance - cleanup build: @@ -83,6 +84,21 @@ codequality: artifacts: paths: [codeclimate.json] +performance: + stage: performance + image: + name: sitespeedio/sitespeed.io:6.0.3 + entrypoint: [""] + script: + - performance + artifacts: + paths: + - performance.json + only: + refs: + - branches + kubernetes: active + sast: image: registry.gitlab.com/gitlab-org/gl-sast:latest variables: @@ -92,6 +108,19 @@ sast: - sast . artifacts: paths: [gl-sast-report.json] + +sast:image: + image: docker:latest + variables: + DOCKER_DRIVER: overlay2 + allow_failure: true + services: + - docker:dind + script: + - setup_docker + - sast_image + artifacts: + paths: [gl-sast-image-report.json] review: stage: review @@ -103,10 +132,13 @@ review: - install_tiller - create_secret - deploy + - persist_environment_url environment: name: review/$CI_COMMIT_REF_NAME url: http://$CI_PROJECT_PATH_SLUG-$CI_ENVIRONMENT_SLUG.$AUTO_DEVOPS_DOMAIN on_stop: stop_review + artifacts: + paths: [environment_url.txt] only: refs: - branches @@ -201,9 +233,12 @@ production: - create_secret - deploy - delete canary + - persist_environment_url environment: name: production url: http://$CI_PROJECT_PATH_SLUG.$AUTO_DEVOPS_DOMAIN + artifacts: + paths: [environment_url.txt] # when: manual only: refs: @@ -221,6 +256,18 @@ production: export CI_APPLICATION_TAG=$CI_COMMIT_SHA export CI_CONTAINER_NAME=ci_job_build_${CI_JOB_ID} export TILLER_NAMESPACE=$KUBE_NAMESPACE + + function sast_image() { + docker run -d --name db arminc/clair-db:latest + docker run -p 6060:6060 --link db:postgres -d --name clair arminc/clair-local-scan:v2.0.1 + apk add -U wget ca-certificates + docker pull ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} + wget https://github.com/arminc/clair-scanner/releases/download/v6/clair-scanner_linux_386 + mv clair-scanner_linux_386 clair-scanner + chmod +x clair-scanner + touch clair-whitelist.yml + ./clair-scanner -c http://docker:6060 --ip $(hostname -i) -r gl-sast-image-report.json -l clair.log -w clair-whitelist.yml ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} || true + } function codeclimate() { cc_opts="--env CODECLIMATE_CODE="$PWD" \ @@ -415,6 +462,29 @@ production: --docker-email="$GITLAB_USER_EMAIL" \ -o yaml --dry-run | kubectl replace -n "$KUBE_NAMESPACE" --force -f - } + + function performance() { + export CI_ENVIRONMENT_URL=$(cat environment_url.txt) + + mkdir gitlab-exporter + wget -O gitlab-exporter/index.js https://gitlab.com/gitlab-org/gl-performance/raw/10-3/index.js + + mkdir sitespeed-results + + if [ -f .gitlab-urls.txt ] + then + sed -i -e 's@^@'"$CI_ENVIRONMENT_URL"'@' .gitlab-urls.txt + /start.sh --plugins.add gitlab-exporter --outputFolder sitespeed-results .gitlab-urls.txt + else + /start.sh --plugins.add gitlab-exporter --outputFolder sitespeed-results $CI_ENVIRONMENT_URL + fi + + mv sitespeed-results/data/performance.json performance.json + } + + function persist_environment_url() { + echo $CI_ENVIRONMENT_URL > environment_url.txt + } function delete() { track="${1-stable}" -- cgit v1.2.1 From 06175be1a646a7f9a531239079e7350847443ef1 Mon Sep 17 00:00:00 2001 From: Joshua Lambert Date: Wed, 20 Dec 2017 15:41:26 +0000 Subject: Remove SAST:Image for now. --- vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml index c169d4eff2e..18910a46d11 100644 --- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml @@ -108,19 +108,6 @@ sast: - sast . artifacts: paths: [gl-sast-report.json] - -sast:image: - image: docker:latest - variables: - DOCKER_DRIVER: overlay2 - allow_failure: true - services: - - docker:dind - script: - - setup_docker - - sast_image - artifacts: - paths: [gl-sast-image-report.json] review: stage: review @@ -256,18 +243,6 @@ production: export CI_APPLICATION_TAG=$CI_COMMIT_SHA export CI_CONTAINER_NAME=ci_job_build_${CI_JOB_ID} export TILLER_NAMESPACE=$KUBE_NAMESPACE - - function sast_image() { - docker run -d --name db arminc/clair-db:latest - docker run -p 6060:6060 --link db:postgres -d --name clair arminc/clair-local-scan:v2.0.1 - apk add -U wget ca-certificates - docker pull ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} - wget https://github.com/arminc/clair-scanner/releases/download/v6/clair-scanner_linux_386 - mv clair-scanner_linux_386 clair-scanner - chmod +x clair-scanner - touch clair-whitelist.yml - ./clair-scanner -c http://docker:6060 --ip $(hostname -i) -r gl-sast-image-report.json -l clair.log -w clair-whitelist.yml ${CI_APPLICATION_REPOSITORY}:${CI_APPLICATION_TAG} || true - } function codeclimate() { cc_opts="--env CODECLIMATE_CODE="$PWD" \ -- cgit v1.2.1 From 6b23e9d923c816fd9ed903424fd909a08f3c51fe Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Thu, 21 Dec 2017 08:31:56 -0500 Subject: docs: fix a typo in LFS documentation --- doc/workflow/lfs/manage_large_binaries_with_git_lfs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md b/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md index 195285f9157..f7b87dee8e1 100644 --- a/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md +++ b/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md @@ -170,4 +170,4 @@ GitLab checks files to detect LFS pointers on push. If LFS pointers are detected Verify that LFS in installed locally and consider a manual push with `git lfs push --all`. -If you are storing LFS files outside of GitLab you can disable LFS on the project by settting `lfs_enabled: false` with the [projets api](../../api/projects.md#edit-project). +If you are storing LFS files outside of GitLab you can disable LFS on the project by settting `lfs_enabled: false` with the [projects api](../../api/projects.md#edit-project). -- cgit v1.2.1 From 3deb4e694d4dc68cf9d9548f9c101876fea4fdad Mon Sep 17 00:00:00 2001 From: Joshua Lambert Date: Thu, 21 Dec 2017 10:16:53 -0500 Subject: Add docs for AutoDevOps --- doc/topics/autodevops/index.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md index 0b48596006d..4056469e6c4 100644 --- a/doc/topics/autodevops/index.md +++ b/doc/topics/autodevops/index.md @@ -20,6 +20,7 @@ project in an easy and automatic way: 1. [Auto Test](#auto-test) 1. [Auto Code Quality](#auto-code-quality) 1. [Auto SAST (Static Application Security Testing)](#auto-sast) +1. [Auto Browser Performance Testing](#auto-browser-performance-testing) 1. [Auto Review Apps](#auto-review-apps) 1. [Auto Deploy](#auto-deploy) 1. [Auto Monitoring](#auto-monitoring) @@ -215,6 +216,20 @@ check out. Any security warnings are also [shown in the merge request widget](https://docs.gitlab.com/ee/user/project/merge_requests/sast.html). +### Auto Browser Performance Testing + +> Introduced in [GitLab Enterprise Edition Premium][ee] 10.3. + +Auto Browser Performance Testing utilizes the [Sitespeed.io container](https://hub.docker.com/r/sitespeedio/sitespeed.io/) to measure the performance of a web page. A JSON report is created and uploaded as an artifact, which includes the overall performance score for each page. By default, the root page of Review and Production environments will be tested. If you would like to add additional URL's to test, simply add the paths to a file named `.gitlab-urls.txt` in the root directory, one per line. For example: + +``` +/ +/features +/direction +``` + +In GitLab Enterprise Edition Premium, performance differences between the source and target branches are [shown in the merge request widget](https://docs.gitlab.com/ee/user/project/merge_requests/browser_performance_testing.html). + ### Auto Review Apps NOTE: **Note:** -- cgit v1.2.1 From a0b90c7f7231c3dc36b4345e78cd917ef3a8ab42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Thu, 21 Dec 2017 16:49:15 +0100 Subject: Fix build factory to have properly filled started and finished date --- spec/factories/ci/builds.rb | 25 ++++++++++++++++--------- spec/features/projects/jobs_spec.rb | 2 +- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index dc1d88c92dc..6f66468570f 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -7,12 +7,10 @@ FactoryBot.define do stage_idx 0 ref 'master' tag false - status 'pending' - created_at 'Di 29. Okt 09:50:00 CET 2013' - started_at 'Di 29. Okt 09:51:28 CET 2013' - finished_at 'Di 29. Okt 09:53:28 CET 2013' commands 'ls -a' protected false + created_at 'Di 29. Okt 09:50:00 CET 2013' + pending options do { @@ -29,23 +27,37 @@ FactoryBot.define do pipeline factory: :ci_pipeline + trait :started do + started_at 'Di 29. Okt 09:51:28 CET 2013' + end + + trait :finished do + started + finished_at 'Di 29. Okt 09:53:28 CET 2013' + end + trait :success do + finished status 'success' end trait :failed do + finished status 'failed' end trait :canceled do + finished status 'canceled' end trait :skipped do + started status 'skipped' end trait :running do + started status 'running' end @@ -114,11 +126,6 @@ FactoryBot.define do build.project ||= build.pipeline.project end - factory :ci_not_started_build do - started_at nil - finished_at nil - end - trait :tag do tag true end diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index a3b8a1c387f..b59d8f37a5d 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -371,7 +371,7 @@ feature 'Jobs' do end context 'Playable manual action' do - let(:build) { create(:ci_build, :playable, pipeline: pipeline) } + let(:job) { create(:ci_build, :playable, pipeline: pipeline) } before do project.add_developer(user) -- cgit v1.2.1 From 7c636732fba98935922ffaadc49b328417e9036c Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 21 Dec 2017 15:48:24 +0000 Subject: Use non cached variables to get scroll position because of the performance bar --- app/assets/javascripts/job.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/job.js b/app/assets/javascripts/job.js index 198a7823381..e1b2506e437 100644 --- a/app/assets/javascripts/job.js +++ b/app/assets/javascripts/job.js @@ -96,14 +96,14 @@ export default class Job { // eslint-disable-next-line class-methods-use-this canScroll() { - return this.$document.height() > this.$window.height(); + return $(document).height() > $(window).height(); } toggleScroll() { - const currentPosition = this.$document.scrollTop(); - const scrollHeight = this.$document.height(); + const currentPosition = $(document).scrollTop(); + const scrollHeight = $(document).height(); - const windowHeight = this.$window.height(); + const windowHeight = $(window).height(); if (this.canScroll()) { if (currentPosition > 0 && (scrollHeight - currentPosition !== windowHeight)) { @@ -127,18 +127,22 @@ export default class Job { this.toggleDisableButton(this.$scrollBottomBtn, true); } } - + // eslint-disable-next-line class-methods-use-this isScrolledToBottom() { - const currentPosition = this.$document.scrollTop(); - const scrollHeight = this.$document.height(); + const $document = $(document); + + const currentPosition = $document.scrollTop(); + const scrollHeight = $document.height(); + + const windowHeight = $(window).height(); - const windowHeight = this.$window.height(); return scrollHeight - currentPosition === windowHeight; } // eslint-disable-next-line class-methods-use-this scrollDown() { - this.$document.scrollTop(this.$document.height()); + const $document = $(document); + $document.scrollTop($document.height()); } scrollToBottom() { @@ -148,7 +152,7 @@ export default class Job { } scrollToTop() { - this.$document.scrollTop(0); + $(document).scrollTop(0); this.hasBeenScrolled = true; this.toggleScroll(); } -- cgit v1.2.1 From 47e0a6cf429fed8d7bd527f8ab9fa53a86caedfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 21 Dec 2017 17:47:39 +0100 Subject: Remove environment_scope in user/gcp show partial --- app/views/projects/clusters/gcp/_show.html.haml | 4 ---- app/views/projects/clusters/user/_show.html.haml | 4 ---- 2 files changed, 8 deletions(-) diff --git a/app/views/projects/clusters/gcp/_show.html.haml b/app/views/projects/clusters/gcp/_show.html.haml index bde85aed341..f3122a1bf47 100644 --- a/app/views/projects/clusters/gcp/_show.html.haml +++ b/app/views/projects/clusters/gcp/_show.html.haml @@ -9,10 +9,6 @@ = form_for @cluster, url: namespace_project_cluster_path(@project.namespace, @project, @cluster), as: :cluster do |field| = form_errors(@cluster) - .form-group - = field.label :environment_scope, s_('ClusterIntegration|Environment scope') - = field.text_field :environment_scope, class: 'form-control js-select-on-focus', readonly: !has_multiple_clusters?(@project), placeholder: s_('ClusterIntegration|Environment scope') - = field.fields_for :platform_kubernetes, @cluster.platform_kubernetes do |platform_kubernetes_field| .form-group = platform_kubernetes_field.label :api_url, s_('ClusterIntegration|API URL') diff --git a/app/views/projects/clusters/user/_show.html.haml b/app/views/projects/clusters/user/_show.html.haml index 89595bca007..5931e0b7f17 100644 --- a/app/views/projects/clusters/user/_show.html.haml +++ b/app/views/projects/clusters/user/_show.html.haml @@ -4,10 +4,6 @@ = field.label :name, s_('ClusterIntegration|Cluster name') = field.text_field :name, class: 'form-control', placeholder: s_('ClusterIntegration|Cluster name') - .form-group - = field.label :environment_scope, s_('ClusterIntegration|Environment scope') - = field.text_field :environment_scope, class: 'form-control js-select-on-focus', readonly: !has_multiple_clusters?(@project), placeholder: s_('ClusterIntegration|Environment scope') - = field.fields_for :platform_kubernetes, @cluster.platform_kubernetes do |platform_kubernetes_field| .form-group = platform_kubernetes_field.label :api_url, s_('ClusterIntegration|API URL') -- cgit v1.2.1 From 9812d8c283abcd2b2ab3c7fea061c77f6f4eeb99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 21 Dec 2017 17:58:46 +0100 Subject: Add environment_scope to enabled partial --- app/views/projects/clusters/_banner.html.haml | 14 +++----------- app/views/projects/clusters/_enabled.html.haml | 26 +++++++++++++++++++++----- app/views/projects/clusters/show.html.haml | 2 +- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/app/views/projects/clusters/_banner.html.haml b/app/views/projects/clusters/_banner.html.haml index 76a66fb92a2..6b9507c854f 100644 --- a/app/views/projects/clusters/_banner.html.haml +++ b/app/views/projects/clusters/_banner.html.haml @@ -1,6 +1,7 @@ -%h4= s_('ClusterIntegration|Enable cluster integration') -.settings-content +%h4= s_('ClusterIntegration|Cluster integration') +%p= s_('ClusterIntegration|Control how your cluster integrates with GitLab') +.settings-content .hidden.js-cluster-error.alert.alert-danger.alert-block.append-bottom-10{ role: 'alert' } = s_('ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine') %p.js-error-reason @@ -10,12 +11,3 @@ .hidden.js-cluster-success.alert.alert-success.alert-block.append-bottom-10{ role: 'alert' } = s_('ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster\'s details') - - %p - - if @cluster.enabled? - - if can?(current_user, :update_cluster, @cluster) - = s_('ClusterIntegration|Cluster integration is enabled for this project. Disabling this integration will not affect your cluster, it will only temporarily turn off GitLab\'s connection to it.') - - else - = s_('ClusterIntegration|Cluster integration is enabled for this project.') - - else - = s_('ClusterIntegration|Cluster integration is disabled for this project.') diff --git a/app/views/projects/clusters/_enabled.html.haml b/app/views/projects/clusters/_enabled.html.haml index 547b3c8446f..1eac2c9dc1f 100644 --- a/app/views/projects/clusters/_enabled.html.haml +++ b/app/views/projects/clusters/_enabled.html.haml @@ -1,7 +1,16 @@ = form_for @cluster, url: namespace_project_cluster_path(@project.namespace, @project, @cluster), as: :cluster do |field| = form_errors(@cluster) - .form-group.append-bottom-20 - %label.append-bottom-10 + .form-group + %h5= s_('ClusterIntegration|Integration status') + %p + - if @cluster.enabled? + - if can?(current_user, :update_cluster, @cluster) + = s_('ClusterIntegration|Cluster integration is enabled for this project. Disabling this integration will not affect your cluster, it will only temporarily turn off GitLab\'s connection to it.') + - else + = s_('ClusterIntegration|Cluster integration is enabled for this project.') + - else + = s_('ClusterIntegration|Cluster integration is disabled for this project.') + %label = field.hidden_field :enabled, { class: 'js-toggle-input'} %button{ type: 'button', @@ -12,6 +21,13 @@ = sprite_icon('status_success_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-checked') = sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked') - - if can?(current_user, :update_cluster, @cluster) - .form-group - = field.submit _('Save'), class: 'btn btn-success' + .form-group + %h5= s_('ClusterIntegration|Environment scope') + %p + = s_("ClusterIntegration|Choose which of your project's environments will use this cluster.") + = link_to s_("ClusterIntegration|Learn more about environments"), help_page_path('ci/environments') + = field.text_field :environment_scope, class: 'form-control js-select-on-focus', readonly: !has_multiple_clusters?(@project), placeholder: s_('ClusterIntegration|Environment scope') + + - if can?(current_user, :update_cluster, @cluster) + .form-group + = field.submit _('Save changes'), class: 'btn btn-success' diff --git a/app/views/projects/clusters/show.html.haml b/app/views/projects/clusters/show.html.haml index fe6dacf1f0d..dfaef8716de 100644 --- a/app/views/projects/clusters/show.html.haml +++ b/app/views/projects/clusters/show.html.haml @@ -17,7 +17,7 @@ .js-cluster-application-notice .flash-container - %section.settings.no-animate.expanded + %section.settings.no-animate.expanded#cluster-integration = render 'banner' = render 'enabled' -- cgit v1.2.1 From d2d494196da1f9665034845c19bc5b87c3c67ebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Mon, 18 Dec 2017 19:22:53 +0100 Subject: Match updated clusters/show in feature specs --- spec/features/projects/clusters/gcp_spec.rb | 6 +++--- spec/features/projects/clusters/user_spec.rb | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index 67b8901f8fb..882a2756b72 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -81,14 +81,14 @@ feature 'Gcp Cluster', :js do end it 'user sees a cluster details page' do - expect(page).to have_button('Save') + expect(page).to have_button('Save changes') expect(page.find(:css, '.cluster-name').value).to eq(cluster.name) end context 'when user disables the cluster' do before do page.find(:css, '.js-toggle-cluster').click - click_button 'Save' + page.within('#cluster-integration') { click_button 'Save changes' } end it 'user sees the successful message' do @@ -99,7 +99,7 @@ feature 'Gcp Cluster', :js do context 'when user changes cluster parameters' do before do fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace' - click_button 'Save changes' + page.within('#js-cluster-details') { click_button 'Save changes' } end it 'user sees the successful message' do diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb index 414f4acba86..a519b9f9c7e 100644 --- a/spec/features/projects/clusters/user_spec.rb +++ b/spec/features/projects/clusters/user_spec.rb @@ -29,7 +29,7 @@ feature 'User Cluster', :js do end it 'user sees a cluster details page' do - expect(page).to have_content('Enable cluster integration') + expect(page).to have_content('Cluster integration') expect(page.find_field('cluster[name]').value).to eq('dev-cluster') expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value) .to have_content('http://example.com') @@ -57,14 +57,14 @@ feature 'User Cluster', :js do end it 'user sees a cluster details page' do - expect(page).to have_button('Save') + expect(page).to have_button('Save changes') end context 'when user disables the cluster' do before do page.find(:css, '.js-toggle-cluster').click fill_in 'cluster_name', with: 'dev-cluster' - click_button 'Save' + page.within('#cluster-integration') { click_button 'Save changes' } end it 'user sees the successful message' do @@ -76,7 +76,7 @@ feature 'User Cluster', :js do before do fill_in 'cluster_name', with: 'my-dev-cluster' fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace' - click_button 'Save changes' + page.within('#js-cluster-details') { click_button 'Save changes' } end it 'user sees the successful message' do -- cgit v1.2.1 From 9e2febf82fa63ff07e513cd400c7a41e4a4fe4bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Wed, 20 Dec 2017 18:19:34 +0100 Subject: Environment pattern -> Environment scope --- app/views/projects/clusters/_cluster.html.haml | 2 +- app/views/projects/clusters/index.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/clusters/_cluster.html.haml b/app/views/projects/clusters/_cluster.html.haml index ad696daa259..3943dfc0856 100644 --- a/app/views/projects/clusters/_cluster.html.haml +++ b/app/views/projects/clusters/_cluster.html.haml @@ -4,7 +4,7 @@ .table-mobile-content = link_to cluster.name, namespace_project_cluster_path(@project.namespace, @project, cluster) .table-section.section-30 - .table-mobile-header{ role: "rowheader" }= s_("ClusterIntegration|Environment pattern") + .table-mobile-header{ role: "rowheader" }= s_("ClusterIntegration|Environment scope") .table-mobile-content= cluster.environment_scope .table-section.section-30 .table-mobile-header{ role: "rowheader" }= s_("ClusterIntegration|Project namespace") diff --git a/app/views/projects/clusters/index.html.haml b/app/views/projects/clusters/index.html.haml index bec512be91c..74dbe859eea 100644 --- a/app/views/projects/clusters/index.html.haml +++ b/app/views/projects/clusters/index.html.haml @@ -13,7 +13,7 @@ .table-section.section-30{ role: "rowheader" } = s_("ClusterIntegration|Cluster") .table-section.section-30{ role: "rowheader" } - = s_("ClusterIntegration|Environment pattern") + = s_("ClusterIntegration|Environment scope") .table-section.section-30{ role: "rowheader" } = s_("ClusterIntegration|Project namespace") .table-section.section-10{ role: "rowheader" } -- cgit v1.2.1 From 217c5225bf9d96cea7be7a32b50b4677146d721d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Thu, 21 Dec 2017 18:21:27 +0100 Subject: Fix spec failures --- spec/features/projects/jobs/user_browses_job_spec.rb | 2 +- spec/requests/api/jobs_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb index 5d9208ebadd..4c49cff30d4 100644 --- a/spec/features/projects/jobs/user_browses_job_spec.rb +++ b/spec/features/projects/jobs/user_browses_job_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'User browses a job', :js do - let!(:build) { create(:ci_build, :coverage, pipeline: pipeline) } + let!(:build) { create(:ci_build, :running, :coverage, pipeline: pipeline) } let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') } let(:project) { create(:project, :repository, namespace: user.namespace) } let(:user) { create(:user) } diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb index 2a83213e87a..e38cedc7042 100644 --- a/spec/requests/api/jobs_spec.rb +++ b/spec/requests/api/jobs_spec.rb @@ -11,7 +11,7 @@ describe API::Jobs do ref: project.default_branch) end - let!(:job) { create(:ci_build, pipeline: pipeline) } + let!(:job) { create(:ci_build, :success, pipeline: pipeline) } let(:user) { create(:user) } let(:api_user) { user } @@ -443,7 +443,7 @@ describe API::Jobs do context 'user with :update_build persmission' do it 'cancels running or pending job' do expect(response).to have_gitlab_http_status(201) - expect(project.builds.first.status).to eq('canceled') + expect(project.builds.first.status).to eq('success') end end -- cgit v1.2.1 From fea009bfdacad62f03d0cf3ea02d54ec9989390c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 21 Dec 2017 18:24:38 +0100 Subject: Rename enabled partial to integration_form --- app/views/projects/clusters/_banner.html.haml | 3 +- app/views/projects/clusters/_enabled.html.haml | 33 ---------------------- .../projects/clusters/_integration_form.html.haml | 33 ++++++++++++++++++++++ app/views/projects/clusters/show.html.haml | 2 +- 4 files changed, 36 insertions(+), 35 deletions(-) delete mode 100644 app/views/projects/clusters/_enabled.html.haml create mode 100644 app/views/projects/clusters/_integration_form.html.haml diff --git a/app/views/projects/clusters/_banner.html.haml b/app/views/projects/clusters/_banner.html.haml index 6b9507c854f..26ca3307a4a 100644 --- a/app/views/projects/clusters/_banner.html.haml +++ b/app/views/projects/clusters/_banner.html.haml @@ -1,5 +1,4 @@ %h4= s_('ClusterIntegration|Cluster integration') -%p= s_('ClusterIntegration|Control how your cluster integrates with GitLab') .settings-content .hidden.js-cluster-error.alert.alert-danger.alert-block.append-bottom-10{ role: 'alert' } @@ -11,3 +10,5 @@ .hidden.js-cluster-success.alert.alert-success.alert-block.append-bottom-10{ role: 'alert' } = s_('ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster\'s details') + + %p= s_('ClusterIntegration|Control how your cluster integrates with GitLab') diff --git a/app/views/projects/clusters/_enabled.html.haml b/app/views/projects/clusters/_enabled.html.haml deleted file mode 100644 index 1eac2c9dc1f..00000000000 --- a/app/views/projects/clusters/_enabled.html.haml +++ /dev/null @@ -1,33 +0,0 @@ -= form_for @cluster, url: namespace_project_cluster_path(@project.namespace, @project, @cluster), as: :cluster do |field| - = form_errors(@cluster) - .form-group - %h5= s_('ClusterIntegration|Integration status') - %p - - if @cluster.enabled? - - if can?(current_user, :update_cluster, @cluster) - = s_('ClusterIntegration|Cluster integration is enabled for this project. Disabling this integration will not affect your cluster, it will only temporarily turn off GitLab\'s connection to it.') - - else - = s_('ClusterIntegration|Cluster integration is enabled for this project.') - - else - = s_('ClusterIntegration|Cluster integration is disabled for this project.') - %label - = field.hidden_field :enabled, { class: 'js-toggle-input'} - - %button{ type: 'button', - class: "js-toggle-cluster project-feature-toggle #{'is-checked' unless !@cluster.enabled?} #{'is-disabled' unless can?(current_user, :update_cluster, @cluster)}", - "aria-label": s_("ClusterIntegration|Toggle Cluster"), - disabled: !can?(current_user, :update_cluster, @cluster) } - %span.toggle-icon - = sprite_icon('status_success_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-checked') - = sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked') - - .form-group - %h5= s_('ClusterIntegration|Environment scope') - %p - = s_("ClusterIntegration|Choose which of your project's environments will use this cluster.") - = link_to s_("ClusterIntegration|Learn more about environments"), help_page_path('ci/environments') - = field.text_field :environment_scope, class: 'form-control js-select-on-focus', readonly: !has_multiple_clusters?(@project), placeholder: s_('ClusterIntegration|Environment scope') - - - if can?(current_user, :update_cluster, @cluster) - .form-group - = field.submit _('Save changes'), class: 'btn btn-success' diff --git a/app/views/projects/clusters/_integration_form.html.haml b/app/views/projects/clusters/_integration_form.html.haml new file mode 100644 index 00000000000..1eac2c9dc1f --- /dev/null +++ b/app/views/projects/clusters/_integration_form.html.haml @@ -0,0 +1,33 @@ += form_for @cluster, url: namespace_project_cluster_path(@project.namespace, @project, @cluster), as: :cluster do |field| + = form_errors(@cluster) + .form-group + %h5= s_('ClusterIntegration|Integration status') + %p + - if @cluster.enabled? + - if can?(current_user, :update_cluster, @cluster) + = s_('ClusterIntegration|Cluster integration is enabled for this project. Disabling this integration will not affect your cluster, it will only temporarily turn off GitLab\'s connection to it.') + - else + = s_('ClusterIntegration|Cluster integration is enabled for this project.') + - else + = s_('ClusterIntegration|Cluster integration is disabled for this project.') + %label + = field.hidden_field :enabled, { class: 'js-toggle-input'} + + %button{ type: 'button', + class: "js-toggle-cluster project-feature-toggle #{'is-checked' unless !@cluster.enabled?} #{'is-disabled' unless can?(current_user, :update_cluster, @cluster)}", + "aria-label": s_("ClusterIntegration|Toggle Cluster"), + disabled: !can?(current_user, :update_cluster, @cluster) } + %span.toggle-icon + = sprite_icon('status_success_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-checked') + = sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked') + + .form-group + %h5= s_('ClusterIntegration|Environment scope') + %p + = s_("ClusterIntegration|Choose which of your project's environments will use this cluster.") + = link_to s_("ClusterIntegration|Learn more about environments"), help_page_path('ci/environments') + = field.text_field :environment_scope, class: 'form-control js-select-on-focus', readonly: !has_multiple_clusters?(@project), placeholder: s_('ClusterIntegration|Environment scope') + + - if can?(current_user, :update_cluster, @cluster) + .form-group + = field.submit _('Save changes'), class: 'btn btn-success' diff --git a/app/views/projects/clusters/show.html.haml b/app/views/projects/clusters/show.html.haml index dfaef8716de..c15785806b9 100644 --- a/app/views/projects/clusters/show.html.haml +++ b/app/views/projects/clusters/show.html.haml @@ -19,7 +19,7 @@ %section.settings.no-animate.expanded#cluster-integration = render 'banner' - = render 'enabled' + = render 'integration_form' .cluster-applications-table#js-cluster-applications -- cgit v1.2.1 From 0b5947849a32991904f8cbc5e4612d2438b97e0b Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 21 Dec 2017 17:25:50 +0000 Subject: Fix broken spinach test --- features/steps/shared/builds.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/shared/builds.rb b/features/steps/shared/builds.rb index c267195f0e8..a3e4459f169 100644 --- a/features/steps/shared/builds.rb +++ b/features/steps/shared/builds.rb @@ -11,7 +11,7 @@ module SharedBuilds step 'project has a recent build' do @pipeline = create(:ci_empty_pipeline, project: @project, sha: @project.commit.sha, ref: 'master') - @build = create(:ci_build, :coverage, pipeline: @pipeline) + @build = create(:ci_build, :running, :coverage, pipeline: @pipeline) end step 'recent build is successful' do -- cgit v1.2.1 From a08bef4ebf3b87e52a32af7a1c297e0de99fa1a0 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 21 Dec 2017 17:34:20 +0000 Subject: Update Browse file to Choose file in all occurences --- app/views/profiles/show.html.haml | 2 +- app/views/projects/edit.html.haml | 2 +- changelogs/unreleased/40780-choose-file.yml | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/40780-choose-file.yml diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 79f334176a5..f9dae310e01 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -26,7 +26,7 @@ Upload new avatar .prepend-top-5.append-bottom-10 %a.btn.js-choose-user-avatar-button - Browse file... + Choose file... %span.avatar-file-name.prepend-left-default.js-avatar-filename No file chosen = f.file_field_without_bootstrap :avatar, class: 'js-user-avatar-input hidden', accept: 'image/*' .help-block diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index 71206f3a386..9d0d525a292 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -52,7 +52,7 @@ - if @project.avatar_in_git Project avatar in repository: #{ @project.avatar_in_git } %a.choose-btn.btn.js-choose-project-avatar-button - Browse file... + Choose file... %span.file_name.prepend-left-default.js-avatar-filename No file chosen = f.file_field :avatar, class: "js-project-avatar-input hidden" .help-block The maximum file size allowed is 200KB. diff --git a/changelogs/unreleased/40780-choose-file.yml b/changelogs/unreleased/40780-choose-file.yml new file mode 100644 index 00000000000..73e59dfcce8 --- /dev/null +++ b/changelogs/unreleased/40780-choose-file.yml @@ -0,0 +1,5 @@ +--- +title: Update Browse file to Choose file in all occurences +merge_request: +author: +type: other -- cgit v1.2.1 From 97b4e76f9b38720bd48d1ee72d339b4bf027d2bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 21 Dec 2017 18:50:17 +0100 Subject: Mark the gcp check page feature spec pending --- spec/features/projects/clusters/gcp_spec.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index 4b682acd47e..4d0abb15b9a 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -137,7 +137,9 @@ feature 'Gcp Cluster', :js do end it 'user sees a check page' do - expect(page).to have_link('Continue') + pending 'the frontend still has not been implemented' do + expect(page).to have_link('Continue') + end end end end -- cgit v1.2.1 From ab2326f87cab96abc91e10d4a1602a5d2b78f1e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 21 Dec 2017 18:53:26 +0100 Subject: Make GCP billing check mock more specific --- spec/support/google_api/cloud_platform_helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/support/google_api/cloud_platform_helpers.rb b/spec/support/google_api/cloud_platform_helpers.rb index 9f9289fa580..887ea5c99b1 100644 --- a/spec/support/google_api/cloud_platform_helpers.rb +++ b/spec/support/google_api/cloud_platform_helpers.rb @@ -13,7 +13,7 @@ module GoogleApi def stub_google_project_billing_status redis_double = double allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) - allow(redis_double).to receive(:get).and_return('true') + allow(redis_double).to receive(:get).with(CheckGcpProjectBillingWorker.redis_shared_state_key_for).and_return('true') end def stub_cloud_platform_get_zone_cluster(project_id, zone, cluster_id, **options) -- cgit v1.2.1 From 59c7f46e2aa33d633fdc3f78c8a4faa792e40972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 21 Dec 2017 19:02:06 +0100 Subject: Remove actions for async GCP project billing check --- .../projects/clusters/gcp_controller.rb | 31 ---- config/routes/project.rb | 2 - .../projects/clusters/gcp_controller_spec.rb | 200 ++------------------- 3 files changed, 11 insertions(+), 222 deletions(-) diff --git a/app/controllers/projects/clusters/gcp_controller.rb b/app/controllers/projects/clusters/gcp_controller.rb index 66a851c52c7..0c8305480ae 100644 --- a/app/controllers/projects/clusters/gcp_controller.rb +++ b/app/controllers/projects/clusters/gcp_controller.rb @@ -18,29 +18,6 @@ class Projects::Clusters::GcpController < Projects::ApplicationController end end - def check - respond_to do |format| - format.json do - Gitlab::PollingInterval.set_header(response, interval: STATUS_POLLING_INTERVAL) - - Gitlab::Redis::SharedState.with do |redis| - render json: { billing: redis.get(CheckGcpProjectBillingWorker.redis_shared_state_key_for(token_in_session)) } - end - end - - format.html { render :check } - end - end - - def run_check - respond_to do |format| - format.json do - CheckGcpProjectBillingWorker.perform_async(token_in_session) - head :no_content - end - end - end - def new @cluster = ::Clusters::Cluster.new.tap do |cluster| cluster.build_provider_gcp @@ -84,14 +61,6 @@ class Projects::Clusters::GcpController < Projects::ApplicationController end end - def authorize_google_project_billing - Gitlab::Redis::SharedState.with do |redis| - unless redis.get(CheckGcpProjectBillingWorker.redis_shared_state_key_for(token_in_session)) == 'true' - CheckGcpProjectBillingWorker.perform_async(token_in_session) - redirect_to action: 'check' - end - end - end def token_in_session @token_in_session ||= diff --git a/config/routes/project.rb b/config/routes/project.rb index b315b53f293..239b5480321 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -192,8 +192,6 @@ constraints(ProjectUrlConstrainer.new) do get '/gcp/new', to: 'clusters/gcp#new' get '/gcp/login', to: 'clusters/gcp#login' - get '/gcp/check', to: 'clusters/gcp#check' - post '/gcp/check', to: 'clusters/gcp#run_check' post '/gcp', to: 'clusters/gcp#create' end end diff --git a/spec/controllers/projects/clusters/gcp_controller_spec.rb b/spec/controllers/projects/clusters/gcp_controller_spec.rb index 4fa798c5856..485b67de30a 100644 --- a/spec/controllers/projects/clusters/gcp_controller_spec.rb +++ b/spec/controllers/projects/clusters/gcp_controller_spec.rb @@ -62,132 +62,6 @@ describe Projects::Clusters::GcpController do end end - describe 'GET check' do - let(:user) { create(:user) } - - before do - project.add_master(user) - sign_in(user) - end - - describe 'functionality' do - context 'when access token is valid' do - before do - stub_google_api_validate_token - end - - context 'when redis has wanted billing status' do - let(:token) { 'bogustoken' } - - before do - redis_double = double - allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) - allow(redis_double).to receive(:get).and_return('true') - end - - it 'should render json with billing status' do - go - - expect(response).to have_http_status(:ok) - expect(JSON.parse(response.body)).to include('billing' => 'true') - end - end - - context 'when redis does not have billing status' do - before do - redis_double = double - allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) - allow(redis_double).to receive(:get).and_return(nil) - end - - it 'should render json with null billing status' do - go - - expect(response).to have_http_status(:ok) - expect(JSON.parse(response.body)).to include('billing' => nil) - end - end - end - - context 'when access token is expired' do - before do - stub_google_api_expired_token - end - - it { expect(go).to redirect_to(gcp_login_project_clusters_path(project)) } - end - - context 'when access token is not stored in session' do - it { expect(go).to redirect_to(gcp_login_project_clusters_path(project)) } - end - end - - describe 'security' do - it { expect { go }.to be_allowed_for(:admin) } - it { expect { go }.to be_allowed_for(:owner).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } - it { expect { go }.to be_denied_for(:developer).of(project) } - it { expect { go }.to be_denied_for(:reporter).of(project) } - it { expect { go }.to be_denied_for(:guest).of(project) } - it { expect { go }.to be_denied_for(:user) } - it { expect { go }.to be_denied_for(:external) } - end - - def go - get :check, namespace_id: project.namespace, project_id: project, format: :json - end - end - - describe 'POST check' do - let(:user) { create(:user) } - - before do - project.add_master(user) - sign_in(user) - end - - describe 'functionality' do - context 'when access token is valid' do - before do - stub_google_api_validate_token - end - - it 'calls check worker asynchronously' do - expect(CheckGcpProjectBillingWorker).to receive(:perform_async) - - expect(go).to have_http_status(:no_content) - end - end - - context 'when access token is expired' do - before do - stub_google_api_expired_token - end - - it { expect(go).to redirect_to(gcp_login_project_clusters_path(project)) } - end - - context 'when access token is not stored in session' do - it { expect(go).to redirect_to(gcp_login_project_clusters_path(project)) } - end - end - - describe 'security' do - it { expect { go }.to be_allowed_for(:admin) } - it { expect { go }.to be_allowed_for(:owner).of(project) } - it { expect { go }.to be_allowed_for(:master).of(project) } - it { expect { go }.to be_denied_for(:developer).of(project) } - it { expect { go }.to be_denied_for(:reporter).of(project) } - it { expect { go }.to be_denied_for(:guest).of(project) } - it { expect { go }.to be_denied_for(:user) } - it { expect { go }.to be_denied_for(:external) } - end - - def go - post :run_check, namespace_id: project.namespace, project_id: project, format: :json - end - end - describe 'GET new' do describe 'functionality' do let(:user) { create(:user) } @@ -202,36 +76,10 @@ describe Projects::Clusters::GcpController do stub_google_api_validate_token end - context 'when google project billing status is true' do - before do - stub_google_project_billing_status - end - - it 'has new object' do - go - - expect(assigns(:cluster)).to be_an_instance_of(Clusters::Cluster) - end - end - - context 'when google project billing status is not true' do - before do - redis_double = double - allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) - allow(redis_double).to receive(:get).and_return(nil) - end - - it 'redirects to check page' do - allow(CheckGcpProjectBillingWorker).to receive(:perform_async) - - expect(go).to redirect_to(gcp_check_project_clusters_path(project)) - end - - it 'calls gcp project billing check worker' do - expect(CheckGcpProjectBillingWorker).to receive(:perform_async) + it 'has new object' do + go - go - end + expect(assigns(:cluster)).to be_an_instance_of(Clusters::Cluster) end end @@ -289,40 +137,14 @@ describe Projects::Clusters::GcpController do stub_google_api_validate_token end - context 'when google project billing status is true' do - before do - stub_google_project_billing_status - end - - context 'when creates a cluster on gke' do - it 'creates a new cluster' do - expect(ClusterProvisionWorker).to receive(:perform_async) - expect { go }.to change { Clusters::Cluster.count } - .and change { Clusters::Providers::Gcp.count } - expect(response).to redirect_to(project_cluster_path(project, project.clusters.first)) - expect(project.clusters.first).to be_gcp - expect(project.clusters.first).to be_kubernetes - end - end - end - - context 'when google project billing status is not true' do - before do - redis_double = double - allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) - allow(redis_double).to receive(:get).and_return(nil) - end - - it 'redirects to check page' do - allow(CheckGcpProjectBillingWorker).to receive(:perform_async) - - expect(go).to redirect_to(gcp_check_project_clusters_path(project)) - end - - it 'calls gcp project billing check worker' do - expect(CheckGcpProjectBillingWorker).to receive(:perform_async) - - go + context 'when creates a cluster on gke' do + it 'creates a new cluster' do + expect(ClusterProvisionWorker).to receive(:perform_async) + expect { go }.to change { Clusters::Cluster.count } + .and change { Clusters::Providers::Gcp.count } + expect(response).to redirect_to(project_cluster_path(project, project.clusters.first)) + expect(project.clusters.first).to be_gcp + expect(project.clusters.first).to be_kubernetes end end end -- cgit v1.2.1 From e395a2c1901aa08c5d1f26f94406552db44140fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 21 Dec 2017 19:25:28 +0100 Subject: Implement GCP billing check in cluster form --- .../projects/clusters/gcp_controller.rb | 28 ++++++++++++++++------ .../projects/clusters/gcp_controller_spec.rb | 17 ++++++++++++- spec/support/google_api/cloud_platform_helpers.rb | 2 +- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/app/controllers/projects/clusters/gcp_controller.rb b/app/controllers/projects/clusters/gcp_controller.rb index 0c8305480ae..27c11ce554d 100644 --- a/app/controllers/projects/clusters/gcp_controller.rb +++ b/app/controllers/projects/clusters/gcp_controller.rb @@ -1,7 +1,7 @@ class Projects::Clusters::GcpController < Projects::ApplicationController before_action :authorize_read_cluster! before_action :authorize_google_api, except: [:login] - before_action :authorize_google_project_billing, except: [:login, :check, :run_check] + before_action :authorize_google_project_billing, only: [:new] before_action :authorize_create_cluster!, only: [:new, :create] STATUS_POLLING_INTERVAL = 1.minute.to_i @@ -25,15 +25,20 @@ class Projects::Clusters::GcpController < Projects::ApplicationController end def create - @cluster = ::Clusters::CreateService - .new(project, current_user, create_params) - .execute(token_in_session) + case google_project_billing_status + when 'true' + @cluster = ::Clusters::CreateService + .new(project, current_user, create_params) + .execute(token_in_session) - if @cluster.persisted? - redirect_to project_cluster_path(project, @cluster) + return redirect_to project_cluster_path(project, @cluster) if @cluster.persisted? + when 'false' + flash[:error] = _('Please enable billing for one of your projects to be able to create a cluster.') else - render :new + flash[:error] = _('We could not verify that one of your projects on GCP has billing enabled. Please try again.') end + + render :new end private @@ -61,6 +66,15 @@ class Projects::Clusters::GcpController < Projects::ApplicationController end end + def authorize_google_project_billing + CheckGcpProjectBillingWorker.perform_async(token_in_session) + end + + def google_project_billing_status + Gitlab::Redis::SharedState.with do |redis| + redis.get(CheckGcpProjectBillingWorker.redis_shared_state_key_for(token_in_session)) + end + end def token_in_session @token_in_session ||= diff --git a/spec/controllers/projects/clusters/gcp_controller_spec.rb b/spec/controllers/projects/clusters/gcp_controller_spec.rb index 485b67de30a..be19fa93183 100644 --- a/spec/controllers/projects/clusters/gcp_controller_spec.rb +++ b/spec/controllers/projects/clusters/gcp_controller_spec.rb @@ -77,6 +77,8 @@ describe Projects::Clusters::GcpController do end it 'has new object' do + expect(controller).to receive(:authorize_google_project_billing) + go expect(assigns(:cluster)).to be_an_instance_of(Clusters::Cluster) @@ -137,7 +139,11 @@ describe Projects::Clusters::GcpController do stub_google_api_validate_token end - context 'when creates a cluster on gke' do + context 'when google project billing is enabled' do + before do + stub_google_project_billing_status + end + it 'creates a new cluster' do expect(ClusterProvisionWorker).to receive(:perform_async) expect { go }.to change { Clusters::Cluster.count } @@ -147,6 +153,15 @@ describe Projects::Clusters::GcpController do expect(project.clusters.first).to be_kubernetes end end + + context 'when google project billing is not enabled' do + it 'renders the cluster form with an error' do + go + + expect(response).to set_flash[:error] + expect(response).to render_template('new') + end + end end context 'when access token is expired' do diff --git a/spec/support/google_api/cloud_platform_helpers.rb b/spec/support/google_api/cloud_platform_helpers.rb index 887ea5c99b1..99752ed396e 100644 --- a/spec/support/google_api/cloud_platform_helpers.rb +++ b/spec/support/google_api/cloud_platform_helpers.rb @@ -13,7 +13,7 @@ module GoogleApi def stub_google_project_billing_status redis_double = double allow(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) - allow(redis_double).to receive(:get).with(CheckGcpProjectBillingWorker.redis_shared_state_key_for).and_return('true') + allow(redis_double).to receive(:get).with(CheckGcpProjectBillingWorker.redis_shared_state_key_for('token')).and_return('true') end def stub_cloud_platform_get_zone_cluster(project_id, zone, cluster_id, **options) -- cgit v1.2.1 From 55f40164c9a012b31adc733d2f081b39970c6b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 21 Dec 2017 20:45:00 +0100 Subject: Add CheckGcpProjectBilling worker to all_queues --- app/workers/all_queues.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index 268b7028fd9..142e33e8325 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -97,3 +97,4 @@ - update_user_activity - upload_checksum - web_hook +- check_gcp_project_billing -- cgit v1.2.1 From 5be9a521df57d8dba6c4520220fe5f8a6a001dfa Mon Sep 17 00:00:00 2001 From: Joshua Lambert Date: Thu, 21 Dec 2017 19:51:53 +0000 Subject: Set Auto Browser Performance Testing to 10.4 --- doc/topics/autodevops/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md index 4056469e6c4..7863252dc17 100644 --- a/doc/topics/autodevops/index.md +++ b/doc/topics/autodevops/index.md @@ -218,7 +218,7 @@ Any security warnings are also [shown in the merge request widget](https://docs. ### Auto Browser Performance Testing -> Introduced in [GitLab Enterprise Edition Premium][ee] 10.3. +> Introduced in [GitLab Enterprise Edition Premium][ee] 10.4. Auto Browser Performance Testing utilizes the [Sitespeed.io container](https://hub.docker.com/r/sitespeedio/sitespeed.io/) to measure the performance of a web page. A JSON report is created and uploaded as an artifact, which includes the overall performance score for each page. By default, the root page of Review and Production environments will be tested. If you would like to add additional URL's to test, simply add the paths to a file named `.gitlab-urls.txt` in the root directory, one per line. For example: -- cgit v1.2.1 From ad1357d6ccb9be58f36f813c2296e48c18809c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 21 Dec 2017 21:10:50 +0100 Subject: Fix use of pending decorator in spec --- spec/features/projects/clusters/gcp_spec.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index 4d0abb15b9a..ad8c1ebc1f8 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -137,9 +137,8 @@ feature 'Gcp Cluster', :js do end it 'user sees a check page' do - pending 'the frontend still has not been implemented' do - expect(page).to have_link('Continue') - end + pending 'the frontend still has not been implemented' + expect(page).to have_link('Continue') end end end -- cgit v1.2.1 From 9416193b30e2fd9cd793d078da5df1ee9d78c5c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 21 Dec 2017 21:30:43 +0100 Subject: Fix clusters/gcp feature spec --- spec/features/projects/clusters/gcp_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index ad8c1ebc1f8..51bd09e88e0 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -22,6 +22,7 @@ feature 'Gcp Cluster', :js do context 'when user has a GCP project with billing enabled' do before do + allow(CheckGcpProjectBillingWorker).to receive(:perform_async) stub_google_project_billing_status end -- cgit v1.2.1 From d4e2805eb23b548cdd9773c23076f536feb524bf Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Thu, 21 Dec 2017 23:24:00 +0200 Subject: Last push event widget width for fixed layout --- app/views/projects/_last_push.html.haml | 27 +++++++++++----------- app/views/projects/tree/show.html.haml | 3 ++- .../fix-last-push-event-widget-layout.yml | 5 ++++ 3 files changed, 21 insertions(+), 14 deletions(-) create mode 100644 changelogs/unreleased/fix-last-push-event-widget-layout.yml diff --git a/app/views/projects/_last_push.html.haml b/app/views/projects/_last_push.html.haml index 56eecece54c..b68eb47c6b4 100644 --- a/app/views/projects/_last_push.html.haml +++ b/app/views/projects/_last_push.html.haml @@ -1,18 +1,19 @@ - event = last_push_event - if event && show_last_push_widget?(event) - .row-content-block.top-block.hidden-xs.white - .event-last-push - .event-last-push-text - %span= s_("LastPushEvent|You pushed to") - %strong - = link_to event.ref_name, project_commits_path(event.project, event.ref_name), class: 'ref-name' + %div{ class: container_class } + .row-content-block.top-block.hidden-xs.white + .event-last-push + .event-last-push-text + %span= s_("LastPushEvent|You pushed to") + %strong + = link_to event.ref_name, project_commits_path(event.project, event.ref_name), class: 'ref-name' - - if event.project != @project - %span= s_("LastPushEvent|at") - %strong= link_to_project event.project + - if event.project != @project + %span= s_("LastPushEvent|at") + %strong= link_to_project event.project - #{time_ago_with_tooltip(event.created_at)} + #{time_ago_with_tooltip(event.created_at)} - .pull-right - = link_to new_mr_path_from_push_event(event), title: _("New merge request"), class: "btn btn-info btn-sm" do - #{ _('Create merge request') } + .pull-right + = link_to new_mr_path_from_push_event(event), title: _("New merge request"), class: "btn btn-info btn-sm" do + #{ _('Create merge request') } diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml index 3b4057e56d0..709be20e00f 100644 --- a/app/views/projects/tree/show.html.haml +++ b/app/views/projects/tree/show.html.haml @@ -6,6 +6,7 @@ = content_for :meta_tags do = auto_discovery_link_tag(:atom, project_commits_url(@project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits") += render 'projects/last_push' + %div{ class: [(container_class), ("limit-container-width" unless fluid_layout)] } - = render 'projects/last_push' = render 'projects/files', commit: @last_commit, project: @project, ref: @ref, content_url: project_tree_path(@project, @id) diff --git a/changelogs/unreleased/fix-last-push-event-widget-layout.yml b/changelogs/unreleased/fix-last-push-event-widget-layout.yml new file mode 100644 index 00000000000..ba5b115ca19 --- /dev/null +++ b/changelogs/unreleased/fix-last-push-event-widget-layout.yml @@ -0,0 +1,5 @@ +--- +title: Last push event widget width for fixed layout +merge_request: 15862 +author: George Tsiolis +type: fixed -- cgit v1.2.1 From 680ebf449bc5700f827559660f28fb4e47022828 Mon Sep 17 00:00:00 2001 From: Greg Stark Date: Wed, 20 Dec 2017 19:43:41 +0000 Subject: Add index on namespaces lower(name) for UsersController#exists --- .../unreleased/index-namespaces-lower-name.yml | 5 ++++ ...220191323_add_index_on_namespaces_lower_name.rb | 30 ++++++++++++++++++++++ db/schema.rb | 2 +- lib/tasks/migrate/setup_postgresql.rake | 2 ++ 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/index-namespaces-lower-name.yml create mode 100644 db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb diff --git a/changelogs/unreleased/index-namespaces-lower-name.yml b/changelogs/unreleased/index-namespaces-lower-name.yml new file mode 100644 index 00000000000..ef08b6d6755 --- /dev/null +++ b/changelogs/unreleased/index-namespaces-lower-name.yml @@ -0,0 +1,5 @@ +--- +title: Add index on namespaces lower(name) for UsersController#exists +merge_request: +author: +type: performance diff --git a/db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb b/db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb new file mode 100644 index 00000000000..7cf1d0cec68 --- /dev/null +++ b/db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb @@ -0,0 +1,30 @@ +class AddIndexOnNamespacesLowerName < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + DOWNTIME = false + INDEX_NAME = 'index_on_namespaces_lower_name' + + disable_ddl_transaction! + + def up + return unless Gitlab::Database.postgresql? + + disable_statement_timeout + if Gitlab::Database.version.to_f >= 9.5 + # Allow us to hot-patch the index manually ahead of the migration + execute "CREATE INDEX CONCURRENTLY IF NOT EXISTS #{INDEX_NAME} ON namespaces (lower(name));" + else + execute "CREATE INDEX CONCURRENTLY #{INDEX_NAME} ON namespaces (lower(name));" + end + end + + def down + return unless Gitlab::Database.postgresql? + + disable_statement_timeout + if Gitlab::Database.version.to_f >= 9.2 + 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 2b20628bd53..81b594cd0c1 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: 20171219121201) do +ActiveRecord::Schema.define(version: 20171220191323) 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 9cc986535e1..c9e3eed82f2 100644 --- a/lib/tasks/migrate/setup_postgresql.rake +++ b/lib/tasks/migrate/setup_postgresql.rake @@ -6,6 +6,7 @@ require Rails.root.join('db/migrate/20161212142807_add_lower_path_index_to_route 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') +require Rails.root.join('db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb') desc 'GitLab | Sets up PostgreSQL' task setup_postgresql: :environment do @@ -15,4 +16,5 @@ task setup_postgresql: :environment do IndexRoutesPathForLike.new.up AddLowerPathIndexToRedirectRoutes.new.up IndexRedirectRoutesPathForLike.new.up + AddIndexOnNamespacesLowerName.new.up end -- cgit v1.2.1 From 965617a05e4715a8687a16bc21ba9b75055d8dac Mon Sep 17 00:00:00 2001 From: asaparov Date: Tue, 19 Dec 2017 19:10:14 -0500 Subject: Bumped mysql2 gem version from 0.4.5 to 0.4.10. --- Gemfile | 2 +- Gemfile.lock | 4 ++-- changelogs/unreleased/bump_mysql_gem.yml | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/bump_mysql_gem.yml diff --git a/Gemfile b/Gemfile index b6ffaf80f24..cc39714295e 100644 --- a/Gemfile +++ b/Gemfile @@ -12,7 +12,7 @@ gem 'sprockets', '~> 3.7.0' gem 'default_value_for', '~> 3.0.0' # Supported DBs -gem 'mysql2', '~> 0.4.5', group: :mysql +gem 'mysql2', '~> 0.4.10', group: :mysql gem 'pg', '~> 0.18.2', group: :postgres gem 'rugged', '~> 0.26.0' diff --git a/Gemfile.lock b/Gemfile.lock index a6e3c9e27cc..d11cadeec30 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -501,7 +501,7 @@ GEM mustermann (1.0.0) mustermann-grape (1.0.0) mustermann (~> 1.0.0) - mysql2 (0.4.5) + mysql2 (0.4.10) net-ldap (0.16.0) net-ssh (4.1.0) netrc (0.11.0) @@ -1082,7 +1082,7 @@ DEPENDENCIES method_source (~> 0.8) minitest (~> 5.7.0) mousetrap-rails (~> 1.4.6) - mysql2 (~> 0.4.5) + mysql2 (~> 0.4.10) net-ldap net-ssh (~> 4.1.0) nokogiri (~> 1.8.1) diff --git a/changelogs/unreleased/bump_mysql_gem.yml b/changelogs/unreleased/bump_mysql_gem.yml new file mode 100644 index 00000000000..58166949d72 --- /dev/null +++ b/changelogs/unreleased/bump_mysql_gem.yml @@ -0,0 +1,5 @@ +--- +title: Bump mysql2 gem version from 0.4.5 to 0.4.10 +merge_request: +author: asaparov +type: other -- cgit v1.2.1 From 17136f702a17e5a42268fd76796579ee95914b28 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 22 Dec 2017 06:59:13 +0000 Subject: Fix typo --- app/views/projects/jobs/show.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml index 85d802a9d9c..ced7b65e940 100644 --- a/app/views/projects/jobs/show.html.haml +++ b/app/views/projects/jobs/show.html.haml @@ -90,7 +90,7 @@ .build-loader-animation.js-build-refresh - else - illustration = @build.playable? ? 'illustrations/manual_action.svg' : 'illustrations/job_not_triggered.svg' - - illustration_size = @build.playable? ? 'svg-394' : 'sgv-306' + - illustration_size = @build.playable? ? 'svg-394' : 'svg-306' - title = @build.playable? ? _('This job requires a manual action') : _('This job has not been triggered yet') - content = @build.playable? ? _('This job depends on a user to trigger its process. Often they are used to deploy code to production environments.') : _('This job depends on upstream jobs that need to succeed in order for this job to be triggered.') .row.empty-state -- cgit v1.2.1 From 21c0031f789d41ca9d2879585777bc0fe5419c7e Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Mon, 16 Oct 2017 12:40:47 +0300 Subject: Add note about using the term GPG for all related implementations Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/36970 --- doc/user/project/repository/gpg_signed_commits/index.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/user/project/repository/gpg_signed_commits/index.md b/doc/user/project/repository/gpg_signed_commits/index.md index 6b9976d133c..d41be0989d2 100644 --- a/doc/user/project/repository/gpg_signed_commits/index.md +++ b/doc/user/project/repository/gpg_signed_commits/index.md @@ -1,6 +1,11 @@ # Signing commits with GPG -> [Introduced][ce-9546] in GitLab 9.5. +NOTE: **Note:** +The term GPG is used for all OpenPGP/PGP/GPG related material and +implementations. + +> - [Introduced][ce-9546] in GitLab 9.5. +> - Subkeys support was added in GitLab 10.1. GitLab can show whether a commit is verified or not when signed with a GPG key. All you need to do is upload the public GPG key in your profile settings. -- cgit v1.2.1 From 27c95364b52f4e93054c45211010aeb22e40a2b2 Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Fri, 22 Dec 2017 19:18:28 +1100 Subject: Replace '.team << [user, role]' with 'add_role(user)' in specs --- app/models/project.rb | 2 +- app/models/project_team.rb | 28 +++++------------ ...-team-user-role-with-add_role-user-in-specs.yml | 5 +++ db/fixtures/development/06_teams.rb | 2 +- features/steps/profile/profile.rb | 2 +- features/steps/project/deploy_keys.rb | 4 +-- features/steps/project/fork.rb | 4 +-- features/steps/project/forked_merge_requests.rb | 2 +- features/steps/project/source/browse_files.rb | 2 +- features/steps/project/source/markdown_render.rb | 2 +- features/steps/shared/group.rb | 2 +- features/steps/shared/project.rb | 21 ++++++------- spec/controllers/admin/users_controller_spec.rb | 2 +- spec/controllers/boards/issues_controller_spec.rb | 6 ++-- spec/controllers/boards/lists_controller_spec.rb | 4 +-- .../dashboard/milestones_controller_spec.rb | 2 +- .../controllers/dashboard/todos_controller_spec.rb | 2 +- spec/controllers/dashboard_controller_spec.rb | 2 +- .../groups/milestones_controller_spec.rb | 2 +- .../notification_settings_controller_spec.rb | 2 +- .../projects/avatars_controller_spec.rb | 2 +- spec/controllers/projects/blame_controller_spec.rb | 2 +- spec/controllers/projects/blob_controller_spec.rb | 8 ++--- .../controllers/projects/boards_controller_spec.rb | 2 +- .../projects/branches_controller_spec.rb | 4 +-- .../projects/commits_controller_spec.rb | 2 +- .../projects/compare_controller_spec.rb | 2 +- .../projects/cycle_analytics_controller_spec.rb | 2 +- .../projects/deploy_keys_controller_spec.rb | 4 +-- .../projects/deployments_controller_spec.rb | 2 +- .../projects/discussions_controller_spec.rb | 4 +-- .../projects/find_file_controller_spec.rb | 2 +- spec/controllers/projects/forks_controller_spec.rb | 2 +- .../controllers/projects/graphs_controller_spec.rb | 2 +- .../projects/group_links_controller_spec.rb | 2 +- spec/controllers/projects/hooks_controller_spec.rb | 2 +- .../projects/imports_controller_spec.rb | 4 +-- .../controllers/projects/issues_controller_spec.rb | 28 ++++++++--------- spec/controllers/projects/jobs_controller_spec.rb | 2 +- .../controllers/projects/labels_controller_spec.rb | 2 +- .../projects/mattermosts_controller_spec.rb | 2 +- .../merge_requests/creations_controller_spec.rb | 4 +-- .../merge_requests/diffs_controller_spec.rb | 2 +- .../projects/milestones_controller_spec.rb | 2 +- spec/controllers/projects/notes_controller_spec.rb | 14 ++++----- .../projects/project_members_controller_spec.rb | 26 ++++++++-------- spec/controllers/projects/refs_controller_spec.rb | 2 +- .../projects/releases_controller_spec.rb | 2 +- .../projects/repositories_controller_spec.rb | 2 +- .../projects/services_controller_spec.rb | 2 +- .../projects/settings/ci_cd_controller_spec.rb | 2 +- .../settings/integrations_controller_spec.rb | 2 +- .../projects/templates_controller_spec.rb | 2 +- spec/controllers/projects/todos_controller_spec.rb | 4 +-- spec/controllers/projects/tree_controller_spec.rb | 2 +- .../projects/variables_controller_spec.rb | 2 +- spec/controllers/projects_controller_spec.rb | 6 ++-- spec/controllers/uploads_controller_spec.rb | 8 ++--- spec/controllers/users_controller_spec.rb | 4 +-- spec/features/admin/admin_projects_spec.rb | 6 ++-- 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 +- spec/features/auto_deploy_spec.rb | 4 +-- spec/features/boards/add_issues_modal_spec.rb | 2 +- spec/features/boards/boards_spec.rb | 6 ++-- spec/features/boards/issue_ordering_spec.rb | 2 +- spec/features/boards/modal_filter_spec.rb | 6 ++-- spec/features/boards/new_issue_spec.rb | 2 +- spec/features/commits_spec.rb | 8 ++--- spec/features/cycle_analytics_spec.rb | 2 +- spec/features/dashboard/archived_projects_spec.rb | 4 +-- .../dashboard/datetime_on_tooltips_spec.rb | 4 +-- spec/features/dashboard/issues_spec.rb | 2 +- spec/features/dashboard/milestones_spec.rb | 2 +- .../project_member_activity_index_spec.rb | 2 +- spec/features/dashboard/projects_spec.rb | 2 +- .../dashboard/todos/todos_filtering_spec.rb | 8 ++--- .../features/dashboard/todos/todos_sorting_spec.rb | 2 +- .../dashboard/user_filters_projects_spec.rb | 4 +-- spec/features/global_search_spec.rb | 2 +- spec/features/issues/award_emoji_spec.rb | 2 +- .../features/issues/bulk_assignment_labels_spec.rb | 2 +- ..._issue_for_discussions_in_merge_request_spec.rb | 4 +-- ..._for_single_discussion_in_merge_request_spec.rb | 4 +-- .../filtered_search/dropdown_assignee_spec.rb | 8 ++--- .../issues/filtered_search/dropdown_author_spec.rb | 8 ++--- .../issues/filtered_search/dropdown_emoji_spec.rb | 2 +- .../issues/filtered_search/dropdown_hint_spec.rb | 2 +- .../filtered_search/dropdown_milestone_spec.rb | 2 +- .../issues/filtered_search/search_bar_spec.rb | 2 +- spec/features/issues/form_spec.rb | 4 +-- spec/features/issues/gfm_autocomplete_spec.rb | 2 +- spec/features/issues/issue_sidebar_spec.rb | 6 ++-- spec/features/issues/move_spec.rb | 10 +++--- 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/update_issues_spec.rb | 2 +- .../issues/user_uses_slash_commands_spec.rb | 12 ++++---- spec/features/issues_spec.rb | 9 +++--- spec/features/merge_requests/assign_issues_spec.rb | 2 +- ...f_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 | 4 +-- spec/features/merge_requests/create_new_mr_spec.rb | 2 +- .../merge_requests/created_from_fork_spec.rb | 2 +- .../merge_requests/deleted_source_branch_spec.rb | 2 +- .../merge_requests/diff_notes_avatars_spec.rb | 2 +- .../merge_requests/diff_notes_resolve_spec.rb | 6 ++-- spec/features/merge_requests/edit_mr_spec.rb | 2 +- .../merge_requests/filter_by_milestone_spec.rb | 2 +- spec/features/merge_requests/form_spec.rb | 6 ++-- .../merge_requests/image_diff_notes_spec.rb | 2 +- .../merge_commit_message_toggle_spec.rb | 2 +- .../merge_immediately_with_pipeline_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/update_merge_requests_spec.rb | 2 +- .../user_uses_slash_commands_spec.rb | 10 +++--- .../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 +- .../profiles/user_visits_notifications_tab_spec.rb | 2 +- spec/features/projects/activity/rss_spec.rb | 2 +- spec/features/projects/badges/coverage_spec.rb | 2 +- spec/features/projects/badges/list_spec.rb | 2 +- spec/features/projects/blobs/edit_spec.rb | 8 ++--- .../projects/branches/download_buttons_spec.rb | 2 +- spec/features/projects/branches_spec.rb | 4 +-- spec/features/projects/commit/builds_spec.rb | 2 +- spec/features/projects/commit/cherry_pick_spec.rb | 2 +- spec/features/projects/commits/rss_spec.rb | 2 +- spec/features/projects/compare_spec.rb | 2 +- spec/features/projects/deploy_keys_spec.rb | 2 +- ...eloper_views_empty_project_instructions_spec.rb | 2 +- spec/features/projects/edit_spec.rb | 2 +- .../projects/environments/environment_spec.rb | 2 +- .../projects/environments/environments_spec.rb | 2 +- spec/features/projects/features_visibility_spec.rb | 6 ++-- spec/features/projects/files/browse_files_spec.rb | 2 +- .../projects/files/creating_a_file_spec.rb | 2 +- .../projects/files/dockerfile_dropdown_spec.rb | 2 +- .../projects/files/download_buttons_spec.rb | 2 +- .../projects/files/edit_file_soft_wrap_spec.rb | 2 +- .../features/projects/files/editing_a_file_spec.rb | 2 +- .../files_sort_submodules_with_folders_spec.rb | 2 +- .../projects/files/find_file_keyboard_spec.rb | 2 +- .../projects/files/gitignore_dropdown_spec.rb | 2 +- .../projects/files/gitlab_ci_yml_dropdown_spec.rb | 2 +- .../project_owner_creates_license_file_spec.rb | 2 +- .../projects/files/template_type_dropdown_spec.rb | 2 +- spec/features/projects/files/undo_template_spec.rb | 2 +- .../projects/guest_navigation_menu_spec.rb | 2 +- spec/features/projects/issuable_templates_spec.rb | 4 +-- spec/features/projects/issues/rss_spec.rb | 2 +- spec/features/projects/jobs_spec.rb | 2 +- spec/features/projects/labels/subscription_spec.rb | 2 +- .../projects/labels/update_prioritization_spec.rb | 2 +- .../projects/main/download_buttons_spec.rb | 2 +- spec/features/projects/main/rss_spec.rb | 2 +- .../members/anonymous_user_sees_members_spec.rb | 2 +- .../projects/members/group_members_spec.rb | 2 +- .../members/groups_with_access_list_spec.rb | 2 +- ...master_adds_member_with_expiration_date_spec.rb | 2 +- .../members/master_manages_access_requests_spec.rb | 2 +- ...er_cannot_request_access_to_his_project_spec.rb | 2 +- .../projects/members/member_leaves_project_spec.rb | 2 +- spec/features/projects/merge_requests/list_spec.rb | 2 +- spec/features/projects/pages_spec.rb | 2 +- spec/features/projects/pipelines/pipeline_spec.rb | 2 +- spec/features/projects/pipelines/pipelines_spec.rb | 2 +- .../projects/services/user_activates_jira_spec.rb | 2 +- ...user_activates_mattermost_slash_command_spec.rb | 2 +- .../user_activates_slack_slash_command_spec.rb | 2 +- .../projects/settings/integration_settings_spec.rb | 2 +- .../settings/merge_requests_settings_spec.rb | 2 +- .../projects/settings/pipelines_settings_spec.rb | 2 +- .../projects/settings/repository_settings_spec.rb | 4 +-- .../projects/settings/visibility_settings_spec.rb | 2 +- .../projects/snippets/create_snippet_spec.rb | 2 +- spec/features/projects/snippets/show_spec.rb | 2 +- .../projects/tags/download_buttons_spec.rb | 2 +- spec/features/projects/tree/rss_spec.rb | 2 +- spec/features/projects/user_browses_files_spec.rb | 2 +- .../projects/user_creates_directory_spec.rb | 4 +-- spec/features/projects/user_creates_files_spec.rb | 6 ++-- spec/features/projects/user_deletes_files_spec.rb | 4 +-- spec/features/projects/user_edits_files_spec.rb | 4 +-- spec/features/projects/user_replaces_files_spec.rb | 4 +-- spec/features/projects/user_uploads_files_spec.rb | 4 +-- .../projects/wiki/markdown_preview_spec.rb | 2 +- .../wiki/user_views_wiki_in_project_page_spec.rb | 2 +- spec/features/projects_spec.rb | 6 ++-- spec/features/signed_commits_spec.rb | 6 ++-- 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/triggers_spec.rb | 6 ++-- spec/features/variables_spec.rb | 2 +- spec/finders/access_requests_finder_spec.rb | 4 +-- spec/finders/group_projects_finder_spec.rb | 4 +-- spec/finders/issues_finder_spec.rb | 6 ++-- spec/finders/labels_finder_spec.rb | 4 +-- spec/finders/merge_requests_finder_spec.rb | 8 ++--- spec/finders/move_to_project_finder_spec.rb | 34 ++++++++++---------- spec/finders/notes_finder_spec.rb | 6 ++-- spec/finders/personal_projects_finder_spec.rb | 2 +- spec/finders/snippets_finder_spec.rb | 4 +-- spec/finders/todos_finder_spec.rb | 2 +- spec/helpers/markup_helper_spec.rb | 2 +- spec/helpers/notes_helper_spec.rb | 8 ++--- spec/lib/banzai/filter/redactor_filter_spec.rb | 6 ++-- .../banzai/filter/user_reference_filter_spec.rb | 6 ++-- .../banzai/reference_parser/user_parser_spec.rb | 6 ++-- spec/lib/gitlab/ci/status/build/common_spec.rb | 2 +- spec/lib/gitlab/ci/status/external/common_spec.rb | 2 +- spec/lib/gitlab/ci/status/external/factory_spec.rb | 2 +- spec/lib/gitlab/ci/status/pipeline/common_spec.rb | 2 +- spec/lib/gitlab/ci/status/pipeline/factory_spec.rb | 2 +- spec/lib/gitlab/ci/status/stage/common_spec.rb | 2 +- spec/lib/gitlab/ci/status/stage/factory_spec.rb | 2 +- spec/lib/gitlab/closing_issue_extractor_spec.rb | 6 ++-- .../lib/gitlab/cycle_analytics/permissions_spec.rb | 8 ++--- .../email/handler/create_note_handler_spec.rb | 4 +-- spec/lib/gitlab/gfm/reference_rewriter_spec.rb | 2 +- spec/lib/gitlab/git/repository_spec.rb | 2 +- spec/lib/gitlab/git_access_spec.rb | 10 +++--- spec/lib/gitlab/git_access_wiki_spec.rb | 4 +-- .../lib/gitlab/google_code_import/importer_spec.rb | 2 +- .../import_export/project_tree_saver_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/project_authorizations_spec.rb | 2 +- spec/lib/gitlab/project_search_results_spec.rb | 8 ++--- spec/lib/gitlab/reference_extractor_spec.rb | 14 ++++----- spec/lib/gitlab/search_results_spec.rb | 10 +++--- spec/lib/gitlab/slash_commands/issue_new_spec.rb | 2 +- .../lib/gitlab/slash_commands/issue_search_spec.rb | 2 +- spec/lib/gitlab/slash_commands/issue_show_spec.rb | 2 +- spec/lib/gitlab/user_access_spec.rb | 36 +++++++++++----------- spec/mailers/notify_spec.rb | 8 ++--- spec/models/ability_spec.rb | 6 ++-- spec/models/ci/pipeline_spec.rb | 2 +- spec/models/ci/trigger_spec.rb | 2 +- spec/models/commit_spec.rb | 4 +-- spec/models/concerns/mentionable_spec.rb | 4 +-- spec/models/concerns/milestoneish_spec.rb | 4 +-- spec/models/concerns/resolvable_discussion_spec.rb | 2 +- spec/models/event_spec.rb | 4 +-- spec/models/generic_commit_status_spec.rb | 2 +- spec/models/hooks/system_hook_spec.rb | 4 +-- spec/models/issue_collection_spec.rb | 2 +- spec/models/issue_spec.rb | 14 ++++----- spec/models/member_spec.rb | 8 ++--- spec/models/members/project_member_spec.rb | 8 ++--- spec/models/merge_request_spec.rb | 12 ++++---- spec/models/note_spec.rb | 2 +- spec/models/project_feature_spec.rb | 2 +- .../pipelines_email_service_spec.rb | 2 +- spec/models/project_spec.rb | 14 ++++----- spec/models/project_team_spec.rb | 4 +-- spec/models/user_spec.rb | 26 ++++++++-------- spec/policies/ci/build_policy_spec.rb | 4 +-- spec/policies/ci/trigger_policy_spec.rb | 10 +++--- spec/policies/issue_policy_spec.rb | 12 ++++---- spec/policies/project_snippet_policy_spec.rb | 6 ++-- spec/presenters/merge_request_presenter_spec.rb | 8 ++--- spec/requests/api/access_requests_spec.rb | 4 +-- spec/requests/api/award_emoji_spec.rb | 2 +- spec/requests/api/boards_spec.rb | 4 +-- spec/requests/api/deployments_spec.rb | 2 +- spec/requests/api/environments_spec.rb | 2 +- spec/requests/api/files_spec.rb | 2 +- spec/requests/api/groups_spec.rb | 2 +- spec/requests/api/internal_spec.rb | 16 +++++----- spec/requests/api/issues_spec.rb | 8 ++--- spec/requests/api/jobs_spec.rb | 2 +- spec/requests/api/labels_spec.rb | 2 +- spec/requests/api/members_spec.rb | 4 +-- spec/requests/api/merge_request_diffs_spec.rb | 2 +- spec/requests/api/merge_requests_spec.rb | 12 ++++---- spec/requests/api/notes_spec.rb | 4 +-- spec/requests/api/pipelines_spec.rb | 4 +-- spec/requests/api/project_hooks_spec.rb | 6 ++-- spec/requests/api/project_milestones_spec.rb | 2 +- spec/requests/api/projects_spec.rb | 10 +++--- spec/requests/api/services_spec.rb | 2 +- spec/requests/api/todos_spec.rb | 6 ++-- spec/requests/api/v3/award_emoji_spec.rb | 2 +- spec/requests/api/v3/boards_spec.rb | 4 +-- spec/requests/api/v3/commits_spec.rb | 8 ++--- spec/requests/api/v3/deployments_spec.rb | 2 +- spec/requests/api/v3/environments_spec.rb | 2 +- spec/requests/api/v3/files_spec.rb | 2 +- spec/requests/api/v3/groups_spec.rb | 2 +- spec/requests/api/v3/issues_spec.rb | 8 ++--- spec/requests/api/v3/labels_spec.rb | 2 +- spec/requests/api/v3/members_spec.rb | 4 +-- spec/requests/api/v3/merge_request_diffs_spec.rb | 2 +- spec/requests/api/v3/merge_requests_spec.rb | 12 ++++---- spec/requests/api/v3/milestones_spec.rb | 6 ++-- spec/requests/api/v3/notes_spec.rb | 4 +-- spec/requests/api/v3/pipelines_spec.rb | 4 +-- spec/requests/api/v3/project_hooks_spec.rb | 6 ++-- spec/requests/api/v3/projects_spec.rb | 10 +++--- spec/requests/api/v3/todos_spec.rb | 4 +-- spec/requests/git_http_spec.rb | 16 +++++----- spec/requests/lfs_http_spec.rb | 30 +++++++++--------- .../projects/cycle_analytics_events_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/lists/create_service_spec.rb | 2 +- .../services/boards/lists/generate_service_spec.rb | 2 +- spec/services/ci/stop_environments_service_spec.rb | 6 ++-- spec/services/delete_branch_service_spec.rb | 2 +- spec/services/discussions/resolve_service_spec.rb | 2 +- spec/services/files/delete_service_spec.rb | 2 +- spec/services/files/multi_service_spec.rb | 2 +- spec/services/files/update_service_spec.rb | 2 +- spec/services/git_push_service_spec.rb | 12 ++++---- spec/services/git_tag_push_service_spec.rb | 2 +- spec/services/issuable/bulk_update_service_spec.rb | 8 ++--- spec/services/issues/build_service_spec.rb | 2 +- spec/services/issues/close_service_spec.rb | 6 ++-- spec/services/issues/create_service_spec.rb | 18 +++++------ spec/services/issues/move_service_spec.rb | 16 +++++----- spec/services/issues/reopen_service_spec.rb | 4 +-- spec/services/issues/resolve_discussions_spec.rb | 2 +- spec/services/issues/update_service_spec.rb | 12 ++++---- .../services/labels/find_or_create_service_spec.rb | 2 +- .../members/approve_access_request_service_spec.rb | 2 +- .../members/authorized_destroy_service_spec.rb | 4 +-- spec/services/members/create_service_spec.rb | 2 +- spec/services/members/destroy_service_spec.rb | 4 +-- .../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 | 6 ++-- .../services/merge_requests/create_service_spec.rb | 18 +++++------ .../merge_requests/ff_merge_service_spec.rb | 4 +-- .../merge_requests/post_merge_service_spec.rb | 2 +- .../merge_requests/refresh_service_spec.rb | 4 +-- .../services/merge_requests/reopen_service_spec.rb | 6 ++-- .../services/merge_requests/update_service_spec.rb | 10 +++--- 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/notes/create_service_spec.rb | 2 +- spec/services/notes/post_process_service_spec.rb | 2 +- spec/services/notes/quick_actions_service_spec.rb | 10 +++--- spec/services/notes/update_service_spec.rb | 6 ++-- .../services/projects/autocomplete_service_spec.rb | 4 +-- .../quick_actions/interpret_service_spec.rb | 4 +-- spec/services/search/snippet_service_spec.rb | 2 +- spec/services/todo_service_spec.rb | 10 +++--- spec/support/api/milestones_shared_examples.rb | 4 +-- .../issuable_slash_commands_shared_examples.rb | 2 +- spec/support/markdown_feature.rb | 4 +-- spec/support/mentionable_shared_examples.rb | 2 +- spec/support/reference_parser_shared_examples.rb | 2 +- ...reate_service_slash_commands_shared_examples.rb | 4 +-- spec/support/updating_mentions_shared_examples.rb | 2 +- spec/views/projects/imports/new.html.haml_spec.rb | 2 +- spec/views/shared/notes/_form.html.haml_spec.rb | 2 +- spec/workers/merge_worker_spec.rb | 2 +- 371 files changed, 792 insertions(+), 799 deletions(-) create mode 100644 changelogs/unreleased/36782-replace-team-user-role-with-add_role-user-in-specs.yml diff --git a/app/models/project.rb b/app/models/project.rb index 3440c01b356..6f946f6edc7 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -226,7 +226,7 @@ class Project < ActiveRecord::Base delegate :name, to: :owner, allow_nil: true, prefix: true delegate :members, to: :team, prefix: true delegate :add_user, :add_users, to: :team - delegate :add_guest, :add_reporter, :add_developer, :add_master, to: :team + delegate :add_guest, :add_reporter, :add_developer, :add_master, :add_role, to: :team # Validations validates :creator, presence: true, on: :create diff --git a/app/models/project_team.rb b/app/models/project_team.rb index c679758973a..a9e5cfb8240 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -7,36 +7,24 @@ class ProjectTeam @project = project end - # Shortcut to add users - # - # Use: - # @team << [@user, :master] - # @team << [@users, :master] - # - def <<(args) - users, access, current_user = *args - - if users.respond_to?(:each) - add_users(users, access, current_user: current_user) - else - add_user(users, access, current_user: current_user) - end - end - def add_guest(user, current_user: nil) - self << [user, :guest, current_user] + add_user(user, :guest, current_user: current_user) end def add_reporter(user, current_user: nil) - self << [user, :reporter, current_user] + add_user(user, :reporter, current_user: current_user) end def add_developer(user, current_user: nil) - self << [user, :developer, current_user] + add_user(user, :developer, current_user: current_user) end def add_master(user, current_user: nil) - self << [user, :master, current_user] + add_user(user, :master, current_user: current_user) + end + + def add_role(user, role, current_user: nil) + send(:"add_#{role}", user, current_user: current_user) # rubocop:disable GitlabSecurity/PublicSend end def find_member(user_id) diff --git a/changelogs/unreleased/36782-replace-team-user-role-with-add_role-user-in-specs.yml b/changelogs/unreleased/36782-replace-team-user-role-with-add_role-user-in-specs.yml new file mode 100644 index 00000000000..8773ac73a75 --- /dev/null +++ b/changelogs/unreleased/36782-replace-team-user-role-with-add_role-user-in-specs.yml @@ -0,0 +1,5 @@ +--- +title: Replace '.team << [user, role]' with 'add_role(user)' in specs +merge_request: 16069 +author: "@blackst0ne" +type: other diff --git a/db/fixtures/development/06_teams.rb b/db/fixtures/development/06_teams.rb index 86e0a38aae1..8afb0dde077 100644 --- a/db/fixtures/development/06_teams.rb +++ b/db/fixtures/development/06_teams.rb @@ -14,7 +14,7 @@ Sidekiq::Testing.inline! do Project.all.each do |project| User.all.sample(4).each do |user| - if project.team << [user, Gitlab::Access.values.sample] + if project.add_role(user, Gitlab::Access.values.sample) print '.' else print 'F' diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb index 4b88cb5e27f..d3b88ae8d2a 100644 --- a/features/steps/profile/profile.rb +++ b/features/steps/profile/profile.rb @@ -165,7 +165,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps @project = create(:project, :repository, namespace: @group) @event = create(:closed_issue_event, project: @project) - @project.team << [current_user, :master] + @project.add_master(current_user) end step 'I should see groups I belong to' do diff --git a/features/steps/project/deploy_keys.rb b/features/steps/project/deploy_keys.rb index b4403becb0d..9db31522c5c 100644 --- a/features/steps/project/deploy_keys.rb +++ b/features/steps/project/deploy_keys.rb @@ -48,11 +48,11 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps step 'other projects have deploy keys' do @second_project = create(:project, namespace: create(:group)) - @second_project.team << [current_user, :master] + @second_project.add_master(current_user) create(:deploy_keys_project, project: @second_project) @third_project = create(:project, namespace: create(:group)) - @third_project.team << [current_user, :master] + @third_project.add_master(current_user) create(:deploy_keys_project, project: @third_project, deploy_key: @second_project.deploy_keys.first) end diff --git a/features/steps/project/fork.rb b/features/steps/project/fork.rb index 60707f26aee..0350e1c2aef 100644 --- a/features/steps/project/fork.rb +++ b/features/steps/project/fork.rb @@ -10,7 +10,7 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps step 'I am a member of project "Shop"' do @project = create(:project, :repository, name: "Shop") - @project.team << [@user, :reporter] + @project.add_reporter(@user) end step 'I should see the forked project page' do @@ -71,7 +71,7 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps step 'There is an existent fork of the "Shop" project' do user = create(:user, name: 'Mike') - @project.team << [user, :reporter] + @project.add_reporter(user) @forked_project = Projects::ForkService.new(@project, user).execute end diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb index 6781a906a94..fd51ee1a316 100644 --- a/features/steps/project/forked_merge_requests.rb +++ b/features/steps/project/forked_merge_requests.rb @@ -10,7 +10,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps step 'I am a member of project "Shop"' do @project = ::Project.find_by(name: "Shop") @project ||= create(:project, :repository, name: "Shop") - @project.team << [@user, :reporter] + @project.add_reporter(@user) end step 'I have a project forked off of "Shop" called "Forked Shop"' do diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb index 93b057430d3..afaad4b255e 100644 --- a/features/steps/project/source/browse_files.rb +++ b/features/steps/project/source/browse_files.rb @@ -8,7 +8,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps step "I don't have write access" do @project = create(:project, :repository, name: "Other Project", path: "other-project") - @project.team << [@user, :reporter] + @project.add_reporter(@user) visit project_tree_path(@project, root_ref) end diff --git a/features/steps/project/source/markdown_render.rb b/features/steps/project/source/markdown_render.rb index f6445b57ec0..fc4ef26f6b6 100644 --- a/features/steps/project/source/markdown_render.rb +++ b/features/steps/project/source/markdown_render.rb @@ -10,7 +10,7 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps step 'I own project "Delta"' do @project = ::Project.find_by(name: "Delta") @project ||= create(:project, :repository, name: "Delta", namespace: @user.namespace) - @project.team << [@user, :master] + @project.add_master(@user) end step 'I should see files from repository in markdown' do diff --git a/features/steps/shared/group.rb b/features/steps/shared/group.rb index 03bc7e798e0..0a0588346b1 100644 --- a/features/steps/shared/group.rb +++ b/features/steps/shared/group.rb @@ -41,7 +41,7 @@ module SharedGroup group.add_user(user, role) project ||= create(:project, :repository, namespace: group) create(:closed_issue_event, project: project) - project.team << [user, :master] + project.add_master(user) end def owned_group diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb index 5e4edaf99a6..affbccccdf9 100644 --- a/features/steps/shared/project.rb +++ b/features/steps/shared/project.rb @@ -4,13 +4,13 @@ module SharedProject # Create a project without caring about what it's called step "I own a project" do @project = create(:project, :repository, namespace: @user.namespace) - @project.team << [@user, :master] + @project.add_master(@user) end step "I own a project in some group namespace" do @group = create(:group, name: 'some group') @project = create(:project, namespace: @group) - @project.team << [@user, :master] + @project.add_master(@user) end step "project exists in some group namespace" do @@ -22,7 +22,7 @@ module SharedProject step 'I own project "Shop"' do @project = Project.find_by(name: "Shop") @project ||= create(:project, :repository, name: "Shop", namespace: @user.namespace) - @project.team << [@user, :master] + @project.add_master(@user) end step 'I disable snippets in project' do @@ -40,7 +40,7 @@ module SharedProject step 'I add a user to project "Shop"' do @project = Project.find_by(name: "Shop") other_user = create(:user, name: 'Alpha') - @project.team << [other_user, :master] + @project.add_master(other_user) end # Create another specific project called "Forum" @@ -49,14 +49,13 @@ module SharedProject @project ||= create(:project, :repository, name: "Forum", namespace: @user.namespace, path: 'forum_project') @project.build_project_feature @project.project_feature.save - @project.team << [@user, :master] + @project.add_master(@user) end # Create an empty project without caring about the name step 'I own an empty project' do - @project = create(:project, - name: 'Empty Project', namespace: @user.namespace) - @project.team << [@user, :master] + @project = create(:project, name: 'Empty Project', namespace: @user.namespace) + @project.add_master(@user) end step 'I visit my empty project page' do @@ -101,11 +100,11 @@ module SharedProject # ---------------------------------------- step 'I am member of a project with a guest role' do - @project.team << [@user, Gitlab::Access::GUEST] + @project.add_guest(@user) end step 'I am member of a project with a reporter role' do - @project.team << [@user, Gitlab::Access::REPORTER] + @project.add_reporter(@user) end # ---------------------------------------- @@ -245,6 +244,6 @@ module SharedProject user = user_exists(user_name, username: user_name.gsub(/\s/, '').underscore) project = Project.find_by(name: project_name) project ||= create(:project, visibility, name: project_name, namespace: user.namespace) - project.team << [user, :master] + project.add_master(user) end end diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index f044a068938..f350641a643 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -13,7 +13,7 @@ describe Admin::UsersController do let!(:issue) { create(:issue, author: user) } before do - project.team << [user, :developer] + project.add_developer(user) end it 'deletes user and ghosts their contributions' do diff --git a/spec/controllers/boards/issues_controller_spec.rb b/spec/controllers/boards/issues_controller_spec.rb index 44d504d5852..79bbc29e80d 100644 --- a/spec/controllers/boards/issues_controller_spec.rb +++ b/spec/controllers/boards/issues_controller_spec.rb @@ -13,8 +13,8 @@ describe Boards::IssuesController do let!(:list2) { create(:list, board: board, label: development, position: 1) } before do - project.team << [user, :master] - project.team << [guest, :guest] + project.add_master(user) + project.add_guest(guest) end describe 'GET index' do @@ -221,7 +221,7 @@ describe Boards::IssuesController do let(:guest) { create(:user) } before do - project.team << [guest, :guest] + project.add_guest(guest) end it 'returns a forbidden 403 response' do diff --git a/spec/controllers/boards/lists_controller_spec.rb b/spec/controllers/boards/lists_controller_spec.rb index a2b432af23a..71d45a22d91 100644 --- a/spec/controllers/boards/lists_controller_spec.rb +++ b/spec/controllers/boards/lists_controller_spec.rb @@ -7,8 +7,8 @@ describe Boards::ListsController do let(:guest) { create(:user) } before do - project.team << [user, :master] - project.team << [guest, :guest] + project.add_master(user) + project.add_guest(guest) end describe 'GET index' do diff --git a/spec/controllers/dashboard/milestones_controller_spec.rb b/spec/controllers/dashboard/milestones_controller_spec.rb index 2f3d7be9abe..60547db82b6 100644 --- a/spec/controllers/dashboard/milestones_controller_spec.rb +++ b/spec/controllers/dashboard/milestones_controller_spec.rb @@ -17,7 +17,7 @@ describe Dashboard::MilestonesController do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) end it_behaves_like 'milestone tabs' diff --git a/spec/controllers/dashboard/todos_controller_spec.rb b/spec/controllers/dashboard/todos_controller_spec.rb index f9faa4fa59a..b4a731fd3a3 100644 --- a/spec/controllers/dashboard/todos_controller_spec.rb +++ b/spec/controllers/dashboard/todos_controller_spec.rb @@ -8,7 +8,7 @@ describe Dashboard::TodosController do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end describe 'GET #index' do diff --git a/spec/controllers/dashboard_controller_spec.rb b/spec/controllers/dashboard_controller_spec.rb index 566d8515198..97c2c3fb940 100644 --- a/spec/controllers/dashboard_controller_spec.rb +++ b/spec/controllers/dashboard_controller_spec.rb @@ -5,7 +5,7 @@ describe DashboardController do let(:project) { create(:project) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/controllers/groups/milestones_controller_spec.rb b/spec/controllers/groups/milestones_controller_spec.rb index c1aba46be04..733386500ca 100644 --- a/spec/controllers/groups/milestones_controller_spec.rb +++ b/spec/controllers/groups/milestones_controller_spec.rb @@ -28,7 +28,7 @@ describe Groups::MilestonesController do before do sign_in(user) group.add_owner(user) - project.team << [user, :master] + project.add_master(user) end describe '#index' do diff --git a/spec/controllers/notification_settings_controller_spec.rb b/spec/controllers/notification_settings_controller_spec.rb index 9014b8b5084..e133950e684 100644 --- a/spec/controllers/notification_settings_controller_spec.rb +++ b/spec/controllers/notification_settings_controller_spec.rb @@ -6,7 +6,7 @@ describe NotificationSettingsController do let(:user) { create(:user) } before do - project.team << [user, :developer] + project.add_developer(user) end describe '#create' do diff --git a/spec/controllers/projects/avatars_controller_spec.rb b/spec/controllers/projects/avatars_controller_spec.rb index f5ea097af8b..3bbe168f6d5 100644 --- a/spec/controllers/projects/avatars_controller_spec.rb +++ b/spec/controllers/projects/avatars_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::AvatarsController do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) controller.instance_variable_set(:@project, project) end diff --git a/spec/controllers/projects/blame_controller_spec.rb b/spec/controllers/projects/blame_controller_spec.rb index 54282aa4001..88d4f4e9cd0 100644 --- a/spec/controllers/projects/blame_controller_spec.rb +++ b/spec/controllers/projects/blame_controller_spec.rb @@ -7,7 +7,7 @@ describe Projects::BlameController do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) controller.instance_variable_set(:@project, project) end diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb index 6a1c07b4a0b..00a7df6ccc8 100644 --- a/spec/controllers/projects/blob_controller_spec.rb +++ b/spec/controllers/projects/blob_controller_spec.rb @@ -89,7 +89,7 @@ describe Projects::BlobController do end before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end @@ -147,7 +147,7 @@ describe Projects::BlobController do let(:developer) { create(:user) } before do - project.team << [developer, :developer] + project.add_developer(developer) sign_in(developer) get :edit, default_params end @@ -161,7 +161,7 @@ describe Projects::BlobController do let(:master) { create(:user) } before do - project.team << [master, :master] + project.add_master(master) sign_in(master) get :edit, default_params end @@ -190,7 +190,7 @@ describe Projects::BlobController do end before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/controllers/projects/boards_controller_spec.rb b/spec/controllers/projects/boards_controller_spec.rb index d6ccb92c54b..305af289531 100644 --- a/spec/controllers/projects/boards_controller_spec.rb +++ b/spec/controllers/projects/boards_controller_spec.rb @@ -5,7 +5,7 @@ describe Projects::BoardsController do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb index d731200f70f..91894661ccb 100644 --- a/spec/controllers/projects/branches_controller_spec.rb +++ b/spec/controllers/projects/branches_controller_spec.rb @@ -6,8 +6,8 @@ describe Projects::BranchesController do let(:developer) { create(:user) } before do - project.team << [user, :master] - project.team << [user, :developer] + project.add_master(user) + project.add_developer(user) allow(project).to receive(:branches).and_return(['master', 'foo/bar/baz']) allow(project).to receive(:tags).and_return(['v1.0.0', 'v2.0.0']) diff --git a/spec/controllers/projects/commits_controller_spec.rb b/spec/controllers/projects/commits_controller_spec.rb index c459d732507..73fb90d73ec 100644 --- a/spec/controllers/projects/commits_controller_spec.rb +++ b/spec/controllers/projects/commits_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::CommitsController do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) end describe "GET show" do diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb index fe5818da0bc..046ce027965 100644 --- a/spec/controllers/projects/compare_controller_spec.rb +++ b/spec/controllers/projects/compare_controller_spec.rb @@ -8,7 +8,7 @@ describe Projects::CompareController do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) end it 'compare shows some diffs' do diff --git a/spec/controllers/projects/cycle_analytics_controller_spec.rb b/spec/controllers/projects/cycle_analytics_controller_spec.rb index 6fae52edbad..7c708a418a7 100644 --- a/spec/controllers/projects/cycle_analytics_controller_spec.rb +++ b/spec/controllers/projects/cycle_analytics_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::CycleAnalyticsController do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) end describe 'cycle analytics not set up flag' do diff --git a/spec/controllers/projects/deploy_keys_controller_spec.rb b/spec/controllers/projects/deploy_keys_controller_spec.rb index c3208357694..97db69427e9 100644 --- a/spec/controllers/projects/deploy_keys_controller_spec.rb +++ b/spec/controllers/projects/deploy_keys_controller_spec.rb @@ -5,7 +5,7 @@ describe Projects::DeployKeysController do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end @@ -48,7 +48,7 @@ describe Projects::DeployKeysController do end before do - project2.team << [user, :developer] + project2.add_developer(user) end it 'returns json in a correct format' do diff --git a/spec/controllers/projects/deployments_controller_spec.rb b/spec/controllers/projects/deployments_controller_spec.rb index 3164fd5c143..73e7921fab7 100644 --- a/spec/controllers/projects/deployments_controller_spec.rb +++ b/spec/controllers/projects/deployments_controller_spec.rb @@ -8,7 +8,7 @@ describe Projects::DeploymentsController do let(:environment) { create(:environment, name: 'production', project: project) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/controllers/projects/discussions_controller_spec.rb b/spec/controllers/projects/discussions_controller_spec.rb index 3bf676637a2..00328d3ea51 100644 --- a/spec/controllers/projects/discussions_controller_spec.rb +++ b/spec/controllers/projects/discussions_controller_spec.rb @@ -31,7 +31,7 @@ describe Projects::DiscussionsController do context "when the user is authorized to resolve the discussion" do before do - project.team << [user, :developer] + project.add_developer(user) end context "when the discussion is not resolvable" do @@ -92,7 +92,7 @@ describe Projects::DiscussionsController do context "when the user is authorized to resolve the discussion" do before do - project.team << [user, :developer] + project.add_developer(user) end context "when the discussion is not resolvable" do diff --git a/spec/controllers/projects/find_file_controller_spec.rb b/spec/controllers/projects/find_file_controller_spec.rb index 6a5433bcc9c..505fe82851a 100644 --- a/spec/controllers/projects/find_file_controller_spec.rb +++ b/spec/controllers/projects/find_file_controller_spec.rb @@ -7,7 +7,7 @@ describe Projects::FindFileController do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) controller.instance_variable_set(:@project, project) end diff --git a/spec/controllers/projects/forks_controller_spec.rb b/spec/controllers/projects/forks_controller_spec.rb index 1bedb8ebdff..c4b32dc3a09 100644 --- a/spec/controllers/projects/forks_controller_spec.rb +++ b/spec/controllers/projects/forks_controller_spec.rb @@ -51,7 +51,7 @@ describe Projects::ForksController do context 'when user is a member of the Project' do before do - forked_project.team << [project.creator, :developer] + forked_project.add_developer(project.creator) end it 'sees the project listed' do diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb index 5af03ae118c..c3605555fe7 100644 --- a/spec/controllers/projects/graphs_controller_spec.rb +++ b/spec/controllers/projects/graphs_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::GraphsController do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) end describe 'GET languages' do diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb index f8c792cd0f0..5bfc3d31401 100644 --- a/spec/controllers/projects/group_links_controller_spec.rb +++ b/spec/controllers/projects/group_links_controller_spec.rb @@ -7,7 +7,7 @@ describe Projects::GroupLinksController do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/controllers/projects/hooks_controller_spec.rb b/spec/controllers/projects/hooks_controller_spec.rb index 07174660f46..aba70c6d4c1 100644 --- a/spec/controllers/projects/hooks_controller_spec.rb +++ b/spec/controllers/projects/hooks_controller_spec.rb @@ -5,7 +5,7 @@ describe Projects::HooksController do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/controllers/projects/imports_controller_spec.rb b/spec/controllers/projects/imports_controller_spec.rb index 2a5ec6d584b..7fb4c1b7425 100644 --- a/spec/controllers/projects/imports_controller_spec.rb +++ b/spec/controllers/projects/imports_controller_spec.rb @@ -9,7 +9,7 @@ describe Projects::ImportsController do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) end it 'renders template' do @@ -30,7 +30,7 @@ describe Projects::ImportsController do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) end context 'when import is in progress' do diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index a2ef937609b..6b7db947216 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -37,7 +37,7 @@ describe Projects::IssuesController do context 'internal issue tracker' do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end it_behaves_like "issuables list meta-data", :issue @@ -69,7 +69,7 @@ describe Projects::IssuesController do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) allow(Kaminari.config).to receive(:default_per_page).and_return(1) end @@ -116,7 +116,7 @@ describe Projects::IssuesController do context 'internal issue tracker' do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end it 'builds a new issue' do @@ -127,7 +127,7 @@ describe Projects::IssuesController do it 'fills in an issue for a merge request' do project_with_repository = create(:project, :repository) - project_with_repository.team << [user, :developer] + project_with_repository.add_developer(user) mr = create(:merge_request_with_diff_notes, source_project: project_with_repository) get :new, namespace_id: project_with_repository.namespace, project_id: project_with_repository, merge_request_to_resolve_discussions_of: mr.iid @@ -153,7 +153,7 @@ describe Projects::IssuesController do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) external = double allow(project).to receive(:external_issue_tracker).and_return(external) @@ -329,7 +329,7 @@ describe Projects::IssuesController do it 'does not list confidential issues for project members with guest role' do sign_in(member) - project.team << [member, :guest] + project.add_guest(member) get_issues @@ -354,7 +354,7 @@ describe Projects::IssuesController do it 'lists confidential issues for project members' do sign_in(member) - project.team << [member, :developer] + project.add_developer(member) get_issues @@ -394,7 +394,7 @@ describe Projects::IssuesController do it 'returns 404 for project members with guest role' do sign_in(member) - project.team << [member, :guest] + project.add_guest(member) go(id: unescaped_parameter_value.to_param) expect(response).to have_gitlab_http_status :not_found @@ -416,7 +416,7 @@ describe Projects::IssuesController do it "returns #{http_status[:success]} for project members" do sign_in(member) - project.team << [member, :developer] + project.add_developer(member) go(id: unescaped_parameter_value.to_param) expect(response).to have_gitlab_http_status http_status[:success] @@ -450,7 +450,7 @@ describe Projects::IssuesController do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end it_behaves_like 'restricted action', success: 200 @@ -594,7 +594,7 @@ describe Projects::IssuesController do let(:deleted_user) { create(:user) } before do - project.team << [user, :developer] + project.add_developer(user) issue.update!(last_edited_by: deleted_user, last_edited_at: Time.now) @@ -638,7 +638,7 @@ describe Projects::IssuesController do def post_new_issue(issue_attrs = {}, additional_params = {}) sign_in(user) project = create(:project, :public) - project.team << [user, :developer] + project.add_developer(user) post :create, { namespace_id: project.namespace.to_param, @@ -655,7 +655,7 @@ describe Projects::IssuesController do let(:project) { merge_request.source_project } before do - project.team << [user, :master] + project.add_master(user) sign_in user end @@ -829,7 +829,7 @@ describe Projects::IssuesController do def post_spam admin = create(:admin) create(:user_agent_detail, subject: issue) - project.team << [admin, :master] + project.add_master(admin) sign_in(admin) post :mark_as_spam, { namespace_id: project.namespace, diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index 7490f8fefce..e6a4e7c8257 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -374,7 +374,7 @@ describe Projects::JobsController do let(:role) { :master } before do - project.team << [user, role] + project.add_role(user, role) sign_in(user) post_erase diff --git a/spec/controllers/projects/labels_controller_spec.rb b/spec/controllers/projects/labels_controller_spec.rb index cf83f2f3265..452d7e23983 100644 --- a/spec/controllers/projects/labels_controller_spec.rb +++ b/spec/controllers/projects/labels_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::LabelsController do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/controllers/projects/mattermosts_controller_spec.rb b/spec/controllers/projects/mattermosts_controller_spec.rb index 33d48ff94d1..c5ac0be27bb 100644 --- a/spec/controllers/projects/mattermosts_controller_spec.rb +++ b/spec/controllers/projects/mattermosts_controller_spec.rb @@ -5,7 +5,7 @@ describe Projects::MattermostsController do let!(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/controllers/projects/merge_requests/creations_controller_spec.rb b/spec/controllers/projects/merge_requests/creations_controller_spec.rb index 7fdddc02fd3..7e2366847f4 100644 --- a/spec/controllers/projects/merge_requests/creations_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/creations_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::MergeRequests::CreationsController do let(:fork_project) { create(:forked_project_with_submodules) } before do - fork_project.team << [user, :master] + fork_project.add_master(user) sign_in(user) end @@ -86,7 +86,7 @@ describe Projects::MergeRequests::CreationsController do let(:other_project) { create(:project, :repository) } before do - other_project.team << [user, :master] + other_project.add_master(user) end context 'when the path exists in the diff' do diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb index ba97ccfbbd4..5d297c654bf 100644 --- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb @@ -151,7 +151,7 @@ describe Projects::MergeRequests::DiffsController do let(:other_project) { create(:project) } before do - other_project.team << [user, :master] + other_project.add_master(user) diff_for_path(old_path: existing_path, new_path: existing_path, project_id: other_project) end diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb index 209979e642d..00cf464ec5b 100644 --- a/spec/controllers/projects/milestones_controller_spec.rb +++ b/spec/controllers/projects/milestones_controller_spec.rb @@ -11,7 +11,7 @@ describe Projects::MilestonesController do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) controller.instance_variable_set(:@project, project) end diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb index 37e9f863fc4..de132dfaa21 100644 --- a/spec/controllers/projects/notes_controller_spec.rb +++ b/spec/controllers/projects/notes_controller_spec.rb @@ -32,7 +32,7 @@ describe Projects::NotesController do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end it 'passes last_fetched_at from headers to NotesFinder' do @@ -351,7 +351,7 @@ describe Projects::NotesController do before do sign_in(note.author) - project.team << [note.author, :developer] + project.add_developer(note.author) end it "updates the note" do @@ -372,7 +372,7 @@ describe Projects::NotesController do context 'user is the author of a note' do before do sign_in(note.author) - project.team << [note.author, :developer] + project.add_developer(note.author) end it "returns status 200 for html" do @@ -389,7 +389,7 @@ describe Projects::NotesController do context 'user is not the author of a note' do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end it "returns status 404" do @@ -403,7 +403,7 @@ describe Projects::NotesController do describe 'POST toggle_award_emoji' do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end it "toggles the award emoji" do @@ -445,7 +445,7 @@ describe Projects::NotesController do context "when the user is authorized to resolve the note" do before do - project.team << [user, :developer] + project.add_developer(user) end context "when the note is not resolvable" do @@ -506,7 +506,7 @@ describe Projects::NotesController do context "when the user is authorized to resolve the note" do before do - project.team << [user, :developer] + project.add_developer(user) end context "when the note is not resolvable" do diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb index 290dba0610a..46b08a03b19 100644 --- a/spec/controllers/projects/project_members_controller_spec.rb +++ b/spec/controllers/projects/project_members_controller_spec.rb @@ -21,7 +21,7 @@ describe Projects::ProjectMembersController do context 'when user does not have enough rights' do before do - project.team << [user, :developer] + project.add_developer(user) end it 'returns 404' do @@ -37,7 +37,7 @@ describe Projects::ProjectMembersController do context 'when user has enough rights' do before do - project.team << [user, :master] + project.add_master(user) end it 'adds user to members' do @@ -106,7 +106,7 @@ describe Projects::ProjectMembersController do context 'when member is found' do context 'when user does not have enough rights' do before do - project.team << [user, :developer] + project.add_developer(user) end it 'returns 404' do @@ -121,7 +121,7 @@ describe Projects::ProjectMembersController do context 'when user has enough rights' do before do - project.team << [user, :master] + project.add_master(user) end it '[HTML] removes user from members' do @@ -164,7 +164,7 @@ describe Projects::ProjectMembersController do context 'when member is found' do context 'and is not an owner' do before do - project.team << [user, :developer] + project.add_developer(user) end it 'removes user from members' do @@ -181,7 +181,7 @@ describe Projects::ProjectMembersController do let(:project) { create(:project, namespace: user.namespace) } before do - project.team << [user, :master] + project.add_master(user) end it 'cannot remove himself from the project' do @@ -248,7 +248,7 @@ describe Projects::ProjectMembersController do context 'when member is found' do context 'when user does not have enough rights' do before do - project.team << [user, :developer] + project.add_developer(user) end it 'returns 404' do @@ -263,7 +263,7 @@ describe Projects::ProjectMembersController do context 'when user has enough rights' do before do - project.team << [user, :master] + project.add_master(user) end it 'adds user to members' do @@ -285,8 +285,8 @@ describe Projects::ProjectMembersController do let(:member) { create(:user) } before do - project.team << [user, :master] - another_project.team << [member, :guest] + project.add_master(user) + another_project.add_guest(member) sign_in(user) end @@ -300,7 +300,7 @@ describe Projects::ProjectMembersController do context 'when user can access source project members' do before do - another_project.team << [user, :guest] + another_project.add_guest(user) end include_context 'import applied' @@ -332,7 +332,7 @@ describe Projects::ProjectMembersController do context 'when creating owner' do before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end @@ -348,7 +348,7 @@ describe Projects::ProjectMembersController do context 'when create master' do before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/controllers/projects/refs_controller_spec.rb b/spec/controllers/projects/refs_controller_spec.rb index 748ae040928..ceaffd92623 100644 --- a/spec/controllers/projects/refs_controller_spec.rb +++ b/spec/controllers/projects/refs_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::RefsController do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end describe 'GET #logs_tree' do diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb index 358f26dfb02..fc1619acec6 100644 --- a/spec/controllers/projects/releases_controller_spec.rb +++ b/spec/controllers/projects/releases_controller_spec.rb @@ -7,7 +7,7 @@ describe Projects::ReleasesController do let!(:tag) { release.tag } before do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) end diff --git a/spec/controllers/projects/repositories_controller_spec.rb b/spec/controllers/projects/repositories_controller_spec.rb index 8b777eb68ca..04d16e98913 100644 --- a/spec/controllers/projects/repositories_controller_spec.rb +++ b/spec/controllers/projects/repositories_controller_spec.rb @@ -17,7 +17,7 @@ describe Projects::RepositoriesController do let(:user) { create(:user) } before do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) end diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb index a907da2b60f..2c6ad00515e 100644 --- a/spec/controllers/projects/services_controller_spec.rb +++ b/spec/controllers/projects/services_controller_spec.rb @@ -9,7 +9,7 @@ describe Projects::ServicesController do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) end describe '#test' do diff --git a/spec/controllers/projects/settings/ci_cd_controller_spec.rb b/spec/controllers/projects/settings/ci_cd_controller_spec.rb index b8fe0f46f57..77a47f0ad13 100644 --- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb +++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb @@ -5,7 +5,7 @@ describe Projects::Settings::CiCdController do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/controllers/projects/settings/integrations_controller_spec.rb b/spec/controllers/projects/settings/integrations_controller_spec.rb index 3068837f394..77df9a6f567 100644 --- a/spec/controllers/projects/settings/integrations_controller_spec.rb +++ b/spec/controllers/projects/settings/integrations_controller_spec.rb @@ -5,7 +5,7 @@ describe Projects::Settings::IntegrationsController do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/controllers/projects/templates_controller_spec.rb b/spec/controllers/projects/templates_controller_spec.rb index 70e7f9ca96e..8fcfa3c9ecd 100644 --- a/spec/controllers/projects/templates_controller_spec.rb +++ b/spec/controllers/projects/templates_controller_spec.rb @@ -8,7 +8,7 @@ describe Projects::TemplatesController do let(:body) { JSON.parse(response.body) } before do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) end diff --git a/spec/controllers/projects/todos_controller_spec.rb b/spec/controllers/projects/todos_controller_spec.rb index 4622e27e60f..e2524be7724 100644 --- a/spec/controllers/projects/todos_controller_spec.rb +++ b/spec/controllers/projects/todos_controller_spec.rb @@ -20,7 +20,7 @@ describe Projects::TodosController do context 'when authorized' do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end it 'creates todo for issue' do @@ -88,7 +88,7 @@ describe Projects::TodosController do context 'when authorized' do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end it 'creates todo for merge request' do diff --git a/spec/controllers/projects/tree_controller_spec.rb b/spec/controllers/projects/tree_controller_spec.rb index 65b821c9486..d3188f054cf 100644 --- a/spec/controllers/projects/tree_controller_spec.rb +++ b/spec/controllers/projects/tree_controller_spec.rb @@ -7,7 +7,7 @@ describe Projects::TreeController do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) controller.instance_variable_set(:@project, project) end diff --git a/spec/controllers/projects/variables_controller_spec.rb b/spec/controllers/projects/variables_controller_spec.rb index d065cd00d00..9fde6544215 100644 --- a/spec/controllers/projects/variables_controller_spec.rb +++ b/spec/controllers/projects/variables_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::VariablesController do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) end describe 'POST #create' do diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index e61187fb518..5202ffdd8bb 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -102,7 +102,7 @@ describe ProjectsController do render_views before do - project.team << [user, :developer] + project.add_developer(user) project.project_feature.update_attribute(:repository_access_level, ProjectFeature::DISABLED) end @@ -437,7 +437,7 @@ describe ProjectsController do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) allow(Gitlab.config.incoming_email).to receive(:enabled).and_return(true) end @@ -465,7 +465,7 @@ describe ProjectsController do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) allow(Gitlab.config.incoming_email).to receive(:enabled).and_return(true) end diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb index 7e42e43345c..b1f601a19e5 100644 --- a/spec/controllers/uploads_controller_spec.rb +++ b/spec/controllers/uploads_controller_spec.rb @@ -265,13 +265,13 @@ describe UploadsController do context "when the user has access to the project" do before do - project.team << [user, :master] + project.add_master(user) end context "when the user is blocked" do before do user.block - project.team << [user, :master] + project.add_master(user) end it "redirects to the sign in page" do @@ -465,13 +465,13 @@ describe UploadsController do context "when the user has access to the project" do before do - project.team << [user, :master] + project.add_master(user) end context "when the user is blocked" do before do user.block - project.team << [user, :master] + project.add_master(user) end it "redirects to the sign in page" do diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 01ab59aa363..2898c4b119e 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -91,7 +91,7 @@ describe UsersController do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) push_data = Gitlab::DataBuilder::Push.build_sample(project, user) @@ -117,7 +117,7 @@ describe UsersController do allow_any_instance_of(User).to receive(:contributed_projects_ids).and_return([project.id]) sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end it 'assigns @calendar_date' do diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb index 94b12105088..d02ac6c2e2a 100644 --- a/spec/features/admin/admin_projects_spec.rb +++ b/spec/features/admin/admin_projects_spec.rb @@ -88,7 +88,7 @@ describe "Admin::Projects" do describe 'add admin himself to a project' do before do - project.team << [user, :master] + project.add_master(user) end it 'adds admin a to a project as developer', :js do @@ -110,8 +110,8 @@ describe "Admin::Projects" do describe 'admin remove himself from a project' do before do - project.team << [user, :master] - project.team << [current_user, :developer] + project.add_master(user) + project.add_developer(current_user) end it 'removes admin from the project' do diff --git a/spec/features/atom/dashboard_issues_spec.rb b/spec/features/atom/dashboard_issues_spec.rb index 89c9d377003..d673bac4995 100644 --- a/spec/features/atom/dashboard_issues_spec.rb +++ b/spec/features/atom/dashboard_issues_spec.rb @@ -8,8 +8,8 @@ describe "Dashboard Issues Feed" do let!(:project2) { create(:project) } before do - project1.team << [user, :master] - project2.team << [user, :master] + project1.add_master(user) + project2.add_master(user) end describe "atom feed" do diff --git a/spec/features/atom/dashboard_spec.rb b/spec/features/atom/dashboard_spec.rb index 2c0c331b6db..c6683bb3bc9 100644 --- a/spec/features/atom/dashboard_spec.rb +++ b/spec/features/atom/dashboard_spec.rb @@ -26,7 +26,7 @@ describe "Dashboard Feed" do let(:note) { create(:note, noteable: issue, author: user, note: 'Bug confirmed', project: project) } before do - project.team << [user, :master] + project.add_master(user) issue_event(issue, user) note_event(note, user) visit dashboard_projects_path(:atom, rss_token: user.rss_token) diff --git a/spec/features/atom/issues_spec.rb b/spec/features/atom/issues_spec.rb index 4102ac0588a..525ce23aa56 100644 --- a/spec/features/atom/issues_spec.rb +++ b/spec/features/atom/issues_spec.rb @@ -9,7 +9,7 @@ describe 'Issues Feed' do let!(:issue) { create(:issue, author: user, assignees: [assignee], project: project) } before do - project.team << [user, :developer] + project.add_developer(user) group.add_developer(user) end diff --git a/spec/features/atom/users_spec.rb b/spec/features/atom/users_spec.rb index 2b934d81674..782f42aab04 100644 --- a/spec/features/atom/users_spec.rb +++ b/spec/features/atom/users_spec.rb @@ -47,7 +47,7 @@ describe "User Feed" do let!(:push_event_payload) { create(:push_event_payload, event: push_event) } before do - project.team << [user, :master] + project.add_master(user) issue_event(issue, user) note_event(note, user) merge_request_event(merge_request, user) diff --git a/spec/features/auto_deploy_spec.rb b/spec/features/auto_deploy_spec.rb index 7a395f62511..9aef68b7156 100644 --- a/spec/features/auto_deploy_spec.rb +++ b/spec/features/auto_deploy_spec.rb @@ -52,7 +52,7 @@ describe 'Auto deploy' do context 'when user configured kubernetes from Integration > Kubernetes' do before do create :kubernetes_service, project: project - project.team << [user, :master] + project.add_master(user) sign_in user end @@ -65,7 +65,7 @@ describe 'Auto deploy' do context 'when user configured kubernetes from CI/CD > Clusters' do before do create(:cluster, :provided_by_gcp, projects: [project]) - project.team << [user, :master] + project.add_master(user) sign_in user end diff --git a/spec/features/boards/add_issues_modal_spec.rb b/spec/features/boards/add_issues_modal_spec.rb index e4cfcea45a5..18901a954cc 100644 --- a/spec/features/boards/add_issues_modal_spec.rb +++ b/spec/features/boards/add_issues_modal_spec.rb @@ -12,7 +12,7 @@ describe 'Issue Boards add issue modal', :js do let!(:issue2) { create(:issue, project: project, title: 'hij', description: 'klm') } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index e8d779f5772..3876d1c76d7 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -11,8 +11,8 @@ describe 'Issue Boards', :js do let!(:user2) { create(:user) } before do - project.team << [user, :master] - project.team << [user2, :master] + project.add_master(user) + project.add_master(user2) set_cookie('sidebar_collapsed', 'true') @@ -551,7 +551,7 @@ describe 'Issue Boards', :js do let(:user_guest) { create(:user) } before do - project.team << [user_guest, :guest] + project.add_guest(user_guest) sign_out(:user) sign_in(user_guest) visit project_board_path(project, board) diff --git a/spec/features/boards/issue_ordering_spec.rb b/spec/features/boards/issue_ordering_spec.rb index 4cbb48e2e6e..5abd02dbb48 100644 --- a/spec/features/boards/issue_ordering_spec.rb +++ b/spec/features/boards/issue_ordering_spec.rb @@ -13,7 +13,7 @@ describe 'Issue Boards', :js do let!(:issue3) { create(:labeled_issue, project: project, title: 'testing 3', labels: [label], relative_position: 1) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/features/boards/modal_filter_spec.rb b/spec/features/boards/modal_filter_spec.rb index 422d96175f7..5907bb0840f 100644 --- a/spec/features/boards/modal_filter_spec.rb +++ b/spec/features/boards/modal_filter_spec.rb @@ -10,7 +10,7 @@ describe 'Issue Boards add issue modal filtering', :js do let!(:issue1) { create(:issue, project: project) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end @@ -76,7 +76,7 @@ describe 'Issue Boards add issue modal filtering', :js do let!(:issue) { create(:issue, project: project, author: user2) } before do - project.team << [user2, :developer] + project.add_developer(user2) visit_board end @@ -99,7 +99,7 @@ describe 'Issue Boards add issue modal filtering', :js do let!(:issue) { create(:issue, project: project, assignees: [user2]) } before do - project.team << [user2, :developer] + project.add_developer(user2) visit_board end diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb index 5ac4d87e90b..6769acb7c9c 100644 --- a/spec/features/boards/new_issue_spec.rb +++ b/spec/features/boards/new_issue_spec.rb @@ -8,7 +8,7 @@ describe 'Issue Boards new issue', :js do context 'authorized user' do before do - project.team << [user, :master] + project.add_master(user) sign_in(user) diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 77dcdf89f37..a28b8905b65 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -26,7 +26,7 @@ describe 'Commits' do let!(:status) { create(:generic_commit_status, pipeline: pipeline) } before do - project.team << [user, :reporter] + project.add_reporter(user) end describe 'Commit builds' do @@ -51,7 +51,7 @@ describe 'Commits' do context 'when logged as developer' do before do - project.team << [user, :developer] + project.add_developer(user) end describe 'Project commits' do @@ -145,7 +145,7 @@ describe 'Commits' do context "when logged as reporter" do before do - project.team << [user, :reporter] + project.add_reporter(user) build.update_attributes(legacy_artifacts_file: artifacts_file) visit pipeline_path(pipeline) end @@ -188,7 +188,7 @@ describe 'Commits' do let(:branch_name) { 'master' } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) visit project_commits_path(project, branch_name) end diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb index 177cd50dd72..d36954954b6 100644 --- a/spec/features/cycle_analytics_spec.rb +++ b/spec/features/cycle_analytics_spec.rb @@ -95,7 +95,7 @@ feature 'Cycle Analytics', :js do before do user.update_attribute(:preferred_language, 'es') - project.team << [user, :master] + project.add_master(user) sign_in(user) visit project_cycle_analytics_path(project) wait_for_requests diff --git a/spec/features/dashboard/archived_projects_spec.rb b/spec/features/dashboard/archived_projects_spec.rb index e8d699ff5e0..b36231fd78b 100644 --- a/spec/features/dashboard/archived_projects_spec.rb +++ b/spec/features/dashboard/archived_projects_spec.rb @@ -6,8 +6,8 @@ RSpec.describe 'Dashboard Archived Project' do let(:archived_project) { create(:project, :archived) } before do - project.team << [user, :master] - archived_project.team << [user, :master] + project.add_master(user) + archived_project.add_master(user) sign_in(user) diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb index 349f9a47112..089c388636d 100644 --- a/spec/features/dashboard/datetime_on_tooltips_spec.rb +++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb @@ -8,7 +8,7 @@ feature 'Tooltips on .timeago dates', :js do context 'on the activity tab' do before do - project.team << [user, :master] + project.add_master(user) Event.create( project: project, author_id: user.id, action: Event::JOINED, updated_at: created_date, created_at: created_date) @@ -27,7 +27,7 @@ feature 'Tooltips on .timeago dates', :js do context 'on the snippets tab' do before do - project.team << [user, :master] + project.add_master(user) create(:snippet, author: user, updated_at: created_date, created_at: created_date) sign_in user diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb index 5b4c00b3c7e..54652e2d849 100644 --- a/spec/features/dashboard/issues_spec.rb +++ b/spec/features/dashboard/issues_spec.rb @@ -12,7 +12,7 @@ RSpec.describe 'Dashboard Issues' do let!(:other_issue) { create :issue, project: project } before do - [project, project_with_issues_disabled].each { |project| project.team << [current_user, :master] } + [project, project_with_issues_disabled].each { |project| project.add_master(current_user) } sign_in(current_user) visit issues_dashboard_path(assignee_id: current_user.id) end diff --git a/spec/features/dashboard/milestones_spec.rb b/spec/features/dashboard/milestones_spec.rb index 41d37376cfb..7787772a958 100644 --- a/spec/features/dashboard/milestones_spec.rb +++ b/spec/features/dashboard/milestones_spec.rb @@ -16,7 +16,7 @@ feature 'Dashboard > Milestones' do let(:project) { create(:project, namespace: user.namespace) } let!(:milestone) { create(:milestone, project: project) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) visit dashboard_milestones_path end diff --git a/spec/features/dashboard/project_member_activity_index_spec.rb b/spec/features/dashboard/project_member_activity_index_spec.rb index 8f96899fb4f..6c3093607b0 100644 --- a/spec/features/dashboard/project_member_activity_index_spec.rb +++ b/spec/features/dashboard/project_member_activity_index_spec.rb @@ -5,7 +5,7 @@ feature 'Project member activity', :js do let(:project) { create(:project, :public, name: 'x', namespace: user.namespace) } before do - project.team << [user, :master] + project.add_master(user) end def visit_activities_and_wait_with_event(event_type) diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb index fbf8b5c0db6..586c7b48d0b 100644 --- a/spec/features/dashboard/projects_spec.rb +++ b/spec/features/dashboard/projects_spec.rb @@ -6,7 +6,7 @@ feature 'Dashboard Projects' do let(:project2) { create(:project, :public, name: 'Community project') } before do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) end diff --git a/spec/features/dashboard/todos/todos_filtering_spec.rb b/spec/features/dashboard/todos/todos_filtering_spec.rb index ad0f132da8c..2fc34301d51 100644 --- a/spec/features/dashboard/todos/todos_filtering_spec.rb +++ b/spec/features/dashboard/todos/todos_filtering_spec.rb @@ -15,8 +15,8 @@ feature 'Dashboard > User filters todos', :js do create(:todo, user: user_1, author: user_2, project: project_1, target: issue, action: 1) create(:todo, user: user_1, author: user_1, project: project_2, target: merge_request, action: 2) - project_1.team << [user_1, :developer] - project_2.team << [user_1, :developer] + project_1.add_developer(user_1) + project_2.add_developer(user_1) sign_in(user_1) visit dashboard_todos_path end @@ -66,8 +66,8 @@ feature 'Dashboard > User filters todos', :js do create(:todo, user: user_1, author: user_3, project: project_1, target: issue, action: 1, state: :done) create(:todo, user: user_1, author: user_4, project: project_2, target: merge_request, action: 2, state: :done) - project_1.team << [user_3, :developer] - project_2.team << [user_4, :developer] + project_1.add_developer(user_3) + project_2.add_developer(user_4) visit dashboard_todos_path(state: 'done') diff --git a/spec/features/dashboard/todos/todos_sorting_spec.rb b/spec/features/dashboard/todos/todos_sorting_spec.rb index b7d39a872b0..10e3ad843fd 100644 --- a/spec/features/dashboard/todos/todos_sorting_spec.rb +++ b/spec/features/dashboard/todos/todos_sorting_spec.rb @@ -9,7 +9,7 @@ feature 'Dashboard > User sorts todos' do let(:label_3) { create(:label, title: 'label_3', project: project, priority: 3) } before do - project.team << [user, :developer] + project.add_developer(user) end context 'sort options' do diff --git a/spec/features/dashboard/user_filters_projects_spec.rb b/spec/features/dashboard/user_filters_projects_spec.rb index c352b6ded14..92f4d4b854c 100644 --- a/spec/features/dashboard/user_filters_projects_spec.rb +++ b/spec/features/dashboard/user_filters_projects_spec.rb @@ -7,14 +7,14 @@ describe 'Dashboard > User filters projects' do let(:project2) { create(:project, name: 'Treasure', namespace: user2.namespace) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end describe 'filtering personal projects' do before do - project2.team << [user, :developer] + project2.add_developer(user) visit dashboard_projects_path end diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb index f04e13adba7..4f575613848 100644 --- a/spec/features/global_search_spec.rb +++ b/spec/features/global_search_spec.rb @@ -5,7 +5,7 @@ feature 'Global search' do let(:project) { create(:project, namespace: user.namespace) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/features/issues/award_emoji_spec.rb b/spec/features/issues/award_emoji_spec.rb index 850b35c4467..1131e1711bf 100644 --- a/spec/features/issues/award_emoji_spec.rb +++ b/spec/features/issues/award_emoji_spec.rb @@ -11,7 +11,7 @@ describe 'Awards Emoji' do context 'authorized user' do before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb index fa4d3a55c62..587ece22ec7 100644 --- a/spec/features/issues/bulk_assignment_labels_spec.rb +++ b/spec/features/issues/bulk_assignment_labels_spec.rb @@ -11,7 +11,7 @@ feature 'Issues > Labels bulk assignment' do context 'as an allowed user', :js do before do - project.team << [user, :master] + project.add_master(user) sign_in user end 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 822ba48e005..e0466aaf422 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 @@ -8,7 +8,7 @@ feature 'Resolving all open discussions in a merge request from an issue', :js d describe 'as a user with access to the project' do before do - project.team << [user, :master] + project.add_master(user) sign_in user visit project_merge_request_path(project, merge_request) end @@ -81,7 +81,7 @@ feature 'Resolving all open discussions in a merge request from an issue', :js d describe 'as a reporter' do before do - project.team << [user, :reporter] + project.add_reporter(user) sign_in user visit new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) end 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 f0bed85595c..34beb282bad 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 @@ -8,7 +8,7 @@ feature 'Resolve an open discussion in a merge request by creating an issue' do describe 'As a user with access to the project' do before do - project.team << [user, :master] + project.add_master(user) sign_in user visit project_merge_request_path(project, merge_request) end @@ -65,7 +65,7 @@ feature 'Resolve an open discussion in a merge request by creating an issue' do describe 'as a reporter' do before do - project.team << [user, :reporter] + project.add_reporter(user) sign_in user visit new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid, discussion_to_resolve: discussion.id) diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb index 2e4a25ee15d..cbd0949c192 100644 --- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb @@ -20,9 +20,9 @@ describe 'Dropdown assignee', :js do end before do - project.team << [user, :master] - project.team << [user_john, :master] - project.team << [user_jacob, :master] + project.add_master(user) + project.add_master(user_john) + project.add_master(user_jacob) sign_in(user) create(:issue, project: project) @@ -222,7 +222,7 @@ describe 'Dropdown assignee', :js do expect(initial_size).to be > 0 new_user = create(:user) - project.team << [new_user, :master] + project.add_master(new_user) find('.filtered-search-box .clear-search').click filtered_search.set('assignee') filtered_search.send_keys(':') diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb index 2fb5e7cdba4..70b4f11410d 100644 --- a/spec/features/issues/filtered_search/dropdown_author_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb @@ -28,9 +28,9 @@ describe 'Dropdown author', :js do end before do - project.team << [user, :master] - project.team << [user_john, :master] - project.team << [user_jacob, :master] + project.add_master(user) + project.add_master(user_john) + project.add_master(user_jacob) sign_in(user) create(:issue, project: project) @@ -195,7 +195,7 @@ describe 'Dropdown author', :js do expect(initial_size).to be > 0 new_user = create(:user) - project.team << [new_user, :master] + project.add_master(new_user) find('.filtered-search-box .clear-search').click filtered_search.set('author') send_keys_to_filtered_search(':') diff --git a/spec/features/issues/filtered_search/dropdown_emoji_spec.rb b/spec/features/issues/filtered_search/dropdown_emoji_spec.rb index 8db435634fd..436625a6f7b 100644 --- a/spec/features/issues/filtered_search/dropdown_emoji_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_emoji_spec.rb @@ -28,7 +28,7 @@ describe 'Dropdown emoji', :js do end before do - project.team << [user, :master] + project.add_master(user) create_list(:award_emoji, 2, user: user, name: 'thumbsup') create_list(:award_emoji, 1, user: user, name: 'thumbsdown') create_list(:award_emoji, 3, user: user, name: 'star') diff --git a/spec/features/issues/filtered_search/dropdown_hint_spec.rb b/spec/features/issues/filtered_search/dropdown_hint_spec.rb index 0183495a1db..18ae45aa340 100644 --- a/spec/features/issues/filtered_search/dropdown_hint_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_hint_spec.rb @@ -13,7 +13,7 @@ describe 'Dropdown hint', :js do end before do - project.team << [user, :master] + project.add_master(user) create(:issue, project: project) end diff --git a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb index 031eb06723a..94710c2f71f 100644 --- a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb @@ -29,7 +29,7 @@ describe 'Dropdown milestone', :js do end before do - project.team << [user, :master] + project.add_master(user) sign_in(user) create(:issue, project: project) diff --git a/spec/features/issues/filtered_search/search_bar_spec.rb b/spec/features/issues/filtered_search/search_bar_spec.rb index 88688422dc7..268590da599 100644 --- a/spec/features/issues/filtered_search/search_bar_spec.rb +++ b/spec/features/issues/filtered_search/search_bar_spec.rb @@ -8,7 +8,7 @@ describe 'Search bar', :js do let(:filtered_search) { find('.filtered-search') } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) create(:issue, project: project) diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb index 2db6f9a2982..faf14be4818 100644 --- a/spec/features/issues/form_spec.rb +++ b/spec/features/issues/form_spec.rb @@ -13,8 +13,8 @@ describe 'New/edit issue', :js do let!(:issue) { create(:issue, project: project, assignees: [user], milestone: milestone) } before do - project.team << [user, :master] - project.team << [user2, :master] + project.add_master(user) + project.add_master(user2) sign_in(user) end diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb index 6a9a80235c1..f2624f55c86 100644 --- a/spec/features/issues/gfm_autocomplete_spec.rb +++ b/spec/features/issues/gfm_autocomplete_spec.rb @@ -7,7 +7,7 @@ feature 'GFM autocomplete', :js do let(:issue) { create(:issue, project: project) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) visit project_issue_path(project, issue) diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb index a9de52bd8d5..a5c9d0bde5d 100644 --- a/spec/features/issues/issue_sidebar_spec.rb +++ b/spec/features/issues/issue_sidebar_spec.rb @@ -18,7 +18,7 @@ feature 'Issue Sidebar' do let(:issue2) { create(:issue, project: project, author: user2) } before do - project.team << [user, :developer] + project.add_developer(user) visit_issue(project, issue2) find('.block.assignee .edit-link').click @@ -78,7 +78,7 @@ feature 'Issue Sidebar' do context 'as a allowed user' do before do - project.team << [user, :developer] + project.add_developer(user) visit_issue(project, issue) end @@ -156,7 +156,7 @@ feature 'Issue Sidebar' do context 'as a guest' do before do - project.team << [user, :guest] + project.add_guest(user) visit_issue(project, issue) end diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb index 17035b5501c..076a02150a4 100644 --- a/spec/features/issues/move_spec.rb +++ b/spec/features/issues/move_spec.rb @@ -13,7 +13,7 @@ feature 'issue move to another project' do context 'user does not have permission to move issue' do background do - old_project.team << [user, :guest] + old_project.add_guest(user) visit issue_path(issue) end @@ -31,8 +31,8 @@ feature 'issue move to another project' do let(:cross_reference) { old_project.to_reference(new_project) } background do - old_project.team << [user, :reporter] - new_project.team << [user, :reporter] + old_project.add_reporter(user) + new_project.add_reporter(user) visit issue_path(issue) end @@ -50,7 +50,7 @@ feature 'issue move to another project' do end scenario 'searching project dropdown', :js do - new_project_search.team << [user, :reporter] + new_project_search.add_reporter(user) find('.js-move-issue').click wait_for_requests @@ -66,7 +66,7 @@ feature 'issue move to another project' do context 'user does not have permission to move the issue to a project', :js do let!(:private_project) { create(:project, :private) } let(:another_project) { create(:project) } - background { another_project.team << [user, :guest] } + background { another_project.add_guest(user) } scenario 'browsing projects in projects select' do find('.js-move-issue').click diff --git a/spec/features/issues/notes_on_issues_spec.rb b/spec/features/issues/notes_on_issues_spec.rb index 05c93a19253..f08c73f947c 100644 --- a/spec/features/issues/notes_on_issues_spec.rb +++ b/spec/features/issues/notes_on_issues_spec.rb @@ -8,7 +8,7 @@ describe 'Create notes on issues', :js do let(:note_text) { "Check #{mention.to_reference}" } before do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) visit project_issue_path(project, issue) diff --git a/spec/features/issues/spam_issues_spec.rb b/spec/features/issues/spam_issues_spec.rb index d25231d624c..53706ef84bc 100644 --- a/spec/features/issues/spam_issues_spec.rb +++ b/spec/features/issues/spam_issues_spec.rb @@ -17,7 +17,7 @@ describe 'New issue', :js do recaptcha_private_key: 'test private key' ) - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/features/issues/todo_spec.rb b/spec/features/issues/todo_spec.rb index 29a2d38ae18..8e6493bbd93 100644 --- a/spec/features/issues/todo_spec.rb +++ b/spec/features/issues/todo_spec.rb @@ -6,7 +6,7 @@ feature 'Manually create a todo item from issue', :js do let!(:user) { create(:user)} before do - project.team << [user, :master] + project.add_master(user) sign_in(user) visit project_issue_path(project, issue) end diff --git a/spec/features/issues/update_issues_spec.rb b/spec/features/issues/update_issues_spec.rb index bcc6e9bab0f..7d6edc171f8 100644 --- a/spec/features/issues/update_issues_spec.rb +++ b/spec/features/issues/update_issues_spec.rb @@ -6,7 +6,7 @@ feature 'Multiple issue updating from issues#index', :js do let!(:user) { create(:user)} before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb index c4c06ed514b..e711a191db2 100644 --- a/spec/features/issues/user_uses_slash_commands_spec.rb +++ b/spec/features/issues/user_uses_slash_commands_spec.rb @@ -12,7 +12,7 @@ feature 'Issues > User uses quick actions', :js do let(:project) { create(:project, :public) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) visit project_issue_path(project, issue) end @@ -50,7 +50,7 @@ feature 'Issues > User uses quick actions', :js do context 'when the current user cannot update the due date' do let(:guest) { create(:user) } before do - project.team << [guest, :guest] + project.add_guest(guest) gitlab_sign_out sign_in(guest) visit project_issue_path(project, issue) @@ -90,7 +90,7 @@ feature 'Issues > User uses quick actions', :js do context 'when the current user cannot update the due date' do let(:guest) { create(:user) } before do - project.team << [guest, :guest] + project.add_guest(guest) gitlab_sign_out sign_in(guest) visit project_issue_path(project, issue) @@ -138,7 +138,7 @@ feature 'Issues > User uses quick actions', :js do context 'when the current user cannot update the issue' do let(:guest) { create(:user) } before do - project.team << [guest, :guest] + project.add_guest(guest) gitlab_sign_out sign_in(guest) visit project_issue_path(project, issue) @@ -163,7 +163,7 @@ feature 'Issues > User uses quick actions', :js do let(:target_project) { create(:project, :public) } before do - target_project.team << [user, :master] + target_project.add_master(user) sign_in(user) visit project_issue_path(project, issue) end @@ -220,7 +220,7 @@ feature 'Issues > User uses quick actions', :js do let(:wontfix_target) { create(:label, project: target_project, title: 'wontfix') } before do - target_project.team << [user, :master] + target_project.add_master(user) sign_in(user) visit project_issue_path(project, issue) end diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index d1ff057a0c6..314bd19f586 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -25,7 +25,8 @@ describe 'Issues' do sign_in(user) user2 = create(:user) - project.team << [[user, user2], :developer] + project.add_developer(user) + project.add_developer(user2) end describe 'empty state' do @@ -383,7 +384,7 @@ describe 'Issues' do before do stub_incoming_email_setting(enabled: true, address: "p+%{key}@gl.ab") - project1.team << [user, :master] + project1.add_master(user) visit namespace_project_issues_path(user.namespace, project1) end @@ -491,7 +492,7 @@ describe 'Issues' do let(:guest) { create(:user) } before do - project.team << [[guest], :guest] + project.add_guest(guest) end it 'shows assignee text', :js do @@ -552,7 +553,7 @@ describe 'Issues' do let(:guest) { create(:user) } before do - project.team << [guest, :guest] + project.add_guest(guest) issue.milestone = milestone issue.save end diff --git a/spec/features/merge_requests/assign_issues_spec.rb b/spec/features/merge_requests/assign_issues_spec.rb index d49d145f254..b2d64a62b4f 100644 --- a/spec/features/merge_requests/assign_issues_spec.rb +++ b/spec/features/merge_requests/assign_issues_spec.rb @@ -9,7 +9,7 @@ feature 'Merge request issue assignment', :js do let(:service) { MergeRequests::AssignIssuesService.new(merge_request, user, user, project) } before do - project.team << [user, :developer] + project.add_developer(user) end def visit_merge_request(current_user = nil) 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 fbbfe7942be..892c32c8806 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 @@ -7,7 +7,7 @@ feature 'Check if mergeable with unresolved discussions', :js do before do sign_in user - project.team << [user, :master] + project.add_master(user) end context 'when project.only_allow_merge_if_all_discussions_are_resolved == true' do diff --git a/spec/features/merge_requests/cherry_pick_spec.rb b/spec/features/merge_requests/cherry_pick_spec.rb index 48f370c3ad4..205e38337d1 100644 --- a/spec/features/merge_requests/cherry_pick_spec.rb +++ b/spec/features/merge_requests/cherry_pick_spec.rb @@ -8,7 +8,7 @@ describe 'Cherry-pick Merge Requests', :js do before do sign_in user - project.team << [user, :master] + project.add_master(user) end context "Viewing a merged merge request" do diff --git a/spec/features/merge_requests/closes_issues_spec.rb b/spec/features/merge_requests/closes_issues_spec.rb index 4dd4e40f52c..55de9a01ed5 100644 --- a/spec/features/merge_requests/closes_issues_spec.rb +++ b/spec/features/merge_requests/closes_issues_spec.rb @@ -18,7 +18,7 @@ feature 'Merge Request closing issues message', :js do let(:merge_request_title) { 'Merge Request Title' } before do - project.team << [user, :master] + project.add_master(user) sign_in user diff --git a/spec/features/merge_requests/conflicts_spec.rb b/spec/features/merge_requests/conflicts_spec.rb index 4e2963c116d..05d99a2dff2 100644 --- a/spec/features/merge_requests/conflicts_spec.rb +++ b/spec/features/merge_requests/conflicts_spec.rb @@ -88,7 +88,7 @@ feature 'Merge request conflict resolution', :js do context 'can be resolved in the UI' do before do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) end @@ -175,7 +175,7 @@ feature 'Merge request conflict resolution', :js do let(:merge_request) { create_merge_request(source_branch) } before do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) visit project_merge_request_path(project, merge_request) diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb index db5ce2d11a8..486555ed5cd 100644 --- a/spec/features/merge_requests/create_new_mr_spec.rb +++ b/spec/features/merge_requests/create_new_mr_spec.rb @@ -5,7 +5,7 @@ feature 'Create New Merge Request', :js do let(:project) { create(:project, :public, :repository) } before do - project.team << [user, :master] + project.add_master(user) sign_in user end diff --git a/spec/features/merge_requests/created_from_fork_spec.rb b/spec/features/merge_requests/created_from_fork_spec.rb index ca2225318cd..53b62caf743 100644 --- a/spec/features/merge_requests/created_from_fork_spec.rb +++ b/spec/features/merge_requests/created_from_fork_spec.rb @@ -14,7 +14,7 @@ feature 'Merge request created from fork' do end background do - forked_project.team << [user, :master] + forked_project.add_master(user) sign_in user end diff --git a/spec/features/merge_requests/deleted_source_branch_spec.rb b/spec/features/merge_requests/deleted_source_branch_spec.rb index 7f69e82af4c..56aa0b2ede2 100644 --- a/spec/features/merge_requests/deleted_source_branch_spec.rb +++ b/spec/features/merge_requests/deleted_source_branch_spec.rb @@ -9,7 +9,7 @@ describe 'Deleted source branch', :js do before do sign_in user - merge_request.project.team << [user, :master] + merge_request.project.add_master(user) merge_request.update!(source_branch: 'this-branch-does-not-exist') visit project_merge_request_path(merge_request.project, merge_request) end diff --git a/spec/features/merge_requests/diff_notes_avatars_spec.rb b/spec/features/merge_requests/diff_notes_avatars_spec.rb index 9e816cf041b..ef8f314cc03 100644 --- a/spec/features/merge_requests/diff_notes_avatars_spec.rb +++ b/spec/features/merge_requests/diff_notes_avatars_spec.rb @@ -19,7 +19,7 @@ feature 'Diff note avatars', :js do let!(:note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request, position: position) } before do - project.team << [user, :master] + project.add_master(user) sign_in user set_cookie('sidebar_collapsed', 'true') diff --git a/spec/features/merge_requests/diff_notes_resolve_spec.rb b/spec/features/merge_requests/diff_notes_resolve_spec.rb index 15d380b1bf4..9d4194d8ca0 100644 --- a/spec/features/merge_requests/diff_notes_resolve_spec.rb +++ b/spec/features/merge_requests/diff_notes_resolve_spec.rb @@ -18,7 +18,7 @@ feature 'Diff notes resolve', :js do context 'no discussions' do before do - project.team << [user, :master] + project.add_master(user) sign_in user note.destroy visit_merge_request @@ -32,7 +32,7 @@ feature 'Diff notes resolve', :js do context 'as authorized user' do before do - project.team << [user, :master] + project.add_master(user) sign_in user visit_merge_request end @@ -429,7 +429,7 @@ feature 'Diff notes resolve', :js do let(:guest) { create(:user) } before do - project.team << [guest, :guest] + project.add_guest(guest) sign_in guest end diff --git a/spec/features/merge_requests/edit_mr_spec.rb b/spec/features/merge_requests/edit_mr_spec.rb index 4362f8b3fcc..79be2fbf945 100644 --- a/spec/features/merge_requests/edit_mr_spec.rb +++ b/spec/features/merge_requests/edit_mr_spec.rb @@ -6,7 +6,7 @@ feature 'Edit Merge Request' do let(:merge_request) { create(:merge_request, :simple, source_project: project) } before do - project.team << [user, :master] + project.add_master(user) sign_in user diff --git a/spec/features/merge_requests/filter_by_milestone_spec.rb b/spec/features/merge_requests/filter_by_milestone_spec.rb index 8b9ff9be943..8db94352f73 100644 --- a/spec/features/merge_requests/filter_by_milestone_spec.rb +++ b/spec/features/merge_requests/filter_by_milestone_spec.rb @@ -14,7 +14,7 @@ feature 'Merge Request filtering by Milestone' do end before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/features/merge_requests/form_spec.rb b/spec/features/merge_requests/form_spec.rb index 1dcc1e139a0..1ebf762a006 100644 --- a/spec/features/merge_requests/form_spec.rb +++ b/spec/features/merge_requests/form_spec.rb @@ -12,8 +12,8 @@ describe 'New/edit merge request', :js do let!(:label2) { create(:label, project: project) } before do - project.team << [user, :master] - project.team << [user2, :master] + project.add_master(user) + project.add_master(user2) end context 'owned projects' do @@ -172,7 +172,7 @@ describe 'New/edit merge request', :js do context 'forked project' do before do - forked_project.team << [user, :master] + forked_project.add_master(user) sign_in(user) end diff --git a/spec/features/merge_requests/image_diff_notes_spec.rb b/spec/features/merge_requests/image_diff_notes_spec.rb index b53570835cb..d0f8da4e6cd 100644 --- a/spec/features/merge_requests/image_diff_notes_spec.rb +++ b/spec/features/merge_requests/image_diff_notes_spec.rb @@ -7,7 +7,7 @@ feature 'image diff notes', :js do let(:project) { create(:project, :public, :repository) } before do - project.team << [user, :master] + project.add_master(user) sign_in user # Stub helper to return any blob file as image from public app folder. 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 82b2b56ef80..ddd034e1376 100644 --- a/spec/features/merge_requests/merge_commit_message_toggle_spec.rb +++ b/spec/features/merge_requests/merge_commit_message_toggle_spec.rb @@ -32,7 +32,7 @@ feature 'Clicking toggle commit message link', :js do end before do - project.team << [user, :master] + project.add_master(user) sign_in user 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 0b5a595acce..e1317b33ad1 100644 --- a/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb +++ b/spec/features/merge_requests/merge_immediately_with_pipeline_spec.rb @@ -19,7 +19,7 @@ feature 'Merge immediately', :js do end before do - project.team << [user, :master] + project.add_master(user) end context 'when there is active pipeline for merge request' do 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 91f207bd339..7d9282b932b 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 @@ -7,7 +7,7 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', :js d before do sign_in merge_request.author - project.team << [merge_request.author, :master] + project.add_master(merge_request.author) end context 'project does not have CI enabled', :js do diff --git a/spec/features/merge_requests/pipelines_spec.rb b/spec/features/merge_requests/pipelines_spec.rb index 307c860eac4..04e3f4bdcf1 100644 --- a/spec/features/merge_requests/pipelines_spec.rb +++ b/spec/features/merge_requests/pipelines_spec.rb @@ -7,7 +7,7 @@ feature 'Pipelines for Merge Requests', :js do given(:project) { merge_request.target_project } before do - project.team << [user, :master] + project.add_master(user) sign_in user end diff --git a/spec/features/merge_requests/reset_filters_spec.rb b/spec/features/merge_requests/reset_filters_spec.rb index eed95816bdf..daca4422bf1 100644 --- a/spec/features/merge_requests/reset_filters_spec.rb +++ b/spec/features/merge_requests/reset_filters_spec.rb @@ -17,7 +17,7 @@ feature 'Merge requests filter clear button', :js do before do mr2.labels << bug - project.team << [user, :developer] + project.add_developer(user) end context 'when a milestone filter has been applied' do diff --git a/spec/features/merge_requests/target_branch_spec.rb b/spec/features/merge_requests/target_branch_spec.rb index bce36e05e57..d9f7a056dea 100644 --- a/spec/features/merge_requests/target_branch_spec.rb +++ b/spec/features/merge_requests/target_branch_spec.rb @@ -11,7 +11,7 @@ describe 'Target branch', :js do before do sign_in user - project.team << [user, :master] + project.add_master(user) end context 'when branch was deleted' do diff --git a/spec/features/merge_requests/update_merge_requests_spec.rb b/spec/features/merge_requests/update_merge_requests_spec.rb index c5498563b39..a96404b86ed 100644 --- a/spec/features/merge_requests/update_merge_requests_spec.rb +++ b/spec/features/merge_requests/update_merge_requests_spec.rb @@ -6,7 +6,7 @@ feature 'Multiple merge requests updating from merge_requests#index' do let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end 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 ee0766f1192..5874bf5e187 100644 --- a/spec/features/merge_requests/user_uses_slash_commands_spec.rb +++ b/spec/features/merge_requests/user_uses_slash_commands_spec.rb @@ -15,7 +15,7 @@ feature 'Merge Requests > User uses quick actions', :js do let!(:milestone) { create(:milestone, project: project, title: 'ASAP') } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) visit project_merge_request_path(project, merge_request) end @@ -58,7 +58,7 @@ feature 'Merge Requests > User uses quick actions', :js do context 'when the current user cannot toggle the WIP prefix' do let(:guest) { create(:user) } before do - project.team << [guest, :guest] + project.add_guest(guest) sign_out(:user) sign_in(guest) visit project_merge_request_path(project, merge_request) @@ -104,7 +104,7 @@ feature 'Merge Requests > User uses quick actions', :js do context 'when the current user cannot merge the MR' do let(:guest) { create(:user) } before do - project.team << [guest, :guest] + project.add_guest(guest) sign_out(:user) sign_in(guest) visit project_merge_request_path(project, merge_request) @@ -134,7 +134,7 @@ feature 'Merge Requests > User uses quick actions', :js do before do sign_out(:user) - another_project.team << [user, :master] + another_project.add_master(user) sign_in(user) end @@ -188,7 +188,7 @@ feature 'Merge Requests > User uses quick actions', :js do context 'when current user can not change target branch' do let(:guest) { create(:user) } before do - project.team << [guest, :guest] + project.add_guest(guest) sign_out(:user) sign_in(guest) visit project_merge_request_path(project, merge_request) diff --git a/spec/features/merge_requests/widget_deployments_spec.rb b/spec/features/merge_requests/widget_deployments_spec.rb index 72a52c979b3..ec2da72ddff 100644 --- a/spec/features/merge_requests/widget_deployments_spec.rb +++ b/spec/features/merge_requests/widget_deployments_spec.rb @@ -13,7 +13,7 @@ feature 'Widget Deployments Header', :js do background do sign_in(user) - project.team << [user, role] + project.add_role(user, role) visit project_merge_request_path(project, merge_request) end diff --git a/spec/features/merge_requests/widget_spec.rb b/spec/features/merge_requests/widget_spec.rb index 3ee094c216e..8970586a160 100644 --- a/spec/features/merge_requests/widget_spec.rb +++ b/spec/features/merge_requests/widget_spec.rb @@ -273,7 +273,7 @@ describe 'Merge request', :js do let(:user2) { create(:user) } before do - project.team << [user2, :master] + project.add_master(user2) sign_out(:user) sign_in(user2) merge_request.update(target_project: fork_project) diff --git a/spec/features/merge_requests/wip_message_spec.rb b/spec/features/merge_requests/wip_message_spec.rb index b422c76249d..2617e735c25 100644 --- a/spec/features/merge_requests/wip_message_spec.rb +++ b/spec/features/merge_requests/wip_message_spec.rb @@ -5,7 +5,7 @@ feature 'Work In Progress help message' do let!(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb index 9f24193a2ac..b02d2d4261c 100644 --- a/spec/features/milestone_spec.rb +++ b/spec/features/milestone_spec.rb @@ -7,7 +7,7 @@ feature 'Milestone' do before do create(:group_member, group: group, user: user) - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/features/profiles/user_visits_notifications_tab_spec.rb b/spec/features/profiles/user_visits_notifications_tab_spec.rb index df89918f17a..1952fdae798 100644 --- a/spec/features/profiles/user_visits_notifications_tab_spec.rb +++ b/spec/features/profiles/user_visits_notifications_tab_spec.rb @@ -5,7 +5,7 @@ feature 'User visits the notifications tab', :js do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) visit(profile_notifications_path) end diff --git a/spec/features/projects/activity/rss_spec.rb b/spec/features/projects/activity/rss_spec.rb index 84c2faa2015..2693e539268 100644 --- a/spec/features/projects/activity/rss_spec.rb +++ b/spec/features/projects/activity/rss_spec.rb @@ -11,7 +11,7 @@ feature 'Project Activity RSS' do context 'when signed in' do before do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) visit path end diff --git a/spec/features/projects/badges/coverage_spec.rb b/spec/features/projects/badges/coverage_spec.rb index c68e10a2563..821ce88a402 100644 --- a/spec/features/projects/badges/coverage_spec.rb +++ b/spec/features/projects/badges/coverage_spec.rb @@ -6,7 +6,7 @@ feature 'test coverage badge' do context 'when user has access to view badge' do background do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) end diff --git a/spec/features/projects/badges/list_spec.rb b/spec/features/projects/badges/list_spec.rb index 68c4a647958..c705e479690 100644 --- a/spec/features/projects/badges/list_spec.rb +++ b/spec/features/projects/badges/list_spec.rb @@ -4,7 +4,7 @@ feature 'list of badges' do background do user = create(:user) project = create(:project, :repository) - project.team << [user, :master] + project.add_master(user) sign_in(user) visit project_pipelines_settings_path(project) end diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb index 965028a6f90..69e4c9f04a1 100644 --- a/spec/features/projects/blobs/edit_spec.rb +++ b/spec/features/projects/blobs/edit_spec.rb @@ -13,7 +13,7 @@ feature 'Editing file blob', :js do let(:role) { :developer } before do - project.team << [user, role] + project.add_role(user, role) sign_in(user) end @@ -55,7 +55,7 @@ feature 'Editing file blob', :js do let(:user) { create(:user) } before do - project.team << [user, :developer] + project.add_developer(user) visit project_edit_blob_path(project, tree_join(branch, file_path)) end @@ -90,7 +90,7 @@ feature 'Editing file blob', :js do let(:protected_branch) { 'protected-branch' } before do - project.team << [user, :developer] + project.add_developer(user) project.repository.add_branch(user, protected_branch, 'master') create(:protected_branch, project: project, name: protected_branch) sign_in(user) @@ -122,7 +122,7 @@ feature 'Editing file blob', :js do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) visit project_edit_blob_path(project, tree_join(branch, file_path)) end diff --git a/spec/features/projects/branches/download_buttons_spec.rb b/spec/features/projects/branches/download_buttons_spec.rb index 2f407b13c2f..39bcea013e7 100644 --- a/spec/features/projects/branches/download_buttons_spec.rb +++ b/spec/features/projects/branches/download_buttons_spec.rb @@ -23,7 +23,7 @@ feature 'Download buttons in branches page' do background do sign_in(user) - project.team << [user, role] + project.add_role(user, role) end describe 'when checking branches' do diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb index 7a77df83034..2fddd274078 100644 --- a/spec/features/projects/branches_spec.rb +++ b/spec/features/projects/branches_spec.rb @@ -8,7 +8,7 @@ describe 'Branches' do context 'logged in as developer' do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end describe 'Initial branches page' do @@ -78,7 +78,7 @@ describe 'Branches' do context 'logged in as master' do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) end describe 'Initial branches page' do diff --git a/spec/features/projects/commit/builds_spec.rb b/spec/features/projects/commit/builds_spec.rb index 79e84a4f0a6..36a746ac83d 100644 --- a/spec/features/projects/commit/builds_spec.rb +++ b/spec/features/projects/commit/builds_spec.rb @@ -5,7 +5,7 @@ feature 'project commit pipelines', :js do background do user = create(:user) - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/features/projects/commit/cherry_pick_spec.rb b/spec/features/projects/commit/cherry_pick_spec.rb index c11a95732b2..c4c399e3058 100644 --- a/spec/features/projects/commit/cherry_pick_spec.rb +++ b/spec/features/projects/commit/cherry_pick_spec.rb @@ -9,7 +9,7 @@ describe 'Cherry-pick Commits' do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) visit project_commit_path(project, master_pickable_commit.id) end diff --git a/spec/features/projects/commits/rss_spec.rb b/spec/features/projects/commits/rss_spec.rb index db958346f06..0d9c7355ddd 100644 --- a/spec/features/projects/commits/rss_spec.rb +++ b/spec/features/projects/commits/rss_spec.rb @@ -7,7 +7,7 @@ feature 'Project Commits RSS' do context 'when signed in' do before do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) visit path end diff --git a/spec/features/projects/compare_spec.rb b/spec/features/projects/compare_spec.rb index 87ffc2a0b90..1fb22fd0e4c 100644 --- a/spec/features/projects/compare_spec.rb +++ b/spec/features/projects/compare_spec.rb @@ -5,7 +5,7 @@ describe "Compare", :js do let(:project) { create(:project, :repository) } before do - project.team << [user, :master] + project.add_master(user) sign_in user visit project_compare_index_path(project, from: "master", to: "master") end diff --git a/spec/features/projects/deploy_keys_spec.rb b/spec/features/projects/deploy_keys_spec.rb index e445758cb5e..886c56e7163 100644 --- a/spec/features/projects/deploy_keys_spec.rb +++ b/spec/features/projects/deploy_keys_spec.rb @@ -5,7 +5,7 @@ describe 'Project deploy keys', :js do let(:project) { create(:project_empty_repo) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end 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 36809240f76..bf55917bf4c 100644 --- a/spec/features/projects/developer_views_empty_project_instructions_spec.rb +++ b/spec/features/projects/developer_views_empty_project_instructions_spec.rb @@ -5,7 +5,7 @@ feature 'Developer views empty project instructions' do let(:developer) { create(:user) } background do - project.team << [developer, :developer] + project.add_developer(developer) sign_in(developer) end diff --git a/spec/features/projects/edit_spec.rb b/spec/features/projects/edit_spec.rb index 7a372757523..1d4b4d0fdca 100644 --- a/spec/features/projects/edit_spec.rb +++ b/spec/features/projects/edit_spec.rb @@ -7,7 +7,7 @@ feature 'Project edit', :js do context 'feature visibility' do before do - project.team << [user, :master] + project.add_master(user) sign_in(user) visit edit_project_path(project) diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb index dfcf97ad495..64e600144e0 100644 --- a/spec/features/projects/environments/environment_spec.rb +++ b/spec/features/projects/environments/environment_spec.rb @@ -7,7 +7,7 @@ feature 'Environment' do background do sign_in(user) - project.team << [user, role] + project.add_role(user, role) end feature 'environment details page' do diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb index 4a05313c14a..5248a783db4 100644 --- a/spec/features/projects/environments/environments_spec.rb +++ b/spec/features/projects/environments/environments_spec.rb @@ -6,7 +6,7 @@ feature 'Environments page', :js do given(:role) { :developer } background do - project.team << [user, role] + project.add_role(user, role) sign_in(user) end diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb index 033c45a60bf..b0eb7c5b42a 100644 --- a/spec/features/projects/features_visibility_spec.rb +++ b/spec/features/projects/features_visibility_spec.rb @@ -8,7 +8,7 @@ describe 'Edit Project Settings' do describe 'project features visibility selectors', :js do before do - project.team << [member, :master] + project.add_master(member) sign_in(member) end @@ -165,7 +165,7 @@ describe 'Edit Project Settings' do describe 'repository visibility', :js do before do - project.team << [member, :master] + project.add_master(member) sign_in(member) visit edit_project_path(project) end @@ -261,7 +261,7 @@ describe 'Edit Project Settings' do let!(:project) { create(:project, :private) } before do - project.team << [member, :guest] + project.add_guest(member) sign_in(member) visit project_path(project) end diff --git a/spec/features/projects/files/browse_files_spec.rb b/spec/features/projects/files/browse_files_spec.rb index 84197e45dcb..2c38c380d9d 100644 --- a/spec/features/projects/files/browse_files_spec.rb +++ b/spec/features/projects/files/browse_files_spec.rb @@ -5,7 +5,7 @@ feature 'user browses project', :js do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) visit project_tree_path(project, project.default_branch) end diff --git a/spec/features/projects/files/creating_a_file_spec.rb b/spec/features/projects/files/creating_a_file_spec.rb index e1852a6e544..8d982636525 100644 --- a/spec/features/projects/files/creating_a_file_spec.rb +++ b/spec/features/projects/files/creating_a_file_spec.rb @@ -5,7 +5,7 @@ feature 'User wants to create a file' do let(:user) { create(:user) } background do - project.team << [user, :master] + project.add_master(user) sign_in user visit project_new_blob_path(project, project.default_branch) end diff --git a/spec/features/projects/files/dockerfile_dropdown_spec.rb b/spec/features/projects/files/dockerfile_dropdown_spec.rb index 3c3a5326538..f4a39e331fd 100644 --- a/spec/features/projects/files/dockerfile_dropdown_spec.rb +++ b/spec/features/projects/files/dockerfile_dropdown_spec.rb @@ -5,7 +5,7 @@ feature 'User wants to add a Dockerfile file' do before do user = create(:user) project = create(:project, :repository) - project.team << [user, :master] + project.add_master(user) sign_in user diff --git a/spec/features/projects/files/download_buttons_spec.rb b/spec/features/projects/files/download_buttons_spec.rb index d2382d55c0b..2101627f324 100644 --- a/spec/features/projects/files/download_buttons_spec.rb +++ b/spec/features/projects/files/download_buttons_spec.rb @@ -23,7 +23,7 @@ feature 'Download buttons in files tree' do background do sign_in(user) - project.team << [user, role] + project.add_role(user, role) end describe 'when files tree' do 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 3ab43b3c656..8d32ada5795 100644 --- a/spec/features/projects/files/edit_file_soft_wrap_spec.rb +++ b/spec/features/projects/files/edit_file_soft_wrap_spec.rb @@ -4,7 +4,7 @@ feature 'User uses soft wrap whilst editing file', :js do before do user = create(:user) project = create(:project, :repository) - project.team << [user, :master] + project.add_master(user) sign_in user visit project_new_blob_path(project, 'master', file_name: 'test_file-name') page.within('.file-editor.code') do diff --git a/spec/features/projects/files/editing_a_file_spec.rb b/spec/features/projects/files/editing_a_file_spec.rb index 20be968e89f..d874cdbff8d 100644 --- a/spec/features/projects/files/editing_a_file_spec.rb +++ b/spec/features/projects/files/editing_a_file_spec.rb @@ -16,7 +16,7 @@ feature 'User wants to edit a file' do end background do - project.team << [user, :master] + project.add_master(user) sign_in user visit project_edit_blob_path(project, File.join(project.default_branch, '.gitignore')) 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 702b99de733..ead9f7e9168 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 @@ -5,7 +5,7 @@ feature 'User views files page' do let(:project) { create(:forked_project_with_submodules) } before do - project.team << [user, :master] + project.add_master(user) sign_in user visit project_tree_path(project, project.repository.root_ref) end diff --git a/spec/features/projects/files/find_file_keyboard_spec.rb b/spec/features/projects/files/find_file_keyboard_spec.rb index 618725ee781..e9ff06c72d8 100644 --- a/spec/features/projects/files/find_file_keyboard_spec.rb +++ b/spec/features/projects/files/find_file_keyboard_spec.rb @@ -5,7 +5,7 @@ feature 'Find file keyboard shortcuts', :js do let(:project) { create(:project, :repository) } before do - project.team << [user, :master] + project.add_master(user) sign_in user visit project_find_file_path(project, project.repository.root_ref) diff --git a/spec/features/projects/files/gitignore_dropdown_spec.rb b/spec/features/projects/files/gitignore_dropdown_spec.rb index 81d68c3d67c..79f3fd09b48 100644 --- a/spec/features/projects/files/gitignore_dropdown_spec.rb +++ b/spec/features/projects/files/gitignore_dropdown_spec.rb @@ -4,7 +4,7 @@ feature 'User wants to add a .gitignore file' do before do user = create(:user) project = create(:project, :repository) - project.team << [user, :master] + project.add_master(user) sign_in user visit project_new_blob_path(project, 'master', file_name: '.gitignore') end 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 8e58fa7bd56..db6c67b802e 100644 --- a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb +++ b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb @@ -4,7 +4,7 @@ feature 'User wants to add a .gitlab-ci.yml file' do before do user = create(:user) project = create(:project, :repository) - project.team << [user, :master] + project.add_master(user) sign_in user visit project_new_blob_path(project, 'master', file_name: '.gitlab-ci.yml') end 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 6c5b1086ec1..07599600876 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 @@ -6,7 +6,7 @@ feature 'project owner creates a license file', :js do background do project.repository.delete_file(project_master, 'LICENSE', message: 'Remove LICENSE', branch_name: 'master') - project.team << [project_master, :master] + project.add_master(project_master) sign_in(project_master) visit project_path(project) end diff --git a/spec/features/projects/files/template_type_dropdown_spec.rb b/spec/features/projects/files/template_type_dropdown_spec.rb index f95a60e5194..97408a9c41e 100644 --- a/spec/features/projects/files/template_type_dropdown_spec.rb +++ b/spec/features/projects/files/template_type_dropdown_spec.rb @@ -5,7 +5,7 @@ feature 'Template type dropdown selector', :js do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in user end diff --git a/spec/features/projects/files/undo_template_spec.rb b/spec/features/projects/files/undo_template_spec.rb index 64fe350f3dc..fbf35fb4e1c 100644 --- a/spec/features/projects/files/undo_template_spec.rb +++ b/spec/features/projects/files/undo_template_spec.rb @@ -5,7 +5,7 @@ feature 'Template Undo Button', :js do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in user end diff --git a/spec/features/projects/guest_navigation_menu_spec.rb b/spec/features/projects/guest_navigation_menu_spec.rb index 98c7ef57a51..199682b943c 100644 --- a/spec/features/projects/guest_navigation_menu_spec.rb +++ b/spec/features/projects/guest_navigation_menu_spec.rb @@ -5,7 +5,7 @@ describe 'Guest navigation menu' do let(:guest) { create(:user) } before do - project.team << [guest, :guest] + project.add_guest(guest) sign_in(guest) end diff --git a/spec/features/projects/issuable_templates_spec.rb b/spec/features/projects/issuable_templates_spec.rb index 4319fc2746c..e26caf1f456 100644 --- a/spec/features/projects/issuable_templates_spec.rb +++ b/spec/features/projects/issuable_templates_spec.rb @@ -8,7 +8,7 @@ feature 'issuable templates', :js do let(:issue_form_location) { '#content-body .issuable-details .detail-page-description' } before do - project.team << [user, :master] + project.add_master(user) sign_in user end @@ -120,7 +120,7 @@ feature 'issuable templates', :js do background do sign_out(:user) - project.team << [fork_user, :developer] + project.add_developer(fork_user) sign_in(fork_user) diff --git a/spec/features/projects/issues/rss_spec.rb b/spec/features/projects/issues/rss_spec.rb index 58eeef8c258..ff91aabc311 100644 --- a/spec/features/projects/issues/rss_spec.rb +++ b/spec/features/projects/issues/rss_spec.rb @@ -12,7 +12,7 @@ feature 'Project Issues RSS' do let(:user) { create(:user) } before do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) visit path end diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index 0b0d5a2dce8..f8ea1a52656 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -15,7 +15,7 @@ feature 'Jobs' do end before do - project.team << [user, user_access_level] + project.add_role(user, user_access_level) sign_in(user) end diff --git a/spec/features/projects/labels/subscription_spec.rb b/spec/features/projects/labels/subscription_spec.rb index e8c70dec854..70e8d436dcb 100644 --- a/spec/features/projects/labels/subscription_spec.rb +++ b/spec/features/projects/labels/subscription_spec.rb @@ -9,7 +9,7 @@ feature 'Labels subscription' do context 'when signed in' do before do - project.team << [user, :developer] + project.add_developer(user) sign_in user end diff --git a/spec/features/projects/labels/update_prioritization_spec.rb b/spec/features/projects/labels/update_prioritization_spec.rb index d063f5c27b5..85bd776932b 100644 --- a/spec/features/projects/labels/update_prioritization_spec.rb +++ b/spec/features/projects/labels/update_prioritization_spec.rb @@ -12,7 +12,7 @@ feature 'Prioritize labels' do context 'when user belongs to project team' do before do - project.team << [user, :developer] + project.add_developer(user) sign_in user end diff --git a/spec/features/projects/main/download_buttons_spec.rb b/spec/features/projects/main/download_buttons_spec.rb index 3f2579bb01a..81f08e44cf3 100644 --- a/spec/features/projects/main/download_buttons_spec.rb +++ b/spec/features/projects/main/download_buttons_spec.rb @@ -23,7 +23,7 @@ feature 'Download buttons in project main page' do background do sign_in(user) - project.team << [user, role] + project.add_role(user, role) end describe 'when checking project main page' do diff --git a/spec/features/projects/main/rss_spec.rb b/spec/features/projects/main/rss_spec.rb index 7914180b951..3c98c11b490 100644 --- a/spec/features/projects/main/rss_spec.rb +++ b/spec/features/projects/main/rss_spec.rb @@ -7,7 +7,7 @@ feature 'Project RSS' do context 'when signed in' do before do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) visit path end 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 bf0990d675d..e2a48bfd1d4 100644 --- a/spec/features/projects/members/anonymous_user_sees_members_spec.rb +++ b/spec/features/projects/members/anonymous_user_sees_members_spec.rb @@ -6,7 +6,7 @@ feature 'Projects > Members > Anonymous user sees members' do let(:project) { create(:project, :public) } background do - project.team << [user, :master] + project.add_master(user) create(:project_group_link, project: project, group: group) end diff --git a/spec/features/projects/members/group_members_spec.rb b/spec/features/projects/members/group_members_spec.rb index c140fece41d..e22b6fa6c43 100644 --- a/spec/features/projects/members/group_members_spec.rb +++ b/spec/features/projects/members/group_members_spec.rb @@ -11,7 +11,7 @@ feature 'Projects members' do let(:group_requester) { create(:user) } background do - project.team << [developer, :developer] + project.add_developer(developer) group.add_owner(user) sign_in(user) end diff --git a/spec/features/projects/members/groups_with_access_list_spec.rb b/spec/features/projects/members/groups_with_access_list_spec.rb index 7f067aadec6..e6d0c6e00f8 100644 --- a/spec/features/projects/members/groups_with_access_list_spec.rb +++ b/spec/features/projects/members/groups_with_access_list_spec.rb @@ -6,7 +6,7 @@ feature 'Projects > Members > Groups with access list', :js do let(:project) { create(:project, :public) } background do - project.team << [user, :master] + project.add_master(user) @group_link = create(:project_group_link, project: project, group: group) sign_in(user) 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 0f88f4cb1e8..8fe340d3bae 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 @@ -9,7 +9,7 @@ feature 'Projects > Members > Master adds member with expiration date', :js do let!(:new_member) { create(:user) } background do - project.team << [master, :master] + project.add_master(master) sign_in(master) end diff --git a/spec/features/projects/members/master_manages_access_requests_spec.rb b/spec/features/projects/members/master_manages_access_requests_spec.rb index eb3c8034873..d575596937d 100644 --- a/spec/features/projects/members/master_manages_access_requests_spec.rb +++ b/spec/features/projects/members/master_manages_access_requests_spec.rb @@ -7,7 +7,7 @@ feature 'Projects > Members > Master manages access requests' do background do project.request_access(user) - project.team << [master, :master] + project.add_master(master) sign_in(master) end 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..47911c32a72 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 @@ -5,7 +5,7 @@ feature 'Projects > Members > Member cannot request access to his project' do let(:project) { create(:project) } background do - project.team << [member, :developer] + project.add_developer(member) sign_in(member) visit project_path(project) end diff --git a/spec/features/projects/members/member_leaves_project_spec.rb b/spec/features/projects/members/member_leaves_project_spec.rb index 1bcf827d33c..e54c2c76975 100644 --- a/spec/features/projects/members/member_leaves_project_spec.rb +++ b/spec/features/projects/members/member_leaves_project_spec.rb @@ -5,7 +5,7 @@ feature 'Projects > Members > Member leaves project' do let(:project) { create(:project, :repository) } background do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) visit project_path(project) end diff --git a/spec/features/projects/merge_requests/list_spec.rb b/spec/features/projects/merge_requests/list_spec.rb index a879efef4b5..b34b13db381 100644 --- a/spec/features/projects/merge_requests/list_spec.rb +++ b/spec/features/projects/merge_requests/list_spec.rb @@ -5,7 +5,7 @@ feature 'Merge Requests List' do let(:project) { create(:project, :repository) } background do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) end diff --git a/spec/features/projects/pages_spec.rb b/spec/features/projects/pages_spec.rb index 013ed6f2e58..2e334caa98f 100644 --- a/spec/features/projects/pages_spec.rb +++ b/spec/features/projects/pages_spec.rb @@ -8,7 +8,7 @@ feature 'Pages' do background do allow(Gitlab.config.pages).to receive(:enabled).and_return(true) - project.team << [user, role] + project.add_role(user, role) sign_in(user) end diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index 3987cea0b4f..266ef693d0b 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -6,7 +6,7 @@ describe 'Pipeline', :js do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end shared_context 'pipeline builds' do diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index b87b47d0e1a..df261c246f7 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -8,7 +8,7 @@ describe 'Pipelines', :js do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end describe 'GET /:project/pipelines' do diff --git a/spec/features/projects/services/user_activates_jira_spec.rb b/spec/features/projects/services/user_activates_jira_spec.rb index ac78b1dfb1c..028669eeaf2 100644 --- a/spec/features/projects/services/user_activates_jira_spec.rb +++ b/spec/features/projects/services/user_activates_jira_spec.rb @@ -18,7 +18,7 @@ describe 'User activates Jira', :js do end before do - project.team << [user, :master] + project.add_master(user) sign_in(user) visit project_settings_integrations_path(project) diff --git a/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb b/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb index 6f057137867..b2906e315f7 100644 --- a/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb +++ b/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb @@ -8,7 +8,7 @@ feature 'Setup Mattermost slash commands', :js do before do stub_mattermost_setting(enabled: mattermost_enabled) - project.team << [user, :master] + project.add_master(user) sign_in(user) visit edit_project_service_path(project, service) end diff --git a/spec/features/projects/services/user_activates_slack_slash_command_spec.rb b/spec/features/projects/services/user_activates_slack_slash_command_spec.rb index a8baf126269..4a88654210c 100644 --- a/spec/features/projects/services/user_activates_slack_slash_command_spec.rb +++ b/spec/features/projects/services/user_activates_slack_slash_command_spec.rb @@ -6,7 +6,7 @@ feature 'Slack slash commands' do given(:service) { project.create_slack_slash_commands_service } background do - project.team << [user, :master] + project.add_master(user) sign_in(user) visit edit_project_service_path(project, service) end diff --git a/spec/features/projects/settings/integration_settings_spec.rb b/spec/features/projects/settings/integration_settings_spec.rb index cbdb7973ac8..f6a1a46df11 100644 --- a/spec/features/projects/settings/integration_settings_spec.rb +++ b/spec/features/projects/settings/integration_settings_spec.rb @@ -8,7 +8,7 @@ feature 'Integration settings' do background do sign_in(user) - project.team << [user, role] + project.add_role(user, role) end context 'for developer' do diff --git a/spec/features/projects/settings/merge_requests_settings_spec.rb b/spec/features/projects/settings/merge_requests_settings_spec.rb index ac76c30cc7c..015db603d33 100644 --- a/spec/features/projects/settings/merge_requests_settings_spec.rb +++ b/spec/features/projects/settings/merge_requests_settings_spec.rb @@ -5,7 +5,7 @@ feature 'Project settings > Merge Requests', :js do let(:user) { create(:user) } background do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/features/projects/settings/pipelines_settings_spec.rb b/spec/features/projects/settings/pipelines_settings_spec.rb index 561f08cba00..d0720855564 100644 --- a/spec/features/projects/settings/pipelines_settings_spec.rb +++ b/spec/features/projects/settings/pipelines_settings_spec.rb @@ -7,7 +7,7 @@ feature "Pipelines settings" do background do sign_in(user) - project.team << [user, role] + project.add_role(user, role) end context 'for developer' do diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb index e2a5619c22b..81b282502fc 100644 --- a/spec/features/projects/settings/repository_settings_spec.rb +++ b/spec/features/projects/settings/repository_settings_spec.rb @@ -6,7 +6,7 @@ feature 'Repository settings' do let(:role) { :developer } background do - project.team << [user, role] + project.add_role(user, role) sign_in(user) end @@ -66,7 +66,7 @@ feature 'Repository settings' do scenario 'edit a deploy key from projects user has access to' do project2 = create(:project_empty_repo) - project2.team << [user, role] + project2.add_role(user, role) project2.deploy_keys << private_deploy_key visit project_settings_repository_path(project) diff --git a/spec/features/projects/settings/visibility_settings_spec.rb b/spec/features/projects/settings/visibility_settings_spec.rb index 1c3b84d0114..06f6702670b 100644 --- a/spec/features/projects/settings/visibility_settings_spec.rb +++ b/spec/features/projects/settings/visibility_settings_spec.rb @@ -31,7 +31,7 @@ feature 'Visibility settings', :js do let(:master_user) { create(:user) } before do - project.team << [master_user, :master] + project.add_master(master_user) sign_in(master_user) visit edit_project_path(project) end diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb index e4215291f99..3466a3dfb77 100644 --- a/spec/features/projects/snippets/create_snippet_spec.rb +++ b/spec/features/projects/snippets/create_snippet_spec.rb @@ -16,7 +16,7 @@ feature 'Create Snippet', :js do context 'when a user is authenticated' do before do - project.team << [user, :master] + project.add_master(user) sign_in(user) visit project_snippets_path(project) diff --git a/spec/features/projects/snippets/show_spec.rb b/spec/features/projects/snippets/show_spec.rb index 08dc7cf6c5b..216f2af7c88 100644 --- a/spec/features/projects/snippets/show_spec.rb +++ b/spec/features/projects/snippets/show_spec.rb @@ -6,7 +6,7 @@ feature 'Project snippet', :js do let(:snippet) { create(:project_snippet, project: project, file_name: file_name, content: content) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/features/projects/tags/download_buttons_spec.rb b/spec/features/projects/tags/download_buttons_spec.rb index d38a5b1324b..b62498194c4 100644 --- a/spec/features/projects/tags/download_buttons_spec.rb +++ b/spec/features/projects/tags/download_buttons_spec.rb @@ -24,7 +24,7 @@ feature 'Download buttons in tags page' do background do sign_in(user) - project.team << [user, role] + project.add_role(user, role) end describe 'when checking tags' do diff --git a/spec/features/projects/tree/rss_spec.rb b/spec/features/projects/tree/rss_spec.rb index 4f2e0a76a65..6407370ac0d 100644 --- a/spec/features/projects/tree/rss_spec.rb +++ b/spec/features/projects/tree/rss_spec.rb @@ -7,7 +7,7 @@ feature 'Project Tree RSS' do context 'when signed in' do before do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) visit path end diff --git a/spec/features/projects/user_browses_files_spec.rb b/spec/features/projects/user_browses_files_spec.rb index f5e4d7f5130..62e6419cc42 100644 --- a/spec/features/projects/user_browses_files_spec.rb +++ b/spec/features/projects/user_browses_files_spec.rb @@ -15,7 +15,7 @@ describe 'User browses files' do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/features/projects/user_creates_directory_spec.rb b/spec/features/projects/user_creates_directory_spec.rb index 052cb3188c5..00e48f6fabd 100644 --- a/spec/features/projects/user_creates_directory_spec.rb +++ b/spec/features/projects/user_creates_directory_spec.rb @@ -11,7 +11,7 @@ feature 'User creates a directory', :js do let(:user) { create(:user) } before do - project.team << [user, :developer] + project.add_developer(user) sign_in(user) visit project_tree_path(project, 'master') end @@ -63,7 +63,7 @@ feature 'User creates a directory', :js do context 'when an user does not have write access' do before do - project2.team << [user, :reporter] + project2.add_reporter(user) visit(project2_tree_path_root_ref) end diff --git a/spec/features/projects/user_creates_files_spec.rb b/spec/features/projects/user_creates_files_spec.rb index d84b91ddc32..7a935dd2477 100644 --- a/spec/features/projects/user_creates_files_spec.rb +++ b/spec/features/projects/user_creates_files_spec.rb @@ -12,7 +12,7 @@ describe 'User creates files' do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end @@ -33,7 +33,7 @@ describe 'User creates files' do context 'when an user does not have write access' do before do - project2.team << [user, :reporter] + project2.add_reporter(user) visit(project2_tree_path_root_ref) end @@ -131,7 +131,7 @@ describe 'User creates files' do context 'when an user does not have write access' do before do - project2.team << [user, :reporter] + project2.add_reporter(user) visit(project2_tree_path_root_ref) end diff --git a/spec/features/projects/user_deletes_files_spec.rb b/spec/features/projects/user_deletes_files_spec.rb index 9e4e92ec076..9d55197e719 100644 --- a/spec/features/projects/user_deletes_files_spec.rb +++ b/spec/features/projects/user_deletes_files_spec.rb @@ -17,7 +17,7 @@ describe 'User deletes files' do context 'when an user has write access' do before do - project.team << [user, :master] + project.add_master(user) visit(project_tree_path_root_ref) end @@ -37,7 +37,7 @@ describe 'User deletes files' do context 'when an user does not have write access' do before do - project2.team << [user, :reporter] + project2.add_reporter(user) visit(project2_tree_path_root_ref) end diff --git a/spec/features/projects/user_edits_files_spec.rb b/spec/features/projects/user_edits_files_spec.rb index d26ee653415..5c5c6a398f6 100644 --- a/spec/features/projects/user_edits_files_spec.rb +++ b/spec/features/projects/user_edits_files_spec.rb @@ -14,7 +14,7 @@ describe 'User edits files' do context 'when an user has write access' do before do - project.team << [user, :master] + project.add_master(user) visit(project_tree_path_root_ref) end @@ -87,7 +87,7 @@ describe 'User edits files' do context 'when an user does not have write access' do before do - project2.team << [user, :reporter] + project2.add_reporter(user) visit(project2_tree_path_root_ref) end diff --git a/spec/features/projects/user_replaces_files_spec.rb b/spec/features/projects/user_replaces_files_spec.rb index 245b6aa285b..74872403b35 100644 --- a/spec/features/projects/user_replaces_files_spec.rb +++ b/spec/features/projects/user_replaces_files_spec.rb @@ -19,7 +19,7 @@ describe 'User replaces files' do context 'when an user has write access' do before do - project.team << [user, :master] + project.add_master(user) visit(project_tree_path_root_ref) end @@ -45,7 +45,7 @@ describe 'User replaces files' do context 'when an user does not have write access' do before do - project2.team << [user, :reporter] + project2.add_reporter(user) visit(project2_tree_path_root_ref) end diff --git a/spec/features/projects/user_uploads_files_spec.rb b/spec/features/projects/user_uploads_files_spec.rb index ae51901adc6..75898afcda9 100644 --- a/spec/features/projects/user_uploads_files_spec.rb +++ b/spec/features/projects/user_uploads_files_spec.rb @@ -14,7 +14,7 @@ describe 'User uploads files' do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end @@ -50,7 +50,7 @@ describe 'User uploads files' do context 'when an user does not have write access' do before do - project2.team << [user, :reporter] + project2.add_reporter(user) visit(project2_tree_path_root_ref) end diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb index 337baaf4dcd..006c15d60c5 100644 --- a/spec/features/projects/wiki/markdown_preview_spec.rb +++ b/spec/features/projects/wiki/markdown_preview_spec.rb @@ -13,7 +13,7 @@ feature 'Projects > Wiki > User previews markdown changes', :js do end background do - project.team << [user, :master] + project.add_master(user) sign_in(user) 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 ebb3bd044c1..2682b62fa04 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 @@ -4,7 +4,7 @@ describe 'Projects > Wiki > User views wiki in project page' do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index 63e6051b571..b66a7dea598 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -133,7 +133,7 @@ feature 'Project' do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) visit edit_project_path(project) end @@ -151,7 +151,7 @@ feature 'Project' do let(:project) { create(:forked_project_with_submodules) } before do - project.team << [user, :master] + project.add_master(user) sign_in user visit project_path(project) end @@ -180,7 +180,7 @@ feature 'Project' do let(:project) { create(:project, :repository) } before do - project.team << [user, :master] + project.add_master(user) sign_in user visit project_path(project) end diff --git a/spec/features/signed_commits_spec.rb b/spec/features/signed_commits_spec.rb index 8efa5b58141..6088b831c14 100644 --- a/spec/features/signed_commits_spec.rb +++ b/spec/features/signed_commits_spec.rb @@ -5,7 +5,7 @@ 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] + project.add_master(user) Sidekiq::Testing.inline! do create :gpg_key, key: GpgHelpers::User1.public_key, user: user @@ -36,7 +36,7 @@ describe 'GPG signed commits', :js do 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] + project.add_master(user) sign_in(user) @@ -86,7 +86,7 @@ describe 'GPG signed commits', :js do before do user = create :user - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/features/tags/master_creates_tag_spec.rb b/spec/features/tags/master_creates_tag_spec.rb index 1f8bd8d681e..8a8f6933fa5 100644 --- a/spec/features/tags/master_creates_tag_spec.rb +++ b/spec/features/tags/master_creates_tag_spec.rb @@ -5,7 +5,7 @@ feature 'Master creates tag' do let(:project) { create(:project, :repository, namespace: user.namespace) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) end diff --git a/spec/features/tags/master_deletes_tag_spec.rb b/spec/features/tags/master_deletes_tag_spec.rb index dfda664d673..c0b4fa52526 100644 --- a/spec/features/tags/master_deletes_tag_spec.rb +++ b/spec/features/tags/master_deletes_tag_spec.rb @@ -5,7 +5,7 @@ feature 'Master deletes tag' do let(:project) { create(:project, :repository, namespace: user.namespace) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) visit project_tags_path(project) end diff --git a/spec/features/tags/master_updates_tag_spec.rb b/spec/features/tags/master_updates_tag_spec.rb index b93ad44dfd3..1c370a99b13 100644 --- a/spec/features/tags/master_updates_tag_spec.rb +++ b/spec/features/tags/master_updates_tag_spec.rb @@ -5,7 +5,7 @@ feature 'Master updates tag' do let(:project) { create(:project, :repository, namespace: user.namespace) } before do - project.team << [user, :master] + project.add_master(user) sign_in(user) visit project_tags_path(project) end diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb index bc472e74997..19784120108 100644 --- a/spec/features/triggers_spec.rb +++ b/spec/features/triggers_spec.rb @@ -10,9 +10,9 @@ feature 'Triggers', :js do sign_in(user) @project = create(:project) - @project.team << [user, :master] - @project.team << [user2, :master] - @project.team << [guest_user, :guest] + @project.add_master(user) + @project.add_master(user2) + @project.add_guest(guest_user) visit project_settings_ci_cd_path(@project) end diff --git a/spec/features/variables_spec.rb b/spec/features/variables_spec.rb index dde60c83536..79ca2b4bb4a 100644 --- a/spec/features/variables_spec.rb +++ b/spec/features/variables_spec.rb @@ -7,7 +7,7 @@ describe 'Project variables', :js do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) project.variables << variable visit project_settings_ci_cd_path(project) diff --git a/spec/finders/access_requests_finder_spec.rb b/spec/finders/access_requests_finder_spec.rb index 0789d3a9b44..650f7229647 100644 --- a/spec/finders/access_requests_finder_spec.rb +++ b/spec/finders/access_requests_finder_spec.rb @@ -51,7 +51,7 @@ describe AccessRequestsFinder do context 'when current user can see access requests' do before do - project.team << [user, :master] + project.add_master(user) group.add_owner(user) end @@ -78,7 +78,7 @@ describe AccessRequestsFinder do context 'when current user can see access requests' do before do - project.team << [user, :master] + project.add_master(user) group.add_owner(user) end diff --git a/spec/finders/group_projects_finder_spec.rb b/spec/finders/group_projects_finder_spec.rb index c6d257bc479..27a09d7c6f5 100644 --- a/spec/finders/group_projects_finder_spec.rb +++ b/spec/finders/group_projects_finder_spec.rb @@ -45,7 +45,7 @@ describe GroupProjectsFinder do describe 'without group member current_user' do before do - shared_project_2.team << [current_user, Gitlab::Access::MASTER] + shared_project_2.add_master(current_user) current_user.reload end @@ -70,7 +70,7 @@ describe GroupProjectsFinder do context "without external user" do before do - private_project.team << [current_user, Gitlab::Access::MASTER] + private_project.add_master(current_user) end it { is_expected.to match_array([private_project, public_project]) } diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb index 47b173dea0a..47fd98234f9 100644 --- a/spec/finders/issues_finder_spec.rb +++ b/spec/finders/issues_finder_spec.rb @@ -22,9 +22,9 @@ describe IssuesFinder do let(:issues) { described_class.new(search_user, params.reverse_merge(scope: scope, state: 'opened')).execute } before(:context) do - project1.team << [user, :master] - project2.team << [user, :developer] - project2.team << [user2, :developer] + project1.add_master(user) + project2.add_developer(user) + project2.add_developer(user2) issue1 issue2 diff --git a/spec/finders/labels_finder_spec.rb b/spec/finders/labels_finder_spec.rb index afa2a40ed2a..d507af3fd3d 100644 --- a/spec/finders/labels_finder_spec.rb +++ b/spec/finders/labels_finder_spec.rb @@ -27,7 +27,7 @@ describe LabelsFinder do create(:label, project: project_3, title: 'Label 3') create(:group_label, group: group_3, title: 'Group Label 4') - project_1.team << [user, :developer] + project_1.add_developer(user) end context 'with no filter' do @@ -73,7 +73,7 @@ describe LabelsFinder do # project_3 has a label associated to it, which we don't want coming # back when we ask for the isolated project's labels - project_3.team << [admin, :reporter] + project_3.add_reporter(admin) finder = described_class.new(admin, project_id: isolated_project.id) expect(finder.execute).to be_empty diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb index 883bdf3746a..687ffaec7cc 100644 --- a/spec/finders/merge_requests_finder_spec.rb +++ b/spec/finders/merge_requests_finder_spec.rb @@ -20,10 +20,10 @@ describe MergeRequestsFinder do let!(:merge_request4) { create(:merge_request, :simple, author: user, source_project: project3, target_project: project3) } before do - project1.team << [user, :master] - project2.team << [user, :developer] - project3.team << [user, :developer] - project2.team << [user2, :developer] + project1.add_master(user) + project2.add_developer(user) + project3.add_developer(user) + project2.add_developer(user2) end describe "#execute" do diff --git a/spec/finders/move_to_project_finder_spec.rb b/spec/finders/move_to_project_finder_spec.rb index e577083a2d0..74639d4147f 100644 --- a/spec/finders/move_to_project_finder_spec.rb +++ b/spec/finders/move_to_project_finder_spec.rb @@ -15,39 +15,39 @@ describe MoveToProjectFinder do describe '#execute' do context 'filter' do it 'does not return projects under Gitlab::Access::REPORTER' do - guest_project.team << [user, :guest] + guest_project.add_guest(user) expect(subject.execute(project)).to be_empty end it 'returns projects equal or above Gitlab::Access::REPORTER ordered by id in descending order' do - reporter_project.team << [user, :reporter] - developer_project.team << [user, :developer] - master_project.team << [user, :master] + reporter_project.add_reporter(user) + developer_project.add_developer(user) + master_project.add_master(user) expect(subject.execute(project).to_a).to eq([master_project, developer_project, reporter_project]) end it 'does not include the source project' do - project.team << [user, :reporter] + project.add_reporter(user) expect(subject.execute(project).to_a).to be_empty end it 'does not return archived projects' do - reporter_project.team << [user, :reporter] + reporter_project.add_reporter(user) reporter_project.archive! other_reporter_project = create(:project) - other_reporter_project.team << [user, :reporter] + other_reporter_project.add_reporter(user) expect(subject.execute(project).to_a).to eq([other_reporter_project]) end it 'does not return projects for which issues are disabled' do - reporter_project.team << [user, :reporter] + reporter_project.add_reporter(user) reporter_project.update_attributes(issues_enabled: false) other_reporter_project = create(:project) - other_reporter_project.team << [user, :reporter] + other_reporter_project.add_reporter(user) expect(subject.execute(project).to_a).to eq([other_reporter_project]) end @@ -55,9 +55,9 @@ describe MoveToProjectFinder do it 'returns a page of projects ordered by id in descending order' do stub_const 'MoveToProjectFinder::PAGE_SIZE', 2 - reporter_project.team << [user, :reporter] - developer_project.team << [user, :developer] - master_project.team << [user, :master] + reporter_project.add_reporter(user) + developer_project.add_developer(user) + master_project.add_master(user) expect(subject.execute(project).to_a).to eq([master_project, developer_project]) end @@ -65,9 +65,9 @@ describe MoveToProjectFinder do it 'returns projects after the given offset id' do stub_const 'MoveToProjectFinder::PAGE_SIZE', 2 - reporter_project.team << [user, :reporter] - developer_project.team << [user, :developer] - master_project.team << [user, :master] + reporter_project.add_reporter(user) + developer_project.add_developer(user) + master_project.add_master(user) expect(subject.execute(project, search: nil, offset_id: master_project.id).to_a).to eq([developer_project, reporter_project]) expect(subject.execute(project, search: nil, offset_id: developer_project.id).to_a).to eq([reporter_project]) @@ -84,10 +84,10 @@ describe MoveToProjectFinder do it 'returns projects matching a search query' do foo_project = create(:project) - foo_project.team << [user, :master] + foo_project.add_master(user) wadus_project = create(:project, name: 'wadus') - wadus_project.team << [user, :master] + wadus_project.add_master(user) expect(subject.execute(project).to_a).to eq([wadus_project, foo_project]) expect(subject.execute(project, search: 'wadus').to_a).to eq([wadus_project]) diff --git a/spec/finders/notes_finder_spec.rb b/spec/finders/notes_finder_spec.rb index 900fa2b12d1..7b43494eea2 100644 --- a/spec/finders/notes_finder_spec.rb +++ b/spec/finders/notes_finder_spec.rb @@ -5,7 +5,7 @@ describe NotesFinder do let(:project) { create(:project) } before do - project.team << [user, :master] + project.add_master(user) end describe '#execute' do @@ -147,7 +147,7 @@ describe NotesFinder do it 'raises an error for project members with guest role' do user = create(:user) - project.team << [user, :guest] + project.add_guest(user) expect { described_class.new(project, user, params).execute }.to raise_error(ActiveRecord::RecordNotFound) end @@ -189,7 +189,7 @@ describe NotesFinder do it "does not return notes with matching content for project members with guest role" do user = create(:user) - project.team << [user, :guest] + project.add_guest(user) expect(described_class.new(confidential_note.project, user, search: confidential_note.note).execute).to be_empty end diff --git a/spec/finders/personal_projects_finder_spec.rb b/spec/finders/personal_projects_finder_spec.rb index d0113ba87df..5e52898e9c0 100644 --- a/spec/finders/personal_projects_finder_spec.rb +++ b/spec/finders/personal_projects_finder_spec.rb @@ -15,7 +15,7 @@ describe PersonalProjectsFinder do end before do - private_project.team << [current_user, Gitlab::Access::DEVELOPER] + private_project.add_developer(current_user) end describe 'without a current user' do diff --git a/spec/finders/snippets_finder_spec.rb b/spec/finders/snippets_finder_spec.rb index 7ae7b7d2140..0a018d2b417 100644 --- a/spec/finders/snippets_finder_spec.rb +++ b/spec/finders/snippets_finder_spec.rb @@ -188,7 +188,7 @@ describe SnippetsFinder do end it "returns all snippets for project members" do - project1.team << [user, :developer] + project1.add_developer(user) snippets = described_class.new(user, project: project1).execute @@ -196,7 +196,7 @@ describe SnippetsFinder do end it "returns private snippets for project members" do - project1.team << [user, :developer] + project1.add_developer(user) snippets = described_class.new(user, project: project1, visibility: Snippet::PRIVATE).execute diff --git a/spec/finders/todos_finder_spec.rb b/spec/finders/todos_finder_spec.rb index 884ce22091e..90eb0fe21e4 100644 --- a/spec/finders/todos_finder_spec.rb +++ b/spec/finders/todos_finder_spec.rb @@ -7,7 +7,7 @@ describe TodosFinder do let(:finder) { described_class } before do - project.team << [user, :developer] + project.add_developer(user) end describe '#sort' do diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb index ba0039f3a11..c0dc9293397 100644 --- a/spec/helpers/markup_helper_spec.rb +++ b/spec/helpers/markup_helper_spec.rb @@ -11,7 +11,7 @@ describe MarkupHelper do before do # Ensure the generated reference links aren't redacted - project.team << [user, :master] + project.add_master(user) # Helper expects a @project instance variable helper.instance_variable_set(:@project, project) diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb index 36a44f8567a..b992bdb4a5e 100644 --- a/spec/helpers/notes_helper_spec.rb +++ b/spec/helpers/notes_helper_spec.rb @@ -17,9 +17,9 @@ describe NotesHelper do before do group.add_owner(owner) - project.team << [master, :master] - project.team << [reporter, :reporter] - project.team << [guest, :guest] + project.add_master(master) + project.add_reporter(reporter) + project.add_guest(guest) end describe "#notes_max_access_for_users" do @@ -31,7 +31,7 @@ describe NotesHelper do it 'handles access in different projects' do second_project = create(:project) - second_project.team << [master, :reporter] + second_project.add_reporter(master) other_note = create(:note, author: master, project: second_project) expect(helper.note_max_access_for_user(master_note)).to eq(Gitlab::Access::MASTER) diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb index 68643effb66..5a7858e77f3 100644 --- a/spec/lib/banzai/filter/redactor_filter_spec.rb +++ b/spec/lib/banzai/filter/redactor_filter_spec.rb @@ -46,7 +46,7 @@ describe Banzai::Filter::RedactorFilter do it 'allows permitted Project references' do user = create(:user) project = create(:project) - project.team << [user, :master] + project.add_master(user) link = reference_link(project: project.id, reference_type: 'test') doc = filter(link, current_user: user) @@ -94,7 +94,7 @@ describe Banzai::Filter::RedactorFilter do it 'removes references for project members with guest role' do member = create(:user) project = create(:project, :public) - project.team << [member, :guest] + project.add_guest(member) issue = create(:issue, :confidential, project: project) link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') @@ -128,7 +128,7 @@ describe Banzai::Filter::RedactorFilter do it 'allows references for project members' do member = create(:user) project = create(:project, :public) - project.team << [member, :developer] + project.add_developer(member) issue = create(:issue, :confidential, project: project) link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') diff --git a/spec/lib/banzai/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb index fc03741976e..c76adc262fc 100644 --- a/spec/lib/banzai/filter/user_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb @@ -34,11 +34,11 @@ describe Banzai::Filter::UserReferenceFilter do let(:reference) { User.reference_prefix + 'all' } before do - project.team << [project.creator, :developer] + project.add_developer(project.creator) end it 'supports a special @all mention' do - project.team << [user, :developer] + project.add_developer(user) doc = reference_filter("Hey #{reference}", author: user) expect(doc.css('a').length).to eq 1 @@ -47,7 +47,7 @@ describe Banzai::Filter::UserReferenceFilter do end it 'includes a data-author attribute when there is an author' do - project.team << [user, :developer] + project.add_developer(user) doc = reference_filter(reference, author: user) expect(doc.css('a').first.attr('data-author')).to eq(user.id.to_s) diff --git a/spec/lib/banzai/reference_parser/user_parser_spec.rb b/spec/lib/banzai/reference_parser/user_parser_spec.rb index e49726aca6c..b079a3be029 100644 --- a/spec/lib/banzai/reference_parser/user_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/user_parser_spec.rb @@ -63,8 +63,8 @@ describe Banzai::ReferenceParser::UserParser do let(:contributor) { create(:user) } before do - project.team << [user, :developer] - project.team << [contributor, :developer] + project.add_developer(user) + project.add_developer(contributor) end it 'returns the members of a project' do @@ -162,7 +162,7 @@ describe Banzai::ReferenceParser::UserParser do context 'when the link has a data-author attribute' do it 'returns the nodes when the user is a member of the project' do other_project = create(:project) - other_project.team << [user, :developer] + other_project.add_developer(user) link['data-project'] = other_project.id.to_s link['data-author'] = user.id.to_s diff --git a/spec/lib/gitlab/ci/status/build/common_spec.rb b/spec/lib/gitlab/ci/status/build/common_spec.rb index 03d1f46b517..2cce7a23ea7 100644 --- a/spec/lib/gitlab/ci/status/build/common_spec.rb +++ b/spec/lib/gitlab/ci/status/build/common_spec.rb @@ -18,7 +18,7 @@ describe Gitlab::Ci::Status::Build::Common do describe '#has_details?' do context 'when user has access to read build' do before do - project.team << [user, :developer] + project.add_developer(user) end it { is_expected.to have_details } diff --git a/spec/lib/gitlab/ci/status/external/common_spec.rb b/spec/lib/gitlab/ci/status/external/common_spec.rb index b38fbee2486..40871f86568 100644 --- a/spec/lib/gitlab/ci/status/external/common_spec.rb +++ b/spec/lib/gitlab/ci/status/external/common_spec.rb @@ -29,7 +29,7 @@ describe Gitlab::Ci::Status::External::Common do describe '#has_details?' do context 'when user has access to read commit status' do before do - project.team << [user, :developer] + project.add_developer(user) end it { is_expected.to have_details } diff --git a/spec/lib/gitlab/ci/status/external/factory_spec.rb b/spec/lib/gitlab/ci/status/external/factory_spec.rb index c96fd53e730..529d02a3e39 100644 --- a/spec/lib/gitlab/ci/status/external/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/external/factory_spec.rb @@ -8,7 +8,7 @@ describe Gitlab::Ci::Status::External::Factory do let(:external_url) { 'http://gitlab.com/status' } before do - project.team << [user, :developer] + project.add_developer(user) end context 'when external status has a simple core status' do diff --git a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb index 4a5b45e7cae..57df8325635 100644 --- a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb +++ b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb @@ -18,7 +18,7 @@ describe Gitlab::Ci::Status::Pipeline::Common do describe '#has_details?' do context 'when user has access to read pipeline' do before do - project.team << [user, :developer] + project.add_developer(user) end it { is_expected.to have_details } diff --git a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb index dd754b849b2..defb3fdc0df 100644 --- a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb @@ -7,7 +7,7 @@ describe Gitlab::Ci::Status::Pipeline::Factory do let(:factory) { described_class.new(pipeline, user) } before do - project.team << [user, :developer] + project.add_developer(user) end context 'when pipeline has a core status' do diff --git a/spec/lib/gitlab/ci/status/stage/common_spec.rb b/spec/lib/gitlab/ci/status/stage/common_spec.rb index f5f03ac0395..6ec35f8da7e 100644 --- a/spec/lib/gitlab/ci/status/stage/common_spec.rb +++ b/spec/lib/gitlab/ci/status/stage/common_spec.rb @@ -27,7 +27,7 @@ describe Gitlab::Ci::Status::Stage::Common do context 'when user has permission to read pipeline' do before do - project.team << [user, :master] + project.add_master(user) end it 'has details' do diff --git a/spec/lib/gitlab/ci/status/stage/factory_spec.rb b/spec/lib/gitlab/ci/status/stage/factory_spec.rb index 432b07e4902..dee4f4efd1b 100644 --- a/spec/lib/gitlab/ci/status/stage/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/stage/factory_spec.rb @@ -18,7 +18,7 @@ describe Gitlab::Ci::Status::Stage::Factory do end before do - project.team << [user, :developer] + project.add_developer(user) end context 'when stage has a core status' do diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb index ef7d766a13d..8c79ef54c6c 100644 --- a/spec/lib/gitlab/closing_issue_extractor_spec.rb +++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb @@ -13,8 +13,8 @@ describe Gitlab::ClosingIssueExtractor do subject { described_class.new(project, project.creator) } before do - project.team << [project.creator, :developer] - project2.team << [project.creator, :master] + project.add_developer(project.creator) + project2.add_master(project.creator) end describe "#closed_by_message" do @@ -297,7 +297,7 @@ describe Gitlab::ClosingIssueExtractor do context 'with an external issue tracker reference' do it 'extracts the referenced issue' do jira_project = create(:jira_project, name: 'JIRA_EXT1') - jira_project.team << [jira_project.creator, :master] + jira_project.add_master(jira_project.creator) jira_issue = ExternalIssue.new("#{jira_project.name}-1", project: jira_project) closing_issue_extractor = described_class.new(jira_project, jira_project.creator) message = "Resolve #{jira_issue.to_reference}" diff --git a/spec/lib/gitlab/cycle_analytics/permissions_spec.rb b/spec/lib/gitlab/cycle_analytics/permissions_spec.rb index 2a0dd7be439..6de4bd3dc7c 100644 --- a/spec/lib/gitlab/cycle_analytics/permissions_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/permissions_spec.rb @@ -38,7 +38,7 @@ describe Gitlab::CycleAnalytics::Permissions do context 'user is master' do before do - project.team << [user, :master] + project.add_master(user) end it 'has permissions to issue stage' do @@ -72,7 +72,7 @@ describe Gitlab::CycleAnalytics::Permissions do context 'user has no build permissions' do before do - project.team << [user, :guest] + project.add_guest(user) end it 'has permissions to issue stage' do @@ -90,7 +90,7 @@ describe Gitlab::CycleAnalytics::Permissions do context 'user has no merge request permissions' do before do - project.team << [user, :guest] + project.add_guest(user) end it 'has permissions to issue stage' do @@ -108,7 +108,7 @@ describe Gitlab::CycleAnalytics::Permissions do context 'user has no issue permissions' do before do - project.team << [user, :developer] + project.add_developer(user) project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED) end 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 d0fa16ce4d1..031efcf1291 100644 --- a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb +++ b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb @@ -66,7 +66,7 @@ describe Gitlab::Email::Handler::CreateNoteHandler do context 'and current user can update noteable' do before do - project.team << [user, :developer] + project.add_developer(user) end it 'does not raise an error' do @@ -99,7 +99,7 @@ describe Gitlab::Email::Handler::CreateNoteHandler do context 'and current user can update noteable' do before do - project.team << [user, :developer] + project.add_developer(user) end it 'post a note and updates the noteable' do diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb index 7dc06c90078..4d2f08f95fc 100644 --- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb +++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb @@ -10,7 +10,7 @@ describe Gitlab::Gfm::ReferenceRewriter do let(:text) { 'some text' } before do - old_project.team << [user, :reporter] + old_project.add_reporter(user) end describe '#rewrite' do diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 03a9cc488ca..d20a2ca935f 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -1670,7 +1670,7 @@ describe Gitlab::Git::Repository, seed_helper: true do let(:branch_name) { "to-be-deleted-soon" } before do - project.team << [user, :developer] + project.add_developer(user) repository.create_branch(branch_name) end diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index 2db560c2cec..4290fbb0087 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -275,7 +275,7 @@ describe Gitlab::GitAccess do describe '#check_command_disabled!' do before do - project.team << [user, :master] + project.add_master(user) end context 'over http' do @@ -404,7 +404,7 @@ describe Gitlab::GitAccess do describe 'reporter user' do before do - project.team << [user, :reporter] + project.add_reporter(user) end context 'pull code' do @@ -417,7 +417,7 @@ describe Gitlab::GitAccess do context 'when member of the project' do before do - project.team << [user, :reporter] + project.add_reporter(user) end context 'pull code' do @@ -497,7 +497,7 @@ describe Gitlab::GitAccess do if role == :admin user.update_attribute(:admin, true) else - project.team << [user, role] + project.add_role(user, role) end aggregate_failures do @@ -658,7 +658,7 @@ describe Gitlab::GitAccess do context 'when project is authorized' do before do - project.team << [user, :reporter] + project.add_reporter(user) end it { expect { push_access_check }.to raise_unauthorized(described_class::ERROR_MESSAGES[:upload]) } diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb index 1056074264a..186b2d9279d 100644 --- a/spec/lib/gitlab/git_access_wiki_spec.rb +++ b/spec/lib/gitlab/git_access_wiki_spec.rb @@ -18,7 +18,7 @@ describe Gitlab::GitAccessWiki do context 'when user can :create_wiki' do before do create(:protected_branch, name: 'master', project: project) - project.team << [user, :developer] + project.add_developer(user) end subject { access.check('git-receive-pack', changes) } @@ -41,7 +41,7 @@ describe Gitlab::GitAccessWiki do subject { access.check('git-upload-pack', '_any') } before do - project.team << [user, :developer] + project.add_developer(user) end context 'when wiki feature is enabled' do diff --git a/spec/lib/gitlab/google_code_import/importer_spec.rb b/spec/lib/gitlab/google_code_import/importer_spec.rb index 798ea0bac58..017facd0f5e 100644 --- a/spec/lib/gitlab/google_code_import/importer_spec.rb +++ b/spec/lib/gitlab/google_code_import/importer_spec.rb @@ -15,7 +15,7 @@ describe Gitlab::GoogleCodeImport::Importer do subject { described_class.new(project) } before do - project.team << [project.creator, :master] + project.add_master(project.creator) project.create_import_data(data: import_data) end 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 6243b6ac9f0..6faf3d82981 100644 --- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb @@ -9,7 +9,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver do let!(:project) { setup_project } before do - project.team << [user, :master] + project.add_master(user) allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) allow_any_instance_of(MergeRequest).to receive(:source_branch_sha).and_return('ABCD') allow_any_instance_of(MergeRequest).to receive(:target_branch_sha).and_return('DCBA') diff --git a/spec/lib/gitlab/import_export/repo_saver_spec.rb b/spec/lib/gitlab/import_export/repo_saver_spec.rb index e6ad516deef..44f972fe530 100644 --- a/spec/lib/gitlab/import_export/repo_saver_spec.rb +++ b/spec/lib/gitlab/import_export/repo_saver_spec.rb @@ -9,7 +9,7 @@ describe Gitlab::ImportExport::RepoSaver do let(:bundler) { described_class.new(project: project, shared: shared) } before do - project.team << [user, :master] + project.add_master(user) allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) end 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 0e55993c8ef..1d1e7e7f89a 100644 --- a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb +++ b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb @@ -10,7 +10,7 @@ describe Gitlab::ImportExport::WikiRepoSaver do let!(:project_wiki) { ProjectWiki.new(project, user) } before do - project.team << [user, :master] + project.add_master(user) allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) project_wiki.wiki project_wiki.create_page("index", "test content") diff --git a/spec/lib/gitlab/project_authorizations_spec.rb b/spec/lib/gitlab/project_authorizations_spec.rb index 953cfbb8b88..f3cd6961e94 100644 --- a/spec/lib/gitlab/project_authorizations_spec.rb +++ b/spec/lib/gitlab/project_authorizations_spec.rb @@ -15,7 +15,7 @@ describe Gitlab::ProjectAuthorizations do end before do - other_project.team << [user, :reporter] + other_project.add_reporter(user) group.add_developer(user) end diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb index a424f0f5cfe..17937726f2c 100644 --- a/spec/lib/gitlab/project_search_results_spec.rb +++ b/spec/lib/gitlab/project_search_results_spec.rb @@ -179,7 +179,7 @@ describe Gitlab::ProjectSearchResults do end it 'does not list project confidential issues for project members with guest role' do - project.team << [member, :guest] + project.add_guest(member) results = described_class.new(member, project, query) issues = results.objects('issues') @@ -211,7 +211,7 @@ describe Gitlab::ProjectSearchResults do end it 'lists project confidential issues for project members' do - project.team << [member, :developer] + project.add_developer(member) results = described_class.new(member, project, query) issues = results.objects('issues') @@ -290,12 +290,12 @@ describe Gitlab::ProjectSearchResults do let!(:private_project) { create(:project, :private, :repository, creator: creator, namespace: creator.namespace) } let(:team_master) do user = create(:user, username: 'private-project-master') - private_project.team << [user, :master] + private_project.add_master(user) user end let(:team_reporter) do user = create(:user, username: 'private-project-reporter') - private_project.team << [user, :reporter] + private_project.add_reporter(user) user end diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb index 8ec3f55e6de..4139d1c650c 100644 --- a/spec/lib/gitlab/reference_extractor_spec.rb +++ b/spec/lib/gitlab/reference_extractor_spec.rb @@ -4,7 +4,7 @@ describe Gitlab::ReferenceExtractor do let(:project) { create(:project) } before do - project.team << [project.creator, :developer] + project.add_developer(project.creator) end subject { described_class.new(project, project.creator) } @@ -14,8 +14,8 @@ describe Gitlab::ReferenceExtractor do @u_bar = create(:user, username: 'bar') @u_offteam = create(:user, username: 'offteam') - project.team << [@u_foo, :reporter] - project.team << [@u_bar, :guest] + project.add_guest(@u_foo) + project.add_guest(@u_bar) subject.analyze('@foo, @baduser, @bar, and @offteam') expect(subject.users).to match_array([@u_foo, @u_bar, @u_offteam]) @@ -26,8 +26,8 @@ describe Gitlab::ReferenceExtractor do @u_bar = create(:user, username: 'bar') @u_offteam = create(:user, username: 'offteam') - project.team << [@u_foo, :reporter] - project.team << [@u_bar, :guest] + project.add_reporter(@u_foo) + project.add_reporter(@u_bar) subject.analyze(%Q{ Inline code: `@foo` @@ -228,7 +228,7 @@ describe Gitlab::ReferenceExtractor do let(:issue) { create(:issue, project: other_project) } before do - other_project.team << [project.creator, :developer] + other_project.add_developer(project.creator) end it 'handles project issue references' do @@ -246,7 +246,7 @@ describe Gitlab::ReferenceExtractor do let(:text) { "Ref. #{issue.to_reference} and #{label.to_reference}" } before do - project.team << [project.creator, :developer] + project.add_developer(project.creator) subject.analyze(text) end diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb index a958baab44f..3dbe510b7ba 100644 --- a/spec/lib/gitlab/search_results_spec.rb +++ b/spec/lib/gitlab/search_results_spec.rb @@ -16,7 +16,7 @@ describe Gitlab::SearchResults do context 'as a user with access' do before do - project.team << [user, :developer] + project.add_developer(user) end describe '#projects_count' do @@ -104,8 +104,8 @@ describe Gitlab::SearchResults do end it 'does not list confidential issues for project members with guest role' do - project_1.team << [member, :guest] - project_2.team << [member, :guest] + project_1.add_guest(member) + project_2.add_guest(member) results = described_class.new(member, limit_projects, query) issues = results.objects('issues') @@ -146,8 +146,8 @@ describe Gitlab::SearchResults do end it 'lists confidential issues for project members' do - project_1.team << [member, :developer] - project_2.team << [member, :developer] + project_1.add_developer(member) + project_2.add_developer(member) results = described_class.new(member, limit_projects, query) issues = results.objects('issues') diff --git a/spec/lib/gitlab/slash_commands/issue_new_spec.rb b/spec/lib/gitlab/slash_commands/issue_new_spec.rb index 75ae58d0582..3b077c58c50 100644 --- a/spec/lib/gitlab/slash_commands/issue_new_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_new_spec.rb @@ -7,7 +7,7 @@ describe Gitlab::SlashCommands::IssueNew do let(:regex_match) { described_class.match("issue create bird is the word") } before do - project.team << [user, :master] + project.add_master(user) end subject do diff --git a/spec/lib/gitlab/slash_commands/issue_search_spec.rb b/spec/lib/gitlab/slash_commands/issue_search_spec.rb index 51f59216413..e41e5254dde 100644 --- a/spec/lib/gitlab/slash_commands/issue_search_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_search_spec.rb @@ -21,7 +21,7 @@ describe Gitlab::SlashCommands::IssueSearch do context 'the user has access' do before do - project.team << [user, :master] + project.add_master(user) end it 'returns all results' do diff --git a/spec/lib/gitlab/slash_commands/issue_show_spec.rb b/spec/lib/gitlab/slash_commands/issue_show_spec.rb index 08c380ca8f1..e5834d5a2ee 100644 --- a/spec/lib/gitlab/slash_commands/issue_show_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_show_spec.rb @@ -8,7 +8,7 @@ describe Gitlab::SlashCommands::IssueShow do let(:regex_match) { described_class.match("issue show #{issue.iid}") } before do - project.team << [user, :master] + project.add_master(user) end subject do diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb index cd97416bcc9..7280acb6c82 100644 --- a/spec/lib/gitlab/user_access_spec.rb +++ b/spec/lib/gitlab/user_access_spec.rb @@ -8,19 +8,19 @@ describe Gitlab::UserAccess do describe '#can_push_to_branch?' do describe 'push to none protected branch' do it 'returns true if user is a master' do - project.team << [user, :master] + project.add_master(user) expect(access.can_push_to_branch?('random_branch')).to be_truthy end it 'returns true if user is a developer' do - project.team << [user, :developer] + project.add_developer(user) expect(access.can_push_to_branch?('random_branch')).to be_truthy end it 'returns false if user is a reporter' do - project.team << [user, :reporter] + project.add_reporter(user) expect(access.can_push_to_branch?('random_branch')).to be_falsey end @@ -31,34 +31,34 @@ describe Gitlab::UserAccess do let(:project_access) { described_class.new(user, project: empty_project) } it 'returns true if user is master' do - empty_project.team << [user, :master] + empty_project.add_master(user) expect(project_access.can_push_to_branch?('master')).to be_truthy end it 'returns false if user is developer and project is fully protected' do - empty_project.team << [user, :developer] + empty_project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_FULL) expect(project_access.can_push_to_branch?('master')).to be_falsey end it 'returns false if user is developer and it is not allowed to push new commits but can merge into branch' do - empty_project.team << [user, :developer] + empty_project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE) expect(project_access.can_push_to_branch?('master')).to be_falsey end it 'returns true if user is developer and project is unprotected' do - empty_project.team << [user, :developer] + empty_project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE) expect(project_access.can_push_to_branch?('master')).to be_truthy end it 'returns true if user is developer and project grants developers permission' do - empty_project.team << [user, :developer] + empty_project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH) expect(project_access.can_push_to_branch?('master')).to be_truthy @@ -70,25 +70,25 @@ describe Gitlab::UserAccess do let(:not_existing_branch) { create :protected_branch, :developers_can_merge, project: project } it 'returns true if user is a master' do - project.team << [user, :master] + project.add_master(user) expect(access.can_push_to_branch?(branch.name)).to be_truthy end it 'returns false if user is a developer' do - project.team << [user, :developer] + project.add_developer(user) expect(access.can_push_to_branch?(branch.name)).to be_falsey end it 'returns false if user is a reporter' do - project.team << [user, :reporter] + project.add_reporter(user) expect(access.can_push_to_branch?(branch.name)).to be_falsey end it 'returns false if branch does not exist' do - project.team << [user, :developer] + project.add_developer(user) expect(access.can_push_to_branch?(not_existing_branch.name)).to be_falsey end @@ -100,19 +100,19 @@ describe Gitlab::UserAccess do end it 'returns true if user is a master' do - project.team << [user, :master] + project.add_master(user) expect(access.can_push_to_branch?(@branch.name)).to be_truthy end it 'returns true if user is a developer' do - project.team << [user, :developer] + project.add_developer(user) expect(access.can_push_to_branch?(@branch.name)).to be_truthy end it 'returns false if user is a reporter' do - project.team << [user, :reporter] + project.add_reporter(user) expect(access.can_push_to_branch?(@branch.name)).to be_falsey end @@ -124,19 +124,19 @@ describe Gitlab::UserAccess do end it 'returns true if user is a master' do - project.team << [user, :master] + project.add_master(user) expect(access.can_merge_to_branch?(@branch.name)).to be_truthy end it 'returns true if user is a developer' do - project.team << [user, :developer] + project.add_developer(user) expect(access.can_merge_to_branch?(@branch.name)).to be_truthy end it 'returns false if user is a reporter' do - project.team << [user, :reporter] + project.add_reporter(user) expect(access.can_merge_to_branch?(@branch.name)).to be_falsey end diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 4d0a3942996..cbc8c67da61 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -417,7 +417,7 @@ describe Notify do context 'for a project in a user namespace' do let(:project) do create(:project, :public, :access_requestable) do |project| - project.team << [project.owner, :master, project.owner] + project.add_master(project.owner, current_user: project.owner) end end @@ -520,7 +520,7 @@ describe Notify do end describe 'project invitation' do - let(:master) { create(:user).tap { |u| project.team << [u, :master] } } + let(:master) { create(:user).tap { |u| project.add_master(u) } } let(:project_member) { invite_to_project(project, inviter: master) } subject { described_class.member_invited_email('project', project_member.id, project_member.invite_token) } @@ -540,7 +540,7 @@ describe Notify do describe 'project invitation accepted' do let(:invited_user) { create(:user, name: 'invited user') } - let(:master) { create(:user).tap { |u| project.team << [u, :master] } } + let(:master) { create(:user).tap { |u| project.add_master(u) } } let(:project_member) do invitee = invite_to_project(project, inviter: master) invitee.accept_invite!(invited_user) @@ -563,7 +563,7 @@ describe Notify do end describe 'project invitation declined' do - let(:master) { create(:user).tap { |u| project.team << [u, :master] } } + let(:master) { create(:user).tap { |u| project.add_master(u) } } let(:project_member) do invitee = invite_to_project(project, inviter: master) invitee.decline_invite! diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 71aa51e1857..38fb98d4f50 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -34,19 +34,19 @@ describe Ability do end it 'returns false for a guest user' do - project.team << [user, :guest] + project.add_guest(user) expect(described_class.can_edit_note?(user, note)).to be_falsy end it 'returns false for a developer' do - project.team << [user, :developer] + project.add_developer(user) expect(described_class.can_edit_note?(user, note)).to be_falsy end it 'returns true for a master' do - project.team << [user, :master] + project.add_master(user) expect(described_class.can_edit_note?(user, note)).to be_truthy end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index a1f63a2534b..7bef798a782 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -1440,7 +1440,7 @@ describe Ci::Pipeline, :mailer do end before do - project.team << [pipeline.user, Gitlab::Access::DEVELOPER] + project.add_developer(pipeline.user) pipeline.user.global_notification_setting .update(level: 'custom', failed_pipeline: true, success_pipeline: true) diff --git a/spec/models/ci/trigger_spec.rb b/spec/models/ci/trigger_spec.rb index bd9c837402f..d4b72205203 100644 --- a/spec/models/ci/trigger_spec.rb +++ b/spec/models/ci/trigger_spec.rb @@ -69,7 +69,7 @@ describe Ci::Trigger do context 'and is member of the project' do before do - project.team << [owner, :developer] + project.add_developer(owner) end it { is_expected.to eq(true) } diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index cd955a5eb69..4f02dc33cd8 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -193,8 +193,8 @@ eos let(:commiter) { create :user } before do - project.team << [commiter, :developer] - other_project.team << [commiter, :developer] + project.add_developer(commiter) + other_project.add_developer(commiter) end it 'detects issues that this commit is marked as closing' do diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb index 8b545aec7f5..c73ea6aa94c 100644 --- a/spec/models/concerns/mentionable_spec.rb +++ b/spec/models/concerns/mentionable_spec.rb @@ -62,7 +62,7 @@ describe Issue, "Mentionable" do context 'when the current user can see the issue' do before do - private_project.team << [user, Gitlab::Access::DEVELOPER] + private_project.add_developer(user) end it 'includes the reference' do @@ -107,7 +107,7 @@ describe Issue, "Mentionable" do let(:issues) { create_list(:issue, 2, project: project, author: author) } before do - project.team << [author, Gitlab::Access::DEVELOPER] + project.add_developer(author) end context 'before changes are persisted' do diff --git a/spec/models/concerns/milestoneish_spec.rb b/spec/models/concerns/milestoneish_spec.rb index 673c609f534..87bf731340f 100644 --- a/spec/models/concerns/milestoneish_spec.rb +++ b/spec/models/concerns/milestoneish_spec.rb @@ -24,8 +24,8 @@ describe Milestone, 'Milestoneish' do let(:label_3) { create(:label, title: 'label_3', project: project) } before do - project.team << [member, :developer] - project.team << [guest, :guest] + project.add_developer(member) + project.add_guest(guest) end describe '#sorted_issues' do diff --git a/spec/models/concerns/resolvable_discussion_spec.rb b/spec/models/concerns/resolvable_discussion_spec.rb index 1616c2ea985..2a2ef5a304d 100644 --- a/spec/models/concerns/resolvable_discussion_spec.rb +++ b/spec/models/concerns/resolvable_discussion_spec.rb @@ -190,7 +190,7 @@ describe Discussion, ResolvableDiscussion do context "when the signed in user can push to the project" do before do - subject.project.team << [current_user, :master] + subject.project.add_master(current_user) end it "returns true" do diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index aa7a8342a4c..e999192940c 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -125,8 +125,8 @@ describe Event do let(:event) { described_class.new(project: project, target: target, author_id: author.id) } before do - project.team << [member, :developer] - project.team << [guest, :guest] + project.add_developer(member) + project.add_guest(guest) end context 'commit note event' do diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb index 7f1909710d8..673049d1cc4 100644 --- a/spec/models/generic_commit_status_spec.rb +++ b/spec/models/generic_commit_status_spec.rb @@ -43,7 +43,7 @@ describe GenericCommitStatus do context 'when user has ability to see datails' do before do - project.team << [user, :developer] + project.add_developer(user) end it 'details path points to an external URL' do diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb index 431e3db9f00..0e965f541d8 100644 --- a/spec/models/hooks/system_hook_spec.rb +++ b/spec/models/hooks/system_hook_spec.rb @@ -62,7 +62,7 @@ describe SystemHook do end it "project_create hook" do - project.team << [user, :master] + project.add_master(user) expect(WebMock).to have_requested(:post, system_hook.url).with( body: /user_add_to_team/, @@ -71,7 +71,7 @@ describe SystemHook do end it "project_destroy hook" do - project.team << [user, :master] + project.add_master(user) project.project_members.destroy_all expect(WebMock).to have_requested(:post, system_hook.url).with( diff --git a/spec/models/issue_collection_spec.rb b/spec/models/issue_collection_spec.rb index 34d98a3c975..580a98193af 100644 --- a/spec/models/issue_collection_spec.rb +++ b/spec/models/issue_collection_spec.rb @@ -42,7 +42,7 @@ describe IssueCollection do context 'using a user that has reporter access to the project' do it 'returns the issues of the project' do - project.team << [user, :reporter] + project.add_reporter(user) expect(collection.updatable_by_user(user)).to eq([issue1, issue2]) end diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index 0ea287d007a..c9deeb45c1a 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -238,7 +238,7 @@ describe Issue do let(:issue) { create(:issue, project: project) } before do - project.team << [user, :reporter] + project.add_reporter(user) end it { is_expected.to eq true } @@ -254,7 +254,7 @@ describe Issue do context 'destination project allowed' do before do - to_project.team << [user, :reporter] + to_project.add_reporter(user) end it { is_expected.to eq true } @@ -262,7 +262,7 @@ describe Issue do context 'destination project not allowed' do before do - to_project.team << [user, :guest] + to_project.add_guest(user) end it { is_expected.to eq false } @@ -550,7 +550,7 @@ describe Issue do context 'when the user is the project owner' do before do - project.team << [user, :master] + project.add_master(user) end it 'returns true for a regular issue' do @@ -574,7 +574,7 @@ describe Issue do context 'using a public project' do before do - project.team << [user, Gitlab::Access::DEVELOPER] + project.add_developer(user) end it 'returns true for a regular issue' do @@ -594,7 +594,7 @@ describe Issue do let(:project) { create(:project, :internal) } before do - project.team << [user, Gitlab::Access::DEVELOPER] + project.add_developer(user) end it 'returns true for a regular issue' do @@ -614,7 +614,7 @@ describe Issue do let(:project) { create(:project, :private) } before do - project.team << [user, Gitlab::Access::DEVELOPER] + project.add_developer(user) end it 'returns true for a regular issue' do diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb index 0a017c068ad..6aa0e7f49c3 100644 --- a/spec/models/member_spec.rb +++ b/spec/models/member_spec.rb @@ -62,12 +62,12 @@ describe Member do @owner_user = create(:user).tap { |u| group.add_owner(u) } @owner = group.members.find_by(user_id: @owner_user.id) - @master_user = create(:user).tap { |u| project.team << [u, :master] } + @master_user = create(:user).tap { |u| project.add_master(u) } @master = project.members.find_by(user_id: @master_user.id) @blocked_user = create(:user).tap do |u| - project.team << [u, :master] - project.team << [u, :developer] + project.add_master(u) + project.add_developer(u) u.block! end @@ -527,7 +527,7 @@ describe Member do it "refreshes user's authorized projects" do project = create(:project, :private) user = create(:user) - member = project.team << [user, :reporter] + member = project.add_reporter(user) member.destroy diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb index fa3e80ba062..3e46fa36375 100644 --- a/spec/models/members/project_member_spec.rb +++ b/spec/models/members/project_member_spec.rb @@ -88,8 +88,8 @@ describe ProjectMember do @user_1 = create :user @user_2 = create :user - @project_1.team << [@user_1, :developer] - @project_2.team << [@user_2, :reporter] + @project_1.add_developer(@user_1) + @project_2.add_reporter(@user_2) @status = @project_2.team.import(@project_1) end @@ -136,8 +136,8 @@ describe ProjectMember do @user_1 = create :user @user_2 = create :user - @project_1.team << [@user_1, :developer] - @project_2.team << [@user_2, :reporter] + @project_1.add_developer(@user_1) + @project_2.add_reporter(@user_2) described_class.truncate_teams([@project_1.id, @project_2.id]) end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index bb63abd167b..df94617a19e 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -195,7 +195,7 @@ describe MergeRequest do describe '#cache_merge_request_closes_issues!' do before do - subject.project.team << [subject.author, :developer] + subject.project.add_developer(subject.author) subject.target_branch = subject.project.default_branch end @@ -481,7 +481,7 @@ describe MergeRequest do let(:commit2) { double('commit2', safe_message: "Fixes #{issue1.to_reference}") } before do - subject.project.team << [subject.author, :developer] + subject.project.add_developer(subject.author) allow(subject).to receive(:commits).and_return([commit0, commit1, commit2]) end @@ -509,7 +509,7 @@ describe MergeRequest do let(:commit) { double('commit', safe_message: "Fixes #{closing_issue.to_reference}") } it 'detects issues mentioned in description but not closed' do - subject.project.team << [subject.author, :developer] + subject.project.add_developer(subject.author) subject.description = "Is related to #{mentioned_issue.to_reference} and #{closing_issue.to_reference}" allow(subject).to receive(:commits).and_return([commit]) @@ -521,7 +521,7 @@ describe MergeRequest do context 'when the project has an external issue tracker' do before do - subject.project.team << [subject.author, :developer] + subject.project.add_developer(subject.author) commit = double(:commit, safe_message: 'Fixes TEST-3') create(:jira_service, project: subject.project) @@ -660,7 +660,7 @@ describe MergeRequest do it 'includes its closed issues in the body' do issue = create(:issue, project: subject.project) - subject.project.team << [subject.author, :developer] + subject.project.add_developer(subject.author) subject.description = "This issue Closes #{issue.to_reference}" allow(subject.project).to receive(:default_branch) @@ -1688,7 +1688,7 @@ describe MergeRequest do let(:mr_sha) { merge_request.diff_head_sha } before do - project.team << [developer, :developer] + project.add_developer(developer) end context 'when autocomplete_precheck is set to true' do diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index cefbf60b28c..3d030927036 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -195,7 +195,7 @@ describe Note do describe "cross_reference_not_visible_for?" do let(:private_user) { create(:user) } - let(:private_project) { create(:project, namespace: private_user.namespace) { |p| p.team << [private_user, :master] } } + let(:private_project) { create(:project, namespace: private_user.namespace) { |p| p.add_master(private_user) } } let(:private_issue) { create(:issue, project: private_project) } let(:ext_proj) { create(:project, :public) } diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb index de3e86b627f..63c6fbda3f2 100644 --- a/spec/models/project_feature_spec.rb +++ b/spec/models/project_feature_spec.rb @@ -37,7 +37,7 @@ describe ProjectFeature do end it "returns true when user is a team member" do - project.team << [user, :developer] + project.add_developer(user) features.each do |feature| project.project_feature.update_attribute("#{feature}_access_level".to_sym, ProjectFeature::PRIVATE) diff --git a/spec/models/project_services/pipelines_email_service_spec.rb b/spec/models/project_services/pipelines_email_service_spec.rb index be07ca2d945..75ae2207910 100644 --- a/spec/models/project_services/pipelines_email_service_spec.rb +++ b/spec/models/project_services/pipelines_email_service_spec.rb @@ -37,7 +37,7 @@ describe PipelinesEmailService, :mailer do let(:user) { create(:user) } before do - project.team << [user, :developer] + project.add_developer(user) end it 'builds test data' do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index cbeac2f05d3..7338e341359 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -93,7 +93,7 @@ describe Project do let(:developer) { create(:user) } before do project.request_access(requester) - project.team << [developer, :developer] + project.add_developer(developer) end it_behaves_like 'members and requesters associations' do @@ -520,7 +520,7 @@ describe Project do let(:user) { create(:user) } before do - project.team << [user, :developer] + project.add_developer(user) end context 'with default issues tracker' do @@ -1435,35 +1435,35 @@ describe Project do let(:user) { create(:user) } it 'returns false when default_branch_protection is in full protection and user is developer' do - project.team << [user, :developer] + project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_FULL) expect(project.user_can_push_to_empty_repo?(user)).to be_falsey end it 'returns false when default_branch_protection only lets devs merge and user is dev' do - project.team << [user, :developer] + project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE) expect(project.user_can_push_to_empty_repo?(user)).to be_falsey end it 'returns true when default_branch_protection lets devs push and user is developer' do - project.team << [user, :developer] + project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH) expect(project.user_can_push_to_empty_repo?(user)).to be_truthy end it 'returns true when default_branch_protection is unprotected and user is developer' do - project.team << [user, :developer] + project.add_developer(user) stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE) expect(project.user_can_push_to_empty_repo?(user)).to be_truthy end it 'returns true when user is master' do - project.team << [user, :master] + project.add_master(user) expect(project.user_can_push_to_empty_repo?(user)).to be_truthy end diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 314824b32da..e07c522800a 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -291,8 +291,8 @@ describe ProjectTeam do group.add_master(master) group.add_developer(developer) - members_project.team << [developer, :developer] - members_project.team << [master, :master] + members_project.add_developer(developer) + members_project.add_master(master) create(:project_group_link, project: shared_project, group: group) end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index e58e7588df0..2557ce71f2b 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -760,7 +760,7 @@ describe User do before do # add user to project - project.team << [user, :master] + project.add_master(user) # create invite to projet create(:project_member, :developer, project: project, invite_token: '1234', invite_email: 'inviteduser1@example.com') @@ -1448,8 +1448,8 @@ describe User do let!(:merge_event) { create(:event, :created, project: project3, target: merge_request, author: subject) } before do - project1.team << [subject, :master] - project2.team << [subject, :master] + project1.add_master(subject) + project2.add_master(subject) end it "includes IDs for projects the user has pushed to" do @@ -1548,7 +1548,7 @@ describe User do user = create(:user) project = create(:project, :private) - project.team << [user, Gitlab::Access::MASTER] + project.add_master(user) expect(user.authorized_projects(Gitlab::Access::REPORTER)) .to contain_exactly(project) @@ -1567,7 +1567,7 @@ describe User do user2 = create(:user) project = create(:project, :private, namespace: user1.namespace) - project.team << [user2, Gitlab::Access::DEVELOPER] + project.add_developer(user2) expect(user2.authorized_projects).to include(project) end @@ -1612,7 +1612,7 @@ describe User do user2 = create(:user) project = create(:project, :private, namespace: user1.namespace) - project.team << [user2, Gitlab::Access::DEVELOPER] + project.add_developer(user2) expect(user2.authorized_projects).to include(project) @@ -1702,7 +1702,7 @@ describe User do shared_examples :member do context 'when the user is a master' do before do - add_user(Gitlab::Access::MASTER) + add_user(:master) end it 'loads' do @@ -1712,7 +1712,7 @@ describe User do context 'when the user is a developer' do before do - add_user(Gitlab::Access::DEVELOPER) + add_user(:developer) end it 'does not load' do @@ -1736,7 +1736,7 @@ describe User do let(:project) { create(:project) } def add_user(access) - project.team << [user, access] + project.add_role(user, access) end it_behaves_like :member @@ -1749,8 +1749,8 @@ describe User do let(:user) { create(:user) } before do - project1.team << [user, :reporter] - project2.team << [user, :guest] + project1.add_reporter(user) + project2.add_guest(user) end it 'returns the projects when using a single project ID' do @@ -1892,8 +1892,8 @@ describe User do let(:user) { create(:user) } before do - project1.team << [user, :reporter] - project2.team << [user, :guest] + project1.add_reporter(user) + project2.add_guest(user) user.project_authorizations.delete_all user.refresh_authorized_projects diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb index 298a9d16425..41cf2ef7225 100644 --- a/spec/policies/ci/build_policy_spec.rb +++ b/spec/policies/ci/build_policy_spec.rb @@ -57,7 +57,7 @@ describe Ci::BuildPolicy do context 'team member is a guest' do before do - project.team << [user, :guest] + project.add_guest(user) end context 'when public builds are enabled' do @@ -77,7 +77,7 @@ describe Ci::BuildPolicy do context 'team member is a reporter' do before do - project.team << [user, :reporter] + project.add_reporter(user) end context 'when public builds are enabled' do diff --git a/spec/policies/ci/trigger_policy_spec.rb b/spec/policies/ci/trigger_policy_spec.rb index be40dbb2aa9..14630748c90 100644 --- a/spec/policies/ci/trigger_policy_spec.rb +++ b/spec/policies/ci/trigger_policy_spec.rb @@ -45,7 +45,7 @@ describe Ci::TriggerPolicy do context 'when user is master of the project' do before do - project.team << [user, :master] + project.add_master(user) end it_behaves_like 'allows to admin and manage trigger' @@ -53,7 +53,7 @@ describe Ci::TriggerPolicy do context 'when user is developer of the project' do before do - project.team << [user, :developer] + project.add_developer(user) end it_behaves_like 'disallows to admin and manage trigger' @@ -69,7 +69,7 @@ describe Ci::TriggerPolicy do context 'when user is master of the project' do before do - project.team << [user, :master] + project.add_master(user) end it_behaves_like 'allows to admin and manage trigger' @@ -81,7 +81,7 @@ describe Ci::TriggerPolicy do context 'when user is master of the project' do before do - project.team << [user, :master] + project.add_master(user) end it_behaves_like 'allows to manage trigger' @@ -89,7 +89,7 @@ describe Ci::TriggerPolicy do context 'when user is developer of the project' do before do - project.team << [user, :developer] + project.add_developer(user) end it_behaves_like 'disallows to admin and manage trigger' diff --git a/spec/policies/issue_policy_spec.rb b/spec/policies/issue_policy_spec.rb index be4c24c727c..a4af9361ea6 100644 --- a/spec/policies/issue_policy_spec.rb +++ b/spec/policies/issue_policy_spec.rb @@ -19,10 +19,10 @@ describe IssuePolicy do let(:issue_no_assignee) { create(:issue, project: project) } before do - project.team << [guest, :guest] - project.team << [author, :guest] - project.team << [assignee, :guest] - project.team << [reporter, :reporter] + project.add_guest(guest) + project.add_guest(author) + project.add_guest(assignee) + project.add_reporter(reporter) group.add_reporter(reporter_from_group_link) @@ -114,8 +114,8 @@ describe IssuePolicy do let(:issue_no_assignee) { create(:issue, project: project) } before do - project.team << [guest, :guest] - project.team << [reporter, :reporter] + project.add_guest(guest) + project.add_reporter(reporter) group.add_reporter(reporter_from_group_link) diff --git a/spec/policies/project_snippet_policy_spec.rb b/spec/policies/project_snippet_policy_spec.rb index f0bf46c480a..cdba1b09fc1 100644 --- a/spec/policies/project_snippet_policy_spec.rb +++ b/spec/policies/project_snippet_policy_spec.rb @@ -87,7 +87,7 @@ describe ProjectSnippetPolicy do subject { abilities(external_user, :internal) } before do - project.team << [external_user, :developer] + project.add_developer(external_user) end it do @@ -131,7 +131,7 @@ describe ProjectSnippetPolicy do subject { abilities(regular_user, :private) } before do - project.team << [regular_user, :developer] + project.add_developer(regular_user) end it do @@ -144,7 +144,7 @@ describe ProjectSnippetPolicy do subject { abilities(external_user, :private) } before do - project.team << [external_user, :developer] + project.add_developer(external_user) end it do diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb index f325d1776e4..969c4753f33 100644 --- a/spec/presenters/merge_request_presenter_spec.rb +++ b/spec/presenters/merge_request_presenter_spec.rb @@ -116,7 +116,7 @@ describe MergeRequestPresenter do end before do - project.team << [user, :developer] + project.add_developer(user) allow(resource.project).to receive(:default_branch) .and_return(resource.target_branch) @@ -270,7 +270,7 @@ describe MergeRequestPresenter do context 'when can create issue and issues enabled' do it 'returns path' do allow(project).to receive(:issues_enabled?) { true } - project.team << [user, :master] + project.add_master(user) is_expected .to eq("/#{resource.project.full_path}/issues/new?merge_request_to_resolve_discussions_of=#{resource.iid}") @@ -288,7 +288,7 @@ describe MergeRequestPresenter do context 'when issues disabled' do it 'returns nil' do allow(project).to receive(:issues_enabled?) { false } - project.team << [user, :master] + project.add_master(user) is_expected.to be_nil end @@ -307,7 +307,7 @@ describe MergeRequestPresenter do context 'when merge request enabled and has permission' do it 'has remove_wip_path' do allow(project).to receive(:merge_requests_enabled?) { true } - project.team << [user, :master] + project.add_master(user) is_expected .to eq("/#{resource.project.full_path}/merge_requests/#{resource.iid}/remove_wip") diff --git a/spec/requests/api/access_requests_spec.rb b/spec/requests/api/access_requests_spec.rb index 35ca3635a9d..24389f28b21 100644 --- a/spec/requests/api/access_requests_spec.rb +++ b/spec/requests/api/access_requests_spec.rb @@ -8,8 +8,8 @@ describe API::AccessRequests do set(:project) do create(:project, :public, :access_requestable, creator_id: master.id, namespace: master.namespace) do |project| - project.team << [developer, :developer] - project.team << [master, :master] + project.add_developer(developer) + project.add_master(master) project.request_access(access_requester) end end diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb index eaf12f71421..5adfb33677f 100644 --- a/spec/requests/api/award_emoji_spec.rb +++ b/spec/requests/api/award_emoji_spec.rb @@ -10,7 +10,7 @@ describe API::AwardEmoji do set(:note) { create(:note, project: project, noteable: issue) } before do - project.team << [user, :master] + project.add_master(user) end describe "GET /projects/:id/awardable/:awardable_id/award_emoji" do diff --git a/spec/requests/api/boards_spec.rb b/spec/requests/api/boards_spec.rb index 546a1697e56..f65af69dc7f 100644 --- a/spec/requests/api/boards_spec.rb +++ b/spec/requests/api/boards_spec.rb @@ -33,8 +33,8 @@ describe API::Boards do end before do - project.team << [user, :reporter] - project.team << [guest, :guest] + project.add_reporter(user) + project.add_guest(guest) end describe "GET /projects/:id/boards" do diff --git a/spec/requests/api/deployments_spec.rb b/spec/requests/api/deployments_spec.rb index c7977e624ff..6732c99e329 100644 --- a/spec/requests/api/deployments_spec.rb +++ b/spec/requests/api/deployments_spec.rb @@ -7,7 +7,7 @@ describe API::Deployments do let!(:deployment) { create(:deployment) } before do - project.team << [user, :master] + project.add_master(user) end describe 'GET /projects/:id/deployments' do diff --git a/spec/requests/api/environments_spec.rb b/spec/requests/api/environments_spec.rb index 3665cfd7241..53d48a91007 100644 --- a/spec/requests/api/environments_spec.rb +++ b/spec/requests/api/environments_spec.rb @@ -7,7 +7,7 @@ describe API::Environments do let!(:environment) { create(:environment, project: project) } before do - project.team << [user, :master] + project.add_master(user) end describe 'GET /projects/:id/environments' do diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index 5d8338a3fb7..d8fdfd6dee1 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -14,7 +14,7 @@ describe API::Files do let(:author_name) { 'John Doe' } before do - project.team << [user, :developer] + project.add_developer(user) end def route(file_path = nil) diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index 6330c140246..3c0b4728dc2 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -417,7 +417,7 @@ describe API::Groups do end it "only returns projects to which user has access" do - project3.team << [user3, :developer] + project3.add_developer(user3) get api("/groups/#{group1.id}/projects", user3) diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index 3c31980b273..bbcd1194ae5 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -147,7 +147,7 @@ describe API::Internal do describe "POST /internal/lfs_authenticate" do before do - project.team << [user, :developer] + project.add_developer(user) end context 'user key' do @@ -199,7 +199,7 @@ describe API::Internal do end before do - project.team << [user, :developer] + project.add_developer(user) end context 'with env passed as a JSON' do @@ -359,7 +359,7 @@ describe API::Internal do context "access denied" do before do - project.team << [user, :guest] + project.add_guest(user) end context "git pull" do @@ -413,7 +413,7 @@ describe API::Internal do context "archived project" do before do - project.team << [user, :developer] + project.add_developer(user) project.archive! end @@ -527,7 +527,7 @@ describe API::Internal do context 'web actions are always allowed' do it 'allows WEB push' do stub_application_setting(enabled_git_access_protocol: 'ssh') - project.team << [user, :developer] + project.add_developer(user) push(key, project, 'web') expect(response.status).to eq(200) @@ -540,7 +540,7 @@ describe API::Internal do let!(:repository) { project.repository } before do - project.team << [user, :developer] + project.add_developer(user) project.path = 'new_path' project.save! end @@ -566,7 +566,7 @@ describe API::Internal do let(:changes) { URI.escape("#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch") } before do - project.team << [user, :developer] + project.add_developer(user) end it 'returns link to create new merge request' do @@ -701,7 +701,7 @@ describe API::Internal do end before do - project.team << [user, :developer] + project.add_developer(user) allow(described_class).to receive(:identify).and_return(user) allow_any_instance_of(Gitlab::Identifier).to receive(:identify).and_return(user) end diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 3f5070a1fd2..00d9c795619 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -58,8 +58,8 @@ describe API::Issues, :mailer do let(:no_milestone_title) { URI.escape(Milestone::None.title) } before(:all) do - project.team << [user, :reporter] - project.team << [guest, :guest] + project.add_reporter(user) + project.add_guest(guest) end describe "GET /issues" do @@ -344,7 +344,7 @@ describe API::Issues, :mailer do let!(:group_note) { create(:note_on_issue, author: user, project: group_project, noteable: group_issue) } before do - group_project.team << [user, :reporter] + group_project.add_reporter(user) end let(:base_url) { "/groups/#{group.id}/issues" } @@ -967,7 +967,7 @@ describe API::Issues, :mailer do let(:project) { merge_request.source_project } before do - project.team << [user, :master] + project.add_master(user) end context 'resolving all discussions in a merge request' do diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb index 2a83213e87a..e77745acbb7 100644 --- a/spec/requests/api/jobs_spec.rb +++ b/spec/requests/api/jobs_spec.rb @@ -503,7 +503,7 @@ describe API::Jobs do let(:role) { :master } before do - project.team << [user, role] + project.add_role(user, role) post api("/projects/#{project.id}/jobs/#{job.id}/erase", user) end diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb index 3498e5bc8d9..34cbf75f4c1 100644 --- a/spec/requests/api/labels_spec.rb +++ b/spec/requests/api/labels_spec.rb @@ -7,7 +7,7 @@ describe API::Labels do let!(:priority_label) { create(:label, title: 'bug', project: project, priority: 3) } before do - project.team << [user, :master] + project.add_master(user) end describe 'GET /projects/:id/labels' do diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb index 3349e396ab8..5d4f81e07a6 100644 --- a/spec/requests/api/members_spec.rb +++ b/spec/requests/api/members_spec.rb @@ -8,8 +8,8 @@ describe API::Members do let(:project) do create(:project, :public, :access_requestable, creator_id: master.id, namespace: master.namespace) do |project| - project.team << [developer, :developer] - project.team << [master, :master] + project.add_developer(developer) + project.add_master(master) project.request_access(access_requester) end end diff --git a/spec/requests/api/merge_request_diffs_spec.rb b/spec/requests/api/merge_request_diffs_spec.rb index bf4c8443b23..cb647aee70f 100644 --- a/spec/requests/api/merge_request_diffs_spec.rb +++ b/spec/requests/api/merge_request_diffs_spec.rb @@ -8,7 +8,7 @@ describe API::MergeRequestDiffs, 'MergeRequestDiffs' do before do merge_request.merge_request_diffs.create(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') merge_request.merge_request_diffs.create(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e') - project.team << [user, :master] + project.add_master(user) end describe 'GET /projects/:id/merge_requests/:merge_request_iid/versions' do diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 60dbd74d59d..ef3f610740d 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -25,7 +25,7 @@ describe API::MergeRequests do let!(:upvote) { create(:award_emoji, :upvote, awardable: merge_request) } before do - project.team << [user, :reporter] + project.add_reporter(user) end describe 'GET /merge_requests' do @@ -730,7 +730,7 @@ describe API::MergeRequests do let(:developer) { create(:user) } before do - project.team << [developer, :developer] + project.add_developer(developer) end it "denies the deletion of the merge request" do @@ -808,7 +808,7 @@ describe API::MergeRequests do it "returns 401 if user has no permissions to merge" do user2 = create(:user) - project.team << [user2, :reporter] + project.add_reporter(user2) put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user2) expect(response).to have_gitlab_http_status(401) expect(json_response['message']).to eq('401 Unauthorized') @@ -997,7 +997,7 @@ describe API::MergeRequests do project = create(:project, :private) merge_request = create(:merge_request, :simple, source_project: project) guest = create(:user) - project.team << [guest, :guest] + project.add_guest(guest) get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/closes_issues", guest) @@ -1045,7 +1045,7 @@ describe API::MergeRequests do it 'returns 403 if user has no access to read code' do guest = create(:user) - project.team << [guest, :guest] + project.add_guest(guest) post api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/subscribe", guest) @@ -1081,7 +1081,7 @@ describe API::MergeRequests do it 'returns 403 if user has no access to read code' do guest = create(:user) - project.team << [guest, :guest] + project.add_guest(guest) post api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/unsubscribe", guest) diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index 3bfb4c5506f..be8d9c19125 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -14,7 +14,7 @@ describe API::Notes do let(:private_user) { create(:user) } let(:private_project) do create(:project, namespace: private_user.namespace) - .tap { |p| p.team << [private_user, :master] } + .tap { |p| p.add_master(private_user) } end let(:private_issue) { create(:issue, project: private_project) } @@ -29,7 +29,7 @@ describe API::Notes do end before do - project.team << [user, :reporter] + project.add_reporter(user) end describe "GET /projects/:id/noteable/:noteable_id/notes" do diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb index e4dcc9252fa..0736329f9fd 100644 --- a/spec/requests/api/pipelines_spec.rb +++ b/spec/requests/api/pipelines_spec.rb @@ -11,7 +11,7 @@ describe API::Pipelines do end before do - project.team << [user, :master] + project.add_master(user) end describe 'GET /projects/:id/pipelines ' do @@ -424,7 +424,7 @@ describe API::Pipelines do let!(:reporter) { create(:user) } before do - project.team << [reporter, :reporter] + project.add_reporter(reporter) end it 'rejects the action' do diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb index f31344a6238..1fd082ecc38 100644 --- a/spec/requests/api/project_hooks_spec.rb +++ b/spec/requests/api/project_hooks_spec.rb @@ -13,8 +13,8 @@ describe API::ProjectHooks, 'ProjectHooks' do end before do - project.team << [user, :master] - project.team << [user3, :developer] + project.add_master(user) + project.add_developer(user3) end describe "GET /projects/:id/hooks" do @@ -206,7 +206,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.team << [test_user, :master] + other_project.add_master(test_user) delete api("/projects/#{other_project.id}/hooks/#{hook.id}", test_user) expect(response).to have_gitlab_http_status(404) diff --git a/spec/requests/api/project_milestones_spec.rb b/spec/requests/api/project_milestones_spec.rb index 72e1574b55f..6fe8ab5a3f6 100644 --- a/spec/requests/api/project_milestones_spec.rb +++ b/spec/requests/api/project_milestones_spec.rb @@ -7,7 +7,7 @@ describe API::ProjectMilestones do let!(:milestone) { create(:milestone, project: project, title: 'version2', description: 'open milestone') } before do - project.team << [user, :developer] + project.add_developer(user) end it_behaves_like 'group and project milestones', "/projects/:id/milestones" do diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index a41345da05b..de1763015fa 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -908,7 +908,7 @@ describe API::Projects do describe 'permissions' do context 'all projects' do before do - project.team << [user, :master] + project.add_master(user) end it 'contains permission information' do @@ -923,7 +923,7 @@ describe API::Projects do context 'personal project' do it 'sets project access and returns 200' do - project.team << [user, :master] + project.add_master(user) get api("/projects/#{project.id}", user) expect(response).to have_gitlab_http_status(200) @@ -1539,7 +1539,7 @@ describe API::Projects do context 'user without archiving rights to the project' do before do - project.team << [user3, :developer] + project.add_developer(user3) end it 'rejects the action' do @@ -1575,7 +1575,7 @@ describe API::Projects do context 'user without archiving rights to the project' do before do - project.team << [user3, :developer] + project.add_developer(user3) end it 'rejects the action' do @@ -1650,7 +1650,7 @@ describe API::Projects do it 'does not remove a project if not an owner' do user3 = create(:user) - project.team << [user3, :developer] + project.add_developer(user3) delete api("/projects/#{project.id}", user3) expect(response).to have_gitlab_http_status(403) end diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb index ba697e2b305..ceafa0e2058 100644 --- a/spec/requests/api/services_spec.rb +++ b/spec/requests/api/services_spec.rb @@ -92,7 +92,7 @@ describe API::Services do end it "returns error when authenticated but not a project owner" do - project.team << [user2, :developer] + project.add_developer(user2) get api("/projects/#{project.id}/services/#{dashed_service}", user2) expect(response).to have_gitlab_http_status(403) diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb index c6063a2e089..fb3a33cadff 100644 --- a/spec/requests/api/todos_spec.rb +++ b/spec/requests/api/todos_spec.rb @@ -13,8 +13,8 @@ describe API::Todos do let!(:done) { create(:todo, :done, project: project_1, author: author_1, user: john_doe) } before do - project_1.team << [john_doe, :developer] - project_2.team << [john_doe, :developer] + project_1.add_developer(john_doe) + project_2.add_developer(john_doe) end describe 'GET /todos' do @@ -191,7 +191,7 @@ describe API::Todos do it 'returns an error if the issuable is not accessible' do guest = create(:user) - project_1.team << [guest, :guest] + project_1.add_guest(guest) post api("/projects/#{project_1.id}/#{issuable_type}/#{issuable.iid}/todo", guest) diff --git a/spec/requests/api/v3/award_emoji_spec.rb b/spec/requests/api/v3/award_emoji_spec.rb index 0cd8b70007f..6dc430676b0 100644 --- a/spec/requests/api/v3/award_emoji_spec.rb +++ b/spec/requests/api/v3/award_emoji_spec.rb @@ -9,7 +9,7 @@ describe API::V3::AwardEmoji do let!(:downvote) { create(:award_emoji, :downvote, awardable: merge_request, user: user) } set(:note) { create(:note, project: project, noteable: issue) } - before { project.team << [user, :master] } + before { project.add_master(user) } describe "GET /projects/:id/awardable/:awardable_id/award_emoji" do context 'on an issue' do diff --git a/spec/requests/api/v3/boards_spec.rb b/spec/requests/api/v3/boards_spec.rb index 14409d25544..dde4f096193 100644 --- a/spec/requests/api/v3/boards_spec.rb +++ b/spec/requests/api/v3/boards_spec.rb @@ -27,8 +27,8 @@ describe API::V3::Boards do end before do - project.team << [user, :reporter] - project.team << [guest, :guest] + project.add_reporter(user) + project.add_guest(guest) end describe "GET /projects/:id/boards" do diff --git a/spec/requests/api/v3/commits_spec.rb b/spec/requests/api/v3/commits_spec.rb index d31c94ddd2c..8b115e01f47 100644 --- a/spec/requests/api/v3/commits_spec.rb +++ b/spec/requests/api/v3/commits_spec.rb @@ -9,11 +9,11 @@ describe API::V3::Commits do let!(:note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') } let!(:another_note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'another comment on a commit') } - before { project.team << [user, :reporter] } + before { project.add_reporter(user) } describe "List repository commits" do context "authorized user" do - before { project.team << [user2, :reporter] } + before { project.add_reporter(user2) } it "returns project commits" do commit = project.repository.commit @@ -415,7 +415,7 @@ describe API::V3::Commits do describe "Get the diff of a commit" do context "authorized user" do - before { project.team << [user2, :reporter] } + before { project.add_reporter(user2) } it "returns the diff of the selected commit" do get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff", user) @@ -487,7 +487,7 @@ describe API::V3::Commits do end it 'returns 400 if you are not allowed to push to the target branch' do - project.team << [user2, :developer] + project.add_developer(user2) protected_branch = create(:protected_branch, project: project, name: 'feature') post v3_api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user2), branch: protected_branch.name diff --git a/spec/requests/api/v3/deployments_spec.rb b/spec/requests/api/v3/deployments_spec.rb index 90eabda4dac..ac86fbea498 100644 --- a/spec/requests/api/v3/deployments_spec.rb +++ b/spec/requests/api/v3/deployments_spec.rb @@ -7,7 +7,7 @@ describe API::V3::Deployments do let!(:deployment) { create(:deployment) } before do - project.team << [user, :master] + project.add_master(user) end shared_examples 'a paginated resources' do diff --git a/spec/requests/api/v3/environments_spec.rb b/spec/requests/api/v3/environments_spec.rb index 937250b5219..68be5256b64 100644 --- a/spec/requests/api/v3/environments_spec.rb +++ b/spec/requests/api/v3/environments_spec.rb @@ -7,7 +7,7 @@ describe API::V3::Environments do let!(:environment) { create(:environment, project: project) } before do - project.team << [user, :master] + project.add_master(user) end shared_examples 'a paginated resources' do diff --git a/spec/requests/api/v3/files_spec.rb b/spec/requests/api/v3/files_spec.rb index 5500c1cf770..26a3d8870a0 100644 --- a/spec/requests/api/v3/files_spec.rb +++ b/spec/requests/api/v3/files_spec.rb @@ -27,7 +27,7 @@ describe API::V3::Files do let(:author_email) { 'user@example.org' } let(:author_name) { 'John Doe' } - before { project.team << [user, :developer] } + before { project.add_developer(user) } describe "GET /projects/:id/repository/files" do let(:route) { "/projects/#{project.id}/repository/files" } diff --git a/spec/requests/api/v3/groups_spec.rb b/spec/requests/api/v3/groups_spec.rb index 498cb42fad1..a1cdf583de3 100644 --- a/spec/requests/api/v3/groups_spec.rb +++ b/spec/requests/api/v3/groups_spec.rb @@ -330,7 +330,7 @@ describe API::V3::Groups do end it "only returns projects to which user has access" do - project3.team << [user3, :developer] + project3.add_developer(user3) get v3_api("/groups/#{group1.id}/projects", user3) diff --git a/spec/requests/api/v3/issues_spec.rb b/spec/requests/api/v3/issues_spec.rb index 39a47a62f16..0dd6d673625 100644 --- a/spec/requests/api/v3/issues_spec.rb +++ b/spec/requests/api/v3/issues_spec.rb @@ -50,8 +50,8 @@ describe API::V3::Issues, :mailer do let(:no_milestone_title) { URI.escape(Milestone::None.title) } before do - project.team << [user, :reporter] - project.team << [guest, :guest] + project.add_reporter(user) + project.add_guest(guest) end describe "GET /issues" do @@ -278,7 +278,7 @@ describe API::V3::Issues, :mailer do let!(:group_note) { create(:note_on_issue, author: user, project: group_project, noteable: group_issue) } before do - group_project.team << [user, :reporter] + group_project.add_reporter(user) end let(:base_url) { "/groups/#{group.id}/issues" } @@ -827,7 +827,7 @@ describe API::V3::Issues, :mailer do let(:merge_request) { discussion.noteable } let(:project) { merge_request.source_project } before do - project.team << [user, :master] + project.add_master(user) post v3_api("/projects/#{project.id}/issues", user), title: 'New Issue', merge_request_for_resolving_discussions: merge_request.iid diff --git a/spec/requests/api/v3/labels_spec.rb b/spec/requests/api/v3/labels_spec.rb index 1d31213d5ca..cdab4d2bd73 100644 --- a/spec/requests/api/v3/labels_spec.rb +++ b/spec/requests/api/v3/labels_spec.rb @@ -7,7 +7,7 @@ describe API::V3::Labels do let!(:priority_label) { create(:label, title: 'bug', project: project, priority: 3) } before do - project.team << [user, :master] + project.add_master(user) end describe 'GET /projects/:id/labels' do diff --git a/spec/requests/api/v3/members_spec.rb b/spec/requests/api/v3/members_spec.rb index 68be3d24c26..b91782ae511 100644 --- a/spec/requests/api/v3/members_spec.rb +++ b/spec/requests/api/v3/members_spec.rb @@ -8,8 +8,8 @@ describe API::V3::Members do let(:project) do create(:project, :public, :access_requestable, creator_id: master.id, namespace: master.namespace) do |project| - project.team << [developer, :developer] - project.team << [master, :master] + project.add_developer(developer) + project.add_master(master) project.request_access(access_requester) end end diff --git a/spec/requests/api/v3/merge_request_diffs_spec.rb b/spec/requests/api/v3/merge_request_diffs_spec.rb index e613036a88d..547c066fadc 100644 --- a/spec/requests/api/v3/merge_request_diffs_spec.rb +++ b/spec/requests/api/v3/merge_request_diffs_spec.rb @@ -8,7 +8,7 @@ describe API::V3::MergeRequestDiffs, 'MergeRequestDiffs' do before do merge_request.merge_request_diffs.create(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') merge_request.merge_request_diffs.create(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e') - project.team << [user, :master] + project.add_master(user) end describe 'GET /projects/:id/merge_requests/:merge_request_id/versions' do diff --git a/spec/requests/api/v3/merge_requests_spec.rb b/spec/requests/api/v3/merge_requests_spec.rb index 2e2b9449429..b8b7d9d1c40 100644 --- a/spec/requests/api/v3/merge_requests_spec.rb +++ b/spec/requests/api/v3/merge_requests_spec.rb @@ -14,7 +14,7 @@ describe API::MergeRequests do let(:milestone) { create(:milestone, title: '1.0.0', project: project) } before do - project.team << [user, :reporter] + project.add_reporter(user) end describe "GET /projects/:id/merge_requests" do @@ -396,7 +396,7 @@ describe API::MergeRequests do let(:developer) { create(:user) } before do - project.team << [developer, :developer] + project.add_developer(developer) end it "denies the deletion of the merge request" do @@ -458,7 +458,7 @@ describe API::MergeRequests do it "returns 401 if user has no permissions to merge" do user2 = create(:user) - project.team << [user2, :reporter] + project.add_reporter(user2) put v3_api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user2) expect(response).to have_gitlab_http_status(401) expect(json_response['message']).to eq('401 Unauthorized') @@ -645,7 +645,7 @@ describe API::MergeRequests do project = create(:project, :private, :repository) merge_request = create(:merge_request, :simple, source_project: project) guest = create(:user) - project.team << [guest, :guest] + project.add_guest(guest) get v3_api("/projects/#{project.id}/merge_requests/#{merge_request.id}/closes_issues", guest) @@ -675,7 +675,7 @@ describe API::MergeRequests do it 'returns 403 if user has no access to read code' do guest = create(:user) - project.team << [guest, :guest] + project.add_guest(guest) post v3_api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", guest) @@ -705,7 +705,7 @@ describe API::MergeRequests do it 'returns 403 if user has no access to read code' do guest = create(:user) - project.team << [guest, :guest] + project.add_guest(guest) delete v3_api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscription", guest) diff --git a/spec/requests/api/v3/milestones_spec.rb b/spec/requests/api/v3/milestones_spec.rb index e82f35598a6..9ee71ea9c5d 100644 --- a/spec/requests/api/v3/milestones_spec.rb +++ b/spec/requests/api/v3/milestones_spec.rb @@ -6,7 +6,7 @@ describe API::V3::Milestones do let!(:closed_milestone) { create(:closed_milestone, project: project) } let!(:milestone) { create(:milestone, project: project) } - before { project.team << [user, :developer] } + before { project.add_developer(user) } describe 'GET /projects/:id/milestones' do it 'returns project milestones' do @@ -200,7 +200,7 @@ describe API::V3::Milestones do let(:confidential_issue) { create(:issue, confidential: true, project: public_project) } before do - public_project.team << [user, :developer] + public_project.add_developer(user) milestone.issues << issue << confidential_issue end @@ -215,7 +215,7 @@ describe API::V3::Milestones do it 'does not return confidential issues to team members with guest role' do member = create(:user) - project.team << [member, :guest] + project.add_guest(member) get v3_api("/projects/#{public_project.id}/milestones/#{milestone.id}/issues", member) diff --git a/spec/requests/api/v3/notes_spec.rb b/spec/requests/api/v3/notes_spec.rb index d3455a4bba4..6428d9daaba 100644 --- a/spec/requests/api/v3/notes_spec.rb +++ b/spec/requests/api/v3/notes_spec.rb @@ -14,7 +14,7 @@ describe API::V3::Notes do let(:private_user) { create(:user) } let(:private_project) do create(:project, namespace: private_user.namespace) - .tap { |p| p.team << [private_user, :master] } + .tap { |p| p.add_master(private_user) } end let(:private_issue) { create(:issue, project: private_project) } @@ -28,7 +28,7 @@ describe API::V3::Notes do system: true end - before { project.team << [user, :reporter] } + before { project.add_reporter(user) } describe "GET /projects/:id/noteable/:noteable_id/notes" do context "when noteable is an Issue" do diff --git a/spec/requests/api/v3/pipelines_spec.rb b/spec/requests/api/v3/pipelines_spec.rb index 1c7d9fe32bb..ea943f22c41 100644 --- a/spec/requests/api/v3/pipelines_spec.rb +++ b/spec/requests/api/v3/pipelines_spec.rb @@ -10,7 +10,7 @@ describe API::V3::Pipelines do ref: project.default_branch) end - before { project.team << [user, :master] } + before { project.add_master(user) } shared_examples 'a paginated resources' do before do @@ -188,7 +188,7 @@ describe API::V3::Pipelines do context 'user without proper access rights' do let!(:reporter) { create(:user) } - before { project.team << [reporter, :reporter] } + before { project.add_reporter(reporter) } it 'rejects the action' do post v3_api("/projects/#{project.id}/pipelines/#{pipeline.id}/cancel", reporter) diff --git a/spec/requests/api/v3/project_hooks_spec.rb b/spec/requests/api/v3/project_hooks_spec.rb index 00f59744a31..248ae97f875 100644 --- a/spec/requests/api/v3/project_hooks_spec.rb +++ b/spec/requests/api/v3/project_hooks_spec.rb @@ -13,8 +13,8 @@ describe API::ProjectHooks, 'ProjectHooks' do end before do - project.team << [user, :master] - project.team << [user3, :developer] + project.add_master(user) + project.add_developer(user3) end describe "GET /projects/:id/hooks" do @@ -205,7 +205,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.team << [test_user, :master] + other_project.add_master(test_user) delete v3_api("/projects/#{other_project.id}/hooks/#{hook.id}", test_user) expect(response).to have_gitlab_http_status(404) diff --git a/spec/requests/api/v3/projects_spec.rb b/spec/requests/api/v3/projects_spec.rb index 27288b98d1c..13e465e0b2d 100644 --- a/spec/requests/api/v3/projects_spec.rb +++ b/spec/requests/api/v3/projects_spec.rb @@ -753,7 +753,7 @@ describe API::V3::Projects do describe 'permissions' do context 'all projects' do - before { project.team << [user, :master] } + before { project.add_master(user) } it 'contains permission information' do get v3_api("/projects", user) @@ -767,7 +767,7 @@ describe API::V3::Projects do context 'personal project' do it 'sets project access and returns 200' do - project.team << [user, :master] + project.add_master(user) get v3_api("/projects/#{project.id}", user) expect(response).to have_gitlab_http_status(200) @@ -1362,7 +1362,7 @@ describe API::V3::Projects do context 'user without archiving rights to the project' do before do - project.team << [user3, :developer] + project.add_developer(user3) end it 'rejects the action' do @@ -1398,7 +1398,7 @@ describe API::V3::Projects do context 'user without archiving rights to the project' do before do - project.team << [user3, :developer] + project.add_developer(user3) end it 'rejects the action' do @@ -1466,7 +1466,7 @@ describe API::V3::Projects do it 'does not remove a project if not an owner' do user3 = create(:user) - project.team << [user3, :developer] + project.add_developer(user3) delete v3_api("/projects/#{project.id}", user3) expect(response).to have_gitlab_http_status(403) end diff --git a/spec/requests/api/v3/todos_spec.rb b/spec/requests/api/v3/todos_spec.rb index 8f5c3fbf8dd..53fd962272a 100644 --- a/spec/requests/api/v3/todos_spec.rb +++ b/spec/requests/api/v3/todos_spec.rb @@ -12,8 +12,8 @@ describe API::V3::Todos do let!(:done) { create(:todo, :done, project: project_1, author: author_1, user: john_doe) } before do - project_1.team << [john_doe, :developer] - project_2.team << [john_doe, :developer] + project_1.add_developer(john_doe) + project_2.add_developer(john_doe) end describe 'DELETE /todos/:id' do diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index fa02fffc82a..27bd22d6bca 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -149,7 +149,7 @@ describe 'Git HTTP requests' do context 'and as a developer on the team' do before do - project.team << [user, :developer] + project.add_developer(user) end context 'but the repo is disabled' do @@ -182,7 +182,7 @@ describe 'Git HTTP requests' do context 'when authenticated' do context 'and as a developer on the team' do before do - project.team << [user, :developer] + project.add_developer(user) end context 'but the repo is disabled' do @@ -240,7 +240,7 @@ describe 'Git HTTP requests' do context 'as a developer on the team' do before do - project.team << [user, :developer] + project.add_developer(user) end it_behaves_like 'pulls are allowed' @@ -365,13 +365,13 @@ describe 'Git HTTP requests' do context "when the user has access to the project" do before do - project.team << [user, :master] + project.add_master(user) end context "when the user is blocked" do it "rejects pulls with 401 Unauthorized" do user.block - project.team << [user, :master] + project.add_master(user) download(path, env) do |response| expect(response).to have_gitlab_http_status(:unauthorized) @@ -434,7 +434,7 @@ describe 'Git HTTP requests' do let(:path) { "#{project.full_path}.git" } before do - project.team << [user, :master] + project.add_master(user) end context 'when username and password are provided' do @@ -612,7 +612,7 @@ describe 'Git HTTP requests' do context 'and build created by' do before do build.update(user: user) - project.team << [user, :reporter] + project.add_reporter(user) end shared_examples 'can download code only' do @@ -795,7 +795,7 @@ describe 'Git HTTP requests' do context 'and the user is on the team' do before do - project.team << [user, :master] + project.add_master(user) end it "responds with status 200" do diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb index c597623bc4d..5e59bb0d585 100644 --- a/spec/requests/lfs_http_spec.rb +++ b/spec/requests/lfs_http_spec.rb @@ -63,7 +63,7 @@ describe 'Git LFS API and storage' do context 'with LFS disabled globally' do before do - project.team << [user, :master] + project.add_master(user) allow(Gitlab.config.lfs).to receive(:enabled).and_return(false) end @@ -106,7 +106,7 @@ describe 'Git LFS API and storage' do context 'with LFS enabled globally' do before do - project.team << [user, :master] + project.add_master(user) enable_lfs end @@ -234,7 +234,7 @@ describe 'Git LFS API and storage' do context 'and does have project access' do let(:update_permissions) do - project.team << [user, :master] + project.add_master(user) project.lfs_objects << lfs_object end @@ -259,7 +259,7 @@ describe 'Git LFS API and storage' do context 'when user allowed' do let(:update_permissions) do - project.team << [user, :master] + project.add_master(user) project.lfs_objects << lfs_object end @@ -295,7 +295,7 @@ describe 'Git LFS API and storage' do let(:pipeline) { create(:ci_empty_pipeline, project: project) } let(:update_permissions) do - project.team << [user, :reporter] + project.add_reporter(user) project.lfs_objects << lfs_object end @@ -517,7 +517,7 @@ describe 'Git LFS API and storage' do let(:authorization) { authorize_user } let(:update_user_permissions) do - project.team << [user, role] + project.add_role(user, role) end it_behaves_like 'an authorized requests' do @@ -553,7 +553,7 @@ describe 'Git LFS API and storage' do let(:pipeline) { create(:ci_empty_pipeline, project: project) } let(:update_user_permissions) do - project.team << [user, :reporter] + project.add_reporter(user) end it_behaves_like 'an authorized requests' @@ -673,7 +673,7 @@ describe 'Git LFS API and storage' do let(:authorization) { authorize_user } let(:update_user_permissions) do - project.team << [user, :developer] + project.add_developer(user) end context 'when pushing an lfs object that already exists' do @@ -795,7 +795,7 @@ describe 'Git LFS API and storage' do context 'when user is not authenticated' do context 'when user has push access' do let(:update_user_permissions) do - project.team << [user, :master] + project.add_master(user) end it 'responds with status 401' do @@ -840,7 +840,7 @@ describe 'Git LFS API and storage' do before do allow(Gitlab::Database).to receive(:read_only?) { true } - project.team << [user, :master] + project.add_master(user) enable_lfs end @@ -935,7 +935,7 @@ describe 'Git LFS API and storage' do describe 'when user has push access to the project' do before do - project.team << [user, :developer] + project.add_developer(user) end context 'and the request bypassed workhorse' do @@ -993,7 +993,7 @@ describe 'Git LFS API and storage' do describe 'and user does not have push access' do before do - project.team << [user, :reporter] + project.add_reporter(user) end it_behaves_like 'forbidden' @@ -1010,7 +1010,7 @@ describe 'Git LFS API and storage' do let(:build) { create(:ci_build, :running, pipeline: pipeline, user: user) } before do - project.team << [user, :developer] + project.add_developer(user) put_authorize end @@ -1062,7 +1062,7 @@ describe 'Git LFS API and storage' do describe 'when user has push access to the project' do before do - project.team << [user, :developer] + project.add_developer(user) end context 'and request is sent by gitlab-workhorse to authorize the request' do @@ -1149,7 +1149,7 @@ describe 'Git LFS API and storage' do let(:authorization) { authorize_user } before do - second_project.team << [user, :master] + second_project.add_master(user) upstream_project.lfs_objects << lfs_object end diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb index 286d8a884a4..98f70e2101b 100644 --- a/spec/requests/projects/cycle_analytics_events_spec.rb +++ b/spec/requests/projects/cycle_analytics_events_spec.rb @@ -7,7 +7,7 @@ describe 'cycle analytics events' do describe 'GET /:namespace/:project/cycle_analytics/events/issues' do before do - project.team << [user, :developer] + project.add_developer(user) 3.times do |count| Timecop.freeze(Time.now + count.days) do diff --git a/spec/services/boards/issues/create_service_spec.rb b/spec/services/boards/issues/create_service_spec.rb index 1a56164dba4..f0179e35652 100644 --- a/spec/services/boards/issues/create_service_spec.rb +++ b/spec/services/boards/issues/create_service_spec.rb @@ -11,7 +11,7 @@ describe Boards::Issues::CreateService do subject(:service) { described_class.new(board.parent, project, user, board_id: board.id, list_id: list.id, title: 'New issue') } before do - project.team << [user, :developer] + project.add_developer(user) end it 'delegates the create proceedings to Issues::CreateService' do diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb index 01ee3856c99..ff5733b7064 100644 --- a/spec/services/boards/issues/list_service_spec.rb +++ b/spec/services/boards/issues/list_service_spec.rb @@ -34,7 +34,7 @@ describe Boards::Issues::ListService do let!(:closed_issue5) { create(:labeled_issue, :closed, project: project, labels: [development]) } before do - project.team << [user, :developer] + project.add_developer(user) end it 'delegates search to IssuesFinder' do diff --git a/spec/services/boards/issues/move_service_spec.rb b/spec/services/boards/issues/move_service_spec.rb index 464ff9f94b3..280e411683e 100644 --- a/spec/services/boards/issues/move_service_spec.rb +++ b/spec/services/boards/issues/move_service_spec.rb @@ -15,7 +15,7 @@ describe Boards::Issues::MoveService do let!(:closed) { create(:closed_list, board: board1) } before do - project.team << [user, :developer] + project.add_developer(user) end context 'when moving an issue between lists' do diff --git a/spec/services/boards/lists/create_service_spec.rb b/spec/services/boards/lists/create_service_spec.rb index 7d0b396cd06..d5322e1bb21 100644 --- a/spec/services/boards/lists/create_service_spec.rb +++ b/spec/services/boards/lists/create_service_spec.rb @@ -10,7 +10,7 @@ describe Boards::Lists::CreateService do subject(:service) { described_class.new(project, user, label_id: label.id) } before do - project.team << [user, :developer] + project.add_developer(user) end context 'when board lists is empty' do diff --git a/spec/services/boards/lists/generate_service_spec.rb b/spec/services/boards/lists/generate_service_spec.rb index 592f25059ac..82dbd1ee744 100644 --- a/spec/services/boards/lists/generate_service_spec.rb +++ b/spec/services/boards/lists/generate_service_spec.rb @@ -9,7 +9,7 @@ describe Boards::Lists::GenerateService do subject(:service) { described_class.new(project, user) } before do - project.team << [user, :developer] + project.add_developer(user) end context 'when board lists is empty' do diff --git a/spec/services/ci/stop_environments_service_spec.rb b/spec/services/ci/stop_environments_service_spec.rb index e2a9ed27e87..3fc4e499b0c 100644 --- a/spec/services/ci/stop_environments_service_spec.rb +++ b/spec/services/ci/stop_environments_service_spec.rb @@ -15,7 +15,7 @@ describe Ci::StopEnvironmentsService do context 'when user has permission to stop environment' do before do - project.team << [user, :developer] + project.add_developer(user) end context 'when environment is associated with removed branch' do @@ -57,7 +57,7 @@ describe Ci::StopEnvironmentsService do context 'when user does not have permission to stop environment' do context 'when user has no access to manage deployments' do before do - project.team << [user, :guest] + project.add_guest(user) end it 'does not stop environment' do @@ -86,7 +86,7 @@ describe Ci::StopEnvironmentsService do context 'when user has permission to stop environments' do before do - project.team << [user, :master] + project.add_master(user) end it 'does not stop environment' do diff --git a/spec/services/delete_branch_service_spec.rb b/spec/services/delete_branch_service_spec.rb index 19855c9bee2..9c9fba030e7 100644 --- a/spec/services/delete_branch_service_spec.rb +++ b/spec/services/delete_branch_service_spec.rb @@ -9,7 +9,7 @@ describe DeleteBranchService do describe '#execute' do context 'when user has access to push to repository' do before do - project.team << [user, :developer] + project.add_developer(user) end it 'removes the branch' do diff --git a/spec/services/discussions/resolve_service_spec.rb b/spec/services/discussions/resolve_service_spec.rb index ab8df7b74cd..3895a0b3aea 100644 --- a/spec/services/discussions/resolve_service_spec.rb +++ b/spec/services/discussions/resolve_service_spec.rb @@ -9,7 +9,7 @@ describe Discussions::ResolveService do let(:service) { described_class.new(discussion.noteable.project, user, merge_request: merge_request) } before do - project.team << [user, :master] + project.add_master(user) end it "doesn't resolve discussions the user can't resolve" do diff --git a/spec/services/files/delete_service_spec.rb b/spec/services/files/delete_service_spec.rb index e9f8f0efe6b..ace5f293097 100644 --- a/spec/services/files/delete_service_spec.rb +++ b/spec/services/files/delete_service_spec.rb @@ -37,7 +37,7 @@ describe Files::DeleteService do end before do - project.team << [user, :master] + project.add_master(user) end describe "#execute" do diff --git a/spec/services/files/multi_service_spec.rb b/spec/services/files/multi_service_spec.rb index 085a28d267f..2b79609930c 100644 --- a/spec/services/files/multi_service_spec.rb +++ b/spec/services/files/multi_service_spec.rb @@ -36,7 +36,7 @@ describe Files::MultiService do end before do - project.team << [user, :master] + project.add_master(user) end describe '#execute' do diff --git a/spec/services/files/update_service_spec.rb b/spec/services/files/update_service_spec.rb index 2b4f8cd42ee..43b0c9a63a9 100644 --- a/spec/services/files/update_service_spec.rb +++ b/spec/services/files/update_service_spec.rb @@ -24,7 +24,7 @@ describe Files::UpdateService do end before do - project.team << [user, :master] + project.add_master(user) end describe "#execute" do diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index cc3d4e7da49..26fdf8d4b24 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -11,7 +11,7 @@ describe GitPushService, services: true do let(:ref) { 'refs/heads/master' } before do - project.team << [user, :master] + project.add_master(user) end describe 'Push branches' do @@ -266,8 +266,8 @@ describe GitPushService, services: true do let(:commit) { project.commit } before do - project.team << [commit_author, :developer] - project.team << [user, :developer] + project.add_developer(commit_author) + project.add_developer(user) allow(commit).to receive_messages( safe_message: "this commit \n mentions #{issue.to_reference}", @@ -323,8 +323,8 @@ describe GitPushService, services: true do let(:commit_time) { Time.now } before do - project.team << [commit_author, :developer] - project.team << [user, :developer] + project.add_developer(commit_author) + project.add_developer(user) allow(commit).to receive_messages( safe_message: "this commit \n mentions #{issue.to_reference}", @@ -376,7 +376,7 @@ describe GitPushService, services: true do allow_any_instance_of(ProcessCommitWorker).to receive(:build_commit) .and_return(closing_commit) - project.team << [commit_author, :master] + project.add_master(commit_author) end context "to default branches" do diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb index 05695aa8188..33405d7a7ec 100644 --- a/spec/services/git_tag_push_service_spec.rb +++ b/spec/services/git_tag_push_service_spec.rb @@ -35,7 +35,7 @@ describe GitTagPushService do before do stub_ci_pipeline_to_return_yaml_file - project.team << [user, :developer] + project.add_developer(user) end it "creates a new pipeline" do diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb index bdaab88d673..53c85f73cde 100644 --- a/spec/services/issuable/bulk_update_service_spec.rb +++ b/spec/services/issuable/bulk_update_service_spec.rb @@ -54,7 +54,7 @@ describe Issuable::BulkUpdateService do context 'when the new assignee ID is a valid user' do it 'succeeds' do new_assignee = create(:user) - project.team << [new_assignee, :developer] + project.add_developer(new_assignee) result = bulk_update(merge_request, assignee_id: new_assignee.id) @@ -64,7 +64,7 @@ describe Issuable::BulkUpdateService do it 'updates the assignee to the user ID passed' do assignee = create(:user) - project.team << [assignee, :developer] + project.add_developer(assignee) expect { bulk_update(merge_request, assignee_id: assignee.id) } .to change { merge_request.reload.assignee }.from(user).to(assignee) @@ -92,7 +92,7 @@ describe Issuable::BulkUpdateService do context 'when the new assignee ID is a valid user' do it 'succeeds' do new_assignee = create(:user) - project.team << [new_assignee, :developer] + project.add_developer(new_assignee) result = bulk_update(issue, assignee_ids: [new_assignee.id]) @@ -102,7 +102,7 @@ describe Issuable::BulkUpdateService do it 'updates the assignee to the user ID passed' do assignee = create(:user) - project.team << [assignee, :developer] + project.add_developer(assignee) expect { bulk_update(issue, assignee_ids: [assignee.id]) } .to change { issue.reload.assignees.first }.from(user).to(assignee) end diff --git a/spec/services/issues/build_service_spec.rb b/spec/services/issues/build_service_spec.rb index 03f76bd428d..248e7d5a389 100644 --- a/spec/services/issues/build_service_spec.rb +++ b/spec/services/issues/build_service_spec.rb @@ -5,7 +5,7 @@ describe Issues::BuildService do let(:user) { create(:user) } before do - project.team << [user, :developer] + project.add_developer(user) end context 'for a single discussion' do diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb index 5c27e8fd561..8897a64a138 100644 --- a/spec/services/issues/close_service_spec.rb +++ b/spec/services/issues/close_service_spec.rb @@ -9,9 +9,9 @@ describe Issues::CloseService do let!(:todo) { create(:todo, :assigned, user: user, project: project, target: issue, author: user2) } before do - project.team << [user, :master] - project.team << [user2, :developer] - project.team << [guest, :guest] + project.add_master(user) + project.add_developer(user2) + project.add_guest(guest) end describe '#execute' do diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb index d86da244520..79bcdc41fb0 100644 --- a/spec/services/issues/create_service_spec.rb +++ b/spec/services/issues/create_service_spec.rb @@ -13,8 +13,8 @@ describe Issues::CreateService do let(:labels) { create_pair(:label, project: project) } before do - project.team << [user, :master] - project.team << [assignee, :master] + project.add_master(user) + project.add_master(assignee) end let(:opts) do @@ -43,7 +43,7 @@ describe Issues::CreateService do let(:guest) { create(:user) } before do - project.team << [guest, :guest] + project.add_guest(guest) end it 'filters out params that cannot be set without the :admin_issue permission' do @@ -130,7 +130,7 @@ describe Issues::CreateService do end it 'invalidates open issues counter for assignees when issue is assigned' do - project.team << [assignee, :master] + project.add_master(assignee) described_class.new(project, user, opts).execute @@ -160,7 +160,7 @@ describe Issues::CreateService do context 'issue create service' do context 'assignees' do before do - project.team << [user, :master] + project.add_master(user) end it 'removes assignee when user id is invalid' do @@ -180,7 +180,7 @@ describe Issues::CreateService do end it 'saves assignee when user id is valid' do - project.team << [assignee, :master] + project.add_master(assignee) opts = { title: 'Title', description: 'Description', assignee_ids: [assignee.id] } issue = described_class.new(project, user, opts).execute @@ -224,8 +224,8 @@ describe Issues::CreateService do end before do - project.team << [user, :master] - project.team << [assignee, :master] + project.add_master(user) + project.add_master(assignee) end it 'assigns and sets milestone to issuable from command' do @@ -242,7 +242,7 @@ describe Issues::CreateService do let(:project) { merge_request.source_project } before do - project.team << [user, :master] + project.add_master(user) end describe 'for a single discussion' do diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb index f2b35a8fadf..40f15f9f096 100644 --- a/spec/services/issues/move_service_spec.rb +++ b/spec/services/issues/move_service_spec.rb @@ -20,8 +20,8 @@ describe Issues::MoveService do shared_context 'user can move issue' do before do - old_project.team << [user, :reporter] - new_project.team << [user, :reporter] + old_project.add_reporter(user) + new_project.add_reporter(user) labels = Array.new(2) { |x| "label%d" % (x + 1) } @@ -301,7 +301,7 @@ describe Issues::MoveService do context 'user is reporter only in new project' do before do - new_project.team << [user, :reporter] + new_project.add_reporter(user) end it { expect { move }.to raise_error(StandardError, /permissions/) } @@ -309,7 +309,7 @@ describe Issues::MoveService do context 'user is reporter only in old project' do before do - old_project.team << [user, :reporter] + old_project.add_reporter(user) end it { expect { move }.to raise_error(StandardError, /permissions/) } @@ -317,8 +317,8 @@ describe Issues::MoveService do context 'user is reporter in one project and guest in another' do before do - new_project.team << [user, :guest] - old_project.team << [user, :reporter] + new_project.add_guest(user) + old_project.add_reporter(user) end it { expect { move }.to raise_error(StandardError, /permissions/) } @@ -346,8 +346,8 @@ describe Issues::MoveService do context 'movable issue with no assigned labels' do before do - old_project.team << [user, :reporter] - new_project.team << [user, :reporter] + old_project.add_reporter(user) + new_project.add_reporter(user) labels = Array.new(2) { |x| "label%d" % (x + 1) } diff --git a/spec/services/issues/reopen_service_spec.rb b/spec/services/issues/reopen_service_spec.rb index 48fc98b3b2f..42e5d544f4c 100644 --- a/spec/services/issues/reopen_service_spec.rb +++ b/spec/services/issues/reopen_service_spec.rb @@ -8,7 +8,7 @@ describe Issues::ReopenService do context 'when user is not authorized to reopen issue' do before do guest = create(:user) - project.team << [guest, :guest] + project.add_guest(guest) perform_enqueued_jobs do described_class.new(project, guest).execute(issue) @@ -24,7 +24,7 @@ describe Issues::ReopenService do let(:user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) end it 'invalidates counter cache for assignees' do diff --git a/spec/services/issues/resolve_discussions_spec.rb b/spec/services/issues/resolve_discussions_spec.rb index 67a86c50fc1..13accc6ae1b 100644 --- a/spec/services/issues/resolve_discussions_spec.rb +++ b/spec/services/issues/resolve_discussions_spec.rb @@ -14,7 +14,7 @@ describe Issues::ResolveDiscussions do let(:user) { create(:user) } before do - project.team << [user, :developer] + project.add_developer(user) end describe "for resolving discussions" do diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index f07b81e842a..1cb6f2e097f 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -17,9 +17,9 @@ describe Issues::UpdateService, :mailer do end before do - project.team << [user, :master] - project.team << [user2, :developer] - project.team << [user3, :developer] + project.add_master(user) + project.add_developer(user2) + project.add_developer(user3) end describe 'execute' do @@ -99,7 +99,7 @@ describe Issues::UpdateService, :mailer do context 'when current user cannot admin issues in the project' do let(:guest) { create(:user) } before do - project.team << [guest, :guest] + project.add_guest(guest) end it 'filters out params that cannot be set without the :admin_issue permission' do @@ -318,7 +318,7 @@ describe Issues::UpdateService, :mailer do let!(:subscriber) do create(:user).tap do |u| label.toggle_subscription(u, project) - project.team << [u, :developer] + project.add_developer(u) end end @@ -556,7 +556,7 @@ describe Issues::UpdateService, :mailer do context 'valid project' do before do - target_project.team << [user, :master] + target_project.add_master(user) end it 'calls the move service with the proper issue and project' do diff --git a/spec/services/labels/find_or_create_service_spec.rb b/spec/services/labels/find_or_create_service_spec.rb index a781fbc7f7d..78aa5d442e7 100644 --- a/spec/services/labels/find_or_create_service_spec.rb +++ b/spec/services/labels/find_or_create_service_spec.rb @@ -17,7 +17,7 @@ describe Labels::FindOrCreateService do let(:user) { create(:user) } subject(:service) { described_class.new(user, project, params) } before do - project.team << [user, :developer] + project.add_developer(user) end context 'when label does not exist at group level' do diff --git a/spec/services/members/approve_access_request_service_spec.rb b/spec/services/members/approve_access_request_service_spec.rb index 302c488d6c6..b3018169a1c 100644 --- a/spec/services/members/approve_access_request_service_spec.rb +++ b/spec/services/members/approve_access_request_service_spec.rb @@ -123,7 +123,7 @@ describe Members::ApproveAccessRequestService do context 'when current user can approve access request to the project' do before do - project.team << [user, :master] + project.add_master(user) group.add_owner(user) end diff --git a/spec/services/members/authorized_destroy_service_spec.rb b/spec/services/members/authorized_destroy_service_spec.rb index d4ef31c0c74..757c45708b9 100644 --- a/spec/services/members/authorized_destroy_service_spec.rb +++ b/spec/services/members/authorized_destroy_service_spec.rb @@ -13,7 +13,7 @@ describe Members::AuthorizedDestroyService do context 'Invited users' do # Regression spec for issue: https://gitlab.com/gitlab-org/gitlab-ce/issues/32504 it 'destroys invited project member' do - project.team << [member_user, :developer] + project.add_developer(member_user) member = create :project_member, :invited, project: project @@ -52,7 +52,7 @@ describe Members::AuthorizedDestroyService do context 'Project member' do it "unassigns issues and merge requests" do - project.team << [member_user, :developer] + project.add_developer(member_user) create :issue, project: project, assignees: [member_user] create :merge_request, target_project: project, source_project: project, assignee: member_user diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb index 2a793e0eb4d..6bd4718e780 100644 --- a/spec/services/members/create_service_spec.rb +++ b/spec/services/members/create_service_spec.rb @@ -6,7 +6,7 @@ describe Members::CreateService do let(:project_user) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) end it 'adds user to members' do diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb index 72f5e27180d..91152df3ad9 100644 --- a/spec/services/members/destroy_service_spec.rb +++ b/spec/services/members/destroy_service_spec.rb @@ -71,7 +71,7 @@ describe Members::DestroyService do context 'when a member is found' do before do - project.team << [member_user, :developer] + project.add_developer(member_user) group.add_developer(member_user) end let(:params) { { user_id: member_user.id } } @@ -88,7 +88,7 @@ describe Members::DestroyService do context 'when current user can destroy the given member' do before do - project.team << [user, :master] + project.add_master(user) group.add_owner(user) end diff --git a/spec/services/merge_requests/assign_issues_service_spec.rb b/spec/services/merge_requests/assign_issues_service_spec.rb index fcbe0e5985f..bda6383a346 100644 --- a/spec/services/merge_requests/assign_issues_service_spec.rb +++ b/spec/services/merge_requests/assign_issues_service_spec.rb @@ -8,7 +8,7 @@ describe MergeRequests::AssignIssuesService do let(:service) { described_class.new(project, user, merge_request: merge_request) } before do - project.team << [user, :developer] + project.add_developer(user) end it 'finds unassigned issues fixed in merge request' do diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb index b5c92e681fb..a9605c6e4c6 100644 --- a/spec/services/merge_requests/build_service_spec.rb +++ b/spec/services/merge_requests/build_service_spec.rb @@ -28,7 +28,7 @@ describe MergeRequests::BuildService do end before do - project.team << [user, :guest] + project.add_guest(user) end def stub_compare diff --git a/spec/services/merge_requests/close_service_spec.rb b/spec/services/merge_requests/close_service_spec.rb index b3886987316..2a59bc4594a 100644 --- a/spec/services/merge_requests/close_service_spec.rb +++ b/spec/services/merge_requests/close_service_spec.rb @@ -9,9 +9,9 @@ describe MergeRequests::CloseService do let!(:todo) { create(:todo, :assigned, user: user, project: project, target: merge_request, author: user2) } before do - project.team << [user, :master] - project.team << [user2, :developer] - project.team << [guest, :guest] + project.add_master(user) + project.add_developer(user2) + project.add_guest(guest) end describe '#execute' do diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb index a047f891ab2..dd8c803a2f7 100644 --- a/spec/services/merge_requests/create_service_spec.rb +++ b/spec/services/merge_requests/create_service_spec.rb @@ -21,8 +21,8 @@ describe MergeRequests::CreateService do let(:merge_request) { service.execute } before do - project.team << [user, :master] - project.team << [assignee, :developer] + project.add_master(user) + project.add_developer(assignee) allow(service).to receive(:execute_hooks) end @@ -148,8 +148,8 @@ describe MergeRequests::CreateService do end before do - project.team << [user, :master] - project.team << [assignee, :master] + project.add_master(user) + project.add_master(assignee) end it 'assigns and sets milestone to issuable from command' do @@ -165,7 +165,7 @@ describe MergeRequests::CreateService do let(:assignee) { create(:user) } before do - project.team << [user, :master] + project.add_master(user) end it 'removes assignee_id when user id is invalid' do @@ -185,7 +185,7 @@ describe MergeRequests::CreateService do end it 'saves assignee when user id is valid' do - project.team << [assignee, :master] + project.add_master(assignee) opts = { title: 'Title', description: 'Description', assignee_id: assignee.id } merge_request = described_class.new(project, user, opts).execute @@ -205,7 +205,7 @@ describe MergeRequests::CreateService do end it 'invalidates open merge request counter for assignees when merge request is assigned' do - project.team << [assignee, :master] + project.add_master(assignee) described_class.new(project, user, opts).execute @@ -249,8 +249,8 @@ describe MergeRequests::CreateService do end before do - project.team << [user, :master] - project.team << [assignee, :developer] + project.add_master(user) + project.add_developer(assignee) end it 'creates a `MergeRequestsClosingIssues` record for each issue' do diff --git a/spec/services/merge_requests/ff_merge_service_spec.rb b/spec/services/merge_requests/ff_merge_service_spec.rb index aaabf3ed2b0..aa90feeef89 100644 --- a/spec/services/merge_requests/ff_merge_service_spec.rb +++ b/spec/services/merge_requests/ff_merge_service_spec.rb @@ -12,8 +12,8 @@ describe MergeRequests::FfMergeService do let(:project) { merge_request.project } before do - project.team << [user, :master] - project.team << [user2, :developer] + project.add_master(user) + project.add_developer(user2) end describe '#execute' do diff --git a/spec/services/merge_requests/post_merge_service_spec.rb b/spec/services/merge_requests/post_merge_service_spec.rb index d2bd05d921f..8f2c5df5907 100644 --- a/spec/services/merge_requests/post_merge_service_spec.rb +++ b/spec/services/merge_requests/post_merge_service_spec.rb @@ -6,7 +6,7 @@ describe MergeRequests::PostMergeService do let(:project) { merge_request.project } before do - project.team << [user, :master] + project.add_master(user) end describe '#execute' do diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 61ec4709c59..7a01d3dd698 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -300,8 +300,8 @@ describe MergeRequests::RefreshService do let(:commit) { project.commit } before do - project.team << [commit_author, :developer] - project.team << [user, :developer] + project.add_developer(commit_author) + project.add_developer(user) allow(commit).to receive_messages( safe_message: "Closes #{issue.to_reference}", diff --git a/spec/services/merge_requests/reopen_service_spec.rb b/spec/services/merge_requests/reopen_service_spec.rb index fa652611c6b..94f31ff139c 100644 --- a/spec/services/merge_requests/reopen_service_spec.rb +++ b/spec/services/merge_requests/reopen_service_spec.rb @@ -8,9 +8,9 @@ describe MergeRequests::ReopenService do let(:project) { merge_request.project } before do - project.team << [user, :master] - project.team << [user2, :developer] - project.team << [guest, :guest] + project.add_master(user) + project.add_developer(user2) + project.add_guest(guest) end describe '#execute' do diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index 7a66b809550..2238da2d14d 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -16,9 +16,9 @@ describe MergeRequests::UpdateService, :mailer do end before do - project.team << [user, :master] - project.team << [user2, :developer] - project.team << [user3, :developer] + project.add_master(user) + project.add_developer(user2) + project.add_developer(user3) end describe 'execute' do @@ -356,8 +356,8 @@ describe MergeRequests::UpdateService, :mailer do let!(:subscriber) { create(:user) { |u| label.toggle_subscription(u, project) } } before do - project.team << [non_subscriber, :developer] - project.team << [subscriber, :developer] + project.add_developer(non_subscriber) + project.add_developer(subscriber) end it 'sends notifications for subscribers of newly added labels' do diff --git a/spec/services/milestones/close_service_spec.rb b/spec/services/milestones/close_service_spec.rb index 2bdf224804d..adad73f7e11 100644 --- a/spec/services/milestones/close_service_spec.rb +++ b/spec/services/milestones/close_service_spec.rb @@ -6,7 +6,7 @@ describe Milestones::CloseService do let(:milestone) { create(:milestone, title: "Milestone v1.2", project: project) } before do - project.team << [user, :master] + project.add_master(user) end describe '#execute' do diff --git a/spec/services/milestones/create_service_spec.rb b/spec/services/milestones/create_service_spec.rb index 8837b91051d..f2a18c7295a 100644 --- a/spec/services/milestones/create_service_spec.rb +++ b/spec/services/milestones/create_service_spec.rb @@ -7,7 +7,7 @@ describe Milestones::CreateService do describe '#execute' do context "valid params" do before do - project.team << [user, :master] + project.add_master(user) opts = { title: 'v2.1.9', diff --git a/spec/services/milestones/destroy_service_spec.rb b/spec/services/milestones/destroy_service_spec.rb index af35e17bfa7..9703780b0e9 100644 --- a/spec/services/milestones/destroy_service_spec.rb +++ b/spec/services/milestones/destroy_service_spec.rb @@ -8,7 +8,7 @@ describe Milestones::DestroyService do let!(:merge_request) { create(:merge_request, source_project: project, milestone: milestone) } before do - project.team << [user, :master] + project.add_master(user) end def service diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb index 661d26946e7..0ae26e87154 100644 --- a/spec/services/notes/create_service_spec.rb +++ b/spec/services/notes/create_service_spec.rb @@ -10,7 +10,7 @@ describe Notes::CreateService do describe '#execute' do before do - project.team << [user, :master] + project.add_master(user) end context "valid params" do diff --git a/spec/services/notes/post_process_service_spec.rb b/spec/services/notes/post_process_service_spec.rb index a2b3638059f..6ef5e93cb20 100644 --- a/spec/services/notes/post_process_service_spec.rb +++ b/spec/services/notes/post_process_service_spec.rb @@ -7,7 +7,7 @@ describe Notes::PostProcessService do describe '#execute' do before do - project.team << [user, :master] + project.add_master(user) note_opts = { note: 'Awesome comment', noteable_type: 'Issue', diff --git a/spec/services/notes/quick_actions_service_spec.rb b/spec/services/notes/quick_actions_service_spec.rb index 0280a19098b..5eafe56c99d 100644 --- a/spec/services/notes/quick_actions_service_spec.rb +++ b/spec/services/notes/quick_actions_service_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' describe Notes::QuickActionsService do shared_context 'note on noteable' do let(:project) { create(:project) } - let(:master) { create(:user).tap { |u| project.team << [u, :master] } } + let(:master) { create(:user).tap { |u| project.add_master(u) } } let(:assignee) { create(:user) } before do - project.team << [assignee, :master] + project.add_master(assignee) end end @@ -226,7 +226,7 @@ describe Notes::QuickActionsService do context 'CE restriction for issue assignees' do describe '/assign' do let(:project) { create(:project) } - let(:master) { create(:user).tap { |u| project.team << [u, :master] } } + let(:master) { create(:user).tap { |u| project.add_master(u) } } let(:assignee) { create(:user) } let(:master) { create(:user) } let(:service) { described_class.new(project, master) } @@ -237,8 +237,8 @@ describe Notes::QuickActionsService do end before do - project.team << [master, :master] - project.team << [assignee, :master] + project.add_master(master) + project.add_master(assignee) end it 'adds only one assignee from the list' do diff --git a/spec/services/notes/update_service_spec.rb b/spec/services/notes/update_service_spec.rb index 3210539f3ee..65b1d613998 100644 --- a/spec/services/notes/update_service_spec.rb +++ b/spec/services/notes/update_service_spec.rb @@ -9,9 +9,9 @@ describe Notes::UpdateService do let(:note) { create(:note, project: project, noteable: issue, author: user, note: "Old note #{user2.to_reference}") } before do - project.team << [user, :master] - project.team << [user2, :developer] - project.team << [user3, :developer] + project.add_master(user) + project.add_developer(user2) + project.add_developer(user3) end describe '#execute' do diff --git a/spec/services/projects/autocomplete_service_spec.rb b/spec/services/projects/autocomplete_service_spec.rb index 426593be428..7a8c54673f7 100644 --- a/spec/services/projects/autocomplete_service_spec.rb +++ b/spec/services/projects/autocomplete_service_spec.rb @@ -34,7 +34,7 @@ describe Projects::AutocompleteService do end it 'does not list project confidential issues for project members with guest role' do - project.team << [member, :guest] + project.add_guest(member) autocomplete = described_class.new(project, non_member) issues = autocomplete.issues.map(&:iid) @@ -66,7 +66,7 @@ describe Projects::AutocompleteService do end it 'lists project confidential issues for project members' do - project.team << [member, :developer] + project.add_developer(member) autocomplete = described_class.new(project, member) issues = autocomplete.issues.map(&:iid) diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index eb46480fa54..ae160d104f1 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -12,7 +12,7 @@ describe QuickActions::InterpretService do let(:service) { described_class.new(project, developer) } before do - project.team << [developer, :developer] + project.add_developer(developer) end describe '#execute' do @@ -440,7 +440,7 @@ describe QuickActions::InterpretService do let(:content) { "/assign @#{developer.username} @#{developer2.username}" } before do - project.team << [developer2, :developer] + project.add_developer(developer2) end context 'Issue' do diff --git a/spec/services/search/snippet_service_spec.rb b/spec/services/search/snippet_service_spec.rb index eae9bd4f5cf..bc7885b03d9 100644 --- a/spec/services/search/snippet_service_spec.rb +++ b/spec/services/search/snippet_service_spec.rb @@ -33,7 +33,7 @@ describe Search::SnippetService do it 'returns public, internal snippets and project private snippets for project members' do member = create(:user) - project.team << [member, :developer] + project.add_developer(member) search = described_class.new(member, search: 'password') results = search.execute diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb index 88013acae0a..5e6c24f5730 100644 --- a/spec/services/todo_service_spec.rb +++ b/spec/services/todo_service_spec.rb @@ -17,11 +17,11 @@ describe TodoService do let(:service) { described_class.new } before do - project.team << [guest, :guest] - project.team << [author, :developer] - project.team << [member, :developer] - project.team << [john_doe, :developer] - project.team << [skipped, :developer] + project.add_guest(guest) + project.add_developer(author) + project.add_developer(member) + project.add_developer(john_doe) + project.add_developer(skipped) end describe 'Issues' do diff --git a/spec/support/api/milestones_shared_examples.rb b/spec/support/api/milestones_shared_examples.rb index d9080b02541..0388f110d71 100644 --- a/spec/support/api/milestones_shared_examples.rb +++ b/spec/support/api/milestones_shared_examples.rb @@ -258,7 +258,7 @@ shared_examples_for 'group and project milestones' do |route_definition| # Add public project to the group in context setup_for_group if context_group - public_project.team << [user, :developer] + public_project.add_developer(user) milestone.issues << issue << confidential_issue end @@ -275,7 +275,7 @@ shared_examples_for 'group and project milestones' do |route_definition| it 'does not return confidential issues to team members with guest role' do member = create(:user) - public_project.team << [member, :guest] + public_project.add_guest(member) get api(issues_route, member) diff --git a/spec/support/features/issuable_slash_commands_shared_examples.rb b/spec/support/features/issuable_slash_commands_shared_examples.rb index 08e21ee2537..2c20821ac3f 100644 --- a/spec/support/features/issuable_slash_commands_shared_examples.rb +++ b/spec/support/features/issuable_slash_commands_shared_examples.rb @@ -19,7 +19,7 @@ shared_examples 'issuable record that supports quick actions in its description let(:new_url_opts) { {} } before do - project.team << [master, :master] + project.add_master(master) gitlab_sign_in(master) end diff --git a/spec/support/markdown_feature.rb b/spec/support/markdown_feature.rb index a0d854d3641..39e94ad53de 100644 --- a/spec/support/markdown_feature.rb +++ b/spec/support/markdown_feature.rb @@ -24,7 +24,7 @@ class MarkdownFeature def project @project ||= create(:project, :repository, group: group).tap do |project| - project.team << [user, :master] + project.add_master(user) end end @@ -85,7 +85,7 @@ class MarkdownFeature @xproject ||= begin group = create(:group, :nested) create(:project, :repository, namespace: group) do |project| - project.team << [user, :developer] + project.add_developer(user) end end end diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb index 3ac201f1fb1..1685decbe94 100644 --- a/spec/support/mentionable_shared_examples.rb +++ b/spec/support/mentionable_shared_examples.rb @@ -53,7 +53,7 @@ shared_context 'mentionable context' do set_mentionable_text.call(ref_string) - project.team << [author, :developer] + project.add_developer(author) end end diff --git a/spec/support/reference_parser_shared_examples.rb b/spec/support/reference_parser_shared_examples.rb index bd83cb88058..baf8bcc04b8 100644 --- a/spec/support/reference_parser_shared_examples.rb +++ b/spec/support/reference_parser_shared_examples.rb @@ -26,7 +26,7 @@ RSpec.shared_examples "referenced feature visibility" do |*related_features| end it "creates reference for member" do - project.team << [user, :developer] + project.add_developer(user) expect(subject.nodes_visible_to_user(user, [link])).to eq([link]) end diff --git a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb index 9399745f900..7b064162726 100644 --- a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb +++ b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb @@ -3,7 +3,7 @@ shared_examples 'new issuable record that supports quick actions' do let!(:project) { create(:project, :repository) } - let(:user) { create(:user).tap { |u| project.team << [u, :master] } } + let(:user) { create(:user).tap { |u| project.add_master(u) } } let(:assignee) { create(:user) } let!(:milestone) { create(:milestone, project: project) } let!(:labels) { create_list(:label, 3, project: project) } @@ -12,7 +12,7 @@ shared_examples 'new issuable record that supports quick actions' do let(:issuable) { described_class.new(project, user, params).execute } before do - project.team << [assignee, :master] + project.add_master(assignee) end context 'with labels in command only' do diff --git a/spec/support/updating_mentions_shared_examples.rb b/spec/support/updating_mentions_shared_examples.rb index 565d3203e4f..5e3f19ba19e 100644 --- a/spec/support/updating_mentions_shared_examples.rb +++ b/spec/support/updating_mentions_shared_examples.rb @@ -3,7 +3,7 @@ RSpec.shared_examples 'updating mentions' do |service_class| let(:service_class) { service_class } before do - project.team << [mentioned_user, :developer] + project.add_developer(mentioned_user) end def update_mentionable(opts) diff --git a/spec/views/projects/imports/new.html.haml_spec.rb b/spec/views/projects/imports/new.html.haml_spec.rb index 9b293065797..ec435ec3b32 100644 --- a/spec/views/projects/imports/new.html.haml_spec.rb +++ b/spec/views/projects/imports/new.html.haml_spec.rb @@ -8,7 +8,7 @@ describe "projects/imports/new.html.haml" do before do sign_in(user) - project.team << [user, :master] + project.add_master(user) end it "escapes HTML in import errors" do diff --git a/spec/views/shared/notes/_form.html.haml_spec.rb b/spec/views/shared/notes/_form.html.haml_spec.rb index cae6bee2776..50980718e66 100644 --- a/spec/views/shared/notes/_form.html.haml_spec.rb +++ b/spec/views/shared/notes/_form.html.haml_spec.rb @@ -7,7 +7,7 @@ describe 'shared/notes/_form' do let(:project) { create(:project, :repository) } before do - project.team << [user, :master] + project.add_master(user) assign(:project, project) assign(:note, note) diff --git a/spec/workers/merge_worker_spec.rb b/spec/workers/merge_worker_spec.rb index 303193bab9b..c861a56497e 100644 --- a/spec/workers/merge_worker_spec.rb +++ b/spec/workers/merge_worker_spec.rb @@ -8,7 +8,7 @@ describe MergeWorker do let!(:author) { merge_request.author } before do - source_project.team << [author, :master] + source_project.add_master(author) source_project.repository.expire_branches_cache end -- cgit v1.2.1 From f7ffe27c2e4075789ccd9e798c8a88c9e1d85a4e Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 21 Dec 2017 23:40:56 -0800 Subject: Disable /dev/shm in CI According to the Chrome source code (https://chromium.googlesource.com/chromium/src/base/+/master/base_switches.cc#120): The /dev/shm partition is too small in certain VM environments, causing Chrome to fail or crash (see http://crbug.com/715363). Use this flag to work-around this issue (a temporary directory will always be used to create anonymous shared memory files). Addresses gitlab-org/gitlab-ee#4252 but doesn't appear to cure it completely. --- features/support/capybara.rb | 3 +++ spec/support/capybara.rb | 3 +++ 2 files changed, 6 insertions(+) diff --git a/features/support/capybara.rb b/features/support/capybara.rb index 5a77b859113..4e2b3c67af5 100644 --- a/features/support/capybara.rb +++ b/features/support/capybara.rb @@ -29,6 +29,9 @@ Capybara.register_driver :chrome do |app| options.add_argument("disable-gpu") end + # Disable /dev/shm use in CI. See https://gitlab.com/gitlab-org/gitlab-ee/issues/4252 + options.add_argument("disable-dev-shm-usage") if ENV['CI'] || ENV['CI_SERVER'] + Capybara::Selenium::Driver.new( app, browser: :chrome, diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index 935b170a0f6..5189c57b7db 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -33,6 +33,9 @@ Capybara.register_driver :chrome do |app| options.add_argument("disable-gpu") end + # Disable /dev/shm use in CI. See https://gitlab.com/gitlab-org/gitlab-ee/issues/4252 + options.add_argument("disable-dev-shm-usage") if ENV['CI'] || ENV['CI_SERVER'] + Capybara::Selenium::Driver.new( app, browser: :chrome, -- cgit v1.2.1 From 8c0e571a2b9e0516f7e2f8e267896fdf8f2eb3b7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 22 Dec 2017 11:40:56 +0200 Subject: Explictly require Gitlab::Utils in ProjectFeaturesCompatibility For some reason Rails does not require it automatically when invoked via rake task which cause tasks like seed_fu fail Signed-off-by: Dmitriy Zaporozhets --- app/models/concerns/project_features_compatibility.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/concerns/project_features_compatibility.rb b/app/models/concerns/project_features_compatibility.rb index cb59b4da3d7..b3fec99c816 100644 --- a/app/models/concerns/project_features_compatibility.rb +++ b/app/models/concerns/project_features_compatibility.rb @@ -2,6 +2,7 @@ # # After migrating issues_enabled merge_requests_enabled builds_enabled snippets_enabled and wiki_enabled # fields to a new table "project_features", support for the old fields is still needed in the API. +require 'gitlab/utils' module ProjectFeaturesCompatibility extend ActiveSupport::Concern -- cgit v1.2.1 From 03a9a1857bda37b3c6be3ca3d2702d50c84ad1f7 Mon Sep 17 00:00:00 2001 From: Tiago Botelho Date: Fri, 22 Dec 2017 09:46:47 +0000 Subject: Update CHANGELOG.md for 10.3.0 [ci skip] --- CHANGELOG.md | 149 +++++++++++++++++++++ changelogs/unreleased/13634-broadcast-message.yml | 5 - ...e-new-pipeline-in-case-of-validation-errors.yml | 5 - .../15774-fix-39233-500-in-merge-request.yml | 5 - ...18040-rubocop-line-break-after-guard-clause.yml | 5 - ...h-name-when-using-create-branch-in-an-issue.yml | 5 - ...ommand-limit-autocomplete-to-applied-labels.yml | 5 - .../28377-add-edit-button-to-mobile-file-view.yml | 5 - ...on-checklist-if-potential-spam-was-detected.yml | 5 - ...support_ordering_project_notes_in_notes_api.yml | 5 - .../unreleased/32098-pipelines-navigation.yml | 6 - .../unreleased/32878-merge-request-from-email.yml | 5 - ...upport-for-prometheus-service-configuration.yml | 5 - .../unreleased/34600-performance-wiki-pages.yml | 5 - ...85-allow-git-pull-push-on-project-redirects.yml | 5 - .../unreleased/35616-move-k8-to-cluster-page.yml | 5 - changelogs/unreleased/35724-animate-sidebar.yml | 5 - changelogs/unreleased/36400-trigger-job.yml | 5 - changelogs/unreleased/37354-pipelines-update.yml | 5 - ...38032-deploy-markers-should-be-more-verbose.yml | 5 - .../38075_allow_refernce_integer_labels.yml | 5 - ...ration-error-message-is-not-accurate-enough.yml | 5 - .../38822-oauth-search-case-insensitive.yml | 5 - ...62-email-notifications-not-sent-as-expected.yml | 6 - changelogs/unreleased/38869-templates.yml | 5 - ...877-disable-autocomplete-in-filtered-search.yml | 5 - ...uto-devops-is-turned-on-in-project-settings.yml | 5 - .../39335-add-time-spend-to-milestones.yml | 5 - ...l-doesn-t-take-in-account-hostname-settings.yml | 5 - .../39367-fix-new-email-session-path.yml | 5 - .../unreleased/39436-pages-api-administrative.yml | 5 - ...55-clone-dropdown-should-not-have-a-tooltip.yml | 5 - .../39497-inline-edit-issue-on-mobile.yml | 5 - .../39601-create-issuable-destroy-service.yml | 5 - ...counter-caches-out-of-issues-merge-requests.yml | 5 - .../unreleased/39720-group-milestone-sorting.yml | 5 - .../unreleased/39727-add-axios-to-common.yml | 5 - ...821-fix-commits-list-with-multi-file-editor.yml | 5 - .../39827-fix-projects-dropdown-overflow.yml | 5 - ...sed_status_of_links_to_issues_on_wiki_pages.yml | 5 - ...peline-transition-with-single-manual-action.yml | 6 - ...nt-set-mattermost-username-channel-from-api.yml | 5 - .../39977-gitlab-shell-default-timeout.yml | 5 - changelogs/unreleased/40016-log-header.yml | 5 - ...red-when-a-comment-with-time-spent-is-added.yml | 5 - ...6_fix_special_charecter_search_in_filenames.yml | 5 - .../40161-extra-margin-on-svg-logo-in-header.yml | 5 - .../40286-hide-full-namespace-groups-tree.yml | 6 - ...emove-rake-gitlab-sidekiq-drop-post-receive.yml | 5 - ...373-fix-issue-note-submit-disabled-on-paste.yml | 6 - .../unreleased/40481-bump-jquery-to-2-2-4.yml | 5 - changelogs/unreleased/40508-snippets-zen-mode.yml | 5 - ...diff-when-branch-and-tag-have-the-same-name.yml | 5 - ...0561-environment-scope-value-is-not-trimmed.yml | 5 - .../unreleased/40568-bump-seed-fu-to-2-3-7.yml | 5 - .../40573-rename-gke-as-kubernetes-engine.yml | 5 - changelogs/unreleased/40770-doc-elasticsearch.yml | 5 - changelogs/unreleased/4080-align-retry-btn.yml | 5 - ...ect_ci_config_path_leading_slash_validation.yml | 6 - .../unreleased/admin-welcome-new-group-link.yml | 5 - changelogs/unreleased/an-gitaly-timeouts.yml | 5 - changelogs/unreleased/brand_header_change.yml | 5 - .../unreleased/bvl-circuitbreaker-process.yml | 5 - .../unreleased/bvl-delete-empty-fork-networks.yml | 5 - .../bvl-limit-fork-queries-on-project-show.yml | 5 - .../unreleased/bvl-subgroup-in-dropdowns.yml | 5 - changelogs/unreleased/cleanup-issues-schema.yml | 5 - changelogs/unreleased/commit-title-wrapping.yml | 5 - changelogs/unreleased/deploy-keys-loading-icon.yml | 5 - .../dm-commit-diff-discussions-in-mr-context.yml | 5 - .../unreleased/dm-image-blob-diff-full-url.yml | 5 - changelogs/unreleased/dm-ldap-email-readonly.yml | 5 - changelogs/unreleased/dm-search-pattern.yml | 5 - .../enable-scss-lint-unnecessary-mantissa.yml | 5 - .../feature-custom-text-for-new-projects.yml | 5 - .../feature-disable-password-authentication.yml | 5 - ...-34834-missing-dependency-should-fail-job-2.yml | 5 - changelogs/unreleased/feature_add_mermaid.yml | 5 - .../unreleased/fix-filter-by-my-reaction.yml | 5 - .../fix-new-project-guidelines-styling.yml | 5 - .../fix-protected-branches-descriptions.yml | 5 - ...sm-31771-do-not-allow-jobs-to-be-erased-new.yml | 5 - ...schedules-execute-a-commit-includes-ci-skip.yml | 6 - changelogs/unreleased/fix-todos-last-page.yml | 5 - .../unreleased/fj-40407-missing-order-paginate.yml | 5 - .../fj-40752-forks-api-not-using-services.yml | 5 - changelogs/unreleased/fl-upgrade-svg.yml | 5 - .../unreleased/group-new-miletone-breadcrumb.yml | 5 - .../hashed-storage-attachments-migration-path.yml | 5 - .../unreleased/improved-changes-dropdown.yml | 5 - changelogs/unreleased/issue_39238.yml | 5 - .../merge-request-lock-icon-size-fix.yml | 5 - .../unreleased/merge-requests-schema-cleanup.yml | 5 - .../mk-add-old-attachments-to-uploads-table.yml | 5 - changelogs/unreleased/mk-add-user-rate-limits.yml | 6 - ...-schema-dump-of-untracked-files-for-uploads.yml | 5 - .../optimize-projects-for-imported-projects.yml | 6 - .../osw-isolate-mr-widget-exposed-attributes.yml | 5 - .../unreleased/outdated-browser-position-fix.yml | 5 - changelogs/unreleased/patch-24.yml | 5 - ...pdate_prometheus_gem_to_well_tested_version.yml | 5 - .../unreleased/perform-sql-matching-of-tags.yml | 5 - .../sh-remove-allocation-tracking-influxdb.yml | 5 - .../unreleased/skip_confirmation_user_API.yml | 7 - changelogs/unreleased/text-utils.yml | 5 - .../unreleased/throttle-touching-of-objects.yml | 5 - .../tm-feature-list-runners-jobs-api.yml | 5 - .../unreleased/tm-feature-namespace-by-id-api.yml | 5 - ...te-emoji-digests-with-latest-from-gemojione.yml | 6 - .../unreleased/update-merge-worker-metrics.yml | 5 - .../unreleased/update_mr_changes_empty_page.yml | 5 - .../unreleased/use-count_commits-directly.yml | 5 - .../use-merge-requests-diff-id-column.yml | 5 - changelogs/unreleased/user-agent-gke-api.yml | 5 - changelogs/unreleased/winh-subgroups-api.yml | 5 - changelogs/unreleased/zj-commit-show-n-1.yml | 5 - changelogs/unreleased/zj-empty-repo-importer.yml | 5 - .../unreleased/zj-memoization-mr-commits.yml | 5 - 118 files changed, 149 insertions(+), 597 deletions(-) delete mode 100644 changelogs/unreleased/13634-broadcast-message.yml delete mode 100644 changelogs/unreleased/15588-fix-empty-dropdown-on-create-new-pipeline-in-case-of-validation-errors.yml delete mode 100644 changelogs/unreleased/15774-fix-39233-500-in-merge-request.yml delete mode 100644 changelogs/unreleased/18040-rubocop-line-break-after-guard-clause.yml delete mode 100644 changelogs/unreleased/21143-customize-branch-name-when-using-create-branch-in-an-issue.yml delete mode 100644 changelogs/unreleased/22680-unlabel-slash-command-limit-autocomplete-to-applied-labels.yml delete mode 100644 changelogs/unreleased/28377-add-edit-button-to-mobile-file-view.yml delete mode 100644 changelogs/unreleased/29483-no-feedback-when-checking-on-checklist-if-potential-spam-was-detected.yml delete mode 100644 changelogs/unreleased/32057_support_ordering_project_notes_in_notes_api.yml delete mode 100644 changelogs/unreleased/32098-pipelines-navigation.yml delete mode 100644 changelogs/unreleased/32878-merge-request-from-email.yml delete mode 100644 changelogs/unreleased/33338-internationalization-support-for-prometheus-service-configuration.yml delete mode 100644 changelogs/unreleased/34600-performance-wiki-pages.yml delete mode 100644 changelogs/unreleased/35385-allow-git-pull-push-on-project-redirects.yml delete mode 100644 changelogs/unreleased/35616-move-k8-to-cluster-page.yml delete mode 100644 changelogs/unreleased/35724-animate-sidebar.yml delete mode 100644 changelogs/unreleased/36400-trigger-job.yml delete mode 100644 changelogs/unreleased/37354-pipelines-update.yml delete mode 100644 changelogs/unreleased/38032-deploy-markers-should-be-more-verbose.yml delete mode 100644 changelogs/unreleased/38075_allow_refernce_integer_labels.yml delete mode 100644 changelogs/unreleased/38393-Milestone-duration-error-message-is-not-accurate-enough.yml delete mode 100644 changelogs/unreleased/38822-oauth-search-case-insensitive.yml delete mode 100644 changelogs/unreleased/38862-email-notifications-not-sent-as-expected.yml delete mode 100644 changelogs/unreleased/38869-templates.yml delete mode 100644 changelogs/unreleased/38877-disable-autocomplete-in-filtered-search.yml delete mode 100644 changelogs/unreleased/38962-automatically-run-a-pipeline-when-auto-devops-is-turned-on-in-project-settings.yml delete mode 100644 changelogs/unreleased/39335-add-time-spend-to-milestones.yml delete mode 100644 changelogs/unreleased/39364-in-issue-board-url-doesn-t-take-in-account-hostname-settings.yml delete mode 100644 changelogs/unreleased/39367-fix-new-email-session-path.yml delete mode 100644 changelogs/unreleased/39436-pages-api-administrative.yml delete mode 100644 changelogs/unreleased/39455-clone-dropdown-should-not-have-a-tooltip.yml delete mode 100644 changelogs/unreleased/39497-inline-edit-issue-on-mobile.yml delete mode 100644 changelogs/unreleased/39601-create-issuable-destroy-service.yml delete mode 100644 changelogs/unreleased/39602-move-update-project-counter-caches-out-of-issues-merge-requests.yml delete mode 100644 changelogs/unreleased/39720-group-milestone-sorting.yml delete mode 100644 changelogs/unreleased/39727-add-axios-to-common.yml delete mode 100644 changelogs/unreleased/39821-fix-commits-list-with-multi-file-editor.yml delete mode 100644 changelogs/unreleased/39827-fix-projects-dropdown-overflow.yml delete mode 100644 changelogs/unreleased/39869_show_closed_status_of_links_to_issues_on_wiki_pages.yml delete mode 100644 changelogs/unreleased/39884-fix-pipeline-transition-with-single-manual-action.yml delete mode 100644 changelogs/unreleased/39895-cant-set-mattermost-username-channel-from-api.yml delete mode 100644 changelogs/unreleased/39977-gitlab-shell-default-timeout.yml delete mode 100644 changelogs/unreleased/40016-log-header.yml delete mode 100644 changelogs/unreleased/40122-only-one-note-webhook-is-triggered-when-a-comment-with-time-spent-is-added.yml delete mode 100644 changelogs/unreleased/40146_fix_special_charecter_search_in_filenames.yml delete mode 100644 changelogs/unreleased/40161-extra-margin-on-svg-logo-in-header.yml delete mode 100644 changelogs/unreleased/40286-hide-full-namespace-groups-tree.yml delete mode 100644 changelogs/unreleased/40290-remove-rake-gitlab-sidekiq-drop-post-receive.yml delete mode 100644 changelogs/unreleased/40373-fix-issue-note-submit-disabled-on-paste.yml delete mode 100644 changelogs/unreleased/40481-bump-jquery-to-2-2-4.yml delete mode 100644 changelogs/unreleased/40508-snippets-zen-mode.yml delete mode 100644 changelogs/unreleased/40530-merge-request-generates-wrong-diff-when-branch-and-tag-have-the-same-name.yml delete mode 100644 changelogs/unreleased/40561-environment-scope-value-is-not-trimmed.yml delete mode 100644 changelogs/unreleased/40568-bump-seed-fu-to-2-3-7.yml delete mode 100644 changelogs/unreleased/40573-rename-gke-as-kubernetes-engine.yml delete mode 100644 changelogs/unreleased/40770-doc-elasticsearch.yml delete mode 100644 changelogs/unreleased/4080-align-retry-btn.yml delete mode 100644 changelogs/unreleased/add_project_ci_config_path_leading_slash_validation.yml delete mode 100644 changelogs/unreleased/admin-welcome-new-group-link.yml delete mode 100644 changelogs/unreleased/an-gitaly-timeouts.yml delete mode 100644 changelogs/unreleased/brand_header_change.yml delete mode 100644 changelogs/unreleased/bvl-circuitbreaker-process.yml delete mode 100644 changelogs/unreleased/bvl-delete-empty-fork-networks.yml delete mode 100644 changelogs/unreleased/bvl-limit-fork-queries-on-project-show.yml delete mode 100644 changelogs/unreleased/bvl-subgroup-in-dropdowns.yml delete mode 100644 changelogs/unreleased/cleanup-issues-schema.yml delete mode 100644 changelogs/unreleased/commit-title-wrapping.yml delete mode 100644 changelogs/unreleased/deploy-keys-loading-icon.yml delete mode 100644 changelogs/unreleased/dm-commit-diff-discussions-in-mr-context.yml delete mode 100644 changelogs/unreleased/dm-image-blob-diff-full-url.yml delete mode 100644 changelogs/unreleased/dm-ldap-email-readonly.yml delete mode 100644 changelogs/unreleased/dm-search-pattern.yml delete mode 100644 changelogs/unreleased/enable-scss-lint-unnecessary-mantissa.yml delete mode 100644 changelogs/unreleased/feature-custom-text-for-new-projects.yml delete mode 100644 changelogs/unreleased/feature-disable-password-authentication.yml delete mode 100644 changelogs/unreleased/feature-sm-34834-missing-dependency-should-fail-job-2.yml delete mode 100644 changelogs/unreleased/feature_add_mermaid.yml delete mode 100644 changelogs/unreleased/fix-filter-by-my-reaction.yml delete mode 100644 changelogs/unreleased/fix-new-project-guidelines-styling.yml delete mode 100644 changelogs/unreleased/fix-protected-branches-descriptions.yml delete mode 100644 changelogs/unreleased/fix-sm-31771-do-not-allow-jobs-to-be-erased-new.yml delete mode 100644 changelogs/unreleased/fix-sm-37991-avoid-deactivation-when-pipeline-schedules-execute-a-commit-includes-ci-skip.yml delete mode 100644 changelogs/unreleased/fix-todos-last-page.yml delete mode 100644 changelogs/unreleased/fj-40407-missing-order-paginate.yml delete mode 100644 changelogs/unreleased/fj-40752-forks-api-not-using-services.yml delete mode 100644 changelogs/unreleased/fl-upgrade-svg.yml delete mode 100644 changelogs/unreleased/group-new-miletone-breadcrumb.yml delete mode 100644 changelogs/unreleased/hashed-storage-attachments-migration-path.yml delete mode 100644 changelogs/unreleased/improved-changes-dropdown.yml delete mode 100644 changelogs/unreleased/issue_39238.yml delete mode 100644 changelogs/unreleased/merge-request-lock-icon-size-fix.yml delete mode 100644 changelogs/unreleased/merge-requests-schema-cleanup.yml delete mode 100644 changelogs/unreleased/mk-add-old-attachments-to-uploads-table.yml delete mode 100644 changelogs/unreleased/mk-add-user-rate-limits.yml delete mode 100644 changelogs/unreleased/mk-fix-schema-dump-of-untracked-files-for-uploads.yml delete mode 100644 changelogs/unreleased/optimize-projects-for-imported-projects.yml delete mode 100644 changelogs/unreleased/osw-isolate-mr-widget-exposed-attributes.yml delete mode 100644 changelogs/unreleased/outdated-browser-position-fix.yml delete mode 100644 changelogs/unreleased/patch-24.yml delete mode 100644 changelogs/unreleased/pawel-update_prometheus_gem_to_well_tested_version.yml delete mode 100644 changelogs/unreleased/perform-sql-matching-of-tags.yml delete mode 100644 changelogs/unreleased/sh-remove-allocation-tracking-influxdb.yml delete mode 100644 changelogs/unreleased/skip_confirmation_user_API.yml delete mode 100644 changelogs/unreleased/text-utils.yml delete mode 100644 changelogs/unreleased/throttle-touching-of-objects.yml delete mode 100644 changelogs/unreleased/tm-feature-list-runners-jobs-api.yml delete mode 100644 changelogs/unreleased/tm-feature-namespace-by-id-api.yml delete mode 100644 changelogs/unreleased/update-emoji-digests-with-latest-from-gemojione.yml delete mode 100644 changelogs/unreleased/update-merge-worker-metrics.yml delete mode 100644 changelogs/unreleased/update_mr_changes_empty_page.yml delete mode 100644 changelogs/unreleased/use-count_commits-directly.yml delete mode 100644 changelogs/unreleased/use-merge-requests-diff-id-column.yml delete mode 100644 changelogs/unreleased/user-agent-gke-api.yml delete mode 100644 changelogs/unreleased/winh-subgroups-api.yml delete mode 100644 changelogs/unreleased/zj-commit-show-n-1.yml delete mode 100644 changelogs/unreleased/zj-empty-repo-importer.yml delete mode 100644 changelogs/unreleased/zj-memoization-mr-commits.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index fd7825b5f82..a9539bbed87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,155 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 10.3.0 (2017-12-22) + +### Security (1 change, 1 of them is from the community) + +- Upgrade jQuery to 2.2.4. !15570 (Takuya Noguchi) + +### Fixed (55 changes, 8 of them are from the community) + +- Fail jobs if its dependency is missing. !14009 +- Fix errors when selecting numeric-only labels in the labels autocomplete selector. !14607 (haseebeqx) +- Fix pipeline status transition for single manual job. This would also fix pipeline duration becuse it is depending on status transition. !15251 +- Fix acceptance of username for Mattermost service update. !15275 +- Set the default gitlab-shell timeout to 3 hours. !15292 +- Make sure a user can add projects to subgroups they have access to. !15294 +- OAuth identity lookups case-insensitive. !15312 +- Fix filter by my reaction is not working. !15345 (Hiroyuki Sato) +- Avoid deactivation when pipeline schedules execute a branch includes `[ci skip]` comment. !15405 +- Add recaptcha modal to issue updates detected as spam. !15408 +- Fix item name and namespace text overflow in Projects dropdown. !15451 +- Removed unused rake task, 'rake gitlab:sidekiq:drop_post_receive'. !15493 +- Fix commits page throwing 500 when the multi-file editor was enabled. !15502 +- Fix Issue comment submit button being disabled when pasting content from another GFM note. !15530 +- Reenable Prometheus metrics, add more control over Prometheus method instrumentation. !15558 +- Fix broadcast message not showing up on login page. !15578 +- Initializes the branches dropdown when the 'Start new pipeline' failed due to validation errors. !15588 (Christiaan Van den Poel) +- Fix merge requests where the source or target branch name matches a tag name. !15591 +- Create a fork network for forks with a deleted source. !15595 +- Fix search results when a filename would contain a special character. !15606 (haseebeqx) +- Strip leading & trailing whitespaces in CI/CD secret variable keys. !15615 +- Correctly link to a forked project from the new fork page. !15653 +- Fix the fork project functionality for projects with hashed storage. !15671 +- Added default order to UsersFinder. !15679 +- Fix graph notes number duplication. !15696 (Vladislav Kaverin) +- Fix updateEndpoint undefined error for issue_show app root. !15698 +- Change boards page boards_data absolute urls to paths. !15703 +- Using appropiate services in the API for managing forks. !15709 +- Confirming email with invalid token should no longer generate an error. !15726 +- fix #39233 - 500 in merge request. !15774 (Martin Nowak) +- Use Markdown styling for new project guidelines. !15785 (Markus Koller) +- Fix error during schema dump. !15866 +- Fix broken illustration images for monitoring page empty states. !15889 +- Make sure user email is read only when synced with LDAP. !15915 +- Fixed outdated browser flash positioning. +- Fix gitlab:import:repos Rake task moving repositories into the wrong location. +- Gracefully handle case when repository's root ref does not exist. +- Fix GitHub importer using removed interface. +- Align retry button with job title with new grid size. +- Fixed admin welcome screen new group path. +- Fix related branches/Merge requests failing to load when the hostname setting is changed. +- Init zen mode in snippets pages. +- Remove extra margin from wordmark in header. +- Fixed long commit links not wrapping correctly. +- Fixed deploy keys remove button loading state not resetting. +- Use app host instead of asset host when rendering image blob or diff. +- Hide log size for mobile screens. +- Fix sending notification emails to users with the mention level set who were mentioned in an issue or merge request description. +- Changed validation error message on wrong milestone dates. (Xurxo Méndez Pérez) +- Fix access to the final page of todos. +- Fixed new group milestone breadcrumbs. +- Fix image diff notification email from showing wrong content. +- Fixed merge request lock icon size. +- Make sure head pippeline always corresponds with the head sha of an MR. +- Prevent 500 error when inspecting job after trigger was removed. + +### Changed (14 changes, 2 of them are from the community) + +- Only owner or master can erase jobs. !15216 +- Allow password authentication to be disabled entirely. !15223 (Markus Koller) +- Add the option to automatically run a pipeline after updating AutoDevOps settings. !15380 +- Add total_time_spent to the `changes` hash in issuable Webhook payloads. !15381 +- Monitor NFS shards for circuitbreaker in a separate process. !15426 +- Add inline editing to issues on mobile. !15438 +- Add custom brand text on new project pages. !15541 (Markus Koller) +- Show only group name by default and put full namespace in tooltip in Groups tree. !15650 +- Use custom user agent header in all GCP API requests. !15705 +- Changed the deploy markers on the prometheus dashboard to be more verbose. !38032 +- Animate contextual sidebar on collapse/expand. +- Update emojis. Add :gay_pride_flag: and :speech_left:. Remove extraneous comma in :cartwheel_tone4:. +- When a custom header logo is present, don't show GitLab type logo. +- Improved diff changed files dropdown design. + +### Performance (19 changes) + +- Add timeouts for Gitaly calls. !15047 +- Performance issues when loading large number of wiki pages. !15276 +- Add performance logging to UpdateMergeRequestsWorker. !15360 +- Keep track of all circuitbreaker keys in a set. !15613 +- Improve the performance for counting commits. !15628 +- Reduce requests for project forks on show page of projects that have forks. !15663 +- Perform SQL matching of Build&Runner tags to greatly speed-up job picking. +- Only load branch names for protected branch checks. +- Optimize API /groups/:id/projects by preloading associations. +- Remove allocation tracking code from InfluxDB sampler for performance. +- Throttle the number of UPDATEs triggered by touch. +- Make finding most recent merge request diffs more efficient. +- Fetch blobs in bulk when generating diffs. +- Cache commits for MergeRequest diffs. +- Use fuzzy search with minimum length of 3 characters where appropriate. +- Add axios to common file. +- Remove template selector from global namespace. +- check the import_status field before doing SQL operations to check the import url. +- Stop sending milestone and labels data over the wire for MR widget requests. + +### Added (22 changes, 15 of them are from the community) + +- Limit autocomplete menu to applied labels. !11110 (Vitaliy @blackst0ne Klachkov) +- Make diff notes created on a commit in a merge request to persist a rebase. !12148 +- Allow creation of merge request from email. !13817 (janp) +- Add an ability to use a custom branch name on creation from issues. !13884 (Vitaliy @blackst0ne Klachkov) +- Add anonymous rate limit per IP, and authenticated (web or API) rate limits per user. !14708 +- Create a new form to add Existing Kubernetes Cluster. !14805 +- Add support of Mermaid (generation of diagrams and flowcharts from text). !15107 (Vitaliy @blackst0ne Klachkov) +- Add total time spent to milestones. !15116 (George Andrinopoulos) +- Add /groups/:id/subgroups endpoint to API. !15142 (marbemac) +- Add administrative endpoint to list all pages domains. !15160 (Travis Miller) +- Adds Rubocop rule for line break after guard clause. !15188 (Jacopo Beschi @jacopo-beschi) +- Add edit button to mobile file view. !15199 (Travis Miller) +- Add dropdown sort to group milestones. !15230 (George Andrinopoulos) +- added support for ordering and sorting in notes api. !15342 (haseebeqx) +- Hashed Storage migration script now supports migrating project attachments. !15352 +- New API endpoint - list jobs for a specified runner. !15432 +- Add new API endpoint - get a namespace by ID. !15442 +- Disables autocomplete in filtered searc. !15477 (Jacopo Beschi @jacopo-beschi) +- Update empty state page of merge request 'changes' tab. !15611 (Vitaliy @blackst0ne Klachkov) +- Allow git pull/push on group/user/project redirects. !15670 +- show status of gitlab reference links in wiki. !15694 (haseebeqx) +- Add email confirmation parameters for user creation and update via API. (Daniel Juarez) + +### Other (17 changes, 7 of them are from the community) + +- Enable UnnecessaryMantissa in scss-lint. !15255 (Takuya Noguchi) +- Add untracked files to uploads table. !15270 +- Move update_project_counter_caches? out of issue and merge request. !15300 (George Andrinopoulos) +- Removed tooltip from clone dropdown. !15334 +- Clean up empty fork networks. !15373 +- Create issuable destroy service. !15604 (George Andrinopoulos) +- Upgrade seed-fu to 2.3.7. !15607 (Takuya Noguchi) +- Rename GKE as Kubernetes Engine. !15608 (Takuya Noguchi) +- Prefer ci_config_path validation for leading slashes instead of sanitizing the input. !15672 (Christiaan Van den Poel) +- Fix typo in docs about Elasticsearch. !15699 (Takuya Noguchi) +- Add internationalization support for the prometheus integration. !33338 +- Export text utils functions as es6 module and add tests. +- Stop reloading the page when using pagination and tabs - use API calls - in Pipelines table. +- Clean up schema of the "issues" table. +- Clarify wording of protected branch settings for the default branch. +- Update svg external depencency. +- Clean up schema of the "merge_requests" table. + + ## 10.2.5 (2017-12-15) ### Fixed (8 changes) diff --git a/changelogs/unreleased/13634-broadcast-message.yml b/changelogs/unreleased/13634-broadcast-message.yml deleted file mode 100644 index 26c4c133443..00000000000 --- a/changelogs/unreleased/13634-broadcast-message.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix broadcast message not showing up on login page -merge_request: 15578 -author: -type: fixed diff --git a/changelogs/unreleased/15588-fix-empty-dropdown-on-create-new-pipeline-in-case-of-validation-errors.yml b/changelogs/unreleased/15588-fix-empty-dropdown-on-create-new-pipeline-in-case-of-validation-errors.yml deleted file mode 100644 index a4934c8896d..00000000000 --- a/changelogs/unreleased/15588-fix-empty-dropdown-on-create-new-pipeline-in-case-of-validation-errors.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Initializes the branches dropdown when the 'Start new pipeline' failed due to validation errors -merge_request: 15588 -author: Christiaan Van den Poel -type: fixed diff --git a/changelogs/unreleased/15774-fix-39233-500-in-merge-request.yml b/changelogs/unreleased/15774-fix-39233-500-in-merge-request.yml deleted file mode 100644 index 1179b3f20e6..00000000000 --- a/changelogs/unreleased/15774-fix-39233-500-in-merge-request.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'fix #39233 - 500 in merge request' -merge_request: 15774 -author: Martin Nowak -type: fixed diff --git a/changelogs/unreleased/18040-rubocop-line-break-after-guard-clause.yml b/changelogs/unreleased/18040-rubocop-line-break-after-guard-clause.yml deleted file mode 100644 index e3c7ffc8046..00000000000 --- a/changelogs/unreleased/18040-rubocop-line-break-after-guard-clause.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Adds Rubocop rule for line break after guard clause -merge_request: 15188 -author: Jacopo Beschi @jacopo-beschi -type: added diff --git a/changelogs/unreleased/21143-customize-branch-name-when-using-create-branch-in-an-issue.yml b/changelogs/unreleased/21143-customize-branch-name-when-using-create-branch-in-an-issue.yml deleted file mode 100644 index d4c209aaf2b..00000000000 --- a/changelogs/unreleased/21143-customize-branch-name-when-using-create-branch-in-an-issue.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add an ability to use a custom branch name on creation from issues -merge_request: 13884 -author: Vitaliy @blackst0ne Klachkov -type: added diff --git a/changelogs/unreleased/22680-unlabel-slash-command-limit-autocomplete-to-applied-labels.yml b/changelogs/unreleased/22680-unlabel-slash-command-limit-autocomplete-to-applied-labels.yml deleted file mode 100644 index 6d7f8655282..00000000000 --- a/changelogs/unreleased/22680-unlabel-slash-command-limit-autocomplete-to-applied-labels.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Limit autocomplete menu to applied labels -merge_request: 11110 -author: Vitaliy @blackst0ne Klachkov -type: added diff --git a/changelogs/unreleased/28377-add-edit-button-to-mobile-file-view.yml b/changelogs/unreleased/28377-add-edit-button-to-mobile-file-view.yml deleted file mode 100644 index b6646379b8d..00000000000 --- a/changelogs/unreleased/28377-add-edit-button-to-mobile-file-view.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add edit button to mobile file view -merge_request: 15199 -author: Travis Miller -type: added diff --git a/changelogs/unreleased/29483-no-feedback-when-checking-on-checklist-if-potential-spam-was-detected.yml b/changelogs/unreleased/29483-no-feedback-when-checking-on-checklist-if-potential-spam-was-detected.yml deleted file mode 100644 index 6bfcc5e70de..00000000000 --- a/changelogs/unreleased/29483-no-feedback-when-checking-on-checklist-if-potential-spam-was-detected.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add recaptcha modal to issue updates detected as spam -merge_request: 15408 -author: -type: fixed diff --git a/changelogs/unreleased/32057_support_ordering_project_notes_in_notes_api.yml b/changelogs/unreleased/32057_support_ordering_project_notes_in_notes_api.yml deleted file mode 100644 index cd19d24e035..00000000000 --- a/changelogs/unreleased/32057_support_ordering_project_notes_in_notes_api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: added support for ordering and sorting in notes api -merge_request: 15342 -author: haseebeqx -type: added diff --git a/changelogs/unreleased/32098-pipelines-navigation.yml b/changelogs/unreleased/32098-pipelines-navigation.yml deleted file mode 100644 index 925c92b6be8..00000000000 --- a/changelogs/unreleased/32098-pipelines-navigation.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Stop reloading the page when using pagination and tabs - use API calls - in - Pipelines table -merge_request: -author: -type: other diff --git a/changelogs/unreleased/32878-merge-request-from-email.yml b/changelogs/unreleased/32878-merge-request-from-email.yml deleted file mode 100644 index 2df148d5a81..00000000000 --- a/changelogs/unreleased/32878-merge-request-from-email.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow creation of merge request from email -merge_request: 13817 -author: janp -type: added diff --git a/changelogs/unreleased/33338-internationalization-support-for-prometheus-service-configuration.yml b/changelogs/unreleased/33338-internationalization-support-for-prometheus-service-configuration.yml deleted file mode 100644 index d61bbf2e355..00000000000 --- a/changelogs/unreleased/33338-internationalization-support-for-prometheus-service-configuration.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add internationalization support for the prometheus integration -merge_request: 33338 -author: -type: other diff --git a/changelogs/unreleased/34600-performance-wiki-pages.yml b/changelogs/unreleased/34600-performance-wiki-pages.yml deleted file mode 100644 index 541ae8f8e60..00000000000 --- a/changelogs/unreleased/34600-performance-wiki-pages.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Performance issues when loading large number of wiki pages -merge_request: 15276 -author: -type: performance diff --git a/changelogs/unreleased/35385-allow-git-pull-push-on-project-redirects.yml b/changelogs/unreleased/35385-allow-git-pull-push-on-project-redirects.yml deleted file mode 100644 index 31450287caf..00000000000 --- a/changelogs/unreleased/35385-allow-git-pull-push-on-project-redirects.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow git pull/push on group/user/project redirects -merge_request: 15670 -author: -type: added diff --git a/changelogs/unreleased/35616-move-k8-to-cluster-page.yml b/changelogs/unreleased/35616-move-k8-to-cluster-page.yml deleted file mode 100644 index 032a39608ce..00000000000 --- a/changelogs/unreleased/35616-move-k8-to-cluster-page.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Create a new form to add Existing Kubernetes Cluster -merge_request: 14805 -author: -type: added diff --git a/changelogs/unreleased/35724-animate-sidebar.yml b/changelogs/unreleased/35724-animate-sidebar.yml deleted file mode 100644 index 5d0b46a23c8..00000000000 --- a/changelogs/unreleased/35724-animate-sidebar.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Animate contextual sidebar on collapse/expand -merge_request: -author: -type: changed diff --git a/changelogs/unreleased/36400-trigger-job.yml b/changelogs/unreleased/36400-trigger-job.yml deleted file mode 100644 index 27243813dc8..00000000000 --- a/changelogs/unreleased/36400-trigger-job.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Prevent 500 error when inspecting job after trigger was removed -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/37354-pipelines-update.yml b/changelogs/unreleased/37354-pipelines-update.yml deleted file mode 100644 index 2b6ddfe95ed..00000000000 --- a/changelogs/unreleased/37354-pipelines-update.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Make sure head pippeline always corresponds with the head sha of an MR -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/38032-deploy-markers-should-be-more-verbose.yml b/changelogs/unreleased/38032-deploy-markers-should-be-more-verbose.yml deleted file mode 100644 index a1f28b3ba0f..00000000000 --- a/changelogs/unreleased/38032-deploy-markers-should-be-more-verbose.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Changed the deploy markers on the prometheus dashboard to be more verbose -merge_request: 38032 -author: -type: changed diff --git a/changelogs/unreleased/38075_allow_refernce_integer_labels.yml b/changelogs/unreleased/38075_allow_refernce_integer_labels.yml deleted file mode 100644 index b5342d4adf8..00000000000 --- a/changelogs/unreleased/38075_allow_refernce_integer_labels.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix errors when selecting numeric-only labels in the labels autocomplete selector -merge_request: 14607 -author: haseebeqx -type: fixed diff --git a/changelogs/unreleased/38393-Milestone-duration-error-message-is-not-accurate-enough.yml b/changelogs/unreleased/38393-Milestone-duration-error-message-is-not-accurate-enough.yml deleted file mode 100644 index c73cf8bf60b..00000000000 --- a/changelogs/unreleased/38393-Milestone-duration-error-message-is-not-accurate-enough.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Changed validation error message on wrong milestone dates -merge_request: -author: Xurxo Méndez Pérez -type: fixed diff --git a/changelogs/unreleased/38822-oauth-search-case-insensitive.yml b/changelogs/unreleased/38822-oauth-search-case-insensitive.yml deleted file mode 100644 index d84360b4c5c..00000000000 --- a/changelogs/unreleased/38822-oauth-search-case-insensitive.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: OAuth identity lookups case-insensitive -merge_request: 15312 -author: -type: fixed diff --git a/changelogs/unreleased/38862-email-notifications-not-sent-as-expected.yml b/changelogs/unreleased/38862-email-notifications-not-sent-as-expected.yml deleted file mode 100644 index 6b1b309ab14..00000000000 --- a/changelogs/unreleased/38862-email-notifications-not-sent-as-expected.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Fix sending notification emails to users with the mention level set who were - mentioned in an issue or merge request description -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/38869-templates.yml b/changelogs/unreleased/38869-templates.yml deleted file mode 100644 index 957b5f27bd0..00000000000 --- a/changelogs/unreleased/38869-templates.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove template selector from global namespace -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/38877-disable-autocomplete-in-filtered-search.yml b/changelogs/unreleased/38877-disable-autocomplete-in-filtered-search.yml deleted file mode 100644 index 07439a860ec..00000000000 --- a/changelogs/unreleased/38877-disable-autocomplete-in-filtered-search.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Disables autocomplete in filtered searc -merge_request: 15477 -author: Jacopo Beschi @jacopo-beschi -type: added diff --git a/changelogs/unreleased/38962-automatically-run-a-pipeline-when-auto-devops-is-turned-on-in-project-settings.yml b/changelogs/unreleased/38962-automatically-run-a-pipeline-when-auto-devops-is-turned-on-in-project-settings.yml deleted file mode 100644 index a4d703bc69f..00000000000 --- a/changelogs/unreleased/38962-automatically-run-a-pipeline-when-auto-devops-is-turned-on-in-project-settings.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add the option to automatically run a pipeline after updating AutoDevOps settings -merge_request: 15380 -author: -type: changed diff --git a/changelogs/unreleased/39335-add-time-spend-to-milestones.yml b/changelogs/unreleased/39335-add-time-spend-to-milestones.yml deleted file mode 100644 index 41a43418cbf..00000000000 --- a/changelogs/unreleased/39335-add-time-spend-to-milestones.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add total time spent to milestones -merge_request: 15116 -author: George Andrinopoulos -type: added diff --git a/changelogs/unreleased/39364-in-issue-board-url-doesn-t-take-in-account-hostname-settings.yml b/changelogs/unreleased/39364-in-issue-board-url-doesn-t-take-in-account-hostname-settings.yml deleted file mode 100644 index 9793c6a8e9c..00000000000 --- a/changelogs/unreleased/39364-in-issue-board-url-doesn-t-take-in-account-hostname-settings.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Change boards page boards_data absolute urls to paths -merge_request: 15703 -author: -type: fixed diff --git a/changelogs/unreleased/39367-fix-new-email-session-path.yml b/changelogs/unreleased/39367-fix-new-email-session-path.yml deleted file mode 100644 index 73485d9d1a9..00000000000 --- a/changelogs/unreleased/39367-fix-new-email-session-path.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Confirming email with invalid token should no longer generate an error -merge_request: 15726 -author: -type: fixed diff --git a/changelogs/unreleased/39436-pages-api-administrative.yml b/changelogs/unreleased/39436-pages-api-administrative.yml deleted file mode 100644 index f38bbbd479c..00000000000 --- a/changelogs/unreleased/39436-pages-api-administrative.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add administrative endpoint to list all pages domains -merge_request: 15160 -author: Travis Miller -type: added diff --git a/changelogs/unreleased/39455-clone-dropdown-should-not-have-a-tooltip.yml b/changelogs/unreleased/39455-clone-dropdown-should-not-have-a-tooltip.yml deleted file mode 100644 index cb522cb7611..00000000000 --- a/changelogs/unreleased/39455-clone-dropdown-should-not-have-a-tooltip.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Removed tooltip from clone dropdown -merge_request: 15334 -author: -type: other diff --git a/changelogs/unreleased/39497-inline-edit-issue-on-mobile.yml b/changelogs/unreleased/39497-inline-edit-issue-on-mobile.yml deleted file mode 100644 index fc7c024f95a..00000000000 --- a/changelogs/unreleased/39497-inline-edit-issue-on-mobile.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add inline editing to issues on mobile -merge_request: 15438 -author: -type: changed diff --git a/changelogs/unreleased/39601-create-issuable-destroy-service.yml b/changelogs/unreleased/39601-create-issuable-destroy-service.yml deleted file mode 100644 index b0463f02eba..00000000000 --- a/changelogs/unreleased/39601-create-issuable-destroy-service.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Create issuable destroy service -merge_request: 15604 -author: George Andrinopoulos -type: other diff --git a/changelogs/unreleased/39602-move-update-project-counter-caches-out-of-issues-merge-requests.yml b/changelogs/unreleased/39602-move-update-project-counter-caches-out-of-issues-merge-requests.yml deleted file mode 100644 index 056afe43010..00000000000 --- a/changelogs/unreleased/39602-move-update-project-counter-caches-out-of-issues-merge-requests.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Move update_project_counter_caches? out of issue and merge request -merge_request: 15300 -author: George Andrinopoulos -type: other diff --git a/changelogs/unreleased/39720-group-milestone-sorting.yml b/changelogs/unreleased/39720-group-milestone-sorting.yml deleted file mode 100644 index 15ef87fa567..00000000000 --- a/changelogs/unreleased/39720-group-milestone-sorting.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add dropdown sort to group milestones -merge_request: 15230 -author: George Andrinopoulos -type: added diff --git a/changelogs/unreleased/39727-add-axios-to-common.yml b/changelogs/unreleased/39727-add-axios-to-common.yml deleted file mode 100644 index 688757d2486..00000000000 --- a/changelogs/unreleased/39727-add-axios-to-common.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add axios to common file -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/39821-fix-commits-list-with-multi-file-editor.yml b/changelogs/unreleased/39821-fix-commits-list-with-multi-file-editor.yml deleted file mode 100644 index 8b27c43d15b..00000000000 --- a/changelogs/unreleased/39821-fix-commits-list-with-multi-file-editor.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix commits page throwing 500 when the multi-file editor was enabled -merge_request: 15502 -author: -type: fixed diff --git a/changelogs/unreleased/39827-fix-projects-dropdown-overflow.yml b/changelogs/unreleased/39827-fix-projects-dropdown-overflow.yml deleted file mode 100644 index ebd7b582e8a..00000000000 --- a/changelogs/unreleased/39827-fix-projects-dropdown-overflow.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix item name and namespace text overflow in Projects dropdown -merge_request: 15451 -author: -type: fixed diff --git a/changelogs/unreleased/39869_show_closed_status_of_links_to_issues_on_wiki_pages.yml b/changelogs/unreleased/39869_show_closed_status_of_links_to_issues_on_wiki_pages.yml deleted file mode 100644 index cd31ed463a2..00000000000 --- a/changelogs/unreleased/39869_show_closed_status_of_links_to_issues_on_wiki_pages.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: show status of gitlab reference links in wiki -merge_request: 15694 -author: haseebeqx -type: added diff --git a/changelogs/unreleased/39884-fix-pipeline-transition-with-single-manual-action.yml b/changelogs/unreleased/39884-fix-pipeline-transition-with-single-manual-action.yml deleted file mode 100644 index 580b97241e7..00000000000 --- a/changelogs/unreleased/39884-fix-pipeline-transition-with-single-manual-action.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Fix pipeline status transition for single manual job. This would also fix pipeline - duration becuse it is depending on status transition -merge_request: 15251 -author: -type: fixed diff --git a/changelogs/unreleased/39895-cant-set-mattermost-username-channel-from-api.yml b/changelogs/unreleased/39895-cant-set-mattermost-username-channel-from-api.yml deleted file mode 100644 index 358c007387e..00000000000 --- a/changelogs/unreleased/39895-cant-set-mattermost-username-channel-from-api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix acceptance of username for Mattermost service update -merge_request: 15275 -author: -type: fixed diff --git a/changelogs/unreleased/39977-gitlab-shell-default-timeout.yml b/changelogs/unreleased/39977-gitlab-shell-default-timeout.yml deleted file mode 100644 index b7a974fd8d9..00000000000 --- a/changelogs/unreleased/39977-gitlab-shell-default-timeout.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Set the default gitlab-shell timeout to 3 hours -merge_request: 15292 -author: -type: fixed diff --git a/changelogs/unreleased/40016-log-header.yml b/changelogs/unreleased/40016-log-header.yml deleted file mode 100644 index f52c2d2a0d5..00000000000 --- a/changelogs/unreleased/40016-log-header.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Hide log size for mobile screens -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/40122-only-one-note-webhook-is-triggered-when-a-comment-with-time-spent-is-added.yml b/changelogs/unreleased/40122-only-one-note-webhook-is-triggered-when-a-comment-with-time-spent-is-added.yml deleted file mode 100644 index a2ae2059c47..00000000000 --- a/changelogs/unreleased/40122-only-one-note-webhook-is-triggered-when-a-comment-with-time-spent-is-added.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add total_time_spent to the `changes` hash in issuable Webhook payloads -merge_request: 15381 -author: -type: changed diff --git a/changelogs/unreleased/40146_fix_special_charecter_search_in_filenames.yml b/changelogs/unreleased/40146_fix_special_charecter_search_in_filenames.yml deleted file mode 100644 index 00f7dd7c0f0..00000000000 --- a/changelogs/unreleased/40146_fix_special_charecter_search_in_filenames.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix search results when a filename would contain a special character. -merge_request: 15606 -author: haseebeqx -type: fixed diff --git a/changelogs/unreleased/40161-extra-margin-on-svg-logo-in-header.yml b/changelogs/unreleased/40161-extra-margin-on-svg-logo-in-header.yml deleted file mode 100644 index fdaa90f0d5d..00000000000 --- a/changelogs/unreleased/40161-extra-margin-on-svg-logo-in-header.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove extra margin from wordmark in header -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/40286-hide-full-namespace-groups-tree.yml b/changelogs/unreleased/40286-hide-full-namespace-groups-tree.yml deleted file mode 100644 index cae02d0c2f6..00000000000 --- a/changelogs/unreleased/40286-hide-full-namespace-groups-tree.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Show only group name by default and put full namespace in tooltip in Groups - tree -merge_request: 15650 -author: -type: changed diff --git a/changelogs/unreleased/40290-remove-rake-gitlab-sidekiq-drop-post-receive.yml b/changelogs/unreleased/40290-remove-rake-gitlab-sidekiq-drop-post-receive.yml deleted file mode 100644 index 9c308321a19..00000000000 --- a/changelogs/unreleased/40290-remove-rake-gitlab-sidekiq-drop-post-receive.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Removed unused rake task, 'rake gitlab:sidekiq:drop_post_receive' -merge_request: 15493 -author: -type: fixed diff --git a/changelogs/unreleased/40373-fix-issue-note-submit-disabled-on-paste.yml b/changelogs/unreleased/40373-fix-issue-note-submit-disabled-on-paste.yml deleted file mode 100644 index e683e60397e..00000000000 --- a/changelogs/unreleased/40373-fix-issue-note-submit-disabled-on-paste.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Fix Issue comment submit button being disabled when pasting content from another - GFM note -merge_request: 15530 -author: -type: fixed diff --git a/changelogs/unreleased/40481-bump-jquery-to-2-2-4.yml b/changelogs/unreleased/40481-bump-jquery-to-2-2-4.yml deleted file mode 100644 index e275c65e8c8..00000000000 --- a/changelogs/unreleased/40481-bump-jquery-to-2-2-4.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Upgrade jQuery to 2.2.4 -merge_request: 15570 -author: Takuya Noguchi -type: security diff --git a/changelogs/unreleased/40508-snippets-zen-mode.yml b/changelogs/unreleased/40508-snippets-zen-mode.yml deleted file mode 100644 index c205218575b..00000000000 --- a/changelogs/unreleased/40508-snippets-zen-mode.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Init zen mode in snippets pages -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/40530-merge-request-generates-wrong-diff-when-branch-and-tag-have-the-same-name.yml b/changelogs/unreleased/40530-merge-request-generates-wrong-diff-when-branch-and-tag-have-the-same-name.yml deleted file mode 100644 index e9fae6fe0d7..00000000000 --- a/changelogs/unreleased/40530-merge-request-generates-wrong-diff-when-branch-and-tag-have-the-same-name.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix merge requests where the source or target branch name matches a tag name -merge_request: 15591 -author: -type: fixed diff --git a/changelogs/unreleased/40561-environment-scope-value-is-not-trimmed.yml b/changelogs/unreleased/40561-environment-scope-value-is-not-trimmed.yml deleted file mode 100644 index e0e3ddbdaa8..00000000000 --- a/changelogs/unreleased/40561-environment-scope-value-is-not-trimmed.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Strip leading & trailing whitespaces in CI/CD secret variable keys -merge_request: 15615 -author: -type: fixed diff --git a/changelogs/unreleased/40568-bump-seed-fu-to-2-3-7.yml b/changelogs/unreleased/40568-bump-seed-fu-to-2-3-7.yml deleted file mode 100644 index 708269d5c83..00000000000 --- a/changelogs/unreleased/40568-bump-seed-fu-to-2-3-7.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Upgrade seed-fu to 2.3.7 -merge_request: 15607 -author: Takuya Noguchi -type: other diff --git a/changelogs/unreleased/40573-rename-gke-as-kubernetes-engine.yml b/changelogs/unreleased/40573-rename-gke-as-kubernetes-engine.yml deleted file mode 100644 index afbb869bdbb..00000000000 --- a/changelogs/unreleased/40573-rename-gke-as-kubernetes-engine.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Rename GKE as Kubernetes Engine -merge_request: 15608 -author: Takuya Noguchi -type: other diff --git a/changelogs/unreleased/40770-doc-elasticsearch.yml b/changelogs/unreleased/40770-doc-elasticsearch.yml deleted file mode 100644 index b770fb7548e..00000000000 --- a/changelogs/unreleased/40770-doc-elasticsearch.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix typo in docs about Elasticsearch -merge_request: 15699 -author: Takuya Noguchi -type: other diff --git a/changelogs/unreleased/4080-align-retry-btn.yml b/changelogs/unreleased/4080-align-retry-btn.yml deleted file mode 100644 index c7d3997839c..00000000000 --- a/changelogs/unreleased/4080-align-retry-btn.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Align retry button with job title with new grid size -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/add_project_ci_config_path_leading_slash_validation.yml b/changelogs/unreleased/add_project_ci_config_path_leading_slash_validation.yml deleted file mode 100644 index 1c96bd66ed4..00000000000 --- a/changelogs/unreleased/add_project_ci_config_path_leading_slash_validation.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Prefer ci_config_path validation for leading slashes instead of sanitizing - the input -merge_request: 15672 -author: Christiaan Van den Poel -type: other diff --git a/changelogs/unreleased/admin-welcome-new-group-link.yml b/changelogs/unreleased/admin-welcome-new-group-link.yml deleted file mode 100644 index 9c939a0a3ad..00000000000 --- a/changelogs/unreleased/admin-welcome-new-group-link.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed admin welcome screen new group path -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/an-gitaly-timeouts.yml b/changelogs/unreleased/an-gitaly-timeouts.yml deleted file mode 100644 index e18d82b2704..00000000000 --- a/changelogs/unreleased/an-gitaly-timeouts.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add timeouts for Gitaly calls -merge_request: 15047 -author: -type: performance diff --git a/changelogs/unreleased/brand_header_change.yml b/changelogs/unreleased/brand_header_change.yml deleted file mode 100644 index 6ea6e8192a4..00000000000 --- a/changelogs/unreleased/brand_header_change.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: When a custom header logo is present, don't show GitLab type logo -merge_request: -author: -type: changed diff --git a/changelogs/unreleased/bvl-circuitbreaker-process.yml b/changelogs/unreleased/bvl-circuitbreaker-process.yml deleted file mode 100644 index 595dd13f724..00000000000 --- a/changelogs/unreleased/bvl-circuitbreaker-process.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Monitor NFS shards for circuitbreaker in a separate process -merge_request: 15426 -author: -type: changed diff --git a/changelogs/unreleased/bvl-delete-empty-fork-networks.yml b/changelogs/unreleased/bvl-delete-empty-fork-networks.yml deleted file mode 100644 index 3bbb4cf6e3c..00000000000 --- a/changelogs/unreleased/bvl-delete-empty-fork-networks.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Clean up empty fork networks -merge_request: 15373 -author: -type: other diff --git a/changelogs/unreleased/bvl-limit-fork-queries-on-project-show.yml b/changelogs/unreleased/bvl-limit-fork-queries-on-project-show.yml deleted file mode 100644 index 299d9bf6b9c..00000000000 --- a/changelogs/unreleased/bvl-limit-fork-queries-on-project-show.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Reduce requests for project forks on show page of projects that have forks -merge_request: 15663 -author: -type: performance diff --git a/changelogs/unreleased/bvl-subgroup-in-dropdowns.yml b/changelogs/unreleased/bvl-subgroup-in-dropdowns.yml deleted file mode 100644 index 1114d429dec..00000000000 --- a/changelogs/unreleased/bvl-subgroup-in-dropdowns.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Make sure a user can add projects to subgroups they have access to -merge_request: 15294 -author: -type: fixed diff --git a/changelogs/unreleased/cleanup-issues-schema.yml b/changelogs/unreleased/cleanup-issues-schema.yml deleted file mode 100644 index 9f5fb0bdf82..00000000000 --- a/changelogs/unreleased/cleanup-issues-schema.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Clean up schema of the "issues" table -merge_request: -author: -type: other diff --git a/changelogs/unreleased/commit-title-wrapping.yml b/changelogs/unreleased/commit-title-wrapping.yml deleted file mode 100644 index 65c28b82b8b..00000000000 --- a/changelogs/unreleased/commit-title-wrapping.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed long commit links not wrapping correctly -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/deploy-keys-loading-icon.yml b/changelogs/unreleased/deploy-keys-loading-icon.yml deleted file mode 100644 index e3cb5bc6924..00000000000 --- a/changelogs/unreleased/deploy-keys-loading-icon.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed deploy keys remove button loading state not resetting -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/dm-commit-diff-discussions-in-mr-context.yml b/changelogs/unreleased/dm-commit-diff-discussions-in-mr-context.yml deleted file mode 100644 index 1f8b42ea21f..00000000000 --- a/changelogs/unreleased/dm-commit-diff-discussions-in-mr-context.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Make diff notes created on a commit in a merge request to persist a rebase. -merge_request: 12148 -author: -type: added diff --git a/changelogs/unreleased/dm-image-blob-diff-full-url.yml b/changelogs/unreleased/dm-image-blob-diff-full-url.yml deleted file mode 100644 index db44a5a16b5..00000000000 --- a/changelogs/unreleased/dm-image-blob-diff-full-url.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use app host instead of asset host when rendering image blob or diff -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/dm-ldap-email-readonly.yml b/changelogs/unreleased/dm-ldap-email-readonly.yml deleted file mode 100644 index 744b21f901e..00000000000 --- a/changelogs/unreleased/dm-ldap-email-readonly.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Make sure user email is read only when synced with LDAP -merge_request: 15915 -author: -type: fixed diff --git a/changelogs/unreleased/dm-search-pattern.yml b/changelogs/unreleased/dm-search-pattern.yml deleted file mode 100644 index 1670d8c4b9a..00000000000 --- a/changelogs/unreleased/dm-search-pattern.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use fuzzy search with minimum length of 3 characters where appropriate -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/enable-scss-lint-unnecessary-mantissa.yml b/changelogs/unreleased/enable-scss-lint-unnecessary-mantissa.yml deleted file mode 100644 index 1049e94f312..00000000000 --- a/changelogs/unreleased/enable-scss-lint-unnecessary-mantissa.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Enable UnnecessaryMantissa in scss-lint -merge_request: 15255 -author: Takuya Noguchi -type: other diff --git a/changelogs/unreleased/feature-custom-text-for-new-projects.yml b/changelogs/unreleased/feature-custom-text-for-new-projects.yml deleted file mode 100644 index 905d76dab33..00000000000 --- a/changelogs/unreleased/feature-custom-text-for-new-projects.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add custom brand text on new project pages -merge_request: 15541 -author: Markus Koller -type: changed diff --git a/changelogs/unreleased/feature-disable-password-authentication.yml b/changelogs/unreleased/feature-disable-password-authentication.yml deleted file mode 100644 index 999203f12ce..00000000000 --- a/changelogs/unreleased/feature-disable-password-authentication.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Allow password authentication to be disabled entirely -merge_request: 15223 -author: Markus Koller -type: changed diff --git a/changelogs/unreleased/feature-sm-34834-missing-dependency-should-fail-job-2.yml b/changelogs/unreleased/feature-sm-34834-missing-dependency-should-fail-job-2.yml deleted file mode 100644 index ab85b8ee515..00000000000 --- a/changelogs/unreleased/feature-sm-34834-missing-dependency-should-fail-job-2.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fail jobs if its dependency is missing -merge_request: 14009 -author: -type: fixed diff --git a/changelogs/unreleased/feature_add_mermaid.yml b/changelogs/unreleased/feature_add_mermaid.yml deleted file mode 100644 index caeb5d3470d..00000000000 --- a/changelogs/unreleased/feature_add_mermaid.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'Add support of Mermaid (generation of diagrams and flowcharts from text)' -merge_request: 15107 -author: Vitaliy @blackst0ne Klachkov -type: added diff --git a/changelogs/unreleased/fix-filter-by-my-reaction.yml b/changelogs/unreleased/fix-filter-by-my-reaction.yml deleted file mode 100644 index 8bf91ddf893..00000000000 --- a/changelogs/unreleased/fix-filter-by-my-reaction.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix filter by my reaction is not working -merge_request: 15345 -author: Hiroyuki Sato -type: fixed diff --git a/changelogs/unreleased/fix-new-project-guidelines-styling.yml b/changelogs/unreleased/fix-new-project-guidelines-styling.yml deleted file mode 100644 index a97f5c485d4..00000000000 --- a/changelogs/unreleased/fix-new-project-guidelines-styling.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use Markdown styling for new project guidelines -merge_request: 15785 -author: Markus Koller -type: fixed diff --git a/changelogs/unreleased/fix-protected-branches-descriptions.yml b/changelogs/unreleased/fix-protected-branches-descriptions.yml deleted file mode 100644 index 8e233d9defd..00000000000 --- a/changelogs/unreleased/fix-protected-branches-descriptions.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Clarify wording of protected branch settings for the default branch -merge_request: -author: -type: other diff --git a/changelogs/unreleased/fix-sm-31771-do-not-allow-jobs-to-be-erased-new.yml b/changelogs/unreleased/fix-sm-31771-do-not-allow-jobs-to-be-erased-new.yml deleted file mode 100644 index 198116f34aa..00000000000 --- a/changelogs/unreleased/fix-sm-31771-do-not-allow-jobs-to-be-erased-new.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Only owner or master can erase jobs -merge_request: 15216 -author: -type: changed diff --git a/changelogs/unreleased/fix-sm-37991-avoid-deactivation-when-pipeline-schedules-execute-a-commit-includes-ci-skip.yml b/changelogs/unreleased/fix-sm-37991-avoid-deactivation-when-pipeline-schedules-execute-a-commit-includes-ci-skip.yml deleted file mode 100644 index 4e525c875ca..00000000000 --- a/changelogs/unreleased/fix-sm-37991-avoid-deactivation-when-pipeline-schedules-execute-a-commit-includes-ci-skip.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Avoid deactivation when pipeline schedules execute a branch includes `[ci skip]` - comment -merge_request: 15405 -author: -type: fixed diff --git a/changelogs/unreleased/fix-todos-last-page.yml b/changelogs/unreleased/fix-todos-last-page.yml deleted file mode 100644 index efcdbb75e6e..00000000000 --- a/changelogs/unreleased/fix-todos-last-page.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix access to the final page of todos -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/fj-40407-missing-order-paginate.yml b/changelogs/unreleased/fj-40407-missing-order-paginate.yml deleted file mode 100644 index 27471dc2c52..00000000000 --- a/changelogs/unreleased/fj-40407-missing-order-paginate.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Added default order to UsersFinder -merge_request: 15679 -author: -type: fixed diff --git a/changelogs/unreleased/fj-40752-forks-api-not-using-services.yml b/changelogs/unreleased/fj-40752-forks-api-not-using-services.yml deleted file mode 100644 index cd7b87596e6..00000000000 --- a/changelogs/unreleased/fj-40752-forks-api-not-using-services.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Using appropiate services in the API for managing forks -merge_request: 15709 -author: -type: fixed diff --git a/changelogs/unreleased/fl-upgrade-svg.yml b/changelogs/unreleased/fl-upgrade-svg.yml deleted file mode 100644 index caf73881d0f..00000000000 --- a/changelogs/unreleased/fl-upgrade-svg.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update svg external depencency -merge_request: -author: -type: other diff --git a/changelogs/unreleased/group-new-miletone-breadcrumb.yml b/changelogs/unreleased/group-new-miletone-breadcrumb.yml deleted file mode 100644 index b82c5b604e8..00000000000 --- a/changelogs/unreleased/group-new-miletone-breadcrumb.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed new group milestone breadcrumbs -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/hashed-storage-attachments-migration-path.yml b/changelogs/unreleased/hashed-storage-attachments-migration-path.yml deleted file mode 100644 index 32535437046..00000000000 --- a/changelogs/unreleased/hashed-storage-attachments-migration-path.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Hashed Storage migration script now supports migrating project attachments -merge_request: 15352 -author: -type: added diff --git a/changelogs/unreleased/improved-changes-dropdown.yml b/changelogs/unreleased/improved-changes-dropdown.yml deleted file mode 100644 index f305cbe573b..00000000000 --- a/changelogs/unreleased/improved-changes-dropdown.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Improved diff changed files dropdown design -merge_request: -author: -type: changed diff --git a/changelogs/unreleased/issue_39238.yml b/changelogs/unreleased/issue_39238.yml deleted file mode 100644 index 75a4969ca9e..00000000000 --- a/changelogs/unreleased/issue_39238.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix image diff notification email from showing wrong content -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/merge-request-lock-icon-size-fix.yml b/changelogs/unreleased/merge-request-lock-icon-size-fix.yml deleted file mode 100644 index 09c059a3011..00000000000 --- a/changelogs/unreleased/merge-request-lock-icon-size-fix.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed merge request lock icon size -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/merge-requests-schema-cleanup.yml b/changelogs/unreleased/merge-requests-schema-cleanup.yml deleted file mode 100644 index ccce9b1436c..00000000000 --- a/changelogs/unreleased/merge-requests-schema-cleanup.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Clean up schema of the "merge_requests" table -merge_request: -author: -type: other diff --git a/changelogs/unreleased/mk-add-old-attachments-to-uploads-table.yml b/changelogs/unreleased/mk-add-old-attachments-to-uploads-table.yml deleted file mode 100644 index 499543ef883..00000000000 --- a/changelogs/unreleased/mk-add-old-attachments-to-uploads-table.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add untracked files to uploads table -merge_request: 15270 -author: -type: other diff --git a/changelogs/unreleased/mk-add-user-rate-limits.yml b/changelogs/unreleased/mk-add-user-rate-limits.yml deleted file mode 100644 index 512757da5fc..00000000000 --- a/changelogs/unreleased/mk-add-user-rate-limits.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Add anonymous rate limit per IP, and authenticated (web or API) rate limits - per user -merge_request: 14708 -author: -type: added diff --git a/changelogs/unreleased/mk-fix-schema-dump-of-untracked-files-for-uploads.yml b/changelogs/unreleased/mk-fix-schema-dump-of-untracked-files-for-uploads.yml deleted file mode 100644 index 2691e85320c..00000000000 --- a/changelogs/unreleased/mk-fix-schema-dump-of-untracked-files-for-uploads.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix error during schema dump. -merge_request: 15866 -author: -type: fixed diff --git a/changelogs/unreleased/optimize-projects-for-imported-projects.yml b/changelogs/unreleased/optimize-projects-for-imported-projects.yml deleted file mode 100644 index 13186fa36d5..00000000000 --- a/changelogs/unreleased/optimize-projects-for-imported-projects.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: check the import_status field before doing SQL operations to check the import - url -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/osw-isolate-mr-widget-exposed-attributes.yml b/changelogs/unreleased/osw-isolate-mr-widget-exposed-attributes.yml deleted file mode 100644 index 6b05713d1a1..00000000000 --- a/changelogs/unreleased/osw-isolate-mr-widget-exposed-attributes.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Stop sending milestone and labels data over the wire for MR widget requests -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/outdated-browser-position-fix.yml b/changelogs/unreleased/outdated-browser-position-fix.yml deleted file mode 100644 index 801e45a28b3..00000000000 --- a/changelogs/unreleased/outdated-browser-position-fix.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fixed outdated browser flash positioning -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/patch-24.yml b/changelogs/unreleased/patch-24.yml deleted file mode 100644 index a670eb3ab56..00000000000 --- a/changelogs/unreleased/patch-24.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix graph notes number duplication. -merge_request: 15696 -author: Vladislav Kaverin -type: fixed diff --git a/changelogs/unreleased/pawel-update_prometheus_gem_to_well_tested_version.yml b/changelogs/unreleased/pawel-update_prometheus_gem_to_well_tested_version.yml deleted file mode 100644 index a4133ae5cec..00000000000 --- a/changelogs/unreleased/pawel-update_prometheus_gem_to_well_tested_version.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Reenable Prometheus metrics, add more control over Prometheus method instrumentation -merge_request: 15558 -author: -type: fixed diff --git a/changelogs/unreleased/perform-sql-matching-of-tags.yml b/changelogs/unreleased/perform-sql-matching-of-tags.yml deleted file mode 100644 index 39f8a867a4d..00000000000 --- a/changelogs/unreleased/perform-sql-matching-of-tags.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Perform SQL matching of Build&Runner tags to greatly speed-up job picking -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/sh-remove-allocation-tracking-influxdb.yml b/changelogs/unreleased/sh-remove-allocation-tracking-influxdb.yml deleted file mode 100644 index b98573df303..00000000000 --- a/changelogs/unreleased/sh-remove-allocation-tracking-influxdb.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove allocation tracking code from InfluxDB sampler for performance -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/skip_confirmation_user_API.yml b/changelogs/unreleased/skip_confirmation_user_API.yml deleted file mode 100644 index 144ccd69e68..00000000000 --- a/changelogs/unreleased/skip_confirmation_user_API.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Add email confirmation parameters for user creation and update via API -merge_request: -author: Daniel Juarez -type: added - - diff --git a/changelogs/unreleased/text-utils.yml b/changelogs/unreleased/text-utils.yml deleted file mode 100644 index b95bb82fe01..00000000000 --- a/changelogs/unreleased/text-utils.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Export text utils functions as es6 module and add tests -merge_request: -author: -type: other diff --git a/changelogs/unreleased/throttle-touching-of-objects.yml b/changelogs/unreleased/throttle-touching-of-objects.yml deleted file mode 100644 index 0a57bea7c83..00000000000 --- a/changelogs/unreleased/throttle-touching-of-objects.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Throttle the number of UPDATEs triggered by touch -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/tm-feature-list-runners-jobs-api.yml b/changelogs/unreleased/tm-feature-list-runners-jobs-api.yml deleted file mode 100644 index d75a2b68c30..00000000000 --- a/changelogs/unreleased/tm-feature-list-runners-jobs-api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: New API endpoint - list jobs for a specified runner -merge_request: 15432 -author: -type: added diff --git a/changelogs/unreleased/tm-feature-namespace-by-id-api.yml b/changelogs/unreleased/tm-feature-namespace-by-id-api.yml deleted file mode 100644 index bc4a8949d28..00000000000 --- a/changelogs/unreleased/tm-feature-namespace-by-id-api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add new API endpoint - get a namespace by ID -merge_request: 15442 -author: -type: added diff --git a/changelogs/unreleased/update-emoji-digests-with-latest-from-gemojione.yml b/changelogs/unreleased/update-emoji-digests-with-latest-from-gemojione.yml deleted file mode 100644 index e509a8df6bc..00000000000 --- a/changelogs/unreleased/update-emoji-digests-with-latest-from-gemojione.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: 'Update emojis. Add :gay_pride_flag: and :speech_left:. Remove extraneous comma - in :cartwheel_tone4:' -merge_request: -author: -type: changed diff --git a/changelogs/unreleased/update-merge-worker-metrics.yml b/changelogs/unreleased/update-merge-worker-metrics.yml deleted file mode 100644 index c733675926a..00000000000 --- a/changelogs/unreleased/update-merge-worker-metrics.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add performance logging to UpdateMergeRequestsWorker. -merge_request: 15360 -author: -type: performance diff --git a/changelogs/unreleased/update_mr_changes_empty_page.yml b/changelogs/unreleased/update_mr_changes_empty_page.yml deleted file mode 100644 index bae73c21e8f..00000000000 --- a/changelogs/unreleased/update_mr_changes_empty_page.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Update empty state page of merge request 'changes' tab -merge_request: 15611 -author: Vitaliy @blackst0ne Klachkov -type: added diff --git a/changelogs/unreleased/use-count_commits-directly.yml b/changelogs/unreleased/use-count_commits-directly.yml deleted file mode 100644 index 549e0744ea4..00000000000 --- a/changelogs/unreleased/use-count_commits-directly.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Improve the performance for counting commits -merge_request: 15628 -author: -type: performance diff --git a/changelogs/unreleased/use-merge-requests-diff-id-column.yml b/changelogs/unreleased/use-merge-requests-diff-id-column.yml deleted file mode 100644 index da4106ec8cf..00000000000 --- a/changelogs/unreleased/use-merge-requests-diff-id-column.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Make finding most recent merge request diffs more efficient -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/user-agent-gke-api.yml b/changelogs/unreleased/user-agent-gke-api.yml deleted file mode 100644 index 1abdbadd53b..00000000000 --- a/changelogs/unreleased/user-agent-gke-api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Use custom user agent header in all GCP API requests. -merge_request: 15705 -author: -type: changed diff --git a/changelogs/unreleased/winh-subgroups-api.yml b/changelogs/unreleased/winh-subgroups-api.yml deleted file mode 100644 index c49e3621e9c..00000000000 --- a/changelogs/unreleased/winh-subgroups-api.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Add /groups/:id/subgroups endpoint to API -merge_request: 15142 -author: marbemac -type: added diff --git a/changelogs/unreleased/zj-commit-show-n-1.yml b/changelogs/unreleased/zj-commit-show-n-1.yml deleted file mode 100644 index e536434f74a..00000000000 --- a/changelogs/unreleased/zj-commit-show-n-1.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fetch blobs in bulk when generating diffs -merge_request: -author: -type: performance diff --git a/changelogs/unreleased/zj-empty-repo-importer.yml b/changelogs/unreleased/zj-empty-repo-importer.yml deleted file mode 100644 index 71d50af9a04..00000000000 --- a/changelogs/unreleased/zj-empty-repo-importer.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix GitHub importer using removed interface -merge_request: -author: -type: fixed diff --git a/changelogs/unreleased/zj-memoization-mr-commits.yml b/changelogs/unreleased/zj-memoization-mr-commits.yml deleted file mode 100644 index 59dfc6d6049..00000000000 --- a/changelogs/unreleased/zj-memoization-mr-commits.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Cache commits for MergeRequest diffs -merge_request: -author: -type: performance -- cgit v1.2.1 From ee12ce8516b316944fac618c5cb92d367208cb0c Mon Sep 17 00:00:00 2001 From: Tiago Botelho Date: Fri, 22 Dec 2017 09:51:40 +0000 Subject: Update VERSION to 10.4.0-pre --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 73cdb768a24..80959b81ba4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -10.3.0-pre +10.4.0-pre -- cgit v1.2.1 From 46464e5fa3ff85b8240e17cb71f20fad8b70d01f Mon Sep 17 00:00:00 2001 From: Winnie Hellmann Date: Fri, 22 Dec 2017 11:10:22 +0000 Subject: Make webpack fail for missing exports --- config/webpack.config.js | 1 + spec/javascripts/monitoring/mock_data.js | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/config/webpack.config.js b/config/webpack.config.js index 1218b0ef208..5f95255334c 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -141,6 +141,7 @@ var config = { ], noParse: [/monaco-editor\/\w+\/vs\//], + strictExportPresence: true, }, plugins: [ diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js index 1f4e858e731..2bbe963e393 100644 --- a/spec/javascripts/monitoring/mock_data.js +++ b/spec/javascripts/monitoring/mock_data.js @@ -1,6 +1,8 @@ /* eslint-disable quote-props, indent, comma-dangle */ -const metricsGroupsAPIResponse = { +export const mockApiEndpoint = `${gl.TEST_HOST}/monitoring/mock`; + +export const metricsGroupsAPIResponse = { 'success': true, 'data': [ { -- cgit v1.2.1 From 85403771042c4a368dae48a87f6518454069b76f Mon Sep 17 00:00:00 2001 From: Fabio Busatto Date: Fri, 22 Dec 2017 11:29:43 +0000 Subject: Clarify Auto DevOps pipelines --- doc/topics/autodevops/img/auto_devops_settings.png | Bin 95233 -> 0 bytes doc/topics/autodevops/index.md | 23 +++++++-------------- 2 files changed, 8 insertions(+), 15 deletions(-) delete mode 100644 doc/topics/autodevops/img/auto_devops_settings.png diff --git a/doc/topics/autodevops/img/auto_devops_settings.png b/doc/topics/autodevops/img/auto_devops_settings.png deleted file mode 100644 index 067c9da3fdc..00000000000 Binary files a/doc/topics/autodevops/img/auto_devops_settings.png and /dev/null differ diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md index 0b48596006d..339bc2bd4fe 100644 --- a/doc/topics/autodevops/index.md +++ b/doc/topics/autodevops/index.md @@ -122,11 +122,13 @@ Google Cloud. ## Enabling Auto DevOps -**Note:** If you haven't done already, read the [prerequisites](#prerequisites) to make full use of Auto DevOps. If this is your fist time, we recommend you follow the [quick start guide](#quick-start). +To enable Auto DevOps to your project: + +1. Check that your project doesn't have a `.gitlab-ci.yml`, and remove it otherwise 1. Go to your project's **Settings > CI/CD > General pipelines settings** and find the Auto DevOps section 1. Select "Enable Auto DevOps" @@ -134,22 +136,13 @@ full use of Auto DevOps. If this is your fist time, we recommend you follow the that will be used by Kubernetes to deploy your application 1. Hit **Save changes** for the changes to take effect -![Project AutoDevops settings section](img/auto_devops_settings.png) - -Now that it's enabled, there are a few more steps depending on whether your project -has a `.gitlab-ci.yml` or not: - -- **For projects with no `.gitlab-ci.yml` present:** - A pipeline needs to be triggered either by pushing a new commit to the - repository or manually visiting `https://example.gitlab.com///pipelines/new` - and creating a new pipeline for your default branch, generally `master`. -- **For projects with a `.gitlab-ci.yml` present:** - All you need to do is remove your existing `.gitlab-ci.yml`, and you can even - do that in a branch to test Auto DevOps before committing to `master`. +Once saved, an Auto DevOps pipeline will be triggered on the default branch. NOTE: **Note:** -Starting with GitLab 10.3, when enabling Auto DevOps, a pipeline is -automatically run on the default branch. +For GitLab versions 10.0 - 10.2, when enabling Auto DevOps, a pipeline needs to be +manually triggered either by pushing a new commit to the repository or by visiting +`https://example.gitlab.com///pipelines/new` and creating +a new pipeline for your default branch, generally `master`. NOTE: **Note:** If you are a GitLab Administrator, you can enable Auto DevOps instance wide -- cgit v1.2.1 From 1e72dd106b20ab8eda4142fadafe9727dfa814f1 Mon Sep 17 00:00:00 2001 From: Mark Fletcher Date: Wed, 20 Dec 2017 17:35:58 +0000 Subject: Support new chat notifications parameters in Services API + Add support for the new separate channel and events settings * Dry up chat notifications in the service properties definitions --- ...ating-slack-notification-not-working-by-api.yml | 5 + doc/api/services.md | 62 ++++++- lib/api/entities.rb | 5 +- lib/api/services.rb | 180 +++++++++++++++++---- 4 files changed, 210 insertions(+), 42 deletions(-) create mode 100644 changelogs/unreleased/32364-updating-slack-notification-not-working-by-api.yml diff --git a/changelogs/unreleased/32364-updating-slack-notification-not-working-by-api.yml b/changelogs/unreleased/32364-updating-slack-notification-not-working-by-api.yml new file mode 100644 index 00000000000..e3fae55c6f0 --- /dev/null +++ b/changelogs/unreleased/32364-updating-slack-notification-not-working-by-api.yml @@ -0,0 +1,5 @@ +--- +title: Support new chat notifications parameters in Services API +merge_request: 11435 +author: +type: added diff --git a/doc/api/services.md b/doc/api/services.md index 08df26db3ec..76b12cdb2da 100644 --- a/doc/api/services.md +++ b/doc/api/services.md @@ -803,11 +803,33 @@ Set Slack service for a project. PUT /projects/:id/services/slack ``` -Parameters: +>**Note:** Specific event parameters (e.g. `push_events` flag and `push_channel`) were [introduced in v10.4][11435] + +#### Parameters -- `webhook` (**required**) - https://hooks.slack.com/services/... -- `username` (optional) - username -- `channel` (optional) - #channel +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `webhook` | string | true | https://hooks.slack.com/services/... | +| `username` | string | false | username | +| `channel` | string | false | Default channel to use if others are not configured | +| `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines | +| `notify_only_default_branch` | boolean | false | Send notifications only for the default branch | +| `push_events` | boolean | false | Enable notifications for push events | +| `issues_events` | boolean | false | Enable notifications for issue events | +| `confidential_issues_events` | boolean | false | Enable notifications for confidential issue events | +| `merge_requests_events` | boolean | false | Enable notifications for merge request events | +| `tag_push_events` | boolean | false | Enable notifications for tag push events | +| `note_events` | boolean | false | Enable notifications for note events | +| `pipeline_events` | boolean | false | Enable notifications for pipeline events | +| `wiki_page_events` | boolean | false | Enable notifications for wiki page events | +| `push_channel` | string | false | The name of the channel to receive push events notifications | +| `issue_channel` | string | false | The name of the channel to receive issues events notifications | +| `confidential_issue_channel` | string | false | The name of the channel to receive confidential issues events notifications | +| `merge_request_channel` | string | false | The name of the channel to receive merge request events notifications | +| `note_channel` | string | false | The name of the channel to receive note events notifications | +| `tag_push_channel` | string | false | The name of the channel to receive tag push events notifications | +| `pipeline_channel` | string | false | The name of the channel to receive pipeline events notifications | +| `wiki_page_channel` | string | false | The name of the channel to receive wiki page events notifications | ### Delete Slack service @@ -837,11 +859,33 @@ Set Mattermost service for a project. PUT /projects/:id/services/mattermost ``` -Parameters: +>**Note:** Specific event parameters (e.g. `push_events` flag and `push_channel`) were [introduced in v10.4][11435] -- `webhook` (**required**) - https://mattermost.example/hooks/1298aff... -- `username` (optional) - username -- `channel` (optional) - #channel +#### Parameters + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `webhook` | string | true | The Mattermost webhook. e.g. http://mattermost_host/hooks/... | +| `username` | string | false | username | +| `channel` | string | false | Default channel to use if others are not configured | +| `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines | +| `notify_only_default_branch` | boolean | false | Send notifications only for the default branch | +| `push_events` | boolean | false | Enable notifications for push events | +| `issues_events` | boolean | false | Enable notifications for issue events | +| `confidential_issues_events` | boolean | false | Enable notifications for confidential issue events | +| `merge_requests_events` | boolean | false | Enable notifications for merge request events | +| `tag_push_events` | boolean | false | Enable notifications for tag push events | +| `note_events` | boolean | false | Enable notifications for note events | +| `pipeline_events` | boolean | false | Enable notifications for pipeline events | +| `wiki_page_events` | boolean | false | Enable notifications for wiki page events | +| `push_channel` | string | false | The name of the channel to receive push events notifications | +| `issue_channel` | string | false | The name of the channel to receive issues events notifications | +| `confidential_issue_channel` | string | false | The name of the channel to receive confidential issues events notifications | +| `merge_request_channel` | string | false | The name of the channel to receive merge request events notifications | +| `note_channel` | string | false | The name of the channel to receive note events notifications | +| `tag_push_channel` | string | false | The name of the channel to receive tag push events notifications | +| `pipeline_channel` | string | false | The name of the channel to receive pipeline events notifications | +| `wiki_page_channel` | string | false | The name of the channel to receive wiki page events notifications | ### Delete Mattermost notifications service @@ -933,3 +977,5 @@ Get MockCI service settings for a project. ``` GET /projects/:id/services/mock-ci ``` + +[11435]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11435 diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 928706dfda7..4ad4a1f7867 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -708,8 +708,9 @@ module API class ProjectService < Grape::Entity expose :id, :title, :created_at, :updated_at, :active - expose :push_events, :issues_events, :merge_requests_events - expose :tag_push_events, :note_events, :pipeline_events + expose :push_events, :issues_events, :confidential_issues_events + expose :merge_requests_events, :tag_push_events, :note_events + expose :pipeline_events, :wiki_page_events expose :job_events # Expose serialized properties expose :properties do |service, options| diff --git a/lib/api/services.rb b/lib/api/services.rb index bbcc851d07a..a7f44e2869c 100644 --- a/lib/api/services.rb +++ b/lib/api/services.rb @@ -1,5 +1,143 @@ module API class Services < Grape::API + chat_notification_settings = [ + { + required: true, + name: :webhook, + type: String, + desc: 'The chat webhook' + }, + { + required: false, + name: :username, + type: String, + desc: 'The chat username' + }, + { + required: false, + name: :channel, + type: String, + desc: 'The default chat channel' + } + ] + + chat_notification_flags = [ + { + required: false, + name: :notify_only_broken_pipelines, + type: Boolean, + desc: 'Send notifications for broken pipelines' + }, + { + required: false, + name: :notify_only_default_branch, + type: Boolean, + desc: 'Send notifications only for the default branch' + } + ] + + chat_notification_channels = [ + { + required: false, + name: :push_channel, + type: String, + desc: 'The name of the channel to receive push_events notifications' + }, + { + required: false, + name: :issue_channel, + type: String, + desc: 'The name of the channel to receive issues_events notifications' + }, + { + required: false, + name: :confidential_issue_channel, + type: String, + desc: 'The name of the channel to receive confidential_issues_events notifications' + }, + { + required: false, + name: :merge_request_channel, + type: String, + desc: 'The name of the channel to receive merge_requests_events notifications' + }, + { + required: false, + name: :note_channel, + type: String, + desc: 'The name of the channel to receive note_events notifications' + }, + { + required: false, + name: :tag_push_channel, + type: String, + desc: 'The name of the channel to receive tag_push_events notifications' + }, + { + required: false, + name: :pipeline_channel, + type: String, + desc: 'The name of the channel to receive pipeline_events notifications' + }, + { + required: false, + name: :wiki_page_channel, + type: String, + desc: 'The name of the channel to receive wiki_page_events notifications' + } + ] + + chat_notification_events = [ + { + required: false, + name: :push_events, + type: Boolean, + desc: 'Enable notifications for push_events' + }, + { + required: false, + name: :issues_events, + type: Boolean, + desc: 'Enable notifications for issues_events' + }, + { + required: false, + name: :confidential_issues_events, + type: Boolean, + desc: 'Enable notifications for confidential_issues_events' + }, + { + required: false, + name: :merge_requests_events, + type: Boolean, + desc: 'Enable notifications for merge_requests_events' + }, + { + required: false, + name: :note_events, + type: Boolean, + desc: 'Enable notifications for note_events' + }, + { + required: false, + name: :tag_push_events, + type: Boolean, + desc: 'Enable notifications for tag_push_events' + }, + { + required: false, + name: :pipeline_events, + type: Boolean, + desc: 'Enable notifications for pipeline_events' + }, + { + required: false, + name: :wiki_page_events, + type: Boolean, + desc: 'Enable notifications for wiki_page_events' + } + ] + services = { 'asana' => [ { @@ -489,25 +627,11 @@ module API } ], 'slack' => [ - { - required: true, - name: :webhook, - type: String, - desc: 'The Slack webhook. e.g. https://hooks.slack.com/services/...' - }, - { - required: false, - name: :new_issue_url, - type: String, - desc: 'The user name' - }, - { - required: false, - name: :channel, - type: String, - desc: 'The channel name' - } - ], + chat_notification_settings, + chat_notification_flags, + chat_notification_channels, + chat_notification_events + ].flatten, 'microsoft-teams' => [ { required: true, @@ -517,19 +641,11 @@ module API } ], 'mattermost' => [ - { - required: true, - name: :webhook, - type: String, - desc: 'The Mattermost webhook. e.g. http://mattermost_host/hooks/...' - }, - { - required: false, - name: :username, - type: String, - desc: 'The username to use to post the message' - } - ], + chat_notification_settings, + chat_notification_flags, + chat_notification_channels, + chat_notification_events + ].flatten, 'teamcity' => [ { required: true, -- cgit v1.2.1 From 0d7f9762a71c0f4118ea284b6843f7d79b20000b Mon Sep 17 00:00:00 2001 From: Mark Fletcher Date: Wed, 20 Dec 2017 17:35:58 +0000 Subject: Update parameter formatting across Service API docs --- doc/api/services.md | 164 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 102 insertions(+), 62 deletions(-) diff --git a/doc/api/services.md b/doc/api/services.md index 76b12cdb2da..7adfabb4b30 100644 --- a/doc/api/services.md +++ b/doc/api/services.md @@ -1,5 +1,7 @@ # Services API +>**Note:** This API requires an access token with Master or Owner permissions + ## Asana Asana - Teamwork without email @@ -16,8 +18,10 @@ PUT /projects/:id/services/asana Parameters: -- `api_key` (**required**) - User API token. User must have access to task, all comments will be attributed to this user. -- `restrict_to_branch` (optional) - Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches. +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `api_key` | string | true | User API token. User must have access to task, all comments will be attributed to this user. | +| `restrict_to_branch` | string | false | Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches. | ### Delete Asana service @@ -49,8 +53,10 @@ PUT /projects/:id/services/assembla Parameters: -- `token` (**required**) -- `subdomain` (optional) +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `token` | string | true | The authentication token +| `subdomain` | string | false | The subdomain setting | ### Delete Assembla service @@ -84,10 +90,12 @@ PUT /projects/:id/services/bamboo Parameters: -- `bamboo_url` (**required**) - Bamboo root URL like https://bamboo.example.com -- `build_key` (**required**) - Bamboo build plan key like KEY -- `username` (**required**) - A user with API access, if applicable -- `password` (**required**) +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `bamboo_url` | string | true | Bamboo root URL like https://bamboo.example.com | +| `build_key` | string | true | Bamboo build plan key like KEY | +| `username` | string | true | A user with API access, if applicable | +| `password` | string | true | Password of the user | ### Delete Atlassian Bamboo CI service @@ -119,9 +127,11 @@ PUT /projects/:id/services/buildkite Parameters: -- `token` (**required**) - Buildkite project GitLab token -- `project_url` (**required**) - https://buildkite.com/example/project -- `enable_ssl_verification` (optional) - Enable SSL verification +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `token` | string | true | Buildkite project GitLab token | +| `project_url` | string | true | https://buildkite.com/example/project | +| `enable_ssl_verification` | boolean | false | Enable SSL verification | ### Delete Buildkite service @@ -153,9 +163,11 @@ PUT /projects/:id/services/campfire Parameters: -- `token` (**required**) -- `subdomain` (optional) -- `room` (optional) +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `token` | string | true | Campfire token | +| `subdomain` | string | false | Campfire subdomain | +| `room` | string | false | Campfire room | ### Delete Campfire service @@ -187,11 +199,13 @@ PUT /projects/:id/services/custom-issue-tracker Parameters: -- `new_issue_url` (**required**) - New Issue url -- `issues_url` (**required**) - Issue url -- `project_url` (**required**) - Project url -- `description` (optional) - Custom issue tracker -- `title` (optional) - Custom Issue Tracker +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `new_issue_url` | string | true | New Issue url +| `issues_url` | string | true | Issue url +| `project_url` | string | true | Project url +| `description` | string | false | Description +| `title` | string | false | Title ### Delete Custom Issue Tracker service @@ -223,9 +237,11 @@ PUT /projects/:id/services/drone-ci Parameters: -- `token` (**required**) - Drone CI project specific token -- `drone_url` (**required**) - http://drone.example.com -- `enable_ssl_verification` (optional) - Enable SSL verification +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `token` | string | true | Drone CI project specific token | +| `drone_url` | string | true | http://drone.example.com | +| `enable_ssl_verification` | boolean | false | Enable SSL verification | ### Delete Drone CI service @@ -257,9 +273,11 @@ PUT /projects/:id/services/emails-on-push Parameters: -- `recipients` (**required**) - Emails separated by whitespace -- `disable_diffs` (optional) - Disable code diffs -- `send_from_committer_email` (optional) - Send from committer +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `recipients` | string | true | Emails separated by whitespace | +| `disable_diffs` | boolean | false | Disable code diffs | +| `send_from_committer_email` | boolean | false | Send from committer | ### Delete Emails on push service @@ -291,7 +309,9 @@ PUT /projects/:id/services/external-wiki Parameters: -- `external_wiki_url` (**required**) - The URL of the external Wiki +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `external_wiki_url` | string | true | The URL of the external Wiki | ### Delete External Wiki service @@ -323,7 +343,9 @@ PUT /projects/:id/services/flowdock Parameters: -- `token` (**required**) - Flowdock Git source token +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `token` | string | true | Flowdock Git source token | ### Delete Flowdock service @@ -355,8 +377,10 @@ PUT /projects/:id/services/gemnasium Parameters: -- `api_key` (**required**) - Your personal API KEY on gemnasium.com -- `token` (**required**) - The project's slug on gemnasium.com +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `api_key` | string | true | Your personal API KEY on gemnasium.com | +| `token` | string | true | The project's slug on gemnasium.com | ### Delete Gemnasium service @@ -388,12 +412,14 @@ PUT /projects/:id/services/hipchat Parameters: -- `token` (**required**) - Room token -- `color` (optional) -- `notify` (optional) -- `room` (optional) - Room name or ID -- `api_version` (optional) - Leave blank for default (v2) -- `server` (optional) - Leave blank for default. https://hipchat.example.com +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `token` | string | true | Room token | +| `color` | string | false | The room color | +| `notify` | boolean | false | Enable notifications | +| `room` | string | false |Room name or ID | +| `api_version` | string | false | Leave blank for default (v2) | +| `server` | string | false | Leave blank for default. https://hipchat.example.com | ### Delete HipChat service @@ -427,11 +453,13 @@ PUT /projects/:id/services/irker Parameters: -- `recipients` (**required**) - Recipients/channels separated by whitespaces -- `default_irc_uri` (optional) - irc://irc.network.net:6697/ -- `server_port` (optional) - 6659 -- `server_host` (optional) - localhost -- `colorize_messages` (optional) +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `recipients` | string | true | Recipients/channels separated by whitespaces | +| `default_irc_uri` | string | false | irc://irc.network.net:6697/ | +| `server_host` | string | false | localhost | +| `server_port` | integer | false | 6659 | +| `colorize_messages` | boolean | false | Colorize messages | ### Delete Irker (IRC gateway) service @@ -474,7 +502,9 @@ Set JIRA service for a project. PUT /projects/:id/services/jira ``` -| Attribute | Type | Required | Description | +Parameters: + +| Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `url` | string | yes | The URL to the JIRA project which is being linked to this GitLab project, e.g., `https://jira.example.com`. | | `project_key` | string | yes | The short identifier for your JIRA project, all uppercase, e.g., `PROJ`. | @@ -569,7 +599,7 @@ PUT /projects/:id/services/slack-slash-commands Parameters: -| Attribute | Type | Required | Description | +| Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `token` | string | yes | The Slack token | @@ -604,7 +634,7 @@ PUT /projects/:id/services/mattermost-slash-commands Parameters: -| Attribute | Type | Required | Description | +| Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `token` | string | yes | The Mattermost token | | `username` | string | no | The username to use to post the message | @@ -665,7 +695,7 @@ PUT /projects/:id/services/pipelines-email Parameters: -| Attribute | Type | Required | Description | +| Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `recipients` | string | yes | Comma-separated list of recipient email addresses | | `add_pusher` | boolean | no | Add pusher to recipients list | @@ -701,8 +731,10 @@ PUT /projects/:id/services/pivotaltracker Parameters: -- `token` (**required**) -- `restrict_to_branch` (optional) - Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches. +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `token` | string | true | The PivotalTracker token | +| `restrict_to_branch` | boolean | false | Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches. | ### Delete PivotalTracker service @@ -734,11 +766,13 @@ PUT /projects/:id/services/pushover Parameters: -- `api_key` (**required**) - Your application key -- `user_key` (**required**) - Your user key -- `priority` (**required**) -- `device` (optional) - Leave blank for all active devices -- `sound` (optional) +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `api_key` | string | true | Your application key | +| `user_key` | string | true | Your user key | +| `priority` | string | true | The priority | +| `device` | string | false | Leave blank for all active devices | +| `sound` | string | false | The sound of the notification | ### Delete Pushover service @@ -770,10 +804,12 @@ PUT /projects/:id/services/redmine Parameters: -- `new_issue_url` (**required**) - New Issue url -- `project_url` (**required**) - Project url -- `issues_url` (**required**) - Issue url -- `description` (optional) - Redmine issue tracker +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `new_issue_url` | string | true | New Issue url | +| `project_url` | string | true | Project url | +| `issues_url` | string | true | Issue url | +| `description` | string | false | Description | ### Delete Redmine service @@ -805,7 +841,7 @@ PUT /projects/:id/services/slack >**Note:** Specific event parameters (e.g. `push_events` flag and `push_channel`) were [introduced in v10.4][11435] -#### Parameters +Parameters: | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | @@ -861,7 +897,7 @@ PUT /projects/:id/services/mattermost >**Note:** Specific event parameters (e.g. `push_events` flag and `push_channel`) were [introduced in v10.4][11435] -#### Parameters +Parameters: | Parameter | Type | Required | Description | | --------- | ---- | -------- | ----------- | @@ -919,10 +955,12 @@ PUT /projects/:id/services/teamcity Parameters: -- `teamcity_url` (**required**) - TeamCity root URL like https://teamcity.example.com -- `build_type` (**required**) - Build configuration ID -- `username` (**required**) - A user with permissions to trigger a manual build -- `password` (**required**) +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `teamcity_url` | string | true | TeamCity root URL like https://teamcity.example.com | +| `build_type` | string | true | Build configuration ID | +| `username` | string | true | A user with permissions to trigger a manual build | +| `password` | string | true | The password of the user | ### Delete JetBrains TeamCity CI service @@ -960,7 +998,9 @@ PUT /projects/:id/services/mock-ci Parameters: -- `mock_service_url` (**required**) - http://localhost:4004 +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `mock_service_url` | string | true | http://localhost:4004 | ### Delete MockCI service -- cgit v1.2.1 From b1941789f5c9ce0d03d69564aba19f382d43d92f Mon Sep 17 00:00:00 2001 From: Mark Fletcher Date: Wed, 20 Dec 2017 17:35:58 +0000 Subject: Add Bugzilla Service API docs --- doc/api/services.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/doc/api/services.md b/doc/api/services.md index 7adfabb4b30..378fd223ad2 100644 --- a/doc/api/services.md +++ b/doc/api/services.md @@ -113,6 +113,44 @@ Get Atlassian Bamboo CI service settings for a project. GET /projects/:id/services/bamboo ``` +## Bugzilla + +Bugzilla Issue Tracker + +### Create/Edit Buildkite service + +Set Bugzilla service for a project. + +``` +PUT /projects/:id/services/bugzilla +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `new_issue_url` | string | true | New Issue url | +| `issues_url` | string | true | Issue url | +| `project_url` | string | true | Project url | +| `description` | string | false | Description | +| `title` | string | false | Title | + +### Delete Bugzilla Service + +Delete Bugzilla service for a project. + +``` +DELETE /projects/:id/services/bugzilla +``` + +### Get Bugzilla Service Settings + +Get Bugzilla service settings for a project. + +``` +GET /projects/:id/services/bugzilla +``` + ## Buildkite Continuous integration and deployments -- cgit v1.2.1 From 00ae3ef6ae8b4813a4ff3a300aaab8528cfa1bc9 Mon Sep 17 00:00:00 2001 From: Mark Fletcher Date: Wed, 20 Dec 2017 17:35:58 +0000 Subject: Add Prometheus Service API docs --- doc/api/services.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/doc/api/services.md b/doc/api/services.md index 378fd223ad2..8e79cd529fb 100644 --- a/doc/api/services.md +++ b/doc/api/services.md @@ -790,6 +790,40 @@ Get PivotalTracker service settings for a project. GET /projects/:id/services/pivotaltracker ``` +## Prometheus + +Prometheus is a powerful time-series monitoring service. + +### Create/Edit Prometheus service + +Set Prometheus service for a project. + +``` +PUT /projects/:id/services/prometheus +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `api_url` | string | true | Prometheus API Base URL, like http://prometheus.example.com/ | + +### Delete Prometheus service + +Delete Prometheus service for a project. + +``` +DELETE /projects/:id/services/prometheus +``` + +### Get Prometheus service settings + +Get Prometheus service settings for a project. + +``` +GET /projects/:id/services/prometheus +``` + ## Pushover Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop. -- cgit v1.2.1 From e84fd5cc636ee38b6ef51416849fb7fd48e65576 Mon Sep 17 00:00:00 2001 From: Mark Fletcher Date: Wed, 20 Dec 2017 17:35:58 +0000 Subject: Add Microsoft Teams Service API docs --- doc/api/services.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/doc/api/services.md b/doc/api/services.md index 8e79cd529fb..7e2afc71f9a 100644 --- a/doc/api/services.md +++ b/doc/api/services.md @@ -955,6 +955,40 @@ Get Slack service settings for a project. GET /projects/:id/services/slack ``` +## Microsoft Teams + +Group Chat Software + +### Create/Edit Microsoft Teams service + +Set Microsoft Teams service for a project. + +``` +PUT /projects/:id/services/microsoft_teams +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `webhook` | string | true | The Microsoft Teams webhook. e.g. https://outlook.office.com/webhook/... | + +### Delete Microsoft Teams service + +Delete Microsoft Teams service for a project. + +``` +DELETE /projects/:id/services/microsoft_teams +``` + +### Get Microsoft Teams service settings + +Get Microsoft Teams service settings for a project. + +``` +GET /projects/:id/services/microsoft_teams +``` + ## Mattermost notifications Receive event notifications in Mattermost -- cgit v1.2.1 From 3f9b3d53f6c9e109f2ce0306a22ddb30ae9ed8f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 22 Dec 2017 14:36:06 +0100 Subject: Add url to link in new GCP cluster header partial --- app/views/projects/clusters/gcp/_header.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/clusters/gcp/_header.html.haml b/app/views/projects/clusters/gcp/_header.html.haml index f23d5b80e4f..e2d7326a312 100644 --- a/app/views/projects/clusters/gcp/_header.html.haml +++ b/app/views/projects/clusters/gcp/_header.html.haml @@ -10,5 +10,5 @@ - link_to_requirements = link_to(s_('ClusterIntegration|meets the requirements'), 'https://cloud.google.com/kubernetes-engine/docs/quickstart', target: '_blank', rel: 'noopener noreferrer') = s_('ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters').html_safe % { link_to_requirements: link_to_requirements } %li - - link_to_container_project = link_to(s_('ClusterIntegration|Google Kubernetes Engine project'), target: '_blank', rel: 'noopener noreferrer') + - link_to_container_project = link_to(s_('ClusterIntegration|Google Kubernetes Engine project'), 'https://console.cloud.google.com/home/dashboard', target: '_blank', rel: 'noopener noreferrer') = s_('ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below').html_safe % { link_to_container_project: link_to_container_project } -- cgit v1.2.1 From a2d39b80109f006ff63752cfaed5e458f9443d1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 19 Sep 2017 17:25:42 +0200 Subject: Use gitlab-styles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- .codeclimate.yml | 1 + .gitlab-ci.yml | 2 +- .rubocop.yml | 1216 +------------------- .rubocop_todo.yml | 714 ++++++++++-- Gemfile | 8 +- Gemfile.lock | 26 +- config/initializers/peek.rb | 2 +- lib/gitlab/ci/config/entry/node.rb | 4 +- lib/gitlab/git/repository.rb | 11 +- rubocop/cop/active_record_dependent.rb | 26 - rubocop/cop/active_record_serialize.rb | 18 - rubocop/cop/custom_error_class.rb | 64 -- rubocop/cop/gem_fetcher.rb | 37 - .../cop/gitlab/module_with_instance_variables.rb | 4 +- rubocop/cop/in_batches.rb | 16 - rubocop/cop/include_sidekiq_worker.rb | 4 +- rubocop/cop/line_break_after_guard_clauses.rb | 100 -- rubocop/cop/migration/add_column.rb | 2 +- .../cop/migration/add_concurrent_foreign_key.rb | 2 +- rubocop/cop/migration/add_concurrent_index.rb | 2 +- rubocop/cop/migration/add_index.rb | 2 +- rubocop/cop/migration/add_timestamps.rb | 2 +- rubocop/cop/migration/datetime.rb | 4 +- rubocop/cop/migration/hash_index.rb | 2 +- rubocop/cop/migration/remove_column.rb | 2 +- rubocop/cop/migration/remove_concurrent_index.rb | 2 +- rubocop/cop/migration/remove_index.rb | 2 +- .../reversible_add_column_with_default.rb | 4 +- rubocop/cop/migration/safer_boolean_column.rb | 4 +- rubocop/cop/migration/timestamps.rb | 2 +- rubocop/cop/migration/update_column_in_batches.rb | 2 +- rubocop/cop/migration/update_large_table.rb | 4 +- rubocop/cop/polymorphic_associations.rb | 23 - rubocop/cop/project_path_helper.rb | 2 +- rubocop/cop/redirect_with_status.rb | 44 - rubocop/cop/rspec/env_assignment.rb | 5 +- rubocop/cop/rspec/single_line_hook.rb | 38 - rubocop/cop/rspec/verbose_include_metadata.rb | 74 -- rubocop/cop/sidekiq_options_queue.rb | 4 +- rubocop/model_helpers.rb | 11 - rubocop/rubocop.rb | 13 +- spec/factories/issues.rb | 1 + spec/rubocop/cop/active_record_dependent_spec.rb | 33 - spec/rubocop/cop/active_record_serialize_spec.rb | 33 - spec/rubocop/cop/custom_error_class_spec.rb | 111 -- spec/rubocop/cop/gem_fetcher_spec.rb | 46 - .../gitlab/module_with_instance_variables_spec.rb | 4 +- spec/rubocop/cop/in_batches_spec.rb | 19 - spec/rubocop/cop/include_sidekiq_worker_spec.rb | 6 +- .../cop/line_break_after_guard_clauses_spec.rb | 160 --- .../migration/add_concurrent_foreign_key_spec.rb | 6 +- .../cop/migration/add_concurrent_index_spec.rb | 6 +- spec/rubocop/cop/migration/add_timestamps_spec.rb | 12 +- spec/rubocop/cop/migration/datetime_spec.rb | 16 +- spec/rubocop/cop/migration/hash_index_spec.rb | 8 +- spec/rubocop/cop/migration/remove_column_spec.rb | 10 +- .../cop/migration/remove_concurrent_index_spec.rb | 6 +- spec/rubocop/cop/migration/remove_index_spec.rb | 4 +- .../reversible_add_column_with_default_spec.rb | 6 +- .../cop/migration/safer_boolean_column_spec.rb | 10 +- spec/rubocop/cop/migration/timestamps_spec.rb | 12 +- .../cop/migration/update_column_in_batches_spec.rb | 8 +- .../cop/migration/update_large_table_spec.rb | 10 +- spec/rubocop/cop/polymorphic_associations_spec.rb | 33 - spec/rubocop/cop/project_path_helper_spec.rb | 6 +- spec/rubocop/cop/redirect_with_status_spec.rb | 86 -- spec/rubocop/cop/rspec/env_assignment_spec.rb | 6 +- spec/rubocop/cop/rspec/single_line_hook_spec.rb | 66 -- .../cop/rspec/verbose_include_metadata_spec.rb | 53 - spec/rubocop/cop/sidekiq_options_queue_spec.rb | 6 +- 70 files changed, 757 insertions(+), 2531 deletions(-) delete mode 100644 rubocop/cop/active_record_dependent.rb delete mode 100644 rubocop/cop/active_record_serialize.rb delete mode 100644 rubocop/cop/custom_error_class.rb delete mode 100644 rubocop/cop/gem_fetcher.rb delete mode 100644 rubocop/cop/in_batches.rb delete mode 100644 rubocop/cop/line_break_after_guard_clauses.rb delete mode 100644 rubocop/cop/polymorphic_associations.rb delete mode 100644 rubocop/cop/redirect_with_status.rb delete mode 100644 rubocop/cop/rspec/single_line_hook.rb delete mode 100644 rubocop/cop/rspec/verbose_include_metadata.rb delete mode 100644 rubocop/model_helpers.rb delete mode 100644 spec/rubocop/cop/active_record_dependent_spec.rb delete mode 100644 spec/rubocop/cop/active_record_serialize_spec.rb delete mode 100644 spec/rubocop/cop/custom_error_class_spec.rb delete mode 100644 spec/rubocop/cop/gem_fetcher_spec.rb delete mode 100644 spec/rubocop/cop/in_batches_spec.rb delete mode 100644 spec/rubocop/cop/line_break_after_guard_clauses_spec.rb delete mode 100644 spec/rubocop/cop/polymorphic_associations_spec.rb delete mode 100644 spec/rubocop/cop/redirect_with_status_spec.rb delete mode 100644 spec/rubocop/cop/rspec/single_line_hook_spec.rb delete mode 100644 spec/rubocop/cop/rspec/verbose_include_metadata_spec.rb diff --git a/.codeclimate.yml b/.codeclimate.yml index 42afed54371..d4905856e72 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -16,6 +16,7 @@ engines: enabled: true rubocop: enabled: true + channel: "gitlab-rubocop-0-52" ratings: paths: - Gemfile.lock diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index edb1069e54f..4b149b13178 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -594,7 +594,7 @@ codequality: script: - cp .rubocop.yml .rubocop.yml.bak - grep -v "rubocop-gitlab-security" .rubocop.yml.bak > .rubocop.yml - - docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate analyze -f json > raw_codeclimate.json + - docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc dev.gitlab.org:5005/gitlab/gitlab-build-images:gitlab-codeclimate-v2 analyze -f json > raw_codeclimate.json - cat raw_codeclimate.json | docker run -i stedolan/jq -c 'map({check_name,fingerprint,location})' > codeclimate.json - mv .rubocop.yml.bak .rubocop.yml artifacts: diff --git a/.rubocop.yml b/.rubocop.yml index 7721cfaf850..0199bb9683a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,1190 +1,22 @@ -require: - - rubocop-rspec - - rubocop-gitlab-security - - ./rubocop/rubocop +inherit_gem: + gitlab-styles: + - rubocop-default.yml 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. - DisplayCopNames: true - # Style guide URLs are not displayed in offense messages by default. Change - # behavior by overriding DisplayStyleGuide, or by giving the - # -S/--display-style-guide option. - DisplayStyleGuide: false - # Exclude some GitLab files Exclude: - 'vendor/**/*' - 'node_modules/**/*' - 'db/*' - 'db/fixtures/**/*' + - 'db/geo/*' - 'tmp/**/*' - 'bin/**/*' - 'generator_templates/**/*' - 'builds/**/*' -# Gems in consecutive lines should be alphabetically sorted -Bundler/OrderedGems: - Enabled: false - -# Layout ###################################################################### - -# Check indentation of private/protected visibility modifiers. -Layout/AccessModifierIndentation: - Enabled: true - -# Align the elements of an array literal if they span more than one line. -Layout/AlignArray: - Enabled: true - -# Align the elements of a hash literal if they span more than one line. -Layout/AlignHash: - Enabled: true - -# Here we check if the parameters on a multi-line method call or -# definition are aligned. -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 - -# Checks that block braces have or don't have a space before the opening -# brace depending on configuration. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: space, no_space -Layout/SpaceBeforeBlockBraces: - 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 - -# Avoid trailing whitespace. -Layout/TrailingWhitespace: - 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: - Enabled: true - -# Use `Array#join` instead of `Array#*`. -Style/ArrayJoin: - Enabled: true - -# Use only ascii symbols in comments. -Style/AsciiComments: - Enabled: true - -# Use only ascii symbols in identifiers. -Style/AsciiIdentifiers: - Enabled: true - -# Checks for uses of Module#attr. -Style/Attr: - Enabled: true - -# Avoid the use of BEGIN blocks. -Style/BeginBlock: - Enabled: true - -# Do not use block comments. -Style/BlockComments: - Enabled: true - -# Avoid using {...} for multi-line blocks (multiline chaining is # always -# ugly). Prefer {...} over do...end for single-line blocks. -Style/BlockDelimiters: - Enabled: true - - # This cop checks for braces around the last parameter in a method call -# if the last parameter is a hash. -Style/BracesAroundHashParameters: - Enabled: false - -# This cop checks for uses of the case equality operator(===). -Style/CaseEquality: - Enabled: false - -# Checks for uses of character literals. -Style/CharacterLiteral: - Enabled: true - -# Use CamelCase for classes and modules.' -Style/ClassAndModuleCamelCase: - Enabled: true - -# Checks style of children classes and modules. -Style/ClassAndModuleChildren: - Enabled: false - -# Enforces consistent use of `Object#is_a?` or `Object#kind_of?`. -Style/ClassCheck: - Enabled: true - -# Use self when defining module/class methods. -Style/ClassMethods: - Enabled: true - -# Avoid the use of class variables. -Style/ClassVars: - Enabled: true - -# This cop checks for methods invoked via the :: operator instead -# of the . operator (like FileUtils::rmdir instead of FileUtils.rmdir). -Style/ColonMethodCall: - Enabled: true - -# This cop checks that comment annotation keywords are written according -# to guidelines. -Style/CommentAnnotation: - Enabled: false - -# 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. -Style/ConditionalAssignment: - Enabled: true - -# Constants should use SCREAMING_SNAKE_CASE. -Style/ConstantName: - Enabled: true - -# Use def with parentheses when there are arguments. -Style/DefWithParentheses: - Enabled: true - -# Document classes and non-namespace modules. -Style/Documentation: - Enabled: false - -# 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 - -# Avoid the use of END blocks. -Style/EndBlock: - Enabled: true - -# Favor the use of Fixnum#even? && Fixnum#odd? -Style/EvenOdd: - Enabled: true - -# Use snake_case for source file names. -Style/FileName: - Enabled: true - -# Checks for flip flops. -Style/FlipFlop: - Enabled: true - -# Checks use of for or each in multiline loops. -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 - -# Do not introduce global variables. -Style/GlobalVars: - Enabled: true - Exclude: - - 'lib/backup/**/*' - - 'lib/tasks/**/*' - -# Prefer Ruby 1.9 hash syntax `{ a: 1, b: 2 }` -# over 1.8 syntax `{ :a => 1, :b => 2 }`. -Style/HashSyntax: - Enabled: true - -# Checks that conditional statements do not have an identical line at the -# end of each branch, which can validly be moved out of the conditional. -Style/IdenticalConditionalBranches: - Enabled: true - -# Do not use if x; .... Use the ternary operator instead. -Style/IfWithSemicolon: - 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 - -# Checks if the method definitions have or don't have parentheses. -Style/MethodDefParentheses: - Enabled: true - -# Use the configured style when naming methods. -Style/MethodName: - Enabled: true - -# Checks for usage of `extend self` in modules. -Style/ModuleFunction: - Enabled: false - -# Avoid multi-line chains of blocks. -Style/MultilineBlockChain: - Enabled: true - -# Do not use then for multi-line if/unless. -Style/MultilineIfThen: - Enabled: true - -# 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: - Enabled: true - Exclude: - - 'db/migrate/**/*' - - 'db/post_migrate/**/*' - -# Favor unless over if for negative conditions (or control flow or). -Style/NegatedIf: - Enabled: true - -# Avoid using nested modifiers. -Style/NestedModifier: - Enabled: true - -# Use one expression per branch in a ternary operator. -Style/NestedTernaryOperator: - Enabled: true - -# Prefer x.nil? to x == nil. -Style/NilComparison: - Enabled: true - -# Checks for redundant nil checks. -Style/NonNilCheck: - Enabled: true - -# Use ! instead of not. -Style/Not: - Enabled: true - -# Add underscores to large numeric literals to improve their readability. -Style/NumericLiterals: - Enabled: false - -# Favor the ternary operator(?:) over if/then/else/end constructs. -Style/OneLineConditional: - Enabled: true - -# When defining binary operators, name the argument other. -Style/OpMethod: - Enabled: true - -# Don't use parentheses around the condition of an if/unless/while. -Style/ParenthesesAroundCondition: - Enabled: true - -# This cop (by default) checks for uses of methods Hash#has_key? and -# Hash#has_value? where it enforces Hash#key? and Hash#value? -# It is configurable to enforce the inverse, using `verbose` method -# names also. -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: short, verbose -Style/PreferredHashMethods: - Enabled: false - -# Checks for an obsolete RuntimeException argument in raise/fail. -Style/RedundantException: - Enabled: true - -# Checks for parentheses that seem not to serve any purpose. -Style/RedundantParentheses: - Enabled: true - -# Don't use semicolons to terminate expressions. -Style/Semicolon: - Enabled: true - -# Checks for proper usage of fail and raise. -Style/SignalException: - EnforcedStyle: only_raise - Enabled: true - -# Check for the usage of parentheses around stabby lambda arguments. -Style/StabbyLambdaParentheses: - EnforcedStyle: require_parentheses - Enabled: true - -# Checks if uses of quotes match the configured preference. -Style/StringLiterals: - Enabled: false - -# Checks if configured preferred methods are used over non-preferred. -Style/StringMethods: - PreferredMethods: - intern: to_sym - 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: - Enabled: true - EnforcedStyleForMultiline: no_comma - -# This cop checks for trailing comma in argument lists. -Style/TrailingCommaInArguments: - Enabled: true - EnforcedStyleForMultiline: no_comma - -# Checks for %W when interpolation is not needed. -Style/UnneededCapitalW: - Enabled: true - -# Checks for %q/%Q when single quotes or double quotes would do. -Style/UnneededPercentQ: - Enabled: false - -# Don't interpolate global, instance and class variables directly in strings. -Style/VariableInterpolation: - Enabled: true - -# Use the configured style when naming variables. -Style/VariableName: - EnforcedStyle: snake_case - Enabled: true - -# Use the configured style when numbering variables. -Style/VariableNumber: - Enabled: false - -# Use when x then ... for one-line cases. -Style/WhenThen: - Enabled: true - -# Checks for redundant do after while or until. -Style/WhileUntilDo: - Enabled: true - -# Favor modifier while/until usage when you have a single-line body. -Style/WhileUntilModifier: - Enabled: true - -# Use %w or %W for arrays of words. -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 - -# Use `spam?` instead of `is_spam?` -# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist. -# NamePrefix: is_, has_, have_ -# NamePrefixBlacklist: is_, has_, have_ -# NameWhitelist: is_a? -Style/PredicateName: - Enabled: true - NamePrefixBlacklist: is_ - Exclude: - - 'spec/**/*' - - 'features/**/*' - -# Metrics ##################################################################### - -# A calculated magnitude based on number of assignments, -# branches, and conditions. -Metrics/AbcSize: - Enabled: true - Max: 54.28 - -# This cop checks if the length of a block exceeds some maximum value. -Metrics/BlockLength: - Enabled: false - -# Avoid excessive block nesting. -Metrics/BlockNesting: - Enabled: true - Max: 4 - -# Avoid classes longer than 100 lines of code. -Metrics/ClassLength: - Enabled: false - -# A complexity metric that is strongly correlated to the number -# of test cases needed to validate a method. -Metrics/CyclomaticComplexity: - Enabled: true - Max: 13 - -# Limit lines to 80 characters. -Metrics/LineLength: - Enabled: false - -# Avoid methods longer than 10 lines of code. -Metrics/MethodLength: - Enabled: false - -# Avoid modules longer than 100 lines of code. -Metrics/ModuleLength: - Enabled: false - -# Avoid parameter lists longer than three or four parameters. -Metrics/ParameterLists: - Enabled: true - Max: 8 - -# A complexity metric geared towards measuring complexity for a human reader. -Metrics/PerceivedComplexity: - Enabled: true - Max: 14 - -# 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: - Enabled: true - -# This cop checks for ambiguous regexp literals in the first argument of -# a method invocation without parentheses. -Lint/AmbiguousRegexpLiteral: - Enabled: false - -# This cop checks for assignments in the conditions of -# if/while/until. -Lint/AssignmentInCondition: - Enabled: false - -# Align block ends correctly. -Lint/BlockAlignment: - Enabled: true - -# Default values in optional keyword arguments and optional ordinal arguments -# should not refer back to the name of the argument. -Lint/CircularArgumentReference: - Enabled: true - -# Checks for condition placed in a confusing position relative to the keyword. -Lint/ConditionPosition: - Enabled: true - -# Check for debugger calls. -Lint/Debugger: - Enabled: true - -# Align ends corresponding to defs correctly. -Lint/DefEndAlignment: - Enabled: true - -# Check for deprecated class method calls. -Lint/DeprecatedClassMethods: - Enabled: true - -# Check for immutable argument given to each_with_object. -Lint/EachWithObjectArgument: - Enabled: true - -# Check for odd code arrangement in an else block. -Lint/ElseLayout: - Enabled: true - -# Checks for empty ensure block. -Lint/EmptyEnsure: - Enabled: true - -# Checks for the presence of `when` branches without a body. -Lint/EmptyWhen: - Enabled: true - -# Align ends correctly. -Lint/EndAlignment: - Enabled: true - -# END blocks should not be placed inside method definitions. -Lint/EndInMethod: - Enabled: true - -# Do not use return in an ensure block. -Lint/EnsureReturn: - Enabled: true - -# Catches floating-point literals too large or small for Ruby to represent. -Lint/FloatOutOfRange: - Enabled: true - -# The number of parameters to format/sprint must match the fields. -Lint/FormatParameterMismatch: - Enabled: true - -# This cop checks for *rescue* blocks with no body. -Lint/HandleExceptions: - Enabled: false - -# Checks for adjacent string literals on the same line, which could better be -# represented as a single string literal. -Lint/ImplicitStringConcatenation: - Enabled: true - -# Checks for attempts to use `private` or `protected` to set the visibility -# of a class method, which does not work. -Lint/IneffectiveAccessModifier: - Enabled: false - -# Checks for invalid character literals with a non-escaped whitespace -# character. -Lint/InvalidCharacterLiteral: - Enabled: true - -# Checks of literals used in conditions. -Lint/LiteralInCondition: - Enabled: true - -# Checks for literals used in interpolation. -Lint/LiteralInInterpolation: - Enabled: true - -# This cop checks for uses of *begin...end while/until something*. -Lint/Loop: - Enabled: false - -# Do not use nested method definitions. -Lint/NestedMethodDefinition: - Enabled: true - -# Do not omit the accumulator when calling `next` in a `reduce`/`inject` block. -Lint/NextWithoutAccumulator: - Enabled: true - -# Checks for method calls with a space before the opening parenthesis. -Lint/ParenthesesAsGroupedExpression: - Enabled: true - -# Checks for `rand(1)` calls. Such calls always return `0` and most likely -# a mistake. -Lint/RandOne: - Enabled: true - -# Use parentheses in the method call to avoid confusion about precedence. -Lint/RequireParentheses: - Enabled: true - -# Avoid rescuing the Exception class. -Lint/RescueException: - Enabled: true - -# Checks for the order which exceptions are rescued to avoid rescueing a less specific exception before a more specific exception. -Lint/ShadowedException: - Enabled: false - -# This cop looks for use of the same name as outer local variables -# for block arguments or block local variables. -Lint/ShadowingOuterLocalVariable: - Enabled: false - -# Checks for Object#to_s usage in string interpolation. -Lint/StringConversionInInterpolation: - Enabled: true - -# Do not use prefix `_` for a variable that is used. -Lint/UnderscorePrefixedVariableName: - Enabled: true - -# This cop checks for using Fixnum or Bignum constant -Lint/UnifiedInteger: - Enabled: true - -# Checks for rubocop:disable comments that can be removed. -# Note: this cop is not disabled when disabling all cops. -# It must be explicitly disabled. -Lint/UnneededDisable: - Enabled: false - -# This cop checks for unneeded usages of splat expansion -Lint/UnneededSplatExpansion: - Enabled: false - -# Unreachable code. -Lint/UnreachableCode: - Enabled: true - -# This cop checks for unused block arguments. -Lint/UnusedBlockArgument: - Enabled: false - -# This cop checks for unused method arguments. -Lint/UnusedMethodArgument: - Enabled: false - -# Checks for useless access modifiers. -Lint/UselessAccessModifier: - Enabled: true - -# Checks for useless assignment to a local variable. -Lint/UselessAssignment: - Enabled: true - -# Checks for comparison of something with itself. -Lint/UselessComparison: - Enabled: true - -# Checks for useless `else` in `begin..end` without `rescue`. -Lint/UselessElseWithoutRescue: - Enabled: true - -# Checks for useless setter call to a local variable. -Lint/UselessSetterCall: - Enabled: true - -# Possible use of operator/literal/variable in void context. -Lint/Void: - Enabled: true - -# Performance ################################################################# - -# Use `caller(n..n)` instead of `caller`. -Performance/Caller: - Enabled: false - -# Use `casecmp` rather than `downcase ==`. -Performance/Casecmp: - Enabled: true - -# Use `str.{start,end}_with?(x, ..., y, ...)` instead of -# `str.{start,end}_with?(x, ...) || str.{start,end}_with?(y, ...)`. -Performance/DoubleStartEndWith: - Enabled: true - -# Use `strip` instead of `lstrip.rstrip`. -Performance/LstripRstrip: - Enabled: true - -# Use `Range#cover?` instead of `Range#include?`. -Performance/RangeInclude: - Enabled: true - -# This cop identifies the use of a `&block` parameter and `block.call` -# where `yield` would do just as well. -Performance/RedundantBlockCall: - Enabled: true - -# This cop identifies use of `Regexp#match` or `String#match in a context -# where the integral return value of `=~` would do just as well. -Performance/RedundantMatch: - Enabled: true - -# This cop identifies places where `Hash#merge!` can be replaced by -# `Hash#[]=`. -Performance/RedundantMerge: - Enabled: true - MaxKeyValuePairs: 1 - -# Use `sort` instead of `sort_by { |x| x }`. -Performance/RedundantSortBy: - Enabled: true - -# Use `start_with?` instead of a regex match anchored to the beginning of a -# string. -Performance/StartWith: - Enabled: true - -# Use `tr` instead of `gsub` when you are replacing the same number of -# characters. Use `delete` instead of `gsub` when you are deleting -# characters. -Performance/StringReplacement: - Enabled: true - -# Checks for `.times.map` calls. -Performance/TimesMap: - Enabled: true - -# Security #################################################################### - -# This cop checks for the use of JSON class methods which have potential -# security issues. -Security/JSONLoad: - Enabled: true - -# This cop checks for the use of *Kernel#eval*. -Security/Eval: - Enabled: true - -# Rails ####################################################################### - -# Enables Rails cops. -Rails: - Enabled: true - -# Enforces consistent use of action filter methods. -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: - Enabled: false - -# Prefer delegate method for delegations. -# Disabled per https://gitlab.com/gitlab-org/gitlab-ce/issues/35869 -Rails/Delegate: - Enabled: false - -# This cop checks dynamic `find_by_*` methods. -Rails/DynamicFindBy: - Enabled: false - -# This cop enforces that 'exit' calls are not used within a rails app. -Rails/Exit: - Enabled: true - Exclude: - - lib/gitlab/upgrader.rb - - 'lib/backup/**/*' - -# Prefer `find_by` over `where.first`. -Rails/FindBy: - Enabled: true - -# Prefer `all.find_each` over `all.find`. -Rails/FindEach: - Enabled: true - -# Prefer has_many :through to has_and_belongs_to_many. -Rails/HasAndBelongsToMany: - Enabled: true - -# This cop is used to identify usages of http methods like `get`, `post`, -# `put`, `patch` without the usage of keyword arguments in your tests and -# change them to use keyword args. -Rails/HttpPositionalArguments: - Enabled: false - -# Checks for calls to puts, print, etc. -Rails/Output: - Enabled: true - Exclude: - - lib/gitlab/seeder.rb - - lib/gitlab/upgrader.rb - - 'lib/backup/**/*' - - 'lib/tasks/**/*' - -# This cop checks for the use of output safety calls like html_safe and -# raw. -Rails/OutputSafety: - Enabled: false - -# Checks for incorrect grammar when using methods like `3.day.ago`. -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 - -# This cop checks for the use of Time methods without zone. -Rails/TimeZone: - Enabled: false - -# This cop checks for the use of old-style attribute validation macros. -Rails/Validation: - Enabled: true - -# RSpec ####################################################################### - -# Check that instances are not being stubbed globally. -RSpec/AnyInstance: - Enabled: false - -# Check for expectations where `be(...)` can replace `eql(...)`. -RSpec/BeEql: - Enabled: true - -# We don't enforce this as we use this technique in a few places. -RSpec/BeforeAfterAll: - Enabled: false - -# Check that the first argument to the top level describe is the tested class or -# module. -RSpec/DescribeClass: - Enabled: false - -# Checks that the second argument to `describe` specifies a method. -RSpec/DescribeMethod: - Enabled: false - -# Avoid describing symbols. -RSpec/DescribeSymbol: - Enabled: true - -# Checks that tests use `described_class`. -RSpec/DescribedClass: - Enabled: true - -# Checks if an example group does not include any tests. -RSpec/EmptyExampleGroup: - Enabled: true - CustomIncludeMethods: - - run_permission_checks - -# Checks for long example. -RSpec/ExampleLength: - Enabled: false - Max: 5 - -# Do not use should when describing your tests. -RSpec/ExampleWording: - Enabled: false - CustomTransform: - be: is - have: has - not: does not - IgnoredWords: [] - -# Checks for `expect(...)` calls containing literal values. -RSpec/ExpectActual: - Enabled: true - -# Checks for opportunities to use `expect { … }.to output`. -RSpec/ExpectOutput: - Enabled: true - -# Checks the file and folder naming of the spec file. -RSpec/FilePath: - Enabled: true - IgnoreMethods: true - Exclude: - - 'qa/**/*' - - 'spec/javascripts/fixtures/*' - - 'spec/requests/api/v3/*' - -# Checks if there are focused specs. -RSpec/Focus: - Enabled: true - -# Checks the arguments passed to `before`, `around`, and `after`. -RSpec/HookArgument: - Enabled: true - EnforcedStyle: implicit - -# Configuration parameters: EnforcedStyle, SupportedStyles. -# SupportedStyles: is_expected, should -RSpec/ImplicitExpect: - Enabled: true - EnforcedStyle: is_expected - -# Checks for the usage of instance variables. -RSpec/InstanceVariable: - Enabled: false - -# Checks for `subject` definitions that come after `let` definitions. -RSpec/LeadingSubject: - Enabled: false - -# Checks unreferenced `let!` calls being used for test setup. -RSpec/LetSetup: - Enabled: false - -# Check that chains of messages are not being stubbed. -RSpec/MessageChain: - Enabled: false - -# Checks that message expectations are set using spies. -RSpec/MessageSpies: - Enabled: false - -# Checks for multiple top-level describes. -RSpec/MultipleDescribes: - Enabled: false - -# Checks if examples contain too many `expect` calls. -RSpec/MultipleExpectations: - Enabled: false - -# Checks for explicitly referenced test subjects. -RSpec/NamedSubject: - Enabled: false - -# Checks for nested example groups. -RSpec/NestedGroups: - Enabled: false - -# Enforces the usage of the same method on all negative message expectations. -RSpec/NotToNot: - EnforcedStyle: not_to - Enabled: true - -# Check for repeated description strings in example groups. -RSpec/RepeatedDescription: - Enabled: false - -# Ensure RSpec hook blocks are always multi-line. -RSpec/SingleLineHook: - Enabled: true - Exclude: - - 'spec/factories/*' - - 'spec/requests/api/v3/*' - -# Checks for stubbed test subjects. -RSpec/SubjectStub: - Enabled: false - -# Prefer using verifying doubles over normal doubles. -RSpec/VerifiedDoubles: - Enabled: false - # Gitlab ################################################################### Gitlab/ModuleWithInstanceVariables: @@ -1197,43 +29,3 @@ Gitlab/ModuleWithInstanceVariables: # We ignore spec helpers because it usually doesn't matter - spec/support/**/*.rb - features/steps/**/*.rb - -# GitlabSecurity ########################################################### - -GitlabSecurity/DeepMunge: - Enabled: true - Exclude: - - 'lib/**/*.rake' - - 'spec/**/*' - -# To be enabled by https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/13610 -GitlabSecurity/JsonSerialization: - Enabled: false - -GitlabSecurity/PublicSend: - Enabled: true - Exclude: - - 'config/**/*' - - 'db/**/*' - - 'features/**/*' - - 'lib/**/*.rake' - - 'qa/**/*' - - 'spec/**/*' - -GitlabSecurity/RedirectToParamsUpdate: - Enabled: true - Exclude: - - 'lib/**/*.rake' - - 'spec/**/*' - -GitlabSecurity/SqlInjection: - Enabled: true - Exclude: - - 'lib/**/*.rake' - - 'spec/**/*' - -GitlabSecurity/SystemCommandInjection: - Enabled: true - Exclude: - - 'lib/**/*.rake' - - 'spec/**/*' diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index cdf97d1d842..085dc153596 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,53 +1,111 @@ # This configuration was generated by -# `rubocop --auto-gen-config --exclude-limit 0` -# on 2017-07-10 01:48:30 +0900 using RuboCop version 0.49.1. +# `rubocop --auto-gen-config` +# on 2017-12-14 12:04:26 +0100 using RuboCop version 0.52.0. # 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: 181 +# Offense count: 174 +Capybara/CurrentPathExpectation: + Enabled: false + +# Offense count: 951 +Capybara/FeatureMethods: + Enabled: false + +# Offense count: 24 +FactoryBot/DynamicAttributeDefinedStatically: + Exclude: + - 'spec/factories/broadcast_messages.rb' + - 'spec/factories/ci/builds.rb' + - 'spec/factories/ci/runners.rb' + - 'spec/factories/clusters/applications/helm.rb' + - 'spec/factories/clusters/applications/ingress.rb' + - 'spec/factories/clusters/platforms/kubernetes.rb' + - 'spec/factories/emails.rb' + - 'spec/factories/gpg_keys.rb' + - 'spec/factories/group_members.rb' + - 'spec/factories/merge_requests.rb' + - 'spec/factories/notes.rb' + - 'spec/factories/oauth_access_grants.rb' + - 'spec/factories/project_members.rb' + - 'spec/factories/todos.rb' + - 'spec/factories/uploads.rb' + +# Offense count: 65 +# Cop supports --auto-correct. +Layout/EmptyLinesAroundArguments: + Enabled: false + +# Offense count: 249 # Cop supports --auto-correct. # Configuration parameters: AllowForAlignment, ForceEqualSignAlignment. Layout/ExtraSpacing: Enabled: false -# Offense count: 119 +# Offense count: 82 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# Configuration parameters: EnforcedStyle, IndentationWidth. # SupportedStyles: special_inside_parentheses, consistent, align_brackets Layout/IndentArray: Enabled: false -# Offense count: 208 +# Offense count: 239 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. +# Configuration parameters: EnforcedStyle, IndentationWidth. # SupportedStyles: special_inside_parentheses, consistent, align_braces Layout/IndentHash: Enabled: false -# Offense count: 8 +# Offense count: 15 # Cop supports --auto-correct. -# Configuration parameters: AllowForAlignment. -Layout/SpaceBeforeFirstArg: - Enabled: false +# Configuration parameters: . +# SupportedStyles: space, no_space +# SupportedStylesForEmptyBraces: space, no_space +Layout/SpaceBeforeBlockBraces: + EnforcedStyle: space + EnforcedStyleForEmptyBraces: space -# Offense count: 64 +# Offense count: 11 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. +# Configuration parameters: AllowForAlignment. +Layout/SpaceBeforeFirstArg: + Exclude: + - 'config/routes/project.rb' + - 'db/migrate/20170506185517_add_foreign_key_pipeline_schedules_and_pipelines.rb' + - 'features/steps/project/source/browse_files.rb' + - 'features/steps/project/source/markdown_render.rb' + - 'lib/api/runners.rb' + - 'spec/features/search/user_uses_search_filters_spec.rb' + - 'spec/routing/project_routing_spec.rb' + - 'spec/services/system_note_service_spec.rb' + +# Offense count: 93 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. # SupportedStyles: require_no_space, require_space Layout/SpaceInLambdaLiteral: Enabled: false -# Offense count: 256 +# Offense count: 1 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters. +# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBrackets. +# SupportedStyles: space, no_space, compact +# SupportedStylesForEmptyBrackets: space, no_space +Layout/SpaceInsideArrayLiteralBrackets: + Exclude: + - 'spec/lib/gitlab/import_export/relation_factory_spec.rb' + +# Offense count: 323 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. # SupportedStyles: space, no_space # SupportedStylesForEmptyBraces: space, no_space Layout/SpaceInsideBlockBraces: Enabled: false -# Offense count: 135 +# Offense count: 146 # Cop supports --auto-correct. Layout/SpaceInsideParens: Enabled: false @@ -55,178 +113,535 @@ Layout/SpaceInsideParens: # Offense count: 14 # Cop supports --auto-correct. Layout/SpaceInsidePercentLiteralDelimiters: + Exclude: + - 'lib/gitlab/git_access.rb' + - 'lib/gitlab/health_checks/fs_shards_check.rb' + - 'spec/lib/gitlab/health_checks/fs_shards_check_spec.rb' + +# Offense count: 25 +Lint/DuplicateMethods: + Exclude: + - 'app/models/application_setting.rb' + - 'app/models/commit.rb' + - 'app/models/note.rb' + - 'app/services/merge_requests/merge_service.rb' + - 'lib/bitbucket/representation/repo.rb' + - 'lib/declarative_policy/base.rb' + - 'lib/gitlab/ci/build/artifacts/metadata/entry.rb' + - 'lib/gitlab/cycle_analytics/base_event_fetcher.rb' + - 'lib/gitlab/diff/formatters/base_formatter.rb' + - 'lib/gitlab/git/blob.rb' + - 'lib/gitlab/git/repository.rb' + - 'lib/gitlab/git/tree.rb' + - 'lib/gitlab/git/wiki_page.rb' + - 'lib/gitlab/ldap/person.rb' + - 'lib/gitlab/o_auth/user.rb' + +# Offense count: 4 +Lint/InterpolationCheck: + Exclude: + - 'spec/features/issues/filtered_search/filter_issues_spec.rb' + - 'spec/features/users_spec.rb' + - 'spec/services/quick_actions/interpret_service_spec.rb' + +# Offense count: 198 +# Configuration parameters: MaximumRangeSize. +Lint/MissingCopEnableDirective: + Enabled: false + +# Offense count: 2 +Lint/NestedPercentLiteral: + Exclude: + - 'lib/gitlab/git/repository.rb' + - 'spec/support/email_format_shared_examples.rb' + +# Offense count: 1 +Lint/ReturnInVoidContext: + Exclude: + - 'app/models/project.rb' + +# Offense count: 1 +# Configuration parameters: IgnoreImplicitReferences. +Lint/ShadowedArgument: + Exclude: + - 'lib/gitlab/database/sha_attribute.rb' + +# Offense count: 3 +# Cop supports --auto-correct. +Lint/UnneededRequireStatement: + Exclude: + - 'db/post_migrate/20161221153951_rename_reserved_project_names.rb' + - 'db/post_migrate/20170313133418_rename_more_reserved_project_names.rb' + - 'lib/declarative_policy.rb' + +# Offense count: 9 +Lint/UriEscapeUnescape: + Exclude: + - 'app/controllers/application_controller.rb' + - 'app/models/project_services/drone_ci_service.rb' + - 'spec/lib/google_api/auth_spec.rb' + - 'spec/requests/api/files_spec.rb' + - 'spec/requests/api/internal_spec.rb' + - 'spec/requests/api/issues_spec.rb' + - 'spec/requests/api/v3/issues_spec.rb' + +# Offense count: 2 +Naming/ConstantName: + Exclude: + - 'lib/gitlab/import_sources.rb' + - 'lib/gitlab/ssh_public_key.rb' + +# Offense count: 11 +# Configuration parameters: EnforcedStyle. +# SupportedStyles: lowercase, uppercase +Naming/HeredocDelimiterCase: + Exclude: + - 'spec/lib/gitlab/diff/parser_spec.rb' + - 'spec/lib/json_web_token/rsa_token_spec.rb' + - 'spec/models/commit_spec.rb' + - 'spec/support/repo_helpers.rb' + - 'spec/support/seed_repo.rb' + +# Offense count: 101 +# Configuration parameters: Blacklist. +# Blacklist: END, (?-mix:EO[A-Z]{1}) +Naming/HeredocDelimiterNaming: + Enabled: false + +# Offense count: 28 +# Cop supports --auto-correct. +# Configuration parameters: AutoCorrect. +Performance/HashEachMethods: + Enabled: false + +# Offense count: 1 +Performance/UnfreezeString: + Exclude: + - 'features/steps/project/commits/commits.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Performance/UriDefaultParser: + Exclude: + - 'lib/gitlab/url_sanitizer.rb' + +# Offense count: 3745 +# Configuration parameters: Prefixes. +# Prefixes: when, with, without +RSpec/ContextWording: Enabled: false -# Offense count: 272 +# Offense count: 291 RSpec/EmptyLineAfterFinalLet: Enabled: false -# Offense count: 181 +# Offense count: 180 RSpec/EmptyLineAfterSubject: Enabled: false -# Offense count: 9 -# Configuration parameters: EnforcedStyle, SupportedStyles. +# Offense count: 220 +RSpec/ExpectInHook: + Enabled: false + +# Offense count: 7 +# Configuration parameters: EnforcedStyle. +# SupportedStyles: implicit, each, example +RSpec/HookArgument: + Exclude: + - 'spec/spec_helper.rb' + - 'spec/support/carrierwave.rb' + - 'spec/support/db_cleaner.rb' + - 'spec/support/gitaly.rb' + - 'spec/support/setup_builds_storage.rb' + +# Offense count: 19 +# Configuration parameters: EnforcedStyle. # SupportedStyles: it_behaves_like, it_should_behave_like RSpec/ItBehavesLike: - Enabled: false + Exclude: + - 'spec/lib/gitlab/git/commit_spec.rb' + - 'spec/lib/gitlab/git/repository_spec.rb' + - 'spec/lib/gitlab/shell_spec.rb' + - 'spec/services/notification_service_spec.rb' + - 'spec/workers/git_garbage_collect_worker_spec.rb' -# Offense count: 4 +# Offense count: 5 RSpec/IteratedExpectation: - Enabled: false + Exclude: + - 'spec/features/admin/admin_settings_spec.rb' + - 'spec/features/merge_requests/diff_notes_resolve_spec.rb' + - 'spec/features/projects/awards/user_interacts_with_awards_in_issue_spec.rb' + - 'spec/lib/gitlab/gitlab_import/client_spec.rb' + - 'spec/lib/gitlab/legacy_github_import/client_spec.rb' + +# Offense count: 75 +RSpec/LetBeforeExamples: + Exclude: + - 'spec/controllers/projects/commit_controller_spec.rb' + - 'spec/lib/banzai/filter/issue_reference_filter_spec.rb' + - 'spec/lib/banzai/filter/user_reference_filter_spec.rb' + - 'spec/lib/gitlab/email/handler/create_issue_handler_spec.rb' + - 'spec/lib/gitlab/email/handler/create_merge_request_handler_spec.rb' + - 'spec/lib/gitlab/email/handler/create_note_handler_spec.rb' + - 'spec/models/commit_range_spec.rb' + - 'spec/models/milestone_spec.rb' + - 'spec/models/project_services/packagist_service_spec.rb' + - 'spec/models/repository_spec.rb' + - 'spec/rubocop/cop/migration/update_column_in_batches_spec.rb' + - 'spec/serializers/pipeline_details_entity_spec.rb' + - 'spec/views/ci/lints/show.html.haml_spec.rb' -# Offense count: 2 +# Offense count: 1 +RSpec/MultipleSubjects: + Exclude: + - 'spec/services/merge_requests/create_from_issue_service_spec.rb' + +# Offense count: 4 RSpec/OverwritingSetup: + Exclude: + - 'spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb' + - 'spec/models/email_spec.rb' + - 'spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb' + - 'spec/services/notes/quick_actions_service_spec.rb' + +# Offense count: 917 +# Configuration parameters: Strict, EnforcedStyle. +# SupportedStyles: inflected, explicit +RSpec/PredicateMatcher: Enabled: false -# Offense count: 36 +# Offense count: 35 RSpec/RepeatedExample: Enabled: false -# Offense count: 86 +# Offense count: 132 +# Configuration parameters: EnforcedStyle. +# SupportedStyles: and_return, block +RSpec/ReturnFromStub: + Enabled: false + +# Offense count: 105 RSpec/ScatteredLet: Enabled: false -# Offense count: 20 +# Offense count: 22 RSpec/ScatteredSetup: - Enabled: false + Exclude: + - 'spec/controllers/projects/templates_controller_spec.rb' + - 'spec/lib/gitlab/bitbucket_import/importer_spec.rb' + - 'spec/lib/gitlab/git/env_spec.rb' + - 'spec/requests/api/jobs_spec.rb' + - 'spec/requests/api/v3/builds_spec.rb' + - 'spec/requests/api/v3/projects_spec.rb' + - 'spec/services/projects/create_service_spec.rb' # Offense count: 1 RSpec/SharedContext: + Exclude: + - 'spec/features/admin/admin_groups_spec.rb' + +# Offense count: 90 +RSpec/SingleLineHook: + Enabled: false + +# Offense count: 5 +RSpec/VoidExpect: + Exclude: + - 'spec/features/projects/artifacts/download_spec.rb' + - 'spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb' + - 'spec/models/ci/group_spec.rb' + - 'spec/models/ci/runner_spec.rb' + - 'spec/services/users/destroy_service_spec.rb' + +# Offense count: 40 +# Configuration parameters: Include. +# Include: db/migrate/*.rb +Rails/CreateTableWithTimestamps: Enabled: false -# Offense count: 115 +# Offense count: 149 Rails/FilePath: Enabled: false +# Offense count: 119 +# Configuration parameters: Include. +# Include: app/models/**/*.rb +Rails/HasManyOrHasOneDependent: + Enabled: false + +# Offense count: 113 +# Configuration parameters: Include. +# Include: app/models/**/*.rb +Rails/InverseOf: + Enabled: false + +# Offense count: 48 +# Configuration parameters: Include. +# Include: app/controllers/**/*.rb +Rails/LexicallyScopedActionFilter: + Enabled: false + +# Offense count: 14 +# Cop supports --auto-correct. +Rails/Presence: + Exclude: + - 'app/controllers/projects/blob_controller.rb' + - 'app/models/ci/pipeline.rb' + - 'app/models/clusters/platforms/kubernetes.rb' + - 'app/models/concerns/mentionable.rb' + - 'app/models/concerns/token_authenticatable.rb' + - 'app/models/project_services/hipchat_service.rb' + - 'app/models/project_services/irker_service.rb' + - 'app/models/project_services/jira_service.rb' + - 'app/models/project_services/kubernetes_service.rb' + - 'app/models/project_services/packagist_service.rb' + - 'app/models/wiki_page.rb' + - 'lib/gitlab/git/hook.rb' + - 'lib/gitlab/github_import/importer/releases_importer.rb' + +# Offense count: 14 +# Cop supports --auto-correct. +Rails/RedundantReceiverInWithOptions: + Exclude: + - 'config/initializers/doorkeeper_openid_connect.rb' + # Offense count: 2 # Configuration parameters: Include. # Include: db/migrate/*.rb Rails/ReversibleMigration: - Enabled: false + Exclude: + - 'db/migrate/20160824103857_drop_unused_ci_tables.rb' -# Offense count: 336 +# Offense count: 430 # 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: 11 -# Cop supports --auto-correct. -Security/YAMLLoad: - Enabled: false +# Offense count: 1 +# Configuration parameters: Environments. +# Environments: development, test, production +Rails/UnknownEnv: + Exclude: + - 'db/migrate/20171124125748_populate_missing_merge_request_statuses.rb' -# Offense count: 58 +# Offense count: 13 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. +Security/YAMLLoad: + Exclude: + - 'config/initializers/carrierwave.rb' + - 'lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits.rb' + - 'lib/gitlab/redis/wrapper.rb' + - 'lib/system_check/incoming_email/imap_authentication_check.rb' + - 'spec/config/mail_room_spec.rb' + - 'spec/initializers/secret_token_spec.rb' + - 'spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb' + - 'spec/models/clusters/platforms/kubernetes_spec.rb' + - 'spec/models/project_services/kubernetes_service_spec.rb' + +# Offense count: 63 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. # SupportedStyles: percent_q, bare_percent Style/BarePercentLiterals: Enabled: false -# Offense count: 6 -# Cop supports --auto-correct. -Style/EachWithObject: +# Offense count: 5 +Style/CommentedKeyword: + Exclude: + - 'lib/tasks/gitlab/backup.rake' + - 'spec/tasks/gitlab/backup_rake_spec.rb' + +# Offense count: 30 +Style/DateTime: Enabled: false -# Offense count: 31 +# Offense count: 1 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. +Style/Dir: + Exclude: + - 'qa/qa.rb' + +# Offense count: 9 +# Cop supports --auto-correct. +Style/EachWithObject: + Exclude: + - 'config/initializers/gollum.rb' + - 'lib/expand_variables.rb' + - 'lib/gitlab/ci/ansi2html.rb' + - 'lib/gitlab/ee_compat_check.rb' + - 'lib/gitlab/hook_data/issuable_builder.rb' + - 'lib/gitlab/i18n/po_linter.rb' + - 'lib/gitlab/import_export/members_mapper.rb' + - 'lib/gitlab/import_export/relation_factory.rb' + - 'scripts/static-analysis' + +# Offense count: 24 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. # SupportedStyles: empty, nil, both Style/EmptyElse: Enabled: false -# Offense count: 9 +# Offense count: 14 +# Cop supports --auto-correct. +Style/EmptyLambdaParameter: + Exclude: + - 'app/models/ci/build.rb' + - 'app/models/ci/runner.rb' + +# Offense count: 12 # Cop supports --auto-correct. Style/EmptyLiteral: - Enabled: false + Exclude: + - 'features/steps/project/commits/commits.rb' + - 'lib/gitlab/fogbugz_import/importer.rb' + - 'lib/gitlab/git/diff_collection.rb' + - 'lib/gitlab/gitaly_client.rb' + - 'scripts/trigger-build-omnibus' + - 'spec/features/merge_requests/versions_spec.rb' + - 'spec/helpers/merge_requests_helper_spec.rb' + - 'spec/lib/gitlab/request_context_spec.rb' + - 'spec/lib/gitlab/workhorse_spec.rb' + - 'spec/requests/api/jobs_spec.rb' + - 'spec/support/chat_slash_commands_shared_examples.rb' -# Offense count: 78 +# Offense count: 98 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. +# Configuration parameters: EnforcedStyle. # SupportedStyles: compact, expanded Style/EmptyMethod: Enabled: false # Offense count: 23 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. +Style/Encoding: + Enabled: false + +# Offense count: 2 +Style/EvalWithLocation: + Exclude: + - 'app/models/service.rb' + +# Offense count: 52 +# Cop supports --auto-correct. +# Configuration parameters: Autocorrect, EnforcedStyle. +# SupportedStyles: module_function, extend_self +Style/ExtendSelf: + Enabled: false + +# Offense count: 34 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. # SupportedStyles: format, sprintf, percent Style/FormatString: Enabled: false -# Offense count: 301 +# Offense count: 371 # Configuration parameters: MinBodyLength. Style/GuardClause: Enabled: false -# Offense count: 18 +# Offense count: 21 Style/IfInsideElse: Enabled: false -# Offense count: 182 +# Offense count: 781 # Cop supports --auto-correct. -# Configuration parameters: MaxLineLength. Style/IfUnlessModifier: Enabled: false -# Offense count: 52 +# Offense count: 71 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. +# Configuration parameters: EnforcedStyle. # SupportedStyles: line_count_dependent, lambda, literal Style/Lambda: Enabled: false -# Offense count: 6 +# Offense count: 11 # Cop supports --auto-correct. Style/LineEndConcatenation: - Enabled: false + Exclude: + - 'app/helpers/tree_helper.rb' + - 'spec/features/issuables/markdown_references_spec.rb' + - 'spec/lib/gitlab/checks/project_moved_spec.rb' + - 'spec/lib/gitlab/gfm/reference_rewriter_spec.rb' + - 'spec/lib/gitlab/incoming_email_spec.rb' -# Offense count: 40 +# Offense count: 39 # Cop supports --auto-correct. Style/MethodCallWithoutArgsParentheses: Enabled: false -# Offense count: 13 +# Offense count: 17 Style/MethodMissing: Enabled: false +# Offense count: 7 +Style/MixinUsage: + Exclude: + - 'features/support/env.rb' + - 'spec/factories/ci/builds.rb' + - 'spec/factories/ci/job_artifacts.rb' + - 'spec/factories/lfs_objects.rb' + - 'spec/factories/notes.rb' + - 'spec/lib/gitlab/import_export/project_tree_restorer_spec.rb' + - 'spec/lib/gitlab/import_export/version_checker_spec.rb' + # Offense count: 6 # Cop supports --auto-correct. Style/MultilineIfModifier: - Enabled: false + Exclude: + - 'app/helpers/snippets_helper.rb' + - 'app/models/project_wiki.rb' + - 'app/services/ci/process_pipeline_service.rb' + - 'app/services/create_deployment_service.rb' + - 'lib/api/commit_statuses.rb' + - 'lib/gitlab/ci/trace.rb' -# Offense count: 26 +# Offense count: 23 # Cop supports --auto-correct. +# Configuration parameters: Whitelist. +# Whitelist: be, be_a, be_an, be_between, be_falsey, be_kind_of, be_instance_of, be_truthy, be_within, eq, eql, end_with, include, match, raise_error, respond_to, start_with Style/NestedParenthesizedCalls: Enabled: false # Offense count: 20 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles. +# Configuration parameters: EnforcedStyle, MinBodyLength. # SupportedStyles: skip_modifier_ifs, always Style/Next: Enabled: false -# Offense count: 45 +# Offense count: 58 # Cop supports --auto-correct. -# Configuration parameters: EnforcedOctalStyle, SupportedOctalStyles. +# Configuration parameters: EnforcedOctalStyle. # SupportedOctalStyles: zero_with_o, zero_only Style/NumericLiteralPrefix: Enabled: false -# Offense count: 98 +# Offense count: 112 # Cop supports --auto-correct. -# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles. +# Configuration parameters: AutoCorrect, EnforcedStyle. # SupportedStyles: predicate, comparison Style/NumericPredicate: Enabled: false -# Offense count: 42 +# Offense count: 4 +# Cop supports --auto-correct. +Style/OrAssignment: + Exclude: + - 'app/models/concerns/token_authenticatable.rb' + - 'lib/api/commit_statuses.rb' + - 'lib/api/v3/members.rb' + - 'lib/gitlab/project_transfer.rb' + +# Offense count: 50 # Cop supports --auto-correct. Style/ParallelAssignment: Enabled: false -# Offense count: 800 +# Offense count: 891 # Cop supports --auto-correct. # Configuration parameters: PreferredDelimiters. Style/PercentLiteralDelimiters: @@ -235,106 +650,194 @@ Style/PercentLiteralDelimiters: # Offense count: 15 # Cop supports --auto-correct. Style/PerlBackrefs: - Enabled: false - -# Offense count: 58 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. + Exclude: + - 'app/controllers/projects/application_controller.rb' + - 'app/helpers/submodule_helper.rb' + - 'lib/backup/manager.rb' + - 'lib/banzai/filter/abstract_reference_filter.rb' + - 'lib/banzai/filter/autolink_filter.rb' + - 'lib/banzai/filter/emoji_filter.rb' + - 'lib/banzai/filter/gollum_tags_filter.rb' + - 'lib/expand_variables.rb' + - 'lib/gitlab/diff/highlight.rb' + - 'lib/gitlab/search_results.rb' + - 'lib/gitlab/sherlock/query.rb' + +# Offense count: 82 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. # SupportedStyles: compact, exploded Style/RaiseArgs: Enabled: false -# Offense count: 6 +# Offense count: 8 # Cop supports --auto-correct. Style/RedundantBegin: - Enabled: false + Exclude: + - 'app/controllers/projects/clusters/gcp_controller.rb' + - 'app/models/merge_request.rb' + - 'app/services/projects/import_service.rb' + - 'lib/api/branches.rb' + - 'lib/gitlab/current_settings.rb' + - 'lib/gitlab/git/commit.rb' + - 'lib/gitlab/health_checks/base_abstract_check.rb' + - 'lib/tasks/gitlab/task_helpers.rb' + +# Offense count: 1 +# Cop supports --auto-correct. +Style/RedundantConditional: + Exclude: + - 'lib/system_check/helpers.rb' -# Offense count: 37 +# Offense count: 58 # Cop supports --auto-correct. Style/RedundantFreeze: Enabled: false -# Offense count: 14 +# Offense count: 15 # Cop supports --auto-correct. # Configuration parameters: AllowMultipleReturnValues. Style/RedundantReturn: - Enabled: false - -# Offense count: 406 + Exclude: + - 'app/controllers/application_controller.rb' + - 'app/controllers/concerns/issuable_actions.rb' + - 'app/controllers/groups/application_controller.rb' + - 'app/controllers/omniauth_callbacks_controller.rb' + - 'app/controllers/profiles/keys_controller.rb' + - 'app/controllers/projects/application_controller.rb' + - 'app/services/access_token_validation_service.rb' + - 'lib/gitlab/utils.rb' + - 'lib/google_api/auth.rb' + +# Offense count: 454 # Cop supports --auto-correct. Style/RedundantSelf: Enabled: false -# Offense count: 115 +# Offense count: 140 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes. +# Configuration parameters: EnforcedStyle, AllowInnerSlashes. # SupportedStyles: slashes, percent_r, mixed Style/RegexpLiteral: Enabled: false -# Offense count: 29 +# Offense count: 35 # Cop supports --auto-correct. Style/RescueModifier: Enabled: false +# Offense count: 105 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: implicit, explicit +Style/RescueStandardError: + Enabled: false + +# Offense count: 91 +# Cop supports --auto-correct. +# Configuration parameters: ConvertCodeThatCanStartToReturnNil. +Style/SafeNavigation: + Enabled: false + # Offense count: 8 # Cop supports --auto-correct. Style/SelfAssignment: - Enabled: false + Exclude: + - 'app/models/concerns/bulk_member_access_load.rb' + - 'app/serializers/base_serializer.rb' + - 'app/services/notification_service.rb' + - 'lib/api/runners.rb' + - 'spec/features/merge_requests/diff_notes_resolve_spec.rb' + - 'spec/features/projects/clusters/interchangeability_spec.rb' + - 'spec/support/import_export/configuration_helper.rb' # Offense count: 50 # Cop supports --auto-correct. # Configuration parameters: AllowIfMethodIsEmpty. Style/SingleLineMethods: - Enabled: false + Exclude: + - 'lib/gitlab/ci/ansi2html.rb' -# Offense count: 64 +# Offense count: 66 # Cop supports --auto-correct. -# Configuration parameters: SupportedStyles. +# Configuration parameters: . # SupportedStyles: use_perl_names, use_english_names Style/SpecialGlobalVars: EnforcedStyle: use_perl_names -# Offense count: 44 +# Offense count: 1 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles. +Style/StderrPuts: + Exclude: + - 'config/initializers/rspec_profiling.rb' + +# Offense count: 45 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. # SupportedStyles: single_quotes, double_quotes Style/StringLiteralsInInterpolation: Enabled: false -# Offense count: 84 +# Offense count: 99 # Cop supports --auto-correct. # Configuration parameters: IgnoredMethods. # IgnoredMethods: respond_to, define_method Style/SymbolProc: Enabled: false -# Offense count: 8 +# Offense count: 9 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, SupportedStyles, AllowSafeAssignment. +# Configuration parameters: EnforcedStyle, AllowSafeAssignment. # SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex Style/TernaryParentheses: - Enabled: false + Exclude: + - 'app/finders/projects_finder.rb' + - 'app/helpers/namespaces_helper.rb' + - 'features/support/capybara.rb' + - 'lib/api/v3/projects.rb' + - 'lib/gitlab/ci/build/artifacts/metadata/entry.rb' + - 'spec/requests/api/pipeline_schedules_spec.rb' + - 'spec/support/capybara.rb' # Offense count: 17 # Cop supports --auto-correct. # Configuration parameters: AllowNamedUnderscoreVariables. Style/TrailingUnderscoreVariable: - Enabled: false + Exclude: + - 'app/controllers/admin/background_jobs_controller.rb' + - 'app/controllers/invites_controller.rb' + - 'app/helpers/tab_helper.rb' + - 'lib/backup/manager.rb' + - 'lib/gitlab/logger.rb' + - 'lib/gitlab/upgrader.rb' + - 'lib/system_check/app/migrations_are_up_check.rb' + - 'lib/system_check/incoming_email/mail_room_running_check.rb' + - 'lib/tasks/gitlab/check.rake' + - 'lib/tasks/gitlab/task_helpers.rb' + - 'spec/lib/gitlab/etag_caching/middleware_spec.rb' + - 'spec/services/quick_actions/interpret_service_spec.rb' -# Offense count: 4 +# Offense count: 5 # 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 + Exclude: + - 'app/models/external_issue.rb' + - 'app/serializers/base_serializer.rb' + - 'lib/gitlab/ldap/person.rb' + - 'lib/system_check/base_check.rb' -# Offense count: 5 +# Offense count: 4 # Cop supports --auto-correct. Style/UnlessElse: - Enabled: false + Exclude: + - 'lib/backup/manager.rb' + - 'lib/gitlab/project_search_results.rb' + - 'lib/tasks/gitlab/check.rake' + - 'spec/features/issues/award_emoji_spec.rb' -# Offense count: 28 +# Offense count: 30 # Cop supports --auto-correct. Style/UnneededInterpolation: Enabled: false @@ -342,4 +845,19 @@ Style/UnneededInterpolation: # Offense count: 11 # Cop supports --auto-correct. Style/ZeroLengthPredicate: - Enabled: false + Exclude: + - 'app/models/deploy_key.rb' + - 'app/models/network/commit.rb' + - 'app/models/network/graph.rb' + - 'app/models/project_services/asana_service.rb' + - 'app/services/boards/create_service.rb' + - 'app/services/merge_requests/conflicts/list_service.rb' + - 'lib/declarative_policy/dsl.rb' + - 'lib/extracts_path.rb' + - 'lib/gitlab/git/repository.rb' + +# Offense count: 22050 +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. +# URISchemes: http, https +Metrics/LineLength: + Max: 1310 diff --git a/Gemfile b/Gemfile index b6ffaf80f24..db86c86428c 100644 --- a/Gemfile +++ b/Gemfile @@ -334,9 +334,11 @@ group :development, :test do gem 'spring-commands-rspec', '~> 1.0.4' gem 'spring-commands-spinach', '~> 1.1.0' - gem 'rubocop', '~> 0.49.1', require: false - gem 'rubocop-rspec', '~> 1.15.1', require: false - gem 'rubocop-gitlab-security', '~> 0.1.0', require: false + gem 'gitlab-styles', '~> 2.2.0', require: false + # Pin these dependencies, otherwise a new rule could break the CI pipelines + gem 'rubocop', '~> 0.52.0' + gem 'rubocop-rspec', '~> 1.20.1' + gem 'scss_lint', '~> 0.54.0', require: false gem 'haml_lint', '~> 0.26.0', require: false gem 'simplecov', '~> 0.14.0', require: false diff --git a/Gemfile.lock b/Gemfile.lock index a6e3c9e27cc..b11b438a29c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -303,6 +303,10 @@ GEM mime-types (>= 1.16) posix-spawn (~> 0.3) gitlab-markup (1.6.3) + gitlab-styles (2.2.0) + rubocop (~> 0.51) + rubocop-gitlab-security (~> 0.1.0) + rubocop-rspec (~> 1.19) gitlab_omniauth-ldap (2.0.4) net-ldap (~> 0.16) omniauth (~> 1.3) @@ -777,21 +781,21 @@ GEM pg rails sqlite3 - rubocop (0.49.1) + rubocop (0.52.0) parallel (~> 1.10) - parser (>= 2.3.3.1, < 3.0) + parser (>= 2.4.0.2, < 3.0) powerpack (~> 0.1) - rainbow (>= 1.99.1, < 3.0) + rainbow (>= 2.2.2, < 4.0) ruby-progressbar (~> 1.7) unicode-display_width (~> 1.0, >= 1.0.1) - rubocop-gitlab-security (0.1.0) - rubocop (>= 0.47.1) - rubocop-rspec (1.15.1) - rubocop (>= 0.42.0) + rubocop-gitlab-security (0.1.1) + rubocop (>= 0.51) + rubocop-rspec (1.20.1) + rubocop (>= 0.51.0) ruby-fogbugz (0.2.1) crack (~> 0.4) ruby-prof (0.16.2) - ruby-progressbar (1.8.1) + ruby-progressbar (1.9.0) ruby-saml (1.4.1) nokogiri (>= 1.5.10) ruby_parser (3.9.0) @@ -1046,6 +1050,7 @@ DEPENDENCIES github-linguist (~> 4.7.0) gitlab-flowdock-git-hook (~> 1.0.1) gitlab-markup (~> 1.6.2) + gitlab-styles (~> 2.2.0) gitlab_omniauth-ldap (~> 2.0.4) gollum-lib (~> 4.2) gollum-rugged_adapter (~> 0.4.4) @@ -1148,9 +1153,8 @@ DEPENDENCIES rspec-retry (~> 0.4.5) rspec-set (~> 0.1.3) rspec_profiling (~> 0.0.5) - rubocop (~> 0.49.1) - rubocop-gitlab-security (~> 0.1.0) - rubocop-rspec (~> 1.15.1) + rubocop (~> 0.52.0) + rubocop-rspec (~> 1.20.1) ruby-fogbugz (~> 0.2.1) ruby-prof (~> 0.16.2) ruby_parser (~> 3.8) diff --git a/config/initializers/peek.rb b/config/initializers/peek.rb index 1cff355346c..581397b26f8 100644 --- a/config/initializers/peek.rb +++ b/config/initializers/peek.rb @@ -18,7 +18,7 @@ Peek.into Peek::Views::Rblineprof Peek.into Peek::Views::GC Peek.into Peek::Views::Gitaly -# rubocop:disable Style/ClassAndModuleCamelCase +# rubocop:disable Naming/ClassAndModuleCamelCase class PEEK_DB_CLIENT class << self attr_accessor :query_details diff --git a/lib/gitlab/ci/config/entry/node.rb b/lib/gitlab/ci/config/entry/node.rb index 1fba0b2db0b..26505c91be3 100644 --- a/lib/gitlab/ci/config/entry/node.rb +++ b/lib/gitlab/ci/config/entry/node.rb @@ -93,9 +93,7 @@ module Gitlab private - def entries - @entries - end + attr_reader :entries end end end diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 044c60caa05..603323d0452 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -56,11 +56,12 @@ module Gitlab # Do nothing if hooks already exist unless real_local_hooks_path == File.realpath(global_hooks_path) - # Move the existing hooks somewhere safe - FileUtils.mv( - local_hooks_path, - "#{local_hooks_path}.old.#{Time.now.to_i}" - ) if File.exist?(local_hooks_path) + if File.exist?(local_hooks_path) + # Move the existing hooks somewhere safe + FileUtils.mv( + local_hooks_path, + "#{local_hooks_path}.old.#{Time.now.to_i}") + end # Create the hooks symlink FileUtils.ln_sf(global_hooks_path, local_hooks_path) diff --git a/rubocop/cop/active_record_dependent.rb b/rubocop/cop/active_record_dependent.rb deleted file mode 100644 index 8d15f150885..00000000000 --- a/rubocop/cop/active_record_dependent.rb +++ /dev/null @@ -1,26 +0,0 @@ -require_relative '../model_helpers' - -module RuboCop - module Cop - # Cop that prevents the use of `dependent: ...` in ActiveRecord models. - class ActiveRecordDependent < RuboCop::Cop::Cop - include ModelHelpers - - MSG = 'Do not use `dependent: to remove associated data, ' \ - 'use foreign keys with cascading deletes instead'.freeze - - METHOD_NAMES = [:has_many, :has_one, :belongs_to].freeze - - def on_send(node) - return unless in_model?(node) - return unless METHOD_NAMES.include?(node.children[1]) - - node.children.last.each_node(:pair) do |pair| - key_name = pair.children[0].children[0] - - add_offense(pair, :expression) if key_name == :dependent - end - end - end - end -end diff --git a/rubocop/cop/active_record_serialize.rb b/rubocop/cop/active_record_serialize.rb deleted file mode 100644 index 204caf37f8b..00000000000 --- a/rubocop/cop/active_record_serialize.rb +++ /dev/null @@ -1,18 +0,0 @@ -require_relative '../model_helpers' - -module RuboCop - module Cop - # Cop that prevents the use of `serialize` in ActiveRecord models. - class ActiveRecordSerialize < RuboCop::Cop::Cop - include ModelHelpers - - MSG = 'Do not store serialized data in the database, use separate columns and/or tables instead'.freeze - - def on_send(node) - return unless in_model?(node) - - add_offense(node, :selector) if node.children[1] == :serialize - end - end - end -end diff --git a/rubocop/cop/custom_error_class.rb b/rubocop/cop/custom_error_class.rb deleted file mode 100644 index 38d93acfe88..00000000000 --- a/rubocop/cop/custom_error_class.rb +++ /dev/null @@ -1,64 +0,0 @@ -module RuboCop - module Cop - # This cop makes sure that custom error classes, when empty, are declared - # with Class.new. - # - # @example - # # bad - # class FooError < StandardError - # end - # - # # okish - # class FooError < StandardError; end - # - # # good - # FooError = Class.new(StandardError) - class CustomErrorClass < RuboCop::Cop::Cop - MSG = 'Use `Class.new(SuperClass)` to define an empty custom error class.'.freeze - - def on_class(node) - _klass, parent, body = node.children - - return if body - - parent_klass = class_name_from_node(parent) - - return unless parent_klass && parent_klass.to_s.end_with?('Error') - - add_offense(node, :expression) - end - - def autocorrect(node) - klass, parent, _body = node.children - replacement = "#{class_name_from_node(klass)} = Class.new(#{class_name_from_node(parent)})" - - lambda do |corrector| - corrector.replace(node.source_range, replacement) - end - end - - private - - # The nested constant `Foo::Bar::Baz` looks like: - # - # s(:const, - # s(:const, - # s(:const, nil, :Foo), :Bar), :Baz) - # - # So recurse through that to get the name as written in the source. - # - def class_name_from_node(node, suffix = nil) - return unless node&.type == :const - - name = node.children[1].to_s - name = "#{name}::#{suffix}" if suffix - - if node.children[0] - class_name_from_node(node.children[0], name) - else - name - end - end - end - end -end diff --git a/rubocop/cop/gem_fetcher.rb b/rubocop/cop/gem_fetcher.rb deleted file mode 100644 index e157d8e0791..00000000000 --- a/rubocop/cop/gem_fetcher.rb +++ /dev/null @@ -1,37 +0,0 @@ -module RuboCop - module Cop - # This cop prevents usage of the `git` and `github` arguments to `gem` in a - # `Gemfile` in order to avoid additional points of failure beyond - # rubygems.org. - class GemFetcher < RuboCop::Cop::Cop - MSG = 'Do not use gems from git repositories, only use gems from RubyGems.'.freeze - - GIT_KEYS = [:git, :github].freeze - - def on_send(node) - return unless gemfile?(node) - - func_name = node.children[1] - return unless func_name == :gem - - node.children.last.each_node(:pair) do |pair| - key_name = pair.children[0].children[0].to_sym - if GIT_KEYS.include?(key_name) - add_offense(node, pair.source_range, MSG) - end - end - end - - private - - def gemfile?(node) - node - .location - .expression - .source_buffer - .name - .end_with?("Gemfile") - end - end - end -end diff --git a/rubocop/cop/gitlab/module_with_instance_variables.rb b/rubocop/cop/gitlab/module_with_instance_variables.rb index 5c9cde98512..dd8bd2dfdf0 100644 --- a/rubocop/cop/gitlab/module_with_instance_variables.rb +++ b/rubocop/cop/gitlab/module_with_instance_variables.rb @@ -30,12 +30,12 @@ module RuboCop if only_ivar_or_assignment?(definition) # We don't allow if any other ivar is used definition.each_descendant(:ivar) do |offense| - add_offense(offense, :expression) + add_offense(offense, location: :expression) end # We allow initialize method and single ivar elsif !initialize_method?(definition) && !single_ivar?(definition) definition.each_descendant(:ivar, :ivasgn) do |offense| - add_offense(offense, :expression) + add_offense(offense, location: :expression) end end end diff --git a/rubocop/cop/in_batches.rb b/rubocop/cop/in_batches.rb deleted file mode 100644 index c0240187e66..00000000000 --- a/rubocop/cop/in_batches.rb +++ /dev/null @@ -1,16 +0,0 @@ -require_relative '../model_helpers' - -module RuboCop - module Cop - # Cop that prevents the use of `in_batches` - class InBatches < RuboCop::Cop::Cop - MSG = 'Do not use `in_batches`, use `each_batch` from the EachBatch module instead'.freeze - - def on_send(node) - return unless node.children[1] == :in_batches - - add_offense(node, :selector) - end - end - end -end diff --git a/rubocop/cop/include_sidekiq_worker.rb b/rubocop/cop/include_sidekiq_worker.rb index 4a6332286a2..8da4a147219 100644 --- a/rubocop/cop/include_sidekiq_worker.rb +++ b/rubocop/cop/include_sidekiq_worker.rb @@ -9,14 +9,14 @@ module RuboCop MSG = 'Include `ApplicationWorker`, not `Sidekiq::Worker`.'.freeze def_node_matcher :includes_sidekiq_worker?, <<~PATTERN - (send nil :include (const (const nil :Sidekiq) :Worker)) + (send nil? :include (const (const nil? :Sidekiq) :Worker)) PATTERN def on_send(node) return if in_spec?(node) return unless includes_sidekiq_worker?(node) - add_offense(node.arguments.first, :expression) + add_offense(node.arguments.first, location: :expression) end def autocorrect(node) diff --git a/rubocop/cop/line_break_after_guard_clauses.rb b/rubocop/cop/line_break_after_guard_clauses.rb deleted file mode 100644 index 67477f064ab..00000000000 --- a/rubocop/cop/line_break_after_guard_clauses.rb +++ /dev/null @@ -1,100 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module Cop - # Ensures a line break after guard clauses. - # - # @example - # # bad - # return unless condition - # do_stuff - # - # # good - # return unless condition - # - # do_stuff - # - # # bad - # raise if condition - # do_stuff - # - # # good - # raise if condition - # - # do_stuff - # - # Multiple guard clauses are allowed without - # line break. - # - # # good - # return unless condition_a - # return unless condition_b - # - # do_stuff - # - # Guard clauses in case statement are allowed without - # line break. - # - # # good - # case model - # when condition_a - # return true unless condition_b - # when - # ... - # end - # - # Guard clauses before end are allowed without - # line break. - # - # # good - # if condition_a - # do_something - # else - # do_something_else - # return unless condition - # end - # - # do_something_more - class LineBreakAfterGuardClauses < RuboCop::Cop::Cop - MSG = 'Add a line break after guard clauses' - - def_node_matcher :guard_clause_node?, <<-PATTERN - [{(send nil? {:raise :fail :throw} ...) return break next} single_line?] - PATTERN - - def on_if(node) - return unless node.single_line? - return unless guard_clause?(node) - return if next_line(node).blank? || clause_last_line?(next_line(node)) || guard_clause?(next_sibling(node)) - - add_offense(node, :expression, MSG) - end - - def autocorrect(node) - lambda do |corrector| - corrector.insert_after(node.loc.expression, "\n") - end - end - - private - - def guard_clause?(node) - return false unless node.if_type? - - guard_clause_node?(node.if_branch) - end - - def next_sibling(node) - node.parent.children[node.sibling_index + 1] - end - - def next_line(node) - processed_source[node.loc.line] - end - - def clause_last_line?(line) - line =~ /^\s*(?:end|elsif|else|when|rescue|ensure)/ - end - end - end -end diff --git a/rubocop/cop/migration/add_column.rb b/rubocop/cop/migration/add_column.rb index d2cf36c454a..2530d6477e8 100644 --- a/rubocop/cop/migration/add_column.rb +++ b/rubocop/cop/migration/add_column.rb @@ -29,7 +29,7 @@ module RuboCop opts.each_node(:pair) do |pair| if hash_key_type(pair) == :sym && hash_key_name(pair) == :default - add_offense(node, :selector) + add_offense(node, location: :selector) end end end diff --git a/rubocop/cop/migration/add_concurrent_foreign_key.rb b/rubocop/cop/migration/add_concurrent_foreign_key.rb index d1fc94d55be..d78c7b9b043 100644 --- a/rubocop/cop/migration/add_concurrent_foreign_key.rb +++ b/rubocop/cop/migration/add_concurrent_foreign_key.rb @@ -15,7 +15,7 @@ module RuboCop name = node.children[1] - add_offense(node, :selector) if name == :add_foreign_key + add_offense(node, location: :selector) if name == :add_foreign_key end def method_name(node) diff --git a/rubocop/cop/migration/add_concurrent_index.rb b/rubocop/cop/migration/add_concurrent_index.rb index 69852f4d580..a2e4ac72565 100644 --- a/rubocop/cop/migration/add_concurrent_index.rb +++ b/rubocop/cop/migration/add_concurrent_index.rb @@ -21,7 +21,7 @@ module RuboCop node.each_ancestor(:def) do |def_node| next unless method_name(def_node) == :change - add_offense(def_node, :name) + add_offense(def_node, location: :name) end end diff --git a/rubocop/cop/migration/add_index.rb b/rubocop/cop/migration/add_index.rb index fa21a0d6555..4aea3c0cce3 100644 --- a/rubocop/cop/migration/add_index.rb +++ b/rubocop/cop/migration/add_index.rb @@ -27,7 +27,7 @@ module RuboCop # data in these tables yet. next if new_tables.include?(first_arg) - add_offense(send_node, :selector) + add_offense(send_node, location: :selector) end end diff --git a/rubocop/cop/migration/add_timestamps.rb b/rubocop/cop/migration/add_timestamps.rb index 08ddd91e54d..ba32d6a9960 100644 --- a/rubocop/cop/migration/add_timestamps.rb +++ b/rubocop/cop/migration/add_timestamps.rb @@ -13,7 +13,7 @@ module RuboCop def on_send(node) return unless in_migration?(node) - add_offense(node, :selector) if method_name(node) == :add_timestamps + add_offense(node, location: :selector) if method_name(node) == :add_timestamps end def method_name(node) diff --git a/rubocop/cop/migration/datetime.rb b/rubocop/cop/migration/datetime.rb index 9cba3c35b26..03ad3f3f601 100644 --- a/rubocop/cop/migration/datetime.rb +++ b/rubocop/cop/migration/datetime.rb @@ -17,7 +17,7 @@ module RuboCop method_name = node.children[1] if method_name == :datetime || method_name == :timestamp - add_offense(send_node, :selector, format(MSG, method_name)) + add_offense(send_node, location: :selector, message: format(MSG, method_name)) end end end @@ -32,7 +32,7 @@ module RuboCop last_argument = descendant.children.last if last_argument == :datetime || last_argument == :timestamp - add_offense(node, :expression, format(MSG, last_argument)) + add_offense(node, location: :expression, message: format(MSG, last_argument)) end end end diff --git a/rubocop/cop/migration/hash_index.rb b/rubocop/cop/migration/hash_index.rb index 2cc59691d84..3206b73bd3d 100644 --- a/rubocop/cop/migration/hash_index.rb +++ b/rubocop/cop/migration/hash_index.rb @@ -29,7 +29,7 @@ module RuboCop hash_key_name(pair) == :using if hash_key_value(pair).to_s == 'hash' - add_offense(pair, :expression) + add_offense(pair, location: :expression) end end end diff --git a/rubocop/cop/migration/remove_column.rb b/rubocop/cop/migration/remove_column.rb index e53eb2e07b2..fffb4ab7fab 100644 --- a/rubocop/cop/migration/remove_column.rb +++ b/rubocop/cop/migration/remove_column.rb @@ -20,7 +20,7 @@ module RuboCop send_method = send_node.children[1] if send_method == :remove_column - add_offense(send_node, :selector) + add_offense(send_node, location: :selector) end end end diff --git a/rubocop/cop/migration/remove_concurrent_index.rb b/rubocop/cop/migration/remove_concurrent_index.rb index 268c49865cb..2328740cf36 100644 --- a/rubocop/cop/migration/remove_concurrent_index.rb +++ b/rubocop/cop/migration/remove_concurrent_index.rb @@ -16,7 +16,7 @@ module RuboCop return unless node.children[1] == :remove_concurrent_index node.each_ancestor(:def) do |def_node| - add_offense(def_node, :name) if method_name(def_node) == :change + add_offense(def_node, location: :name) if method_name(def_node) == :change end end diff --git a/rubocop/cop/migration/remove_index.rb b/rubocop/cop/migration/remove_index.rb index 613b35dd00d..4df3b1ba756 100644 --- a/rubocop/cop/migration/remove_index.rb +++ b/rubocop/cop/migration/remove_index.rb @@ -13,7 +13,7 @@ module RuboCop return unless in_migration?(node) node.each_descendant(:send) do |send_node| - add_offense(send_node, :selector) if method_name(send_node) == :remove_index + add_offense(send_node, location: :selector) if method_name(send_node) == :remove_index end end diff --git a/rubocop/cop/migration/reversible_add_column_with_default.rb b/rubocop/cop/migration/reversible_add_column_with_default.rb index f413f06f39b..dd49188defa 100644 --- a/rubocop/cop/migration/reversible_add_column_with_default.rb +++ b/rubocop/cop/migration/reversible_add_column_with_default.rb @@ -9,7 +9,7 @@ module RuboCop include MigrationHelpers def_node_matcher :add_column_with_default?, <<~PATTERN - (send nil :add_column_with_default $...) + (send nil? :add_column_with_default $...) PATTERN def_node_matcher :defines_change?, <<~PATTERN @@ -26,7 +26,7 @@ module RuboCop node.each_ancestor(:def) do |def_node| next unless defines_change?(def_node) - add_offense(def_node, :name) + add_offense(def_node, location: :name) end end end diff --git a/rubocop/cop/migration/safer_boolean_column.rb b/rubocop/cop/migration/safer_boolean_column.rb index 0335c25d85d..dc5c55df6fb 100644 --- a/rubocop/cop/migration/safer_boolean_column.rb +++ b/rubocop/cop/migration/safer_boolean_column.rb @@ -28,7 +28,7 @@ module RuboCop ].freeze def_node_matcher :add_column?, <<~PATTERN - (send nil :add_column $...) + (send nil? :add_column $...) PATTERN def on_send(node) @@ -54,7 +54,7 @@ module RuboCop NULL_OFFENSE end - add_offense(node, :expression, format(offense, table)) if offense + add_offense(node, location: :expression, message: format(offense, table)) if offense end def no_default?(opts) diff --git a/rubocop/cop/migration/timestamps.rb b/rubocop/cop/migration/timestamps.rb index 71a9420cc3b..6cf5648b996 100644 --- a/rubocop/cop/migration/timestamps.rb +++ b/rubocop/cop/migration/timestamps.rb @@ -14,7 +14,7 @@ module RuboCop return unless in_migration?(node) node.each_descendant(:send) do |send_node| - add_offense(send_node, :selector) if method_name(send_node) == :timestamps + add_offense(send_node, location: :selector) if method_name(send_node) == :timestamps end end diff --git a/rubocop/cop/migration/update_column_in_batches.rb b/rubocop/cop/migration/update_column_in_batches.rb index 3f886cbfea3..db2b5564297 100644 --- a/rubocop/cop/migration/update_column_in_batches.rb +++ b/rubocop/cop/migration/update_column_in_batches.rb @@ -18,7 +18,7 @@ module RuboCop spec_path = spec_filename(node) unless File.exist?(File.expand_path(spec_path, rails_root)) - add_offense(node, :expression, format(MSG, spec_path)) + add_offense(node, location: :expression, message: format(MSG, spec_path)) end end diff --git a/rubocop/cop/migration/update_large_table.rb b/rubocop/cop/migration/update_large_table.rb index 3ae3fb1b68e..bb14d0f4f56 100644 --- a/rubocop/cop/migration/update_large_table.rb +++ b/rubocop/cop/migration/update_large_table.rb @@ -35,7 +35,7 @@ module RuboCop ].freeze def_node_matcher :batch_update?, <<~PATTERN - (send nil ${:add_column_with_default :update_column_in_batches} $(sym ...) ...) + (send nil? ${:add_column_with_default :update_column_in_batches} $(sym ...) ...) PATTERN def on_send(node) @@ -49,7 +49,7 @@ module RuboCop return unless LARGE_TABLES.include?(table) - add_offense(node, :expression, format(MSG, update_method, table)) + add_offense(node, location: :expression, message: format(MSG, update_method, table)) end end end diff --git a/rubocop/cop/polymorphic_associations.rb b/rubocop/cop/polymorphic_associations.rb deleted file mode 100644 index 7d554704550..00000000000 --- a/rubocop/cop/polymorphic_associations.rb +++ /dev/null @@ -1,23 +0,0 @@ -require_relative '../model_helpers' - -module RuboCop - module Cop - # Cop that prevents the use of polymorphic associations - class PolymorphicAssociations < RuboCop::Cop::Cop - include ModelHelpers - - MSG = 'Do not use polymorphic associations, use separate tables instead'.freeze - - def on_send(node) - return unless in_model?(node) - return unless node.children[1] == :belongs_to - - node.children.last.each_node(:pair) do |pair| - key_name = pair.children[0].children[0] - - add_offense(pair, :expression) if key_name == :polymorphic - end - end - end - end -end diff --git a/rubocop/cop/project_path_helper.rb b/rubocop/cop/project_path_helper.rb index 3e1ce71ac06..f3810622eb1 100644 --- a/rubocop/cop/project_path_helper.rb +++ b/rubocop/cop/project_path_helper.rb @@ -17,7 +17,7 @@ module RuboCop return unless method_name(namespace_expr) == :namespace return unless receiver(namespace_expr) == project_expr - add_offense(node, :selector) + add_offense(node, location: :selector) end def autocorrect(node) diff --git a/rubocop/cop/redirect_with_status.rb b/rubocop/cop/redirect_with_status.rb deleted file mode 100644 index 36810642c88..00000000000 --- a/rubocop/cop/redirect_with_status.rb +++ /dev/null @@ -1,44 +0,0 @@ -module RuboCop - module Cop - # This cop prevents usage of 'redirect_to' in actions 'destroy' without specifying 'status'. - # See https://gitlab.com/gitlab-org/gitlab-ce/issues/31840 - class RedirectWithStatus < RuboCop::Cop::Cop - MSG = 'Do not use "redirect_to" without "status" in "destroy" action'.freeze - - def on_def(node) - return unless in_controller?(node) - return unless destroy?(node) || destroy_all?(node) - - node.each_descendant(:send) do |def_node| - next unless redirect_to?(def_node) - - methods = [] - - def_node.children.last.each_node(:pair) do |pair| - methods << pair.children.first.children.first - end - - add_offense(def_node, :selector) unless methods.include?(:status) - end - end - - private - - def in_controller?(node) - node.location.expression.source_buffer.name.end_with?('_controller.rb') - end - - def destroy?(node) - node.children.first == :destroy - end - - def destroy_all?(node) - node.children.first == :destroy_all - end - - def redirect_to?(node) - node.children[1] == :redirect_to - end - end - end -end diff --git a/rubocop/cop/rspec/env_assignment.rb b/rubocop/cop/rspec/env_assignment.rb index 257454af0e1..8b61fa8e264 100644 --- a/rubocop/cop/rspec/env_assignment.rb +++ b/rubocop/cop/rspec/env_assignment.rb @@ -1,4 +1,3 @@ -require 'rubocop-rspec' require_relative '../../spec_helpers' module RuboCop @@ -17,7 +16,7 @@ module RuboCop # before do # stub_env('FOO', 'bar') # end - class EnvAssignment < Cop + class EnvAssignment < RuboCop::Cop::Cop include SpecHelpers MESSAGE = "Don't assign to ENV, use `stub_env` instead.".freeze @@ -32,7 +31,7 @@ module RuboCop return unless in_spec?(node) return unless env_assignment?(node) - add_offense(node, :expression, MESSAGE) + add_offense(node, location: :expression, message: MESSAGE) end def autocorrect(node) diff --git a/rubocop/cop/rspec/single_line_hook.rb b/rubocop/cop/rspec/single_line_hook.rb deleted file mode 100644 index be611054323..00000000000 --- a/rubocop/cop/rspec/single_line_hook.rb +++ /dev/null @@ -1,38 +0,0 @@ -require 'rubocop-rspec' - -module RuboCop - module Cop - module RSpec - # This cop checks for single-line hook blocks - # - # @example - # - # # bad - # before { do_something } - # after(:each) { undo_something } - # - # # good - # before do - # do_something - # end - # - # after(:each) do - # undo_something - # end - class SingleLineHook < Cop - MESSAGE = "Don't use single-line hook blocks.".freeze - - def_node_search :rspec_hook?, <<~PATTERN - (send nil {:after :around :before} ...) - PATTERN - - def on_block(node) - return unless rspec_hook?(node) - return unless node.single_line? - - add_offense(node, :expression, MESSAGE) - end - end - end - end -end diff --git a/rubocop/cop/rspec/verbose_include_metadata.rb b/rubocop/cop/rspec/verbose_include_metadata.rb deleted file mode 100644 index 58390622d60..00000000000 --- a/rubocop/cop/rspec/verbose_include_metadata.rb +++ /dev/null @@ -1,74 +0,0 @@ -# frozen_string_literal: true - -require 'rubocop-rspec' - -module RuboCop - module Cop - module RSpec - # Checks for verbose include metadata used in the specs. - # - # @example - # # bad - # describe MyClass, js: true do - # end - # - # # good - # describe MyClass, :js do - # end - class VerboseIncludeMetadata < Cop - MSG = 'Use `%s` instead of `%s`.' - - SELECTORS = %i[describe context feature example_group it specify example scenario its].freeze - - def_node_matcher :include_metadata, <<-PATTERN - (send {(const nil :RSpec) nil} {#{SELECTORS.map(&:inspect).join(' ')}} - !const - ... - (hash $...)) - PATTERN - - def_node_matcher :invalid_metadata?, <<-PATTERN - (pair - (sym $...) - (true)) - PATTERN - - def on_send(node) - invalid_metadata_matches(node) do |match| - add_offense(node, :expression, format(MSG, good(match), bad(match))) - end - end - - def autocorrect(node) - lambda do |corrector| - invalid_metadata_matches(node) do |match| - corrector.replace(match.loc.expression, good(match)) - end - end - end - - private - - def invalid_metadata_matches(node) - include_metadata(node) do |matches| - matches.select(&method(:invalid_metadata?)).each do |match| - yield match - end - end - end - - def bad(match) - "#{metadata_key(match)}: true" - end - - def good(match) - ":#{metadata_key(match)}" - end - - def metadata_key(match) - match.children[0].source - end - end - end - end -end diff --git a/rubocop/cop/sidekiq_options_queue.rb b/rubocop/cop/sidekiq_options_queue.rb index 43b35ba0214..253d2958866 100644 --- a/rubocop/cop/sidekiq_options_queue.rb +++ b/rubocop/cop/sidekiq_options_queue.rb @@ -9,7 +9,7 @@ module RuboCop MSG = 'Do not manually set a queue; `ApplicationWorker` sets one automatically.'.freeze def_node_matcher :sidekiq_options?, <<~PATTERN - (send nil :sidekiq_options $...) + (send nil? :sidekiq_options $...) PATTERN def on_send(node) @@ -19,7 +19,7 @@ module RuboCop node.arguments.first.each_node(:pair) do |pair| key_name = pair.key.children[0] - add_offense(pair, :expression) if key_name == :queue + add_offense(pair, location: :expression) if key_name == :queue end end end diff --git a/rubocop/model_helpers.rb b/rubocop/model_helpers.rb deleted file mode 100644 index 309723dc34c..00000000000 --- a/rubocop/model_helpers.rb +++ /dev/null @@ -1,11 +0,0 @@ -module RuboCop - module ModelHelpers - # Returns true if the given node originated from the models directory. - def in_model?(node) - path = node.location.expression.source_buffer.name - models_path = File.join(Dir.pwd, 'app', 'models') - - path.start_with?(models_path) - end - end -end diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb index 8aa82e9413d..26087f15984 100644 --- a/rubocop/rubocop.rb +++ b/rubocop/rubocop.rb @@ -1,15 +1,6 @@ require_relative 'cop/active_record_dependent' -require_relative 'cop/active_record_serialize' -require_relative 'cop/custom_error_class' -require_relative 'cop/gem_fetcher' -require_relative 'cop/in_batches' -require_relative 'cop/include_sidekiq_worker' -require_relative 'cop/line_break_after_guard_clauses' -require_relative 'cop/polymorphic_associations' -require_relative 'cop/project_path_helper' -require_relative 'cop/redirect_with_status' require_relative 'cop/gitlab/module_with_instance_variables' -require_relative 'cop/sidekiq_options_queue' +require_relative 'cop/include_sidekiq_worker' require_relative 'cop/migration/add_column' require_relative 'cop/migration/add_concurrent_foreign_key' require_relative 'cop/migration/add_concurrent_index' @@ -25,6 +16,8 @@ require_relative 'cop/migration/safer_boolean_column' require_relative 'cop/migration/timestamps' require_relative 'cop/migration/update_column_in_batches' require_relative 'cop/migration/update_large_table' +require_relative 'cop/project_path_helper' require_relative 'cop/rspec/env_assignment' require_relative 'cop/rspec/single_line_hook' require_relative 'cop/rspec/verbose_include_metadata' +require_relative 'cop/sidekiq_options_queue' diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb index 5ed6b017dee..71dc169c6a2 100644 --- a/spec/factories/issues.rb +++ b/spec/factories/issues.rb @@ -14,6 +14,7 @@ FactoryBot.define do trait :closed do state :closed + closed_at { Time.now } end factory :closed_issue, traits: [:closed] diff --git a/spec/rubocop/cop/active_record_dependent_spec.rb b/spec/rubocop/cop/active_record_dependent_spec.rb deleted file mode 100644 index 599a032bfc5..00000000000 --- a/spec/rubocop/cop/active_record_dependent_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -require 'spec_helper' -require 'rubocop' -require 'rubocop/rspec/support' -require_relative '../../../rubocop/cop/active_record_dependent' - -describe RuboCop::Cop::ActiveRecordDependent do - include CopHelper - - subject(:cop) { described_class.new } - - context 'inside the app/models directory' do - it 'registers an offense when dependent: is used' do - allow(cop).to receive(:in_model?).and_return(true) - - inspect_source(cop, 'belongs_to :foo, dependent: :destroy') - - aggregate_failures do - expect(cop.offenses.size).to eq(1) - expect(cop.offenses.map(&:line)).to eq([1]) - end - end - end - - context 'outside the app/models directory' do - it 'does nothing' do - allow(cop).to receive(:in_model?).and_return(false) - - inspect_source(cop, 'belongs_to :foo, dependent: :destroy') - - expect(cop.offenses).to be_empty - end - end -end diff --git a/spec/rubocop/cop/active_record_serialize_spec.rb b/spec/rubocop/cop/active_record_serialize_spec.rb deleted file mode 100644 index b94b25cecd0..00000000000 --- a/spec/rubocop/cop/active_record_serialize_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -require 'spec_helper' -require 'rubocop' -require 'rubocop/rspec/support' -require_relative '../../../rubocop/cop/active_record_serialize' - -describe RuboCop::Cop::ActiveRecordSerialize do - include CopHelper - - subject(:cop) { described_class.new } - - context 'inside the app/models directory' do - it 'registers an offense when serialize is used' do - allow(cop).to receive(:in_model?).and_return(true) - - inspect_source(cop, 'serialize :foo') - - aggregate_failures do - expect(cop.offenses.size).to eq(1) - expect(cop.offenses.map(&:line)).to eq([1]) - end - end - end - - context 'outside the app/models directory' do - it 'does nothing' do - allow(cop).to receive(:in_model?).and_return(false) - - inspect_source(cop, 'serialize :foo') - - expect(cop.offenses).to be_empty - end - end -end diff --git a/spec/rubocop/cop/custom_error_class_spec.rb b/spec/rubocop/cop/custom_error_class_spec.rb deleted file mode 100644 index 381d7871a40..00000000000 --- a/spec/rubocop/cop/custom_error_class_spec.rb +++ /dev/null @@ -1,111 +0,0 @@ -require 'spec_helper' - -require 'rubocop' -require 'rubocop/rspec/support' - -require_relative '../../../rubocop/cop/custom_error_class' - -describe RuboCop::Cop::CustomErrorClass do - include CopHelper - - subject(:cop) { described_class.new } - - context 'when a class has a body' do - it 'does nothing' do - inspect_source(cop, 'class CustomError < StandardError; def foo; end; end') - - expect(cop.offenses).to be_empty - end - end - - context 'when a class has no explicit superclass' do - it 'does nothing' do - inspect_source(cop, 'class CustomError; end') - - expect(cop.offenses).to be_empty - end - end - - context 'when a class has a superclass that does not end in Error' do - it 'does nothing' do - inspect_source(cop, 'class CustomError < BasicObject; end') - - expect(cop.offenses).to be_empty - end - end - - context 'when a class is empty and inherits from a class ending in Error' do - context 'when the class is on a single line' do - let(:source) do - <<-SOURCE - module Foo - class CustomError < Bar::Baz::BaseError; end - end - SOURCE - end - - let(:expected) do - <<-EXPECTED - module Foo - CustomError = Class.new(Bar::Baz::BaseError) - end - EXPECTED - end - - it 'registers an offense' do - expected_highlights = source.split("\n")[1].strip - - inspect_source(cop, source) - - aggregate_failures do - expect(cop.offenses.size).to eq(1) - expect(cop.offenses.map(&:line)).to eq([2]) - expect(cop.highlights).to contain_exactly(expected_highlights) - end - end - - it 'autocorrects to the right version' do - autocorrected = autocorrect_source(cop, source, 'foo/custom_error.rb') - - expect(autocorrected).to eq(expected) - end - end - - context 'when the class is on multiple lines' do - let(:source) do - <<-SOURCE - module Foo - class CustomError < Bar::Baz::BaseError - end - end - SOURCE - end - - let(:expected) do - <<-EXPECTED - module Foo - CustomError = Class.new(Bar::Baz::BaseError) - end - EXPECTED - end - - it 'registers an offense' do - expected_highlights = source.split("\n")[1..2].join("\n").strip - - inspect_source(cop, source) - - aggregate_failures do - expect(cop.offenses.size).to eq(1) - expect(cop.offenses.map(&:line)).to eq([2]) - expect(cop.highlights).to contain_exactly(expected_highlights) - end - end - - it 'autocorrects to the right version' do - autocorrected = autocorrect_source(cop, source, 'foo/custom_error.rb') - - expect(autocorrected).to eq(expected) - end - end - end -end diff --git a/spec/rubocop/cop/gem_fetcher_spec.rb b/spec/rubocop/cop/gem_fetcher_spec.rb deleted file mode 100644 index c07f6a831dc..00000000000 --- a/spec/rubocop/cop/gem_fetcher_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -require 'spec_helper' - -require 'rubocop' -require 'rubocop/rspec/support' - -require_relative '../../../rubocop/cop/gem_fetcher' - -describe RuboCop::Cop::GemFetcher do - include CopHelper - - subject(:cop) { described_class.new } - - context 'in Gemfile' do - before do - allow(cop).to receive(:gemfile?).and_return(true) - end - - it 'registers an offense when a gem uses `git`' do - inspect_source(cop, 'gem "foo", git: "https://gitlab.com/foo/bar.git"') - - aggregate_failures do - expect(cop.offenses.size).to eq(1) - expect(cop.offenses.map(&:line)).to eq([1]) - expect(cop.highlights).to eq(['git: "https://gitlab.com/foo/bar.git"']) - end - end - - it 'registers an offense when a gem uses `github`' do - inspect_source(cop, 'gem "foo", github: "foo/bar.git"') - - aggregate_failures do - expect(cop.offenses.size).to eq(1) - expect(cop.offenses.map(&:line)).to eq([1]) - expect(cop.highlights).to eq(['github: "foo/bar.git"']) - end - end - end - - context 'outside of Gemfile' do - it 'registers no offense' do - inspect_source(cop, 'gem "foo", git: "https://gitlab.com/foo/bar.git"') - - expect(cop.offenses.size).to eq(0) - end - end -end diff --git a/spec/rubocop/cop/gitlab/module_with_instance_variables_spec.rb b/spec/rubocop/cop/gitlab/module_with_instance_variables_spec.rb index 1fd40653f79..8e2d5f70353 100644 --- a/spec/rubocop/cop/gitlab/module_with_instance_variables_spec.rb +++ b/spec/rubocop/cop/gitlab/module_with_instance_variables_spec.rb @@ -12,7 +12,7 @@ describe RuboCop::Cop::Gitlab::ModuleWithInstanceVariables do let(:offending_lines) { options[:offending_lines] } it 'registers an offense when instance variable is used in a module' do - inspect_source(cop, source) + inspect_source(source) aggregate_failures do expect(cop.offenses.size).to eq(offending_lines.size) @@ -23,7 +23,7 @@ describe RuboCop::Cop::Gitlab::ModuleWithInstanceVariables do shared_examples('not registering offense') do it 'does not register offenses' do - inspect_source(cop, source) + inspect_source(source) expect(cop.offenses).to be_empty end diff --git a/spec/rubocop/cop/in_batches_spec.rb b/spec/rubocop/cop/in_batches_spec.rb deleted file mode 100644 index 072481984c6..00000000000 --- a/spec/rubocop/cop/in_batches_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'spec_helper' -require 'rubocop' -require 'rubocop/rspec/support' -require_relative '../../../rubocop/cop/in_batches' - -describe RuboCop::Cop::InBatches do - include CopHelper - - subject(:cop) { described_class.new } - - it 'registers an offense when in_batches is used' do - inspect_source(cop, 'foo.in_batches do; end') - - aggregate_failures do - expect(cop.offenses.size).to eq(1) - expect(cop.offenses.map(&:line)).to eq([1]) - end - end -end diff --git a/spec/rubocop/cop/include_sidekiq_worker_spec.rb b/spec/rubocop/cop/include_sidekiq_worker_spec.rb index 7f406535dda..f5109287876 100644 --- a/spec/rubocop/cop/include_sidekiq_worker_spec.rb +++ b/spec/rubocop/cop/include_sidekiq_worker_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' + require 'rubocop' require 'rubocop/rspec/support' + require_relative '../../../rubocop/cop/include_sidekiq_worker' describe RuboCop::Cop::IncludeSidekiqWorker do @@ -13,7 +15,7 @@ describe RuboCop::Cop::IncludeSidekiqWorker do let(:correct_source) { 'include ApplicationWorker' } it 'registers an offense ' do - inspect_source(cop, source) + inspect_source(source) aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -23,7 +25,7 @@ describe RuboCop::Cop::IncludeSidekiqWorker do end it 'autocorrects to the right version' do - autocorrected = autocorrect_source(cop, source) + autocorrected = autocorrect_source(source) expect(autocorrected).to eq(correct_source) end diff --git a/spec/rubocop/cop/line_break_after_guard_clauses_spec.rb b/spec/rubocop/cop/line_break_after_guard_clauses_spec.rb deleted file mode 100644 index 8899dc85384..00000000000 --- a/spec/rubocop/cop/line_break_after_guard_clauses_spec.rb +++ /dev/null @@ -1,160 +0,0 @@ -require 'spec_helper' -require 'rubocop' -require 'rubocop/rspec/support' -require_relative '../../../rubocop/cop/line_break_after_guard_clauses' - -describe RuboCop::Cop::LineBreakAfterGuardClauses do - include CopHelper - - subject(:cop) { described_class.new } - - shared_examples 'examples with guard clause' do |title| - %w[if unless].each do |conditional| - it "flags violation for #{title} #{conditional} without line breaks" do - source = <<~RUBY - #{title} #{conditional} condition - do_stuff - RUBY - inspect_source(cop, source) - - expect(cop.offenses.size).to eq(1) - offense = cop.offenses.first - - expect(offense.line).to eq(1) - expect(cop.highlights).to eq(["#{title} #{conditional} condition"]) - expect(offense.message).to eq('Add a line break after guard clauses') - end - - it "doesn't flag violation for #{title} #{conditional} with line break" do - source = <<~RUBY - #{title} #{conditional} condition - - do_stuff - RUBY - inspect_source(cop, source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{title} #{conditional} on multiple lines without line break" do - source = <<~RUBY - #{conditional} condition - #{title} - end - do_stuff - RUBY - inspect_source(cop, source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{title} #{conditional} without line breaks when followed by end keyword" do - source = <<~RUBY - def test - #{title} #{conditional} condition - end - RUBY - inspect_source(cop, source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{title} #{conditional} without line breaks when followed by elsif keyword" do - source = <<~RUBY - if model - #{title} #{conditional} condition - elsif - do_something - end - RUBY - inspect_source(cop, source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{title} #{conditional} without line breaks when followed by else keyword" do - source = <<~RUBY - if model - #{title} #{conditional} condition - else - do_something - end - RUBY - inspect_source(cop, source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{title} #{conditional} without line breaks when followed by when keyword" do - source = <<~RUBY - case model - when condition_a - #{title} #{conditional} condition - when condition_b - do_something - end - RUBY - inspect_source(cop, source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{title} #{conditional} without line breaks when followed by rescue keyword" do - source = <<~RUBY - begin - #{title} #{conditional} condition - rescue StandardError - do_something - end - RUBY - inspect_source(cop, source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{title} #{conditional} without line breaks when followed by ensure keyword" do - source = <<~RUBY - def foo - #{title} #{conditional} condition - ensure - do_something - end - RUBY - inspect_source(cop, source) - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{title} #{conditional} without line breaks when followed by another guard clause" do - source = <<~RUBY - #{title} #{conditional} condition - #{title} #{conditional} condition - - do_stuff - RUBY - inspect_source(cop, source) - - expect(cop.offenses).to be_empty - end - - it "autocorrects #{title} #{conditional} guard clauses without line break" do - source = <<~RUBY - #{title} #{conditional} condition - do_stuff - RUBY - autocorrected = autocorrect_source(cop, source) - - expected_source = <<~RUBY - #{title} #{conditional} condition - - do_stuff - RUBY - expect(autocorrected).to eql(expected_source) - end - end - end - - %w[return fail raise next break throw].each do |example| - it_behaves_like 'examples with guard clause', example - end -end diff --git a/spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb b/spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb index 7cb24dc5646..1df1fffb94e 100644 --- a/spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb +++ b/spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' + require 'rubocop' require 'rubocop/rspec/support' + require_relative '../../../../rubocop/cop/migration/add_concurrent_foreign_key' describe RuboCop::Cop::Migration::AddConcurrentForeignKey do @@ -10,7 +12,7 @@ describe RuboCop::Cop::Migration::AddConcurrentForeignKey do context 'outside of a migration' do it 'does not register any offenses' do - inspect_source(cop, 'def up; add_foreign_key(:projects, :users, column: :user_id); end') + inspect_source('def up; add_foreign_key(:projects, :users, column: :user_id); end') expect(cop.offenses).to be_empty end @@ -22,7 +24,7 @@ describe RuboCop::Cop::Migration::AddConcurrentForeignKey do end it 'registers an offense when using add_foreign_key' do - inspect_source(cop, 'def up; add_foreign_key(:projects, :users, column: :user_id); end') + inspect_source('def up; add_foreign_key(:projects, :users, column: :user_id); end') aggregate_failures do expect(cop.offenses.size).to eq(1) diff --git a/spec/rubocop/cop/migration/add_concurrent_index_spec.rb b/spec/rubocop/cop/migration/add_concurrent_index_spec.rb index 19a5718b0b1..9c1ebcc0ced 100644 --- a/spec/rubocop/cop/migration/add_concurrent_index_spec.rb +++ b/spec/rubocop/cop/migration/add_concurrent_index_spec.rb @@ -16,7 +16,7 @@ describe RuboCop::Cop::Migration::AddConcurrentIndex do end it 'registers an offense when add_concurrent_index is used inside a change method' do - inspect_source(cop, 'def change; add_concurrent_index :table, :column; end') + inspect_source('def change; add_concurrent_index :table, :column; end') aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -25,7 +25,7 @@ describe RuboCop::Cop::Migration::AddConcurrentIndex do end it 'registers no offense when add_concurrent_index is used inside an up method' do - inspect_source(cop, 'def up; add_concurrent_index :table, :column; end') + inspect_source('def up; add_concurrent_index :table, :column; end') expect(cop.offenses.size).to eq(0) end @@ -33,7 +33,7 @@ describe RuboCop::Cop::Migration::AddConcurrentIndex do context 'outside of migration' do it 'registers no offense' do - inspect_source(cop, 'def change; add_concurrent_index :table, :column; end') + inspect_source('def change; add_concurrent_index :table, :column; end') expect(cop.offenses.size).to eq(0) end diff --git a/spec/rubocop/cop/migration/add_timestamps_spec.rb b/spec/rubocop/cop/migration/add_timestamps_spec.rb index 18df62dec3e..3a41c91add2 100644 --- a/spec/rubocop/cop/migration/add_timestamps_spec.rb +++ b/spec/rubocop/cop/migration/add_timestamps_spec.rb @@ -53,7 +53,7 @@ describe RuboCop::Cop::Migration::AddTimestamps do end it 'registers an offense when the "add_timestamps" method is used' do - inspect_source(cop, migration_with_add_timestamps) + inspect_source(migration_with_add_timestamps) aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -62,7 +62,7 @@ describe RuboCop::Cop::Migration::AddTimestamps do end it 'does not register an offense when the "add_timestamps" method is not used' do - inspect_source(cop, migration_without_add_timestamps) + inspect_source(migration_without_add_timestamps) aggregate_failures do expect(cop.offenses.size).to eq(0) @@ -70,7 +70,7 @@ describe RuboCop::Cop::Migration::AddTimestamps do end it 'does not register an offense when the "add_timestamps_with_timezone" method is used' do - inspect_source(cop, migration_with_add_timestamps_with_timezone) + inspect_source(migration_with_add_timestamps_with_timezone) aggregate_failures do expect(cop.offenses.size).to eq(0) @@ -80,9 +80,9 @@ describe RuboCop::Cop::Migration::AddTimestamps do context 'outside of migration' do it 'registers no offense' do - inspect_source(cop, migration_with_add_timestamps) - inspect_source(cop, migration_without_add_timestamps) - inspect_source(cop, migration_with_add_timestamps_with_timezone) + inspect_source(migration_with_add_timestamps) + inspect_source(migration_without_add_timestamps) + inspect_source(migration_with_add_timestamps_with_timezone) expect(cop.offenses.size).to eq(0) end diff --git a/spec/rubocop/cop/migration/datetime_spec.rb b/spec/rubocop/cop/migration/datetime_spec.rb index b1dfcf1b048..9e844325371 100644 --- a/spec/rubocop/cop/migration/datetime_spec.rb +++ b/spec/rubocop/cop/migration/datetime_spec.rb @@ -67,7 +67,7 @@ describe RuboCop::Cop::Migration::Datetime do end it 'registers an offense when the ":datetime" data type is used' do - inspect_source(cop, migration_with_datetime) + inspect_source(migration_with_datetime) aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -77,7 +77,7 @@ describe RuboCop::Cop::Migration::Datetime do end it 'registers an offense when the ":timestamp" data type is used' do - inspect_source(cop, migration_with_timestamp) + inspect_source(migration_with_timestamp) aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -87,7 +87,7 @@ describe RuboCop::Cop::Migration::Datetime do end it 'does not register an offense when the ":datetime" data type is not used' do - inspect_source(cop, migration_without_datetime) + inspect_source(migration_without_datetime) aggregate_failures do expect(cop.offenses.size).to eq(0) @@ -95,7 +95,7 @@ describe RuboCop::Cop::Migration::Datetime do end it 'does not register an offense when the ":datetime_with_timezone" data type is used' do - inspect_source(cop, migration_with_datetime_with_timezone) + inspect_source(migration_with_datetime_with_timezone) aggregate_failures do expect(cop.offenses.size).to eq(0) @@ -105,10 +105,10 @@ describe RuboCop::Cop::Migration::Datetime do context 'outside of migration' do it 'registers no offense' do - inspect_source(cop, migration_with_datetime) - inspect_source(cop, migration_with_timestamp) - inspect_source(cop, migration_without_datetime) - inspect_source(cop, migration_with_datetime_with_timezone) + inspect_source(migration_with_datetime) + inspect_source(migration_with_timestamp) + inspect_source(migration_without_datetime) + inspect_source(migration_with_datetime_with_timezone) expect(cop.offenses.size).to eq(0) end diff --git a/spec/rubocop/cop/migration/hash_index_spec.rb b/spec/rubocop/cop/migration/hash_index_spec.rb index 9a8576a19e5..5d53dde9a79 100644 --- a/spec/rubocop/cop/migration/hash_index_spec.rb +++ b/spec/rubocop/cop/migration/hash_index_spec.rb @@ -16,7 +16,7 @@ describe RuboCop::Cop::Migration::HashIndex do end it 'registers an offense when creating a hash index' do - inspect_source(cop, 'def change; add_index :table, :column, using: :hash; end') + inspect_source('def change; add_index :table, :column, using: :hash; end') aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -25,7 +25,7 @@ describe RuboCop::Cop::Migration::HashIndex do end it 'registers an offense when creating a concurrent hash index' do - inspect_source(cop, 'def change; add_concurrent_index :table, :column, using: :hash; end') + inspect_source('def change; add_concurrent_index :table, :column, using: :hash; end') aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -34,7 +34,7 @@ describe RuboCop::Cop::Migration::HashIndex do end it 'registers an offense when creating a hash index using t.index' do - inspect_source(cop, 'def change; t.index :table, :column, using: :hash; end') + inspect_source('def change; t.index :table, :column, using: :hash; end') aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -45,7 +45,7 @@ describe RuboCop::Cop::Migration::HashIndex do context 'outside of migration' do it 'registers no offense' do - inspect_source(cop, 'def change; index :table, :column, using: :hash; end') + inspect_source('def change; index :table, :column, using: :hash; end') expect(cop.offenses.size).to eq(0) end diff --git a/spec/rubocop/cop/migration/remove_column_spec.rb b/spec/rubocop/cop/migration/remove_column_spec.rb index 89112f01723..f1a64f431bd 100644 --- a/spec/rubocop/cop/migration/remove_column_spec.rb +++ b/spec/rubocop/cop/migration/remove_column_spec.rb @@ -21,7 +21,7 @@ describe RuboCop::Cop::Migration::RemoveColumn do end it 'registers an offense when remove_column is used in the change method' do - inspect_source(cop, source('change')) + inspect_source(source('change')) aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -30,7 +30,7 @@ describe RuboCop::Cop::Migration::RemoveColumn do end it 'registers an offense when remove_column is used in the up method' do - inspect_source(cop, source('up')) + inspect_source(source('up')) aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -39,7 +39,7 @@ describe RuboCop::Cop::Migration::RemoveColumn do end it 'registers no offense when remove_column is used in the down method' do - inspect_source(cop, source('down')) + inspect_source(source('down')) expect(cop.offenses.size).to eq(0) end @@ -52,7 +52,7 @@ describe RuboCop::Cop::Migration::RemoveColumn do end it 'registers no offense' do - inspect_source(cop, source) + inspect_source(source) expect(cop.offenses.size).to eq(0) end @@ -60,7 +60,7 @@ describe RuboCop::Cop::Migration::RemoveColumn do context 'outside of a migration' do it 'registers no offense' do - inspect_source(cop, source) + inspect_source(source) expect(cop.offenses.size).to eq(0) end diff --git a/spec/rubocop/cop/migration/remove_concurrent_index_spec.rb b/spec/rubocop/cop/migration/remove_concurrent_index_spec.rb index a714bf4e5d5..a23d5d022e3 100644 --- a/spec/rubocop/cop/migration/remove_concurrent_index_spec.rb +++ b/spec/rubocop/cop/migration/remove_concurrent_index_spec.rb @@ -16,7 +16,7 @@ describe RuboCop::Cop::Migration::RemoveConcurrentIndex do end it 'registers an offense when remove_concurrent_index is used inside a change method' do - inspect_source(cop, 'def change; remove_concurrent_index :table, :column; end') + inspect_source('def change; remove_concurrent_index :table, :column; end') aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -25,7 +25,7 @@ describe RuboCop::Cop::Migration::RemoveConcurrentIndex do end it 'registers no offense when remove_concurrent_index is used inside an up method' do - inspect_source(cop, 'def up; remove_concurrent_index :table, :column; end') + inspect_source('def up; remove_concurrent_index :table, :column; end') expect(cop.offenses.size).to eq(0) end @@ -33,7 +33,7 @@ describe RuboCop::Cop::Migration::RemoveConcurrentIndex do context 'outside of migration' do it 'registers no offense' do - inspect_source(cop, 'def change; remove_concurrent_index :table, :column; end') + inspect_source('def change; remove_concurrent_index :table, :column; end') expect(cop.offenses.size).to eq(0) end diff --git a/spec/rubocop/cop/migration/remove_index_spec.rb b/spec/rubocop/cop/migration/remove_index_spec.rb index 31923cb7429..bbf2227e512 100644 --- a/spec/rubocop/cop/migration/remove_index_spec.rb +++ b/spec/rubocop/cop/migration/remove_index_spec.rb @@ -16,7 +16,7 @@ describe RuboCop::Cop::Migration::RemoveIndex do end it 'registers an offense when remove_index is used' do - inspect_source(cop, 'def change; remove_index :table, :column; end') + inspect_source('def change; remove_index :table, :column; end') aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -27,7 +27,7 @@ describe RuboCop::Cop::Migration::RemoveIndex do context 'outside of migration' do it 'registers no offense' do - inspect_source(cop, 'def change; remove_index :table, :column; end') + inspect_source('def change; remove_index :table, :column; end') expect(cop.offenses.size).to eq(0) end diff --git a/spec/rubocop/cop/migration/reversible_add_column_with_default_spec.rb b/spec/rubocop/cop/migration/reversible_add_column_with_default_spec.rb index 3723d635083..ba8cd2c6c4a 100644 --- a/spec/rubocop/cop/migration/reversible_add_column_with_default_spec.rb +++ b/spec/rubocop/cop/migration/reversible_add_column_with_default_spec.rb @@ -16,7 +16,7 @@ describe RuboCop::Cop::Migration::ReversibleAddColumnWithDefault do end it 'registers an offense when add_column_with_default is used inside a change method' do - inspect_source(cop, 'def change; add_column_with_default :table, :column, default: false; end') + inspect_source('def change; add_column_with_default :table, :column, default: false; end') aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -25,7 +25,7 @@ describe RuboCop::Cop::Migration::ReversibleAddColumnWithDefault do end it 'registers no offense when add_column_with_default is used inside an up method' do - inspect_source(cop, 'def up; add_column_with_default :table, :column, default: false; end') + inspect_source('def up; add_column_with_default :table, :column, default: false; end') expect(cop.offenses.size).to eq(0) end @@ -33,7 +33,7 @@ describe RuboCop::Cop::Migration::ReversibleAddColumnWithDefault do context 'outside of migration' do it 'registers no offense' do - inspect_source(cop, 'def change; add_column_with_default :table, :column, default: false; end') + inspect_source('def change; add_column_with_default :table, :column, default: false; end') expect(cop.offenses.size).to eq(0) end diff --git a/spec/rubocop/cop/migration/safer_boolean_column_spec.rb b/spec/rubocop/cop/migration/safer_boolean_column_spec.rb index 1006594499a..1c4f18fbcc3 100644 --- a/spec/rubocop/cop/migration/safer_boolean_column_spec.rb +++ b/spec/rubocop/cop/migration/safer_boolean_column_spec.rb @@ -32,7 +32,7 @@ describe RuboCop::Cop::Migration::SaferBooleanColumn do sources_and_offense.each do |source, offense| context "given the source \"#{source}\"" do it "registers the offense matching \"#{offense}\"" do - inspect_source(cop, source) + inspect_source(source) aggregate_failures do expect(cop.offenses.first.message).to match(offense) @@ -49,7 +49,7 @@ describe RuboCop::Cop::Migration::SaferBooleanColumn do inoffensive_sources.each do |source| context "given the source \"#{source}\"" do it "registers no offense" do - inspect_source(cop, source) + inspect_source(source) aggregate_failures do expect(cop.offenses).to be_empty @@ -61,14 +61,14 @@ describe RuboCop::Cop::Migration::SaferBooleanColumn do end it 'registers no offense for tables not listed in SMALL_TABLES' do - inspect_source(cop, "add_column :large_table, :column, :boolean") + inspect_source("add_column :large_table, :column, :boolean") expect(cop.offenses).to be_empty end it 'registers no offense for non-boolean columns' do table = described_class::SMALL_TABLES.sample - inspect_source(cop, "add_column :#{table}, :column, :string") + inspect_source("add_column :#{table}, :column, :string") expect(cop.offenses).to be_empty end @@ -77,7 +77,7 @@ describe RuboCop::Cop::Migration::SaferBooleanColumn do context 'outside of migration' do it 'registers no offense' do table = described_class::SMALL_TABLES.sample - inspect_source(cop, "add_column :#{table}, :column, :boolean") + inspect_source("add_column :#{table}, :column, :boolean") expect(cop.offenses).to be_empty end diff --git a/spec/rubocop/cop/migration/timestamps_spec.rb b/spec/rubocop/cop/migration/timestamps_spec.rb index cdf1423d0c5..685bdb21803 100644 --- a/spec/rubocop/cop/migration/timestamps_spec.rb +++ b/spec/rubocop/cop/migration/timestamps_spec.rb @@ -62,7 +62,7 @@ describe RuboCop::Cop::Migration::Timestamps do end it 'registers an offense when the "timestamps" method is used' do - inspect_source(cop, migration_with_timestamps) + inspect_source(migration_with_timestamps) aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -71,7 +71,7 @@ describe RuboCop::Cop::Migration::Timestamps do end it 'does not register an offense when the "timestamps" method is not used' do - inspect_source(cop, migration_without_timestamps) + inspect_source(migration_without_timestamps) aggregate_failures do expect(cop.offenses.size).to eq(0) @@ -79,7 +79,7 @@ describe RuboCop::Cop::Migration::Timestamps do end it 'does not register an offense when the "timestamps_with_timezone" method is used' do - inspect_source(cop, migration_with_timestamps_with_timezone) + inspect_source(migration_with_timestamps_with_timezone) aggregate_failures do expect(cop.offenses.size).to eq(0) @@ -89,9 +89,9 @@ describe RuboCop::Cop::Migration::Timestamps do context 'outside of migration' do it 'registers no offense' do - inspect_source(cop, migration_with_timestamps) - inspect_source(cop, migration_without_timestamps) - inspect_source(cop, migration_with_timestamps_with_timezone) + inspect_source(migration_with_timestamps) + inspect_source(migration_without_timestamps) + inspect_source(migration_with_timestamps_with_timezone) expect(cop.offenses.size).to eq(0) end diff --git a/spec/rubocop/cop/migration/update_column_in_batches_spec.rb b/spec/rubocop/cop/migration/update_column_in_batches_spec.rb index 38b8f439a55..1c8ab0ad5d2 100644 --- a/spec/rubocop/cop/migration/update_column_in_batches_spec.rb +++ b/spec/rubocop/cop/migration/update_column_in_batches_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' + require 'rubocop' require 'rubocop/rspec/support' + require_relative '../../../../rubocop/cop/migration/update_column_in_batches' describe RuboCop::Cop::Migration::UpdateColumnInBatches do @@ -25,7 +27,7 @@ describe RuboCop::Cop::Migration::UpdateColumnInBatches do context 'outside of a migration' do it 'does not register any offenses' do - inspect_source(cop, migration_code) + inspect_source(migration_code) expect(cop.offenses).to be_empty end @@ -49,7 +51,7 @@ describe RuboCop::Cop::Migration::UpdateColumnInBatches do let(:relative_spec_filepath) { Pathname.new(spec_filepath).relative_path_from(tmp_rails_root) } it 'registers an offense when using update_column_in_batches' do - inspect_source(cop, migration_code, @migration_file) + inspect_source(migration_code, @migration_file) aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -72,7 +74,7 @@ describe RuboCop::Cop::Migration::UpdateColumnInBatches do end it 'does not register any offenses' do - inspect_source(cop, migration_code, @migration_file) + inspect_source(migration_code, @migration_file) expect(cop.offenses).to be_empty end diff --git a/spec/rubocop/cop/migration/update_large_table_spec.rb b/spec/rubocop/cop/migration/update_large_table_spec.rb index 17b19e139e4..ef724fc8bad 100644 --- a/spec/rubocop/cop/migration/update_large_table_spec.rb +++ b/spec/rubocop/cop/migration/update_large_table_spec.rb @@ -18,7 +18,7 @@ describe RuboCop::Cop::Migration::UpdateLargeTable do shared_examples 'large tables' do |update_method| described_class::LARGE_TABLES.each do |table| it "registers an offense for the #{table} table" do - inspect_source(cop, "#{update_method} :#{table}, :column, default: true") + inspect_source("#{update_method} :#{table}, :column, default: true") aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -37,7 +37,7 @@ describe RuboCop::Cop::Migration::UpdateLargeTable do end it 'registers no offense for non-blacklisted tables' do - inspect_source(cop, "add_column_with_default :table, :column, default: true") + inspect_source("add_column_with_default :table, :column, default: true") expect(cop.offenses).to be_empty end @@ -45,7 +45,7 @@ describe RuboCop::Cop::Migration::UpdateLargeTable do it 'registers no offense for non-blacklisted methods' do table = described_class::LARGE_TABLES.sample - inspect_source(cop, "some_other_method :#{table}, :column, default: true") + inspect_source("some_other_method :#{table}, :column, default: true") expect(cop.offenses).to be_empty end @@ -55,13 +55,13 @@ describe RuboCop::Cop::Migration::UpdateLargeTable do let(:table) { described_class::LARGE_TABLES.sample } it 'registers no offense for add_column_with_default' do - inspect_source(cop, "add_column_with_default :#{table}, :column, default: true") + inspect_source("add_column_with_default :#{table}, :column, default: true") expect(cop.offenses).to be_empty end it 'registers no offense for update_column_in_batches' do - inspect_source(cop, "add_column_with_default :#{table}, :column, default: true") + inspect_source("add_column_with_default :#{table}, :column, default: true") expect(cop.offenses).to be_empty end diff --git a/spec/rubocop/cop/polymorphic_associations_spec.rb b/spec/rubocop/cop/polymorphic_associations_spec.rb deleted file mode 100644 index 49959aa6419..00000000000 --- a/spec/rubocop/cop/polymorphic_associations_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -require 'spec_helper' -require 'rubocop' -require 'rubocop/rspec/support' -require_relative '../../../rubocop/cop/polymorphic_associations' - -describe RuboCop::Cop::PolymorphicAssociations do - include CopHelper - - subject(:cop) { described_class.new } - - context 'inside the app/models directory' do - it 'registers an offense when polymorphic: true is used' do - allow(cop).to receive(:in_model?).and_return(true) - - inspect_source(cop, 'belongs_to :foo, polymorphic: true') - - aggregate_failures do - expect(cop.offenses.size).to eq(1) - expect(cop.offenses.map(&:line)).to eq([1]) - end - end - end - - context 'outside the app/models directory' do - it 'does nothing' do - allow(cop).to receive(:in_model?).and_return(false) - - inspect_source(cop, 'belongs_to :foo, polymorphic: true') - - expect(cop.offenses).to be_empty - end - end -end diff --git a/spec/rubocop/cop/project_path_helper_spec.rb b/spec/rubocop/cop/project_path_helper_spec.rb index bc47b45cad7..84e6eb7d87f 100644 --- a/spec/rubocop/cop/project_path_helper_spec.rb +++ b/spec/rubocop/cop/project_path_helper_spec.rb @@ -15,7 +15,7 @@ describe RuboCop::Cop::ProjectPathHelper do let(:correct_source) { 'edit_project_issue_path(@issue.project, @issue)' } it 'registers an offense' do - inspect_source(cop, source) + inspect_source(source) aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -25,7 +25,7 @@ describe RuboCop::Cop::ProjectPathHelper do end it 'autocorrects to the right version' do - autocorrected = autocorrect_source(cop, source) + autocorrected = autocorrect_source(source) expect(autocorrected).to eq(correct_source) end @@ -33,7 +33,7 @@ describe RuboCop::Cop::ProjectPathHelper do context 'when using namespace_project with a different namespace' do it 'registers no offense' do - inspect_source(cop, 'edit_namespace_project_issue_path(namespace, project)') + inspect_source('edit_namespace_project_issue_path(namespace, project)') expect(cop.offenses.size).to eq(0) end diff --git a/spec/rubocop/cop/redirect_with_status_spec.rb b/spec/rubocop/cop/redirect_with_status_spec.rb deleted file mode 100644 index 5ad63567f84..00000000000 --- a/spec/rubocop/cop/redirect_with_status_spec.rb +++ /dev/null @@ -1,86 +0,0 @@ -require 'spec_helper' - -require 'rubocop' -require 'rubocop/rspec/support' - -require_relative '../../../rubocop/cop/redirect_with_status' - -describe RuboCop::Cop::RedirectWithStatus do - include CopHelper - - subject(:cop) { described_class.new } - let(:controller_fixture_without_status) do - %q( - class UserController < ApplicationController - def show - user = User.find(params[:id]) - redirect_to user_path if user.name == 'John Wick' - end - - def destroy - user = User.find(params[:id]) - - if user.destroy - redirect_to root_path - else - render :show - end - end - end - ) - end - - let(:controller_fixture_with_status) do - %q( - class UserController < ApplicationController - def show - user = User.find(params[:id]) - redirect_to user_path if user.name == 'John Wick' - end - - def destroy - user = User.find(params[:id]) - - if user.destroy - redirect_to root_path, status: 302 - else - render :show - end - end - end - ) - end - - context 'in controller' do - before do - allow(cop).to receive(:in_controller?).and_return(true) - end - - it 'registers an offense when a "destroy" action uses "redirect_to" without "status"' do - inspect_source(cop, controller_fixture_without_status) - - aggregate_failures do - expect(cop.offenses.size).to eq(1) - expect(cop.offenses.map(&:line)).to eq([12]) # 'redirect_to' is located on 12th line in controller_fixture. - expect(cop.highlights).to eq(['redirect_to']) - end - end - - it 'does not register an offense when a "destroy" action uses "redirect_to" with "status"' do - inspect_source(cop, controller_fixture_with_status) - - aggregate_failures do - expect(cop.offenses.size).to eq(0) - end - end - end - - context 'outside of controller' do - it 'registers no offense' do - inspect_source(cop, controller_fixture_without_status) - inspect_source(cop, controller_fixture_with_status) - - expect(cop.offenses.size).to eq(0) - end - end -end diff --git a/spec/rubocop/cop/rspec/env_assignment_spec.rb b/spec/rubocop/cop/rspec/env_assignment_spec.rb index 4e859b6f6fa..659633f6467 100644 --- a/spec/rubocop/cop/rspec/env_assignment_spec.rb +++ b/spec/rubocop/cop/rspec/env_assignment_spec.rb @@ -17,7 +17,7 @@ describe RuboCop::Cop::RSpec::EnvAssignment do shared_examples 'an offensive ENV#[]= call' do |content| it "registers an offense for `#{content}`" do - inspect_source(cop, content, source_file) + inspect_source(content, source_file) expect(cop.offenses.size).to eq(1) expect(cop.offenses.map(&:line)).to eq([1]) @@ -27,7 +27,7 @@ describe RuboCop::Cop::RSpec::EnvAssignment do shared_examples 'an autocorrected ENV#[]= call' do |content, autocorrected_content| it "registers an offense for `#{content}` and autocorrects it to `#{autocorrected_content}`" do - autocorrected = autocorrect_source(cop, content, source_file) + autocorrected = autocorrect_source(content, source_file) expect(autocorrected).to eql(autocorrected_content) end @@ -51,7 +51,7 @@ describe RuboCop::Cop::RSpec::EnvAssignment do context 'outside of a spec file' do it "does not register an offense for `#{OFFENSE_CALL_SINGLE_QUOTES_KEY}` in a non-spec file" do - inspect_source(cop, OFFENSE_CALL_SINGLE_QUOTES_KEY) + inspect_source(OFFENSE_CALL_SINGLE_QUOTES_KEY) expect(cop.offenses.size).to eq(0) end diff --git a/spec/rubocop/cop/rspec/single_line_hook_spec.rb b/spec/rubocop/cop/rspec/single_line_hook_spec.rb deleted file mode 100644 index 6cf0831d3ad..00000000000 --- a/spec/rubocop/cop/rspec/single_line_hook_spec.rb +++ /dev/null @@ -1,66 +0,0 @@ -require 'spec_helper' - -require 'rubocop' -require 'rubocop/rspec/support' - -require_relative '../../../../rubocop/cop/rspec/single_line_hook' - -describe RuboCop::Cop::RSpec::SingleLineHook do - include CopHelper - - subject(:cop) { described_class.new } - - # Override `CopHelper#inspect_source` to always appear to be in a spec file, - # so that our RSpec-only cop actually runs - def inspect_source(*args) - super(*args, 'foo_spec.rb') - end - - it 'registers an offense for a single-line `before` block' do - inspect_source(cop, 'before { do_something }') - - expect(cop.offenses.size).to eq(1) - expect(cop.offenses.map(&:line)).to eq([1]) - expect(cop.highlights).to eq(['before { do_something }']) - end - - it 'registers an offense for a single-line `after` block' do - inspect_source(cop, 'after(:each) { undo_something }') - - expect(cop.offenses.size).to eq(1) - expect(cop.offenses.map(&:line)).to eq([1]) - expect(cop.highlights).to eq(['after(:each) { undo_something }']) - end - - it 'registers an offense for a single-line `around` block' do - inspect_source(cop, 'around { |ex| do_something_else }') - - expect(cop.offenses.size).to eq(1) - expect(cop.offenses.map(&:line)).to eq([1]) - expect(cop.highlights).to eq(['around { |ex| do_something_else }']) - end - - it 'ignores a multi-line `before` block' do - inspect_source(cop, ['before do', - ' do_something', - 'end']) - - expect(cop.offenses.size).to eq(0) - end - - it 'ignores a multi-line `after` block' do - inspect_source(cop, ['after(:each) do', - ' undo_something', - 'end']) - - expect(cop.offenses.size).to eq(0) - end - - it 'ignores a multi-line `around` block' do - inspect_source(cop, ['around do |ex|', - ' do_something_else', - 'end']) - - expect(cop.offenses.size).to eq(0) - end -end diff --git a/spec/rubocop/cop/rspec/verbose_include_metadata_spec.rb b/spec/rubocop/cop/rspec/verbose_include_metadata_spec.rb deleted file mode 100644 index 278662d32ea..00000000000 --- a/spec/rubocop/cop/rspec/verbose_include_metadata_spec.rb +++ /dev/null @@ -1,53 +0,0 @@ -require 'spec_helper' -require 'rubocop' -require 'rubocop/rspec/support' -require_relative '../../../../rubocop/cop/rspec/verbose_include_metadata' - -describe RuboCop::Cop::RSpec::VerboseIncludeMetadata do - include CopHelper - - subject(:cop) { described_class.new } - - let(:source_file) { 'foo_spec.rb' } - - # Override `CopHelper#inspect_source` to always appear to be in a spec file, - # so that our RSpec-only cop actually runs - def inspect_source(*args) - super(*args, source_file) - end - - shared_examples 'examples with include syntax' do |title| - it "flags violation for #{title} examples that uses verbose include syntax" do - inspect_source(cop, "#{title} 'Test', js: true do; end") - - expect(cop.offenses.size).to eq(1) - offense = cop.offenses.first - - expect(offense.line).to eq(1) - expect(cop.highlights).to eq(["#{title} 'Test', js: true"]) - expect(offense.message).to eq('Use `:js` instead of `js: true`.') - end - - it "doesn't flag violation for #{title} examples that uses compact include syntax", :aggregate_failures do - inspect_source(cop, "#{title} 'Test', :js do; end") - - expect(cop.offenses).to be_empty - end - - it "doesn't flag violation for #{title} examples that uses flag: symbol" do - inspect_source(cop, "#{title} 'Test', flag: :symbol do; end") - - expect(cop.offenses).to be_empty - end - - it "autocorrects #{title} examples that uses verbose syntax into compact syntax" do - autocorrected = autocorrect_source(cop, "#{title} 'Test', js: true do; end", source_file) - - expect(autocorrected).to eql("#{title} 'Test', :js do; end") - end - end - - %w(describe context feature example_group it specify example scenario its).each do |example| - it_behaves_like 'examples with include syntax', example - end -end diff --git a/spec/rubocop/cop/sidekiq_options_queue_spec.rb b/spec/rubocop/cop/sidekiq_options_queue_spec.rb index a31de381631..7f237d5ffbb 100644 --- a/spec/rubocop/cop/sidekiq_options_queue_spec.rb +++ b/spec/rubocop/cop/sidekiq_options_queue_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' + require 'rubocop' require 'rubocop/rspec/support' + require_relative '../../../rubocop/cop/sidekiq_options_queue' describe RuboCop::Cop::SidekiqOptionsQueue do @@ -9,7 +11,7 @@ describe RuboCop::Cop::SidekiqOptionsQueue do subject(:cop) { described_class.new } it 'registers an offense when `sidekiq_options` is used with the `queue` option' do - inspect_source(cop, 'sidekiq_options queue: "some_queue"') + inspect_source('sidekiq_options queue: "some_queue"') aggregate_failures do expect(cop.offenses.size).to eq(1) @@ -19,7 +21,7 @@ describe RuboCop::Cop::SidekiqOptionsQueue do end it 'does not register an offense when `sidekiq_options` is used with another option' do - inspect_source(cop, 'sidekiq_options retry: false') + inspect_source('sidekiq_options retry: false') expect(cop.offenses).to be_empty end -- cgit v1.2.1 From a0c4f0059592c788b14f8cb71e655c05f1fc1dd7 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Tue, 5 Dec 2017 18:47:54 +0000 Subject: Use relative URLs when linking to uploaded files --- app/models/concerns/cache_markdown_field.rb | 2 +- .../38893-banzai-upload-filter-relative-urls.yml | 5 + lib/banzai/filter/relative_link_filter.rb | 46 +++++-- lib/banzai/filter/upload_link_filter.rb | 60 ---------- lib/banzai/pipeline/gfm_pipeline.rb | 1 - .../lib/banzai/filter/relative_link_filter_spec.rb | 81 +++++++++++++ spec/lib/banzai/filter/upload_link_filter_spec.rb | 133 --------------------- 7 files changed, 126 insertions(+), 202 deletions(-) create mode 100644 changelogs/unreleased/38893-banzai-upload-filter-relative-urls.yml delete mode 100644 lib/banzai/filter/upload_link_filter.rb delete mode 100644 spec/lib/banzai/filter/upload_link_filter_spec.rb diff --git a/app/models/concerns/cache_markdown_field.rb b/app/models/concerns/cache_markdown_field.rb index 90ad644ce34..4ae5dd8c677 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 = 2 + CACHE_VERSION = 3 # changes to these attributes cause the cache to be invalidates INVALIDATED_BY = %w[author project].freeze diff --git a/changelogs/unreleased/38893-banzai-upload-filter-relative-urls.yml b/changelogs/unreleased/38893-banzai-upload-filter-relative-urls.yml new file mode 100644 index 00000000000..9ab0a0159e9 --- /dev/null +++ b/changelogs/unreleased/38893-banzai-upload-filter-relative-urls.yml @@ -0,0 +1,5 @@ +--- +title: Use relative URLs when linking to uploaded files +merge_request: 15751 +author: +type: other diff --git a/lib/banzai/filter/relative_link_filter.rb b/lib/banzai/filter/relative_link_filter.rb index 758f15c8a67..c1f933ec54b 100644 --- a/lib/banzai/filter/relative_link_filter.rb +++ b/lib/banzai/filter/relative_link_filter.rb @@ -2,19 +2,21 @@ require 'uri' module Banzai module Filter - # HTML filter that "fixes" relative links to files in a repository. + # HTML filter that "fixes" relative links to uploads or files in a repository. # # Context options: # :commit + # :group # :project # :project_wiki # :ref # :requested_path class RelativeLinkFilter < HTML::Pipeline::Filter - def call - return doc unless linkable_files? + include Gitlab::Utils::StrongMemoize + def call @uri_types = {} + clear_memoization(:linkable_files) doc.search('a:not(.gfm)').each do |el| process_link_attr el.attribute('href') @@ -31,13 +33,35 @@ module Banzai protected def linkable_files? - context[:project_wiki].nil? && repository.try(:exists?) && !repository.empty? + strong_memoize(:linkable_files) do + context[:project_wiki].nil? && repository.try(:exists?) && !repository.empty? + end end def process_link_attr(html_attr) return if html_attr.blank? return if html_attr.value.start_with?('//') + if html_attr.value.start_with?('/uploads/') + process_link_to_upload_attr(html_attr) + elsif linkable_files? + process_link_to_repository_attr(html_attr) + end + end + + def process_link_to_upload_attr(html_attr) + uri_parts = [html_attr.value] + + if group + uri_parts.unshift(relative_url_root, 'groups', group.full_path, '-') + elsif project + uri_parts.unshift(relative_url_root, project.full_path) + end + + html_attr.value = File.join(*uri_parts) + end + + def process_link_to_repository_attr(html_attr) uri = URI(html_attr.value) if uri.relative? && uri.path.present? html_attr.value = rebuild_relative_uri(uri).to_s @@ -51,7 +75,7 @@ module Banzai uri.path = [ relative_url_root, - context[:project].full_path, + project.full_path, uri_type(file_path), Addressable::URI.escape(ref), Addressable::URI.escape(file_path) @@ -123,11 +147,19 @@ module Banzai end def ref - context[:ref] || context[:project].default_branch + context[:ref] || project.default_branch + end + + def group + context[:group] + end + + def project + context[:project] end def repository - @repository ||= context[:project].try(:repository) + @repository ||= project&.repository end end end diff --git a/lib/banzai/filter/upload_link_filter.rb b/lib/banzai/filter/upload_link_filter.rb deleted file mode 100644 index d64f9ac4eb6..00000000000 --- a/lib/banzai/filter/upload_link_filter.rb +++ /dev/null @@ -1,60 +0,0 @@ -require 'uri' - -module Banzai - module Filter - # HTML filter that "fixes" relative upload links to files. - # Context options: - # :project (required) - Current project - # - class UploadLinkFilter < HTML::Pipeline::Filter - def call - return doc unless project || group - - doc.xpath('descendant-or-self::a[starts-with(@href, "/uploads/")]').each do |el| - process_link_attr el.attribute('href') - end - - doc.xpath('descendant-or-self::img[starts-with(@src, "/uploads/")]').each do |el| - process_link_attr el.attribute('src') - end - - doc - end - - protected - - def process_link_attr(html_attr) - html_attr.value = build_url(html_attr.value).to_s - end - - def build_url(uri) - base_path = Gitlab.config.gitlab.url - - if group - urls = Gitlab::Routing.url_helpers - # we need to get last 2 parts of the uri which are secret and filename - uri_parts = uri.split(File::SEPARATOR) - file_path = urls.show_group_uploads_path(group, uri_parts[-2], uri_parts[-1]) - File.join(base_path, file_path) - else - File.join(base_path, project.full_path, uri) - end - end - - def project - context[:project] - end - - def group - context[:group] - end - - # Ensure that a :project key exists in context - # - # Note that while the key might exist, its value could be nil! - def validate - needs :project - end - end - end -end diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb index 55874ad50a3..c746f6f64e9 100644 --- a/lib/banzai/pipeline/gfm_pipeline.rb +++ b/lib/banzai/pipeline/gfm_pipeline.rb @@ -15,7 +15,6 @@ module Banzai Filter::MathFilter, Filter::MermaidFilter, - Filter::UploadLinkFilter, Filter::VideoLinkFilter, Filter::ImageLazyLoadFilter, Filter::ImageLinkFilter, diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb index 08beede62db..ef306f1cd4a 100644 --- a/spec/lib/banzai/filter/relative_link_filter_spec.rb +++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb @@ -5,6 +5,7 @@ describe Banzai::Filter::RelativeLinkFilter do contexts.reverse_merge!({ commit: commit, project: project, + group: group, project_wiki: project_wiki, ref: ref, requested_path: requested_path @@ -25,7 +26,12 @@ describe Banzai::Filter::RelativeLinkFilter do %(#{path}) end + def nested(element) + %(
#{element}
) + end + let(:project) { create(:project, :repository) } + let(:group) { nil } let(:project_path) { project.full_path } let(:ref) { 'markdown' } let(:commit) { project.commit(ref) } @@ -223,4 +229,79 @@ describe Banzai::Filter::RelativeLinkFilter do let(:commit) { nil } # force filter to use ref instead of commit include_examples :valid_repository end + + context 'with a /upload/ URL' do + # not needed + let(:commit) { nil } + let(:ref) { nil } + let(:requested_path) { nil } + + context 'to a project upload' do + it 'rebuilds relative URL for a link' do + doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) + expect(doc.at_css('a')['href']) + .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + + doc = filter(nested(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))) + expect(doc.at_css('a')['href']) + .to eq "/#{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 "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + + doc = filter(nested(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))) + expect(doc.at_css('img')['src']) + .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + end + + it 'does not modify absolute URL' do + doc = filter(link('http://example.com')) + expect(doc.at_css('a')['href']).to eq 'http://example.com' + end + + it 'supports Unicode filenames' do + path = '/uploads/한글.png' + escaped = Addressable::URI.escape(path) + + # Stub these methods so the file doesn't actually need to be in the repo + allow_any_instance_of(described_class) + .to receive(:file_exists?).and_return(true) + allow_any_instance_of(described_class) + .to receive(:image?).with(path).and_return(true) + + doc = filter(image(escaped)) + expect(doc.at_css('img')['src']).to match "/#{project.full_path}/uploads/%ED%95%9C%EA%B8%80.png" + end + end + + context 'to a group upload' do + let(:upload_link) { link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg') } + let(:group) { create(:group) } + let(:project) { nil } + let(:relative_path) { "/groups/#{group.full_path}/-/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" } + + it 'rewrites the link correctly' do + doc = filter(upload_link) + + expect(doc.at_css('a')['href']).to eq(relative_path) + end + + it 'rewrites the link correctly for subgroup' do + group.update!(parent: create(:group)) + + doc = filter(upload_link) + + expect(doc.at_css('a')['href']).to eq(relative_path) + end + + it 'does not modify absolute URL' do + doc = filter(link('http://example.com')) + + expect(doc.at_css('a')['href']).to eq 'http://example.com' + end + end + end end diff --git a/spec/lib/banzai/filter/upload_link_filter_spec.rb b/spec/lib/banzai/filter/upload_link_filter_spec.rb deleted file mode 100644 index 76bc0c36ab7..00000000000 --- a/spec/lib/banzai/filter/upload_link_filter_spec.rb +++ /dev/null @@ -1,133 +0,0 @@ -require 'spec_helper' - -describe Banzai::Filter::UploadLinkFilter do - def filter(doc, contexts = {}) - contexts.reverse_merge!({ - project: project - }) - - raw_filter(doc, contexts) - end - - def raw_filter(doc, contexts = {}) - described_class.call(doc, contexts) - end - - def image(path) - %() - end - - def link(path) - %(#{path}) - end - - def nested_image(path) - %(
) - end - - def nested_link(path) - %() - end - - let(:project) { create(:project) } - - shared_examples :preserve_unchanged do - it 'does not modify any relative URL in anchor' do - doc = filter(link('README.md')) - expect(doc.at_css('a')['href']).to eq 'README.md' - end - - it 'does not modify any relative URL in image' do - doc = filter(image('files/images/logo-black.png')) - expect(doc.at_css('img')['src']).to eq 'files/images/logo-black.png' - end - end - - it 'does not raise an exception on invalid URIs' do - act = link("://foo") - expect { filter(act) }.not_to raise_error - end - - context 'with a valid repository' 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.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.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.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.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" - end - - it 'does not modify absolute URL' do - doc = filter(link('http://example.com')) - expect(doc.at_css('a')['href']).to eq 'http://example.com' - end - - it 'supports Unicode filenames' do - path = '/uploads/한글.png' - escaped = Addressable::URI.escape(path) - - # Stub these methods so the file doesn't actually need to be in the repo - allow_any_instance_of(described_class) - .to receive(:file_exists?).and_return(true) - allow_any_instance_of(described_class) - .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.full_path}/uploads/%ED%95%9C%EA%B8%80.png" - end - end - - context 'in group context' do - let(:upload_link) { link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg') } - let(:group) { create(:group) } - let(:filter_context) { { project: nil, group: group } } - let(:relative_path) { "groups/#{group.full_path}/-/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" } - - it 'rewrites the link correctly' do - doc = raw_filter(upload_link, filter_context) - - expect(doc.at_css('a')['href']).to eq("#{Gitlab.config.gitlab.url}/#{relative_path}") - end - - it 'rewrites the link correctly for subgroup' do - subgroup = create(:group, parent: group) - relative_path = "groups/#{subgroup.full_path}/-/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" - - doc = raw_filter(upload_link, { project: nil, group: subgroup }) - - expect(doc.at_css('a')['href']).to eq("#{Gitlab.config.gitlab.url}/#{relative_path}") - end - - it 'does not modify absolute URL' do - doc = filter(link('http://example.com'), filter_context) - - expect(doc.at_css('a')['href']).to eq 'http://example.com' - end - end - - context 'when project or group context does not exist' do - let(:upload_link) { link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg') } - - it 'does not raise error' do - expect { raw_filter(upload_link, project: nil) }.not_to raise_error - end - - it 'does not rewrite link' do - doc = raw_filter(upload_link, project: nil) - - expect(doc.to_html).to eq upload_link - end - end -end -- cgit v1.2.1 From 16b8297e77501134cd93a74c3d5c60712930e7fd Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 22 Dec 2017 11:38:35 +0100 Subject: Execute project hooks and services after commit when moving an issue --- app/models/project.rb | 16 +++++++++++----- .../unreleased/dm-issue-move-transaction-error.yml | 5 +++++ config/initializers/forbid_sidekiq_in_transactions.rb | 8 +++++--- lib/after_commit_queue.rb | 10 +++++++++- spec/services/issues/move_service_spec.rb | 12 ++++++++++++ 5 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 changelogs/unreleased/dm-issue-move-transaction-error.yml diff --git a/app/models/project.rb b/app/models/project.rb index 3440c01b356..f9c640300ff 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -951,7 +951,9 @@ class Project < ActiveRecord::Base def send_move_instructions(old_path_with_namespace) # New project path needs to be committed to the DB or notification will # retrieve stale information - run_after_commit { NotificationService.new.project_was_moved(self, old_path_with_namespace) } + run_after_commit do + NotificationService.new.project_was_moved(self, old_path_with_namespace) + end end def owner @@ -963,15 +965,19 @@ class Project < ActiveRecord::Base end def execute_hooks(data, hooks_scope = :push_hooks) - hooks.public_send(hooks_scope).each do |hook| # rubocop:disable GitlabSecurity/PublicSend - hook.async_execute(data, hooks_scope.to_s) + run_after_commit_or_now do + hooks.public_send(hooks_scope).each do |hook| # rubocop:disable GitlabSecurity/PublicSend + hook.async_execute(data, hooks_scope.to_s) + end end end def execute_services(data, hooks_scope = :push_hooks) # Call only service hooks that are active for this scope - services.public_send(hooks_scope).each do |service| # rubocop:disable GitlabSecurity/PublicSend - service.async_execute(data) + run_after_commit_or_now do + services.public_send(hooks_scope).each do |service| # rubocop:disable GitlabSecurity/PublicSend + service.async_execute(data) + end end end diff --git a/changelogs/unreleased/dm-issue-move-transaction-error.yml b/changelogs/unreleased/dm-issue-move-transaction-error.yml new file mode 100644 index 00000000000..0892169894a --- /dev/null +++ b/changelogs/unreleased/dm-issue-move-transaction-error.yml @@ -0,0 +1,5 @@ +--- +title: Execute project hooks and services after commit when moving an issue +merge_request: +author: +type: fixed diff --git a/config/initializers/forbid_sidekiq_in_transactions.rb b/config/initializers/forbid_sidekiq_in_transactions.rb index bedd57ede04..cb611aa21df 100644 --- a/config/initializers/forbid_sidekiq_in_transactions.rb +++ b/config/initializers/forbid_sidekiq_in_transactions.rb @@ -1,5 +1,7 @@ module Sidekiq module Worker + EnqueueFromTransactionError = Class.new(StandardError) + mattr_accessor :skip_transaction_check self.skip_transaction_check = false @@ -12,11 +14,11 @@ module Sidekiq end module ClassMethods - module NoSchedulingFromTransactions + module NoEnqueueingFromTransactions %i(perform_async perform_at perform_in).each do |name| define_method(name) do |*args| if !Sidekiq::Worker.skip_transaction_check && AfterCommitQueue.inside_transaction? - raise <<-MSG.strip_heredoc + raise Sidekiq::Worker::EnqueueFromTransactionError, <<~MSG `#{self}.#{name}` cannot be called inside a transaction as this can lead to race conditions when the worker runs before the transaction is committed and tries to access a model that has not been saved yet. @@ -30,7 +32,7 @@ module Sidekiq end end - prepend NoSchedulingFromTransactions + prepend NoEnqueueingFromTransactions end end end diff --git a/lib/after_commit_queue.rb b/lib/after_commit_queue.rb index db63c5038ae..a4d8507960e 100644 --- a/lib/after_commit_queue.rb +++ b/lib/after_commit_queue.rb @@ -14,7 +14,15 @@ module AfterCommitQueue def run_after_commit_or_now(&block) if AfterCommitQueue.inside_transaction? - run_after_commit(&block) + if ActiveRecord::Base.connection.current_transaction.records.include?(self) + run_after_commit(&block) + else + # If the current transaction does not include this record, we can run + # the block now, even if it queues a Sidekiq job. + Sidekiq::Worker.skipping_transaction_check do + instance_eval(&block) + end + end else instance_eval(&block) end diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb index f2b35a8fadf..2cad695d7c4 100644 --- a/spec/services/issues/move_service_spec.rb +++ b/spec/services/issues/move_service_spec.rb @@ -289,6 +289,18 @@ describe Issues::MoveService do .to raise_error(StandardError, /Cannot move issue/) end end + + context 'project issue hooks' do + let(:hook) { create(:project_hook, project: old_project, issues_events: true) } + + it 'executes project issue hooks' do + # Ideally, we'd test that `WebHookWorker.jobs.size` increased by 1, + # but since the entire spec run takes place in a transaction, we never + # actually get to the `after_commit` hook that queues these jobs. + expect { move_service.execute(old_issue, new_project) } + .not_to raise_error # Sidekiq::Worker::EnqueueFromTransactionError + end + end end describe 'move permissions' do -- cgit v1.2.1 From 5d6fea1bb98355081fc94f299a4b01cd986c6bdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Javier=20L=C3=B3pez?= Date: Fri, 22 Dec 2017 18:02:48 +0100 Subject: Reverted fix https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15788 --- app/models/event.rb | 2 +- changelogs/unreleased/fix-event-target-author-preloading.yml | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 changelogs/unreleased/fix-event-target-author-preloading.yml diff --git a/app/models/event.rb b/app/models/event.rb index 6053594fab5..0997b056c6a 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -72,7 +72,7 @@ class Event < ActiveRecord::Base # We're using preload for "push_event_payload" as otherwise the association # is not always available (depending on the query being built). includes(:author, :project, project: :namespace) - .preload(:push_event_payload, target: :author) + .preload(:target, :push_event_payload) end scope :for_milestone_id, ->(milestone_id) { where(target_type: "Milestone", target_id: milestone_id) } diff --git a/changelogs/unreleased/fix-event-target-author-preloading.yml b/changelogs/unreleased/fix-event-target-author-preloading.yml deleted file mode 100644 index c6154cc0835..00000000000 --- a/changelogs/unreleased/fix-event-target-author-preloading.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix N+1 query when displaying events -merge_request: -author: -type: performance -- cgit v1.2.1 From 771bf9527ffd5fd8fe258381593f686d5d960a42 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 22 Dec 2017 12:49:56 +0100 Subject: Improve performance of DiffDiscussion#truncated_diff_lines and DiffNote#diff_line by removing expensive diff position calculation and comparison --- app/models/concerns/discussion_on_diff.rb | 10 ++++------ app/models/concerns/note_on_diff.rb | 4 ---- app/models/diff_note.rb | 6 +----- app/models/legacy_diff_note.rb | 6 +----- .../unreleased/dm-diff-note-for-line-performance.yml | 5 +++++ lib/gitlab/diff/file.rb | 4 +++- spec/models/diff_note_spec.rb | 16 ---------------- 7 files changed, 14 insertions(+), 37 deletions(-) create mode 100644 changelogs/unreleased/dm-diff-note-for-line-performance.yml diff --git a/app/models/concerns/discussion_on_diff.rb b/app/models/concerns/discussion_on_diff.rb index 4b4d519f3df..db9770fabf4 100644 --- a/app/models/concerns/discussion_on_diff.rb +++ b/app/models/concerns/discussion_on_diff.rb @@ -9,7 +9,6 @@ module DiscussionOnDiff :original_line_code, :diff_file, :diff_line, - :for_line?, :active?, :created_at_diff?, @@ -39,17 +38,16 @@ module DiscussionOnDiff # Returns an array of at most 16 highlighted lines above a diff note def truncated_diff_lines(highlight: true) lines = highlight ? highlighted_diff_lines : diff_lines + + initial_line_index = [diff_line.index - NUMBER_OF_TRUNCATED_DIFF_LINES + 1, 0].max + prev_lines = [] - lines.each do |line| + lines[initial_line_index..diff_line.index].each do |line| if line.meta? prev_lines.clear else prev_lines << line - - break if for_line?(line) - - prev_lines.shift if prev_lines.length >= NUMBER_OF_TRUNCATED_DIFF_LINES end end diff --git a/app/models/concerns/note_on_diff.rb b/app/models/concerns/note_on_diff.rb index f734952fa6c..510b8868462 100644 --- a/app/models/concerns/note_on_diff.rb +++ b/app/models/concerns/note_on_diff.rb @@ -14,10 +14,6 @@ module NoteOnDiff raise NotImplementedError end - def for_line?(line) - raise NotImplementedError - end - def original_line_code raise NotImplementedError end diff --git a/app/models/diff_note.rb b/app/models/diff_note.rb index b53d44cda95..15122cbc693 100644 --- a/app/models/diff_note.rb +++ b/app/models/diff_note.rb @@ -21,7 +21,7 @@ class DiffNote < Note before_validation :set_original_position, on: :create before_validation :update_position, on: :create, if: :on_text? - before_validation :set_line_code + before_validation :set_line_code, if: :on_text? after_save :keep_around_commits def discussion_class(*) @@ -61,10 +61,6 @@ class DiffNote < Note @diff_line ||= diff_file&.line_for_position(self.original_position) end - def for_line?(line) - diff_file.position(line) == self.original_position - end - def original_line_code return unless on_text? diff --git a/app/models/legacy_diff_note.rb b/app/models/legacy_diff_note.rb index c36be956ff0..d90cafd14b4 100644 --- a/app/models/legacy_diff_note.rb +++ b/app/models/legacy_diff_note.rb @@ -38,11 +38,7 @@ class LegacyDiffNote < Note end def diff_line - @diff_line ||= diff_file.line_for_line_code(self.line_code) if diff_file - end - - def for_line?(line) - line.discussable? && diff_file.line_code(line) == self.line_code + @diff_line ||= diff_file&.line_for_line_code(self.line_code) end def original_line_code diff --git a/changelogs/unreleased/dm-diff-note-for-line-performance.yml b/changelogs/unreleased/dm-diff-note-for-line-performance.yml new file mode 100644 index 00000000000..cbc418ab103 --- /dev/null +++ b/changelogs/unreleased/dm-diff-note-for-line-performance.yml @@ -0,0 +1,5 @@ +--- +title: Improve performance of MR discussions on large diffs +merge_request: +author: +type: performance diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index d0cfe2386ca..cd490aaa291 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -61,7 +61,9 @@ module Gitlab end def line_for_position(pos) - diff_lines.find { |line| position(line) == pos } + return nil unless pos.position_type == 'text' + + diff_lines.find { |line| line.old_line == pos.old_line && line.new_line == pos.new_line } end def position_for_line_code(code) diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb index 4d0b3245a13..2705421e540 100644 --- a/spec/models/diff_note_spec.rb +++ b/spec/models/diff_note_spec.rb @@ -112,22 +112,6 @@ describe DiffNote do end end - describe "#for_line?" do - context "when provided the correct diff line" do - it "returns true" do - expect(subject.for_line?(subject.diff_line)).to be true - end - end - - context "when provided a different diff line" do - it "returns false" do - some_line = subject.diff_file.diff_lines.first - - expect(subject.for_line?(some_line)).to be false - end - end - end - describe "#active?" do context "when noteable is a commit" do subject { build(:diff_note_on_commit, project: project, position: position) } -- cgit v1.2.1 From 26b3a0b34b94d4961ff9f7596cd512fb08c1dd67 Mon Sep 17 00:00:00 2001 From: Marcia Ramos Date: Fri, 22 Dec 2017 17:15:08 +0000 Subject: Docs: move article LDAP-CE to its topic-related folder --- .../img/gitlab_ou.png | Bin 0 -> 27877 bytes .../img/ldap_ou.gif | Bin 0 -> 222162 bytes .../img/user_auth.gif | Bin 0 -> 110971 bytes .../auth/how_to_configure_ldap_gitlab_ce/index.md | 267 ++++++++++++++++++++ doc/administration/auth/ldap.md | 3 + .../img/gitlab_ou.png | Bin 27877 -> 0 bytes .../img/ldap_ou.gif | Bin 222162 -> 0 bytes .../img/user_auth.gif | Bin 110971 -> 0 bytes .../how_to_configure_ldap_gitlab_ce/index.md | 268 +-------------------- doc/articles/index.md | 10 - doc/topics/authentication/index.md | 2 +- 11 files changed, 272 insertions(+), 278 deletions(-) create mode 100644 doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png create mode 100644 doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif create mode 100644 doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/user_auth.gif create mode 100644 doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md delete mode 100644 doc/articles/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png delete mode 100644 doc/articles/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif delete mode 100644 doc/articles/how_to_configure_ldap_gitlab_ce/img/user_auth.gif diff --git a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png new file mode 100644 index 00000000000..11ce324f938 Binary files /dev/null and b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png differ diff --git a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif new file mode 100644 index 00000000000..a6727a3d85f Binary files /dev/null and b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif differ diff --git a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/user_auth.gif b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/user_auth.gif new file mode 100644 index 00000000000..36e6085259f Binary files /dev/null and b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/img/user_auth.gif differ diff --git a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md new file mode 100644 index 00000000000..9b9b8ca89e5 --- /dev/null +++ b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md @@ -0,0 +1,267 @@ +# How to configure LDAP with GitLab CE + +> **[Article Type](../../../development/writing_documentation.html#types-of-technical-articles):** admin guide || +> **Level:** intermediary || +> **Author:** [Chris Wilson](https://gitlab.com/MrChrisW) || +> **Publication date:** 2017-05-03 + +## Introduction + +Managing a large number of users in GitLab can become a burden for system administrators. As an organization grows so do user accounts. Keeping these user accounts in sync across multiple enterprise applications often becomes a time consuming task. + +In this guide we will focus on configuring GitLab with Active Directory. [Active Directory](https://en.wikipedia.org/wiki/Active_Directory) is a popular LDAP compatible directory service provided by Microsoft, included in all modern Windows Server operating systems. + +GitLab has supported LDAP integration since [version 2.2](https://about.gitlab.com/2012/02/22/gitlab-version-2-2/). With GitLab LDAP [group syncing](#group-syncing-ee) being added to GitLab Enterprise Edition in [version 6.0](https://about.gitlab.com/2013/08/20/gitlab-6-dot-0-released/). LDAP integration has become one of the most popular features in GitLab. + +## Getting started + +### Choosing an LDAP Server + +The main reason organizations choose to utilize a LDAP server is to keep the entire organization's user base consolidated into a central repository. Users can access multiple applications and systems across the IT environment using a single login. Because LDAP is an open, vendor-neutral, industry standard application protocol, the number of applications using LDAP authentication continues to increase. + +There are many commercial and open source [directory servers](https://en.wikipedia.org/wiki/Directory_service#LDAP_implementations) that support the LDAP protocol. Deciding on the right directory server highly depends on the existing IT environment in which the server will be integrated with. + +For example, [Active Directory](https://technet.microsoft.com/en-us/library/hh831484(v=ws.11).aspx) is generally favored in a primarily Windows environment, as this allows quick integration with existing services. Other popular directory services include: + +- [Oracle Internet Directory](http://www.oracle.com/technetwork/middleware/id-mgmt/overview/index-082035.html) +- [OpenLDAP](http://www.openldap.org/) +- [389 Directory](http://directory.fedoraproject.org/) +- [OpenDJ](https://forgerock.org/opendj/) +- [ApacheDS](https://directory.apache.org/) + +> GitLab uses the [Net::LDAP](https://rubygems.org/gems/net-ldap) library under the hood. This means it supports all [IETF](https://tools.ietf.org/html/rfc2251) compliant LDAPv3 servers. + +### Active Directory (AD) + +We won't cover the installation and configuration of Windows Server or Active Directory Domain Services in this tutorial. There are a number of resources online to guide you through this process: + +- Install Windows Server 2012 - (_technet.microsoft.com_) - [Installing Windows Server 2012 ](https://technet.microsoft.com/en-us/library/jj134246(v=ws.11).aspx) + +- Install Active Directory Domain Services (AD DS) (_technet.microsoft.com_)- [Install Active Directory Domain Services](https://technet.microsoft.com/windows-server-docs/identity/ad-ds/deploy/install-active-directory-domain-services--level-100-#BKMK_PS) + +> **Shortcut:** You can quickly install AD DS via PowerShell using +`Install-WindowsFeature AD-Domain-Services -IncludeManagementTools` + +### Creating an AD **OU** structure + +Configuring organizational units (**OU**s) is an important part of setting up Active Directory. **OU**s form the base for an entire organizational structure. Using GitLab as an example we have designed the **OU** structure below using the geographic **OU** model. In the Geographic Model we separate **OU**s for different geographic regions. + +| GitLab **OU** Design | GitLab AD Structure | +| :----------------------------: | :------------------------------: | +| ![GitLab OU Design][gitlab_ou] | ![GitLab AD Structure][ldap_ou] | + +[gitlab_ou]: img/gitlab_ou.png +[ldap_ou]: img/ldap_ou.gif + +Using PowerShell you can output the **OU** structure as a table (_all names are examples only_): + +```ps +Get-ADObject -LDAPFilter "(objectClass=*)" -SearchBase 'OU=GitLab INT,DC=GitLab,DC=org' -Properties CanonicalName | Format-Table Name,CanonicalName -A +``` + +``` +OU CanonicalName +---- ------------- +GitLab INT GitLab.org/GitLab INT +United States GitLab.org/GitLab INT/United States +Developers GitLab.org/GitLab INT/United States/Developers +Gary Johnson GitLab.org/GitLab INT/United States/Developers/Gary Johnson +Ellis Matthews GitLab.org/GitLab INT/United States/Developers/Ellis Matthews +William Collins GitLab.org/GitLab INT/United States/Developers/William Collins +People Ops GitLab.org/GitLab INT/United States/People Ops +Margaret Baker GitLab.org/GitLab INT/United States/People Ops/Margaret Baker +Libby Hartzler GitLab.org/GitLab INT/United States/People Ops/Libby Hartzler +Victoria Ryles GitLab.org/GitLab INT/United States/People Ops/Victoria Ryles +The Netherlands GitLab.org/GitLab INT/The Netherlands +Developers GitLab.org/GitLab INT/The Netherlands/Developers +John Doe GitLab.org/GitLab INT/The Netherlands/Developers/John Doe +Jon Mealy GitLab.org/GitLab INT/The Netherlands/Developers/Jon Mealy +Jane Weingarten GitLab.org/GitLab INT/The Netherlands/Developers/Jane Weingarten +Production GitLab.org/GitLab INT/The Netherlands/Production +Sarah Konopka GitLab.org/GitLab INT/The Netherlands/Production/Sarah Konopka +Cynthia Bruno GitLab.org/GitLab INT/The Netherlands/Production/Cynthia Bruno +David George GitLab.org/GitLab INT/The Netherlands/Production/David George +United Kingdom GitLab.org/GitLab INT/United Kingdom +Developers GitLab.org/GitLab INT/United Kingdom/Developers +Leroy Fox GitLab.org/GitLab INT/United Kingdom/Developers/Leroy Fox +Christopher Alley GitLab.org/GitLab INT/United Kingdom/Developers/Christopher Alley +Norris Morita GitLab.org/GitLab INT/United Kingdom/Developers/Norris Morita +Support GitLab.org/GitLab INT/United Kingdom/Support +Laura Stanley GitLab.org/GitLab INT/United Kingdom/Support/Laura Stanley +Nikki Schuman GitLab.org/GitLab INT/United Kingdom/Support/Nikki Schuman +Harriet Butcher GitLab.org/GitLab INT/United Kingdom/Support/Harriet Butcher +Global Groups GitLab.org/GitLab INT/Global Groups +DevelopersNL GitLab.org/GitLab INT/Global Groups/DevelopersNL +DevelopersUK GitLab.org/GitLab INT/Global Groups/DevelopersUK +DevelopersUS GitLab.org/GitLab INT/Global Groups/DevelopersUS +ProductionNL GitLab.org/GitLab INT/Global Groups/ProductionNL +SupportUK GitLab.org/GitLab INT/Global Groups/SupportUK +People Ops US GitLab.org/GitLab INT/Global Groups/People Ops US +Global Admins GitLab.org/GitLab INT/Global Groups/Global Admins +``` + +> See [more information](https://technet.microsoft.com/en-us/library/ff730967.aspx) on searching Active Directory with Windows PowerShell from [The Scripting Guys](https://technet.microsoft.com/en-us/scriptcenter/dd901334.aspx) + +## GitLab LDAP configuration + +The initial configuration of LDAP in GitLab requires changes to the `gitlab.rb` configuration file. Below is an example of a complete configuration using an Active Directory. + +The two Active Directory specific values are `active_directory: true` and `uid: 'sAMAccountName'`. `sAMAccountName` is an attribute returned by Active Directory used for GitLab usernames. See the example output from `ldapsearch` for a full list of attributes a "person" object (user) has in **AD** - [`ldapsearch` example](#using-ldapsearch-unix) + +> Both group_base and admin_group configuration options are only available in GitLab Enterprise Edition. See [GitLab EE - LDAP Features](#gitlab-enterprise-edition---ldap-features) + +### Example `gitlab.rb` LDAP + +``` +gitlab_rails['ldap_enabled'] = true +gitlab_rails['ldap_servers'] = { +'main' => { + 'label' => 'GitLab AD', + 'host' => 'ad.example.org', + 'port' => 636, + 'uid' => 'sAMAccountName', + 'encryption' => 'simple_tls', + 'verify_certificates' => true, + 'bind_dn' => 'CN=GitLabSRV,CN=Users,DC=GitLab,DC=org', + 'password' => 'Password1', + 'active_directory' => true, + 'base' => 'OU=GitLab INT,DC=GitLab,DC=org', + 'group_base' => 'OU=Global Groups,OU=GitLab INT,DC=GitLab,DC=org', + 'admin_group' => 'Global Admins' + } +} +``` + +> **Note:** Remember to run `gitlab-ctl reconfigure` after modifying `gitlab.rb` + +## Security improvements (LDAPS) + +Security is an important aspect when deploying an LDAP server. By default, LDAP traffic is transmitted unsecured. LDAP can be secured using SSL/TLS called LDAPS, or commonly "LDAP over SSL". + +Securing LDAP (enabling LDAPS) on Windows Server 2012 involves installing a valid SSL certificate. For full details see Microsoft's guide [How to enable LDAP over SSL with a third-party certification authority](https://support.microsoft.com/en-us/help/321051/how-to-enable-ldap-over-ssl-with-a-third-party-certification-authority) + +> By default a LDAP service listens for connections on TCP and UDP port 389. LDAPS (LDAP over SSL) listens on port 636 + +### Testing you AD server + +#### Using **AdFind** (Windows) + +You can use the [`AdFind`](https://social.technet.microsoft.com/wiki/contents/articles/7535.adfind-command-examples.aspx) utility (on Windows based systems) to test that your LDAP server is accessible and authentication is working correctly. This is a freeware utility built by [Joe Richards](http://www.joeware.net/freetools/tools/adfind/index.htm). + +**Return all objects** + +You can use the filter `objectclass=*` to return all directory objects. + +```sh +adfind -h ad.example.org:636 -ssl -u "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -up Password1 -b "OU=GitLab INT,DC=GitLab,DC=org" -f (objectClass=*) +``` + +**Return single object using filter** + +You can also retrieve a single object by **specifying** the object name or full **DN**. In this example we specify the object name only `CN=Leroy Fox`. + +```sh +adfind -h ad.example.org:636 -ssl -u "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -up Password1 -b "OU=GitLab INT,DC=GitLab,DC=org" -f (&(objectcategory=person)(CN=Leroy Fox))” +``` + +#### Using **ldapsearch** (Unix) + +You can use the `ldapsearch` utility (on Unix based systems) to test that your LDAP server is accessible and authentication is working correctly. This utility is included in the [`ldap-utils`](https://wiki.debian.org/LDAP/LDAPUtils) package. + +**Return all objects** + +You can use the filter `objectclass=*` to return all directory objects. + +```sh +ldapsearch -D "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" \ +-w Password1 -p 636 -h ad.example.org \ +-b "OU=GitLab INT,DC=GitLab,DC=org" -Z \ +-s sub "(objectclass=*)" +``` + +**Return single object using filter** + +You can also retrieve a single object by **specifying** the object name or full **DN**. In this example we specify the object name only `CN=Leroy Fox`. + +```sh +ldapsearch -D "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -w Password1 -p 389 -h ad.example.org -b "OU=GitLab INT,DC=GitLab,DC=org" -Z -s sub "CN=Leroy Fox" +``` + +**Full output of `ldapsearch` command:** - Filtering for _CN=Leroy Fox_ + +``` +# LDAPv3 +# base with scope subtree +# filter: CN=Leroy Fox +# requesting: ALL +# + +# Leroy Fox, Developers, United Kingdom, GitLab INT, GitLab.org +dn: CN=Leroy Fox,OU=Developers,OU=United Kingdom,OU=GitLab INT,DC=GitLab,DC=or + g +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: user +cn: Leroy Fox +sn: Fox +givenName: Leroy +distinguishedName: CN=Leroy Fox,OU=Developers,OU=United Kingdom,OU=GitLab INT, + DC=GitLab,DC=org +instanceType: 4 +whenCreated: 20170210030500.0Z +whenChanged: 20170213050128.0Z +displayName: Leroy Fox +uSNCreated: 16790 +memberOf: CN=DevelopersUK,OU=Global Groups,OU=GitLab INT,DC=GitLab,DC=org +uSNChanged: 20812 +name: Leroy Fox +objectGUID:: rBCAo6NR6E6vfSKgzcUILg== +userAccountControl: 512 +badPwdCount: 0 +codePage: 0 +countryCode: 0 +badPasswordTime: 0 +lastLogoff: 0 +lastLogon: 0 +pwdLastSet: 131311695009850084 +primaryGroupID: 513 +objectSid:: AQUAAAAAAAUVAAAA9GMAb7tdJZvsATf7ZwQAAA== +accountExpires: 9223372036854775807 +logonCount: 0 +sAMAccountName: Leroyf +sAMAccountType: 805306368 +userPrincipalName: Leroyf@GitLab.org +objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=GitLab,DC=org +dSCorePropagationData: 16010101000000.0Z +lastLogonTimestamp: 131314356887754250 + +# search result +search: 2 +result: 0 Success + +# numResponses: 2 +# numEntries: 1 +``` + +## Basic user authentication + +After configuring LDAP, basic authentication will be available. Users can then login using their directory credentials. An extra tab is added to the GitLab login screen for the configured LDAP server (e.g "**GitLab AD**"). + +![GitLab OU Structure](img/user_auth.gif) + +Users that are removed from the LDAP base group (e.g `OU=GitLab INT,DC=GitLab,DC=org`) will be **blocked** in GitLab. [More information](../ldap.md#security) on LDAP security. + +If `allow_username_or_email_login` is enabled in the LDAP configuration, GitLab will ignore everything after the first '@' in the LDAP username used on login. Example: The username `jon.doe@example.com` is converted to `jon.doe` when authenticating with the LDAP server. Disable this setting if you use `userPrincipalName` as the `uid`. + +## LDAP extended features on GitLab EE + +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 +- Group permissions +- Updating user permissions +- Multiple LDAP servers + +Read through the article on [LDAP for GitLab EE](https://docs.gitlab.com/ee/administration/auth/how_to_configure_ldap_gitlab_ee/) for an overview. diff --git a/doc/administration/auth/ldap.md b/doc/administration/auth/ldap.md index 6b5a0f139c5..881b6a827f4 100644 --- a/doc/administration/auth/ldap.md +++ b/doc/administration/auth/ldap.md @@ -38,6 +38,9 @@ in the application settings. ## Configuration +For a complete guide on configuring LDAP with GitLab Community Edition, please check +the admin guide [How to configure LDAP with GitLab CE](how_to_configure_ldap_gitlab_ce/index.md). + To enable LDAP integration you need to add your LDAP server settings in `/etc/gitlab/gitlab.rb` or `/home/git/gitlab/config/gitlab.yml`. diff --git a/doc/articles/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png b/doc/articles/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png deleted file mode 100644 index 11ce324f938..00000000000 Binary files a/doc/articles/how_to_configure_ldap_gitlab_ce/img/gitlab_ou.png and /dev/null differ diff --git a/doc/articles/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif b/doc/articles/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif deleted file mode 100644 index a6727a3d85f..00000000000 Binary files a/doc/articles/how_to_configure_ldap_gitlab_ce/img/ldap_ou.gif and /dev/null differ diff --git a/doc/articles/how_to_configure_ldap_gitlab_ce/img/user_auth.gif b/doc/articles/how_to_configure_ldap_gitlab_ce/img/user_auth.gif deleted file mode 100644 index 36e6085259f..00000000000 Binary files a/doc/articles/how_to_configure_ldap_gitlab_ce/img/user_auth.gif and /dev/null differ 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 25a24bc1d32..a8320c12e6b 100644 --- a/doc/articles/how_to_configure_ldap_gitlab_ce/index.md +++ b/doc/articles/how_to_configure_ldap_gitlab_ce/index.md @@ -1,267 +1 @@ -# How to configure LDAP with GitLab CE - -> **Article [Type](../../development/writing_documentation.html#types-of-technical-articles):** admin guide || -> **Level:** intermediary || -> **Author:** [Chris Wilson](https://gitlab.com/MrChrisW) || -> **Publication date:** 2017-05-03 - -## Introduction - -Managing a large number of users in GitLab can become a burden for system administrators. As an organization grows so do user accounts. Keeping these user accounts in sync across multiple enterprise applications often becomes a time consuming task. - -In this guide we will focus on configuring GitLab with Active Directory. [Active Directory](https://en.wikipedia.org/wiki/Active_Directory) is a popular LDAP compatible directory service provided by Microsoft, included in all modern Windows Server operating systems. - -GitLab has supported LDAP integration since [version 2.2](https://about.gitlab.com/2012/02/22/gitlab-version-2-2/). With GitLab LDAP [group syncing](#group-syncing-ee) being added to GitLab Enterprise Edition in [version 6.0](https://about.gitlab.com/2013/08/20/gitlab-6-dot-0-released/). LDAP integration has become one of the most popular features in GitLab. - -## Getting started - -### Choosing an LDAP Server - -The main reason organizations choose to utilize a LDAP server is to keep the entire organization's user base consolidated into a central repository. Users can access multiple applications and systems across the IT environment using a single login. Because LDAP is an open, vendor-neutral, industry standard application protocol, the number of applications using LDAP authentication continues to increase. - -There are many commercial and open source [directory servers](https://en.wikipedia.org/wiki/Directory_service#LDAP_implementations) that support the LDAP protocol. Deciding on the right directory server highly depends on the existing IT environment in which the server will be integrated with. - -For example, [Active Directory](https://technet.microsoft.com/en-us/library/hh831484(v=ws.11).aspx) is generally favored in a primarily Windows environment, as this allows quick integration with existing services. Other popular directory services include: - -- [Oracle Internet Directory](http://www.oracle.com/technetwork/middleware/id-mgmt/overview/index-082035.html) -- [OpenLDAP](http://www.openldap.org/) -- [389 Directory](http://directory.fedoraproject.org/) -- [OpenDJ](https://forgerock.org/opendj/) -- [ApacheDS](https://directory.apache.org/) - -> GitLab uses the [Net::LDAP](https://rubygems.org/gems/net-ldap) library under the hood. This means it supports all [IETF](https://tools.ietf.org/html/rfc2251) compliant LDAPv3 servers. - -### Active Directory (AD) - -We won't cover the installation and configuration of Windows Server or Active Directory Domain Services in this tutorial. There are a number of resources online to guide you through this process: - -- Install Windows Server 2012 - (_technet.microsoft.com_) - [Installing Windows Server 2012 ](https://technet.microsoft.com/en-us/library/jj134246(v=ws.11).aspx) - -- Install Active Directory Domain Services (AD DS) (_technet.microsoft.com_)- [Install Active Directory Domain Services](https://technet.microsoft.com/windows-server-docs/identity/ad-ds/deploy/install-active-directory-domain-services--level-100-#BKMK_PS) - -> **Shortcut:** You can quickly install AD DS via PowerShell using -`Install-WindowsFeature AD-Domain-Services -IncludeManagementTools` - -### Creating an AD **OU** structure - -Configuring organizational units (**OU**s) is an important part of setting up Active Directory. **OU**s form the base for an entire organizational structure. Using GitLab as an example we have designed the **OU** structure below using the geographic **OU** model. In the Geographic Model we separate **OU**s for different geographic regions. - -| GitLab **OU** Design | GitLab AD Structure | -| :----------------------------: | :------------------------------: | -| ![GitLab OU Design][gitlab_ou] | ![GitLab AD Structure][ldap_ou] | - -[gitlab_ou]: img/gitlab_ou.png -[ldap_ou]: img/ldap_ou.gif - -Using PowerShell you can output the **OU** structure as a table (_all names are examples only_): - -```ps -Get-ADObject -LDAPFilter "(objectClass=*)" -SearchBase 'OU=GitLab INT,DC=GitLab,DC=org' -Properties CanonicalName | Format-Table Name,CanonicalName -A -``` - -``` -OU CanonicalName ----- ------------- -GitLab INT GitLab.org/GitLab INT -United States GitLab.org/GitLab INT/United States -Developers GitLab.org/GitLab INT/United States/Developers -Gary Johnson GitLab.org/GitLab INT/United States/Developers/Gary Johnson -Ellis Matthews GitLab.org/GitLab INT/United States/Developers/Ellis Matthews -William Collins GitLab.org/GitLab INT/United States/Developers/William Collins -People Ops GitLab.org/GitLab INT/United States/People Ops -Margaret Baker GitLab.org/GitLab INT/United States/People Ops/Margaret Baker -Libby Hartzler GitLab.org/GitLab INT/United States/People Ops/Libby Hartzler -Victoria Ryles GitLab.org/GitLab INT/United States/People Ops/Victoria Ryles -The Netherlands GitLab.org/GitLab INT/The Netherlands -Developers GitLab.org/GitLab INT/The Netherlands/Developers -John Doe GitLab.org/GitLab INT/The Netherlands/Developers/John Doe -Jon Mealy GitLab.org/GitLab INT/The Netherlands/Developers/Jon Mealy -Jane Weingarten GitLab.org/GitLab INT/The Netherlands/Developers/Jane Weingarten -Production GitLab.org/GitLab INT/The Netherlands/Production -Sarah Konopka GitLab.org/GitLab INT/The Netherlands/Production/Sarah Konopka -Cynthia Bruno GitLab.org/GitLab INT/The Netherlands/Production/Cynthia Bruno -David George GitLab.org/GitLab INT/The Netherlands/Production/David George -United Kingdom GitLab.org/GitLab INT/United Kingdom -Developers GitLab.org/GitLab INT/United Kingdom/Developers -Leroy Fox GitLab.org/GitLab INT/United Kingdom/Developers/Leroy Fox -Christopher Alley GitLab.org/GitLab INT/United Kingdom/Developers/Christopher Alley -Norris Morita GitLab.org/GitLab INT/United Kingdom/Developers/Norris Morita -Support GitLab.org/GitLab INT/United Kingdom/Support -Laura Stanley GitLab.org/GitLab INT/United Kingdom/Support/Laura Stanley -Nikki Schuman GitLab.org/GitLab INT/United Kingdom/Support/Nikki Schuman -Harriet Butcher GitLab.org/GitLab INT/United Kingdom/Support/Harriet Butcher -Global Groups GitLab.org/GitLab INT/Global Groups -DevelopersNL GitLab.org/GitLab INT/Global Groups/DevelopersNL -DevelopersUK GitLab.org/GitLab INT/Global Groups/DevelopersUK -DevelopersUS GitLab.org/GitLab INT/Global Groups/DevelopersUS -ProductionNL GitLab.org/GitLab INT/Global Groups/ProductionNL -SupportUK GitLab.org/GitLab INT/Global Groups/SupportUK -People Ops US GitLab.org/GitLab INT/Global Groups/People Ops US -Global Admins GitLab.org/GitLab INT/Global Groups/Global Admins -``` - -> See [more information](https://technet.microsoft.com/en-us/library/ff730967.aspx) on searching Active Directory with Windows PowerShell from [The Scripting Guys](https://technet.microsoft.com/en-us/scriptcenter/dd901334.aspx) - -## GitLab LDAP configuration - -The initial configuration of LDAP in GitLab requires changes to the `gitlab.rb` configuration file. Below is an example of a complete configuration using an Active Directory. - -The two Active Directory specific values are `active_directory: true` and `uid: 'sAMAccountName'`. `sAMAccountName` is an attribute returned by Active Directory used for GitLab usernames. See the example output from `ldapsearch` for a full list of attributes a "person" object (user) has in **AD** - [`ldapsearch` example](#using-ldapsearch-unix) - -> Both group_base and admin_group configuration options are only available in GitLab Enterprise Edition. See [GitLab EE - LDAP Features](#gitlab-enterprise-edition---ldap-features) - -### Example `gitlab.rb` LDAP - -``` -gitlab_rails['ldap_enabled'] = true -gitlab_rails['ldap_servers'] = { -'main' => { - 'label' => 'GitLab AD', - 'host' => 'ad.example.org', - 'port' => 636, - 'uid' => 'sAMAccountName', - 'encryption' => 'simple_tls', - 'verify_certificates' => true, - 'bind_dn' => 'CN=GitLabSRV,CN=Users,DC=GitLab,DC=org', - 'password' => 'Password1', - 'active_directory' => true, - 'base' => 'OU=GitLab INT,DC=GitLab,DC=org', - 'group_base' => 'OU=Global Groups,OU=GitLab INT,DC=GitLab,DC=org', - 'admin_group' => 'Global Admins' - } -} -``` - -> **Note:** Remember to run `gitlab-ctl reconfigure` after modifying `gitlab.rb` - -## Security improvements (LDAPS) - -Security is an important aspect when deploying an LDAP server. By default, LDAP traffic is transmitted unsecured. LDAP can be secured using SSL/TLS called LDAPS, or commonly "LDAP over SSL". - -Securing LDAP (enabling LDAPS) on Windows Server 2012 involves installing a valid SSL certificate. For full details see Microsoft's guide [How to enable LDAP over SSL with a third-party certification authority](https://support.microsoft.com/en-us/help/321051/how-to-enable-ldap-over-ssl-with-a-third-party-certification-authority) - -> By default a LDAP service listens for connections on TCP and UDP port 389. LDAPS (LDAP over SSL) listens on port 636 - -### Testing you AD server - -#### Using **AdFind** (Windows) - -You can use the [`AdFind`](https://social.technet.microsoft.com/wiki/contents/articles/7535.adfind-command-examples.aspx) utility (on Windows based systems) to test that your LDAP server is accessible and authentication is working correctly. This is a freeware utility built by [Joe Richards](http://www.joeware.net/freetools/tools/adfind/index.htm). - -**Return all objects** - -You can use the filter `objectclass=*` to return all directory objects. - -```sh -adfind -h ad.example.org:636 -ssl -u "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -up Password1 -b "OU=GitLab INT,DC=GitLab,DC=org" -f (objectClass=*) -``` - -**Return single object using filter** - -You can also retrieve a single object by **specifying** the object name or full **DN**. In this example we specify the object name only `CN=Leroy Fox`. - -```sh -adfind -h ad.example.org:636 -ssl -u "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -up Password1 -b "OU=GitLab INT,DC=GitLab,DC=org" -f (&(objectcategory=person)(CN=Leroy Fox))” -``` - -#### Using **ldapsearch** (Unix) - -You can use the `ldapsearch` utility (on Unix based systems) to test that your LDAP server is accessible and authentication is working correctly. This utility is included in the [`ldap-utils`](https://wiki.debian.org/LDAP/LDAPUtils) package. - -**Return all objects** - -You can use the filter `objectclass=*` to return all directory objects. - -```sh -ldapsearch -D "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" \ --w Password1 -p 636 -h ad.example.org \ --b "OU=GitLab INT,DC=GitLab,DC=org" -Z \ --s sub "(objectclass=*)" -``` - -**Return single object using filter** - -You can also retrieve a single object by **specifying** the object name or full **DN**. In this example we specify the object name only `CN=Leroy Fox`. - -```sh -ldapsearch -D "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -w Password1 -p 389 -h ad.example.org -b "OU=GitLab INT,DC=GitLab,DC=org" -Z -s sub "CN=Leroy Fox" -``` - -**Full output of `ldapsearch` command:** - Filtering for _CN=Leroy Fox_ - -``` -# LDAPv3 -# base with scope subtree -# filter: CN=Leroy Fox -# requesting: ALL -# - -# Leroy Fox, Developers, United Kingdom, GitLab INT, GitLab.org -dn: CN=Leroy Fox,OU=Developers,OU=United Kingdom,OU=GitLab INT,DC=GitLab,DC=or - g -objectClass: top -objectClass: person -objectClass: organizationalPerson -objectClass: user -cn: Leroy Fox -sn: Fox -givenName: Leroy -distinguishedName: CN=Leroy Fox,OU=Developers,OU=United Kingdom,OU=GitLab INT, - DC=GitLab,DC=org -instanceType: 4 -whenCreated: 20170210030500.0Z -whenChanged: 20170213050128.0Z -displayName: Leroy Fox -uSNCreated: 16790 -memberOf: CN=DevelopersUK,OU=Global Groups,OU=GitLab INT,DC=GitLab,DC=org -uSNChanged: 20812 -name: Leroy Fox -objectGUID:: rBCAo6NR6E6vfSKgzcUILg== -userAccountControl: 512 -badPwdCount: 0 -codePage: 0 -countryCode: 0 -badPasswordTime: 0 -lastLogoff: 0 -lastLogon: 0 -pwdLastSet: 131311695009850084 -primaryGroupID: 513 -objectSid:: AQUAAAAAAAUVAAAA9GMAb7tdJZvsATf7ZwQAAA== -accountExpires: 9223372036854775807 -logonCount: 0 -sAMAccountName: Leroyf -sAMAccountType: 805306368 -userPrincipalName: Leroyf@GitLab.org -objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=GitLab,DC=org -dSCorePropagationData: 16010101000000.0Z -lastLogonTimestamp: 131314356887754250 - -# search result -search: 2 -result: 0 Success - -# numResponses: 2 -# numEntries: 1 -``` - -## Basic user authentication - -After configuring LDAP, basic authentication will be available. Users can then login using their directory credentials. An extra tab is added to the GitLab login screen for the configured LDAP server (e.g "**GitLab AD**"). - -![GitLab OU Structure](img/user_auth.gif) - -Users that are removed from the LDAP base group (e.g `OU=GitLab INT,DC=GitLab,DC=org`) will be **blocked** in GitLab. [More information](../../administration/auth/ldap.md#security) on LDAP security. - -If `allow_username_or_email_login` is enabled in the LDAP configuration, GitLab will ignore everything after the first '@' in the LDAP username used on login. Example: The username `jon.doe@example.com` is converted to `jon.doe` when authenticating with the LDAP server. Disable this setting if you use `userPrincipalName` as the `uid`. - -## LDAP extended features on GitLab EE - -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 -- Group permissions -- Updating user permissions -- Multiple LDAP servers - -Read through the article on [LDAP for GitLab EE](https://docs.gitlab.com/ee/articles/how_to_configure_ldap_gitlab_ee/) for an overview. +This document was moved to [another location](../../administration/auth/how_to_configure_ldap_gitlab_ce/index.md). diff --git a/doc/articles/index.md b/doc/articles/index.md index 7b60ce1d8b9..06675e15d76 100644 --- a/doc/articles/index.md +++ b/doc/articles/index.md @@ -10,16 +10,6 @@ They are written by members of the GitLab Team and by Part of the articles listed below link to the [GitLab Blog](https://about.gitlab.com/blog/), where they were originally published. -## Authentication - -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): diff --git a/doc/topics/authentication/index.md b/doc/topics/authentication/index.md index 1f30909b0aa..a8aa11265d0 100644 --- a/doc/topics/authentication/index.md +++ b/doc/topics/authentication/index.md @@ -20,7 +20,7 @@ This page gathers all the resources for the topic **Authentication** within GitL - [LDAP (Enterprise Edition)](https://docs.gitlab.com/ee/administration/auth/ldap-ee.html) - [Enforce Two-factor Authentication (2FA)](../../security/two_factor_authentication.md#enforce-two-factor-authentication-2fa) - **Articles:** - - [How to Configure LDAP with GitLab CE](../../articles/how_to_configure_ldap_gitlab_ce/index.md) + - [How to Configure LDAP with GitLab CE](../../administration/auth/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/) - [Feature Highlight: LDAP Integration](https://about.gitlab.com/2014/07/10/feature-highlight-ldap-sync/) - [Debugging LDAP](https://about.gitlab.com/handbook/support/workflows/ldap/debugging_ldap.html) -- cgit v1.2.1 From 0d4548026f3060ca0a8f7aa8d8fc89838bc66130 Mon Sep 17 00:00:00 2001 From: Mayra Cabrera Date: Fri, 22 Dec 2017 17:23:43 +0000 Subject: Extend Cluster Applications to allow installation of Prometheus --- app/assets/javascripts/clusters/clusters_bundle.js | 2 + .../clusters/components/applications.vue | 20 +++ .../clusters/services/clusters_service.js | 1 + .../javascripts/clusters/stores/clusters_store.js | 7 ++ app/assets/stylesheets/pages/clusters.scss | 2 +- app/models/clusters/applications/helm.rb | 17 +-- app/models/clusters/applications/ingress.rb | 23 +--- app/models/clusters/applications/prometheus.rb | 26 ++++ app/models/clusters/cluster.rb | 7 +- app/models/clusters/concerns/application_core.rb | 29 +++++ .../clusters/applications/base_helm_service.rb | 2 +- app/views/projects/clusters/show.html.haml | 1 + ...applications-to-allow-install-to-prometheus.yml | 5 + ...3433_create_clusters_applications_prometheus.rb | 18 +++ db/schema.rb | 9 ++ lib/gitlab/kubernetes/helm.rb | 90 +------------- lib/gitlab/kubernetes/helm/api.rb | 42 +++++++ lib/gitlab/kubernetes/helm/install_command.rb | 53 ++++++++ lib/gitlab/kubernetes/helm/pod.rb | 69 +++++++++++ .../clusters/applications_controller_spec.rb | 2 +- spec/factories/clusters/applications/helm.rb | 5 +- spec/factories/clusters/applications/ingress.rb | 35 ------ .../projects/clusters/applications_spec.rb | 2 +- .../clusters/components/applications_spec.js | 5 + spec/javascripts/clusters/services/mock_data.js | 6 + .../clusters/stores/clusters_store_spec.js | 7 ++ spec/lib/gitlab/kubernetes/helm/api_spec.rb | 69 +++++++++++ .../gitlab/kubernetes/helm/install_command_spec.rb | 111 +++++++++++++++++ spec/lib/gitlab/kubernetes/helm/pod_spec.rb | 86 +++++++++++++ spec/lib/gitlab/kubernetes/helm_spec.rb | 100 --------------- spec/models/clusters/applications/helm_spec.rb | 12 +- spec/models/clusters/applications/ingress_spec.rb | 102 +--------------- .../clusters/applications/prometheus_spec.rb | 16 +++ spec/models/clusters/cluster_spec.rb | 10 +- .../serializers/cluster_application_entity_spec.rb | 4 +- .../check_installation_progress_service_spec.rb | 4 +- .../clusters/applications/install_service_spec.rb | 12 +- .../schedule_installation_service_spec.rb | 2 +- spec/support/cluster_application_spec.rb | 105 ++++++++++++++++ vendor/prometheus/values.yaml | 134 +++++++++++++++++++++ 40 files changed, 865 insertions(+), 387 deletions(-) create mode 100644 app/models/clusters/applications/prometheus.rb create mode 100644 app/models/clusters/concerns/application_core.rb create mode 100644 changelogs/unreleased/41053-extend-cluster-applications-to-allow-install-to-prometheus.yml create mode 100644 db/migrate/20171212203433_create_clusters_applications_prometheus.rb create mode 100644 lib/gitlab/kubernetes/helm/api.rb create mode 100644 lib/gitlab/kubernetes/helm/install_command.rb create mode 100644 lib/gitlab/kubernetes/helm/pod.rb delete mode 100644 spec/factories/clusters/applications/ingress.rb create mode 100644 spec/lib/gitlab/kubernetes/helm/api_spec.rb create mode 100644 spec/lib/gitlab/kubernetes/helm/install_command_spec.rb create mode 100644 spec/lib/gitlab/kubernetes/helm/pod_spec.rb delete mode 100644 spec/lib/gitlab/kubernetes/helm_spec.rb create mode 100644 spec/models/clusters/applications/prometheus_spec.rb create mode 100644 spec/support/cluster_application_spec.rb create mode 100644 vendor/prometheus/values.yaml diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js index 2cfd6179a25..637d0dbde23 100644 --- a/app/assets/javascripts/clusters/clusters_bundle.js +++ b/app/assets/javascripts/clusters/clusters_bundle.js @@ -30,6 +30,7 @@ export default class Clusters { installHelmPath, installIngressPath, installRunnerPath, + installPrometheusPath, clusterStatus, clusterStatusReason, helpPath, @@ -44,6 +45,7 @@ export default class Clusters { installHelmEndpoint: installHelmPath, installIngressEndpoint: installIngressPath, installRunnerEndpoint: installRunnerPath, + installPrometheusEndpoint: installPrometheusPath, }); this.toggle = this.toggle.bind(this); diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue index e5ae439d26e..cd58b88db69 100644 --- a/app/assets/javascripts/clusters/components/applications.vue +++ b/app/assets/javascripts/clusters/components/applications.vue @@ -67,6 +67,16 @@ export default { and send the results back to GitLab.`, )); }, + prometheusDescription() { + return sprintf( + _.escape(s__('ClusterIntegration|Prometheus is an open-source monitoring system with %{gitlabIntegrationLink} to monitor deployed applications.')), { + gitlabIntegrationLink: ` + ${_.escape(s__('ClusterIntegration|Gitlab Integration'))} + `, + }, + false, + ); + }, }, }; @@ -105,6 +115,16 @@ export default { :status-reason="applications.ingress.statusReason" :request-status="applications.ingress.requestStatus" :request-reason="applications.ingress.requestReason" + /> + diff --git a/app/assets/javascripts/clusters/services/clusters_service.js b/app/assets/javascripts/clusters/services/clusters_service.js index 755c2981c2e..13468578f4f 100644 --- a/app/assets/javascripts/clusters/services/clusters_service.js +++ b/app/assets/javascripts/clusters/services/clusters_service.js @@ -7,6 +7,7 @@ export default class ClusterService { helm: this.options.installHelmEndpoint, ingress: this.options.installIngressEndpoint, runner: this.options.installRunnerEndpoint, + prometheus: this.options.installPrometheusEndpoint, }; } diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js index e731cdc3042..bd4a1fb37f9 100644 --- a/app/assets/javascripts/clusters/stores/clusters_store.js +++ b/app/assets/javascripts/clusters/stores/clusters_store.js @@ -28,6 +28,13 @@ export default class ClusterStore { requestStatus: null, requestReason: null, }, + prometheus: { + title: s__('ClusterIntegration|Prometheus'), + status: null, + statusReason: null, + requestStatus: null, + requestReason: null, + }, }, }; } diff --git a/app/assets/stylesheets/pages/clusters.scss b/app/assets/stylesheets/pages/clusters.scss index 88d44131d5b..7b8ee026357 100644 --- a/app/assets/stylesheets/pages/clusters.scss +++ b/app/assets/stylesheets/pages/clusters.scss @@ -6,7 +6,7 @@ .cluster-applications-table { // Wait for the Vue to kick-in and render the applications block - min-height: 302px; + min-height: 400px; } .clusters-dropdown-menu { diff --git a/app/models/clusters/applications/helm.rb b/app/models/clusters/applications/helm.rb index c7949d11ef8..193bb48e54d 100644 --- a/app/models/clusters/applications/helm.rb +++ b/app/models/clusters/applications/helm.rb @@ -3,32 +3,19 @@ module Clusters class Helm < ActiveRecord::Base self.table_name = 'clusters_applications_helm' + include ::Clusters::Concerns::ApplicationCore include ::Clusters::Concerns::ApplicationStatus - belongs_to :cluster, class_name: 'Clusters::Cluster', foreign_key: :cluster_id - default_value_for :version, Gitlab::Kubernetes::Helm::HELM_VERSION - validates :cluster, presence: true - - after_initialize :set_initial_status - - def self.application_name - self.to_s.demodulize.underscore - end - def set_initial_status return unless not_installable? self.status = 'installable' if cluster&.platform_kubernetes_active? end - def name - self.class.application_name - end - def install_command - Gitlab::Kubernetes::Helm::InstallCommand.new(name, true) + Gitlab::Kubernetes::Helm::InstallCommand.new(name, install_helm: true) end end end diff --git a/app/models/clusters/applications/ingress.rb b/app/models/clusters/applications/ingress.rb index 44bd979741e..9024f1df1cd 100644 --- a/app/models/clusters/applications/ingress.rb +++ b/app/models/clusters/applications/ingress.rb @@ -3,41 +3,22 @@ module Clusters class Ingress < ActiveRecord::Base self.table_name = 'clusters_applications_ingress' + include ::Clusters::Concerns::ApplicationCore include ::Clusters::Concerns::ApplicationStatus - belongs_to :cluster, class_name: 'Clusters::Cluster', foreign_key: :cluster_id - - validates :cluster, presence: true - default_value_for :ingress_type, :nginx default_value_for :version, :nginx - after_initialize :set_initial_status - enum ingress_type: { nginx: 1 } - def self.application_name - self.to_s.demodulize.underscore - end - - def set_initial_status - return unless not_installable? - - self.status = 'installable' if cluster&.application_helm_installed? - end - - def name - self.class.application_name - end - def chart 'stable/nginx-ingress' end def install_command - Gitlab::Kubernetes::Helm::InstallCommand.new(name, false, chart) + Gitlab::Kubernetes::Helm::InstallCommand.new(name, chart: chart) end end end diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb new file mode 100644 index 00000000000..9b0787ee6ca --- /dev/null +++ b/app/models/clusters/applications/prometheus.rb @@ -0,0 +1,26 @@ +module Clusters + module Applications + class Prometheus < ActiveRecord::Base + VERSION = "2.0.0".freeze + + self.table_name = 'clusters_applications_prometheus' + + include ::Clusters::Concerns::ApplicationCore + include ::Clusters::Concerns::ApplicationStatus + + default_value_for :version, VERSION + + def chart + 'stable/prometheus' + end + + def chart_values_file + "#{Rails.root}/vendor/#{name}/values.yaml" + end + + def install_command + Gitlab::Kubernetes::Helm::InstallCommand.new(name, chart: chart, chart_values_file: chart_values_file) + end + end + end +end diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index 55419189282..5ecbd4cbceb 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -6,7 +6,8 @@ module Clusters APPLICATIONS = { Applications::Helm.application_name => Applications::Helm, - Applications::Ingress.application_name => Applications::Ingress + Applications::Ingress.application_name => Applications::Ingress, + Applications::Prometheus.application_name => Applications::Prometheus }.freeze belongs_to :user @@ -21,6 +22,7 @@ module Clusters has_one :application_helm, class_name: 'Clusters::Applications::Helm' has_one :application_ingress, class_name: 'Clusters::Applications::Ingress' + has_one :application_prometheus, class_name: 'Clusters::Applications::Prometheus' accepts_nested_attributes_for :provider_gcp, update_only: true accepts_nested_attributes_for :platform_kubernetes, update_only: true @@ -62,7 +64,8 @@ module Clusters def applications [ application_helm || build_application_helm, - application_ingress || build_application_ingress + application_ingress || build_application_ingress, + application_prometheus || build_application_prometheus ] end diff --git a/app/models/clusters/concerns/application_core.rb b/app/models/clusters/concerns/application_core.rb new file mode 100644 index 00000000000..a98fa85a5ff --- /dev/null +++ b/app/models/clusters/concerns/application_core.rb @@ -0,0 +1,29 @@ +module Clusters + module Concerns + module ApplicationCore + extend ActiveSupport::Concern + + included do + belongs_to :cluster, class_name: 'Clusters::Cluster', foreign_key: :cluster_id + + validates :cluster, presence: true + + after_initialize :set_initial_status + + def set_initial_status + return unless not_installable? + + self.status = 'installable' if cluster&.application_helm_installed? + end + + def self.application_name + self.to_s.demodulize.underscore + end + + def name + self.class.application_name + end + end + end + end +end diff --git a/app/services/clusters/applications/base_helm_service.rb b/app/services/clusters/applications/base_helm_service.rb index 9a4ce31cb39..cba1b920f7c 100644 --- a/app/services/clusters/applications/base_helm_service.rb +++ b/app/services/clusters/applications/base_helm_service.rb @@ -18,7 +18,7 @@ module Clusters end def helm_api - @helm_api ||= Gitlab::Kubernetes::Helm.new(kubeclient) + @helm_api ||= Gitlab::Kubernetes::Helm::Api.new(kubeclient) end def install_command diff --git a/app/views/projects/clusters/show.html.haml b/app/views/projects/clusters/show.html.haml index fe6dacf1f0d..0115c64c076 100644 --- a/app/views/projects/clusters/show.html.haml +++ b/app/views/projects/clusters/show.html.haml @@ -9,6 +9,7 @@ .edit-cluster-form.js-edit-cluster-form{ data: { status_path: status_path, install_helm_path: install_applications_namespace_project_cluster_path(@cluster.project.namespace, @cluster.project, @cluster, :helm), install_ingress_path: install_applications_namespace_project_cluster_path(@cluster.project.namespace, @cluster.project, @cluster, :ingress), + install_prometheus_path: install_applications_namespace_project_cluster_path(@cluster.project.namespace, @cluster.project, @cluster, :prometheus), toggle_status: @cluster.enabled? ? 'true': 'false', cluster_status: @cluster.status_name, cluster_status_reason: @cluster.status_reason, diff --git a/changelogs/unreleased/41053-extend-cluster-applications-to-allow-install-to-prometheus.yml b/changelogs/unreleased/41053-extend-cluster-applications-to-allow-install-to-prometheus.yml new file mode 100644 index 00000000000..ffb79d7d79f --- /dev/null +++ b/changelogs/unreleased/41053-extend-cluster-applications-to-allow-install-to-prometheus.yml @@ -0,0 +1,5 @@ +--- +title: Add Prometheus to available Cluster applications +merge_request: 15895 +author: +type: added diff --git a/db/migrate/20171212203433_create_clusters_applications_prometheus.rb b/db/migrate/20171212203433_create_clusters_applications_prometheus.rb new file mode 100644 index 00000000000..dc2531d2691 --- /dev/null +++ b/db/migrate/20171212203433_create_clusters_applications_prometheus.rb @@ -0,0 +1,18 @@ +class CreateClustersApplicationsPrometheus < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def change + create_table :clusters_applications_prometheus do |t| + t.references :cluster, null: false, unique: true, foreign_key: { on_delete: :cascade } + + t.integer :status, null: false + t.string :version, null: false + + t.text :status_reason + + t.timestamps_with_timezone null: false + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 81b594cd0c1..aa5db5da4f0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -568,6 +568,15 @@ ActiveRecord::Schema.define(version: 20171220191323) do t.text "status_reason" end + create_table "clusters_applications_prometheus", force: :cascade do |t| + t.integer "cluster_id", null: false + t.integer "status", null: false + t.string "version", null: false + t.text "status_reason" + t.datetime_with_timezone "created_at", null: false + t.datetime_with_timezone "updated_at", null: false + end + create_table "container_repositories", force: :cascade do |t| t.integer "project_id", null: false t.string "name", null: false diff --git a/lib/gitlab/kubernetes/helm.rb b/lib/gitlab/kubernetes/helm.rb index 407cdefc04d..0f0588b8b23 100644 --- a/lib/gitlab/kubernetes/helm.rb +++ b/lib/gitlab/kubernetes/helm.rb @@ -1,96 +1,8 @@ module Gitlab module Kubernetes - class Helm + module Helm HELM_VERSION = '2.7.0'.freeze NAMESPACE = 'gitlab-managed-apps'.freeze - INSTALL_DEPS = <<-EOS.freeze - set -eo pipefail - apk add -U ca-certificates openssl >/dev/null - wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v${HELM_VERSION}-linux-amd64.tar.gz | tar zxC /tmp >/dev/null - mv /tmp/linux-amd64/helm /usr/bin/ - EOS - - InstallCommand = Struct.new(:name, :install_helm, :chart) do - def pod_name - "install-#{name}" - end - end - - def initialize(kubeclient) - @kubeclient = kubeclient - @namespace = Gitlab::Kubernetes::Namespace.new(NAMESPACE, kubeclient) - end - - def install(command) - @namespace.ensure_exists! - @kubeclient.create_pod(pod_resource(command)) - end - - ## - # Returns Pod phase - # - # https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase - # - # values: "Pending", "Running", "Succeeded", "Failed", "Unknown" - # - def installation_status(pod_name) - @kubeclient.get_pod(pod_name, @namespace.name).status.phase - end - - def installation_log(pod_name) - @kubeclient.get_pod_log(pod_name, @namespace.name).body - end - - def delete_installation_pod!(pod_name) - @kubeclient.delete_pod(pod_name, @namespace.name) - end - - private - - def pod_resource(command) - labels = { 'gitlab.org/action': 'install', 'gitlab.org/application': command.name } - metadata = { name: command.pod_name, namespace: @namespace.name, labels: labels } - container = { - name: 'helm', - image: 'alpine:3.6', - env: generate_pod_env(command), - command: %w(/bin/sh), - args: %w(-c $(COMMAND_SCRIPT)) - } - spec = { containers: [container], restartPolicy: 'Never' } - - ::Kubeclient::Resource.new(metadata: metadata, spec: spec) - end - - def generate_pod_env(command) - { - HELM_VERSION: HELM_VERSION, - TILLER_NAMESPACE: @namespace.name, - COMMAND_SCRIPT: generate_script(command) - }.map { |key, value| { name: key, value: value } } - end - - def generate_script(command) - [ - INSTALL_DEPS, - helm_init_command(command), - helm_install_command(command) - ].join("\n") - end - - def helm_init_command(command) - if command.install_helm - 'helm init >/dev/null' - else - 'helm init --client-only >/dev/null' - end - end - - def helm_install_command(command) - return if command.chart.nil? - - "helm install #{command.chart} --name #{command.name} --namespace #{@namespace.name} >/dev/null" - end end end end diff --git a/lib/gitlab/kubernetes/helm/api.rb b/lib/gitlab/kubernetes/helm/api.rb new file mode 100644 index 00000000000..ebd7dc1b100 --- /dev/null +++ b/lib/gitlab/kubernetes/helm/api.rb @@ -0,0 +1,42 @@ +module Gitlab + module Kubernetes + module Helm + class Api + def initialize(kubeclient) + @kubeclient = kubeclient + @namespace = Gitlab::Kubernetes::Namespace.new(Gitlab::Kubernetes::Helm::NAMESPACE, kubeclient) + end + + def install(command) + @namespace.ensure_exists! + @kubeclient.create_pod(pod_resource(command)) + end + + ## + # Returns Pod phase + # + # https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase + # + # values: "Pending", "Running", "Succeeded", "Failed", "Unknown" + # + def installation_status(pod_name) + @kubeclient.get_pod(pod_name, @namespace.name).status.phase + end + + def installation_log(pod_name) + @kubeclient.get_pod_log(pod_name, @namespace.name).body + end + + def delete_installation_pod!(pod_name) + @kubeclient.delete_pod(pod_name, @namespace.name) + end + + private + + def pod_resource(command) + Pod.new(command, @namespace.name, @kubeclient).generate + end + end + end + end +end diff --git a/lib/gitlab/kubernetes/helm/install_command.rb b/lib/gitlab/kubernetes/helm/install_command.rb new file mode 100644 index 00000000000..8d8c441a4b1 --- /dev/null +++ b/lib/gitlab/kubernetes/helm/install_command.rb @@ -0,0 +1,53 @@ +module Gitlab + module Kubernetes + module Helm + class InstallCommand + attr_reader :name, :install_helm, :chart, :chart_values_file + + def initialize(name, install_helm: false, chart: false, chart_values_file: false) + @name = name + @install_helm = install_helm + @chart = chart + @chart_values_file = chart_values_file + end + + def pod_name + "install-#{name}" + end + + def generate_script(namespace_name) + [ + install_dps_command, + init_command, + complete_command(namespace_name) + ].join("\n") + end + + private + + def init_command + if install_helm + 'helm init >/dev/null' + else + 'helm init --client-only >/dev/null' + end + end + + def complete_command(namespace_name) + return unless chart + + "helm install #{chart} --name #{name} --namespace #{namespace_name} >/dev/null" + end + + def install_dps_command + <<~HEREDOC + set -eo pipefail + apk add -U ca-certificates openssl >/dev/null + wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v#{Gitlab::Kubernetes::Helm::HELM_VERSION}-linux-amd64.tar.gz | tar zxC /tmp >/dev/null + mv /tmp/linux-amd64/helm /usr/bin/ + HEREDOC + end + end + end + end +end diff --git a/lib/gitlab/kubernetes/helm/pod.rb b/lib/gitlab/kubernetes/helm/pod.rb new file mode 100644 index 00000000000..233f6bf6227 --- /dev/null +++ b/lib/gitlab/kubernetes/helm/pod.rb @@ -0,0 +1,69 @@ +module Gitlab + module Kubernetes + module Helm + class Pod + def initialize(command, namespace_name, kubeclient) + @command = command + @namespace_name = namespace_name + @kubeclient = kubeclient + end + + def generate + spec = { containers: [container_specification], restartPolicy: 'Never' } + if command.chart_values_file + generate_config_map + spec['volumes'] = volumes_specification + end + ::Kubeclient::Resource.new(metadata: metadata, spec: spec) + end + + private + + attr_reader :command, :namespace_name, :kubeclient + + def container_specification + container = { + name: 'helm', + image: 'alpine:3.6', + env: generate_pod_env(command), + command: %w(/bin/sh), + args: %w(-c $(COMMAND_SCRIPT)) + } + container[:volumeMounts] = volume_mounts_specification if command.chart_values_file + container + end + + def labels + { 'gitlab.org/action': 'install', 'gitlab.org/application': command.name } + end + + def metadata + { name: command.pod_name, namespace: namespace_name, labels: labels } + end + + def volume_mounts_specification + [{ name: 'config-volume', mountPath: '/etc/config' }] + end + + def volumes_specification + [{ name: 'config-volume', configMap: { name: 'values-config' } }] + end + + def generate_pod_env(command) + { + HELM_VERSION: Gitlab::Kubernetes::Helm::HELM_VERSION, + TILLER_NAMESPACE: namespace_name, + COMMAND_SCRIPT: command.generate_script(namespace_name) + }.map { |key, value| { name: key, value: value } } + end + + def generate_config_map + resource = ::Kubeclient::Resource.new + resource.metadata = { name: 'values-config', namespace: namespace_name } + resource.data = YAML.load_file(command.chart_values_file) + kubeclient.create_config_map(resource) + end + end + end + end +end diff --git a/spec/controllers/projects/clusters/applications_controller_spec.rb b/spec/controllers/projects/clusters/applications_controller_spec.rb index 8b460646059..99fdff5f846 100644 --- a/spec/controllers/projects/clusters/applications_controller_spec.rb +++ b/spec/controllers/projects/clusters/applications_controller_spec.rb @@ -52,7 +52,7 @@ describe Projects::Clusters::ApplicationsController do context 'when application is already installing' do before do - create(:cluster_applications_helm, :installing, cluster: cluster) + create(:clusters_applications_helm, :installing, cluster: cluster) end it 'returns 400' do diff --git a/spec/factories/clusters/applications/helm.rb b/spec/factories/clusters/applications/helm.rb index d82fa8e34aa..775fbb3d27b 100644 --- a/spec/factories/clusters/applications/helm.rb +++ b/spec/factories/clusters/applications/helm.rb @@ -1,5 +1,5 @@ FactoryBot.define do - factory :cluster_applications_helm, class: Clusters::Applications::Helm do + factory :clusters_applications_helm, class: Clusters::Applications::Helm do cluster factory: %i(cluster provided_by_gcp) trait :not_installable do @@ -31,5 +31,8 @@ FactoryBot.define do installing updated_at ClusterWaitForAppInstallationWorker::TIMEOUT.ago end + + factory :clusters_applications_ingress, class: Clusters::Applications::Ingress + factory :clusters_applications_prometheus, class: Clusters::Applications::Prometheus end end diff --git a/spec/factories/clusters/applications/ingress.rb b/spec/factories/clusters/applications/ingress.rb deleted file mode 100644 index 85f54a9d744..00000000000 --- a/spec/factories/clusters/applications/ingress.rb +++ /dev/null @@ -1,35 +0,0 @@ -FactoryBot.define do - factory :cluster_applications_ingress, class: Clusters::Applications::Ingress do - cluster factory: %i(cluster provided_by_gcp) - - trait :not_installable do - status(-2) - end - - trait :installable do - status 0 - end - - trait :scheduled do - status 1 - end - - trait :installing do - status 2 - end - - trait :installed do - status 3 - end - - trait :errored do - status(-1) - status_reason 'something went wrong' - end - - trait :timeouted do - installing - updated_at ClusterWaitForAppInstallationWorker::TIMEOUT.ago - end - end -end diff --git a/spec/features/projects/clusters/applications_spec.rb b/spec/features/projects/clusters/applications_spec.rb index b34cd061ec6..9c4abec115f 100644 --- a/spec/features/projects/clusters/applications_spec.rb +++ b/spec/features/projects/clusters/applications_spec.rb @@ -73,7 +73,7 @@ feature 'Clusters Applications', :js do before do allow(ClusterInstallAppWorker).to receive(:perform_async).and_return(nil) - create(:cluster_applications_helm, :installed, cluster: cluster) + create(:clusters_applications_helm, :installed, cluster: cluster) page.within('.js-cluster-application-row-ingress') do page.find(:css, '.js-cluster-application-install-button').click diff --git a/spec/javascripts/clusters/components/applications_spec.js b/spec/javascripts/clusters/components/applications_spec.js index 7460da031c4..1a8affad4e3 100644 --- a/spec/javascripts/clusters/components/applications_spec.js +++ b/spec/javascripts/clusters/components/applications_spec.js @@ -21,6 +21,7 @@ describe('Applications', () => { helm: { title: 'Helm Tiller' }, ingress: { title: 'Ingress' }, runner: { title: 'GitLab Runner' }, + prometheus: { title: 'Prometheus' }, }, }); }); @@ -33,6 +34,10 @@ describe('Applications', () => { expect(vm.$el.querySelector('.js-cluster-application-row-ingress')).toBeDefined(); }); + it('renders a row for Prometheus', () => { + expect(vm.$el.querySelector('.js-cluster-application-row-prometheus')).toBeDefined(); + }); + /* * / it('renders a row for GitLab Runner', () => { expect(vm.$el.querySelector('.js-cluster-application-row-runner')).toBeDefined(); diff --git a/spec/javascripts/clusters/services/mock_data.js b/spec/javascripts/clusters/services/mock_data.js index af6b6a73819..253b3c45243 100644 --- a/spec/javascripts/clusters/services/mock_data.js +++ b/spec/javascripts/clusters/services/mock_data.js @@ -22,6 +22,11 @@ const CLUSTERS_MOCK_DATA = { name: 'runner', status: APPLICATION_INSTALLING, status_reason: null, + }, + { + name: 'prometheus', + status: APPLICATION_ERROR, + status_reason: 'Cannot connect', }], }, }, @@ -30,6 +35,7 @@ const CLUSTERS_MOCK_DATA = { '/gitlab-org/gitlab-shell/clusters/1/applications/helm': { }, '/gitlab-org/gitlab-shell/clusters/1/applications/ingress': { }, '/gitlab-org/gitlab-shell/clusters/1/applications/runner': { }, + '/gitlab-org/gitlab-shell/clusters/1/applications/prometheus': { }, }, }; diff --git a/spec/javascripts/clusters/stores/clusters_store_spec.js b/spec/javascripts/clusters/stores/clusters_store_spec.js index cb8b3d38e2e..ec2889355e6 100644 --- a/spec/javascripts/clusters/stores/clusters_store_spec.js +++ b/spec/javascripts/clusters/stores/clusters_store_spec.js @@ -82,6 +82,13 @@ describe('Clusters Store', () => { requestStatus: null, requestReason: null, }, + prometheus: { + title: 'Prometheus', + status: mockResponseData.applications[3].status, + statusReason: mockResponseData.applications[3].status_reason, + requestStatus: null, + requestReason: null, + }, }, }); }); diff --git a/spec/lib/gitlab/kubernetes/helm/api_spec.rb b/spec/lib/gitlab/kubernetes/helm/api_spec.rb new file mode 100644 index 00000000000..69112fe90b1 --- /dev/null +++ b/spec/lib/gitlab/kubernetes/helm/api_spec.rb @@ -0,0 +1,69 @@ +require 'spec_helper' + +describe Gitlab::Kubernetes::Helm::Api do + let(:client) { double('kubernetes client') } + let(:helm) { described_class.new(client) } + let(:gitlab_namespace) { Gitlab::Kubernetes::Helm::NAMESPACE } + let(:namespace) { Gitlab::Kubernetes::Namespace.new(gitlab_namespace, client) } + let(:install_helm) { true } + let(:chart) { 'stable/a_chart' } + let(:application_name) { 'app_name' } + let(:command) { Gitlab::Kubernetes::Helm::InstallCommand.new(application_name, install_helm: install_helm, chart: chart) } + subject { helm } + + before do + allow(Gitlab::Kubernetes::Namespace).to receive(:new).with(gitlab_namespace, client).and_return(namespace) + end + + describe '#initialize' do + it 'creates a namespace object' do + expect(Gitlab::Kubernetes::Namespace).to receive(:new).with(gitlab_namespace, client) + + subject + end + end + + describe '#install' do + before do + allow(client).to receive(:create_pod).and_return(nil) + allow(namespace).to receive(:ensure_exists!).once + end + + it 'ensures the namespace exists before creating the POD' do + expect(namespace).to receive(:ensure_exists!).once.ordered + expect(client).to receive(:create_pod).once.ordered + + subject.install(command) + end + end + + describe '#installation_status' do + let(:phase) { Gitlab::Kubernetes::Pod::RUNNING } + let(:pod) { Kubeclient::Resource.new(status: { phase: phase }) } # partial representation + + it 'fetches POD phase from kubernetes cluster' do + expect(client).to receive(:get_pod).with(command.pod_name, gitlab_namespace).once.and_return(pod) + + expect(subject.installation_status(command.pod_name)).to eq(phase) + end + end + + describe '#installation_log' do + let(:log) { 'some output' } + let(:response) { RestClient::Response.new(log) } + + it 'fetches POD phase from kubernetes cluster' do + expect(client).to receive(:get_pod_log).with(command.pod_name, gitlab_namespace).once.and_return(response) + + expect(subject.installation_log(command.pod_name)).to eq(log) + end + end + + describe '#delete_installation_pod!' do + it 'deletes the POD from kubernetes cluster' do + expect(client).to receive(:delete_pod).with(command.pod_name, gitlab_namespace).once + + subject.delete_installation_pod!(command.pod_name) + end + end +end diff --git a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb new file mode 100644 index 00000000000..4afe48e72ad --- /dev/null +++ b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb @@ -0,0 +1,111 @@ +require 'rails_helper' + +describe Gitlab::Kubernetes::Helm::InstallCommand do + let(:prometheus) { create(:clusters_applications_prometheus) } + + describe "#initialize" do + context "With all the params" do + subject { described_class.new(prometheus.name, install_helm: true, chart: prometheus.chart, chart_values_file: prometheus.chart_values_file) } + + it 'should assign all parameters' do + expect(subject.name).to eq(prometheus.name) + expect(subject.install_helm).to be_truthy + expect(subject.chart).to eq(prometheus.chart) + expect(subject.chart_values_file).to eq("#{Rails.root}/vendor/prometheus/values.yaml") + end + end + + context 'when install_helm is not set' do + subject { described_class.new(prometheus.name, chart: prometheus.chart, chart_values_file: true) } + + it 'should set install_helm as false' do + expect(subject.install_helm).to be_falsy + end + end + + context 'when chart is not set' do + subject { described_class.new(prometheus.name, install_helm: true) } + + it 'should set chart as nil' do + expect(subject.chart).to be_falsy + end + end + + context 'when chart_values_file is not set' do + subject { described_class.new(prometheus.name, install_helm: true, chart: prometheus.chart) } + + it 'should set chart_values_file as nil' do + expect(subject.chart_values_file).to be_falsy + end + end + end + + describe "#generate_script" do + let(:install_command) { described_class.new(prometheus.name, install_helm: install_helm) } + let(:client) { double('kubernetes client') } + let(:namespace) { Gitlab::Kubernetes::Namespace.new(Gitlab::Kubernetes::Helm::NAMESPACE, client) } + subject { install_command.send(:generate_script, namespace.name) } + + context 'when install helm is true' do + let(:install_helm) { true } + let(:command) do + <<~MSG + set -eo pipefail + apk add -U ca-certificates openssl >/dev/null + wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null + mv /tmp/linux-amd64/helm /usr/bin/ + + helm init >/dev/null + MSG + end + + it 'should return appropriate command' do + is_expected.to eq(command) + end + end + + context 'when install helm is false' do + let(:install_helm) { false } + let(:command) do + <<~MSG + set -eo pipefail + apk add -U ca-certificates openssl >/dev/null + wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null + mv /tmp/linux-amd64/helm /usr/bin/ + + helm init --client-only >/dev/null + MSG + end + + it 'should return appropriate command' do + is_expected.to eq(command) + end + end + + context 'when chart is present' do + let(:install_command) { described_class.new(prometheus.name, chart: prometheus.chart) } + let(:command) do + <<~MSG.chomp + set -eo pipefail + apk add -U ca-certificates openssl >/dev/null + wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null + mv /tmp/linux-amd64/helm /usr/bin/ + + helm init --client-only >/dev/null + helm install #{prometheus.chart} --name #{prometheus.name} --namespace #{namespace.name} >/dev/null + MSG + end + + it 'should return appropriate command' do + is_expected.to eq(command) + end + end + end + + describe "#pod_name" do + let(:install_command) { described_class.new(prometheus.name, install_helm: true, chart: prometheus.chart, chart_values_file: true) } + subject { install_command.send(:pod_name) } + + it { is_expected.to eq('install-prometheus') } + end +end diff --git a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb new file mode 100644 index 00000000000..906b10b96d4 --- /dev/null +++ b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb @@ -0,0 +1,86 @@ +require 'rails_helper' + +describe Gitlab::Kubernetes::Helm::Pod do + describe '#generate' do + let(:cluster) { create(:cluster) } + let(:app) { create(:clusters_applications_prometheus, cluster: cluster) } + let(:command) { app.install_command } + let(:client) { double('kubernetes client') } + let(:namespace) { Gitlab::Kubernetes::Namespace.new(Gitlab::Kubernetes::Helm::NAMESPACE, client) } + subject { described_class.new(command, namespace.name, client) } + + before do + allow(client).to receive(:create_config_map).and_return(nil) + end + + shared_examples 'helm pod' do + it 'should generate a Kubeclient::Resource' do + expect(subject.generate).to be_a_kind_of(Kubeclient::Resource) + end + + it 'should generate the appropriate metadata' do + metadata = subject.generate.metadata + expect(metadata.name).to eq("install-#{app.name}") + expect(metadata.namespace).to eq('gitlab-managed-apps') + expect(metadata.labels['gitlab.org/action']).to eq('install') + expect(metadata.labels['gitlab.org/application']).to eq(app.name) + end + + it 'should generate a container spec' do + spec = subject.generate.spec + expect(spec.containers.count).to eq(1) + end + + it 'should generate the appropriate specifications for the container' do + container = subject.generate.spec.containers.first + expect(container.name).to eq('helm') + expect(container.image).to eq('alpine:3.6') + expect(container.env.count).to eq(3) + expect(container.env.map(&:name)).to match_array([:HELM_VERSION, :TILLER_NAMESPACE, :COMMAND_SCRIPT]) + expect(container.command).to match_array(["/bin/sh"]) + expect(container.args).to match_array(["-c", "$(COMMAND_SCRIPT)"]) + end + + it 'should include a never restart policy' do + spec = subject.generate.spec + expect(spec.restartPolicy).to eq('Never') + end + end + + context 'with a configuration file' do + it_behaves_like 'helm pod' + + it 'should include volumes for the container' do + container = subject.generate.spec.containers.first + expect(container.volumeMounts.first['name']).to eq('config-volume') + expect(container.volumeMounts.first['mountPath']).to eq('/etc/config') + end + + it 'should include a volume inside the specification' do + spec = subject.generate.spec + expect(spec.volumes.first['name']).to eq('config-volume') + end + + it 'should mount configMap specification in the volume' do + spec = subject.generate.spec + expect(spec.volumes.first.configMap['name']).to eq('values-config') + end + end + + context 'without a configuration file' do + let(:app) { create(:clusters_applications_ingress, cluster: cluster) } + + it_behaves_like 'helm pod' + + it 'should not include volumeMounts inside the container' do + container = subject.generate.spec.containers.first + expect(container.volumeMounts).to be_nil + end + + it 'should not a volume inside the specification' do + spec = subject.generate.spec + expect(spec.volumes).to be_nil + end + end + end +end diff --git a/spec/lib/gitlab/kubernetes/helm_spec.rb b/spec/lib/gitlab/kubernetes/helm_spec.rb deleted file mode 100644 index 15f99b0401f..00000000000 --- a/spec/lib/gitlab/kubernetes/helm_spec.rb +++ /dev/null @@ -1,100 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Kubernetes::Helm do - let(:client) { double('kubernetes client') } - let(:helm) { described_class.new(client) } - let(:namespace) { Gitlab::Kubernetes::Namespace.new(described_class::NAMESPACE, client) } - let(:install_helm) { true } - let(:chart) { 'stable/a_chart' } - let(:application_name) { 'app_name' } - let(:command) { Gitlab::Kubernetes::Helm::InstallCommand.new(application_name, install_helm, chart) } - subject { helm } - - before do - allow(Gitlab::Kubernetes::Namespace).to receive(:new).with(described_class::NAMESPACE, client).and_return(namespace) - end - - describe '#initialize' do - it 'creates a namespace object' do - expect(Gitlab::Kubernetes::Namespace).to receive(:new).with(described_class::NAMESPACE, client) - - subject - end - end - - describe '#install' do - before do - allow(client).to receive(:create_pod).and_return(nil) - allow(namespace).to receive(:ensure_exists!).once - end - - it 'ensures the namespace exists before creating the POD' do - expect(namespace).to receive(:ensure_exists!).once.ordered - expect(client).to receive(:create_pod).once.ordered - - subject.install(command) - end - end - - describe '#installation_status' do - let(:phase) { Gitlab::Kubernetes::Pod::RUNNING } - let(:pod) { Kubeclient::Resource.new(status: { phase: phase }) } # partial representation - - it 'fetches POD phase from kubernetes cluster' do - expect(client).to receive(:get_pod).with(command.pod_name, described_class::NAMESPACE).once.and_return(pod) - - expect(subject.installation_status(command.pod_name)).to eq(phase) - end - end - - describe '#installation_log' do - let(:log) { 'some output' } - let(:response) { RestClient::Response.new(log) } - - it 'fetches POD phase from kubernetes cluster' do - expect(client).to receive(:get_pod_log).with(command.pod_name, described_class::NAMESPACE).once.and_return(response) - - expect(subject.installation_log(command.pod_name)).to eq(log) - end - end - - describe '#delete_installation_pod!' do - it 'deletes the POD from kubernetes cluster' do - expect(client).to receive(:delete_pod).with(command.pod_name, described_class::NAMESPACE).once - - subject.delete_installation_pod!(command.pod_name) - end - end - - describe '#helm_init_command' do - subject { helm.send(:helm_init_command, command) } - - context 'when command.install_helm is true' do - let(:install_helm) { true } - - it { is_expected.to eq('helm init >/dev/null') } - end - - context 'when command.install_helm is false' do - let(:install_helm) { false } - - it { is_expected.to eq('helm init --client-only >/dev/null') } - end - end - - describe '#helm_install_command' do - subject { helm.send(:helm_install_command, command) } - - context 'when command.chart is nil' do - let(:chart) { nil } - - it { is_expected.to be_nil } - end - - context 'when command.chart is set' do - let(:chart) { 'stable/a_chart' } - - it { is_expected.to eq("helm install #{chart} --name #{application_name} --namespace #{namespace.name} >/dev/null")} - end - end -end diff --git a/spec/models/clusters/applications/helm_spec.rb b/spec/models/clusters/applications/helm_spec.rb index f8855079842..eb57abaf6ef 100644 --- a/spec/models/clusters/applications/helm_spec.rb +++ b/spec/models/clusters/applications/helm_spec.rb @@ -40,13 +40,13 @@ describe Clusters::Applications::Helm do describe '#install_command' do it 'has all the needed information' do - expect(subject.install_command).to have_attributes(name: subject.name, install_helm: true, chart: nil) + expect(subject.install_command).to have_attributes(name: subject.name, install_helm: true) end end describe 'status state machine' do describe '#make_installing' do - subject { create(:cluster_applications_helm, :scheduled) } + subject { create(:clusters_applications_helm, :scheduled) } it 'is installing' do subject.make_installing! @@ -56,7 +56,7 @@ describe Clusters::Applications::Helm do end describe '#make_installed' do - subject { create(:cluster_applications_helm, :installing) } + subject { create(:clusters_applications_helm, :installing) } it 'is installed' do subject.make_installed @@ -66,7 +66,7 @@ describe Clusters::Applications::Helm do end describe '#make_errored' do - subject { create(:cluster_applications_helm, :installing) } + subject { create(:clusters_applications_helm, :installing) } let(:reason) { 'some errors' } it 'is errored' do @@ -78,7 +78,7 @@ describe Clusters::Applications::Helm do end describe '#make_scheduled' do - subject { create(:cluster_applications_helm, :installable) } + subject { create(:clusters_applications_helm, :installable) } it 'is scheduled' do subject.make_scheduled @@ -87,7 +87,7 @@ describe Clusters::Applications::Helm do end describe 'when was errored' do - subject { create(:cluster_applications_helm, :errored) } + subject { create(:clusters_applications_helm, :errored) } it 'clears #status_reason' do expect(subject.status_reason).not_to be_nil diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb index b83472e1944..619c088b0bf 100644 --- a/spec/models/clusters/applications/ingress_spec.rb +++ b/spec/models/clusters/applications/ingress_spec.rb @@ -4,105 +4,5 @@ describe Clusters::Applications::Ingress do it { is_expected.to belong_to(:cluster) } it { is_expected.to validate_presence_of(:cluster) } - describe '#name' do - it 'is .application_name' do - expect(subject.name).to eq(described_class.application_name) - end - - it 'is recorded in Clusters::Cluster::APPLICATIONS' do - expect(Clusters::Cluster::APPLICATIONS[subject.name]).to eq(described_class) - end - end - - describe '#status' do - let(:cluster) { create(:cluster, :provided_by_gcp) } - - subject { described_class.new(cluster: cluster) } - - it 'defaults to :not_installable' do - expect(subject.status_name).to be(:not_installable) - end - - context 'when application helm is scheduled' do - before do - create(:cluster_applications_helm, :scheduled, cluster: cluster) - end - - it 'defaults to :not_installable' do - expect(subject.status_name).to be(:not_installable) - end - end - - context 'when application helm is installed' do - before do - create(:cluster_applications_helm, :installed, cluster: cluster) - end - - it 'defaults to :installable' do - expect(subject.status_name).to be(:installable) - end - end - end - - describe '#install_command' do - it 'has all the needed information' do - expect(subject.install_command).to have_attributes(name: subject.name, install_helm: false, chart: subject.chart) - end - end - - describe 'status state machine' do - describe '#make_installing' do - subject { create(:cluster_applications_ingress, :scheduled) } - - it 'is installing' do - subject.make_installing! - - expect(subject).to be_installing - end - end - - describe '#make_installed' do - subject { create(:cluster_applications_ingress, :installing) } - - it 'is installed' do - subject.make_installed - - expect(subject).to be_installed - end - end - - describe '#make_errored' do - subject { create(:cluster_applications_ingress, :installing) } - let(:reason) { 'some errors' } - - it 'is errored' do - subject.make_errored(reason) - - expect(subject).to be_errored - expect(subject.status_reason).to eq(reason) - end - end - - describe '#make_scheduled' do - subject { create(:cluster_applications_ingress, :installable) } - - it 'is scheduled' do - subject.make_scheduled - - expect(subject).to be_scheduled - end - - describe 'when was errored' do - subject { create(:cluster_applications_ingress, :errored) } - - it 'clears #status_reason' do - expect(subject.status_reason).not_to be_nil - - subject.make_scheduled! - - expect(subject.status_reason).to be_nil - end - end - end - end + include_examples 'cluster application specs', described_class end diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb new file mode 100644 index 00000000000..696099f7cf7 --- /dev/null +++ b/spec/models/clusters/applications/prometheus_spec.rb @@ -0,0 +1,16 @@ +require 'rails_helper' + +describe Clusters::Applications::Prometheus do + it { is_expected.to belong_to(:cluster) } + it { is_expected.to validate_presence_of(:cluster) } + + include_examples 'cluster application specs', described_class + + describe "#chart_values_file" do + subject { create(:clusters_applications_prometheus).chart_values_file } + + it 'should return chart values file path' do + expect(subject).to eq("#{Rails.root}/vendor/prometheus/values.yaml") + end + end +end diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 2683d21ddbe..799d7ced116 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -5,6 +5,9 @@ describe Clusters::Cluster do it { is_expected.to have_many(:projects) } it { is_expected.to have_one(:provider_gcp) } it { is_expected.to have_one(:platform_kubernetes) } + it { is_expected.to have_one(:application_helm) } + it { is_expected.to have_one(:application_ingress) } + it { is_expected.to have_one(:application_prometheus) } it { is_expected.to delegate_method(:status).to(:provider) } it { is_expected.to delegate_method(:status_reason).to(:provider) } it { is_expected.to delegate_method(:status_name).to(:provider) } @@ -190,11 +193,12 @@ describe Clusters::Cluster do end context 'when applications are created' do - let!(:helm) { create(:cluster_applications_helm, cluster: cluster) } - let!(:ingress) { create(:cluster_applications_ingress, cluster: cluster) } + let!(:helm) { create(:clusters_applications_helm, cluster: cluster) } + let!(:ingress) { create(:clusters_applications_ingress, cluster: cluster) } + let!(:prometheus) { create(:clusters_applications_prometheus, cluster: cluster) } it 'returns a list of created applications' do - is_expected.to contain_exactly(helm, ingress) + is_expected.to contain_exactly(helm, ingress, prometheus) end end end diff --git a/spec/serializers/cluster_application_entity_spec.rb b/spec/serializers/cluster_application_entity_spec.rb index 87c7b2ad36e..b5a55b4ef6e 100644 --- a/spec/serializers/cluster_application_entity_spec.rb +++ b/spec/serializers/cluster_application_entity_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe ClusterApplicationEntity do describe '#as_json' do - let(:application) { build(:cluster_applications_helm) } + let(:application) { build(:clusters_applications_helm) } subject { described_class.new(application).as_json } it 'has name' do @@ -18,7 +18,7 @@ describe ClusterApplicationEntity do end context 'when application is errored' do - let(:application) { build(:cluster_applications_helm, :errored) } + let(:application) { build(:clusters_applications_helm, :errored) } it 'has corresponded data' do expect(subject[:status]).to eq(:errored) diff --git a/spec/services/clusters/applications/check_installation_progress_service_spec.rb b/spec/services/clusters/applications/check_installation_progress_service_spec.rb index 75fc05d36e9..6894c1797b0 100644 --- a/spec/services/clusters/applications/check_installation_progress_service_spec.rb +++ b/spec/services/clusters/applications/check_installation_progress_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Clusters::Applications::CheckInstallationProgressService do RESCHEDULE_PHASES = Gitlab::Kubernetes::Pod::PHASES - [Gitlab::Kubernetes::Pod::SUCCEEDED, Gitlab::Kubernetes::Pod::FAILED].freeze - let(:application) { create(:cluster_applications_helm, :installing) } + let(:application) { create(:clusters_applications_helm, :installing) } let(:service) { described_class.new(application) } let(:phase) { Gitlab::Kubernetes::Pod::UNKNOWN } let(:errors) { nil } @@ -33,7 +33,7 @@ describe Clusters::Applications::CheckInstallationProgressService do end context 'when timeouted' do - let(:application) { create(:cluster_applications_helm, :timeouted) } + let(:application) { create(:clusters_applications_helm, :timeouted) } it_behaves_like 'a terminated installation' diff --git a/spec/services/clusters/applications/install_service_spec.rb b/spec/services/clusters/applications/install_service_spec.rb index 054a49ffedf..ad175226e92 100644 --- a/spec/services/clusters/applications/install_service_spec.rb +++ b/spec/services/clusters/applications/install_service_spec.rb @@ -2,17 +2,19 @@ require 'spec_helper' describe Clusters::Applications::InstallService do describe '#execute' do - let(:application) { create(:cluster_applications_helm, :scheduled) } + let(:application) { create(:clusters_applications_helm, :scheduled) } + let!(:install_command) { application.install_command } let(:service) { described_class.new(application) } - let(:helm_client) { instance_double(Gitlab::Kubernetes::Helm) } + let(:helm_client) { instance_double(Gitlab::Kubernetes::Helm::Api) } before do + allow(service).to receive(:install_command).and_return(install_command) allow(service).to receive(:helm_api).and_return(helm_client) end context 'when there are no errors' do before do - expect(helm_client).to receive(:install).with(application.install_command) + expect(helm_client).to receive(:install).with(install_command) allow(ClusterWaitForAppInstallationWorker).to receive(:perform_in).and_return(nil) end @@ -33,7 +35,7 @@ describe Clusters::Applications::InstallService do context 'when k8s cluster communication fails' do before do error = KubeException.new(500, 'system failure', nil) - expect(helm_client).to receive(:install).with(application.install_command).and_raise(error) + expect(helm_client).to receive(:install).with(install_command).and_raise(error) end it 'make the application errored' do @@ -45,7 +47,7 @@ describe Clusters::Applications::InstallService do end context 'when application cannot be persisted' do - let(:application) { build(:cluster_applications_helm, :scheduled) } + let(:application) { build(:clusters_applications_helm, :scheduled) } it 'make the application errored' do expect(application).to receive(:make_installing!).once.and_raise(ActiveRecord::RecordInvalid) diff --git a/spec/services/clusters/applications/schedule_installation_service_spec.rb b/spec/services/clusters/applications/schedule_installation_service_spec.rb index 047a6e44dab..473dbcbb692 100644 --- a/spec/services/clusters/applications/schedule_installation_service_spec.rb +++ b/spec/services/clusters/applications/schedule_installation_service_spec.rb @@ -34,7 +34,7 @@ describe Clusters::Applications::ScheduleInstallationService do end context 'when installation is already in progress' do - let(:application) { create(:cluster_applications_helm, :installing) } + let(:application) { create(:clusters_applications_helm, :installing) } let(:cluster) { application.cluster } it_behaves_like 'a failing service' diff --git a/spec/support/cluster_application_spec.rb b/spec/support/cluster_application_spec.rb new file mode 100644 index 00000000000..ab77910a050 --- /dev/null +++ b/spec/support/cluster_application_spec.rb @@ -0,0 +1,105 @@ +shared_examples 'cluster application specs' do + let(:factory_name) { described_class.to_s.downcase.gsub("::", "_") } + + describe '#name' do + it 'is .application_name' do + expect(subject.name).to eq(described_class.application_name) + end + + it 'is recorded in Clusters::Cluster::APPLICATIONS' do + expect(Clusters::Cluster::APPLICATIONS[subject.name]).to eq(described_class) + end + end + + describe '#status' do + let(:cluster) { create(:cluster, :provided_by_gcp) } + + subject { described_class.new(cluster: cluster) } + + it 'defaults to :not_installable' do + expect(subject.status_name).to be(:not_installable) + end + + context 'when application helm is scheduled' do + before do + create(factory_name, :scheduled, cluster: cluster) + end + + it 'defaults to :not_installable' do + expect(subject.status_name).to be(:not_installable) + end + end + + context 'when application helm is installed' do + before do + create(:clusters_applications_helm, :installed, cluster: cluster) + end + + it 'defaults to :installable' do + expect(subject.status_name).to be(:installable) + end + end + end + + describe '#install_command' do + it 'has all the needed information' do + expect(subject.install_command).to have_attributes(name: subject.name, install_helm: false) + end + end + + describe 'status state machine' do + describe '#make_installing' do + subject { create(factory_name, :scheduled) } + + it 'is installing' do + subject.make_installing! + + expect(subject).to be_installing + end + end + + describe '#make_installed' do + subject { create(factory_name, :installing) } + + it 'is installed' do + subject.make_installed + + expect(subject).to be_installed + end + end + + describe '#make_errored' do + subject { create(factory_name, :installing) } + let(:reason) { 'some errors' } + + it 'is errored' do + subject.make_errored(reason) + + expect(subject).to be_errored + expect(subject.status_reason).to eq(reason) + end + end + + describe '#make_scheduled' do + subject { create(factory_name, :installable) } + + it 'is scheduled' do + subject.make_scheduled + + expect(subject).to be_scheduled + end + + describe 'when was errored' do + subject { create(factory_name, :errored) } + + it 'clears #status_reason' do + expect(subject.status_reason).not_to be_nil + + subject.make_scheduled! + + expect(subject.status_reason).to be_nil + end + end + end + end +end diff --git a/vendor/prometheus/values.yaml b/vendor/prometheus/values.yaml new file mode 100644 index 00000000000..dd9496deb4d --- /dev/null +++ b/vendor/prometheus/values.yaml @@ -0,0 +1,134 @@ +alertmanager: | + enabled: false + +kubeStateMetrics: | + enabled: 'false' + +nodeExporter: | + enabled: 'false' + +pushgateway: | + enabled: 'false' + +serverFiles: | + alerts: '' + rules: '' + + prometheus.yml: |- + rule_files: | + - /etc/config/rules + - /etc/config/alerts + scrape_configs: | + - job_name: prometheus + static_configs: | + - targets: + - localhost:9090 + + - job_name: 'kubernetes-apiservers' + kubernetes_sd_configs: | + - role: endpoints + scheme: https + + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + insecure_skip_verify: true + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + relabel_configs: + - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name] + action: keep + regex: default;kubernetes;https + - job_name: 'kubernetes-nodes' + scheme: https + tls_config: + ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + insecure_skip_verify: true + bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token + kubernetes_sd_configs: + - role: node + relabel_configs: + - action: labelmap + regex: __meta_kubernetes_node_label_(.+) + - target_label: __address__ + replacement: kubernetes.default.svc:443 + - source_labels: [__meta_kubernetes_node_name] + regex: (.+) + target_label: __metrics_path__ + replacement: /api/v1/nodes/${1}/proxy/metrics + + - job_name: 'kubernetes-service-endpoints' + kubernetes_sd_configs: + - role: endpoints + relabel_configs: | + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape] + action: keep + regex: 'true' + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme] + action: replace + target_label: __scheme__ + regex: (https?) + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port] + action: replace + target_label: __address__ + regex: (.+)(?::\d+);(\d+) + replacement: $1:$2 + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + action: replace + target_label: kubernetes_name + - job_name: 'prometheus-pushgateway' + honor_labels: true + kubernetes_sd_configs: | + - role: service + relabel_configs: | + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe] + action: keep + regex: pushgateway + - job_name: 'kubernetes-services' + metrics_path: /probe + params: | + module: [http_2xx] + kubernetes_sd_configs: | + - role: service + relabel_configs: | + - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe] + action: keep + regex: 'true' + - source_labels: [__address__] + target_label: __param_target + - target_label: __address__ + replacement: blackbox + - source_labels: [__param_target] + target_label: instance + - action: labelmap + regex: __meta_kubernetes_service_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_service_name] + target_label: kubernetes_name + - job_name: 'kubernetes-pods' + kubernetes_sd_configs: + - role: pod + relabel_configs: + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] + action: keep + regex: 'true' + - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] + action: replace + target_label: __metrics_path__ + regex: (.+) + - action: labelmap + regex: __meta_kubernetes_pod_label_(.+) + - source_labels: [__meta_kubernetes_namespace] + action: replace + target_label: kubernetes_namespace + - source_labels: [__meta_kubernetes_pod_name] + action: replace + target_label: kubernetes_pod_name -- cgit v1.2.1 From 86c0bb49b79217e318122e8921f92ef78ee7a1cf Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 22 Dec 2017 18:23:14 +0000 Subject: Uniform style between all upload forms --- app/views/groups/edit.html.haml | 4 ++-- app/views/profiles/show.html.haml | 13 +++++------ app/views/projects/edit.html.haml | 25 +++++++++++----------- .../shared/_choose_group_avatar_button.html.haml | 11 ++++------ 4 files changed, 23 insertions(+), 30 deletions(-) diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index 16038ef2f79..76a8099d7c0 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -13,13 +13,13 @@ = group_icon(@group, alt: '', class: 'avatar group-avatar s160') %p.light - if @group.avatar? - You can change your group avatar here + You can change the group avatar here - else You can upload a group avatar here = render 'shared/choose_group_avatar_button', f: f - if @group.avatar? %hr - = link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar" + = link_to _('Remove avatar'), group_avatar_path(@group.to_param), data: { confirm: _("Avatar will be removed. Are you sure?")}, method: :delete, class: "btn btn-danger btn-inverted" = render 'shared/visibility_level', f: f, visibility_level: @group.visibility_level, can_change_visibility_level: can_change_group_visibility_level?(@group), form_model: @group diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index f9dae310e01..0f773933ac2 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -22,18 +22,15 @@ .clearfix.avatar-image.append-bottom-default = link_to avatar_icon(@user, 400), target: '_blank', rel: 'noopener noreferrer' do = image_tag avatar_icon(@user, 160), alt: '', class: 'avatar s160' - %h5.prepend-top-0 - Upload new avatar + %h5.prepend-top-0= _("Upload new avatar") .prepend-top-5.append-bottom-10 - %a.btn.js-choose-user-avatar-button - Choose file... - %span.avatar-file-name.prepend-left-default.js-avatar-filename No file chosen + %button.btn.js-choose-user-avatar-button{ type: 'button' }= _("Choose file...") + %span.avatar-file-name.prepend-left-default.js-avatar-filename= _("No file chosen") = f.file_field_without_bootstrap :avatar, class: 'js-user-avatar-input hidden', accept: 'image/*' - .help-block - The maximum file size allowed is 200KB. + .help-block= _("The maximum file size allowed is 200KB.") - if @user.avatar? %hr - = link_to 'Remove avatar', profile_avatar_path, data: { confirm: 'Avatar will be removed. Are you sure?' }, method: :delete, class: 'btn btn-gray' + = link_to _('Remove avatar'), profile_avatar_path, data: { confirm: _('Avatar will be removed. Are you sure?') }, method: :delete, class: 'btn btn-danger btn-inverted' %hr .row .col-lg-4.profile-settings-sidebar diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index 9d0d525a292..e16d132f869 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -42,24 +42,23 @@ = f.text_field :tag_list, value: @project.tag_list.sort.join(', '), maxlength: 2000, class: "form-control" %p.help-block Separate tags with commas. %fieldset.features - %h5.prepend-top-0 - Project avatar + %h5.prepend-top-0= _("Project avatar") .form-group - if @project.avatar? - .avatar-container.s160 + .avatar-container.s160.append-bottom-15 = project_icon(@project.full_path, alt: '', class: 'avatar project-avatar s160') - %p.light - - if @project.avatar_in_git - Project avatar in repository: #{ @project.avatar_in_git } - %a.choose-btn.btn.js-choose-project-avatar-button - Choose file... - %span.file_name.prepend-left-default.js-avatar-filename No file chosen - = f.file_field :avatar, class: "js-project-avatar-input hidden" - .help-block The maximum file size allowed is 200KB. + - if @project.avatar_in_git + %p.light + = _("Project avatar in repository: %{link}").html_safe % { link: @project.avatar_in_git } + .prepend-top-5.append-bottom-10 + %button.btn.js-choose-project-avatar-button{ type: 'button' }= _("Choose file...") + %span.file_name.prepend-left-default.js-avatar-filename= _("No file chosen") + = f.file_field :avatar, class: "js-project-avatar-input hidden" + .help-block= _("The maximum file size allowed is 200KB.") - if @project.avatar? %hr - = link_to 'Remove avatar', project_avatar_path(@project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar" - = f.submit 'Save changes', class: "btn btn-save" + = link_to _('Remove avatar'), project_avatar_path(@project), data: { confirm: _("Avatar will be removed. Are you sure?") }, method: :delete, class: "btn btn-danger btn-inverted" + = f.submit 'Save changes', class: "btn btn-success" %section.settings.sharing-permissions.no-animate{ class: ('expanded' if expanded) } .settings-header diff --git a/app/views/shared/_choose_group_avatar_button.html.haml b/app/views/shared/_choose_group_avatar_button.html.haml index 94295970acf..75c65520350 100644 --- a/app/views/shared/_choose_group_avatar_button.html.haml +++ b/app/views/shared/_choose_group_avatar_button.html.haml @@ -1,7 +1,4 @@ -%button.choose-btn.btn.btn-sm.js-choose-group-avatar-button{ type: 'button' } - %i.fa.fa-paperclip - %span Choose File ... -  -%span.file_name.js-avatar-filename File name... -= f.file_field :avatar, class: 'js-group-avatar-input hidden' -.light The maximum file size allowed is 200KB. +%button.btn.js-choose-group-avatar-button{ type: 'button' }= _("Choose File ...") +%span.file_name.js-avatar-filename= _("No file chosen") += f.file_field :avatar, class: "js-group-avatar-input hidden" +.help-block= _("The maximum file size allowed is 200KB.") -- cgit v1.2.1 From 705022d11422e42f5ff2473bdc1c80ddd0be9529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 22 Dec 2017 20:07:49 +0100 Subject: Add cache_index migration --- .../20171222183504_add_cache_index_to_project.rb | 19 +++++++++++++++++++ db/schema.rb | 3 ++- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20171222183504_add_cache_index_to_project.rb diff --git a/db/migrate/20171222183504_add_cache_index_to_project.rb b/db/migrate/20171222183504_add_cache_index_to_project.rb new file mode 100644 index 00000000000..f43be14fb42 --- /dev/null +++ b/db/migrate/20171222183504_add_cache_index_to_project.rb @@ -0,0 +1,19 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddCacheIndexToProject < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_column_with_default(:projects, :cache_index, :integer, default: 0) + end + + def down + remove_column(:projects, :cache_index) + end +end diff --git a/db/schema.rb b/db/schema.rb index aa5db5da4f0..5ecfb0651c6 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: 20171220191323) do +ActiveRecord::Schema.define(version: 20171222183504) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -1447,6 +1447,7 @@ ActiveRecord::Schema.define(version: 20171220191323) do t.boolean "repository_read_only" t.boolean "merge_requests_ff_only_enabled", default: false t.boolean "merge_requests_rebase_enabled", default: false, null: false + t.integer "cache_index", default: 0, null: false end add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree -- cgit v1.2.1 From f58cc2ee6044ab3445ff9a4438faa29b30b303fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 22 Dec 2017 20:22:29 +0100 Subject: Remove default value from cache_index migration --- db/migrate/20171222183504_add_cache_index_to_project.rb | 10 ++-------- db/schema.rb | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/db/migrate/20171222183504_add_cache_index_to_project.rb b/db/migrate/20171222183504_add_cache_index_to_project.rb index f43be14fb42..e1d73db1ab0 100644 --- a/db/migrate/20171222183504_add_cache_index_to_project.rb +++ b/db/migrate/20171222183504_add_cache_index_to_project.rb @@ -7,13 +7,7 @@ class AddCacheIndexToProject < ActiveRecord::Migration # Set this constant to true if this migration requires downtime. DOWNTIME = false - disable_ddl_transaction! - - def up - add_column_with_default(:projects, :cache_index, :integer, default: 0) - end - - def down - remove_column(:projects, :cache_index) + def change + add_column :projects, :cache_index, :integer end end diff --git a/db/schema.rb b/db/schema.rb index 5ecfb0651c6..b7512f293a6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1447,7 +1447,7 @@ ActiveRecord::Schema.define(version: 20171222183504) do t.boolean "repository_read_only" t.boolean "merge_requests_ff_only_enabled", default: false t.boolean "merge_requests_rebase_enabled", default: false, null: false - t.integer "cache_index", default: 0, null: false + t.integer "cache_index" end add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree -- cgit v1.2.1 From 0a002e230badf96f5c89d55945ddd85113edd628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 22 Dec 2017 21:28:25 +0100 Subject: Implement ResetProjectCacheService --- app/services/reset_project_cache_service.rb | 1 + spec/services/reset_project_cache_service_spec.rb | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/app/services/reset_project_cache_service.rb b/app/services/reset_project_cache_service.rb index 85ba6d953a2..0886c6b8315 100644 --- a/app/services/reset_project_cache_service.rb +++ b/app/services/reset_project_cache_service.rb @@ -1,4 +1,5 @@ class ResetProjectCacheService < BaseService def execute + @project.increment!(:cache_index) end end diff --git a/spec/services/reset_project_cache_service_spec.rb b/spec/services/reset_project_cache_service_spec.rb index 9623035a5a4..df969d08f39 100644 --- a/spec/services/reset_project_cache_service_spec.rb +++ b/spec/services/reset_project_cache_service_spec.rb @@ -6,7 +6,23 @@ describe ResetProjectCacheService do subject { described_class.new(project, user).execute } - it "resets project cache" do - fail + context 'when project cache_index is nil' do + before do + project.cache_index = nil + end + + it 'sets project cache_index to one' do + expect { subject }.to change { project.reload.cache_index }.from(nil).to(1) + end + end + + context 'when project cache_index is a numeric value' do + before do + project.update_attributes(cache_index: 1) + end + + it 'increments project cache index' do + expect { subject }.to change { project.reload.cache_index }.by(1) + end end end -- cgit v1.2.1 From 771b97394a16ae8dcd9acc84ab6a076f68726fd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 22 Dec 2017 23:06:15 +0100 Subject: Use Project.cache_index in Build#cache --- app/models/ci/build.rb | 6 +++++- spec/models/ci/build_spec.rb | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 83fe23606d1..e4ca74f87f2 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -461,7 +461,11 @@ module Ci end def cache - [options[:cache]] + if options[:cache] && project.cache_index + options[:cache].merge(key: "#{options[:cache][:key]}:#{project.cache_index}") + else + [options[:cache]] + end end def credentials diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 871e8b47650..96513281994 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -255,6 +255,42 @@ describe Ci::Build do end end + describe '#cache' do + let(:options) { { cache: { key: "key", paths: ["public"], policy: "pull-push" } } } + + subject { build.cache } + + context 'when build has cache' do + before do + allow(build).to receive(:options).and_return(options) + end + + context 'when project has cache_index' do + before do + allow_any_instance_of(Project).to receive(:cache_index).and_return(1) + end + + it { is_expected.to include(key: "key:1") } + end + + context 'when project does not have cache_index' do + before do + allow_any_instance_of(Project).to receive(:cache_index).and_return(nil) + end + + it { is_expected.to eq([options[:cache]]) } + end + end + + context 'when build does not have cache' do + before do + allow(build).to receive(:options).and_return({}) + end + + it { is_expected.to eq([nil]) } + end + end + describe '#depends_on_builds' do let!(:build) { create(:ci_build, pipeline: pipeline, name: 'build', stage_idx: 0, stage: 'build') } let!(:rspec_test) { create(:ci_build, pipeline: pipeline, name: 'rspec', stage_idx: 1, stage: 'test') } -- cgit v1.2.1 From 7354c9f75dfbf4c495d2869b5dd4f0dd4f5c9612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Wed, 20 Dec 2017 16:54:09 -0300 Subject: Remove unused method `remote_exists?` --- app/models/repository.rb | 4 ---- lib/gitlab/git/repository.rb | 5 ----- spec/lib/gitlab/git/repository_spec.rb | 15 --------------- 3 files changed, 24 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index a34f5e5439b..b1fd981965c 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1010,10 +1010,6 @@ class Repository raw_repository.fetch_source_branch!(source_repository.raw_repository, source_branch, local_ref) end - def remote_exists?(name) - raw_repository.remote_exists?(name) - end - def compare_source_branch(target_branch_name, source_repository, source_branch_name, straight:) raw_repository.compare_source_branch(target_branch_name, source_repository.raw_repository, source_branch_name, straight: straight) end diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 044c60caa05..4fc37b63085 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -940,11 +940,6 @@ module Gitlab false end - # Returns true if a remote exists. - def remote_exists?(name) - rugged.remotes[name].present? - end - # Update the specified remote using the values in the +options+ hash # # Example diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 03a9cc488ca..ad16f9af0f1 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -701,21 +701,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end end - describe '#remote_exists?' do - before(:all) do - @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') - @repo.add_remote("new_remote", SeedHelper::GITLAB_GIT_TEST_REPO_URL) - end - - it 'returns true for an existing remote' do - expect(@repo.remote_exists?('new_remote')).to eq(true) - end - - it 'returns false for a non-existing remote' do - expect(@repo.remote_exists?('foo')).to eq(false) - end - end - describe "#log" do let(:commit_with_old_name) do Gitlab::Git::Commit.decorate(repository, @commit_with_old_name_id) -- cgit v1.2.1 From 2694355bb6f6bf174b42127db35aa2c912501a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Wed, 20 Dec 2017 17:17:28 -0300 Subject: Incorporate Gitaly's RemoteService RPCs --- GITALY_SERVER_VERSION | 2 +- Gemfile | 2 +- Gemfile.lock | 4 +- lib/gitlab/git/repository.rb | 56 +++++++++++++++------- lib/gitlab/gitaly_client/remote_service.rb | 28 +++++++++++ spec/lib/gitlab/git/repository_spec.rb | 56 ++++++++++++++++++++++ .../gitlab/gitaly_client/remote_service_spec.rb | 34 +++++++++++++ 7 files changed, 162 insertions(+), 20 deletions(-) create mode 100644 lib/gitlab/gitaly_client/remote_service.rb create mode 100644 spec/lib/gitlab/gitaly_client/remote_service_spec.rb diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 7e750b4ebf3..d4f16f06004 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -0.60.0 +0.64.0 diff --git a/Gemfile b/Gemfile index b6ffaf80f24..a9a50ec084c 100644 --- a/Gemfile +++ b/Gemfile @@ -400,7 +400,7 @@ group :ed25519 do end # Gitaly GRPC client -gem 'gitaly-proto', '~> 0.61.0', require: 'gitaly' +gem 'gitaly-proto', '~> 0.62.0', require: 'gitaly' gem 'toml-rb', '~> 0.3.15', require: false diff --git a/Gemfile.lock b/Gemfile.lock index a6e3c9e27cc..64f8c955391 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -284,7 +284,7 @@ GEM po_to_json (>= 1.0.0) rails (>= 3.2.0) gherkin-ruby (0.3.2) - gitaly-proto (0.61.0) + gitaly-proto (0.62.0) google-protobuf (~> 3.1) grpc (~> 1.0) github-linguist (4.7.6) @@ -1042,7 +1042,7 @@ DEPENDENCIES gettext (~> 3.2.2) gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails_js (~> 1.2.0) - gitaly-proto (~> 0.61.0) + gitaly-proto (~> 0.62.0) github-linguist (~> 4.7.0) gitlab-flowdock-git-hook (~> 1.0.1) gitlab-markup (~> 1.6.2) diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 4fc37b63085..3ddd8fbe873 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -918,26 +918,23 @@ module Gitlab # If `mirror_refmap` is present the remote is set as mirror with that mapping def add_remote(remote_name, url, mirror_refmap: nil) - rugged.remotes.create(remote_name, url) - - set_remote_as_mirror(remote_name, refmap: mirror_refmap) if mirror_refmap - rescue Rugged::ConfigError - remote_update(remote_name, url: url) + gitaly_migrate(:operation_user_add_tag) do |is_enabled| + if is_enabled + gitaly_remote_client.add_remote(remote_name, url, mirror_refmap) + else + rugged_add_remote(remote_name, url, mirror_refmap) + end + end end def remove_remote(remote_name) - # When a remote is deleted all its remote refs are deleted too, but in - # the case of mirrors we map its refs (that would usualy go under - # [remote_name]/) to the top level namespace. We clean the mapping so - # those don't get deleted. - if rugged.config["remote.#{remote_name}.mirror"] - rugged.config.delete("remote.#{remote_name}.fetch") + gitaly_migrate(:operation_user_add_tag) do |is_enabled| + if is_enabled + gitaly_remote_client.remove_remote(remote_name) + else + rugged_remove_remote(remote_name) + end end - - rugged.remotes.delete(remote_name) - true - rescue Rugged::ConfigError - false end # Update the specified remote using the values in the +options+ hash @@ -1292,6 +1289,10 @@ module Gitlab @gitaly_operation_client ||= Gitlab::GitalyClient::OperationService.new(self) end + def gitaly_remote_client + @gitaly_remote_client ||= Gitlab::GitalyClient::RemoteService.new(self) + end + def gitaly_migrate(method, status: Gitlab::GitalyClient::MigrationStatus::OPT_IN, &block) Gitlab::GitalyClient.migrate(method, status: status, &block) rescue GRPC::NotFound => e @@ -1911,6 +1912,29 @@ module Gitlab raise ArgumentError, 'Invalid merge source' end + def rugged_add_remote(remote_name, url, mirror_refmap) + rugged.remotes.create(remote_name, url) + + set_remote_as_mirror(remote_name, refmap: mirror_refmap) if mirror_refmap + rescue Rugged::ConfigError + remote_update(remote_name, url: url) + end + + def rugged_remove_remote(remote_name) + # When a remote is deleted all its remote refs are deleted too, but in + # the case of mirrors we map its refs (that would usualy go under + # [remote_name]/) to the top level namespace. We clean the mapping so + # those don't get deleted. + if rugged.config["remote.#{remote_name}.mirror"] + rugged.config.delete("remote.#{remote_name}.fetch") + end + + rugged.remotes.delete(remote_name) + true + rescue Rugged::ConfigError + false + end + def fetch_remote(remote_name = 'origin', env: nil) run_git(['fetch', remote_name], env: env).last.zero? end diff --git a/lib/gitlab/gitaly_client/remote_service.rb b/lib/gitlab/gitaly_client/remote_service.rb new file mode 100644 index 00000000000..9218f6cfd68 --- /dev/null +++ b/lib/gitlab/gitaly_client/remote_service.rb @@ -0,0 +1,28 @@ +module Gitlab + module GitalyClient + class RemoteService + def initialize(repository) + @repository = repository + @gitaly_repo = repository.gitaly_repository + @storage = repository.storage + end + + def add_remote(name, url, mirror_refmap) + request = Gitaly::AddRemoteRequest.new( + repository: @gitaly_repo, name: name, url: url, + mirror_refmap: mirror_refmap.to_s + ) + + GitalyClient.call(@storage, :remote_service, :add_remote, request) + end + + def remove_remote(name) + request = Gitaly::RemoveRemoteRequest.new(repository: @gitaly_repo, name: name) + + response = GitalyClient.call(@storage, :remote_service, :remove_remote, request) + + response.result + end + end + end +end diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index ad16f9af0f1..cf14f7d2207 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -1828,6 +1828,62 @@ describe Gitlab::Git::Repository, seed_helper: true do end end + describe 'remotes' do + let(:repository) do + Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') + end + let(:remote_name) { 'my-remote' } + + after do + ensure_seeds + end + + describe '#add_remote' do + let(:url) { 'http://my-repo.git' } + let(:mirror_refmap) { '+refs/*:refs/*' } + + it 'creates a new remote via Gitaly' do + expect_any_instance_of(Gitlab::GitalyClient::RemoteService) + .to receive(:add_remote).with(remote_name, url, mirror_refmap) + + repository.add_remote(remote_name, url, mirror_refmap: mirror_refmap) + end + + context 'with Gitaly disabled', :skip_gitaly_mock do + it 'creates a new remote via Rugged' do + expect_any_instance_of(Rugged::RemoteCollection).to receive(:create) + .with(remote_name, url) + expect_any_instance_of(Rugged::Config).to receive(:[]=) + .with("remote.#{remote_name}.mirror", true) + expect_any_instance_of(Rugged::Config).to receive(:[]=) + .with("remote.#{remote_name}.prune", true) + expect_any_instance_of(Rugged::Config).to receive(:[]=) + .with("remote.#{remote_name}.fetch", mirror_refmap) + + repository.add_remote(remote_name, url, mirror_refmap: mirror_refmap) + end + end + end + + describe '#remove_remote' do + it 'removes the remote via Gitaly' do + expect_any_instance_of(Gitlab::GitalyClient::RemoteService) + .to receive(:remove_remote).with(remote_name) + + repository.remove_remote(remote_name) + end + + context 'with Gitaly disabled', :skip_gitaly_mock do + it 'removes the remote via Rugged' do + expect_any_instance_of(Rugged::RemoteCollection).to receive(:delete) + .with(remote_name) + + repository.remove_remote(remote_name) + end + end + 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 diff --git a/spec/lib/gitlab/gitaly_client/remote_service_spec.rb b/spec/lib/gitlab/gitaly_client/remote_service_spec.rb new file mode 100644 index 00000000000..69c6f054016 --- /dev/null +++ b/spec/lib/gitlab/gitaly_client/remote_service_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe Gitlab::GitalyClient::RemoteService do + let(:project) { create(:project) } + let(:storage_name) { project.repository_storage } + let(:relative_path) { project.disk_path + '.git' } + let(:remote_name) { 'my-remote' } + let(:client) { described_class.new(project.repository) } + + describe '#add_remote' do + let(:url) { 'http://my-repo.git' } + let(:mirror_refmap) { :all_refs } + + it 'sends an add_remote message' do + expect_any_instance_of(Gitaly::RemoteService::Stub) + .to receive(:add_remote) + .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash)) + .and_return(double(:add_remote_response)) + + client.add_remote(remote_name, url, mirror_refmap) + end + end + + describe '#remove_remote' do + it 'sends an remove_remote message and returns the result value' do + expect_any_instance_of(Gitaly::RemoteService::Stub) + .to receive(:remove_remote) + .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash)) + .and_return(double(result: true)) + + expect(client.remove_remote(remote_name)).to be(true) + end + end +end -- cgit v1.2.1 From f20581773a12b5653ad43d9e908d756935dcf62c Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Sat, 23 Dec 2017 12:53:13 +1100 Subject: Return exception messages in scripts/lint-changelog-yaml --- scripts/lint-changelog-yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/lint-changelog-yaml b/scripts/lint-changelog-yaml index cce5f1c7667..6553e02ffca 100755 --- a/scripts/lint-changelog-yaml +++ b/scripts/lint-changelog-yaml @@ -8,11 +8,13 @@ invalid_changelogs = Dir['changelogs/**/*'].reject do |changelog| begin YAML.load_file(changelog) - rescue + rescue => exception + puts exception end end if invalid_changelogs.any? + puts puts "Invalid changelogs found!\n" puts invalid_changelogs.sort exit 1 -- cgit v1.2.1 From 0faf772b6cfd691e16d529051a8901627a660a7a Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Fri, 22 Dec 2017 23:19:57 -0800 Subject: Gracefully handle garbled URIs in Markdown There are certain inputs that look like valid URIs that are accepted by URI but not Addressable::URI. Handle the case where the latter fails. Closes #41442 --- changelogs/unreleased/sh-catch-invalid-uri-markdown.yml | 5 +++++ lib/banzai/filter/relative_link_filter.rb | 2 +- spec/lib/banzai/filter/relative_link_filter_spec.rb | 5 +++++ 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/sh-catch-invalid-uri-markdown.yml diff --git a/changelogs/unreleased/sh-catch-invalid-uri-markdown.yml b/changelogs/unreleased/sh-catch-invalid-uri-markdown.yml new file mode 100644 index 00000000000..9b0233fe988 --- /dev/null +++ b/changelogs/unreleased/sh-catch-invalid-uri-markdown.yml @@ -0,0 +1,5 @@ +--- +title: Gracefully handle garbled URIs in Markdown +merge_request: +author: +type: fixed diff --git a/lib/banzai/filter/relative_link_filter.rb b/lib/banzai/filter/relative_link_filter.rb index c1f933ec54b..5c197afd782 100644 --- a/lib/banzai/filter/relative_link_filter.rb +++ b/lib/banzai/filter/relative_link_filter.rb @@ -66,7 +66,7 @@ module Banzai if uri.relative? && uri.path.present? html_attr.value = rebuild_relative_uri(uri).to_s end - rescue URI::Error + rescue URI::Error, Addressable::URI::InvalidURIError # noop end diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb index ef306f1cd4a..f38f0776303 100644 --- a/spec/lib/banzai/filter/relative_link_filter_spec.rb +++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb @@ -76,6 +76,11 @@ describe Banzai::Filter::RelativeLinkFilter do expect { filter(act) }.not_to raise_error end + it 'does not raise an exception with a garbled path' do + act = link("open(/var/tmp/):%20/location%0Afrom:%20/test") + expect { filter(act) }.not_to raise_error + end + it 'ignores ref if commit is passed' do doc = filter(link('non/existent.file'), commit: project.commit('empty-branch') ) expect(doc.at_css('a')['href']) -- cgit v1.2.1 From ef82cbef90c59a8d1d59f05d4acf75a2ecbb42c9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 23 Dec 2017 14:18:39 +0000 Subject: Remove security checks from static analysis and add sast job --- .gitlab-ci.yml | 8 ++++++++ scripts/static-analysis | 2 -- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4b149b13178..6ca2fb471aa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -600,6 +600,14 @@ codequality: artifacts: paths: [codeclimate.json] +sast: + image: registry.gitlab.com/gitlab-org/gl-sast:latest + before_script: [] + script: + - /app/bin/run . + artifacts: + paths: [gl-sast-report.json] + qa:internal: <<: *dedicated-runner <<: *except-docs diff --git a/scripts/static-analysis b/scripts/static-analysis index 51a2fd81a79..2a2bc67800d 100755 --- a/scripts/static-analysis +++ b/scripts/static-analysis @@ -3,12 +3,10 @@ require ::File.expand_path('../lib/gitlab/popen', __dir__) tasks = [ - %w[bundle exec bundle-audit check --update], %w[bundle exec rake config_lint], %w[bundle exec rake flay], %w[bundle exec rake haml_lint], %w[bundle exec rake scss_lint], - %w[bundle exec rake brakeman], %w[bundle exec license_finder], %w[yarn run eslint], %w[bundle exec rubocop --parallel], -- cgit v1.2.1 From 6185ce0c84b5674abf4f54576fec44fece571565 Mon Sep 17 00:00:00 2001 From: Jacopo Date: Thu, 21 Dec 2017 22:15:50 +0100 Subject: Rendering of emoji's in Group-Overview Allows rendering of emoji's in the Group Overview. --- app/assets/javascripts/groups/components/group_item.vue | 3 ++- app/assets/javascripts/groups/store/groups_store.js | 2 +- app/serializers/group_child_entity.rb | 9 +++++++++ .../unreleased/40549-render-emoj-in-groups-overview.yml | 5 +++++ spec/features/groups/show_spec.rb | 16 ++++++++++++++++ spec/serializers/group_child_entity_spec.rb | 12 +++++++++++- 6 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/40549-render-emoj-in-groups-overview.yml diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue index 6421547bbde..ad01c261b7f 100644 --- a/app/assets/javascripts/groups/components/group_item.vue +++ b/app/assets/javascripts/groups/components/group_item.vue @@ -139,7 +139,8 @@ export default {
- {{group.description}} + +
😄

') + end + end + it_behaves_like 'group child json' end end -- cgit v1.2.1 From 36bdf3dc9ac290058b73ab54abeb9ba84b211b29 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 24 Dec 2017 09:03:58 -0800 Subject: Gracefully handle orphaned write deploy keys in /internal/post_receive On GitLab.com, there are write deploy keys with no associated users. Pushes with these deploy keys end with an Error 500 since we attempt to look up redirect message. If there is no user, don't attempt to display a redirect message. Closes #41466 --- changelogs/unreleased/sh-handle-orphaned-deploy-keys.yml | 5 +++++ lib/api/internal.rb | 9 ++++++--- spec/requests/api/internal_spec.rb | 10 ++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/sh-handle-orphaned-deploy-keys.yml diff --git a/changelogs/unreleased/sh-handle-orphaned-deploy-keys.yml b/changelogs/unreleased/sh-handle-orphaned-deploy-keys.yml new file mode 100644 index 00000000000..7d3b622534e --- /dev/null +++ b/changelogs/unreleased/sh-handle-orphaned-deploy-keys.yml @@ -0,0 +1,5 @@ +--- +title: Gracefully handle orphaned write deploy keys in /internal/post_receive +merge_request: +author: +type: fixed diff --git a/lib/api/internal.rb b/lib/api/internal.rb index ccaaeca10d4..79b302aae70 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -190,9 +190,12 @@ module API project = Gitlab::GlRepository.parse(params[:gl_repository]).first user = identify(params[:identifier]) - redirect_message = Gitlab::Checks::ProjectMoved.fetch_redirect_message(user.id, project.id) - if redirect_message - output[:redirected_message] = redirect_message + + # A user is not guaranteed to be returned; an orphaned write deploy + # key could be used + if user + redirect_message = Gitlab::Checks::ProjectMoved.fetch_redirect_message(user.id, project.id) + output[:redirected_message] = redirect_message if redirect_message end output diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index bbcd1194ae5..7b25047ea8f 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -784,6 +784,16 @@ describe API::Internal do expect(json_response["redirected_message"]).to eq(project_moved.redirect_message) end end + + context 'with an orphaned write deploy key' do + it 'does not try to notify that project moved' do + allow_any_instance_of(Gitlab::Identifier).to receive(:identify).and_return(nil) + + post api("/internal/post_receive"), valid_params + + expect(response).to have_gitlab_http_status(200) + end + end end describe 'POST /internal/pre_receive' do -- cgit v1.2.1 From 7b52a3482ec696320e4a101a80537e4e61118b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sun, 24 Dec 2017 22:35:18 +0100 Subject: Add cache_index to list of safe Project attributes --- spec/lib/gitlab/import_export/safe_model_attributes.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index ec8fa99e0da..7e09f486854 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -459,6 +459,7 @@ Project: - delete_error - merge_requests_ff_only_enabled - merge_requests_rebase_enabled +- cache_index Author: - name ProjectFeature: -- cgit v1.2.1 From b762430795230aca5e949c24f7c06b172750ebb6 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 24 Dec 2017 09:35:30 -0800 Subject: Fix namespace ambiguity with Kubernetes Pod definitions This was causing a spec failure between Gitlab::Kubernetes::Helm::Pod and Gitlab::Kubernetes::Helm::Api::Pod if one spec loaded the former definition first. Closes #41458 --- lib/gitlab/kubernetes/helm/api.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gitlab/kubernetes/helm/api.rb b/lib/gitlab/kubernetes/helm/api.rb index ebd7dc1b100..737081ddc5b 100644 --- a/lib/gitlab/kubernetes/helm/api.rb +++ b/lib/gitlab/kubernetes/helm/api.rb @@ -34,7 +34,7 @@ module Gitlab private def pod_resource(command) - Pod.new(command, @namespace.name, @kubeclient).generate + Gitlab::Kubernetes::Helm::Pod.new(command, @namespace.name, @kubeclient).generate end end end -- cgit v1.2.1 From 40264b87af1c8a228a6b943367d6cd06d9f8d812 Mon Sep 17 00:00:00 2001 From: Semyon Pupkov Date: Sun, 24 Dec 2017 17:03:38 +0500 Subject: Move invites spinach test to Rspec https://gitlab.com/gitlab-org/gitlab-ce/issues/23036 --- features/invites.feature | 45 -------------------- features/steps/invites.rb | 80 ----------------------------------- spec/features/invites_spec.rb | 97 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 125 deletions(-) delete mode 100644 features/invites.feature delete mode 100644 features/steps/invites.rb create mode 100644 spec/features/invites_spec.rb diff --git a/features/invites.feature b/features/invites.feature deleted file mode 100644 index dc8eefaeaed..00000000000 --- a/features/invites.feature +++ /dev/null @@ -1,45 +0,0 @@ -Feature: Invites - Background: - Given "John Doe" is owner of group "Owned" - And "John Doe" has invited "user@example.com" to group "Owned" - - Scenario: Viewing invitation when signed out - When I visit the invitation page - Then I should be redirected to the sign in page - And I should see a notice telling me to sign in - - Scenario: Signing in to view invitation - When I visit the invitation page - And I sign in as "Mary Jane" - Then I should be redirected to the invitation page - - Scenario: Viewing invitation when signed in - Given I sign in as "Mary Jane" - And I visit the invitation page - Then I should see the invitation details - And I should see an "Accept invitation" button - And I should see a "Decline" button - - Scenario: Viewing invitation as an existing member - Given I sign in as "John Doe" - And I visit the invitation page - Then I should see a message telling me I'm already a member - - Scenario: Accepting the invitation - Given I sign in as "Mary Jane" - And I visit the invitation page - And I click the "Accept invitation" button - Then I should be redirected to the group page - And I should see a notice telling me I have access - - Scenario: Declining the application when signed in - Given I sign in as "Mary Jane" - And I visit the invitation page - And I click the "Decline" button - Then I should be redirected to the dashboard - And I should see a notice telling me I have declined - - Scenario: Declining the application when signed out - When I visit the invitation's decline page - Then I should be redirected to the sign in page - And I should see a notice telling me I have declined diff --git a/features/steps/invites.rb b/features/steps/invites.rb deleted file mode 100644 index dac972172aa..00000000000 --- a/features/steps/invites.rb +++ /dev/null @@ -1,80 +0,0 @@ -class Spinach::Features::Invites < Spinach::FeatureSteps - include SharedAuthentication - include SharedUser - include SharedGroup - - step '"John Doe" has invited "user@example.com" to group "Owned"' do - user = User.find_by(name: "John Doe") - group = Group.find_by(name: "Owned") - group.add_developer("user@example.com", user) - end - - step 'I visit the invitation page' do - group = Group.find_by(name: "Owned") - invite = group.group_members.invite.last - invite.generate_invite_token! - @raw_invite_token = invite.raw_invite_token - visit invite_path(@raw_invite_token) - end - - step 'I should be redirected to the sign in page' do - expect(current_path).to eq(new_user_session_path) - end - - step 'I should see a notice telling me to sign in' do - expect(page).to have_content "To accept this invitation, sign in" - end - - step 'I should be redirected to the invitation page' do - expect(current_path).to eq(invite_path(@raw_invite_token)) - end - - step 'I should see the invitation details' do - expect(page).to have_content("You have been invited by John Doe to join group Owned as Developer.") - end - - step "I should see a message telling me I'm already a member" do - expect(page).to have_content("However, you are already a member of this group.") - end - - step 'I should see an "Accept invitation" button' do - expect(page).to have_link("Accept invitation") - end - - step 'I should see a "Decline" button' do - expect(page).to have_link("Decline") - end - - step 'I click the "Accept invitation" button' do - page.click_link "Accept invitation" - end - - step 'I should be redirected to the group page' do - group = Group.find_by(name: "Owned") - expect(current_path).to eq(group_path(group)) - end - - step 'I should see a notice telling me I have access' do - expect(page).to have_content("You have been granted Developer access to group Owned.") - end - - step 'I click the "Decline" button' do - page.click_link "Decline" - end - - step 'I should be redirected to the dashboard' do - expect(current_path).to eq(dashboard_projects_path) - end - - step 'I should see a notice telling me I have declined' do - expect(page).to have_content("You have declined the invitation to join group Owned.") - end - - step "I visit the invitation's decline page" do - group = Group.find_by(name: "Owned") - invite = group.group_members.invite.last - invite.generate_invite_token! - @raw_invite_token = invite.raw_invite_token - visit decline_invite_path(@raw_invite_token) - end -end diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb new file mode 100644 index 00000000000..e4be6193b8b --- /dev/null +++ b/spec/features/invites_spec.rb @@ -0,0 +1,97 @@ +require 'spec_helper' + +describe 'Invites' do + let(:user) { create(:user) } + let(:owner) { create(:user, name: 'John Doe') } + let(:group) { create(:group, name: 'Owned') } + let(:project) { create(:project, :repository, namespace: group) } + let(:invite) { group.group_members.invite.last } + + before do + project.add_master(owner) + group.add_user(owner, Gitlab::Access::OWNER) + group.add_developer('user@example.com', owner) + invite.generate_invite_token! + end + + context 'when signed out' do + before do + visit invite_path(invite.raw_invite_token) + end + + it 'renders sign in page with sign in notice' do + expect(current_path).to eq(new_user_session_path) + expect(page).to have_content('To accept this invitation, sign in') + end + + it 'sign in and redirects to invitation page' do + fill_in 'user_login', with: user.email + fill_in 'user_password', with: user.password + check 'user_remember_me' + click_button 'Sign in' + + expect(current_path).to eq(invite_path(invite.raw_invite_token)) + expect(page).to have_content( + 'You have been invited by John Doe to join group Owned as Developer.' + ) + expect(page).to have_link('Accept invitation') + expect(page).to have_link('Decline') + end + end + + context 'when signed in as an exists member' do + before do + sign_in(owner) + end + + it 'shows message user already a member' do + visit invite_path(invite.raw_invite_token) + expect(page).to have_content('However, you are already a member of this group.') + end + end + + describe 'accepting the invitation' do + before do + sign_in(user) + visit invite_path(invite.raw_invite_token) + end + + it 'grants access and redirects to group page' do + page.click_link 'Accept invitation' + expect(current_path).to eq(group_path(group)) + expect(page).to have_content( + 'You have been granted Developer access to group Owned.' + ) + end + end + + describe 'declining the application' do + context 'when signed in' do + before do + sign_in(user) + visit invite_path(invite.raw_invite_token) + end + + it 'declines application and redirects to dashboard' do + page.click_link 'Decline' + expect(current_path).to eq(dashboard_projects_path) + expect(page).to have_content( + 'You have declined the invitation to join group Owned.' + ) + end + end + + context 'when signed out' do + before do + visit decline_invite_path(invite.raw_invite_token) + end + + it 'declines application and redirects to sign in page' do + expect(current_path).to eq(new_user_session_path) + expect(page).to have_content( + 'You have declined the invitation to join group Owned.' + ) + end + end + end +end -- cgit v1.2.1 From 7a815d7585a8a433359297f37b349604bfbcf2c8 Mon Sep 17 00:00:00 2001 From: Semyon Pupkov Date: Sun, 24 Dec 2017 22:46:30 +0500 Subject: Move explore groups spinach test to RSpec https://gitlab.com/gitlab-org/gitlab-ce/issues/23036 --- features/explore/groups.feature | 105 ----------------------------------- features/steps/explore/groups.rb | 88 ----------------------------- spec/features/explore/groups_spec.rb | 87 +++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 193 deletions(-) delete mode 100644 features/explore/groups.feature delete mode 100644 features/steps/explore/groups.rb create mode 100644 spec/features/explore/groups_spec.rb diff --git a/features/explore/groups.feature b/features/explore/groups.feature deleted file mode 100644 index 830810615e0..00000000000 --- a/features/explore/groups.feature +++ /dev/null @@ -1,105 +0,0 @@ -@public -Feature: Explore Groups - Background: - Given group "TestGroup" has private project "Enterprise" - - @javascript - Scenario: I should see group with private and internal projects as user - Given group "TestGroup" has internal project "Internal" - When I sign in as a user - And I visit group "TestGroup" page - Then I should see project "Internal" items - And I should not see project "Enterprise" items - - @javascript - Scenario: I should see group issues for internal project as user - Given group "TestGroup" has internal project "Internal" - When I sign in as a user - And I visit group "TestGroup" issues page - Then I should see project "Internal" items - And I should not see project "Enterprise" items - - @javascript - Scenario: I should see group merge requests for internal project as user - Given group "TestGroup" has internal project "Internal" - When I sign in as a user - And I visit group "TestGroup" merge requests page - Then I should see project "Internal" items - And I should not see project "Enterprise" items - - @javascript - Scenario: I should see group with private, internal and public projects as visitor - Given group "TestGroup" has internal project "Internal" - Given group "TestGroup" has public project "Community" - When I visit group "TestGroup" page - Then I should see project "Community" items - And I should not see project "Internal" items - And I should not see project "Enterprise" items - - @javascript - Scenario: I should see group issues for public project as visitor - Given group "TestGroup" has internal project "Internal" - Given group "TestGroup" has public project "Community" - When I visit group "TestGroup" issues page - Then I should see project "Community" items - And I should not see project "Internal" items - And I should not see project "Enterprise" items - - @javascript - Scenario: I should see group merge requests for public project as visitor - Given group "TestGroup" has internal project "Internal" - Given group "TestGroup" has public project "Community" - When I visit group "TestGroup" merge requests page - Then I should see project "Community" items - And I should not see project "Internal" items - And I should not see project "Enterprise" items - - @javascript - Scenario: I should see group with private, internal and public projects as user - Given group "TestGroup" has internal project "Internal" - Given group "TestGroup" has public project "Community" - When I sign in as a user - And I visit group "TestGroup" page - Then I should see project "Community" items - And I should see project "Internal" items - And I should not see project "Enterprise" items - - @javascript - Scenario: I should see group issues for internal and public projects as user - Given group "TestGroup" has internal project "Internal" - Given group "TestGroup" has public project "Community" - When I sign in as a user - And I visit group "TestGroup" issues page - Then I should see project "Community" items - And I should see project "Internal" items - And I should not see project "Enterprise" items - - @javascript - Scenario: I should see group merge requests for internal and public projects as user - Given group "TestGroup" has internal project "Internal" - Given group "TestGroup" has public project "Community" - When I sign in as a user - And I visit group "TestGroup" merge requests page - Then I should see project "Community" items - And I should see project "Internal" items - And I should not see project "Enterprise" items - - @javascript - Scenario: I should see group with public project in public groups area - Given group "TestGroup" has public project "Community" - When I visit the public groups area - Then I should see group "TestGroup" - - @javascript - Scenario: I should see group with public project in public groups area as user - Given group "TestGroup" has public project "Community" - When I sign in as a user - And I visit the public groups area - Then I should see group "TestGroup" - - @javascript - Scenario: I should see group with internal project in public groups area as user - Given group "TestGroup" has internal project "Internal" - When I sign in as a user - And I visit the public groups area - Then I should see group "TestGroup" diff --git a/features/steps/explore/groups.rb b/features/steps/explore/groups.rb deleted file mode 100644 index 409bf0cb416..00000000000 --- a/features/steps/explore/groups.rb +++ /dev/null @@ -1,88 +0,0 @@ -class Spinach::Features::ExploreGroups < Spinach::FeatureSteps - include SharedAuthentication - include SharedPaths - include SharedGroup - include SharedProject - - step 'group "TestGroup" has private project "Enterprise"' do - group_has_project("TestGroup", "Enterprise", Gitlab::VisibilityLevel::PRIVATE) - end - - step 'group "TestGroup" has internal project "Internal"' do - group_has_project("TestGroup", "Internal", Gitlab::VisibilityLevel::INTERNAL) - end - - step 'group "TestGroup" has public project "Community"' do - group_has_project("TestGroup", "Community", Gitlab::VisibilityLevel::PUBLIC) - end - - step '"John Doe" is owner of group "TestGroup"' do - group = Group.find_by(name: "TestGroup") || create(:group, name: "TestGroup") - user = create(:user, name: "John Doe") - group.add_owner(user) - end - - step 'I visit group "TestGroup" page' do - visit group_path(Group.find_by(name: "TestGroup")) - end - - step 'I visit group "TestGroup" issues page' do - visit issues_group_path(Group.find_by(name: "TestGroup")) - end - - step 'I visit group "TestGroup" merge requests page' do - visit merge_requests_group_path(Group.find_by(name: "TestGroup")) - end - - step 'I visit group "TestGroup" members page' do - visit group_group_members_path(Group.find_by(name: "TestGroup")) - end - - step 'I should not see project "Enterprise" items' do - expect(page).not_to have_content "Enterprise" - end - - step 'I should see project "Internal" items' do - expect(page).to have_content "Internal" - end - - step 'I should not see project "Internal" items' do - expect(page).not_to have_content "Internal" - end - - step 'I should see project "Community" items' do - expect(page).to have_content "Community" - end - - step 'I change filter to Everyone\'s' do - click_link "Everyone's" - end - - step 'I should see group member "John Doe"' do - expect(page).to have_content "John Doe" - end - - protected - - def group_has_project(groupname, projectname, visibility_level) - group = Group.find_by(name: groupname) || create(:group, name: groupname) - project = create(:project, - namespace: group, - name: projectname, - path: "#{groupname}-#{projectname}", - visibility_level: visibility_level - ) - create(:issue, - title: "#{projectname} feature", - project: project - ) - create(:merge_request, - title: "#{projectname} feature implemented", - source_project: project, - target_project: project - ) - create(:closed_issue_event, - project: project - ) - end -end diff --git a/spec/features/explore/groups_spec.rb b/spec/features/explore/groups_spec.rb new file mode 100644 index 00000000000..e4ef47d88dd --- /dev/null +++ b/spec/features/explore/groups_spec.rb @@ -0,0 +1,87 @@ +require 'spec_helper' + +describe 'Explore Groups', :js do + let(:user) { create :user } + let(:group) { create :group } + let!(:private_project) do + create :project, :private, namespace: group do |project| + create(:issue, project: internal_project) + create(:merge_request, source_project: project, target_project: project) + end + end + + let!(:internal_project) do + create :project, :internal, namespace: group do |project| + create(:issue, project: project) + create(:merge_request, source_project: project, target_project: project) + end + end + + let!(:public_project) do + create(:project, :public, namespace: group) do |project| + create(:issue, project: project) + create(:merge_request, source_project: project, target_project: project) + end + end + + shared_examples 'renders public and internal projects' do + it do + visit_page + expect(page).to have_content(public_project.name) + expect(page).to have_content(internal_project.name) + expect(page).not_to have_content(private_project.name) + end + end + + shared_examples 'renders only public project' do + it do + visit_page + expect(page).to have_content(public_project.name) + expect(page).not_to have_content(internal_project.name) + expect(page).not_to have_content(private_project.name) + end + end + + shared_examples 'renders group in public groups area' do + it do + visit explore_groups_path + expect(page).to have_content(group.name) + end + end + + context 'when signed in' do + before do + sign_in(user) + end + + it_behaves_like 'renders public and internal projects' do + subject(:visit_page) { visit group_path(group) } + end + + it_behaves_like 'renders public and internal projects' do + subject(:visit_page) { visit issues_group_path(group) } + end + + it_behaves_like 'renders public and internal projects' do + subject(:visit_page) { visit merge_requests_group_path(group) } + end + + it_behaves_like 'renders group in public groups area' + end + + context 'when signed out' do + it_behaves_like 'renders only public project' do + subject(:visit_page) { visit group_path(group) } + end + + it_behaves_like 'renders only public project' do + subject(:visit_page) { visit issues_group_path(group) } + end + + it_behaves_like 'renders only public project' do + subject(:visit_page) { visit merge_requests_group_path(group) } + end + + it_behaves_like 'renders group in public groups area' + end +end -- cgit v1.2.1 From 0960c703c0a7e37c2177aaf32b64c316f531fe15 Mon Sep 17 00:00:00 2001 From: Jonathan Duck Date: Mon, 25 Dec 2017 12:48:48 +0000 Subject: Update code_climate recommended usage. --- doc/ci/examples/code_climate.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/ci/examples/code_climate.md b/doc/ci/examples/code_climate.md index 4d0ba8bfef3..6a5821762cc 100644 --- a/doc/ci/examples/code_climate.md +++ b/doc/ci/examples/code_climate.md @@ -16,8 +16,7 @@ codequality: - docker:dind script: - docker pull codeclimate/codeclimate - - docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate init - - docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate analyze -f json > codeclimate.json + - docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate analyze -f json > codeclimate.json || true artifacts: paths: [codeclimate.json] ``` -- cgit v1.2.1 From a83c41f6c6e0035c40916b3cbdda7fdd4f7e925f Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 24 Dec 2017 09:35:30 -0800 Subject: Fix Error 500s with anonymous clones for a project that has moved Closes #41457 --- .../unreleased/sh-handle-anonymous-clones-project-moved.yml | 5 +++++ lib/gitlab/checks/project_moved.rb | 13 ++++++++++--- spec/lib/gitlab/checks/project_moved_spec.rb | 7 +++++++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/sh-handle-anonymous-clones-project-moved.yml diff --git a/changelogs/unreleased/sh-handle-anonymous-clones-project-moved.yml b/changelogs/unreleased/sh-handle-anonymous-clones-project-moved.yml new file mode 100644 index 00000000000..a0860871152 --- /dev/null +++ b/changelogs/unreleased/sh-handle-anonymous-clones-project-moved.yml @@ -0,0 +1,5 @@ +--- +title: Fix Error 500s with anonymous clones for a project that has moved +merge_request: +author: +type: fixed diff --git a/lib/gitlab/checks/project_moved.rb b/lib/gitlab/checks/project_moved.rb index 3a1c0a3455e..c1da2471b54 100644 --- a/lib/gitlab/checks/project_moved.rb +++ b/lib/gitlab/checks/project_moved.rb @@ -2,6 +2,7 @@ module Gitlab module Checks class ProjectMoved REDIRECT_NAMESPACE = "redirect_namespace".freeze + ANONYMOUS_ID_KEY = 'anonymous'.freeze def initialize(project, user, redirected_path, protocol) @project = project @@ -22,7 +23,7 @@ module Gitlab def add_redirect_message Gitlab::Redis::SharedState.with do |redis| - key = self.class.redirect_message_key(user.id, project.id) + key = self.class.redirect_message_key(user_identifier, project.id) redis.setex(key, 5.minutes, redirect_message) end end @@ -45,8 +46,14 @@ module Gitlab attr_reader :project, :redirected_path, :protocol, :user - def self.redirect_message_key(user_id, project_id) - "#{REDIRECT_NAMESPACE}:#{user_id}:#{project_id}" + def self.redirect_message_key(user_identifier, project_id) + "#{REDIRECT_NAMESPACE}:#{user_identifier}:#{project_id}" + end + + def user_identifier + return ANONYMOUS_ID_KEY unless user.present? + + user.id end def remote_url_message(rejected) diff --git a/spec/lib/gitlab/checks/project_moved_spec.rb b/spec/lib/gitlab/checks/project_moved_spec.rb index fa1575e2177..3d72e78332d 100644 --- a/spec/lib/gitlab/checks/project_moved_spec.rb +++ b/spec/lib/gitlab/checks/project_moved_spec.rb @@ -35,6 +35,13 @@ describe Gitlab::Checks::ProjectMoved, :clean_gitlab_redis_shared_state do project_moved = described_class.new(project, user, 'foo/bar', 'http') expect(project_moved.add_redirect_message).to eq("OK") end + + it 'should handle anonymous clones' do + project_moved = described_class.new(project, nil, 'foo/bar', 'http') + + expect(project_moved.add_redirect_message).to eq("OK") + expect(Gitlab::Redis::SharedState.with { |redis| redis.get("redirect_namespace:anonymous:#{project.id}") }).not_to be_nil + end end describe '#redirect_message' do -- cgit v1.2.1 From b6c711fd38f65d78bbd02ad9ad05f22bcb5033c5 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 25 Dec 2017 05:33:32 -0800 Subject: Disable redirect messages for anonymous clones --- lib/gitlab/checks/project_moved.rb | 17 +++++++---------- spec/lib/gitlab/checks/project_moved_spec.rb | 3 +-- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/lib/gitlab/checks/project_moved.rb b/lib/gitlab/checks/project_moved.rb index c1da2471b54..dfb2f4d4054 100644 --- a/lib/gitlab/checks/project_moved.rb +++ b/lib/gitlab/checks/project_moved.rb @@ -2,7 +2,6 @@ module Gitlab module Checks class ProjectMoved REDIRECT_NAMESPACE = "redirect_namespace".freeze - ANONYMOUS_ID_KEY = 'anonymous'.freeze def initialize(project, user, redirected_path, protocol) @project = project @@ -22,8 +21,12 @@ module Gitlab end def add_redirect_message + # Don't bother with sending a redirect message for anonymous clones + # because they never see it via the `/internal/post_receive` endpoint + return unless user.present? && project.present? + Gitlab::Redis::SharedState.with do |redis| - key = self.class.redirect_message_key(user_identifier, project.id) + key = self.class.redirect_message_key(user.id, project.id) redis.setex(key, 5.minutes, redirect_message) end end @@ -46,14 +49,8 @@ module Gitlab attr_reader :project, :redirected_path, :protocol, :user - def self.redirect_message_key(user_identifier, project_id) - "#{REDIRECT_NAMESPACE}:#{user_identifier}:#{project_id}" - end - - def user_identifier - return ANONYMOUS_ID_KEY unless user.present? - - user.id + def self.redirect_message_key(user_id, project_id) + "#{REDIRECT_NAMESPACE}:#{user_id}:#{project_id}" end def remote_url_message(rejected) diff --git a/spec/lib/gitlab/checks/project_moved_spec.rb b/spec/lib/gitlab/checks/project_moved_spec.rb index 3d72e78332d..f90c2d6aded 100644 --- a/spec/lib/gitlab/checks/project_moved_spec.rb +++ b/spec/lib/gitlab/checks/project_moved_spec.rb @@ -39,8 +39,7 @@ describe Gitlab::Checks::ProjectMoved, :clean_gitlab_redis_shared_state do it 'should handle anonymous clones' do project_moved = described_class.new(project, nil, 'foo/bar', 'http') - expect(project_moved.add_redirect_message).to eq("OK") - expect(Gitlab::Redis::SharedState.with { |redis| redis.get("redirect_namespace:anonymous:#{project.id}") }).not_to be_nil + expect(project_moved.add_redirect_message).to eq(nil) end end -- cgit v1.2.1 From 8ae129954ffb5850d1804b5bd6a907696f6d77ee Mon Sep 17 00:00:00 2001 From: Kushal Pandya Date: Fri, 22 Dec 2017 12:28:44 +0530 Subject: Reduce font size for 24px identicon --- app/assets/stylesheets/framework/avatar.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss index 26db2386879..077d0424093 100644 --- a/app/assets/stylesheets/framework/avatar.scss +++ b/app/assets/stylesheets/framework/avatar.scss @@ -71,7 +71,7 @@ vertical-align: top; &.s16 { font-size: 12px; line-height: 1.33; } - &.s24 { font-size: 14px; line-height: 1.8; } + &.s24 { font-size: 13px; line-height: 1.8; } &.s26 { font-size: 20px; line-height: 1.33; } &.s32 { font-size: 20px; line-height: 30px; } &.s40 { font-size: 16px; line-height: 38px; } -- cgit v1.2.1 From 86e0d931abc34600ea65f86e92d8d2423664150a Mon Sep 17 00:00:00 2001 From: Kushal Pandya Date: Fri, 22 Dec 2017 12:29:09 +0530 Subject: Add `updatedAt` prop for Projects --- app/assets/javascripts/groups/store/groups_store.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/groups/store/groups_store.js b/app/assets/javascripts/groups/store/groups_store.js index a1689f4c5cc..ffc86175548 100644 --- a/app/assets/javascripts/groups/store/groups_store.js +++ b/app/assets/javascripts/groups/store/groups_store.js @@ -91,6 +91,7 @@ export default class GroupsStore { subgroupCount: rawGroupItem.subgroup_count, memberCount: rawGroupItem.number_users_with_delimiter, starCount: rawGroupItem.star_count, + updatedAt: rawGroupItem.updated_at, }; } -- cgit v1.2.1 From 95ff461314a23a21a52f4dc240fa91873b91226c Mon Sep 17 00:00:00 2001 From: Kushal Pandya Date: Fri, 22 Dec 2017 12:30:07 +0530 Subject: Use SVG sprite icons --- .../javascripts/groups/components/item_actions.vue | 18 +++++++----------- .../javascripts/groups/components/item_type_icon.vue | 13 +++++++------ 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/app/assets/javascripts/groups/components/item_actions.vue b/app/assets/javascripts/groups/components/item_actions.vue index 58ba5aff7cf..d3817cae6dc 100644 --- a/app/assets/javascripts/groups/components/item_actions.vue +++ b/app/assets/javascripts/groups/components/item_actions.vue @@ -1,14 +1,14 @@ + + diff --git a/spec/javascripts/groups/components/item_stats_value_spec.js b/spec/javascripts/groups/components/item_stats_value_spec.js new file mode 100644 index 00000000000..e990870aaa6 --- /dev/null +++ b/spec/javascripts/groups/components/item_stats_value_spec.js @@ -0,0 +1,81 @@ +import Vue from 'vue'; + +import itemStatsValueComponent from '~/groups/components/item_stats_value.vue'; + +import mountComponent from '../../helpers/vue_mount_component_helper'; + +const createComponent = ({ title, cssClass, iconName, tooltipPlacement, value }) => { + const Component = Vue.extend(itemStatsValueComponent); + + return mountComponent(Component, { + title, + cssClass, + iconName, + tooltipPlacement, + value, + }); +}; + +describe('ItemStatsValueComponent', () => { + describe('computed', () => { + let vm; + const itemConfig = { + title: 'Subgroups', + cssClass: 'number-subgroups', + iconName: 'folder', + tooltipPlacement: 'left', + }; + + describe('isValuePresent', () => { + it('returns true if non-empty `value` is present', () => { + vm = createComponent(Object.assign({}, itemConfig, { value: 10 })); + expect(vm.isValuePresent).toBeTruthy(); + }); + + it('returns false if empty `value` is present', () => { + vm = createComponent(itemConfig); + expect(vm.isValuePresent).toBeFalsy(); + }); + + afterEach(() => { + vm.$destroy(); + }); + }); + }); + + describe('template', () => { + let vm; + beforeEach(() => { + vm = createComponent({ + title: 'Subgroups', + cssClass: 'number-subgroups', + iconName: 'folder', + tooltipPlacement: 'left', + value: 10, + }); + }); + + it('renders component element correctly', () => { + expect(vm.$el.classList.contains('number-subgroups')).toBeTruthy(); + expect(vm.$el.querySelectorAll('svg').length > 0).toBeTruthy(); + expect(vm.$el.querySelectorAll('.stat-value').length > 0).toBeTruthy(); + }); + + it('renders element tooltip correctly', () => { + expect(vm.$el.dataset.originalTitle).toBe('Subgroups'); + expect(vm.$el.dataset.placement).toBe('left'); + }); + + it('renders element icon correctly', () => { + expect(vm.$el.querySelector('svg use').getAttribute('xlink:href')).toContain('folder'); + }); + + it('renders value count correctly', () => { + expect(vm.$el.querySelector('.stat-value').innerText.trim()).toContain('10'); + }); + + afterEach(() => { + vm.$destroy(); + }); + }); +}); -- cgit v1.2.1 From f39f5d2f230d0b99852a6f5e40c2150a51022856 Mon Sep 17 00:00:00 2001 From: Kushal Pandya Date: Fri, 22 Dec 2017 13:05:10 +0530 Subject: Use ItemStatsValue Component, add `updatedAt` info for projects --- .../javascripts/groups/components/item_stats.vue | 88 +++++++++------------- 1 file changed, 37 insertions(+), 51 deletions(-) diff --git a/app/assets/javascripts/groups/components/item_stats.vue b/app/assets/javascripts/groups/components/item_stats.vue index 9f8ac138fc3..fbe129913fe 100644 --- a/app/assets/javascripts/groups/components/item_stats.vue +++ b/app/assets/javascripts/groups/components/item_stats.vue @@ -1,10 +1,14 @@ + diff --git a/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js b/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js new file mode 100644 index 00000000000..9ffbaae3ea5 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js @@ -0,0 +1,589 @@ +const fileExtensionIcons = { + html: 'html', + htm: 'html', + html_vm: 'html', + asp: 'html', + jade: 'pug', + pug: 'pug', + md: 'markdown', + 'md.rendered': 'markdown', + markdown: 'markdown', + 'markdown.rendered': 'markdown', + rst: 'markdown', + blink: 'blink', + css: 'css', + scss: 'sass', + sass: 'sass', + less: 'less', + json: 'json', + yaml: 'yaml', + 'YAML-tmLanguage': 'yaml', + yml: 'yaml', + xml: 'xml', + plist: 'xml', + xsd: 'xml', + dtd: 'xml', + xsl: 'xml', + xslt: 'xml', + resx: 'xml', + iml: 'xml', + xquery: 'xml', + tmLanguage: 'xml', + manifest: 'xml', + project: 'xml', + png: 'image', + jpeg: 'image', + jpg: 'image', + gif: 'image', + svg: 'image', + ico: 'image', + tif: 'image', + tiff: 'image', + psd: 'image', + psb: 'image', + ami: 'image', + apx: 'image', + bmp: 'image', + bpg: 'image', + brk: 'image', + cur: 'image', + dds: 'image', + dng: 'image', + exr: 'image', + fpx: 'image', + gbr: 'image', + img: 'image', + jbig2: 'image', + jb2: 'image', + jng: 'image', + jxr: 'image', + pbm: 'image', + pgf: 'image', + pic: 'image', + raw: 'image', + webp: 'image', + js: 'javascript', + ejs: 'javascript', + esx: 'javascript', + jsx: 'react', + tsx: 'react', + ini: 'settings', + dlc: 'settings', + dll: 'settings', + config: 'settings', + conf: 'settings', + properties: 'settings', + prop: 'settings', + settings: 'settings', + option: 'settings', + props: 'settings', + toml: 'settings', + prefs: 'settings', + 'sln.dotsettings': 'settings', + 'sln.dotsettings.user': 'settings', + ts: 'typescript', + 'd.ts': 'typescript-def', + marko: 'markojs', + pdf: 'pdf', + xlsx: 'table', + xls: 'table', + csv: 'table', + tsv: 'table', + vscodeignore: 'vscode', + vsixmanifest: 'vscode', + vsix: 'vscode', + 'code-workplace': 'vscode', + suo: 'visualstudio', + sln: 'visualstudio', + csproj: 'visualstudio', + vb: 'visualstudio', + pdb: 'database', + sql: 'database', + pks: 'database', + pkb: 'database', + accdb: 'database', + mdb: 'database', + sqlite: 'database', + cs: 'csharp', + zip: 'zip', + tar: 'zip', + gz: 'zip', + xz: 'zip', + bzip2: 'zip', + gzip: 'zip', + '7z': 'zip', + rar: 'zip', + tgz: 'zip', + exe: 'exe', + msi: 'exe', + java: 'java', + jar: 'java', + jsp: 'java', + c: 'c', + m: 'c', + h: 'h', + cc: 'cpp', + cpp: 'cpp', + mm: 'cpp', + cxx: 'cpp', + hpp: 'hpp', + go: 'go', + py: 'python', + url: 'url', + sh: 'console', + ksh: 'console', + csh: 'console', + tcsh: 'console', + zsh: 'console', + bash: 'console', + bat: 'console', + cmd: 'console', + ps1: 'powershell', + psm1: 'powershell', + psd1: 'powershell', + ps1xml: 'powershell', + psc1: 'powershell', + pssc: 'powershell', + gradle: 'gradle', + doc: 'word', + docx: 'word', + rtf: 'word', + cer: 'certificate', + cert: 'certificate', + crt: 'certificate', + pub: 'key', + key: 'key', + pem: 'key', + asc: 'key', + gpg: 'key', + woff: 'font', + woff2: 'font', + ttf: 'font', + eot: 'font', + suit: 'font', + otf: 'font', + bmap: 'font', + fnt: 'font', + odttf: 'font', + ttc: 'font', + font: 'font', + fonts: 'font', + sui: 'font', + ntf: 'font', + mrf: 'font', + lib: 'lib', + bib: 'lib', + rb: 'ruby', + erb: 'ruby', + fs: 'fsharp', + fsx: 'fsharp', + fsi: 'fsharp', + fsproj: 'fsharp', + swift: 'swift', + ino: 'arduino', + dockerignore: 'docker', + dockerfile: 'docker', + tex: 'tex', + cls: 'tex', + sty: 'tex', + pptx: 'powerpoint', + ppt: 'powerpoint', + pptm: 'powerpoint', + potx: 'powerpoint', + pot: 'powerpoint', + potm: 'powerpoint', + ppsx: 'powerpoint', + ppsm: 'powerpoint', + pps: 'powerpoint', + ppam: 'powerpoint', + ppa: 'powerpoint', + webm: 'movie', + mkv: 'movie', + flv: 'movie', + vob: 'movie', + ogv: 'movie', + ogg: 'movie', + gifv: 'movie', + avi: 'movie', + mov: 'movie', + qt: 'movie', + wmv: 'movie', + yuv: 'movie', + rm: 'movie', + rmvb: 'movie', + mp4: 'movie', + m4v: 'movie', + mpg: 'movie', + mp2: 'movie', + mpeg: 'movie', + mpe: 'movie', + mpv: 'movie', + m2v: 'movie', + vdi: 'virtual', + vbox: 'virtual', + 'vbox-prev': 'virtual', + ics: 'email', + mp3: 'music', + flac: 'music', + m4a: 'music', + wma: 'music', + aiff: 'music', + coffee: 'coffee', + txt: 'document', + graphql: 'graphql', + rs: 'rust', + raml: 'raml', + xaml: 'xaml', + hs: 'haskell', + kt: 'kotlin', + kts: 'kotlin', + patch: 'git', + lua: 'lua', + clj: 'clojure', + cljs: 'clojure', + groovy: 'groovy', + r: 'r', + rmd: 'r', + dart: 'dart', + as: 'actionscript', + mxml: 'mxml', + ahk: 'autohotkey', + swf: 'flash', + swc: 'swc', + cmake: 'cmake', + asm: 'assembly', + a51: 'assembly', + inc: 'assembly', + nasm: 'assembly', + s: 'assembly', + ms: 'assembly', + agc: 'assembly', + ags: 'assembly', + aea: 'assembly', + argus: 'assembly', + mitigus: 'assembly', + binsource: 'assembly', + vue: 'vue', + ml: 'ocaml', + mli: 'ocaml', + cmx: 'ocaml', + 'js.map': 'javascript-map', + 'css.map': 'css-map', + lock: 'lock', + hbs: 'handlebars', + mustache: 'handlebars', + pl: 'perl', + pm: 'perl', + hx: 'haxe', + 'spec.ts': 'test-ts', + 'test.ts': 'test-ts', + 'ts.snap': 'test-ts', + 'spec.tsx': 'test-jsx', + 'test.tsx': 'test-jsx', + 'tsx.snap': 'test-jsx', + 'spec.jsx': 'test-jsx', + 'test.jsx': 'test-jsx', + 'jsx.snap': 'test-jsx', + 'spec.js': 'test-js', + 'test.js': 'test-js', + 'js.snap': 'test-js', + 'routing.ts': 'angular-routing', + 'routing.js': 'angular-routing', + 'module.ts': 'angular', + 'module.js': 'angular', + 'ng-template': 'angular', + 'component.ts': 'angular-component', + 'component.js': 'angular-component', + 'guard.ts': 'angular-guard', + 'guard.js': 'angular-guard', + 'service.ts': 'angular-service', + 'service.js': 'angular-service', + 'pipe.ts': 'angular-pipe', + 'pipe.js': 'angular-pipe', + 'filter.js': 'angular-pipe', + 'directive.ts': 'angular-directive', + 'directive.js': 'angular-directive', + 'resolver.ts': 'angular-resolver', + 'resolver.js': 'angular-resolver', + pp: 'puppet', + ex: 'elixir', + exs: 'elixir', + ls: 'livescript', + erl: 'erlang', + twig: 'twig', + jl: 'julia', + elm: 'elm', + pure: 'purescript', + tpl: 'smarty', + styl: 'stylus', + re: 'reason', + rei: 'reason', + cmj: 'bucklescript', + merlin: 'merlin', + v: 'verilog', + vhd: 'verilog', + sv: 'verilog', + svh: 'verilog', + nb: 'mathematica', + wl: 'wolframlanguage', + wls: 'wolframlanguage', + njk: 'nunjucks', + nunjucks: 'nunjucks', + robot: 'robot', + sol: 'solidity', + au3: 'autoit', + haml: 'haml', + yang: 'yang', + tf: 'terraform', + 'tf.json': 'terraform', + tfvars: 'terraform', + tfstate: 'terraform', + 'blade.php': 'laravel', + 'inky.php': 'laravel', + applescript: 'applescript', + cake: 'cake', + feature: 'cucumber', + nim: 'nim', + nimble: 'nim', + apib: 'apiblueprint', + apiblueprint: 'apiblueprint', + tag: 'riot', + vfl: 'vfl', + kl: 'kl', + pcss: 'postcss', + sss: 'postcss', + todo: 'todo', + cfml: 'coldfusion', + cfc: 'coldfusion', + lucee: 'coldfusion', + cabal: 'cabal', + nix: 'nix', + slim: 'slim', + http: 'http', + rest: 'http', + rql: 'restql', + restql: 'restql', + kv: 'kivy', + graphcool: 'graphcool', + sbt: 'sbt', + 'reducer.ts': 'ngrx-reducer', + 'rootReducer.ts': 'ngrx-reducer', + 'state.ts': 'ngrx-state', + 'actions.ts': 'ngrx-actions', + 'effects.ts': 'ngrx-effects', + cr: 'crystal', + 'drone.yml': 'drone', + cu: 'cuda', + cuh: 'cuda', + log: 'log', +}; + +const fileNameIcons = { + '.jscsrc': 'json', + '.jshintrc': 'json', + 'tsconfig.json': 'json', + 'tslint.json': 'json', + 'composer.lock': 'json', + '.jsbeautifyrc': 'json', + '.esformatter': 'json', + 'cdp.pid': 'json', + '.htaccess': 'xml', + '.jshintignore': 'settings', + '.buildignore': 'settings', + makefile: 'settings', + '.mrconfig': 'settings', + '.yardopts': 'settings', + 'gradle.properties': 'gradle', + gradlew: 'gradle', + 'gradle-wrapper.properties': 'gradle', + license: 'certificate', + 'license.md': 'certificate', + 'license.md.rendered': 'certificate', + 'license.txt': 'certificate', + licence: 'certificate', + 'licence.md': 'certificate', + 'licence.md.rendered': 'certificate', + 'licence.txt': 'certificate', + dockerfile: 'docker', + 'docker-compose.yml': 'docker', + '.mailmap': 'email', + '.gitignore': 'git', + '.gitconfig': 'git', + '.gitattributes': 'git', + '.gitmodules': 'git', + '.gitkeep': 'git', + 'git-history': 'git', + '.Rhistory': 'r', + 'cmakelists.txt': 'cmake', + 'cmakecache.txt': 'cmake', + 'angular-cli.json': 'angular', + '.angular-cli.json': 'angular', + '.vfl': 'vfl', + '.kl': 'kl', + 'postcss.config.js': 'postcss', + '.postcssrc.js': 'postcss', + 'project.graphcool': 'graphcool', + 'webpack.js': 'webpack', + 'webpack.ts': 'webpack', + 'webpack.base.js': 'webpack', + 'webpack.base.ts': 'webpack', + 'webpack.config.js': 'webpack', + 'webpack.config.ts': 'webpack', + 'webpack.common.js': 'webpack', + 'webpack.common.ts': 'webpack', + 'webpack.config.common.js': 'webpack', + 'webpack.config.common.ts': 'webpack', + 'webpack.config.common.babel.js': 'webpack', + 'webpack.config.common.babel.ts': 'webpack', + 'webpack.dev.js': 'webpack', + 'webpack.dev.ts': 'webpack', + 'webpack.config.dev.js': 'webpack', + 'webpack.config.dev.ts': 'webpack', + 'webpack.config.dev.babel.js': 'webpack', + 'webpack.config.dev.babel.ts': 'webpack', + 'webpack.prod.js': 'webpack', + 'webpack.prod.ts': 'webpack', + 'webpack.server.js': 'webpack', + 'webpack.server.ts': 'webpack', + 'webpack.client.js': 'webpack', + 'webpack.client.ts': 'webpack', + 'webpack.config.server.js': 'webpack', + 'webpack.config.server.ts': 'webpack', + 'webpack.config.client.js': 'webpack', + 'webpack.config.client.ts': 'webpack', + 'webpack.config.production.babel.js': 'webpack', + 'webpack.config.production.babel.ts': 'webpack', + 'webpack.config.prod.babel.js': 'webpack', + 'webpack.config.prod.babel.ts': 'webpack', + 'webpack.config.prod.js': 'webpack', + 'webpack.config.prod.ts': 'webpack', + 'webpack.config.production.js': 'webpack', + 'webpack.config.production.ts': 'webpack', + 'webpack.config.staging.js': 'webpack', + 'webpack.config.staging.ts': 'webpack', + 'webpack.config.babel.js': 'webpack', + 'webpack.config.babel.ts': 'webpack', + 'webpack.config.base.babel.js': 'webpack', + 'webpack.config.base.babel.ts': 'webpack', + 'webpack.config.base.js': 'webpack', + 'webpack.config.base.ts': 'webpack', + 'webpack.config.staging.babel.js': 'webpack', + 'webpack.config.staging.babel.ts': 'webpack', + 'webpack.config.coffee': 'webpack', + 'webpack.config.test.js': 'webpack', + 'webpack.config.test.ts': 'webpack', + 'webpack.config.vendor.js': 'webpack', + 'webpack.config.vendor.ts': 'webpack', + 'webpack.config.vendor.production.js': 'webpack', + 'webpack.config.vendor.production.ts': 'webpack', + 'webpack.test.js': 'webpack', + 'webpack.test.ts': 'webpack', + 'webpack.dist.js': 'webpack', + 'webpack.dist.ts': 'webpack', + 'webpackfile.js': 'webpack', + 'webpackfile.ts': 'webpack', + 'ionic.config.json': 'ionic', + '.io-config.json': 'ionic', + 'gulpfile.js': 'gulp', + 'gulpfile.ts': 'gulp', + 'gulpfile.babel.js': 'gulp', + 'package.json': 'nodejs', + 'package-lock.json': 'nodejs', + '.nvmrc': 'nodejs', + '.npmignore': 'npm', + '.npmrc': 'npm', + '.yarnrc': 'yarn', + 'yarn.lock': 'yarn', + '.yarnclean': 'yarn', + '.yarn-integrity': 'yarn', + 'yarn-error.log': 'yarn', + 'androidmanifest.xml': 'android', + '.env': 'tune', + '.env.example': 'tune', + '.babelrc': 'babel', + 'contributing.md': 'contributing', + 'contributing.md.rendered': 'contributing', + 'readme.md': 'readme', + 'readme.md.rendered': 'readme', + changelog: 'changelog', + 'changelog.md': 'changelog', + 'changelog.md.rendered': 'changelog', + CREDITS: 'credits', + 'credits.txt': 'credits', + 'credits.md': 'credits', + 'credits.md.rendered': 'credits', + '.flowconfig': 'flow', + 'favicon.ico': 'favicon', + 'karma.conf.js': 'karma', + 'karma.conf.ts': 'karma', + 'karma.conf.coffee': 'karma', + 'karma.config.js': 'karma', + 'karma.config.ts': 'karma', + 'karma-main.js': 'karma', + 'karma-main.ts': 'karma', + '.bithoundrc': 'bithound', + 'appveyor.yml': 'appveyor', + '.travis.yml': 'travis', + 'protractor.conf.js': 'protractor', + 'protractor.conf.ts': 'protractor', + 'protractor.conf.coffee': 'protractor', + 'protractor.config.js': 'protractor', + 'protractor.config.ts': 'protractor', + 'fuse.js': 'fusebox', + procfile: 'heroku', + '.editorconfig': 'editorconfig', + '.gitlab-ci.yml': 'gitlab', + '.bowerrc': 'bower', + 'bower.json': 'bower', + '.eslintrc.js': 'eslint', + '.eslintrc.yaml': 'eslint', + '.eslintrc.yml': 'eslint', + '.eslintrc.json': 'eslint', + '.eslintrc': 'eslint', + '.eslintignore': 'eslint', + 'code_of_conduct.md': 'conduct', + 'code_of_conduct.md.rendered': 'conduct', + '.watchmanconfig': 'watchman', + 'aurelia.json': 'aurelia', + 'mocha.opts': 'mocha', + jenkinsfile: 'jenkins', + 'firebase.json': 'firebase', + '.firebaserc': 'firebase', + 'rollup.config.js': 'rollup', + 'rollup.config.ts': 'rollup', + 'rollup-config.js': 'rollup', + 'rollup-config.ts': 'rollup', + 'rollup.config.prod.js': 'rollup', + 'rollup.config.prod.ts': 'rollup', + 'rollup.config.dev.js': 'rollup', + 'rollup.config.dev.ts': 'rollup', + 'rollup.config.prod.vendor.js': 'rollup', + 'rollup.config.prod.vendor.ts': 'rollup', + '.hhconfig': 'hack', + '.stylelintrc': 'stylelint', + 'stylelint.config.js': 'stylelint', + '.stylelintrc.json': 'stylelint', + '.stylelintrc.yaml': 'stylelint', + '.stylelintrc.yml': 'stylelint', + '.stylelintrc.js': 'stylelint', + '.stylelintignore': 'stylelint', + '.codeclimate.yml': 'code-climate', + '.prettierrc': 'prettier', + 'prettier.config.js': 'prettier', + '.prettierrc.js': 'prettier', + '.prettierrc.json': 'prettier', + '.prettierrc.yaml': 'prettier', + '.prettierrc.yml': 'prettier', + 'nodemon.json': 'nodemon', + '.sonarrc': 'sonar', + browserslist: 'browserlist', + '.browserslistrc': 'browserlist', + '.snyk': 'snyk', + '.drone.yml': 'drone', +}; + +export default function getIconForFile(name) { + return fileNameIcons[name] || + fileExtensionIcons[name ? name.split('.').pop() : ''] || + ''; +} diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss index da3c2d7fa5d..51cc1729d9a 100644 --- a/app/assets/stylesheets/pages/repo.scss +++ b/app/assets/stylesheets/pages/repo.scss @@ -96,8 +96,14 @@ padding: 6px 12px; } -.multi-file-table-name { +table.table tr td.multi-file-table-name { width: 350px; + padding: 6px 12px; + + svg { + vertical-align: middle; + margin-right: 2px; + } } .multi-file-table-col-commit-message { @@ -132,6 +138,10 @@ border-bottom: 1px solid $white-dark; cursor: pointer; + svg { + vertical-align: middle; + } + &.active { background-color: $white-light; border-bottom-color: $white-light; diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index c6a83f21ceb..c5522ff7a69 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -30,6 +30,13 @@ module IconsHelper ActionController::Base.helpers.image_path('icons.svg', host: sprite_base_url) end + def sprite_file_icons_path + # SVG Sprites currently don't work across domains, so in the case of a CDN + # we have to set the current path deliberately to prevent addition of asset_host + sprite_base_url = Gitlab.config.gitlab.url if ActionController::Base.asset_host + ActionController::Base.helpers.image_path('file_icons.svg', host: sprite_base_url) + end + def sprite_icon(icon_name, size: nil, css_class: nil) css_classes = size ? "s#{size}" : "" css_classes << " #{css_class}" unless css_class.blank? diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb index dfcdfc307b6..9148d7571f2 100644 --- a/lib/gitlab/gon_helper.rb +++ b/lib/gitlab/gon_helper.rb @@ -21,6 +21,7 @@ module Gitlab gon.revision = Gitlab::REVISION gon.gitlab_logo = ActionController::Base.helpers.asset_path('gitlab_logo.png') gon.sprite_icons = IconsHelper.sprite_icon_path + gon.sprite_file_icons = IconsHelper.sprite_file_icons_path if current_user gon.current_user_id = current_user.id diff --git a/spec/javascripts/repo/components/repo_file_spec.js b/spec/javascripts/repo/components/repo_file_spec.js index e8b370f97b4..0810da87e80 100644 --- a/spec/javascripts/repo/components/repo_file_spec.js +++ b/spec/javascripts/repo/components/repo_file_spec.js @@ -32,13 +32,9 @@ describe('RepoFile', () => { vm.$mount(); const name = vm.$el.querySelector('.repo-file-name'); - const fileIcon = vm.$el.querySelector('.file-icon'); - expect(vm.$el.querySelector(`.${vm.file.icon}`).style.marginLeft).toEqual('0px'); expect(name.href).toMatch(''); expect(name.textContent.trim()).toEqual(vm.file.name); - expect(fileIcon.classList.contains(vm.file.icon)).toBeTruthy(); - expect(fileIcon.style.marginLeft).toEqual(`${vm.file.level * 10}px`); }); it('does render if hasFiles is true and is loading tree', () => { @@ -49,17 +45,6 @@ describe('RepoFile', () => { expect(vm.$el.querySelector('.fa-spin.fa-spinner')).toBeFalsy(); }); - it('renders a spinner if the file is loading', () => { - const f = file(); - f.loading = true; - vm = createComponent({ - file: f, - }); - - expect(vm.$el.querySelector('.fa-spin.fa-spinner')).not.toBeNull(); - expect(vm.$el.querySelector('.fa-spin.fa-spinner').style.marginLeft).toEqual(`${vm.file.level * 16}px`); - }); - it('does not render commit message and datetime if mini', (done) => { vm = createComponent({ file: file(), diff --git a/spec/javascripts/vue_shared/components/file_icon_spec.js b/spec/javascripts/vue_shared/components/file_icon_spec.js new file mode 100644 index 00000000000..d99b17bdc79 --- /dev/null +++ b/spec/javascripts/vue_shared/components/file_icon_spec.js @@ -0,0 +1,83 @@ +import Vue from 'vue'; +import fileIcon from '~/vue_shared/components/file_icon.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('File Icon component', () => { + let vm; + let FileIcon; + + beforeEach(() => { + FileIcon = Vue.extend(fileIcon); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('should render a span element with an svg', () => { + vm = mountComponent(FileIcon, { + fileName: 'test.js', + }); + + expect(vm.$el.tagName).toEqual('SPAN'); + expect(vm.$el.querySelector('span > svg')).toBeDefined(); + }); + + it('should render a javascript icon based on file ending', () => { + vm = mountComponent(FileIcon, { + fileName: 'test.js', + }); + + expect(vm.$el.firstChild.firstChild.getAttribute('xlink:href')).toBe(`${gon.sprite_file_icons}#javascript`); + }); + + it('should render a image icon based on file ending', () => { + vm = mountComponent(FileIcon, { + fileName: 'test.png', + }); + + expect(vm.$el.firstChild.firstChild.getAttribute('xlink:href')).toBe(`${gon.sprite_file_icons}#image`); + }); + + it('should render a webpack icon based on file namer', () => { + vm = mountComponent(FileIcon, { + fileName: 'webpack.js', + }); + + expect(vm.$el.firstChild.firstChild.getAttribute('xlink:href')).toBe(`${gon.sprite_file_icons}#webpack`); + }); + + it('should render a standard folder icon', () => { + vm = mountComponent(FileIcon, { + fileName: 'js', + folder: true, + }); + + expect(vm.$el.querySelector('span > svg > use').getAttribute('xlink:href')).toBe(`${gon.sprite_file_icons}#folder`); + }); + + it('should render a loading icon', () => { + vm = mountComponent(FileIcon, { + fileName: 'test.js', + loading: true, + }); + + expect( + vm.$el.querySelector('i').getAttribute('class'), + ).toEqual('fa fa-spin fa-spinner fa-1x'); + }); + + it('should add a special class and a size class', () => { + vm = mountComponent(FileIcon, { + fileName: 'test.js', + cssClasses: 'extraclasses', + size: 120, + }); + + const classList = vm.$el.firstChild.classList; + const containsSizeClass = classList.contains('s120'); + const containsCustomClass = classList.contains('extraclasses'); + expect(containsSizeClass).toBe(true); + expect(containsCustomClass).toBe(true); + }); +}); -- cgit v1.2.1 From 8cf0ea4469290815daa1d64c4f3e16cbba8c00c1 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 22 Dec 2017 16:58:05 +0100 Subject: Handle Gitaly aborted merge due to branch update --- lib/gitlab/gitaly_client/operation_service.rb | 1 + spec/lib/gitlab/git/repository_spec.rb | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/gitlab/gitaly_client/operation_service.rb b/lib/gitlab/gitaly_client/operation_service.rb index c7732764880..ae1753ff0ae 100644 --- a/lib/gitlab/gitaly_client/operation_service.rb +++ b/lib/gitlab/gitaly_client/operation_service.rb @@ -101,6 +101,7 @@ module Gitlab request_enum.push(Gitaly::UserMergeBranchRequest.new(apply: true)) branch_update = response_enum.next.branch_update + return if branch_update.nil? raise Gitlab::Git::CommitError.new('failed to apply merge to branch') unless branch_update.commit_id.present? Gitlab::Git::OperationService::BranchUpdate.from_gitaly(branch_update) diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 0e4292026df..c8ed0494f68 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -1719,6 +1719,20 @@ describe Gitlab::Git::Repository, seed_helper: true do expect(result.repo_created).to eq(false) expect(result.branch_created).to eq(false) end + + it 'returns nil if there was a concurrent branch update' do + concurrent_update_id = '33f3729a45c02fc67d00adb1b8bca394b0e761d9' + result = repository.merge(user, source_sha, target_branch, 'Test merge') do + # This ref update should make the merge fail + repository.write_ref(Gitlab::Git::BRANCH_REF_PREFIX + target_branch, concurrent_update_id) + end + + # This 'nil' signals that the merge was not applied + expect(result).to be_nil + + # Our concurrent ref update should not have been reversed + expect(repository.find_branch(target_branch).target).to eq(concurrent_update_id) + end end context 'with gitaly' do -- cgit v1.2.1 From 78d22fb20db14c90861318b9f316466fbf002114 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 21 Dec 2017 16:44:07 +0100 Subject: Use a background migration for issues.closed_at In a previous attempt (rolled back in https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/16021) we tried to migrate `issues.closed_at` from timestamp to timestamptz using a regular migration. This has a bad impact on GitLab.com and as such was rolled back. This commit re-implements the original migrations using generic background migrations, allowing us to still migrate the data in a single release but without a negative impact on availability. To ensure the database schema is up to date the background migrations are performed inline in development and test environments. We also make sure to not migrate that that doesn't need migrating in the first place or has already been migrated. --- ...hange-issues-closed-at-background-migration.yml | 5 + ...140220_schedule_issues_closed_at_type_change.rb | 45 ++++++++ db/schema.rb | 2 +- doc/development/what_requires_downtime.md | 57 ++++++++++ .../cleanup_concurrent_type_change.rb | 54 +++++++++ lib/gitlab/background_migration/copy_column.rb | 39 +++++++ lib/gitlab/database/migration_helpers.rb | 121 +++++++++++++++++++-- spec/lib/gitlab/database/migration_helpers_spec.rb | 91 +++++++++++++++- 8 files changed, 402 insertions(+), 12 deletions(-) create mode 100644 changelogs/unreleased/change-issues-closed-at-background-migration.yml create mode 100644 db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb create mode 100644 lib/gitlab/background_migration/cleanup_concurrent_type_change.rb create mode 100644 lib/gitlab/background_migration/copy_column.rb diff --git a/changelogs/unreleased/change-issues-closed-at-background-migration.yml b/changelogs/unreleased/change-issues-closed-at-background-migration.yml new file mode 100644 index 00000000000..1c81c6a889e --- /dev/null +++ b/changelogs/unreleased/change-issues-closed-at-background-migration.yml @@ -0,0 +1,5 @@ +--- +title: Use a background migration for issues.closed_at +merge_request: +author: +type: other diff --git a/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb b/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb new file mode 100644 index 00000000000..be18c5866ae --- /dev/null +++ b/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb @@ -0,0 +1,45 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class ScheduleIssuesClosedAtTypeChange < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + class Issue < ActiveRecord::Base + self.table_name = 'issues' + include EachBatch + + def self.to_migrate + where('closed_at IS NOT NULL') + end + end + + def up + return unless migrate_column_type? + + change_column_type_using_background_migration( + Issue.to_migrate, + :closed_at, + :datetime_with_timezone + ) + end + + def down + return if migrate_column_type? + + change_column_type_using_background_migration( + Issue.to_migrate, + :closed_at, + :datetime + ) + end + + def migrate_column_type? + # Some environments may have already executed the previous version of this + # migration, thus we don't need to migrate those environments again. + column_for('issues', 'closed_at').type == :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index 42715d5e1e8..cd1f5d12fef 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: 20171220191323) do +ActiveRecord::Schema.define(version: 20171221140220) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" diff --git a/doc/development/what_requires_downtime.md b/doc/development/what_requires_downtime.md index 05e0a64af18..9d0c62ecc35 100644 --- a/doc/development/what_requires_downtime.md +++ b/doc/development/what_requires_downtime.md @@ -195,6 +195,63 @@ end And that's it, we're done! +## Changing Column Types For Large Tables + +While `change_column_type_concurrently` can be used for changing the type of a +column without downtime it doesn't work very well for large tables. Because all +of the work happens in sequence the migration can take a very long time to +complete, preventing a deployment from proceeding. +`change_column_type_concurrently` can also produce a lot of pressure on the +database due to it rapidly updating many rows in sequence. + +To reduce database pressure you should instead use +`change_column_type_using_background_migration` when migrating a column in a +large table (e.g. `issues`). This method works similar to +`change_column_type_concurrently` but uses background migration to spread the +work / load over a longer time period, without slowing down deployments. + +Usage of this method is fairly simple: + +```ruby +class ExampleMigration < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + disable_ddl_transaction! + + class Issue < ActiveRecord::Base + self.table_name = 'issues' + + include EachBatch + + def self.to_migrate + where('closed_at IS NOT NULL') + end + end + + def up + change_column_type_using_background_migration( + Issue.to_migrate, + :closed_at, + :datetime_with_timezone + ) + end + + def down + change_column_type_using_background_migration( + Issue.to_migrate, + :closed_at, + :datetime + ) + end +end +``` + +This would change the type of `issues.closed_at` to `timestamp with time zone`. + +Keep in mind that the relation passed to +`change_column_type_using_background_migration` _must_ include `EachBatch`, +otherwise it will raise a `TypeError`. + ## Adding Indexes Adding indexes is an expensive process that blocks INSERT and UPDATE queries for diff --git a/lib/gitlab/background_migration/cleanup_concurrent_type_change.rb b/lib/gitlab/background_migration/cleanup_concurrent_type_change.rb new file mode 100644 index 00000000000..de622f657b2 --- /dev/null +++ b/lib/gitlab/background_migration/cleanup_concurrent_type_change.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module Gitlab + module BackgroundMigration + # Background migration for cleaning up a concurrent column rename. + class CleanupConcurrentTypeChange + include Database::MigrationHelpers + + RESCHEDULE_DELAY = 10.minutes + + # table - The name of the table the migration is performed for. + # old_column - The name of the old (to drop) column. + # new_column - The name of the new column. + def perform(table, old_column, new_column) + return unless column_exists?(:issues, new_column) + + rows_to_migrate = define_model_for(table) + .where(new_column => nil) + .where + .not(old_column => nil) + + if rows_to_migrate.any? + BackgroundMigrationWorker.perform_in( + RESCHEDULE_DELAY, + 'CleanupConcurrentTypeChange', + [table, old_column, new_column] + ) + else + cleanup_concurrent_column_type_change(table, old_column) + end + end + + # These methods are necessary so we can re-use the migration helpers in + # this class. + def connection + ActiveRecord::Base.connection + end + + def method_missing(name, *args, &block) + connection.__send__(name, *args, &block) # rubocop: disable GitlabSecurity/PublicSend + end + + def respond_to_missing?(*args) + connection.respond_to?(*args) || super + end + + def define_model_for(table) + Class.new(ActiveRecord::Base) do + self.table_name = table + end + end + end + end +end diff --git a/lib/gitlab/background_migration/copy_column.rb b/lib/gitlab/background_migration/copy_column.rb new file mode 100644 index 00000000000..a2cb215c230 --- /dev/null +++ b/lib/gitlab/background_migration/copy_column.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Gitlab + module BackgroundMigration + # CopyColumn is a simple (reusable) background migration that can be used to + # update the value of a column based on the value of another column in the + # same table. + # + # For this background migration to work the table that is migrated _has_ to + # have an `id` column as the primary key. + class CopyColumn + # table - The name of the table that contains the columns. + # copy_from - The column containing the data to copy. + # copy_to - The column to copy the data to. + # start_id - The start ID of the range of rows to update. + # end_id - The end ID of the range of rows to update. + def perform(table, copy_from, copy_to, start_id, end_id) + return unless connection.column_exists?(table, copy_to) + + quoted_table = connection.quote_table_name(table) + quoted_copy_from = connection.quote_column_name(copy_from) + quoted_copy_to = connection.quote_column_name(copy_to) + + # We're using raw SQL here since this job may be frequently executed. As + # a result dynamically defining models would lead to many unnecessary + # schema information queries. + connection.execute <<-SQL.strip_heredoc + UPDATE #{quoted_table} + SET #{quoted_copy_to} = #{quoted_copy_from} + WHERE id BETWEEN #{start_id} AND #{end_id} + SQL + end + + def connection + ActiveRecord::Base.connection + end + end + end +end diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb index 3f65bc912de..33171f83692 100644 --- a/lib/gitlab/database/migration_helpers.rb +++ b/lib/gitlab/database/migration_helpers.rb @@ -385,10 +385,27 @@ module Gitlab # necessary since we copy over old values further down. change_column_default(table, new, old_col.default) if old_col.default - trigger_name = rename_trigger_name(table, old, new) + install_rename_triggers(table, old, new) + + update_column_in_batches(table, new, Arel::Table.new(table)[old]) + + change_column_null(table, new, false) unless old_col.null + + copy_indexes(table, old, new) + copy_foreign_keys(table, old, new) + end + + # Installs triggers in a table that keep a new column in sync with an old + # one. + # + # table - The name of the table to install the trigger in. + # old_column - The name of the old column. + # new_column - The name of the new column. + def install_rename_triggers(table, old_column, new_column) + trigger_name = rename_trigger_name(table, old_column, new_column) quoted_table = quote_table_name(table) - quoted_old = quote_column_name(old) - quoted_new = quote_column_name(new) + quoted_old = quote_column_name(old_column) + quoted_new = quote_column_name(new_column) if Database.postgresql? install_rename_triggers_for_postgresql(trigger_name, quoted_table, @@ -397,13 +414,6 @@ module Gitlab install_rename_triggers_for_mysql(trigger_name, quoted_table, quoted_old, quoted_new) end - - update_column_in_batches(table, new, Arel::Table.new(table)[old]) - - change_column_null(table, new, false) unless old_col.null - - copy_indexes(table, old, new) - copy_foreign_keys(table, old, new) end # Changes the type of a column concurrently. @@ -455,6 +465,97 @@ module Gitlab remove_column(table, old) end + # Changes the column type of a table using a background migration. + # + # Because this method uses a background migration it's more suitable for + # large tables. For small tables it's better to use + # `change_column_type_concurrently` since it can complete its work in a + # much shorter amount of time and doesn't rely on Sidekiq. + # + # Example usage: + # + # class Issue < ActiveRecord::Base + # self.table_name = 'issues' + # + # include EachBatch + # + # def self.to_migrate + # where('closed_at IS NOT NULL') + # end + # end + # + # change_column_type_using_background_migration( + # Issue.to_migrate, + # :closed_at, + # :datetime_with_timezone + # ) + # + # Reverting a migration like this is done exactly the same way, just with + # a different type to migrate to (e.g. `:datetime` in the above example). + # + # relation - An ActiveRecord relation to use for scheduling jobs and + # figuring out what table we're modifying. This relation _must_ + # have the EachBatch module included. + # + # column - The name of the column for which the type will be changed. + # + # new_type - The new type of the column. + # + # batch_size - The number of rows to schedule in a single background + # migration. + # + # interval - The time interval between every background migration. + def change_column_type_using_background_migration( + relation, + column, + new_type, + batch_size: 10_000, + interval: 10.minutes + ) + unless relation.model < EachBatch + raise TypeError, 'The relation must include the EachBatch module' + end + + temp_column = "#{column}_for_type_change" + table = relation.table_name + max_index = 0 + + add_column(table, temp_column, new_type) + install_rename_triggers(table, column, temp_column) + + # Schedule the jobs that will copy the data from the old column to the + # new one. + relation.each_batch(of: batch_size) do |batch, index| + start_id, end_id = batch.pluck('MIN(id), MAX(id)').first + max_index = index + + BackgroundMigrationWorker.perform_in( + index * interval, + 'CopyColumn', + [table, column, temp_column, start_id, end_id] + ) + end + + # Schedule the renaming of the column to happen (initially) 1 hour after + # the last batch finished. + BackgroundMigrationWorker.perform_in( + (max_index * interval) + 1.hour, + 'CleanupConcurrentTypeChange', + [table, column, temp_column] + ) + + if perform_background_migration_inline? + # To ensure the schema is up to date immediately we perform the + # migration inline in dev / test environments. + Gitlab::BackgroundMigration.steal('CopyColumn') + Gitlab::BackgroundMigration.steal('CleanupConcurrentTypeChange') + end + end + + def perform_background_migration_inline? + Rails.env.test? || Rails.env.development? + end + # Performs a concurrent column rename when using PostgreSQL. def install_rename_triggers_for_postgresql(trigger, table, old, new) execute <<-EOF.strip_heredoc diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index 664ba0f7234..7727a1d81b1 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -902,7 +902,7 @@ describe Gitlab::Database::MigrationHelpers do describe '#check_trigger_permissions!' do it 'does nothing when the user has the correct permissions' do expect { model.check_trigger_permissions!('users') } - .not_to raise_error(RuntimeError) + .not_to raise_error end it 'raises RuntimeError when the user does not have the correct permissions' do @@ -1036,4 +1036,93 @@ describe Gitlab::Database::MigrationHelpers do end end end + + describe '#change_column_type_using_background_migration' do + let!(:issue) { create(:issue) } + + let(:issue_model) do + Class.new(ActiveRecord::Base) do + self.table_name = 'issues' + include EachBatch + end + end + + it 'changes the type of a column using a background migration' do + expect(model) + .to receive(:add_column) + .with('issues', 'closed_at_for_type_change', :datetime_with_timezone) + + expect(model) + .to receive(:install_rename_triggers) + .with('issues', :closed_at, 'closed_at_for_type_change') + + expect(BackgroundMigrationWorker) + .to receive(:perform_in) + .ordered + .with( + 10.minutes, + 'CopyColumn', + ['issues', :closed_at, 'closed_at_for_type_change', issue.id, issue.id] + ) + + expect(BackgroundMigrationWorker) + .to receive(:perform_in) + .ordered + .with( + 1.hour + 10.minutes, + 'CleanupConcurrentTypeChange', + ['issues', :closed_at, 'closed_at_for_type_change'] + ) + + expect(Gitlab::BackgroundMigration) + .to receive(:steal) + .ordered + .with('CopyColumn') + + expect(Gitlab::BackgroundMigration) + .to receive(:steal) + .ordered + .with('CleanupConcurrentTypeChange') + + model.change_column_type_using_background_migration( + issue_model.all, + :closed_at, + :datetime_with_timezone + ) + end + end + + describe '#perform_background_migration_inline?' do + it 'returns true in a test environment' do + allow(Rails.env) + .to receive(:test?) + .and_return(true) + + expect(model.perform_background_migration_inline?).to eq(true) + end + + it 'returns true in a development environment' do + allow(Rails.env) + .to receive(:test?) + .and_return(false) + + allow(Rails.env) + .to receive(:development?) + .and_return(true) + + expect(model.perform_background_migration_inline?).to eq(true) + end + + it 'returns false in a production environment' do + allow(Rails.env) + .to receive(:test?) + .and_return(false) + + allow(Rails.env) + .to receive(:development?) + .and_return(false) + + expect(model.perform_background_migration_inline?).to eq(false) + end + end end -- cgit v1.2.1 From 8d8550c78ba0b7d6ac4a26b77b9b2def203d4eec Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Wed, 3 Jan 2018 12:44:57 +0100 Subject: Fix method lookup --- lib/gitlab/gitaly_client/conflicts_service.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/gitaly_client/conflicts_service.rb b/lib/gitlab/gitaly_client/conflicts_service.rb index 1e631e4bd3d..40f032cf873 100644 --- a/lib/gitlab/gitaly_client/conflicts_service.rb +++ b/lib/gitlab/gitaly_client/conflicts_service.rb @@ -1,6 +1,8 @@ module Gitlab module GitalyClient class ConflictsService + include Gitlab::EncodingHelper + MAX_MSG_SIZE = 128.kilobytes.freeze def initialize(repository, our_commit_oid, their_commit_oid) @@ -22,7 +24,7 @@ module Gitlab end def resolve_conflicts(target_repository, resolution, source_branch, target_branch) - reader = GitalyClient.binary_stringio(resolution.files.to_json) + reader = binary_stringio(resolution.files.to_json) req_enum = Enumerator.new do |y| header = resolve_conflicts_request_header(target_repository, resolution, source_branch, target_branch) -- cgit v1.2.1 From ce09dc31827e36fa0bd26c939a81bdb710e1fb93 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Wed, 3 Jan 2018 12:44:57 +0100 Subject: Fix method lookup --- lib/gitlab/gitaly_client/conflicts_service.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/gitaly_client/conflicts_service.rb b/lib/gitlab/gitaly_client/conflicts_service.rb index 1e631e4bd3d..40f032cf873 100644 --- a/lib/gitlab/gitaly_client/conflicts_service.rb +++ b/lib/gitlab/gitaly_client/conflicts_service.rb @@ -1,6 +1,8 @@ module Gitlab module GitalyClient class ConflictsService + include Gitlab::EncodingHelper + MAX_MSG_SIZE = 128.kilobytes.freeze def initialize(repository, our_commit_oid, their_commit_oid) @@ -22,7 +24,7 @@ module Gitlab end def resolve_conflicts(target_repository, resolution, source_branch, target_branch) - reader = GitalyClient.binary_stringio(resolution.files.to_json) + reader = binary_stringio(resolution.files.to_json) req_enum = Enumerator.new do |y| header = resolve_conflicts_request_header(target_repository, resolution, source_branch, target_branch) -- cgit v1.2.1 From 449b59ec69f7da2be9e75fdaf282592f048b9853 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Wed, 3 Jan 2018 12:54:47 +0100 Subject: Better English --- spec/lib/gitlab/git/repository_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index c8ed0494f68..21379ae0f45 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -1730,7 +1730,7 @@ describe Gitlab::Git::Repository, seed_helper: true do # This 'nil' signals that the merge was not applied expect(result).to be_nil - # Our concurrent ref update should not have been reversed + # Our concurrent ref update should not have been undone expect(repository.find_branch(target_branch).target).to eq(concurrent_update_id) end end -- cgit v1.2.1 From 6c8daa6827353564dac45f495b5953cb3b4b273b Mon Sep 17 00:00:00 2001 From: James Ramsay Date: Wed, 3 Jan 2018 08:46:06 -0500 Subject: Remove superfluous i18n namespaces --- app/views/projects/compare/_form.html.haml | 8 ++++---- app/views/projects/compare/index.html.haml | 4 ++-- app/views/projects/compare/show.html.haml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/views/projects/compare/_form.html.haml b/app/views/projects/compare/_form.html.haml index ebeeeff5e76..d0c8a699608 100644 --- a/app/views/projects/compare/_form.html.haml +++ b/app/views/projects/compare/_form.html.haml @@ -9,7 +9,7 @@ = s_("CompareBranches|Source") = hidden_field_tag :to, params[:to] = button_tag type: 'button', title: params[:to], class: "form-control compare-dropdown-toggle js-compare-dropdown has-tooltip git-revision-dropdown-toggle", required: true, data: { refs_url: refs_project_path(@project), toggle: "dropdown", target: ".js-compare-to-dropdown", selected: params[:to], field_name: :to } do - .dropdown-toggle-text.str-truncated= params[:to] || s_("CompareBranches|Select branch/tag") + .dropdown-toggle-text.str-truncated= params[:to] || _("Select branch/tag") = render 'shared/ref_dropdown' .compare-ellipsis.inline ... .form-group.dropdown.compare-form-group.from.js-compare-from-dropdown @@ -18,11 +18,11 @@ = s_("CompareBranches|Target") = hidden_field_tag :from, params[:from] = button_tag type: 'button', title: params[:from], class: "form-control compare-dropdown-toggle js-compare-dropdown has-tooltip git-revision-dropdown-toggle", required: true, data: { refs_url: refs_project_path(@project), toggle: "dropdown", target: ".js-compare-from-dropdown", selected: params[:from], field_name: :from } do - .dropdown-toggle-text.str-truncated= params[:from] || s_("CompareBranches|Select branch/tag") + .dropdown-toggle-text.str-truncated= params[:from] || _("Select branch/tag") = render 'shared/ref_dropdown'   = button_tag s_("CompareBranches|Compare"), class: "btn btn-create commits-compare-btn" - if @merge_request.present? - = link_to s_("CompareBranches|View open merge request"), project_merge_request_path(@project, @merge_request), class: 'prepend-left-10 btn' + = link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'prepend-left-10 btn' - elsif create_mr_button? - = link_to s_("CompareBranches|Create merge request"), create_mr_path, class: 'prepend-left-10 btn' + = link_to _("Create merge request"), create_mr_path, class: 'prepend-left-10 btn' diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml index b3b9aa55b7c..9b0095f5f0f 100644 --- a/app/views/projects/compare/index.html.haml +++ b/app/views/projects/compare/index.html.haml @@ -10,9 +10,9 @@ %code.ref-name master - example_sha = capture_haml do %code.ref-name 4eedf23 - = (s_("CompareBranches|Choose a branch/tag (e.g. %{master}) or enter a commit (e.g. %{sha}) to what's changed or to create a merge request.") % { master: example_master, sha: example_sha }).html_safe + = (_("Choose a branch/tag (e.g. %{master}) or enter a commit (e.g. %{sha}) to see what's changed or to create a merge request.") % { master: example_master, sha: example_sha }).html_safe %br - = (s_("ComparBranches|Changes are shown as if the source revision was being merged into the target revision.")).html_safe + = (_("Changes are shown as if the source revision was being merged into the target revision.")).html_safe .prepend-top-20 = render "form" diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml index b892d4d8ba5..0939b2a3b07 100644 --- a/app/views/projects/compare/show.html.haml +++ b/app/views/projects/compare/show.html.haml @@ -22,4 +22,4 @@ %span.ref-name= params[:to] = (s_("CompareBranches|%{source_branch} and %{target_branch} are the same.") % { source_branch: sourceBranch, target_branch: targetBranch }).html_safe - else - = s_("CompareBranches|You'll need to use different branch names to get a valid comparison.") + = _("You'll need to use different branch names to get a valid comparison.") -- cgit v1.2.1 From 5e0143a84bca7fd8b2dccd175e0f50c87dea4b98 Mon Sep 17 00:00:00 2001 From: Alessio Caiazza Date: Sat, 27 May 2017 15:23:27 +0200 Subject: Add online attribute to runner api entity --- .../unreleased/feature-api_runners_online.yml | 4 +++ doc/api/runners.md | 29 +++++++++++++++------- lib/api/entities.rb | 1 + 3 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 changelogs/unreleased/feature-api_runners_online.yml diff --git a/changelogs/unreleased/feature-api_runners_online.yml b/changelogs/unreleased/feature-api_runners_online.yml new file mode 100644 index 00000000000..f5077507e5b --- /dev/null +++ b/changelogs/unreleased/feature-api_runners_online.yml @@ -0,0 +1,4 @@ +--- +title: Add online attribute to runner api entity +merge_request: 11750 +author: Alessio Caiazza diff --git a/doc/api/runners.md b/doc/api/runners.md index 015b09a745e..50981ed96bc 100644 --- a/doc/api/runners.md +++ b/doc/api/runners.md @@ -30,14 +30,16 @@ Example response: "description": "test-1-20150125", "id": 6, "is_shared": false, - "name": null + "name": null, + "online": true }, { "active": true, "description": "test-2-20150125", "id": 8, "is_shared": false, - "name": null + "name": null, + "online": false } ] ``` @@ -69,28 +71,32 @@ Example response: "description": "shared-runner-1", "id": 1, "is_shared": true, - "name": null + "name": null, + "online": true }, { "active": true, "description": "shared-runner-2", "id": 3, "is_shared": true, - "name": null + "name": null, + "online": false }, { "active": true, "description": "test-1-20150125", "id": 6, "is_shared": false, - "name": null + "name": null, + "online": true }, { "active": true, "description": "test-2-20150125", "id": 8, "is_shared": false, - "name": null + "name": null, + "online": false } ] ``` @@ -122,6 +128,7 @@ Example response: "is_shared": false, "contacted_at": "2016-01-25T16:39:48.066Z", "name": null, + "online": true, "platform": null, "projects": [ { @@ -176,6 +183,7 @@ Example response: "is_shared": false, "contacted_at": "2016-01-25T16:39:48.066Z", "name": null, + "online": true, "platform": null, "projects": [ { @@ -327,14 +335,16 @@ Example response: "description": "test-2-20150125", "id": 8, "is_shared": false, - "name": null + "name": null, + "online": false }, { "active": true, "description": "development_runner", "id": 5, "is_shared": true, - "name": null + "name": null, + "online": true } ] ``` @@ -364,7 +374,8 @@ Example response: "description": "test-2016-02-01", "id": 9, "is_shared": false, - "name": null + "name": null, + "online": true } ``` diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 4ad4a1f7867..c612dde7f73 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -862,6 +862,7 @@ module API expose :active expose :is_shared expose :name + expose :online?, as: :online end class RunnerDetails < Runner -- cgit v1.2.1 From 87a437995e4bec0c9b84c1ae2833cf7186709911 Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Wed, 3 Jan 2018 11:57:07 -0200 Subject: Simplify metrics fetching for closed/merged MRs --- app/serializers/merge_request_widget_entity.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb index 83ea36adcc1..e905e6876c2 100644 --- a/app/serializers/merge_request_widget_entity.rb +++ b/app/serializers/merge_request_widget_entity.rb @@ -187,12 +187,11 @@ class MergeRequestWidgetEntity < IssuableEntity def build_metrics(merge_request) # There's no need to query and serialize metrics data for merge requests that are not # merged or closed. - case merge_request.state - when 'merged' - merge_request.metrics&.merged_by_id ? merge_request.metrics : build_metrics_from_events(merge_request) - when 'closed' - merge_request.metrics&.latest_closed_by_id ? merge_request.metrics : build_metrics_from_events(merge_request) - end + return unless merge_request.merged? || merge_request.closed? + return merge_request.metrics if merge_request.merged? && merge_request.metrics&.merged_by_id + return merge_request.metrics if merge_request.closed? && merge_request.metrics&.latest_closed_by_id + + build_metrics_from_events(merge_request) end def build_metrics_from_events(merge_request) -- cgit v1.2.1 From e24e0c90a30c37917555baa0bfa0849458ce93d5 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Tue, 2 Jan 2018 22:40:07 +0800 Subject: Use heredoc for long strings so it's easier to read --- qa/qa/runtime/user.rb | 14 +++++------ spec/factories/keys.rb | 63 ++++++++++++++++++++++++++++---------------------- 2 files changed, 43 insertions(+), 34 deletions(-) diff --git a/qa/qa/runtime/user.rb b/qa/qa/runtime/user.rb index 7bd50023561..2832439d9e0 100644 --- a/qa/qa/runtime/user.rb +++ b/qa/qa/runtime/user.rb @@ -12,13 +12,13 @@ module QA end def ssh_key - <<~KEY.tr("\n", '') - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFf6RYK3qu/RKF/3ndJmL5xgMLp3O9 - 6x8lTay+QGZ0+9FnnAXMdUqBq/ZU6d/gyMB4IaW3nHzM1w049++yAB6UPCzMB8Uo27K5 - /jyZCtj7Vm9PFNjF/8am1kp46c/SeYicQgQaSBdzIW3UDEa1Ef68qroOlvpi9PYZ/tA7 - M0YP0K5PXX+E36zaIRnJVMPT3f2k+GnrxtjafZrwFdpOP/Fol5BQLBgcsyiU+LM1SuaC - rzd8c9vyaTA1CxrkxaZh+buAi0PmdDtaDrHd42gqZkXCKavyvgM5o2CkQ5LJHCgzpXy0 - 5qNFzmThBSkb+XtoxbyagBiGbVZtSVow6Xa7qewz= dummy@gitlab.com + <<~KEY.delete("\n") + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFf6RYK3qu/RKF/3ndJmL5xgMLp3O9 + 6x8lTay+QGZ0+9FnnAXMdUqBq/ZU6d/gyMB4IaW3nHzM1w049++yAB6UPCzMB8Uo27K5 + /jyZCtj7Vm9PFNjF/8am1kp46c/SeYicQgQaSBdzIW3UDEa1Ef68qroOlvpi9PYZ/tA7 + M0YP0K5PXX+E36zaIRnJVMPT3f2k+GnrxtjafZrwFdpOP/Fol5BQLBgcsyiU+LM1SuaC + rzd8c9vyaTA1CxrkxaZh+buAi0PmdDtaDrHd42gqZkXCKavyvgM5o2CkQ5LJHCgzpXy0 + 5qNFzmThBSkb+XtoxbyagBiGbVZtSVow6Xa7qewz= dummy@gitlab.com KEY end end diff --git a/spec/factories/keys.rb b/spec/factories/keys.rb index e6eb76f71d3..552b4b7e06e 100644 --- a/spec/factories/keys.rb +++ b/spec/factories/keys.rb @@ -21,12 +21,14 @@ FactoryBot.define do factory :rsa_key_2048 do key do - 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFf6RYK3qu/RKF/3ndJmL5xgMLp3O9' \ - '6x8lTay+QGZ0+9FnnAXMdUqBq/ZU6d/gyMB4IaW3nHzM1w049++yAB6UPCzMB8Uo27K5' \ - '/jyZCtj7Vm9PFNjF/8am1kp46c/SeYicQgQaSBdzIW3UDEa1Ef68qroOlvpi9PYZ/tA7' \ - 'M0YP0K5PXX+E36zaIRnJVMPT3f2k+GnrxtjafZrwFdpOP/Fol5BQLBgcsyiU+LM1SuaC' \ - 'rzd8c9vyaTA1CxrkxaZh+buAi0PmdDtaDrHd42gqZkXCKavyvgM5o2CkQ5LJHCgzpXy0' \ - '5qNFzmThBSkb+XtoxbyagBiGbVZtSVow6Xa7qewz= dummy@gitlab.com' + <<~KEY.delete("\n") + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDFf6RYK3qu/RKF/3ndJmL5xgMLp3O9 + 6x8lTay+QGZ0+9FnnAXMdUqBq/ZU6d/gyMB4IaW3nHzM1w049++yAB6UPCzMB8Uo27K5 + /jyZCtj7Vm9PFNjF/8am1kp46c/SeYicQgQaSBdzIW3UDEa1Ef68qroOlvpi9PYZ/tA7 + M0YP0K5PXX+E36zaIRnJVMPT3f2k+GnrxtjafZrwFdpOP/Fol5BQLBgcsyiU+LM1SuaC + rzd8c9vyaTA1CxrkxaZh+buAi0PmdDtaDrHd42gqZkXCKavyvgM5o2CkQ5LJHCgzpXy0 + 5qNFzmThBSkb+XtoxbyagBiGbVZtSVow6Xa7qewz= dummy@gitlab.com + KEY end factory :rsa_deploy_key_2048, class: 'DeployKey' @@ -34,37 +36,44 @@ FactoryBot.define do factory :dsa_key_2048 do key do - 'ssh-dss AAAAB3NzaC1kc3MAAAEBAO/3/NPLA/zSFkMOCaTtGo+uos1flfQ5f038Uk+G' \ - 'Y9AeLGzX+Srhw59GdVXmOQLYBrOt5HdGwqYcmLnE2VurUGmhtfeO5H+3p5pGJbkS0Gxp' \ - 'YH1HRO9lWsncF3Hh1w4lYsDjkclDiSTdfTuN8F4Kb3DXNnVSCieeonp+B25F/CXagyTQ' \ - '/pvNmHFeYgGCVdnBtFdi+xfxaZ8NKdPrGggzokbKHElDZQ4Xo5EpdcyLajgM7nB2r2Rz' \ - 'OrmeaevKi5lV68ehRa9Yyrb7vxvwiwBwOgqR/mnN7Gnaq1jUdmJY+ct04Qwx37f5jvhv' \ - '5gA4U40SGMoiHM8RFIN7Ksz0jsyX73MAAAAVALRWOfjfzHpK7KLz4iqDvvTUAevJAAAB' \ - 'AEa9NZ+6y9iQ5erGsdfLTXFrhSefTG0NhghoO/5IFkSGfd8V7kzTvCHaFrcfpEA5kP8t' \ - 'poeOG0TASB6tgGOxm1Bq4Wncry5RORBPJlAVpDGRcvZ931ddH7IgltEInS6za2uH6F/1' \ - 'M1QfKePSLr6xJ1ZLYfP0Og5KTp1x6yMQvfwV0a+XdA+EPgaJWLWp/pWwKWa0oLUgjsIH' \ - 'MYzuOGh5c708uZrmkzqvgtW2NgXhcIroRgynT3IfI2lP2rqqb3uuuE/qH5UCUFO+Dc3H' \ - 'nAFNeQDT/M25AERdPYBAY5a+iPjIgO+jT7BfmfByT+AZTqZySrCyc7nNZL3YgGLK0l6A' \ - '1GgAAAEBAN9FpFOdIXE+YEZhKl1vPmbcn+b1y5zOl6N4x1B7Q8pD/pLMziWROIS8uLzb' \ - 'aZ0sMIWezHIkxuo1iROMeT+jtCubn7ragaN6AX7nMpxYUH9+mYZZs/fyElt6wCviVhTI' \ - 'zM+u7VdQsnZttOOlQfogHdL+SpeAft0DsfJjlcgQnsLlHQKv6aPqCPYUST2nE7RyW/Ex' \ - 'PrMxLtOWt0/j8RYHbwwqvyeZqBz3ESBgrS9c5tBdBfauwYUV/E7gPLOU3OZFw9ue7o+z' \ - 'wzoTZqW6Xouy5wtWvSLQSLT5XwOslmQz8QMBxD0AQyDfEFGsBCWzmbTgKv9uqrBjubsS' \ - 'Taja+Cf9kMo== dummy@gitlab.com' + <<~KEY.delete("\n") + ssh-dss AAAAB3NzaC1kc3MAAAEBAO/3/NPLA/zSFkMOCaTtGo+uos1flfQ5f038Uk+G + Y9AeLGzX+Srhw59GdVXmOQLYBrOt5HdGwqYcmLnE2VurUGmhtfeO5H+3p5pGJbkS0Gxp + YH1HRO9lWsncF3Hh1w4lYsDjkclDiSTdfTuN8F4Kb3DXNnVSCieeonp+B25F/CXagyTQ + /pvNmHFeYgGCVdnBtFdi+xfxaZ8NKdPrGggzokbKHElDZQ4Xo5EpdcyLajgM7nB2r2Rz + OrmeaevKi5lV68ehRa9Yyrb7vxvwiwBwOgqR/mnN7Gnaq1jUdmJY+ct04Qwx37f5jvhv + 5gA4U40SGMoiHM8RFIN7Ksz0jsyX73MAAAAVALRWOfjfzHpK7KLz4iqDvvTUAevJAAAB + AEa9NZ+6y9iQ5erGsdfLTXFrhSefTG0NhghoO/5IFkSGfd8V7kzTvCHaFrcfpEA5kP8t + poeOG0TASB6tgGOxm1Bq4Wncry5RORBPJlAVpDGRcvZ931ddH7IgltEInS6za2uH6F/1 + M1QfKePSLr6xJ1ZLYfP0Og5KTp1x6yMQvfwV0a+XdA+EPgaJWLWp/pWwKWa0oLUgjsIH + MYzuOGh5c708uZrmkzqvgtW2NgXhcIroRgynT3IfI2lP2rqqb3uuuE/qH5UCUFO+Dc3H + nAFNeQDT/M25AERdPYBAY5a+iPjIgO+jT7BfmfByT+AZTqZySrCyc7nNZL3YgGLK0l6A + 1GgAAAEBAN9FpFOdIXE+YEZhKl1vPmbcn+b1y5zOl6N4x1B7Q8pD/pLMziWROIS8uLzb + aZ0sMIWezHIkxuo1iROMeT+jtCubn7ragaN6AX7nMpxYUH9+mYZZs/fyElt6wCviVhTI + zM+u7VdQsnZttOOlQfogHdL+SpeAft0DsfJjlcgQnsLlHQKv6aPqCPYUST2nE7RyW/Ex + PrMxLtOWt0/j8RYHbwwqvyeZqBz3ESBgrS9c5tBdBfauwYUV/E7gPLOU3OZFw9ue7o+z + wzoTZqW6Xouy5wtWvSLQSLT5XwOslmQz8QMBxD0AQyDfEFGsBCWzmbTgKv9uqrBjubsS + Taja+Cf9kMo== dummy@gitlab.com + KEY end end factory :ecdsa_key_256 do key do - 'ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYA' \ - 'AABBBJZmkzTgY0fiCQ+DVReyH/fFwTFz0XoR3RUO0u+199H19KFw7mNPxRSMOVS7tEtO' \ - 'Nj3Q7FcZXfqthHvgAzDiHsc= dummy@gitlab.com' + <<~KEY.delete("\n") + ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYA + AABBBJZmkzTgY0fiCQ+DVReyH/fFwTFz0XoR3RUO0u+199H19KFw7mNPxRSMOVS7tEtO + Nj3Q7FcZXfqthHvgAzDiHsc= dummy@gitlab.com + KEY end end factory :ed25519_key_256 do key do - 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIETnVTgzqC1gatgSlC4zH6aYt2CAQzgJOhDRvf59ohL6 dummy@gitlab.com' + <<~KEY.delete("\n") + ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIETnVTgzqC1gatgSlC4zH6aYt2CAQzgJ + OhDRvf59ohL6 dummy@gitlab.com + KEY end end end -- cgit v1.2.1 From 86257cf7138a6d28c055071219142722787b6546 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 3 Jan 2018 16:17:16 +0100 Subject: refactor project create service --- app/models/project.rb | 2 +- app/services/projects/create_service.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/project.rb b/app/models/project.rb index e37eae9f176..6ebb083aeb4 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -639,7 +639,7 @@ class Project < ActiveRecord::Base end def import? - external_import? || forked? || gitlab_project_import? + external_import? || forked? || gitlab_project_import? || bare_repository_import? end def no_import? diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index 52b90cdf135..dc7b1f1f5cc 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -120,7 +120,7 @@ module Projects Project.transaction do @project.create_or_update_import_data(data: import_data[:data], credentials: import_data[:credentials]) if import_data - if @project.save && !@project.import? && !@project.bare_repository_import? + if @project.save && !@project.import? raise 'Failed to create repository' unless @project.create_repository end end @@ -165,7 +165,7 @@ module Projects def import_schedule if @project.errors.empty? - @project.import_schedule if @project.import? + @project.import_schedule if @project.import? && !@project.bare_repository_import? else fail(error: @project.errors.full_messages.join(', ')) end -- cgit v1.2.1 From 274bde5d8bbf17f1cbc71ff6a38d45d6fe606245 Mon Sep 17 00:00:00 2001 From: James Ramsay Date: Wed, 3 Jan 2018 10:32:03 -0500 Subject: Fix incorrect case of ruby vars --- app/views/projects/compare/show.html.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml index 0939b2a3b07..0d59d800d1e 100644 --- a/app/views/projects/compare/show.html.haml +++ b/app/views/projects/compare/show.html.haml @@ -16,10 +16,10 @@ = s_("CompareBranches|There isn't anything to compare.") %p.slead - if params[:to] == params[:from] - - sourceBranch = capture_haml do + - source_branch = capture_haml do %span.ref-name= params[:from] - - targetBranch = capture_haml do + - target_branch = capture_haml do %span.ref-name= params[:to] - = (s_("CompareBranches|%{source_branch} and %{target_branch} are the same.") % { source_branch: sourceBranch, target_branch: targetBranch }).html_safe + = (s_("CompareBranches|%{source_branch} and %{target_branch} are the same.") % { source_branch: source_branch, target_branch: target_branch }).html_safe - else = _("You'll need to use different branch names to get a valid comparison.") -- cgit v1.2.1 From 592e81503abee7087dca0c4994a9dbeff5bf6945 Mon Sep 17 00:00:00 2001 From: James Ramsay Date: Wed, 3 Jan 2018 10:32:46 -0500 Subject: Add changelog entry --- changelogs/unreleased/jramsay-4012-i18n-compare.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/jramsay-4012-i18n-compare.yml diff --git a/changelogs/unreleased/jramsay-4012-i18n-compare.yml b/changelogs/unreleased/jramsay-4012-i18n-compare.yml new file mode 100644 index 00000000000..ff15724be39 --- /dev/null +++ b/changelogs/unreleased/jramsay-4012-i18n-compare.yml @@ -0,0 +1,5 @@ +--- +title: Add i18n helpers to branch comparison view +merge_request: 16031 +author: James Ramsay +type: added -- cgit v1.2.1 From 0d6b9e30cb5c3b76ee97cd14dea1dae12a74e8d6 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Fri, 22 Dec 2017 12:25:24 -0600 Subject: Fix import project url not updating project name --- app/assets/javascripts/projects/project_new.js | 7 +++-- .../unreleased/jivl-fix-import-project-url-bug.yml | 5 ++++ spec/javascripts/projects/project_new_spec.js | 32 ++++++++++++---------- 3 files changed, 27 insertions(+), 17 deletions(-) create mode 100644 changelogs/unreleased/jivl-fix-import-project-url-bug.yml diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js index 3ecc0c2a6e5..4710e70d619 100644 --- a/app/assets/javascripts/projects/project_new.js +++ b/app/assets/javascripts/projects/project_new.js @@ -1,6 +1,7 @@ let hasUserDefinedProjectPath = false; -const deriveProjectPathFromUrl = ($projectImportUrl, $projectPath) => { +const deriveProjectPathFromUrl = ($projectImportUrl) => { + const $currentProjectPath = $projectImportUrl.parents('.toggle-import-form').find('#project_path'); if (hasUserDefinedProjectPath) { return; } @@ -21,7 +22,7 @@ const deriveProjectPathFromUrl = ($projectImportUrl, $projectPath) => { // extract everything after the last slash const pathMatch = /\/([^/]+)$/.exec(importUrl); if (pathMatch) { - $projectPath.val(pathMatch[1]); + $currentProjectPath.val(pathMatch[1]); } }; @@ -96,7 +97,7 @@ const bindEvents = () => { hasUserDefinedProjectPath = $projectPath.val().trim().length > 0; }); - $projectImportUrl.keyup(() => deriveProjectPathFromUrl($projectImportUrl, $projectPath)); + $projectImportUrl.keyup(() => deriveProjectPathFromUrl($projectImportUrl)); }; document.addEventListener('DOMContentLoaded', bindEvents); diff --git a/changelogs/unreleased/jivl-fix-import-project-url-bug.yml b/changelogs/unreleased/jivl-fix-import-project-url-bug.yml new file mode 100644 index 00000000000..0d97b9c9a53 --- /dev/null +++ b/changelogs/unreleased/jivl-fix-import-project-url-bug.yml @@ -0,0 +1,5 @@ +--- +title: Fix import project url not updating project name +merge_request: 16120 +author: +type: fixed diff --git a/spec/javascripts/projects/project_new_spec.js b/spec/javascripts/projects/project_new_spec.js index 850768f0e4f..c314ca8ab72 100644 --- a/spec/javascripts/projects/project_new_spec.js +++ b/spec/javascripts/projects/project_new_spec.js @@ -6,8 +6,12 @@ describe('New Project', () => { beforeEach(() => { setFixtures(` - - +
+
+ + +
+
`); $projectImportUrl = $('#project_import_url'); @@ -25,7 +29,7 @@ describe('New Project', () => { it('does not change project path for disabled $projectImportUrl', () => { $projectImportUrl.attr('disabled', true); - projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + projectNew.deriveProjectPathFromUrl($projectImportUrl); expect($projectPath.val()).toEqual(dummyImportUrl); }); @@ -38,7 +42,7 @@ describe('New Project', () => { it('does not change project path if it is set by user', () => { $projectPath.keyup(); - projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + projectNew.deriveProjectPathFromUrl($projectImportUrl); expect($projectPath.val()).toEqual(dummyImportUrl); }); @@ -46,7 +50,7 @@ describe('New Project', () => { it('does not change project path for empty $projectImportUrl', () => { $projectImportUrl.val(''); - projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + projectNew.deriveProjectPathFromUrl($projectImportUrl); expect($projectPath.val()).toEqual(dummyImportUrl); }); @@ -54,7 +58,7 @@ describe('New Project', () => { it('does not change project path for whitespace $projectImportUrl', () => { $projectImportUrl.val(' '); - projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + projectNew.deriveProjectPathFromUrl($projectImportUrl); expect($projectPath.val()).toEqual(dummyImportUrl); }); @@ -62,7 +66,7 @@ describe('New Project', () => { it('does not change project path for $projectImportUrl without slashes', () => { $projectImportUrl.val('has-no-slash'); - projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + projectNew.deriveProjectPathFromUrl($projectImportUrl); expect($projectPath.val()).toEqual(dummyImportUrl); }); @@ -70,7 +74,7 @@ describe('New Project', () => { it('changes project path to last $projectImportUrl component', () => { $projectImportUrl.val('/this/is/last'); - projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + projectNew.deriveProjectPathFromUrl($projectImportUrl); expect($projectPath.val()).toEqual('last'); }); @@ -78,7 +82,7 @@ describe('New Project', () => { it('ignores trailing slashes in $projectImportUrl', () => { $projectImportUrl.val('/has/trailing/slash/'); - projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + projectNew.deriveProjectPathFromUrl($projectImportUrl); expect($projectPath.val()).toEqual('slash'); }); @@ -86,7 +90,7 @@ describe('New Project', () => { it('ignores fragment identifier in $projectImportUrl', () => { $projectImportUrl.val('/this/has/a#fragment-identifier/'); - projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + projectNew.deriveProjectPathFromUrl($projectImportUrl); expect($projectPath.val()).toEqual('a'); }); @@ -94,7 +98,7 @@ describe('New Project', () => { it('ignores query string in $projectImportUrl', () => { $projectImportUrl.val('/url/with?query=string'); - projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + projectNew.deriveProjectPathFromUrl($projectImportUrl); expect($projectPath.val()).toEqual('with'); }); @@ -102,7 +106,7 @@ describe('New Project', () => { it('ignores trailing .git in $projectImportUrl', () => { $projectImportUrl.val('/repository.git'); - projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + projectNew.deriveProjectPathFromUrl($projectImportUrl); expect($projectPath.val()).toEqual('repository'); }); @@ -110,7 +114,7 @@ describe('New Project', () => { it('changes project path for HTTPS URL in $projectImportUrl', () => { $projectImportUrl.val('https://username:password@gitlab.company.com/group/project.git'); - projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + projectNew.deriveProjectPathFromUrl($projectImportUrl); expect($projectPath.val()).toEqual('project'); }); @@ -118,7 +122,7 @@ describe('New Project', () => { it('changes project path for SSH URL in $projectImportUrl', () => { $projectImportUrl.val('git@gitlab.com:gitlab-org/gitlab-ce.git'); - projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + projectNew.deriveProjectPathFromUrl($projectImportUrl); expect($projectPath.val()).toEqual('gitlab-ce'); }); -- cgit v1.2.1 From 7c721e7bba4359b60f20090d850c672d06023072 Mon Sep 17 00:00:00 2001 From: James Ramsay Date: Wed, 3 Jan 2018 11:43:01 -0500 Subject: Replace use of capture_haml with capture --- app/views/projects/compare/index.html.haml | 4 ++-- app/views/projects/compare/show.html.haml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/projects/compare/index.html.haml b/app/views/projects/compare/index.html.haml index 9b0095f5f0f..14c64b3534a 100644 --- a/app/views/projects/compare/index.html.haml +++ b/app/views/projects/compare/index.html.haml @@ -6,9 +6,9 @@ %h3.page-title = _("Compare Git revisions") .sub-header-block - - example_master = capture_haml do + - example_master = capture do %code.ref-name master - - example_sha = capture_haml do + - example_sha = capture do %code.ref-name 4eedf23 = (_("Choose a branch/tag (e.g. %{master}) or enter a commit (e.g. %{sha}) to see what's changed or to create a merge request.") % { master: example_master, sha: example_sha }).html_safe %br diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml index 0d59d800d1e..8da55664878 100644 --- a/app/views/projects/compare/show.html.haml +++ b/app/views/projects/compare/show.html.haml @@ -16,9 +16,9 @@ = s_("CompareBranches|There isn't anything to compare.") %p.slead - if params[:to] == params[:from] - - source_branch = capture_haml do + - source_branch = capture do %span.ref-name= params[:from] - - target_branch = capture_haml do + - target_branch = capture do %span.ref-name= params[:to] = (s_("CompareBranches|%{source_branch} and %{target_branch} are the same.") % { source_branch: source_branch, target_branch: target_branch }).html_safe - else -- cgit v1.2.1 From 9504a529b758b0352b9c60d67fda8b4ee2a5fec0 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 19 Dec 2017 14:36:33 -0200 Subject: Write project full path to .git/config when creating projects We'd need to keep track of project full path otherwise directory tree created with hashed storage enabled cannot be usefully imported using the import rake task. --- app/models/project.rb | 5 +++++ app/services/projects/create_service.rb | 5 +++++ spec/services/projects/create_service_spec.rb | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/app/models/project.rb b/app/models/project.rb index 6ebb083aeb4..eac78de1ac9 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1432,6 +1432,11 @@ class Project < ActiveRecord::Base Gitlab::PagesTransfer.new.rename_project(path_before_change, self.path, namespace.full_path) end + def write_repository_config(key, value, prefix: :gitlab) + key = [prefix, key].compact.join('.') + repo.config[key] = value + end + def rename_repo_notify! send_move_instructions(full_path_was) expires_full_path_cache diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index dc7b1f1f5cc..4c7e5370bbe 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -87,6 +87,11 @@ module Projects def after_create_actions log_info("#{@project.owner.name} created a new project \"#{@project.name_with_namespace}\"") + # We'd need to keep track of project full path otherwise directory tree + # created with hashed storage enabled cannot be usefully imported using + # the import rake task. + @project.write_repository_config(:fullpath, @project.full_path) + unless @project.gitlab_project_import? @project.create_wiki unless skip_wiki? create_services_from_active_templates(@project) diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb index dc89fdebce7..1833078f37c 100644 --- a/spec/services/projects/create_service_spec.rb +++ b/spec/services/projects/create_service_spec.rb @@ -252,6 +252,12 @@ describe Projects::CreateService, '#execute' do end end + it 'writes project full path to .git/config' do + project = create_project(user, opts) + + expect(project.repo.config['gitlab.fullpath']).to eq project.full_path + end + def create_project(user, opts) Projects::CreateService.new(user, opts).execute end -- cgit v1.2.1 From 64fe954dcebaadd6f686f30eb4ff0be5ebcf172d Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 19 Dec 2017 14:53:59 -0200 Subject: Update project full path in .git/config when renaming a repository --- app/models/project.rb | 5 +++++ spec/models/project_spec.rb | 14 ++++++++++++++ spec/services/projects/update_service_spec.rb | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/app/models/project.rb b/app/models/project.rb index eac78de1ac9..1182dbda0c0 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1420,6 +1420,11 @@ class Project < ActiveRecord::Base end def after_rename_repo + # We'd need to keep track of project full path otherwise directory tree + # created with hashed storage enabled cannot be usefully imported using + # the import rake task. + write_repository_config(:fullpath, full_path) + path_before_change = previous_changes['path'].first # We need to check if project had been rolled out to move resource to hashed storage or not and decide diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 7338e341359..10634d22b39 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -2626,6 +2626,14 @@ describe Project do project.rename_repo end end + + it 'updates project full path in .git/config' do + allow(project_storage).to receive(:rename_repo).and_return(true) + + expect(project).to receive(:write_repository_config).with(:fullpath, project.full_path) + + project.rename_repo + end end describe '#pages_path' do @@ -2781,6 +2789,12 @@ describe Project do end end end + + it 'updates project full path in .git/config' do + expect(project).to receive(:write_repository_config).with(:fullpath, project.full_path) + + project.rename_repo + end end describe '#pages_path' do diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb index d887f70efae..fc6aa713d6f 100644 --- a/spec/services/projects/update_service_spec.rb +++ b/spec/services/projects/update_service_spec.rb @@ -61,7 +61,7 @@ describe Projects::UpdateService do end end - context 'When project visibility is higher than parent group' do + context 'when project visibility is higher than parent group' do let(:group) { create(:group, visibility_level: Gitlab::VisibilityLevel::INTERNAL) } before do -- cgit v1.2.1 From bd90330740e0ea5c0ce0672fd605a463fcdfc898 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 19 Dec 2017 17:18:26 -0200 Subject: Update project full path in .git/config when transfering a project --- app/services/projects/transfer_service.rb | 10 ++++++++++ spec/services/projects/transfer_service_spec.rb | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index e5cd6fcdfe3..e742df5f696 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -75,6 +75,8 @@ module Projects project.old_path_with_namespace = @old_path project.expires_full_path_cache + write_repository_config(@new_path) + execute_system_hooks end rescue Exception # rubocop:disable Lint/RescueException @@ -98,6 +100,13 @@ module Projects project.save! end + def write_repository_config(full_path) + # We'd need to keep track of project full path otherwise directory tree + # created with hashed storage enabled cannot be usefully imported using + # the import rake task. + project.write_repository_config(:fullpath, full_path) + end + def refresh_permissions # This ensures we only schedule 1 job for every user that has access to # the namespaces. @@ -110,6 +119,7 @@ module Projects def rollback_side_effects rollback_folder_move update_namespace_and_visibility(@old_namespace) + write_repository_config(@old_path) end def rollback_folder_move diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index 2b1337bee7e..7377c748698 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -54,6 +54,12 @@ describe Projects::TransferService do expect(project.disk_path).not_to eq(old_path) expect(project.disk_path).to start_with(group.path) end + + it 'updates project full path in .git/config' do + transfer_project(project, user, group) + + expect(project.repo.config['gitlab.fullpath']).to eq "#{group.full_path}/#{project.path}" + end end context 'when transfer fails' do @@ -86,6 +92,12 @@ describe Projects::TransferService do expect(original_path).to eq current_path end + it 'rolls back project full path in .git/config' do + attempt_project_transfer + + expect(project.repo.config['gitlab.fullpath']).to eq project.full_path + end + it "doesn't send move notifications" do expect_any_instance_of(NotificationService).not_to receive(:project_was_moved) -- cgit v1.2.1 From ca089f59687fb8616bcbd3d5501fbc6006893e8f Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 19 Dec 2017 17:42:51 -0200 Subject: Update project full path in .git/config when renaming namespace --- app/models/concerns/storage/legacy_namespace.rb | 2 ++ app/models/namespace.rb | 7 +++++++ spec/models/namespace_spec.rb | 14 ++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/app/models/concerns/storage/legacy_namespace.rb b/app/models/concerns/storage/legacy_namespace.rb index b3020484738..22b9ef4e338 100644 --- a/app/models/concerns/storage/legacy_namespace.rb +++ b/app/models/concerns/storage/legacy_namespace.rb @@ -34,6 +34,8 @@ module Storage # So we basically we mute exceptions in next actions begin send_update_instructions + write_projects_full_path_config + true rescue # Returning false does not rollback after_* transaction but gives diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 0ff169d4531..d983b2f106b 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -268,4 +268,11 @@ class Namespace < ActiveRecord::Base def namespace_previously_created_with_same_path? RedirectRoute.permanent.exists?(path: path) end + + def write_projects_full_path_config + all_projects.each do |project| + project.expires_full_path_cache # we need to clear cache to validate renames correctly + project.write_repository_config(:fullpath, project.full_path) + end + end end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index b7c6286fd83..0a99485ec8e 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -240,6 +240,20 @@ describe Namespace do end end end + + it 'updates project full path in .git/config for each project inside namespace' do + parent = create(:group, name: 'mygroup', path: 'mygroup') + subgroup = create(:group, name: 'mysubgroup', path: 'mysubgroup', parent: parent) + project_in_parent_group = create(:project, :repository, namespace: parent, name: 'foo1') + hashed_project_in_subgroup = create(:project, :repository, :hashed, namespace: subgroup, name: 'foo2') + legacy_project_in_subgroup = create(:project, :repository, namespace: subgroup, name: 'foo3') + + parent.update(path: 'mygroup_new') + + expect(project_in_parent_group.repo.config['gitlab.fullpath']).to eq "mygroup_new/#{project_in_parent_group.path}" + expect(hashed_project_in_subgroup.repo.config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{hashed_project_in_subgroup.path}" + expect(legacy_project_in_subgroup.repo.config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{legacy_project_in_subgroup.path}" + end end describe '#rm_dir', 'callback' do -- cgit v1.2.1 From 2f2233774c3d6416f5571a2e83b367d34bad3f5f Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 19 Dec 2017 18:04:48 -0200 Subject: Write project full path to .git/config when migrating legacy storage --- .../projects/hashed_storage/migrate_repository_service.rb | 7 +++++++ .../projects/hashed_storage/migrate_repository_service_spec.rb | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/services/projects/hashed_storage/migrate_repository_service.rb b/app/services/projects/hashed_storage/migrate_repository_service.rb index 7212e7524ab..c076ce06278 100644 --- a/app/services/projects/hashed_storage/migrate_repository_service.rb +++ b/app/services/projects/hashed_storage/migrate_repository_service.rb @@ -39,6 +39,13 @@ module Projects yield end + # We'd need to keep track of project full path otherwise directory tree + # created with hashed storage enabled cannot be usefully imported using + # the import rake task. + if result + project.write_repository_config(:fullpath, project.full_path) + end + result end diff --git a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb index 3a3e47fd9c0..ded864beb1d 100644 --- a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb +++ b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Projects::HashedStorage::MigrateRepositoryService do let(:gitlab_shell) { Gitlab::Shell.new } - let(:project) { create(:project, :empty_repo, :wiki_repo) } + let(:project) { create(:project, :repository, :wiki_repo) } let(:service) { described_class.new(project) } let(:legacy_storage) { Storage::LegacyProject.new(project) } let(:hashed_storage) { Storage::HashedProject.new(project) } @@ -33,6 +33,12 @@ describe Projects::HashedStorage::MigrateRepositoryService do service.execute end + + it 'writes project full path to .git/config' do + service.execute + + expect(project.repo.config['gitlab.fullpath']).to eq project.full_path + end end context 'when one move fails' do -- cgit v1.2.1 From d3d617354e0f0da7c8930dd9c089f437603dea20 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 19 Dec 2017 19:54:04 -0200 Subject: Does not write to .git/config when importing bare repositories --- app/services/projects/create_service.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index 4c7e5370bbe..24ae50f8dc4 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -87,12 +87,12 @@ module Projects def after_create_actions log_info("#{@project.owner.name} created a new project \"#{@project.name_with_namespace}\"") - # We'd need to keep track of project full path otherwise directory tree - # created with hashed storage enabled cannot be usefully imported using - # the import rake task. - @project.write_repository_config(:fullpath, @project.full_path) - unless @project.gitlab_project_import? + # We'd need to keep track of project full path otherwise directory tree + # created with hashed storage enabled cannot be usefully imported using + # the import rake task. + @project.write_repository_config(:fullpath, @project.full_path) + @project.create_wiki unless skip_wiki? create_services_from_active_templates(@project) -- cgit v1.2.1 From 582678b5f5e1399603610b20149acf1d305309d3 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 19 Dec 2017 23:58:54 -0200 Subject: Import directory tree created with hashed storage using import rake task --- lib/gitlab/bare_repository_import/importer.rb | 9 +- lib/gitlab/bare_repository_import/repository.rb | 36 +++++-- .../gitlab/bare_repository_import/importer_spec.rb | 14 ++- .../bare_repository_import/repository_spec.rb | 119 +++++++++++++++------ 4 files changed, 129 insertions(+), 49 deletions(-) diff --git a/lib/gitlab/bare_repository_import/importer.rb b/lib/gitlab/bare_repository_import/importer.rb index 64e41d42709..1f0fdc6685e 100644 --- a/lib/gitlab/bare_repository_import/importer.rb +++ b/lib/gitlab/bare_repository_import/importer.rb @@ -14,13 +14,13 @@ module Gitlab repos_to_import.each do |repo_path| bare_repo = Gitlab::BareRepositoryImport::Repository.new(import_path, repo_path) - if bare_repo.hashed? || bare_repo.wiki? + unless bare_repo.processable? log " * Skipping repo #{bare_repo.repo_path}".color(:yellow) next end - log "Processing #{repo_path}".color(:yellow) + log "Processing #{repo_path} -> #{bare_repo.project_full_path}".color(:yellow) new(user, bare_repo).create_project_if_needed end @@ -62,6 +62,11 @@ module Gitlab if project.persisted? && mv_repo(project) log " * Created #{project.name} (#{project_full_path})".color(:green) + # We'd need to keep track of project full path otherwise directory tree + # created with hashed storage enabled cannot be usefully imported using + # the import rake task. + project.write_repository_config(:fullpath, project.full_path) + ProjectCacheWorker.perform_async(project.id) else log " * Failed trying to create #{project.name} (#{project_full_path})".color(:red) diff --git a/lib/gitlab/bare_repository_import/repository.rb b/lib/gitlab/bare_repository_import/repository.rb index fa7891c8dcc..b5907875460 100644 --- a/lib/gitlab/bare_repository_import/repository.rb +++ b/lib/gitlab/bare_repository_import/repository.rb @@ -6,39 +6,55 @@ module Gitlab def initialize(root_path, repo_path) @root_path = root_path @repo_path = repo_path - @root_path << '/' unless root_path.ends_with?('/') + full_path = + if hashed? && !wiki? + repository.config.get('gitlab.fullpath') + else + repo_relative_path + end + # Split path into 'all/the/namespaces' and 'project_name' - @group_path, _, @project_name = repo_relative_path.rpartition('/') + @group_path, _, @project_name = full_path.to_s.rpartition('/') end def wiki_exists? File.exist?(wiki_path) end - def wiki? - @wiki ||= repo_path.end_with?('.wiki.git') - end - def wiki_path @wiki_path ||= repo_path.sub(/\.git$/, '.wiki.git') end - def hashed? - @hashed ||= group_path.start_with?('@hashed') - end - def project_full_path @project_full_path ||= "#{group_path}/#{project_name}" end + def processable? + return false if wiki? + + group_path.present? && project_name.present? + end + private + def wiki? + @wiki ||= repo_path.end_with?('.wiki.git') + end + + def hashed? + @hashed ||= repo_relative_path.include?('@hashed') + end + def repo_relative_path # Remove root path and `.git` at the end repo_path[@root_path.size...-4] end + + def repository + @repository ||= Rugged::Repository.new(repo_path) + end end end end diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb index 82ac3c424d4..99cc9c4bd41 100644 --- a/spec/lib/gitlab/bare_repository_import/importer_spec.rb +++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' describe Gitlab::BareRepositoryImport::Importer, repository: true do + let(:gitlab_shell) { Gitlab::Shell.new } let!(:admin) { create(:admin) } let!(:base_dir) { Dir.mktmpdir + '/' } let(:bare_repository) { Gitlab::BareRepositoryImport::Repository.new(base_dir, File.join(base_dir, "#{project_path}.git")) } @@ -75,7 +76,7 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do end it 'creates the Git repo in disk' do - FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git")) + create_bare_repository("#{project_path}.git") importer.create_project_if_needed @@ -130,7 +131,7 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do end it 'creates the Git repo in disk' do - FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git")) + create_bare_repository("#{project_path}.git") importer.create_project_if_needed @@ -165,8 +166,8 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do it_behaves_like 'importing a repository' it 'creates the Wiki git repo in disk' do - FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git")) - FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.wiki.git")) + create_bare_repository("#{project_path}.git") + create_bare_repository("#{project_path}.wiki.git") expect(Projects::CreateService).to receive(:new).with(admin, hash_including(skip_wiki: true, import_type: 'bare_repository')).and_call_original @@ -192,4 +193,9 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do end end end + + def create_bare_repository(project_path) + repo_path = File.join(base_dir, project_path) + Gitlab::Git::Repository.create(repo_path, bare: true) + end end diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb index 61b73abcba4..770e26bbf6a 100644 --- a/spec/lib/gitlab/bare_repository_import/repository_spec.rb +++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb @@ -1,58 +1,111 @@ require 'spec_helper' describe ::Gitlab::BareRepositoryImport::Repository do - let(:project_repo_path) { described_class.new('/full/path/', '/full/path/to/repo.git') } + context 'legacy storage' do + subject { described_class.new('/full/path/', '/full/path/to/repo.git') } - it 'stores the repo path' do - expect(project_repo_path.repo_path).to eq('/full/path/to/repo.git') - end + it 'stores the repo path' do + expect(subject.repo_path).to eq('/full/path/to/repo.git') + end - it 'stores the group path' do - expect(project_repo_path.group_path).to eq('to') - end + it 'stores the group path' do + expect(subject.group_path).to eq('to') + end - it 'stores the project name' do - expect(project_repo_path.project_name).to eq('repo') - end + it 'stores the project name' do + expect(subject.project_name).to eq('repo') + end - it 'stores the wiki path' do - expect(project_repo_path.wiki_path).to eq('/full/path/to/repo.wiki.git') - end + it 'stores the wiki path' do + expect(subject.wiki_path).to eq('/full/path/to/repo.wiki.git') + end + + describe '#processable?' do + it 'returns false if it is a wiki' do + subject = described_class.new('/full/path/', '/full/path/to/a/b/my.wiki.git') - describe '#wiki?' do - it 'returns true if it is a wiki' do - wiki_path = described_class.new('/full/path/', '/full/path/to/a/b/my.wiki.git') + expect(subject.processable?).to eq(false) + end - expect(wiki_path.wiki?).to eq(true) + it 'returns true when group and project name are present' do + expect(subject.processable?).to eq(true) + end end - it 'returns false if it is not a wiki' do - expect(project_repo_path.wiki?).to eq(false) + describe '#project_full_path' do + it 'returns the project full path' do + expect(subject.repo_path).to eq('/full/path/to/repo.git') + expect(subject.project_full_path).to eq('to/repo') + end + + it 'with no trailing slash in the root path' do + repo_path = described_class.new('/full/path', '/full/path/to/repo.git') + + expect(repo_path.project_full_path).to eq('to/repo') + end end end - describe '#hashed?' do - it 'returns true if it is a hashed folder' do - path = described_class.new('/full/path/', '/full/path/@hashed/my.repo.git') + context 'hashed storage' do + let(:gitlab_shell) { Gitlab::Shell.new } + let(:repository_storage) { 'default' } + let(:root_path) { Gitlab.config.repositories.storages[repository_storage]['path'] } + let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' } + let(:hashed_path) { "@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b" } + let(:repo_path) { File.join(root_path, "#{hashed_path}.git") } + let(:wiki_path) { File.join(root_path, "#{hashed_path}.wiki.git") } - expect(path.hashed?).to eq(true) + before do + gitlab_shell.add_repository(repository_storage, hashed_path) + repository = Rugged::Repository.new(repo_path) + repository.config['gitlab.fullpath'] = 'to/repo' end - it 'returns false if it is not a hashed folder' do - expect(project_repo_path.hashed?).to eq(false) + after do + gitlab_shell.remove_repository(root_path, hashed_path) end - end - describe '#project_full_path' do - it 'returns the project full path' do - expect(project_repo_path.repo_path).to eq('/full/path/to/repo.git') - expect(project_repo_path.project_full_path).to eq('to/repo') + subject { described_class.new(root_path, repo_path) } + + it 'stores the repo path' do + expect(subject.repo_path).to eq(repo_path) + end + + it 'stores the wiki path' do + expect(subject.wiki_path).to eq(wiki_path) + end + + it 'reads the group path from .git/config' do + expect(subject.group_path).to eq('to') + end + + it 'reads the project name from .git/config' do + expect(subject.project_name).to eq('repo') end - it 'with no trailing slash in the root path' do - repo_path = described_class.new('/full/path', '/full/path/to/repo.git') + describe '#processable?' do + it 'returns false if it is a wiki' do + subject = described_class.new(root_path, wiki_path) + + expect(subject.processable?).to eq(false) + end + + it 'returns false when group and project name are missing' do + repository = Rugged::Repository.new(repo_path) + repository.config.delete('gitlab.fullpath') + + expect(subject.processable?).to eq(false) + end + + it 'returns true when group and project name are present' do + expect(subject.processable?).to eq(true) + end + end - expect(repo_path.project_full_path).to eq('to/repo') + describe '#project_full_path' do + it 'returns the project full path' do + expect(subject.project_full_path).to eq('to/repo') + end end end end -- cgit v1.2.1 From c328a7db75b601bed449ad04100e12779f5bdb36 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 20 Dec 2017 14:22:13 -0200 Subject: Handle exceptions when writing to .git/config --- app/models/project.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/models/project.rb b/app/models/project.rb index 1182dbda0c0..47ca62aa5bb 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1440,6 +1440,9 @@ class Project < ActiveRecord::Base def write_repository_config(key, value, prefix: :gitlab) key = [prefix, key].compact.join('.') repo.config[key] = value + rescue Gitlab::Git::Repository::NoRepository => e + Rails.logger.error("Error writing key #{key} to .git/config for project #{full_path} (#{id}): #{e.message}.") + nil end def rename_repo_notify! -- cgit v1.2.1 From 603fcb6b9ca0aec1a5f8d75fa16d626dd8058269 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 20 Dec 2017 15:40:59 -0200 Subject: Add CHANGELOG --- .../da-handle-hashed-storage-repos-using-repo-import-task.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/da-handle-hashed-storage-repos-using-repo-import-task.yml diff --git a/changelogs/unreleased/da-handle-hashed-storage-repos-using-repo-import-task.yml b/changelogs/unreleased/da-handle-hashed-storage-repos-using-repo-import-task.yml new file mode 100644 index 00000000000..74a00d49ab3 --- /dev/null +++ b/changelogs/unreleased/da-handle-hashed-storage-repos-using-repo-import-task.yml @@ -0,0 +1,5 @@ +--- +title: Handle GitLab hashed storage repositories using the repo import task +merge_request: +author: +type: added -- cgit v1.2.1 From 9d575acc5b46be7e0b76ccc763997412cd278ef0 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 19 Dec 2017 17:06:38 -0200 Subject: Fix TestEnv.copy_repo to use disk_path instead of full_path --- spec/models/namespace_spec.rb | 2 +- spec/models/project_spec.rb | 2 +- spec/support/test_env.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 0a99485ec8e..0678cae9b93 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -203,7 +203,7 @@ describe Namespace do context 'with subgroups' do let(:parent) { create(:group, name: 'parent', path: 'parent') } let(:child) { create(:group, name: 'child', path: 'child', parent: parent) } - let!(:project) { create(:project_empty_repo, path: 'the-project', namespace: child) } + let!(:project) { create(:project_empty_repo, path: 'the-project', namespace: child, skip_disk_validation: true) } let(:uploads_dir) { File.join(CarrierWave.root, FileUploader.base_dir) } let(:pages_dir) { File.join(TestEnv.pages_path) } diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 10634d22b39..62029f385a2 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -2676,7 +2676,7 @@ describe Project do end context 'hashed storage' do - let(:project) { create(:project, :repository) } + let(:project) { create(:project, :repository, skip_disk_validation: true) } let(:gitlab_shell) { Gitlab::Shell.new } let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' } diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index ffc051a3fff..1d99746b09f 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -215,7 +215,7 @@ module TestEnv end def copy_repo(project, bare_repo:, refs:) - target_repo_path = File.expand_path(project.repository_storage_path + "/#{project.full_path}.git") + target_repo_path = File.expand_path(project.repository_storage_path + "/#{project.disk_path}.git") FileUtils.mkdir_p(target_repo_path) FileUtils.cp_r("#{File.expand_path(bare_repo)}/.", target_repo_path) FileUtils.chmod_R 0755, target_repo_path -- cgit v1.2.1 From 93eba91df9af083ea80b3b8ab01986efdeec43a0 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 21 Dec 2017 13:58:36 -0200 Subject: Refactoring Project#write_repository_config --- app/models/namespace.rb | 2 +- app/models/project.rb | 15 +++++++-------- app/services/projects/create_service.rb | 6 +----- .../hashed_storage/migrate_repository_service.rb | 9 ++------- app/services/projects/transfer_service.rb | 5 +---- lib/gitlab/bare_repository_import/importer.rb | 7 ++----- spec/models/project_spec.rb | 22 +++++++++++----------- 7 files changed, 25 insertions(+), 41 deletions(-) diff --git a/app/models/namespace.rb b/app/models/namespace.rb index d983b2f106b..efbfc607040 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -272,7 +272,7 @@ class Namespace < ActiveRecord::Base def write_projects_full_path_config all_projects.each do |project| project.expires_full_path_cache # we need to clear cache to validate renames correctly - project.write_repository_config(:fullpath, project.full_path) + project.write_repository_config end end end diff --git a/app/models/project.rb b/app/models/project.rb index 47ca62aa5bb..9c0bbf697e2 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1420,10 +1420,7 @@ class Project < ActiveRecord::Base end def after_rename_repo - # We'd need to keep track of project full path otherwise directory tree - # created with hashed storage enabled cannot be usefully imported using - # the import rake task. - write_repository_config(:fullpath, full_path) + write_repository_config path_before_change = previous_changes['path'].first @@ -1437,11 +1434,13 @@ class Project < ActiveRecord::Base Gitlab::PagesTransfer.new.rename_project(path_before_change, self.path, namespace.full_path) end - def write_repository_config(key, value, prefix: :gitlab) - key = [prefix, key].compact.join('.') - repo.config[key] = value + def write_repository_config(gl_full_path: full_path) + # We'd need to keep track of project full path otherwise directory tree + # created with hashed storage enabled cannot be usefully imported using + # the import rake task. + repo.config['gitlab.fullpath'] = gl_full_path rescue Gitlab::Git::Repository::NoRepository => e - Rails.logger.error("Error writing key #{key} to .git/config for project #{full_path} (#{id}): #{e.message}.") + Rails.logger.error("Error writing to .git/config for project #{full_path} (#{id}): #{e.message}.") nil end diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index 24ae50f8dc4..01838ec6b5d 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -88,11 +88,7 @@ module Projects log_info("#{@project.owner.name} created a new project \"#{@project.name_with_namespace}\"") unless @project.gitlab_project_import? - # We'd need to keep track of project full path otherwise directory tree - # created with hashed storage enabled cannot be usefully imported using - # the import rake task. - @project.write_repository_config(:fullpath, @project.full_path) - + @project.write_repository_config @project.create_wiki unless skip_wiki? create_services_from_active_templates(@project) diff --git a/app/services/projects/hashed_storage/migrate_repository_service.rb b/app/services/projects/hashed_storage/migrate_repository_service.rb index c076ce06278..b6763c9436f 100644 --- a/app/services/projects/hashed_storage/migrate_repository_service.rb +++ b/app/services/projects/hashed_storage/migrate_repository_service.rb @@ -30,6 +30,8 @@ module Projects unless result rollback_folder_move project.storage_version = nil + else + project.write_repository_config end project.repository_read_only = false @@ -39,13 +41,6 @@ module Projects yield end - # We'd need to keep track of project full path otherwise directory tree - # created with hashed storage enabled cannot be usefully imported using - # the import rake task. - if result - project.write_repository_config(:fullpath, project.full_path) - end - result end diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index e742df5f696..14cf9f82bdb 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -101,10 +101,7 @@ module Projects end def write_repository_config(full_path) - # We'd need to keep track of project full path otherwise directory tree - # created with hashed storage enabled cannot be usefully imported using - # the import rake task. - project.write_repository_config(:fullpath, full_path) + project.write_repository_config(:gl_fullpath, full_path) end def refresh_permissions diff --git a/lib/gitlab/bare_repository_import/importer.rb b/lib/gitlab/bare_repository_import/importer.rb index 1f0fdc6685e..709a901aa77 100644 --- a/lib/gitlab/bare_repository_import/importer.rb +++ b/lib/gitlab/bare_repository_import/importer.rb @@ -20,7 +20,7 @@ module Gitlab next end - log "Processing #{repo_path} -> #{bare_repo.project_full_path}".color(:yellow) + log "Processing #{repo_path}".color(:yellow) new(user, bare_repo).create_project_if_needed end @@ -62,10 +62,7 @@ module Gitlab if project.persisted? && mv_repo(project) log " * Created #{project.name} (#{project_full_path})".color(:green) - # We'd need to keep track of project full path otherwise directory tree - # created with hashed storage enabled cannot be usefully imported using - # the import rake task. - project.write_repository_config(:fullpath, project.full_path) + project.write_repository_config ProjectCacheWorker.perform_async(project.id) else diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 62029f385a2..1d4b68bdf8d 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -2630,9 +2630,9 @@ describe Project do it 'updates project full path in .git/config' do allow(project_storage).to receive(:rename_repo).and_return(true) - expect(project).to receive(:write_repository_config).with(:fullpath, project.full_path) - project.rename_repo + + expect(project.repo.config['gitlab.fullpath']).to eq(project.full_path) end end @@ -2678,12 +2678,10 @@ describe Project do context 'hashed storage' do let(:project) { create(:project, :repository, skip_disk_validation: true) } let(:gitlab_shell) { Gitlab::Shell.new } - let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' } + let(:hash) { Digest::SHA2.hexdigest(project.id.to_s) } before do stub_application_setting(hashed_storage_enabled: true) - allow(Digest::SHA2).to receive(:hexdigest) { hash } - allow(project).to receive(:gitlab_shell).and_return(gitlab_shell) end describe '#legacy_storage?' do @@ -2706,13 +2704,13 @@ describe Project do describe '#base_dir' do it 'returns base_dir based on hash of project id' do - expect(project.base_dir).to eq('@hashed/6b/86') + expect(project.base_dir).to eq("@hashed/#{hash[0..1]}/#{hash[2..3]}") end end describe '#disk_path' do it 'returns disk_path based on hash of project id' do - hashed_path = '@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' + hashed_path = "@hashed/#{hash[0..1]}/#{hash[2..3]}/#{hash}" expect(project.disk_path).to eq(hashed_path) end @@ -2720,7 +2718,9 @@ describe Project do describe '#ensure_storage_path_exists' do it 'delegates to gitlab_shell to ensure namespace is created' do - expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage_path, '@hashed/6b/86') + allow(project).to receive(:gitlab_shell).and_return(gitlab_shell) + + expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage_path, "@hashed/#{hash[0..1]}/#{hash[2..3]}") project.ensure_storage_path_exists end @@ -2780,7 +2780,7 @@ describe Project do end context 'when not rolled out' do - let(:project) { create(:project, :repository, storage_version: 1) } + let(:project) { create(:project, :repository, storage_version: 1, skip_disk_validation: true) } it 'moves pages folder to new location' do expect_any_instance_of(Gitlab::UploadsTransfer).to receive(:rename_project) @@ -2791,9 +2791,9 @@ describe Project do end it 'updates project full path in .git/config' do - expect(project).to receive(:write_repository_config).with(:fullpath, project.full_path) - project.rename_repo + + expect(project.repo.config['gitlab.fullpath']).to eq(project.full_path) end end -- cgit v1.2.1 From fcb967ac672e224737f6e170693e45331eb4d636 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 21 Dec 2017 15:32:08 -0200 Subject: Write projects config to all projects inside namespace in batches --- app/models/concerns/storage/legacy_namespace.rb | 2 +- app/models/namespace.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/concerns/storage/legacy_namespace.rb b/app/models/concerns/storage/legacy_namespace.rb index 22b9ef4e338..99dbd4fbacf 100644 --- a/app/models/concerns/storage/legacy_namespace.rb +++ b/app/models/concerns/storage/legacy_namespace.rb @@ -34,7 +34,7 @@ module Storage # So we basically we mute exceptions in next actions begin send_update_instructions - write_projects_full_path_config + write_projects_repository_config true rescue diff --git a/app/models/namespace.rb b/app/models/namespace.rb index efbfc607040..bdcc9159d26 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -269,8 +269,8 @@ class Namespace < ActiveRecord::Base RedirectRoute.permanent.exists?(path: path) end - def write_projects_full_path_config - all_projects.each do |project| + def write_projects_repository_config + all_projects.find_each do |project| project.expires_full_path_cache # we need to clear cache to validate renames correctly project.write_repository_config end -- cgit v1.2.1 From 2af3400c4eeb0227ca6f38117323a18e9fbd7d9b Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 21 Dec 2017 16:04:58 -0200 Subject: Add spec for Project#write_repository_config --- spec/models/project_spec.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 1d4b68bdf8d..cea22bbd184 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -3155,4 +3155,26 @@ describe Project do it { is_expected.to eq(platform_kubernetes) } end end + + describe '#write_repository_config' do + set(:project) { create(:project, :repository) } + + it 'writes full path in .git/config when key is missing' do + project.write_repository_config + + expect(project.repo.config['gitlab.fullpath']).to eq project.full_path + end + + it 'updates full path in .git/config when key is present' do + project.write_repository_config(gl_full_path: 'old/path') + + expect { project.write_repository_config }.to change { project.repo.config['gitlab.fullpath'] }.from('old/path').to(project.full_path) + end + + it 'does not raise an error with an empty repository' do + project = create(:project_empty_repo) + + expect { project.write_repository_config }.not_to raise_error + end + end end -- cgit v1.2.1 From 58c2f3b5796cd8349dbd90404ed6ad0ca3ee6caf Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 21 Dec 2017 16:49:32 -0200 Subject: Fix Repository#processable? to allow .git repos in the root folder --- lib/gitlab/bare_repository_import/repository.rb | 3 ++- spec/lib/gitlab/bare_repository_import/repository_spec.rb | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/gitlab/bare_repository_import/repository.rb b/lib/gitlab/bare_repository_import/repository.rb index b5907875460..85b79362196 100644 --- a/lib/gitlab/bare_repository_import/repository.rb +++ b/lib/gitlab/bare_repository_import/repository.rb @@ -33,8 +33,9 @@ module Gitlab def processable? return false if wiki? + return false if hashed? && (group_path.blank? || project_name.blank?) - group_path.present? && project_name.present? + true end private diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb index 770e26bbf6a..e0b7d16ebb7 100644 --- a/spec/lib/gitlab/bare_repository_import/repository_spec.rb +++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb @@ -27,7 +27,13 @@ describe ::Gitlab::BareRepositoryImport::Repository do expect(subject.processable?).to eq(false) end - it 'returns true when group and project name are present' do + it 'returns true if group path is missing' do + subject = described_class.new('/full/path/', '/full/path/repo.git') + + expect(subject.processable?).to eq(true) + end + + it 'returns true when group path and project name are present' do expect(subject.processable?).to eq(true) end end @@ -97,7 +103,7 @@ describe ::Gitlab::BareRepositoryImport::Repository do expect(subject.processable?).to eq(false) end - it 'returns true when group and project name are present' do + it 'returns true when group path and project name are present' do expect(subject.processable?).to eq(true) end end -- cgit v1.2.1 From 6c95c771fb9a3c71d176aa996b82096a8e0a3f7a Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 21 Dec 2017 17:08:00 -0200 Subject: Fix Projects::TransferService#write_repository_config method --- app/services/projects/transfer_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 14cf9f82bdb..26765e5c3f3 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -101,7 +101,7 @@ module Projects end def write_repository_config(full_path) - project.write_repository_config(:gl_fullpath, full_path) + project.write_repository_config(gl_full_path: full_path) end def refresh_permissions -- cgit v1.2.1 From 62ee2ccfcc1d765cf2b80ba8f7a226855f2f8a2f Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Fri, 22 Dec 2017 11:28:46 -0200 Subject: Refactoring spec for Gitlab::BareRepositoryImport::Repository --- .../gitlab/bare_repository_import/repository_spec.rb | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb index e0b7d16ebb7..39f2cfe6175 100644 --- a/spec/lib/gitlab/bare_repository_import/repository_spec.rb +++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb @@ -39,15 +39,14 @@ describe ::Gitlab::BareRepositoryImport::Repository do end describe '#project_full_path' do - it 'returns the project full path' do - expect(subject.repo_path).to eq('/full/path/to/repo.git') + it 'returns the project full path with trailing slash in the root path' do expect(subject.project_full_path).to eq('to/repo') end - it 'with no trailing slash in the root path' do - repo_path = described_class.new('/full/path', '/full/path/to/repo.git') + it 'returns the project full path with no trailing slash in the root path' do + subject = described_class.new('/full/path', '/full/path/to/repo.git') - expect(repo_path.project_full_path).to eq('to/repo') + expect(subject.project_full_path).to eq('to/repo') end end end @@ -109,7 +108,13 @@ describe ::Gitlab::BareRepositoryImport::Repository do end describe '#project_full_path' do - it 'returns the project full path' do + it 'returns the project full path with trailing slash in the root path' do + expect(subject.project_full_path).to eq('to/repo') + end + + it 'returns the project full path with no trailing slash in the root path' do + subject = described_class.new(root_path[0...-1], repo_path) + expect(subject.project_full_path).to eq('to/repo') end end -- cgit v1.2.1 From 3f5403ab74b2f60c1a306a2f617d1cd323854c7a Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 3 Jan 2018 16:17:11 -0200 Subject: Remove unused variable from bare repository importer spec --- spec/lib/gitlab/bare_repository_import/importer_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb index 99cc9c4bd41..b5d86df09d2 100644 --- a/spec/lib/gitlab/bare_repository_import/importer_spec.rb +++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' describe Gitlab::BareRepositoryImport::Importer, repository: true do - let(:gitlab_shell) { Gitlab::Shell.new } let!(:admin) { create(:admin) } let!(:base_dir) { Dir.mktmpdir + '/' } let(:bare_repository) { Gitlab::BareRepositoryImport::Repository.new(base_dir, File.join(base_dir, "#{project_path}.git")) } -- cgit v1.2.1 From 08de4746dc03e7f090546063711153e99de344ae Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 3 Jan 2018 16:22:00 -0200 Subject: Refactoring Gitlab::BareRepositoryImport::Repository --- spec/lib/gitlab/bare_repository_import/repository_spec.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb index 39f2cfe6175..9f42cf1dfca 100644 --- a/spec/lib/gitlab/bare_repository_import/repository_spec.rb +++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb @@ -24,17 +24,17 @@ describe ::Gitlab::BareRepositoryImport::Repository do it 'returns false if it is a wiki' do subject = described_class.new('/full/path/', '/full/path/to/a/b/my.wiki.git') - expect(subject.processable?).to eq(false) + expect(subject).not_to be_processable end it 'returns true if group path is missing' do subject = described_class.new('/full/path/', '/full/path/repo.git') - expect(subject.processable?).to eq(true) + expect(subject).to be_processable end it 'returns true when group path and project name are present' do - expect(subject.processable?).to eq(true) + expect(subject).to be_processable end end @@ -92,18 +92,18 @@ describe ::Gitlab::BareRepositoryImport::Repository do it 'returns false if it is a wiki' do subject = described_class.new(root_path, wiki_path) - expect(subject.processable?).to eq(false) + expect(subject).not_to be_processable end it 'returns false when group and project name are missing' do repository = Rugged::Repository.new(repo_path) repository.config.delete('gitlab.fullpath') - expect(subject.processable?).to eq(false) + expect(subject).not_to be_processable end it 'returns true when group path and project name are present' do - expect(subject.processable?).to eq(true) + expect(subject).to be_processable end end -- cgit v1.2.1 From 540a2b67098782842cfdd98b4177a29ac3c81ebf Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Tue, 2 Jan 2018 15:07:13 +0200 Subject: Move 2FA disable button - Removed disable button from /profile/account - Added disable button to /profile/two_factor_auth - Changed 2FA breadcrumb from 'User Settings > Account > Account' to 'User Settings > Account > Two-Factor Authentication' --- app/views/profiles/accounts/show.html.haml | 4 ---- app/views/profiles/two_factor_auths/show.html.haml | 9 +++++++-- changelogs/unreleased/fix-move-2fa-disable-button.yml | 5 +++++ spec/features/u2f_spec.rb | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 changelogs/unreleased/fix-move-2fa-disable-button.yml diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index ced58dffcdc..f1313b79589 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -17,10 +17,6 @@ Status: #{current_user.two_factor_enabled? ? 'Enabled' : 'Disabled'} - if current_user.two_factor_enabled? = link_to 'Manage two-factor authentication', profile_two_factor_auth_path, class: 'btn btn-info' - = link_to 'Disable', profile_two_factor_auth_path, - method: :delete, - data: { confirm: "Are you sure? This will invalidate your registered applications and U2F devices." }, - class: 'btn btn-danger' - else .append-bottom-10 = link_to 'Enable two-factor authentication', profile_two_factor_auth_path, class: 'btn btn-success' diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml index 0b03276efcc..5207dac3ac2 100644 --- a/app/views/profiles/two_factor_auths/show.html.haml +++ b/app/views/profiles/two_factor_auths/show.html.haml @@ -1,5 +1,5 @@ - page_title 'Two-Factor Authentication', 'Account' -- add_to_breadcrumbs("Account", profile_account_path) +- add_to_breadcrumbs("Two-Factor Authentication", profile_account_path) - @content_class = "limit-container-width" unless fluid_layout = render 'profiles/head' @@ -18,7 +18,12 @@ 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." + %p + You've already enabled two-factor authentication using mobile authenticator applications. In order to register a different device, you must first disable two-factor authentication. + = link_to 'Disable two-factor authentication', profile_two_factor_auth_path, + method: :delete, + data: { confirm: "Are you sure? This will invalidate your registered applications and U2F devices." }, + class: 'btn btn-danger' - else %p Download the Google Authenticator application from App Store or Google Play Store and scan this code. diff --git a/changelogs/unreleased/fix-move-2fa-disable-button.yml b/changelogs/unreleased/fix-move-2fa-disable-button.yml new file mode 100644 index 00000000000..bac98ad5148 --- /dev/null +++ b/changelogs/unreleased/fix-move-2fa-disable-button.yml @@ -0,0 +1,5 @@ +--- +title: Move 2FA disable button +merge_request: 16177 +author: George Tsiolis +type: fixed diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb index c9afef2a8de..50ee1656e10 100644 --- a/spec/features/u2f_spec.rb +++ b/spec/features/u2f_spec.rb @@ -264,7 +264,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do end it "deletes u2f registrations" do - visit profile_account_path + visit profile_two_factor_auth_path expect do accept_confirm { click_on "Disable" } end.to change { U2fRegistration.count }.by(-1) -- cgit v1.2.1 From 14336c0bda493a870ffeed86379b274c522fe804 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 3 Jan 2018 16:26:59 -0200 Subject: Use if instead of unless on Projects::HashedStorage::MigrateRepositoryService --- app/services/projects/hashed_storage/migrate_repository_service.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/services/projects/hashed_storage/migrate_repository_service.rb b/app/services/projects/hashed_storage/migrate_repository_service.rb index b6763c9436f..67178de75de 100644 --- a/app/services/projects/hashed_storage/migrate_repository_service.rb +++ b/app/services/projects/hashed_storage/migrate_repository_service.rb @@ -27,11 +27,11 @@ module Projects result &&= move_repository("#{@old_wiki_disk_path}", "#{@new_disk_path}.wiki") end - unless result + if result + project.write_repository_config + else rollback_folder_move project.storage_version = nil - else - project.write_repository_config end project.repository_read_only = false -- cgit v1.2.1 From fd8e284dde6a263e7f0364b36c642c92f3ad31a4 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Wed, 3 Jan 2018 11:36:18 -0700 Subject: Add left margin to definition elements --- app/assets/stylesheets/framework/typography.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index 11c1aeea871..d0999e60e65 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -178,6 +178,10 @@ font-weight: inherit; } + dd { + margin-left: $gl-padding; + } + ul, ol { padding: 0; -- cgit v1.2.1 From 78cdac8401375cc85be54ae68e5d94d02a90233c Mon Sep 17 00:00:00 2001 From: Luc Didry Date: Wed, 3 Jan 2018 17:32:34 +0100 Subject: Expose project_id on /api/v4/pages/domains --- changelogs/unreleased/api-domains-expose-project_id.yml | 5 +++++ doc/api/pages_domains.md | 1 + lib/api/entities.rb | 1 + spec/fixtures/api/schemas/public_api/v4/pages_domain/basic.json | 3 ++- spec/requests/api/pages_domains_spec.rb | 1 + 5 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/api-domains-expose-project_id.yml diff --git a/changelogs/unreleased/api-domains-expose-project_id.yml b/changelogs/unreleased/api-domains-expose-project_id.yml new file mode 100644 index 00000000000..22617ffe9b5 --- /dev/null +++ b/changelogs/unreleased/api-domains-expose-project_id.yml @@ -0,0 +1,5 @@ +--- +title: Expose project_id on /api/v4/pages/domains +merge_request: 16200 +author: Luc Didry +type: changed diff --git a/doc/api/pages_domains.md b/doc/api/pages_domains.md index 50685f335f7..20275b902c6 100644 --- a/doc/api/pages_domains.md +++ b/doc/api/pages_domains.md @@ -21,6 +21,7 @@ curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/a { "domain": "ssl.domain.example", "url": "https://ssl.domain.example", + "project_id": 1337, "certificate": { "expired": false, "expiration": "2020-04-12T14:32:00.000Z" diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 4ad4a1f7867..270b456597d 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -1133,6 +1133,7 @@ module API class PagesDomainBasic < Grape::Entity expose :domain expose :url + expose :project_id expose :certificate, as: :certificate_expiration, if: ->(pages_domain, _) { pages_domain.certificate? }, diff --git a/spec/fixtures/api/schemas/public_api/v4/pages_domain/basic.json b/spec/fixtures/api/schemas/public_api/v4/pages_domain/basic.json index 4ba6422406c..e8c17298b43 100644 --- a/spec/fixtures/api/schemas/public_api/v4/pages_domain/basic.json +++ b/spec/fixtures/api/schemas/public_api/v4/pages_domain/basic.json @@ -3,6 +3,7 @@ "properties": { "domain": { "type": "string" }, "url": { "type": "uri" }, + "project_id": { "type": "integer" }, "certificate_expiration": { "type": "object", "properties": { @@ -13,6 +14,6 @@ "additionalProperties": false } }, - "required": ["domain", "url"], + "required": ["domain", "url", "project_id"], "additionalProperties": false } diff --git a/spec/requests/api/pages_domains_spec.rb b/spec/requests/api/pages_domains_spec.rb index d412b045e9f..5d01dc37f0e 100644 --- a/spec/requests/api/pages_domains_spec.rb +++ b/spec/requests/api/pages_domains_spec.rb @@ -46,6 +46,7 @@ describe API::PagesDomains do expect(json_response).to be_an Array expect(json_response.size).to eq(3) expect(json_response.last).to have_key('domain') + expect(json_response.last).to have_key('project_id') expect(json_response.last).to have_key('certificate_expiration') expect(json_response.last['certificate_expiration']['expired']).to be true expect(json_response.first).not_to have_key('certificate_expiration') -- cgit v1.2.1 From f635277228c4ac90bd7215db741392df1998ddfc Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Wed, 3 Jan 2018 12:03:52 -0800 Subject: Make DeleteConflictingRedirectRoutes no-op Both the post-deploy and background migration. --- .../mk-no-op-delete-conflicting-redirects.yml | 6 ++++ ...907170235_delete_conflicting_redirect_routes.rb | 28 ++--------------- .../delete_conflicting_redirect_routes_range.rb | 36 ++-------------------- ...elete_conflicting_redirect_routes_range_spec.rb | 13 +++----- .../delete_conflicting_redirect_routes_spec.rb | 22 ++----------- 5 files changed, 17 insertions(+), 88 deletions(-) create mode 100644 changelogs/unreleased/mk-no-op-delete-conflicting-redirects.yml diff --git a/changelogs/unreleased/mk-no-op-delete-conflicting-redirects.yml b/changelogs/unreleased/mk-no-op-delete-conflicting-redirects.yml new file mode 100644 index 00000000000..37fdb1df6df --- /dev/null +++ b/changelogs/unreleased/mk-no-op-delete-conflicting-redirects.yml @@ -0,0 +1,6 @@ +--- +title: Prevent excessive DB load due to faulty DeleteConflictingRedirectRoutes background + migration +merge_request: 16205 +author: +type: fixed diff --git a/db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb b/db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb index 3e84b295be4..033019c398e 100644 --- a/db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb +++ b/db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb @@ -2,36 +2,12 @@ # for more information on how to write migrations for GitLab. class DeleteConflictingRedirectRoutes < ActiveRecord::Migration - include Gitlab::Database::MigrationHelpers - - DOWNTIME = false - MIGRATION = 'DeleteConflictingRedirectRoutesRange'.freeze - BATCH_SIZE = 200 # At 200, I expect under 20s per batch, which is under our query timeout of 60s. - DELAY_INTERVAL = 12.seconds - - disable_ddl_transaction! - - class Route < ActiveRecord::Base - include EachBatch - - self.table_name = 'routes' - end - def up - say opening_message - - queue_background_migration_jobs_by_range_at_intervals(Route, MIGRATION, DELAY_INTERVAL, batch_size: BATCH_SIZE) + # No-op. + # See https://gitlab.com/gitlab-com/infrastructure/issues/3460#note_53223252 end def down # nothing end - - def opening_message - <<~MSG - Clean up redirect routes that conflict with regular routes. - See initial bug fix: - https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/13357 - MSG - end end diff --git a/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range.rb b/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range.rb index a1af045a71f..21b626dde56 100644 --- a/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range.rb +++ b/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range.rb @@ -1,44 +1,12 @@ # frozen_string_literal: true -# rubocop:disable Metrics/LineLength # rubocop:disable Style/Documentation module Gitlab module BackgroundMigration class DeleteConflictingRedirectRoutesRange - class Route < ActiveRecord::Base - self.table_name = 'routes' - end - - class RedirectRoute < ActiveRecord::Base - self.table_name = 'redirect_routes' - end - - # start_id - The start ID of the range of events to process - # end_id - The end ID of the range to process. def perform(start_id, end_id) - return unless migrate? - - conflicts = RedirectRoute.where(routes_match_redirects_clause(start_id, end_id)) - num_rows = conflicts.delete_all - - Rails.logger.info("Gitlab::BackgroundMigration::DeleteConflictingRedirectRoutesRange [#{start_id}, #{end_id}] - Deleted #{num_rows} redirect routes that were conflicting with routes.") - end - - def migrate? - Route.table_exists? && RedirectRoute.table_exists? - end - - def routes_match_redirects_clause(start_id, end_id) - <<~ROUTES_MATCH_REDIRECTS - EXISTS ( - SELECT 1 FROM routes - WHERE ( - LOWER(redirect_routes.path) = LOWER(routes.path) - OR LOWER(redirect_routes.path) LIKE LOWER(CONCAT(routes.path, '/%')) - ) - AND routes.id BETWEEN #{start_id} AND #{end_id} - ) - ROUTES_MATCH_REDIRECTS + # No-op. + # See https://gitlab.com/gitlab-com/infrastructure/issues/3460#note_53223252 end end end diff --git a/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb b/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb index 5c471cbdeda..9bae7e53b71 100644 --- a/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb +++ b/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb @@ -24,17 +24,12 @@ describe Gitlab::BackgroundMigration::DeleteConflictingRedirectRoutesRange, :mig redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'foo5') end - it 'deletes the conflicting redirect_routes in the range' do + # No-op. See https://gitlab.com/gitlab-com/infrastructure/issues/3460#note_53223252 + it 'NO-OP: does not delete any redirect_routes' do expect(redirect_routes.count).to eq(8) - expect do - described_class.new.perform(1, 3) - end.to change { redirect_routes.where("path like 'foo%'").count }.from(5).to(2) + described_class.new.perform(1, 5) - expect do - described_class.new.perform(4, 5) - end.to change { redirect_routes.where("path like 'foo%'").count }.from(2).to(0) - - expect(redirect_routes.count).to eq(3) + expect(redirect_routes.count).to eq(8) end end diff --git a/spec/migrations/delete_conflicting_redirect_routes_spec.rb b/spec/migrations/delete_conflicting_redirect_routes_spec.rb index 1df2477da51..8a191bd7139 100644 --- a/spec/migrations/delete_conflicting_redirect_routes_spec.rb +++ b/spec/migrations/delete_conflicting_redirect_routes_spec.rb @@ -10,9 +10,6 @@ describe DeleteConflictingRedirectRoutes, :migration, :sidekiq do end before do - stub_const("DeleteConflictingRedirectRoutes::BATCH_SIZE", 2) - stub_const("Gitlab::Database::MigrationHelpers::BACKGROUND_MIGRATION_JOB_BUFFER_SIZE", 2) - routes.create!(id: 1, source_id: 1, source_type: 'Namespace', path: 'foo1') routes.create!(id: 2, source_id: 2, source_type: 'Namespace', path: 'foo2') routes.create!(id: 3, source_id: 3, source_type: 'Namespace', path: 'foo3') @@ -32,27 +29,14 @@ describe DeleteConflictingRedirectRoutes, :migration, :sidekiq do redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'foo5') end - it 'correctly schedules background migrations' do + # No-op. See https://gitlab.com/gitlab-com/infrastructure/issues/3460#note_53223252 + it 'NO-OP: does not schedule any background migrations' do Sidekiq::Testing.fake! do Timecop.freeze do migrate! - expect(BackgroundMigrationWorker.jobs[0]['args']).to eq([described_class::MIGRATION, [1, 2]]) - expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(12.seconds.from_now.to_f) - expect(BackgroundMigrationWorker.jobs[1]['args']).to eq([described_class::MIGRATION, [3, 4]]) - expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(24.seconds.from_now.to_f) - expect(BackgroundMigrationWorker.jobs[2]['args']).to eq([described_class::MIGRATION, [5, 5]]) - expect(BackgroundMigrationWorker.jobs[2]['at']).to eq(36.seconds.from_now.to_f) - expect(BackgroundMigrationWorker.jobs.size).to eq 3 + expect(BackgroundMigrationWorker.jobs.size).to eq 0 end end end - - it 'schedules background migrations' do - Sidekiq::Testing.inline! do - expect do - migrate! - end.to change { redirect_routes.count }.from(8).to(3) - end - end end -- cgit v1.2.1 From 57a490ec192d91ec2fd9dc9e0511af1709001fe6 Mon Sep 17 00:00:00 2001 From: Danny Date: Wed, 3 Jan 2018 20:57:41 +0000 Subject: fix issue #37843 --- ...-due-wrongly-ansi2html-light-color-variant-conversion-feature.yml | 5 +++++ lib/gitlab/ci/ansi2html.rb | 2 +- spec/lib/gitlab/ci/ansi2html_spec.rb | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/37843-ci-trace-ansi-colours-256-bold-have-no-css-due-wrongly-ansi2html-light-color-variant-conversion-feature.yml diff --git a/changelogs/unreleased/37843-ci-trace-ansi-colours-256-bold-have-no-css-due-wrongly-ansi2html-light-color-variant-conversion-feature.yml b/changelogs/unreleased/37843-ci-trace-ansi-colours-256-bold-have-no-css-due-wrongly-ansi2html-light-color-variant-conversion-feature.yml new file mode 100644 index 00000000000..abf98cd2af4 --- /dev/null +++ b/changelogs/unreleased/37843-ci-trace-ansi-colours-256-bold-have-no-css-due-wrongly-ansi2html-light-color-variant-conversion-feature.yml @@ -0,0 +1,5 @@ +--- +title: Fix ANSI 256 bold colors in pipelines job output +merge_request: +author: +type: fixed diff --git a/lib/gitlab/ci/ansi2html.rb b/lib/gitlab/ci/ansi2html.rb index 72b75791bbb..e25916528f4 100644 --- a/lib/gitlab/ci/ansi2html.rb +++ b/lib/gitlab/ci/ansi2html.rb @@ -234,7 +234,7 @@ module Gitlab # Most terminals show bold colored text in the light color variant # Let's mimic that here if @style_mask & STYLE_SWITCHES[:bold] != 0 - fg_color.sub!(/fg-(\w{2,}+)/, 'fg-l-\1') + fg_color.sub!(/fg-([a-z]{2,}+)/, 'fg-l-\1') end css_classes << fg_color end diff --git a/spec/lib/gitlab/ci/ansi2html_spec.rb b/spec/lib/gitlab/ci/ansi2html_spec.rb index 33540eab5d6..05e2d94cbd6 100644 --- a/spec/lib/gitlab/ci/ansi2html_spec.rb +++ b/spec/lib/gitlab/ci/ansi2html_spec.rb @@ -120,6 +120,10 @@ describe Gitlab::Ci::Ansi2html do expect(convert_html("\e[48;5;240mHello")).to eq('Hello') end + it "can print 256 xterm fg bold colors" do + expect(convert_html("\e[38;5;16;1mHello")).to eq('Hello') + end + it "can print 256 xterm bg colors on normal magenta foreground" do expect(convert_html("\e[48;5;16;35mHello")).to eq('Hello') end -- cgit v1.2.1 From f6e339141d527fe50f61d9204ccf16b8ccc6d861 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Wed, 3 Jan 2018 21:03:39 +0000 Subject: Backport of methods and components added in EBackport of methods and components added in EEE --- app/assets/javascripts/lib/utils/text_utility.js | 9 +++++ .../vue_shared/components/expand_button.vue | 46 ++++++++++++++++++++++ spec/javascripts/lib/utils/text_utility_spec.js | 10 +++++ .../vue_shared/components/expand_button_spec.js | 32 +++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 app/assets/javascripts/vue_shared/components/expand_button.vue create mode 100644 spec/javascripts/vue_shared/components/expand_button_spec.js diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js index 9280b7f150c..cb6e06ea584 100644 --- a/app/assets/javascripts/lib/utils/text_utility.js +++ b/app/assets/javascripts/lib/utils/text_utility.js @@ -64,3 +64,12 @@ export const truncate = (string, maxLength) => `${string.substr(0, (maxLength - export function capitalizeFirstCharacter(text) { return `${text[0].toUpperCase()}${text.slice(1)}`; } + +/** + * Replaces all html tags from a string with the given replacement. + * + * @param {String} string + * @param {*} replace + * @returns {String} + */ +export const stripeHtml = (string, replace = '') => string.replace(/<[^>]*>/g, replace); diff --git a/app/assets/javascripts/vue_shared/components/expand_button.vue b/app/assets/javascripts/vue_shared/components/expand_button.vue new file mode 100644 index 00000000000..96991c4e268 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/expand_button.vue @@ -0,0 +1,46 @@ + + diff --git a/spec/javascripts/lib/utils/text_utility_spec.js b/spec/javascripts/lib/utils/text_utility_spec.js index 1f46c225071..6f8dad6b835 100644 --- a/spec/javascripts/lib/utils/text_utility_spec.js +++ b/spec/javascripts/lib/utils/text_utility_spec.js @@ -62,4 +62,14 @@ describe('text_utility', () => { expect(textUtils.slugify('João')).toEqual('joão'); }); }); + + describe('stripeHtml', () => { + it('replaces html tag with the default replacement', () => { + expect(textUtils.stripeHtml('This is a text with

html

.')).toEqual('This is a text with html.'); + }); + + it('replaces html tags with the provided replacement', () => { + expect(textUtils.stripeHtml('This is a text with

html

.', ' ')).toEqual('This is a text with html .'); + }); + }); }); diff --git a/spec/javascripts/vue_shared/components/expand_button_spec.js b/spec/javascripts/vue_shared/components/expand_button_spec.js new file mode 100644 index 00000000000..a33ab689dd1 --- /dev/null +++ b/spec/javascripts/vue_shared/components/expand_button_spec.js @@ -0,0 +1,32 @@ +import Vue from 'vue'; +import expandButton from '~/vue_shared/components/expand_button.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('expand button', () => { + let vm; + + beforeEach(() => { + const Component = Vue.extend(expandButton); + vm = mountComponent(Component, { + slots: { + expanded: '

Expanded!

', + }, + }); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders a collpased button', () => { + expect(vm.$el.textContent.trim()).toEqual('...'); + }); + + it('hides expander on click', (done) => { + vm.$el.querySelector('button').click(); + vm.$nextTick(() => { + expect(vm.$el.querySelector('button').getAttribute('style')).toEqual('display: none;'); + done(); + }); + }); +}); -- cgit v1.2.1 From 127cedd0203a7ad16808391b6b768a52e8cb89f8 Mon Sep 17 00:00:00 2001 From: Mayra Cabrera Date: Wed, 3 Jan 2018 17:59:23 -0600 Subject: Update Kubernetes service documentation States this service was deprecated on 10.3 and his behavior depends on the kubernetes service status. Also includes a link for the release post for more information. --- doc/api/services.md | 3 +++ doc/user/project/integrations/kubernetes.md | 2 +- doc/user/project/integrations/project_services.md | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/api/services.md b/doc/api/services.md index 7e2afc71f9a..2928ab6cc75 100644 --- a/doc/api/services.md +++ b/doc/api/services.md @@ -562,6 +562,9 @@ DELETE /projects/:id/services/jira Kubernetes / Openshift integration +CAUTION: **Warning:** +Kubernetes service integration has been deprecated in GitLab 10.3. API service endpoints will continue to work as long as the Kubernetes service is active, however if the service is inactive API endpoints will automatically return a `400 Bad Request`. Read [GitLab 10.3 release post](https://about.gitlab.com/2017/12/22/gitlab-10-3-released/#kubernetes-integration-service) for more information. + ### Create/Edit Kubernetes service Set Kubernetes service for a project. diff --git a/doc/user/project/integrations/kubernetes.md b/doc/user/project/integrations/kubernetes.md index 079a840a56a..710cf78e84f 100644 --- a/doc/user/project/integrations/kubernetes.md +++ b/doc/user/project/integrations/kubernetes.md @@ -3,7 +3,7 @@ last_updated: 2017-12-28 --- CAUTION: **Warning:** -Kubernetes service integration has been deprecated on GitLab 10.4. Fields on Kubernetes integration page are now uneditable, you can configure your clusters using the new [Clusters](../clusters/index.md) page. +Kubernetes service integration has been deprecated in GitLab 10.3. If the service is active the cluster information still be editable, however we advised to disable and reconfigure the clusters using the new [Clusters](../clusters/index.md) page. If the service is inactive the fields will be uneditable. Read [GitLab 10.3 release post](https://about.gitlab.com/2017/12/22/gitlab-10-3-released/#kubernetes-integration-service) for more information. # GitLab Kubernetes / OpenShift integration diff --git a/doc/user/project/integrations/project_services.md b/doc/user/project/integrations/project_services.md index 6bda07f103e..9496d6f2ce0 100644 --- a/doc/user/project/integrations/project_services.md +++ b/doc/user/project/integrations/project_services.md @@ -39,7 +39,7 @@ Click on the service links to see further configuration instructions and details | [Irker (IRC gateway)](irker.md) | Send IRC messages, on update, to a list of recipients through an Irker gateway | | [JIRA](jira.md) | JIRA issue tracker | | JetBrains TeamCity CI | A continuous integration and build server | -| [Kubernetes](kubernetes.md) _(Has been deprecated in GitLab 10.4)_ | A containerized deployment service | +| [Kubernetes](kubernetes.md) _(Has been deprecated in GitLab 10.3)_ | A containerized deployment service | | [Mattermost slash commands](mattermost_slash_commands.md) | Mattermost chat and ChatOps slash commands | | [Mattermost Notifications](mattermost.md) | Receive event notifications in Mattermost | | [Microsoft teams](microsoft_teams.md) | Receive notifications for actions that happen on GitLab into a room on Microsoft Teams using Office 365 Connectors | -- cgit v1.2.1 From 5d3ade5cebfaefa38f888d2b2c3ae85c131ada7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 4 Jan 2018 01:55:18 +0100 Subject: Update Advanced cluster settings subtitle --- app/views/projects/clusters/show.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/clusters/show.html.haml b/app/views/projects/clusters/show.html.haml index c15785806b9..1f5426dcfa5 100644 --- a/app/views/projects/clusters/show.html.haml +++ b/app/views/projects/clusters/show.html.haml @@ -40,6 +40,6 @@ %h4= _('Advanced settings') %button.btn.js-settings-toggle = expanded ? 'Collapse' : 'Expand' - %p= s_('ClusterIntegration|Manage cluster integration on your GitLab project') + %p= s_("ClusterIntegration|Advanced options on this cluster's integration") .settings-content = render 'advanced_settings' -- cgit v1.2.1 From e712d1d121d7e5d02987710e460be9ecb9593978 Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Thu, 4 Jan 2018 02:58:10 +0200 Subject: Remove unnecessary dashboard scroll --- app/assets/stylesheets/framework/layout.scss | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss index 3f0268541a4..fab3270b9f5 100644 --- a/app/assets/stylesheets/framework/layout.scss +++ b/app/assets/stylesheets/framework/layout.scss @@ -106,10 +106,6 @@ body { } } -.layout-page > .content-wrapper { - min-height: calc(100vh - #{$header-height}); -} - .with-performance-bar .layout-page { margin-top: $header-height + $performance-bar-height; } -- cgit v1.2.1 From ab7382f90a8a59d1dcd4445eadb0a3adb0eda7c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 4 Jan 2018 01:58:28 +0100 Subject: Update Remove cluster subtitle and alert --- app/views/projects/clusters/_advanced_settings.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/clusters/_advanced_settings.html.haml b/app/views/projects/clusters/_advanced_settings.html.haml index 7032b892029..8a13713ae02 100644 --- a/app/views/projects/clusters/_advanced_settings.html.haml +++ b/app/views/projects/clusters/_advanced_settings.html.haml @@ -11,5 +11,5 @@ %label.text-danger = s_('ClusterIntegration|Remove cluster integration') %p - = s_('ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine.') - = link_to(s_('ClusterIntegration|Remove integration'), namespace_project_cluster_path(@project.namespace, @project, @cluster.id), method: :delete, class: 'btn btn-danger', data: { confirm: "Are you sure you want to remove cluster integration from this project? This will not delete your cluster on Google Kubernetes Engine"}) + = s_("ClusterIntegration|Remove this cluster's configuration from this project. This will not delete your actual cluster.") + = link_to(s_('ClusterIntegration|Remove integration'), namespace_project_cluster_path(@project.namespace, @project, @cluster.id), method: :delete, class: 'btn btn-danger', data: { confirm: s_("ClusterIntegration|Are you sure you want to remove this cluster's integration? This will not delete your actual cluster.")}) -- cgit v1.2.1 From 43308bd826a88f92bbc92320e0591faf92acd66f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Mon, 18 Dec 2017 23:27:21 -0300 Subject: Move push_remote_branches from Gitlab::Shell to Gitlab::Git::Repository --- lib/gitlab/git/repository.rb | 19 +++++++++++++++- lib/gitlab/shell.rb | 21 ------------------ spec/lib/gitlab/git/repository_spec.rb | 40 ++++++++++++++++++++++++++++++++-- spec/lib/gitlab/shell_spec.rb | 28 ------------------------ 4 files changed, 56 insertions(+), 52 deletions(-) diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 37d67b6052c..e159a795960 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -21,6 +21,7 @@ module Gitlab REBASE_WORKTREE_PREFIX = 'rebase'.freeze SQUASH_WORKTREE_PREFIX = 'squash'.freeze GITALY_INTERNAL_URL = 'ssh://gitaly/internal.git'.freeze + GITLAB_PROJECTS_TIMEOUT = Gitlab.config.gitlab_shell.git_timeout NoRepository = Class.new(StandardError) InvalidBlobName = Class.new(StandardError) @@ -83,7 +84,7 @@ module Gitlab # Rugged repo object attr_reader :rugged - attr_reader :storage, :gl_repository, :relative_path + attr_reader :gitlab_projects, :storage, :gl_repository, :relative_path # This initializer method is only used on the client side (gitlab-ce). # Gitaly-ruby uses a different initializer. @@ -93,6 +94,12 @@ module Gitlab @gl_repository = gl_repository storage_path = Gitlab.config.repositories.storages[@storage]['path'] + @gitlab_projects = Gitlab::Git::GitlabProjects.new( + storage_path, + relative_path, + global_hooks_path: Gitlab.config.gitlab_shell.hooks_path, + logger: Rails.logger + ) @path = File.join(storage_path, @relative_path) @name = @relative_path.split("/").last @attributes = Gitlab::Git::Attributes.new(path) @@ -1266,6 +1273,12 @@ module Gitlab fresh_worktree?(worktree_path(SQUASH_WORKTREE_PREFIX, squash_id)) end + def push_remote_branches(remote_name, branch_names, forced: true) + success = @gitlab_projects.push_branches(remote_name, GITLAB_PROJECTS_TIMEOUT, forced, branch_names) + + success || gitlab_projects_error + end + def gitaly_repository Gitlab::GitalyClient::Util.repository(@storage, @relative_path, @gl_repository) end @@ -1943,6 +1956,10 @@ module Gitlab def fetch_remote(remote_name = 'origin', env: nil) run_git(['fetch', remote_name], env: env).last.zero? end + + def gitlab_projects_error + raise CommandError, @gitlab_projects.output + end end end end diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb index 9cdd3d22f18..8dbe8ba5df0 100644 --- a/lib/gitlab/shell.rb +++ b/lib/gitlab/shell.rb @@ -306,27 +306,6 @@ module Gitlab end end - # Push branch to remote repository - # - # storage - project's storage path - # project_name - project's disk path - # remote_name - remote name - # branch_names - remote branch names to push - # forced - should we use --force flag - # - # Ex. - # push_remote_branches('/path/to/storage', 'gitlab-org/gitlab-test' 'upstream', ['feature']) - # - def push_remote_branches(storage, project_name, remote_name, branch_names, forced: true) - cmd = gitlab_projects(storage, "#{project_name}.git") - - success = cmd.push_branches(remote_name, git_timeout, forced, branch_names) - - raise Error, cmd.output unless success - - success - end - # Delete branch from remote repository # # storage - project's storage path diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 0e4292026df..12ec7b1fdc4 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -18,9 +18,10 @@ describe Gitlab::Git::Repository, seed_helper: true do end let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') } + let(:storage_path) { TestEnv.repos_path } describe '.create_hooks' do - let(:repo_path) { File.join(TestEnv.repos_path, 'hook-test.git') } + let(:repo_path) { File.join(storage_path, 'hook-test.git') } let(:hooks_dir) { File.join(repo_path, 'hooks') } let(:target_hooks_dir) { Gitlab.config.gitlab_shell.hooks_path } let(:existing_target) { File.join(repo_path, 'foobar') } @@ -645,7 +646,7 @@ describe Gitlab::Git::Repository, seed_helper: true do end after do - Gitlab::Shell.new.remove_repository(TestEnv.repos_path, 'my_project') + Gitlab::Shell.new.remove_repository(storage_path, 'my_project') end it 'fetches a repository as a mirror remote' do @@ -1884,6 +1885,41 @@ describe Gitlab::Git::Repository, seed_helper: true do end end + describe '#gitlab_projects' do + subject { repository.gitlab_projects } + + it { expect(subject.shard_path).to eq(storage_path) } + it { expect(subject.repository_relative_path).to eq(repository.relative_path) } + end + + context 'gitlab_projects commands' do + let(:gitlab_projects) { repository.gitlab_projects } + let(:timeout) { Gitlab.config.gitlab_shell.git_timeout } + + describe '#push_remote_branches' do + subject do + repository.push_remote_branches('downstream-remote', ['master']) + end + + it 'executes the command' do + expect(gitlab_projects).to receive(:push_branches) + .with('downstream-remote', timeout, true, ['master']) + .and_return(true) + + is_expected.to be_truthy + end + + it 'raises an error if the command fails' do + allow(gitlab_projects).to receive(:output) { 'error' } + expect(gitlab_projects).to receive(:push_branches) + .with('downstream-remote', timeout, true, ['master']) + .and_return(false) + + expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error') + end + 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 diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb index dd779b04741..7c2c02505b3 100644 --- a/spec/lib/gitlab/shell_spec.rb +++ b/spec/lib/gitlab/shell_spec.rb @@ -348,34 +348,6 @@ describe Gitlab::Shell do end end - describe '#push_remote_branches' do - subject(:result) do - gitlab_shell.push_remote_branches( - project.repository_storage_path, - project.disk_path, - 'downstream-remote', - ['master'] - ) - end - - it 'executes the command' do - expect(gitlab_projects).to receive(:push_branches) - .with('downstream-remote', timeout, true, ['master']) - .and_return(true) - - is_expected.to be_truthy - end - - it 'fails to execute the command' do - allow(gitlab_projects).to receive(:output) { 'error' } - expect(gitlab_projects).to receive(:push_branches) - .with('downstream-remote', timeout, true, ['master']) - .and_return(false) - - expect { result }.to raise_error(Gitlab::Shell::Error, 'error') - end - end - describe '#delete_remote_branches' do subject(:result) do gitlab_shell.delete_remote_branches( -- cgit v1.2.1 From 1c458d17d723161d871659f888dd24b995b8491d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Tue, 19 Dec 2017 01:41:02 -0300 Subject: Move delete_remote_branches from Gitlab::Shell to Gitlab::Git::Repository --- lib/gitlab/git/repository.rb | 12 ++++++ lib/gitlab/shell.rb | 20 ---------- spec/lib/gitlab/git/repository_spec.rb | 69 ++++++++++++++++++++++++++++++++++ spec/lib/gitlab/shell_spec.rb | 28 -------------- 4 files changed, 81 insertions(+), 48 deletions(-) diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index e159a795960..59c5484e587 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -1279,6 +1279,18 @@ module Gitlab success || gitlab_projects_error end + def delete_remote_branches(remote_name, branch_names) + success = @gitlab_projects.delete_remote_branches(remote_name, branch_names) + + success || gitlab_projects_error + end + + def delete_remote_branches(remote_name, branch_names) + success = @gitlab_projects.delete_remote_branches(remote_name, branch_names) + + success || gitlab_projects_error + end + def gitaly_repository Gitlab::GitalyClient::Util.repository(@storage, @relative_path, @gl_repository) end diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb index 8dbe8ba5df0..40650fc5ee7 100644 --- a/lib/gitlab/shell.rb +++ b/lib/gitlab/shell.rb @@ -306,26 +306,6 @@ module Gitlab end end - # Delete branch from remote repository - # - # storage - project's storage path - # project_name - project's disk path - # remote_name - remote name - # branch_names - remote branch names - # - # Ex. - # delete_remote_branches('/path/to/storage', 'gitlab-org/gitlab-test', 'upstream', ['feature']) - # - def delete_remote_branches(storage, project_name, remote_name, branch_names) - cmd = gitlab_projects(storage, "#{project_name}.git") - - success = cmd.delete_remote_branches(remote_name, branch_names) - - raise Error, cmd.output unless success - - success - end - protected def gitlab_shell_path diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 12ec7b1fdc4..7c2c3584788 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -1918,6 +1918,75 @@ describe Gitlab::Git::Repository, seed_helper: true do expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error') end end + + describe '#delete_remote_branches' do + subject do + repository.delete_remote_branches('downstream-remote', ['master']) + end + + it 'executes the command' do + expect(gitlab_projects).to receive(:delete_remote_branches) + .with('downstream-remote', ['master']) + .and_return(true) + + is_expected.to be_truthy + end + + it 'raises an error if the command fails' do + allow(gitlab_projects).to receive(:output) { 'error' } + expect(gitlab_projects).to receive(:delete_remote_branches) + .with('downstream-remote', ['master']) + .and_return(false) + + expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error') + end + end + + describe '#delete_remote_branches' do + subject do + repository.delete_remote_branches('downstream-remote', ['master']) + end + + it 'executes the command' do + expect(gitlab_projects).to receive(:delete_remote_branches) + .with('downstream-remote', ['master']) + .and_return(true) + + is_expected.to be_truthy + end + + it 'raises an error if the command fails' do + allow(gitlab_projects).to receive(:output) { 'error' } + expect(gitlab_projects).to receive(:delete_remote_branches) + .with('downstream-remote', ['master']) + .and_return(false) + + expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error') + end + end + + describe '#delete_remote_branches' do + subject do + repository.delete_remote_branches('downstream-remote', ['master']) + end + + it 'executes the command' do + expect(gitlab_projects).to receive(:delete_remote_branches) + .with('downstream-remote', ['master']) + .and_return(true) + + is_expected.to be_truthy + end + + it 'raises an error if the command fails' do + allow(gitlab_projects).to receive(:output) { 'error' } + expect(gitlab_projects).to receive(:delete_remote_branches) + .with('downstream-remote', ['master']) + .and_return(false) + + expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error') + end + end end def create_remote_branch(repository, remote_name, branch_name, source_branch_name) diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb index 7c2c02505b3..81d9e6a8f82 100644 --- a/spec/lib/gitlab/shell_spec.rb +++ b/spec/lib/gitlab/shell_spec.rb @@ -347,34 +347,6 @@ describe Gitlab::Shell do end.to raise_error(Gitlab::Shell::Error, "error") end end - - describe '#delete_remote_branches' do - subject(:result) do - gitlab_shell.delete_remote_branches( - project.repository_storage_path, - project.disk_path, - 'downstream-remote', - ['master'] - ) - end - - it 'executes the command' do - expect(gitlab_projects).to receive(:delete_remote_branches) - .with('downstream-remote', ['master']) - .and_return(true) - - is_expected.to be_truthy - end - - it 'fails to execute the command' do - allow(gitlab_projects).to receive(:output) { 'error' } - expect(gitlab_projects).to receive(:delete_remote_branches) - .with('downstream-remote', ['master']) - .and_return(false) - - expect { result }.to raise_error(Gitlab::Shell::Error, 'error') - end - end end describe 'namespace actions' do -- cgit v1.2.1 From 996becdcbb3cd40f9620b704dea3fd9229081f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Mon, 18 Dec 2017 20:58:20 -0300 Subject: Move git operations for UpdateRemoteMirrorService into Gitlab::Git --- lib/gitlab/git/remote_mirror.rb | 75 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 lib/gitlab/git/remote_mirror.rb diff --git a/lib/gitlab/git/remote_mirror.rb b/lib/gitlab/git/remote_mirror.rb new file mode 100644 index 00000000000..38e9d2a8554 --- /dev/null +++ b/lib/gitlab/git/remote_mirror.rb @@ -0,0 +1,75 @@ +module Gitlab + module Git + class RemoteMirror + def initialize(repository, ref_name) + @repository = repository + @ref_name = ref_name + end + + def update(only_branches_matching: [], only_tags_matching: []) + local_branches = refs_obj(@repository.local_branches, only_refs_matching: only_branches_matching) + remote_branches = refs_obj(@repository.remote_branches(@ref_name), only_refs_matching: only_branches_matching) + + updated_branches = changed_refs(local_branches, remote_branches) + push_branches(updated_branches.keys) if updated_branches.present? + + delete_refs(local_branches, remote_branches) + + local_tags = refs_obj(@repository.tags, only_refs_matching: only_tags_matching) + remote_tags = refs_obj(@repository.remote_tags(@ref_name), only_refs_matching: only_tags_matching) + + updated_tags = changed_refs(local_tags, remote_tags) + @repository.push_remote_branches(@ref_name, updated_tags.keys) if updated_tags.present? + + delete_refs(local_tags, remote_tags) + end + + private + + def refs_obj(refs, only_refs_matching: []) + refs.each_with_object({}) do |ref, refs| + next if only_refs_matching.present? && !only_refs_matching.include?(ref.name) + + refs[ref.name] = ref + end + end + + def changed_refs(local_refs, remote_refs) + local_refs.select do |ref_name, ref| + remote_ref = remote_refs[ref_name] + + remote_ref.nil? || ref.dereferenced_target != remote_ref.dereferenced_target + end + end + + def push_branches(branches) + default_branch, branches = branches.partition do |branch| + @repository.root_ref == branch + end + + # Push the default branch first so it works fine when remote mirror is empty. + branches.unshift(*default_branch) + + @repository.push_remote_branches(@ref_name, branches) + end + + def delete_refs(local_refs, remote_refs) + refs = refs_to_delete(local_refs, remote_refs) + + @repository.delete_remote_branches(@ref_name, refs.keys) if refs.present? + end + + def refs_to_delete(local_refs, remote_refs) + default_branch_id = @repository.commit.id + + remote_refs.select do |remote_ref_name, remote_ref| + next false if local_refs[remote_ref_name] # skip if branch or tag exist in local repo + + remote_ref_id = remote_ref.dereferenced_target.try(:id) + + remote_ref_id && @repository.rugged_is_ancestor?(remote_ref_id, default_branch_id) + end + end + end + end +end -- cgit v1.2.1 From 57dc5a521bbdd94cc2eab34f22e2b6fac9e8bd55 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 17 Dec 2017 15:17:55 -0800 Subject: Avoid leaving a push event empty if payload cannot be created If the payload cannot be created for some reason, we could be left with a nil push event payload, which causes Error 500s when viewing the dashboard. Guard against this error and log when it happens. Avoids problems seen in #38823 --- .../unreleased/sh-validate-path-project-import.yml | 5 +++++ .../migrate_events_to_push_event_payloads.rb | 16 ++++++++-------- .../migrate_events_to_push_event_payloads_spec.rb | 14 ++++++++++++-- 3 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 changelogs/unreleased/sh-validate-path-project-import.yml diff --git a/changelogs/unreleased/sh-validate-path-project-import.yml b/changelogs/unreleased/sh-validate-path-project-import.yml new file mode 100644 index 00000000000..acad66c0ab2 --- /dev/null +++ b/changelogs/unreleased/sh-validate-path-project-import.yml @@ -0,0 +1,5 @@ +--- +title: Avoid leaving a push event empty if payload cannot be created +merge_request: +author: +type: fixed diff --git a/lib/gitlab/background_migration/migrate_events_to_push_event_payloads.rb b/lib/gitlab/background_migration/migrate_events_to_push_event_payloads.rb index 84ac00f1a5c..7088aa0860a 100644 --- a/lib/gitlab/background_migration/migrate_events_to_push_event_payloads.rb +++ b/lib/gitlab/background_migration/migrate_events_to_push_event_payloads.rb @@ -128,8 +128,14 @@ module Gitlab end def process_event(event) - replicate_event(event) - create_push_event_payload(event) if event.push_event? + ActiveRecord::Base.transaction do + replicate_event(event) + create_push_event_payload(event) if event.push_event? + end + rescue ActiveRecord::InvalidForeignKey => e + # A foreign key error means the associated event was removed. In this + # case we'll just skip migrating the event. + Rails.logger.error("Unable to migrate event #{event.id}: #{e}") end def replicate_event(event) @@ -137,9 +143,6 @@ module Gitlab .with_indifferent_access.except(:title, :data) EventForMigration.create!(new_attributes) - rescue ActiveRecord::InvalidForeignKey - # A foreign key error means the associated event was removed. In this - # case we'll just skip migrating the event. end def create_push_event_payload(event) @@ -156,9 +159,6 @@ module Gitlab ref: event.trimmed_ref_name, commit_title: event.commit_title ) - rescue ActiveRecord::InvalidForeignKey - # A foreign key error means the associated event was removed. In this - # case we'll just skip migrating the event. end def find_events(start_id, end_id) diff --git a/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb b/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb index 7351d45336a..5432d270555 100644 --- a/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb +++ b/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb @@ -281,6 +281,17 @@ describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads, :migrati migration.process_event(event) end + + it 'handles an error gracefully' do + event1 = create_push_event(project, author, { commits: [] }) + + expect(migration).to receive(:replicate_event).and_call_original + expect(migration).to receive(:create_push_event_payload).and_raise(ActiveRecord::InvalidForeignKey, 'invalid foreign key') + + migration.process_event(event1) + + expect(described_class::EventForMigration.all.count).to eq(0) + end end describe '#replicate_event' do @@ -335,9 +346,8 @@ describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads, :migrati it 'does not create push event payloads for removed events' do allow(event).to receive(:id).and_return(-1) - payload = migration.create_push_event_payload(event) + expect { migration.create_push_event_payload(event) }.to raise_error(ActiveRecord::InvalidForeignKey) - expect(payload).to be_nil expect(PushEventPayload.count).to eq(0) end -- cgit v1.2.1 From 9222900b5f528ad38299a7dac2b3fa92bdb858e4 Mon Sep 17 00:00:00 2001 From: Kushal Pandya Date: Wed, 3 Jan 2018 12:12:18 +0530 Subject: Fix groups list icon, timestamp alignment and row height --- app/assets/stylesheets/framework/lists.scss | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index 17915a55b45..f453fc2b547 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -450,6 +450,7 @@ ul.indent-list { } .stats { + position: relative; line-height: 46px; > span { @@ -459,20 +460,40 @@ ul.indent-list { min-width: 30px; } + > span:last-child { + margin-right: 0; + } + .stat-value { margin: 2px 0 0 5px; } } + + .controls { + margin-left: 5px; + + > .btn { + margin-right: $btn-xs-side-margin; + } + } } .project-row-contents .stats { line-height: inherit; - span:first-child { + > span:first-child { margin-left: 25px; } + .item-visibility { + margin-right: 0; + } + .last-updated { + position: absolute; + right: 12px; + min-width: 250px; + text-align: right; color: $gl-text-color-secondary; } } @@ -486,11 +507,11 @@ ul.indent-list { ul.group-list-tree { li.group-row { - .title { + > .group-row-contents .title { line-height: $list-text-height; } - &.has-description .title { + &.has-description > .group-row-contents .title { line-height: inherit; } } -- cgit v1.2.1 From 703aa9d23229c69c0d5d90869f979d318b17d028 Mon Sep 17 00:00:00 2001 From: Kushal Pandya Date: Thu, 4 Jan 2018 12:32:47 +0530 Subject: Make tooltip placement bottom by default as per design guidelines --- app/assets/javascripts/groups/components/group_item.vue | 2 +- app/assets/javascripts/groups/components/item_actions.vue | 2 ++ app/assets/javascripts/groups/components/item_stats_value.vue | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/groups/components/group_item.vue b/app/assets/javascripts/groups/components/group_item.vue index 583f14e6885..02129d39846 100644 --- a/app/assets/javascripts/groups/components/group_item.vue +++ b/app/assets/javascripts/groups/components/group_item.vue @@ -125,7 +125,7 @@ export default { :href="group.relativePath" :title="group.fullName" class="no-expand" - data-placement="top" + data-placement="bottom" >{{ // ending bracket must be by closing tag to prevent // link hover text-decoration from over-extending diff --git a/app/assets/javascripts/groups/components/item_actions.vue b/app/assets/javascripts/groups/components/item_actions.vue index d3817cae6dc..a685960d862 100644 --- a/app/assets/javascripts/groups/components/item_actions.vue +++ b/app/assets/javascripts/groups/components/item_actions.vue @@ -64,6 +64,7 @@ export default { :title="editBtnTitle" :aria-label="editBtnTitle" data-container="body" + data-placement="bottom" class="edit-group btn no-expand"> @@ -75,6 +76,7 @@ export default { :title="leaveBtnTitle" :aria-label="leaveBtnTitle" data-container="body" + data-placement="bottom" class="leave-group btn no-expand"> diff --git a/app/assets/javascripts/groups/components/item_stats_value.vue b/app/assets/javascripts/groups/components/item_stats_value.vue index 46402b304c5..f441cabf6d2 100644 --- a/app/assets/javascripts/groups/components/item_stats_value.vue +++ b/app/assets/javascripts/groups/components/item_stats_value.vue @@ -21,7 +21,7 @@ export default { tooltipPlacement: { type: String, required: false, - default: 'top', + default: 'bottom', }, /** * value could either be number or string -- cgit v1.2.1 From 7fbb5addaf7c15c971f584ebeecb2c93773093c0 Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Thu, 4 Jan 2018 09:31:06 +0000 Subject: Resolve "Resizable file list and commit panel" --- .../javascripts/ide/components/ide_context_bar.vue | 33 ++++++++ .../javascripts/ide/components/ide_side_bar.vue | 33 ++++++++ .../javascripts/ide/components/repo_editor.vue | 6 ++ app/assets/javascripts/ide/stores/actions.js | 4 + .../javascripts/ide/stores/mutation_types.js | 1 + app/assets/javascripts/ide/stores/mutations.js | 5 ++ app/assets/javascripts/ide/stores/state.js | 1 + .../vue_shared/components/panel_resizer.vue | 91 ++++++++++++++++++++++ app/assets/stylesheets/pages/repo.scss | 34 ++++++-- .../vue_shared/components/panel_resizer_spec.js | 59 ++++++++++++++ 10 files changed, 262 insertions(+), 5 deletions(-) create mode 100644 app/assets/javascripts/vue_shared/components/panel_resizer.vue create mode 100644 spec/javascripts/vue_shared/components/panel_resizer_spec.js diff --git a/app/assets/javascripts/ide/components/ide_context_bar.vue b/app/assets/javascripts/ide/components/ide_context_bar.vue index 5a08718e386..78c01272af6 100644 --- a/app/assets/javascripts/ide/components/ide_context_bar.vue +++ b/app/assets/javascripts/ide/components/ide_context_bar.vue @@ -2,11 +2,18 @@ import { mapGetters, mapState, mapActions } from 'vuex'; import repoCommitSection from './repo_commit_section.vue'; import icon from '../../vue_shared/components/icon.vue'; +import panelResizer from '../../vue_shared/components/panel_resizer.vue'; export default { + data() { + return { + width: 290, + }; + }, components: { repoCommitSection, icon, + panelResizer, }, computed: { ...mapState([ @@ -18,10 +25,20 @@ export default { currentIcon() { return this.rightPanelCollapsed ? 'angle-double-left' : 'angle-double-right'; }, + maxSize() { + return window.innerWidth / 2; + }, + panelStyle() { + if (!this.rightPanelCollapsed) { + return { width: `${this.width}px` }; + } + return {}; + }, }, methods: { ...mapActions([ 'setPanelCollapsedStatus', + 'setResizingStatus', ]), toggleCollapsed() { this.setPanelCollapsedStatus({ @@ -29,6 +46,12 @@ export default { collapsed: !this.rightPanelCollapsed, }); }, + resizingStarted() { + this.setResizingStatus(true); + }, + resizingEnded() { + this.setResizingStatus(false); + }, }, }; @@ -39,6 +62,7 @@ export default { :class="{ 'is-collapsed': rightPanelCollapsed, }" + :style="panelStyle" >
@@ -71,5 +95,14 @@ export default {
+ diff --git a/app/assets/javascripts/ide/components/ide_side_bar.vue b/app/assets/javascripts/ide/components/ide_side_bar.vue index 535398d98c2..269f300a04d 100644 --- a/app/assets/javascripts/ide/components/ide_side_bar.vue +++ b/app/assets/javascripts/ide/components/ide_side_bar.vue @@ -2,11 +2,18 @@ import { mapState, mapActions } from 'vuex'; import projectTree from './ide_project_tree.vue'; import icon from '../../vue_shared/components/icon.vue'; +import panelResizer from '../../vue_shared/components/panel_resizer.vue'; export default { + data() { + return { + width: 290, + }; + }, components: { projectTree, icon, + panelResizer, }, computed: { ...mapState([ @@ -16,10 +23,20 @@ export default { currentIcon() { return this.leftPanelCollapsed ? 'angle-double-right' : 'angle-double-left'; }, + maxSize() { + return window.innerWidth / 2; + }, + panelStyle() { + if (!this.leftPanelCollapsed) { + return { width: `${this.width}px` }; + } + return {}; + }, }, methods: { ...mapActions([ 'setPanelCollapsedStatus', + 'setResizingStatus', ]), toggleCollapsed() { this.setPanelCollapsedStatus({ @@ -27,6 +44,12 @@ export default { collapsed: !this.leftPanelCollapsed, }); }, + resizingStarted() { + this.setResizingStatus(true); + }, + resizingEnded() { + this.setResizingStatus(false); + }, }, }; @@ -37,6 +60,7 @@ export default { :class="{ 'is-collapsed': leftPanelCollapsed, }" + :style="panelStyle" >
Collapse sidebar +
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue index 221be4b9074..343fd0a5300 100644 --- a/app/assets/javascripts/ide/components/repo_editor.vue +++ b/app/assets/javascripts/ide/components/repo_editor.vue @@ -90,6 +90,11 @@ export default { rightPanelCollapsed() { this.editor.updateDimensions(); }, + panelResizing(isResizing) { + if (isResizing === false) { + this.editor.updateDimensions(); + } + }, }, computed: { ...mapGetters([ @@ -99,6 +104,7 @@ export default { ...mapState([ 'leftPanelCollapsed', 'rightPanelCollapsed', + 'panelResizing', ]), shouldHideEditor() { return this.activeFile.binary && !this.activeFile.raw; diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js index c01046c8c76..335882bb6d7 100644 --- a/app/assets/javascripts/ide/stores/actions.js +++ b/app/assets/javascripts/ide/stores/actions.js @@ -63,6 +63,10 @@ export const setPanelCollapsedStatus = ({ commit }, { side, collapsed }) => { } }; +export const setResizingStatus = ({ commit }, resizing) => { + commit(types.SET_RESIZING_STATUS, resizing); +}; + export const checkCommitStatus = ({ state }) => service .getBranchData(state.currentProjectId, state.currentBranchId) diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js index 4e3c10972ba..69b218a5e7d 100644 --- a/app/assets/javascripts/ide/stores/mutation_types.js +++ b/app/assets/javascripts/ide/stores/mutation_types.js @@ -5,6 +5,7 @@ export const SET_ROOT = 'SET_ROOT'; export const SET_LAST_COMMIT_DATA = 'SET_LAST_COMMIT_DATA'; export const SET_LEFT_PANEL_COLLAPSED = 'SET_LEFT_PANEL_COLLAPSED'; export const SET_RIGHT_PANEL_COLLAPSED = 'SET_RIGHT_PANEL_COLLAPSED'; +export const SET_RESIZING_STATUS = 'SET_RESIZING_STATUS'; // Project Mutation Types export const SET_PROJECT = 'SET_PROJECT'; diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js index 2fed9019cb6..03d81be10a1 100644 --- a/app/assets/javascripts/ide/stores/mutations.js +++ b/app/assets/javascripts/ide/stores/mutations.js @@ -49,6 +49,11 @@ export default { rightPanelCollapsed: collapsed, }); }, + [types.SET_RESIZING_STATUS](state, resizing) { + Object.assign(state, { + panelResizing: resizing, + }); + }, [types.SET_LAST_COMMIT_DATA](state, { entry, lastCommit }) { Object.assign(entry.lastCommit, { id: lastCommit.commit.id, diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js index 539e382830f..61d12096946 100644 --- a/app/assets/javascripts/ide/stores/state.js +++ b/app/assets/javascripts/ide/stores/state.js @@ -19,4 +19,5 @@ export default () => ({ projects: {}, leftPanelCollapsed: false, rightPanelCollapsed: true, + panelResizing: false, }); diff --git a/app/assets/javascripts/vue_shared/components/panel_resizer.vue b/app/assets/javascripts/vue_shared/components/panel_resizer.vue new file mode 100644 index 00000000000..4371534d345 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/panel_resizer.vue @@ -0,0 +1,91 @@ + + + diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss index 51cc1729d9a..d01cbadebcc 100644 --- a/app/assets/stylesheets/pages/repo.scss +++ b/app/assets/stylesheets/pages/repo.scss @@ -36,10 +36,6 @@ } } -.with-performance-bar .ide-view { - height: calc(100vh - #{$header-height}); -} - .ide-file-list { flex: 1; @@ -242,12 +238,13 @@ table.table tr td.multi-file-table-name { .multi-file-commit-panel { display: flex; + position: relative; flex-direction: column; height: 100%; width: 290px; padding: 0; background-color: $gray-light; - border-left: 1px solid $white-dark; + padding-right: 3px; .projects-sidebar { display: flex; @@ -496,3 +493,30 @@ table.table tr td.multi-file-table-name { margin-top: $header-height; margin-bottom: 0; } + +.with-performance-bar { + .ide-flash-container.flash-container { + margin-top: $header-height + $performance-bar-height; + } + + .ide-view { + height: calc(100vh - #{$header-height + $performance-bar-height}); + } +} + + +.dragHandle { + position: absolute; + top: 0; + bottom: 0; + width: 3px; + background-color: $white-dark; + + &.dragright { + right: 0; + } + + &.dragleft { + left: 0; + } +} diff --git a/spec/javascripts/vue_shared/components/panel_resizer_spec.js b/spec/javascripts/vue_shared/components/panel_resizer_spec.js new file mode 100644 index 00000000000..70ce3dffaba --- /dev/null +++ b/spec/javascripts/vue_shared/components/panel_resizer_spec.js @@ -0,0 +1,59 @@ +import Vue from 'vue'; +import panelResizer from '~/vue_shared/components/panel_resizer.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('Panel Resizer component', () => { + let vm; + let PanelResizer; + + const triggerEvent = (eventName, el = vm.$el, clientX = 0) => { + const event = document.createEvent('MouseEvents'); + event.initMouseEvent(eventName, true, true, window, 1, clientX, 0, clientX, 0, false, false, + false, false, 0, null); + + el.dispatchEvent(event); + }; + + beforeEach(() => { + PanelResizer = Vue.extend(panelResizer); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('should render a div element with the correct classes and styles', () => { + vm = mountComponent(PanelResizer, { + startSize: 100, + side: 'left', + }); + + expect(vm.$el.tagName).toEqual('DIV'); + expect(vm.$el.getAttribute('class')).toBe('dragHandle dragleft'); + expect(vm.$el.getAttribute('style')).toBe('cursor: ew-resize;'); + }); + + it('should render a div element with the correct classes for a right side panel', () => { + vm = mountComponent(PanelResizer, { + startSize: 100, + side: 'right', + }); + + expect(vm.$el.tagName).toEqual('DIV'); + expect(vm.$el.getAttribute('class')).toBe('dragHandle dragright'); + }); + + it('drag the resizer', () => { + vm = mountComponent(PanelResizer, { + startSize: 100, + side: 'left', + }); + + spyOn(vm, '$emit'); + triggerEvent('mousedown', vm.$el); + triggerEvent('mousemove', document); + triggerEvent('mouseup', document); + expect(vm.$emit.calls.allArgs()).toEqual([['resize-start', 100], ['update:size', 100], ['resize-end', 100]]); + expect(vm.size).toBe(100); + }); +}); -- cgit v1.2.1 From e028d795c484dcd1030b4f6bba8f53d4e677f0b3 Mon Sep 17 00:00:00 2001 From: Mayra Cabrera Date: Thu, 4 Jan 2018 09:33:51 +0000 Subject: 41054-Disallow creation of new Kubernetes integrations --- app/assets/stylesheets/pages/settings.scss | 4 + app/helpers/services_helper.rb | 11 +++ app/models/project_services/kubernetes_service.rb | 28 ++++++ app/models/service.rb | 8 ++ .../services/_deprecated_message.html.haml | 3 + app/views/projects/services/_form.html.haml | 5 +- app/views/projects/services/edit.html.haml | 2 + app/views/shared/_field.html.haml | 11 ++- app/views/shared/_service_settings.html.haml | 2 +- ...ble-creation-of-new-kubernetes-integrations.yml | 6 ++ .../projects/services_controller_spec.rb | 36 ++++++++ spec/factories/services.rb | 1 + .../projects/clusters/interchangeability_spec.rb | 2 +- .../project_services/kubernetes_service_spec.rb | 101 +++++++++++++++++++++ spec/models/service_spec.rb | 18 ++++ spec/requests/api/services_spec.rb | 8 +- spec/requests/api/v3/services_spec.rb | 4 + spec/support/services_shared_context.rb | 8 ++ 18 files changed, 244 insertions(+), 14 deletions(-) create mode 100644 app/views/projects/services/_deprecated_message.html.haml create mode 100644 changelogs/unreleased/41054-disable-creation-of-new-kubernetes-integrations.yml diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss index 5d630c7d61e..6353482ede7 100644 --- a/app/assets/stylesheets/pages/settings.scss +++ b/app/assets/stylesheets/pages/settings.scss @@ -268,3 +268,7 @@ margin: 0 0 5px 17px; } } + +.deprecated-service { + cursor: default; +} diff --git a/app/helpers/services_helper.rb b/app/helpers/services_helper.rb index 3707bb5ba36..240783bc7fd 100644 --- a/app/helpers/services_helper.rb +++ b/app/helpers/services_helper.rb @@ -27,5 +27,16 @@ module ServicesHelper "#{event}_events" end + def service_save_button(service) + button_tag(class: 'btn btn-save', type: 'submit', disabled: service.deprecated?) do + icon('spinner spin', class: 'hidden js-btn-spinner') + + content_tag(:span, 'Save changes', class: 'js-btn-label') + end + end + + def disable_fields_service?(service) + !current_controller?("admin/services") && service.deprecated? + end + extend self end diff --git a/app/models/project_services/kubernetes_service.rb b/app/models/project_services/kubernetes_service.rb index b82567ce2b3..c72b01b64af 100644 --- a/app/models/project_services/kubernetes_service.rb +++ b/app/models/project_services/kubernetes_service.rb @@ -31,6 +31,7 @@ class KubernetesService < DeploymentService before_validation :enforce_namespace_to_lower_case + validate :deprecation_validation, unless: :template? validates :namespace, allow_blank: true, length: 1..63, @@ -145,6 +146,17 @@ class KubernetesService < DeploymentService @kubeclient ||= build_kubeclient! end + def deprecated? + !active + end + + def deprecation_message + content = <<-MESSAGE.strip_heredoc + Kubernetes service integration has been deprecated. #{deprecated_message_content} your clusters using the new Clusters page + MESSAGE + content.html_safe + end + TEMPLATE_PLACEHOLDER = 'Kubernetes namespace'.freeze private @@ -226,4 +238,20 @@ class KubernetesService < DeploymentService def enforce_namespace_to_lower_case self.namespace = self.namespace&.downcase end + + def deprecation_validation + return if active_changed?(from: true, to: false) + + if deprecated? + errors[:base] << deprecation_message + end + end + + def deprecated_message_content + if active? + "Your cluster information on this page is still editable, but you are advised to disable and reconfigure" + else + "Fields on this page are now uneditable, you can configure" + end + end end diff --git a/app/models/service.rb b/app/models/service.rb index 3c4f1885dd0..176b472e724 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -263,6 +263,14 @@ class Service < ActiveRecord::Base service end + def deprecated? + false + end + + def deprecation_message + nil + end + private def cache_project_has_external_issue_tracker diff --git a/app/views/projects/services/_deprecated_message.html.haml b/app/views/projects/services/_deprecated_message.html.haml new file mode 100644 index 00000000000..fea9506a4bb --- /dev/null +++ b/app/views/projects/services/_deprecated_message.html.haml @@ -0,0 +1,3 @@ +.flash-container.flash-container-page + .flash-alert.deprecated-service + %span= @service.deprecation_message diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml index c0b1c62e8ef..21acd857ce7 100644 --- a/app/views/projects/services/_form.html.haml +++ b/app/views/projects/services/_form.html.haml @@ -13,10 +13,7 @@ = render 'shared/service_settings', form: form, subject: @service - if @service.editable? .footer-block.row-content-block - %button.btn.btn-save{ type: 'submit' } - = icon('spinner spin', class: 'hidden js-btn-spinner') - %span.js-btn-label - Save changes + = service_save_button(@service)   - if @service.valid? && @service.activated? - unless @service.can_test? diff --git a/app/views/projects/services/edit.html.haml b/app/views/projects/services/edit.html.haml index 25770df1c90..df1fd583670 100644 --- a/app/views/projects/services/edit.html.haml +++ b/app/views/projects/services/edit.html.haml @@ -2,4 +2,6 @@ - page_title @service.title, "Services" - add_to_breadcrumbs("Settings", edit_project_path(@project)) += render 'deprecated_message' if @service.deprecation_message + = render 'form' diff --git a/app/views/shared/_field.html.haml b/app/views/shared/_field.html.haml index 795447a9ca6..aea0a8fd8e0 100644 --- a/app/views/shared/_field.html.haml +++ b/app/views/shared/_field.html.haml @@ -7,6 +7,7 @@ - choices = field[:choices] - default_choice = field[:default_choice] - help = field[:help] +- disabled = disable_fields_service?(@service) .form-group - if type == "password" && value.present? @@ -15,14 +16,14 @@ = form.label name, title, class: "control-label" .col-sm-10 - if type == 'text' - = form.text_field name, class: "form-control", placeholder: placeholder, required: required + = form.text_field name, class: "form-control", placeholder: placeholder, required: required, disabled: disabled - elsif type == 'textarea' - = form.text_area name, rows: 5, class: "form-control", placeholder: placeholder, required: required + = form.text_area name, rows: 5, class: "form-control", placeholder: placeholder, required: required, disabled: disabled - elsif type == 'checkbox' - = form.check_box name + = form.check_box name, disabled: disabled - elsif type == 'select' - = form.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" } + = form.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control", disabled: disabled} - elsif type == 'password' - = form.password_field name, autocomplete: "new-password", class: "form-control", required: value.blank? && :required + = form.password_field name, autocomplete: "new-password", class: "form-control", required: value.blank? && required, disabled: disabled - if help %span.help-block= help diff --git a/app/views/shared/_service_settings.html.haml b/app/views/shared/_service_settings.html.haml index 7ca14ac93cc..61b39afb5d4 100644 --- a/app/views/shared/_service_settings.html.haml +++ b/app/views/shared/_service_settings.html.haml @@ -11,7 +11,7 @@ .form-group = form.label :active, "Active", class: "control-label" .col-sm-10 - = form.check_box :active + = form.check_box :active, disabled: disable_fields_service?(@service) - if @service.supported_events.present? .form-group diff --git a/changelogs/unreleased/41054-disable-creation-of-new-kubernetes-integrations.yml b/changelogs/unreleased/41054-disable-creation-of-new-kubernetes-integrations.yml new file mode 100644 index 00000000000..b960b14624c --- /dev/null +++ b/changelogs/unreleased/41054-disable-creation-of-new-kubernetes-integrations.yml @@ -0,0 +1,6 @@ +--- +title: Disable creation of new Kubernetes Integrations unless they're active or created + from template +merge_request: 41054 +author: +type: added diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb index 2c6ad00515e..847ac6f2be0 100644 --- a/spec/controllers/projects/services_controller_spec.rb +++ b/spec/controllers/projects/services_controller_spec.rb @@ -114,5 +114,41 @@ describe Projects::ServicesController do expect(flash[:notice]).to eq 'HipChat settings saved, but not activated.' end end + + context 'with a deprecated service' do + let(:service) { create(:kubernetes_service, project: project) } + + before do + put :update, + namespace_id: project.namespace, project_id: project, id: service.to_param, service: { namespace: 'updated_namespace' } + end + + it 'should not update the service' do + service.reload + expect(service.namespace).not_to eq('updated_namespace') + end + end + end + + describe "GET #edit" do + before do + get :edit, namespace_id: project.namespace, project_id: project, id: service_id + end + + context 'with approved services' do + let(:service_id) { 'jira' } + + it 'should render edit page' do + expect(response).to be_success + end + end + + context 'with a deprecated service' do + let(:service_id) { 'kubernetes' } + + it 'should render edit page' do + expect(response).to be_success + end + end end end diff --git a/spec/factories/services.rb b/spec/factories/services.rb index 4b0377967c7..110ef33c6f7 100644 --- a/spec/factories/services.rb +++ b/spec/factories/services.rb @@ -18,6 +18,7 @@ FactoryBot.define do factory :kubernetes_service do project + type 'KubernetesService' active true properties({ api_url: 'https://kubernetes.example.com', diff --git a/spec/features/projects/clusters/interchangeability_spec.rb b/spec/features/projects/clusters/interchangeability_spec.rb index 01f9526608f..3ddb35c755c 100644 --- a/spec/features/projects/clusters/interchangeability_spec.rb +++ b/spec/features/projects/clusters/interchangeability_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Interchangeability between KubernetesService and Platform::Kubernetes' do - EXCEPT_METHODS = %i[test title description help fields initialize_properties namespace namespace= api_url api_url=].freeze + EXCEPT_METHODS = %i[test title description help fields initialize_properties namespace namespace= api_url api_url= deprecated? deprecation_message].freeze EXCEPT_METHODS_GREP_V = %w[_touched? _changed? _was].freeze it 'Clusters::Platform::Kubernetes covers core interfaces in KubernetesService' do diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index f037ee77a94..6980ba335b8 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -52,12 +52,75 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do context 'when service is inactive' do before do + subject.project = project subject.active = false end it { is_expected.not_to validate_presence_of(:api_url) } it { is_expected.not_to validate_presence_of(:token) } end + + context 'with a deprecated service' do + let(:kubernetes_service) { create(:kubernetes_service) } + + before do + kubernetes_service.update_attribute(:active, false) + kubernetes_service.properties[:namespace] = "foo" + end + + it 'should not update attributes' do + expect(kubernetes_service.save).to be_falsy + end + + it 'should include an error with a deprecation message' do + kubernetes_service.valid? + expect(kubernetes_service.errors[:base].first).to match(/Kubernetes service integration has been deprecated/) + end + end + + context 'with a non-deprecated service' do + let(:kubernetes_service) { create(:kubernetes_service) } + + it 'should update attributes' do + kubernetes_service.properties[:namespace] = 'foo' + expect(kubernetes_service.save).to be_truthy + end + end + + context 'with an active and deprecated service' do + let(:kubernetes_service) { create(:kubernetes_service) } + + before do + kubernetes_service.active = false + kubernetes_service.properties[:namespace] = 'foo' + kubernetes_service.save + end + + it 'should deactive the service' do + expect(kubernetes_service.active?).to be_falsy + end + + it 'should not include a deprecation message as error' do + expect(kubernetes_service.errors.messages.count).to eq(0) + end + + it 'should update attributes' do + expect(kubernetes_service.properties[:namespace]).to eq("foo") + end + end + + context 'with a template service' do + let(:kubernetes_service) { create(:kubernetes_service, template: true, active: false) } + + before do + kubernetes_service.properties[:namespace] = 'foo' + end + + it 'should update attributes' do + expect(kubernetes_service.save).to be_truthy + expect(kubernetes_service.properties[:namespace]).to eq('foo') + end + end end describe '#initialize_properties' do @@ -318,4 +381,42 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do it { is_expected.to eq(pods: []) } end end + + describe "#deprecated?" do + let(:kubernetes_service) { create(:kubernetes_service) } + + context 'with an active kubernetes service' do + it 'should return false' do + expect(kubernetes_service.deprecated?).to be_falsy + end + end + + context 'with a inactive kubernetes service' do + it 'should return true' do + kubernetes_service.update_attribute(:active, false) + expect(kubernetes_service.deprecated?).to be_truthy + end + end + end + + describe "#deprecation_message" do + let(:kubernetes_service) { create(:kubernetes_service) } + + it 'should indicate the service is deprecated' do + expect(kubernetes_service.deprecation_message).to match(/Kubernetes service integration has been deprecated/) + end + + context 'if the services is active' do + it 'should return a message' do + expect(kubernetes_service.deprecation_message).to match(/Your cluster information on this page is still editable/) + end + end + + context 'if the service is not active' do + it 'should return a message' do + kubernetes_service.update_attribute(:active, false) + expect(kubernetes_service.deprecation_message).to match(/Fields on this page are now uneditable/) + end + end + end end diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index 0f2f906c667..540615de117 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -254,4 +254,22 @@ describe Service do end end end + + describe "#deprecated?" do + let(:project) { create(:project, :repository) } + + it 'should return false by default' do + service = create(:service, project: project) + expect(service.deprecated?).to be_falsy + end + end + + describe "#deprecation_message" do + let(:project) { create(:project, :repository) } + + it 'should be empty by default' do + service = create(:service, project: project) + expect(service.deprecation_message).to be_nil + end + end end diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb index ceafa0e2058..26d56c04862 100644 --- a/spec/requests/api/services_spec.rb +++ b/spec/requests/api/services_spec.rb @@ -53,6 +53,10 @@ describe API::Services do describe "DELETE /projects/:id/services/#{service.dasherize}" do include_context service + before do + initialize_service(service) + end + it "deletes #{service}" do delete api("/projects/#{project.id}/services/#{dashed_service}", user) @@ -67,9 +71,7 @@ describe API::Services do # inject some properties into the service before do - service_object = project.find_or_initialize_service(service) - service_object.properties = service_attrs - service_object.save + initialize_service(service) end it 'returns authentication error when unauthenticated' do diff --git a/spec/requests/api/v3/services_spec.rb b/spec/requests/api/v3/services_spec.rb index 8f212ab6be6..c69a7d58ca6 100644 --- a/spec/requests/api/v3/services_spec.rb +++ b/spec/requests/api/v3/services_spec.rb @@ -10,6 +10,10 @@ describe API::V3::Services do describe "DELETE /projects/:id/services/#{service.dasherize}" do include_context service + before do + initialize_service(service) + end + it "deletes #{service}" do delete v3_api("/projects/#{project.id}/services/#{dashed_service}", user) diff --git a/spec/support/services_shared_context.rb b/spec/support/services_shared_context.rb index 7457484a932..3f1fd169b72 100644 --- a/spec/support/services_shared_context.rb +++ b/spec/support/services_shared_context.rb @@ -29,5 +29,13 @@ Service.available_services_names.each do |service| end end end + + def initialize_service(service) + service_item = project.find_or_initialize_service(service) + service_item.properties = service_attrs + service_item.active = true if service == "kubernetes" + service_item.save + service_item + end end end -- cgit v1.2.1 From 20f79920e584f70218c78ce7a2c9c42328020031 Mon Sep 17 00:00:00 2001 From: Alessio Caiazza Date: Thu, 4 Jan 2018 10:29:16 +0100 Subject: Backport gitlab-org/gitlab-ci-yml!128 - Fix kubectl version to 1.8.6 This commit extracts `kubectl`, `helm` and `codeclimate` versions as CI variables. `kubectl` changes from latest stable version to `1.8.6`, the other two are just extracted in order to be easily updated; now we can also test tool upgrades overriding CI secret variables. --- changelogs/unreleased/ac-autodevopfix-kubectl-version.yml | 5 +++++ vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml | 12 ++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 changelogs/unreleased/ac-autodevopfix-kubectl-version.yml diff --git a/changelogs/unreleased/ac-autodevopfix-kubectl-version.yml b/changelogs/unreleased/ac-autodevopfix-kubectl-version.yml new file mode 100644 index 00000000000..0ceeb7ccee1 --- /dev/null +++ b/changelogs/unreleased/ac-autodevopfix-kubectl-version.yml @@ -0,0 +1,5 @@ +--- +title: Force Auto DevOps kubectl version to 1.8.6 +merge_request: 16218 +author: +type: fixed diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml index 18910a46d11..06473fba8e1 100644 --- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml +++ b/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml @@ -34,6 +34,10 @@ variables: POSTGRES_ENABLED: "true" POSTGRES_DB: $CI_ENVIRONMENT_SLUG + KUBERNETES_VERSION: 1.8.6 + HELM_VERSION: 2.6.1 + CODECLIMATE_VERSION: 0.69.0 + stages: - build - test @@ -250,8 +254,8 @@ production: --volume /var/run/docker.sock:/var/run/docker.sock \ --volume /tmp/cc:/tmp/cc" - docker run ${cc_opts} codeclimate/codeclimate:0.69.0 init - docker run ${cc_opts} codeclimate/codeclimate:0.69.0 analyze -f json > codeclimate.json + docker run ${cc_opts} "codeclimate/codeclimate:${CODECLIMATE_VERSION}" init + docker run ${cc_opts} "codeclimate/codeclimate:${CODECLIMATE_VERSION}" analyze -f json > codeclimate.json } function sast() { @@ -323,11 +327,11 @@ production: apk add glibc-2.23-r3.apk rm glibc-2.23-r3.apk - curl https://kubernetes-helm.storage.googleapis.com/helm-v2.6.1-linux-amd64.tar.gz | tar zx + curl "https://kubernetes-helm.storage.googleapis.com/helm-v${HELM_VERSION}-linux-amd64.tar.gz" | tar zx mv linux-amd64/helm /usr/bin/ helm version --client - curl -L -o /usr/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl + curl -L -o /usr/bin/kubectl "https://storage.googleapis.com/kubernetes-release/release/v${KUBERNETES_VERSION}/bin/linux/amd64/kubectl" chmod +x /usr/bin/kubectl kubectl version --client } -- cgit v1.2.1 From 260935868acfb7c0cb720088d4f8c4c1c1088ddb Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 14 Dec 2017 11:49:35 +0100 Subject: add new git fsck rake task and spec --- lib/tasks/gitlab/git.rake | 10 ++++++++++ spec/tasks/gitlab/git_rake_spec.rb | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 spec/tasks/gitlab/git_rake_spec.rb diff --git a/lib/tasks/gitlab/git.rake b/lib/tasks/gitlab/git.rake index cf82134d97e..f3ffff43726 100644 --- a/lib/tasks/gitlab/git.rake +++ b/lib/tasks/gitlab/git.rake @@ -30,6 +30,16 @@ namespace :gitlab do end end + desc 'GitLab | Git | Check all repos integrity' + task fsck: :environment do + failures = perform_git_cmd(%W(#{Gitlab.config.git.bin_path} fsck --name-objects --no-progress), "Checking integrity") + if failures.empty? + puts "Done".color(:green) + else + output_failures(failures) + end + end + def perform_git_cmd(cmd, message) puts "Starting #{message} on all repositories" diff --git a/spec/tasks/gitlab/git_rake_spec.rb b/spec/tasks/gitlab/git_rake_spec.rb new file mode 100644 index 00000000000..63a7f7efe73 --- /dev/null +++ b/spec/tasks/gitlab/git_rake_spec.rb @@ -0,0 +1,27 @@ +require 'rake_helper' + +describe 'gitlab:git rake tasks' do + before do + Rake.application.rake_require 'tasks/gitlab/git' + + stub_warn_user_is_not_gitlab + + FileUtils.mkdir(Settings.absolute('tmp/tests/default_storage')) + end + + after do + FileUtils.rm_rf(Settings.absolute('tmp/tests/default_storage')) + end + + describe 'fsck' do + let(:storages) do + { 'default' => { 'path' => Settings.absolute('tmp/tests/default_storage') } } + end + + it 'outputs the right git command' do + expect(Kernel).to receive(:system).with('').and_return(true) + + run_rake_task('gitlab:git:fsck') + end + end +end -- cgit v1.2.1 From 7721e8dfca9d272376f58dcb03ff277aef0a9c31 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 14 Dec 2017 14:53:34 +0100 Subject: fix spec --- spec/tasks/gitlab/git_rake_spec.rb | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/spec/tasks/gitlab/git_rake_spec.rb b/spec/tasks/gitlab/git_rake_spec.rb index 63a7f7efe73..60b51186ceb 100644 --- a/spec/tasks/gitlab/git_rake_spec.rb +++ b/spec/tasks/gitlab/git_rake_spec.rb @@ -4,9 +4,11 @@ describe 'gitlab:git rake tasks' do before do Rake.application.rake_require 'tasks/gitlab/git' - stub_warn_user_is_not_gitlab + storages = { 'default' => { 'path' => Settings.absolute('tmp/tests/default_storage') } } - FileUtils.mkdir(Settings.absolute('tmp/tests/default_storage')) + FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/repo/test.git')) + allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + stub_warn_user_is_not_gitlab end after do @@ -14,14 +16,8 @@ describe 'gitlab:git rake tasks' do end describe 'fsck' do - let(:storages) do - { 'default' => { 'path' => Settings.absolute('tmp/tests/default_storage') } } - end - it 'outputs the right git command' do - expect(Kernel).to receive(:system).with('').and_return(true) - - run_rake_task('gitlab:git:fsck') + expect { run_rake_task('gitlab:git:fsck') }.to output(/Performed Checking integrity/).to_stdout end end end -- cgit v1.2.1 From bc46c822fc94cfa54a190cfb0e89afeae799f57a Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 21 Dec 2017 15:42:25 +0100 Subject: remove max-depth flag so it works with subgroups --- lib/tasks/gitlab/task_helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/gitlab/task_helpers.rb b/lib/tasks/gitlab/task_helpers.rb index 6723662703c..c1182af1014 100644 --- a/lib/tasks/gitlab/task_helpers.rb +++ b/lib/tasks/gitlab/task_helpers.rb @@ -130,7 +130,7 @@ module Gitlab def all_repos Gitlab.config.repositories.storages.each_value do |repository_storage| - IO.popen(%W(find #{repository_storage['path']} -mindepth 2 -maxdepth 2 -type d -name *.git)) do |find| + IO.popen(%W(find #{repository_storage['path']} -mindepth 2 -type d -name *.git)) do |find| find.each_line do |path| yield path.chomp end -- cgit v1.2.1 From f8e1b44dc5d2a78676672dfc7d44c17e6defeda6 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 3 Jan 2018 14:51:04 +0100 Subject: add locks chek --- lib/tasks/gitlab/git.rake | 26 +++++++++++++++++++++++++- spec/tasks/gitlab/git_rake_spec.rb | 4 +++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/tasks/gitlab/git.rake b/lib/tasks/gitlab/git.rake index f3ffff43726..5c1b19860f0 100644 --- a/lib/tasks/gitlab/git.rake +++ b/lib/tasks/gitlab/git.rake @@ -32,7 +32,10 @@ namespace :gitlab do desc 'GitLab | Git | Check all repos integrity' task fsck: :environment do - failures = perform_git_cmd(%W(#{Gitlab.config.git.bin_path} fsck --name-objects --no-progress), "Checking integrity") + failures = perform_git_cmd(%W(#{Gitlab.config.git.bin_path} fsck --name-objects --no-progress), "Checking integrity") do |repo| + check_config_lock(repo) + check_ref_locks(repo) + end if failures.empty? puts "Done".color(:green) else @@ -50,6 +53,8 @@ namespace :gitlab do else failures << repo end + + yield(repo) if block_given? end failures @@ -59,5 +64,24 @@ namespace :gitlab do puts "The following repositories reported errors:".color(:red) failures.each { |f| puts "- #{f}" } end + + def check_config_lock(repo_dir) + config_exists = File.exist?(File.join(repo_dir, 'config.lock')) + config_output = config_exists ? 'yes'.color(:red) : 'no'.color(:green) + + puts "'config.lock' file exists?".color(:yellow) + " ... #{config_output}" + end + + def check_ref_locks(repo_dir) + lock_files = Dir.glob(File.join(repo_dir, 'refs/heads/*.lock')) + + if lock_files.present? + puts "Ref lock files exist:".color(:red) + + lock_files.each { |lock_file| puts " #{lock_file}" } + else + puts "No ref lock files exist".color(:green) + end + end end end diff --git a/spec/tasks/gitlab/git_rake_spec.rb b/spec/tasks/gitlab/git_rake_spec.rb index 60b51186ceb..19d298fb36d 100644 --- a/spec/tasks/gitlab/git_rake_spec.rb +++ b/spec/tasks/gitlab/git_rake_spec.rb @@ -1,3 +1,5 @@ + + require 'rake_helper' describe 'gitlab:git rake tasks' do @@ -6,7 +8,7 @@ describe 'gitlab:git rake tasks' do storages = { 'default' => { 'path' => Settings.absolute('tmp/tests/default_storage') } } - FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/repo/test.git')) + FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git')) allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) stub_warn_user_is_not_gitlab end -- cgit v1.2.1 From 5b9e7773766eebbe73bb400025de002962532a7c Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 3 Jan 2018 15:32:16 +0100 Subject: add lock specs --- spec/tasks/gitlab/git_rake_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/spec/tasks/gitlab/git_rake_spec.rb b/spec/tasks/gitlab/git_rake_spec.rb index 19d298fb36d..44a2607bea2 100644 --- a/spec/tasks/gitlab/git_rake_spec.rb +++ b/spec/tasks/gitlab/git_rake_spec.rb @@ -21,5 +21,18 @@ describe 'gitlab:git rake tasks' do it 'outputs the right git command' do expect { run_rake_task('gitlab:git:fsck') }.to output(/Performed Checking integrity/).to_stdout end + + it 'errors out about config.lock issues' do + FileUtils.touch(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git/config.lock')) + + expect { run_rake_task('gitlab:git:fsck') }.to output(/file exists\? ... yes/).to_stdout + end + + it 'errors out about ref lock issues' do + FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git/refs/heads')) + FileUtils.touch(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git/refs/heads/blah.lock')) + + expect { run_rake_task('gitlab:git:fsck') }.to output(/Ref lock files exist:/).to_stdout + end end end -- cgit v1.2.1 From 6ee122c04ee8263dc1cb9dfddd010c5c0b587e8e Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 3 Jan 2018 16:11:17 +0100 Subject: deprecate check integrity task --- lib/tasks/gitlab/check.rake | 41 ++--------------------------------------- 1 file changed, 2 insertions(+), 39 deletions(-) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index dfade1f3885..903e84359cd 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -387,14 +387,8 @@ namespace :gitlab do namespace :repo do desc "GitLab | Check the integrity of the repositories managed by GitLab" task check: :environment do - Gitlab.config.repositories.storages.each do |name, repository_storage| - namespace_dirs = Dir.glob(File.join(repository_storage['path'], '*')) - - namespace_dirs.each do |namespace_dir| - repo_dirs = Dir.glob(File.join(namespace_dir, '*')) - repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) } - end - end + puts "This task is deprecated. Please use gitlab:git:fsck instead".color(:red) + Rake::Task["gitlab:git:fsck"].execute end end @@ -461,35 +455,4 @@ namespace :gitlab do puts "FAIL. Please update gitlab-shell to #{required_version} from #{current_version}".color(:red) end end - - def check_repo_integrity(repo_dir) - puts "\nChecking repo at #{repo_dir.color(:yellow)}" - - git_fsck(repo_dir) - check_config_lock(repo_dir) - check_ref_locks(repo_dir) - end - - def git_fsck(repo_dir) - puts "Running `git fsck`".color(:yellow) - system(*%W(#{Gitlab.config.git.bin_path} fsck), chdir: repo_dir) - end - - def check_config_lock(repo_dir) - config_exists = File.exist?(File.join(repo_dir, 'config.lock')) - config_output = config_exists ? 'yes'.color(:red) : 'no'.color(:green) - puts "'config.lock' file exists?".color(:yellow) + " ... #{config_output}" - end - - def check_ref_locks(repo_dir) - lock_files = Dir.glob(File.join(repo_dir, 'refs/heads/*.lock')) - if lock_files.present? - puts "Ref lock files exist:".color(:red) - lock_files.each do |lock_file| - puts " #{lock_file}" - end - else - puts "No ref lock files exist".color(:green) - end - end end -- cgit v1.2.1 From de36a8e27961d4c2af43d0ac2d700a391c245353 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 4 Jan 2018 11:02:43 +0100 Subject: refactor spec, add docs --- doc/administration/raketasks/check.md | 4 ++-- lib/tasks/gitlab/git.rake | 1 + spec/tasks/gitlab/git_rake_spec.rb | 16 ++++++++-------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/doc/administration/raketasks/check.md b/doc/administration/raketasks/check.md index c8b5434c068..7dabc014bad 100644 --- a/doc/administration/raketasks/check.md +++ b/doc/administration/raketasks/check.md @@ -34,13 +34,13 @@ This task loops through all repositories on the GitLab server and runs the **Omnibus Installation** ``` -sudo gitlab-rake gitlab:repo:check +sudo gitlab-rake gitlab:git:fsck ``` **Source Installation** ```bash -sudo -u git -H bundle exec rake gitlab:repo:check RAILS_ENV=production +sudo -u git -H bundle exec rake gitlab:git:fsck RAILS_ENV=production ``` ### Check repositories for a specific user diff --git a/lib/tasks/gitlab/git.rake b/lib/tasks/gitlab/git.rake index 5c1b19860f0..3f5dd2ae3b3 100644 --- a/lib/tasks/gitlab/git.rake +++ b/lib/tasks/gitlab/git.rake @@ -36,6 +36,7 @@ namespace :gitlab do check_config_lock(repo) check_ref_locks(repo) end + if failures.empty? puts "Done".color(:green) else diff --git a/spec/tasks/gitlab/git_rake_spec.rb b/spec/tasks/gitlab/git_rake_spec.rb index 44a2607bea2..dacc5dc5ae7 100644 --- a/spec/tasks/gitlab/git_rake_spec.rb +++ b/spec/tasks/gitlab/git_rake_spec.rb @@ -1,5 +1,3 @@ - - require 'rake_helper' describe 'gitlab:git rake tasks' do @@ -8,8 +6,10 @@ describe 'gitlab:git rake tasks' do storages = { 'default' => { 'path' => Settings.absolute('tmp/tests/default_storage') } } - FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git')) + FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/@hashed/1/2/test.git')) allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) + allow_any_instance_of(String).to receive(:color) { |string, _color| string } + stub_warn_user_is_not_gitlab end @@ -18,19 +18,19 @@ describe 'gitlab:git rake tasks' do end describe 'fsck' do - it 'outputs the right git command' do - expect { run_rake_task('gitlab:git:fsck') }.to output(/Performed Checking integrity/).to_stdout + it 'outputs the integrity check for a repo' do + expect { run_rake_task('gitlab:git:fsck') }.to output(/Performed Checking integrity at .*@hashed\/1\/2\/test.git/).to_stdout end it 'errors out about config.lock issues' do - FileUtils.touch(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git/config.lock')) + FileUtils.touch(Settings.absolute('tmp/tests/default_storage/@hashed/1/2/test.git/config.lock')) expect { run_rake_task('gitlab:git:fsck') }.to output(/file exists\? ... yes/).to_stdout end it 'errors out about ref lock issues' do - FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git/refs/heads')) - FileUtils.touch(Settings.absolute('tmp/tests/default_storage/@repo/1/2/test.git/refs/heads/blah.lock')) + FileUtils.mkdir_p(Settings.absolute('tmp/tests/default_storage/@hashed/1/2/test.git/refs/heads')) + FileUtils.touch(Settings.absolute('tmp/tests/default_storage/@hashed/1/2/test.git/refs/heads/blah.lock')) expect { run_rake_task('gitlab:git:fsck') }.to output(/Ref lock files exist:/).to_stdout end -- cgit v1.2.1 From 21d0a3a6c4ee78724e084f355da9e40c4243b036 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Thu, 4 Jan 2018 11:19:11 +0100 Subject: add missing changelog --- changelogs/unreleased/40228-verify-integrity-of-repositories.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/40228-verify-integrity-of-repositories.yml diff --git a/changelogs/unreleased/40228-verify-integrity-of-repositories.yml b/changelogs/unreleased/40228-verify-integrity-of-repositories.yml new file mode 100644 index 00000000000..261d48652db --- /dev/null +++ b/changelogs/unreleased/40228-verify-integrity-of-repositories.yml @@ -0,0 +1,5 @@ +--- +title: Fix gitlab-rake gitlab:import:repos import schedule +merge_request: 15931 +author: +type: fixed -- cgit v1.2.1 From 3b8cee95a7d62bce3b3890ff8618073958dc2fb0 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 4 Jan 2018 11:28:18 +0100 Subject: Fix cycle analytics specs --- spec/lib/gitlab/cycle_analytics/events_spec.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/spec/lib/gitlab/cycle_analytics/events_spec.rb b/spec/lib/gitlab/cycle_analytics/events_spec.rb index 28ea7d4c303..38a47a159e1 100644 --- a/spec/lib/gitlab/cycle_analytics/events_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/events_spec.rb @@ -122,17 +122,18 @@ describe 'cycle analytics events' do let(:stage) { :test } let(:merge_request) { MergeRequest.first } + let!(:pipeline) do create(:ci_pipeline, ref: merge_request.source_branch, sha: merge_request.diff_head_sha, - project: context.project, + project: project, head_pipeline_of: merge_request) end before do - create(:ci_build, pipeline: pipeline, status: :success, author: user) - create(:ci_build, pipeline: pipeline, status: :success, author: user) + create(:ci_build, :success, pipeline: pipeline, author: user) + create(:ci_build, :success, pipeline: pipeline, author: user) pipeline.run! pipeline.succeed! @@ -219,17 +220,18 @@ describe 'cycle analytics events' do describe '#staging_events' do let(:stage) { :staging } let(:merge_request) { MergeRequest.first } + let!(:pipeline) do create(:ci_pipeline, ref: merge_request.source_branch, sha: merge_request.diff_head_sha, - project: context.project, + project: project, head_pipeline_of: merge_request) end before do - create(:ci_build, pipeline: pipeline, status: :success, author: user) - create(:ci_build, pipeline: pipeline, status: :success, author: user) + create(:ci_build, :success, pipeline: pipeline, author: user) + create(:ci_build, :success, pipeline: pipeline, author: user) pipeline.run! pipeline.succeed! -- cgit v1.2.1 From 55137e200d9f9f8cdbdadc96cf098a088873e3f1 Mon Sep 17 00:00:00 2001 From: Joshua Lambert Date: Thu, 4 Jan 2018 10:59:08 +0000 Subject: Include integration tests in CE/EE testing documentation --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 01d4a546b97..2b79f0825e2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -553,7 +553,7 @@ the feature you contribute through all of these steps. 1. Description explaining the relevancy (see following item) 1. Working and clean code that is commented where needed -1. [Unit and system tests][testing] that pass on the CI server +1. [Unit, integration, and system tests][testing] that pass on the CI server 1. Performance/scalability implications have been considered, addressed, and tested 1. [Documented][doc-styleguide] in the `/doc` directory 1. [Changelog entry added][changelog], if necessary -- cgit v1.2.1 From e8acb3f11755811fca28d38bb0cbba44add7b0af Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 4 Jan 2018 12:09:14 +0100 Subject: Copy-edit end-to-end testing guide documentation --- doc/development/testing_guide/end_to_end_tests.md | 34 ++++++++++++----------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/doc/development/testing_guide/end_to_end_tests.md b/doc/development/testing_guide/end_to_end_tests.md index 561547e1581..30efe3e3b76 100644 --- a/doc/development/testing_guide/end_to_end_tests.md +++ b/doc/development/testing_guide/end_to_end_tests.md @@ -23,24 +23,25 @@ You can find these nightly pipelines at [GitLab QA pipelines page][gitlab-qa-pip It is also possible to trigger build of GitLab packages and then pass these package to GitLab QA to run tests in a [pipeline][gitlab-qa-pipelines]. -Developers can trigger a `package-qa` manual action, that should be present in -the merge request widget in your merge request. +Developers can trigger the `package-qa` manual action, that should be present in +the merge request widget. -It is possible to trigger Gitlab QA pipeline from merge requests in GitLab CE -and GitLab EE, but QA triggering manual action is also available in the Omnibus -GitLab project as well. +It is also possible to trigger Gitlab QA pipeline from merge requests in +Omnibus GitLab project. You can find a manual action that is similar to +`package-qa`, mentioned above, in your Omnibus-related merge requests as well. Below you can read more about how to use it and how does it work. #### How does it work? -Currently, we are _multi-project pipeline_-like approach to run QA pipelines. +Currently, we are using _multi-project pipeline_-like approach to run QA +pipelines. 1. Developer triggers a manual action, that can be found in CE and EE merge -requests, what starts a chain of pipelines. +requests. This starts a chain of pipelines in multiple projects. -1. The script, that is being executed, triggers a pipeline in GitLab Omnibus -projects, and waits for the resulting status. We call this a _status attribution_. +1. The script being executed triggers a pipeline in GitLab Omnibus and waits +for the resulting status. We call this a _status attribution_. 1. GitLab packages are being built in Omnibus pipeline. Packages are going to be pushed to Container Registry. @@ -50,24 +51,25 @@ pipeline, that is now running in Omnibus, triggers a new pipeline in the GitLab QA project. It also waits for a resulting status. 1. GitLab QA pulls images from the registry, spins-up containers and runs tests -against a test environment that has been just orchestrated by `gitlab-qa` tool. +against a test environment that has been just orchestrated by the `gitlab-qa` +tool. -1. The result of GitLab QA pipeline is being propagated upstream, through +1. The result of the GitLab QA pipeline is being propagated upstream, through Omnibus, back to CE / EE merge request. #### How do I write tests? In order to write new tests, you first need to learn more about GitLab QA -architecture. There is some documentation about it in GitLab QA project -[here][gitlab-qa-architecture]. +architecture. See the [documentation about it][gitlab-qa-architecture] in +GitLab QA project. -Once you decided were to put test environment orchestration scenarios and -instance specs, take a looks at [relevant documentation][instance-qa-readme] +Once you decided where to put test environment orchestration scenarios and +instance specs, take a look at the [relevant documentation][instance-qa-readme] and examples in [the `qa/` directory][instance-qa-examples]. ## Where can I ask for help? -You can ask question in `#qa` channel on Slack (GitLab internal) or you can +You can ask question in the `#qa` channel on Slack (GitLab internal) or you can find an issue you would like to work on in [the issue tracker][gitlab-qa-issues] and start a new discussion there. -- cgit v1.2.1 From 0ba0f9de08eb3d5113f4557b925506167484950a Mon Sep 17 00:00:00 2001 From: Ahmad Sherif Date: Wed, 3 Jan 2018 13:31:06 +0100 Subject: Prepare Gitlab::Git::Repository#rebase for Gitaly migration --- lib/gitlab/git/operation_service.rb | 5 +++++ lib/gitlab/git/repository.rb | 9 ++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/git/operation_service.rb b/lib/gitlab/git/operation_service.rb index ef5bdbaf819..3fb0e2eed93 100644 --- a/lib/gitlab/git/operation_service.rb +++ b/lib/gitlab/git/operation_service.rb @@ -97,6 +97,11 @@ module Gitlab end end + def update_branch(branch_name, newrev, oldrev) + ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name + update_ref_in_hooks(ref, newrev, oldrev) + end + private # Returns [newrev, should_run_after_create, should_run_after_create_branch] diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 176bd953ca1..7c6349f4e84 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -1212,9 +1212,16 @@ module Gitlab rebase_path = worktree_path(REBASE_WORKTREE_PREFIX, rebase_id) env = git_env_for_user(user) + if remote_repository.is_a?(RemoteRepository) + env.merge!(remote_repository.fetch_env) + remote_repo_path = GITALY_INTERNAL_URL + else + remote_repo_path = remote_repository.path + end + with_worktree(rebase_path, branch, env: env) do run_git!( - %W(pull --rebase #{remote_repository.path} #{remote_branch}), + %W(pull --rebase #{remote_repo_path} #{remote_branch}), chdir: rebase_path, env: env ) -- cgit v1.2.1 From 88cc49fa17d212e087f6e8a5aec0b2a680cec6e3 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 4 Jan 2018 13:00:02 +0100 Subject: Add test for restoring associations with import/export --- spec/lib/gitlab/import_export/project.json | 26 ++++++++++++++++++++-- .../import_export/project_tree_restorer_spec.rb | 12 ++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json index f0752649121..6778b23ee7f 100644 --- a/spec/lib/gitlab/import_export/project.json +++ b/spec/lib/gitlab/import_export/project.json @@ -6465,6 +6465,26 @@ } } ], + "stages": [ + { + "id": 11, + "project_id": 5, + "pipeline_id": 36, + "name": "test", + "status": 1, + "created_at": "2016-03-22T15:44:44.772Z", + "updated_at": "2016-03-29T06:44:44.634Z" + }, + { + "id": 12, + "project_id": 5, + "pipeline_id": 36, + "name": "deploy", + "status": 2, + "created_at": "2016-03-22T15:45:45.772Z", + "updated_at": "2016-03-29T06:45:45.634Z" + } + ], "statuses": [ { "id": 71, @@ -6487,6 +6507,7 @@ "stage": "test", "trigger_request_id": null, "stage_idx": 1, + "stage_id": 11, "tag": null, "ref": "master", "user_id": null, @@ -6515,15 +6536,16 @@ "runner_id": null, "coverage": null, "commit_id": 36, - "commands": "$ build command", + "commands": "$ deploy command", "job_id": null, "name": "test build 2", "deploy": false, "options": null, "allow_failure": false, - "stage": "test", + "stage": "deploy", "trigger_request_id": null, "stage_idx": 1, + "stage_id": 12, "tag": null, "ref": "master", "user_id": null, 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 0ab3afd0074..d4342f2b1a8 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -179,6 +179,18 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do end end end + + context 'when restoring hierarchy of pipeline, stages and jobs' do + let(:pipeline) { Ci::Pipeline.first } + + it 'restores pipeline stages' do + expect(pipeline.stages.count).to be 2 + end + + it 'correctly restores association between a stage and a job' do + expect(pipeline.statuses).to all(have_attributes(stage_id: a_value > 10)) + end + end end end -- cgit v1.2.1 From 099a59e8fd461a01b1b4f84583b46b4c7d6888e9 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 4 Jan 2018 13:11:24 +0100 Subject: Check if stage_id relation has been assigned only --- spec/lib/gitlab/import_export/project_tree_restorer_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 d4342f2b1a8..70a6d1a3c6a 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -188,7 +188,7 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do end it 'correctly restores association between a stage and a job' do - expect(pipeline.statuses).to all(have_attributes(stage_id: a_value > 10)) + expect(pipeline.statuses).to all(have_attributes(stage_id: a_value > 0)) end end end -- cgit v1.2.1 From ebdcbd4552b16b8aacaaaf0bdc1c600685d4e696 Mon Sep 17 00:00:00 2001 From: Alessio Caiazza Date: Wed, 3 Jan 2018 09:57:48 +0100 Subject: Do not run ee_compat_check on security branches Branches started from `security-X-Y` will likely fail on `ee_compat_check`, the check tries to merge against EE `master` which may likely fail for MR that are not targetted on `master`, like security fixes. This commit disables `ee_compat_check` on branches starting with `security-`. --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e98ac200332..038eeb2bf61 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -431,6 +431,7 @@ ee_compat_check: - master - tags - /^[\d-]+-stable(-ee)?/ + - /^security-/ - branches@gitlab-org/gitlab-ee - branches@gitlab/gitlab-ee retry: 0 -- cgit v1.2.1 From dac51ace521d7b2b2a5a5bb19167a8690ead242e Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 3 Jan 2018 17:44:29 +0100 Subject: Eager load event target authors whenever possible This ensures that the "author" association of an event's "target" association is eager loaded whenever the "target" association defines an "author" association. This in turn solves the N+1 query problem we first tried to solve in https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15788 but caused problems when displaying milestones as those don't define an "author" association. The approach in this commit does mean that the authors are _always_ eager loaded since this takes place in the "belongs_to" block. This however shouldn't pose too much of a problem, and as far as I can tell there's no real way around this unfortunately. --- app/models/event.rb | 13 ++++++++++++- .../conditionally-eager-load-event-target-authors.yml | 5 +++++ spec/features/dashboard/activity_spec.rb | 7 +++++++ spec/models/event_spec.rb | 16 ++++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/conditionally-eager-load-event-target-authors.yml diff --git a/app/models/event.rb b/app/models/event.rb index 0997b056c6a..8a79100de5a 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -48,7 +48,18 @@ class Event < ActiveRecord::Base belongs_to :author, class_name: "User" belongs_to :project - belongs_to :target, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations + + belongs_to :target, -> { + # If the association for "target" defines an "author" association we want to + # eager-load this so Banzai & friends don't end up performing N+1 queries to + # get the authors of notes, issues, etc. + if reflections['events'].active_record.reflect_on_association(:author) + includes(:author) + else + self + end + }, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations + has_one :push_event_payload # Callbacks diff --git a/changelogs/unreleased/conditionally-eager-load-event-target-authors.yml b/changelogs/unreleased/conditionally-eager-load-event-target-authors.yml new file mode 100644 index 00000000000..a5f1a958fa8 --- /dev/null +++ b/changelogs/unreleased/conditionally-eager-load-event-target-authors.yml @@ -0,0 +1,5 @@ +--- +title: Eager load event target authors whenever possible +merge_request: +author: +type: performance diff --git a/spec/features/dashboard/activity_spec.rb b/spec/features/dashboard/activity_spec.rb index bd115785646..a74a8aac2b2 100644 --- a/spec/features/dashboard/activity_spec.rb +++ b/spec/features/dashboard/activity_spec.rb @@ -24,6 +24,7 @@ feature 'Dashboard > Activity' do end let(:note) { create(:note, project: project, noteable: merge_request) } + let(:milestone) { create(:milestone, :active, project: project, title: '1.0') } let!(:push_event) do event = create(:push_event, project: project, author: user) @@ -54,6 +55,10 @@ feature 'Dashboard > Activity' do create(:event, :commented, project: project, target: note, author: user) end + let!(:milestone_event) do + create(:event, :closed, project: project, target: milestone, author: user) + end + before do project.add_master(user) @@ -68,6 +73,7 @@ feature 'Dashboard > Activity' do expect(page).to have_content('accepted') expect(page).to have_content('closed') expect(page).to have_content('commented on') + expect(page).to have_content('closed milestone') end end @@ -107,6 +113,7 @@ feature 'Dashboard > Activity' do expect(page).not_to have_content('accepted') expect(page).to have_content('closed') expect(page).not_to have_content('commented on') + expect(page).to have_content('closed milestone') end end diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index e999192940c..67f49348acb 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -347,6 +347,22 @@ describe Event do end end + describe '#target' do + it 'eager loads the author of an event target' do + create(:closed_issue_event) + + events = described_class.preload(:target).all.to_a + count = ActiveRecord::QueryRecorder + .new { events.first.target.author }.count + + # This expectation exists to make sure the test doesn't pass when the + # author is for some reason not loaded at all. + expect(events.first.target.author).to be_an_instance_of(User) + + expect(count).to be_zero + end + end + def create_push_event(project, user) event = create(:push_event, project: project, author: user) -- cgit v1.2.1 From e1f0d23c898d9133e36afec868abdcef4fb4e8e8 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Thu, 4 Jan 2018 08:44:27 -0500 Subject: Moves prettier to dev dependency --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8c3932dccfd..3587b015fb3 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,6 @@ "mousetrap": "^1.4.6", "name-all-modules-plugin": "^1.0.1", "pikaday": "^1.6.1", - "prettier": "^1.9.2", "prismjs": "^1.6.0", "raphael": "^2.2.7", "raven-js": "^3.14.0", @@ -109,6 +108,7 @@ "karma-sourcemap-loader": "^0.3.7", "karma-webpack": "^2.0.4", "nodemon": "^1.11.0", + "prettier": "1.9.2", "webpack-dev-server": "^2.6.1" } } diff --git a/yarn.lock b/yarn.lock index 381b1a243f8..b29fc022bde 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5146,14 +5146,14 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" +prettier@1.9.2: + version "1.9.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.9.2.tgz#96bc2132f7a32338e6078aeb29727178c6335827" + prettier@^1.7.0: version "1.8.2" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.8.2.tgz#bff83e7fd573933c607875e5ba3abbdffb96aeb8" -prettier@^1.9.2: - version "1.9.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.9.2.tgz#96bc2132f7a32338e6078aeb29727178c6335827" - prismjs@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.6.0.tgz#118d95fb7a66dba2272e343b345f5236659db365" -- cgit v1.2.1 From 528b5eeb761f627bb1972fa8a25a09dc1cea4556 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Wed, 3 Jan 2018 14:18:13 +0000 Subject: Fix error when viewing diffs without blobs Old merge requests can have diffs without corresponding blobs. (This also may be possible for commit diffs in corrupt repositories.) We can't use the `&.` operator on the blobs, because the blob objects are never nil, but `BatchLoader` instances that delegate to `Blob`. We can't use `Object#try`, because `Blob` doesn't inherit from `Object`. `BatchLoader` provides a `__sync` method that returns the delegated object, but using `itself` also works because it's forwarded, and will work for non-`BatchLoader` instances too. So the simplest solution is to just use that with the `&.` operator. --- ...on-undefined-method-binary-for-nil-nilclass.yml | 5 ++++ lib/gitlab/diff/file.rb | 31 ++++++++++++++++------ spec/lib/gitlab/diff/file_spec.rb | 25 +++++++++++++++++ 3 files changed, 53 insertions(+), 8 deletions(-) create mode 100644 changelogs/unreleased/41468-error-500-trying-to-view-a-merge-request-json-undefined-method-binary-for-nil-nilclass.yml diff --git a/changelogs/unreleased/41468-error-500-trying-to-view-a-merge-request-json-undefined-method-binary-for-nil-nilclass.yml b/changelogs/unreleased/41468-error-500-trying-to-view-a-merge-request-json-undefined-method-binary-for-nil-nilclass.yml new file mode 100644 index 00000000000..f69116382f0 --- /dev/null +++ b/changelogs/unreleased/41468-error-500-trying-to-view-a-merge-request-json-undefined-method-binary-for-nil-nilclass.yml @@ -0,0 +1,5 @@ +--- +title: Fix viewing merge request diffs where the underlying blobs are unavailable +merge_request: +author: +type: fixed diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index cd490aaa291..34b070dd375 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -116,8 +116,10 @@ module Gitlab new_content_sha || old_content_sha end + # Use #itself to check the value wrapped by a BatchLoader instance, rather + # than if the BatchLoader instance itself is falsey. def blob - new_blob || old_blob + new_blob&.itself || old_blob&.itself end attr_writer :highlighted_diff_lines @@ -173,7 +175,7 @@ module Gitlab end def binary? - has_binary_notice? || old_blob&.binary? || new_blob&.binary? + has_binary_notice? || try_blobs(:binary?) end def text? @@ -181,15 +183,15 @@ module Gitlab end def external_storage_error? - old_blob&.external_storage_error? || new_blob&.external_storage_error? + try_blobs(:external_storage_error?) end def stored_externally? - old_blob&.stored_externally? || new_blob&.stored_externally? + try_blobs(:stored_externally?) end def external_storage - old_blob&.external_storage || new_blob&.external_storage + try_blobs(:external_storage) end def content_changed? @@ -204,15 +206,15 @@ module Gitlab end def size - [old_blob&.size, new_blob&.size].compact.sum + valid_blobs.map(&:size).sum end def raw_size - [old_blob&.raw_size, new_blob&.raw_size].compact.sum + valid_blobs.map(&:raw_size).sum end def raw_binary? - old_blob&.raw_binary? || new_blob&.raw_binary? + try_blobs(:raw_binary?) end def raw_text? @@ -235,6 +237,19 @@ module Gitlab private + # The blob instances are instances of BatchLoader, which means calling + # &. directly on them won't work. Object#try also won't work, because Blob + # doesn't inherit from Object, but from BasicObject (via SimpleDelegator). + def try_blobs(meth) + old_blob&.itself&.public_send(meth) || new_blob&.itself&.public_send(meth) + end + + # We can't use #compact for the same reason we can't use &., but calling + # #nil? explicitly does work because it is proxied to the blob itself. + def valid_blobs + [old_blob, new_blob].reject(&:nil?) + end + def text_position_properties(line) { old_line: line.old_line, new_line: line.new_line } end diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb index ff9acfd08b9..9204ea37963 100644 --- a/spec/lib/gitlab/diff/file_spec.rb +++ b/spec/lib/gitlab/diff/file_spec.rb @@ -431,4 +431,29 @@ describe Gitlab::Diff::File do end end end + + context 'when neither blob exists' do + let(:blank_diff_refs) { Gitlab::Diff::DiffRefs.new(base_sha: Gitlab::Git::BLANK_SHA, head_sha: Gitlab::Git::BLANK_SHA) } + let(:diff_file) { described_class.new(diff, diff_refs: blank_diff_refs, repository: project.repository) } + + describe '#blob' do + it 'returns a concrete nil so it can be used in boolean expressions' do + actual = diff_file.blob && true + + expect(actual).to be_nil + end + end + + describe '#binary?' do + it 'returns false' do + expect(diff_file).not_to be_binary + end + end + + describe '#size' do + it 'returns zero' do + expect(diff_file.size).to be_zero + end + end + end end -- cgit v1.2.1 From b5fe3916752aafd5c79b2aa7a770fbd51f1b4bef Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 4 Jan 2018 15:44:00 +0100 Subject: Update some Gitaly annotations in Gitlab::Shell --- lib/gitlab/shell.rb | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb index 9cdd3d22f18..18da242e1cb 100644 --- a/lib/gitlab/shell.rb +++ b/lib/gitlab/shell.rb @@ -71,7 +71,6 @@ module Gitlab # Ex. # add_repository("/path/to/storage", "gitlab/gitlab-ci") # - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387 def add_repository(storage, name) relative_path = name.dup relative_path << '.git' unless relative_path.end_with?('.git') @@ -100,7 +99,7 @@ module Gitlab # Ex. # import_repository("/path/to/storage", "gitlab/gitlab-ci", "https://gitlab.com/gitlab-org/gitlab-test.git") # - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387 + # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/874 def import_repository(storage, name, url) # The timeout ensures the subprocess won't hang forever cmd = gitlab_projects(storage, "#{name}.git") @@ -122,7 +121,6 @@ module Gitlab # Ex. # fetch_remote(my_repo, "upstream") # - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387 def fetch_remote(repository, remote, ssh_auth: nil, forced: false, no_tags: false) gitaly_migrate(:fetch_remote) do |is_enabled| if is_enabled @@ -142,7 +140,7 @@ module Gitlab # Ex. # mv_repository("/path/to/storage", "gitlab/gitlab-ci", "randx/gitlab-ci-new") # - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387 + # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/873 def mv_repository(storage, path, new_path) gitlab_projects(storage, "#{path}.git").mv_project("#{new_path}.git") end @@ -156,7 +154,7 @@ module Gitlab # Ex. # fork_repository("/path/to/forked_from/storage", "gitlab/gitlab-ci", "/path/to/forked_to/storage", "new-namespace/gitlab-ci") # - # Gitaly note: JV: not easy to migrate because this involves two Gitaly servers, not one. + # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/817 def fork_repository(forked_from_storage, forked_from_disk_path, forked_to_storage, forked_to_disk_path) gitlab_projects(forked_from_storage, "#{forked_from_disk_path}.git") .fork_repository(forked_to_storage, "#{forked_to_disk_path}.git") @@ -170,7 +168,7 @@ module Gitlab # Ex. # remove_repository("/path/to/storage", "gitlab/gitlab-ci") # - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387 + # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/873 def remove_repository(storage, name) gitlab_projects(storage, "#{name}.git").rm_project end @@ -221,7 +219,6 @@ module Gitlab # Ex. # add_namespace("/path/to/storage", "gitlab") # - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385 def add_namespace(storage, name) Gitlab::GitalyClient.migrate(:add_namespace) do |enabled| if enabled @@ -243,7 +240,6 @@ module Gitlab # Ex. # rm_namespace("/path/to/storage", "gitlab") # - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385 def rm_namespace(storage, name) Gitlab::GitalyClient.migrate(:remove_namespace) do |enabled| if enabled @@ -261,7 +257,6 @@ module Gitlab # Ex. # mv_namespace("/path/to/storage", "gitlab", "gitlabhq") # - # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385 def mv_namespace(storage, old_name, new_name) Gitlab::GitalyClient.migrate(:rename_namespace) do |enabled| if enabled -- cgit v1.2.1 From 44d15e414348ab7befaa22636b85d1c0d9064d08 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 4 Jan 2018 16:34:37 +0100 Subject: get it working --- lib/gitlab/import_export/command_line_util.rb | 4 ++++ lib/gitlab/import_export/repo_restorer.rb | 4 +++- lib/gitlab/shell.rb | 4 ++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/import_export/command_line_util.rb b/lib/gitlab/import_export/command_line_util.rb index 0135b3c6f22..349f17cf0f8 100644 --- a/lib/gitlab/import_export/command_line_util.rb +++ b/lib/gitlab/import_export/command_line_util.rb @@ -15,6 +15,10 @@ module Gitlab execute(%W(#{git_bin_path} --git-dir=#{repo_path} bundle create #{bundle_path} --all)) end + def git_clone_bundle(repo_path:, bundle_path:) + execute(%W(#{git_bin_path} clone --bare -- #{bundle_path} #{repo_path})) + end + def mkdir_p(path) FileUtils.mkdir_p(path, mode: DEFAULT_MODE) FileUtils.chmod(DEFAULT_MODE, path) diff --git a/lib/gitlab/import_export/repo_restorer.rb b/lib/gitlab/import_export/repo_restorer.rb index 32ca2809b2f..a7e00c71990 100644 --- a/lib/gitlab/import_export/repo_restorer.rb +++ b/lib/gitlab/import_export/repo_restorer.rb @@ -13,7 +13,9 @@ module Gitlab def restore return true unless File.exist?(@path_to_bundle) - gitlab_shell.import_repository(@project.repository_storage_path, @project.disk_path, @path_to_bundle) + repo_path = @project.repository.path_to_repo + git_clone_bundle(repo_path: repo_path, bundle_path: @path_to_bundle) + Gitlab::Git::Repository.create_hooks(repo_path, File.expand_path(Gitlab.config.gitlab_shell.hooks_path)) rescue => e @shared.error(e) false diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb index 9cdd3d22f18..1d0eae28f82 100644 --- a/lib/gitlab/shell.rb +++ b/lib/gitlab/shell.rb @@ -102,6 +102,10 @@ module Gitlab # # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387 def import_repository(storage, name, url) + if url.start_with?('.') || url.start_with?('/') + raise Error.new("don't use disk paths with import_repository: #{url.inspect}") + end + # The timeout ensures the subprocess won't hang forever cmd = gitlab_projects(storage, "#{name}.git") success = cmd.import_project(url, git_timeout) -- cgit v1.2.1 From 80242f246b69a803120bc06527b80601fafc526c Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 4 Jan 2018 16:37:18 +0100 Subject: Hide hooks stuff --- lib/gitlab/import_export/command_line_util.rb | 1 + lib/gitlab/import_export/repo_restorer.rb | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/gitlab/import_export/command_line_util.rb b/lib/gitlab/import_export/command_line_util.rb index 349f17cf0f8..dd5d35feab9 100644 --- a/lib/gitlab/import_export/command_line_util.rb +++ b/lib/gitlab/import_export/command_line_util.rb @@ -17,6 +17,7 @@ module Gitlab def git_clone_bundle(repo_path:, bundle_path:) execute(%W(#{git_bin_path} clone --bare -- #{bundle_path} #{repo_path})) + Gitlab::Git::Repository.create_hooks(repo_path, File.expand_path(Gitlab.config.gitlab_shell.hooks_path)) end def mkdir_p(path) diff --git a/lib/gitlab/import_export/repo_restorer.rb b/lib/gitlab/import_export/repo_restorer.rb index a7e00c71990..d0e5cfcfd3e 100644 --- a/lib/gitlab/import_export/repo_restorer.rb +++ b/lib/gitlab/import_export/repo_restorer.rb @@ -13,9 +13,7 @@ module Gitlab def restore return true unless File.exist?(@path_to_bundle) - repo_path = @project.repository.path_to_repo - git_clone_bundle(repo_path: repo_path, bundle_path: @path_to_bundle) - Gitlab::Git::Repository.create_hooks(repo_path, File.expand_path(Gitlab.config.gitlab_shell.hooks_path)) + git_clone_bundle(repo_path: @project.repository.path_to_repo, bundle_path: @path_to_bundle) rescue => e @shared.error(e) false -- cgit v1.2.1 From e28bf81e9aa2b00452e71e9e8dd5f485c541e7d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 4 Jan 2018 16:37:21 +0100 Subject: Rename db:seed_fu-{pg,mysql} to gitlab:setup-{pg,mysql} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- .gitlab-ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e98ac200332..82bc62bc0ab 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -508,7 +508,7 @@ db:rollback-mysql: <<: *db-rollback <<: *use-mysql -.db-seed_fu: &db-seed_fu +.gitlab-setup: &gitlab-setup <<: *dedicated-runner <<: *except-docs-and-qa <<: *pull-cache @@ -529,12 +529,12 @@ db:rollback-mysql: paths: - log/development.log -db:seed_fu-pg: - <<: *db-seed_fu +gitlab:setup-pg: + <<: *gitlab-setup <<: *use-pg -db:seed_fu-mysql: - <<: *db-seed_fu +gitlab:setup-mysql: + <<: *gitlab-setup <<: *use-mysql # Frontend-related jobs -- cgit v1.2.1 From 3df6fa6c05ad86f1bc861a8f38d8096098110e37 Mon Sep 17 00:00:00 2001 From: Kushal Pandya Date: Thu, 4 Jan 2018 21:33:25 +0530 Subject: Enclose props in quotes --- app/assets/javascripts/groups/components/item_stats.vue | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/groups/components/item_stats.vue b/app/assets/javascripts/groups/components/item_stats.vue index 803dc63d39c..3a94e57a028 100644 --- a/app/assets/javascripts/groups/components/item_stats.vue +++ b/app/assets/javascripts/groups/components/item_stats.vue @@ -43,27 +43,27 @@ export default { css-class="number-subgroups" icon-name="folder" :title="s__('Subgroups')" - :value=item.subgroupCount + :value="item.subgroupCount" /> Date: Thu, 4 Jan 2018 21:47:40 +0530 Subject: Use `__` instead of `s__` when context is not required --- app/assets/javascripts/groups/components/item_stats.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/groups/components/item_stats.vue b/app/assets/javascripts/groups/components/item_stats.vue index 3a94e57a028..2e42fb6c9a6 100644 --- a/app/assets/javascripts/groups/components/item_stats.vue +++ b/app/assets/javascripts/groups/components/item_stats.vue @@ -42,21 +42,21 @@ export default { v-if="isGroup" css-class="number-subgroups" icon-name="folder" - :title="s__('Subgroups')" + :title="__('Subgroups')" :value="item.subgroupCount" /> Date: Tue, 2 Jan 2018 12:57:28 -0500 Subject: Remove downcase from special path helper --- app/helpers/projects_helper.rb | 2 +- changelogs/unreleased/jramsay-41590-add-readme-case.yml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/jramsay-41590-add-readme-case.yml diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 4a6b22b5ff6..f7bdcc6fd9c 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -389,7 +389,7 @@ module ProjectsHelper end def add_special_file_path(project, file_name:, commit_message: nil, branch_name: nil, context: nil) - commit_message ||= s_("CommitMessage|Add %{file_name}") % { file_name: file_name.downcase } + commit_message ||= s_("CommitMessage|Add %{file_name}") % { file_name: file_name } project_new_blob_path( project, project.default_branch || 'master', diff --git a/changelogs/unreleased/jramsay-41590-add-readme-case.yml b/changelogs/unreleased/jramsay-41590-add-readme-case.yml new file mode 100644 index 00000000000..37b2bd44e0e --- /dev/null +++ b/changelogs/unreleased/jramsay-41590-add-readme-case.yml @@ -0,0 +1,5 @@ +--- +title: Fix inconsistent downcase of filenames in prefilled `Add` commit messages +merge_request: 16232 +author: James Ramsay +type: fixed -- cgit v1.2.1 From 0a02b0d8eada41b72d19bee3f963d7cee5b19c57 Mon Sep 17 00:00:00 2001 From: Gauthier Wallet Date: Thu, 4 Jan 2018 16:26:14 +0000 Subject: Update settings.md --- doc/api/settings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/settings.md b/doc/api/settings.md index 0e4758cda2d..0b5b1f0c134 100644 --- a/doc/api/settings.md +++ b/doc/api/settings.md @@ -69,7 +69,7 @@ PUT /application/settings | `after_sign_up_text` | string | no | Text shown to the user after signing up | | `akismet_api_key` | string | no | API key for akismet spam protection | | `akismet_enabled` | boolean | no | Enable or disable akismet spam protection | -| `circuitbreaker_access_retries | integer | no | The number of attempts GitLab will make to access a storage. | +| `circuitbreaker_access_retries` | integer | no | The number of attempts GitLab will make to access a storage. | | `circuitbreaker_check_interval` | integer | no | Number of seconds in between storage checks. | | `circuitbreaker_failure_count_threshold` | integer | no | The number of failures of after which GitLab will completely prevent access to the storage. | | `circuitbreaker_failure_reset_time` | integer | no | Time in seconds GitLab will keep storage failure information. When no failures occur during this time, the failure information is reset. | -- cgit v1.2.1 From ac2cb65ab3dc2688b3a1db9de661dc01ed196177 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 4 Jan 2018 18:00:28 +0100 Subject: Remove the Commit#tree method --- app/models/commit.rb | 2 +- lib/gitlab/git/blob.rb | 4 ++-- lib/gitlab/git/commit.rb | 7 +++++-- spec/lib/gitlab/git/blob_spec.rb | 4 ++-- spec/lib/gitlab/git/commit_spec.rb | 1 - spec/models/commit_spec.rb | 1 - 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/app/models/commit.rb b/app/models/commit.rb index 2be07ca7d3c..39d7f5b159d 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -371,7 +371,7 @@ class Commit # # Returns a symbol def uri_type(path) - entry = @raw.tree.path(path) + entry = @raw.rugged_tree_entry(path) if entry[:type] == :blob blob = ::Blob.decorate(Gitlab::Git::Blob.new(name: entry[:name]), @project) blob.image? || blob.video? ? :raw : :blob diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb index 228d97a87ab..c4caa306b5d 100644 --- a/lib/gitlab/git/blob.rb +++ b/lib/gitlab/git/blob.rb @@ -154,8 +154,8 @@ module Gitlab end def find_by_rugged(repository, sha, path, limit:) - commit = repository.lookup(sha) - root_tree = commit.tree + rugged_commit = repository.lookup(sha) + root_tree = rugged_commit.tree blob_entry = find_entry_by_path(repository, root_tree.oid, path) diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index 145721dea76..016437b2419 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -15,8 +15,6 @@ module Gitlab attr_accessor *SERIALIZE_KEYS # rubocop:disable Lint/AmbiguousOperator - delegate :tree, to: :rugged_commit - def ==(other) return false unless other.is_a?(Gitlab::Git::Commit) @@ -452,6 +450,11 @@ module Gitlab ) end + # Is this the same as Blob.find_entry_by_path ? + def rugged_tree_entry(path) + rugged_commit.tree.path(path) + end + private def init_from_hash(hash) diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb index c04a9688503..67838163b05 100644 --- a/spec/lib/gitlab/git/blob_spec.rb +++ b/spec/lib/gitlab/git/blob_spec.rb @@ -146,7 +146,7 @@ describe Gitlab::Git::Blob, seed_helper: true do context 'when sha references a tree' do it 'returns nil' do - tree = Gitlab::Git::Commit.find(repository, 'master').tree + tree = repository.rugged.rev_parse('master^{tree}') blob = Gitlab::Git::Blob.raw(repository, tree.oid) @@ -237,7 +237,7 @@ describe Gitlab::Git::Blob, seed_helper: true do end describe '.batch_lfs_pointers' do - let(:tree_object) { Gitlab::Git::Commit.find(repository, 'master').tree } + let(:tree_object) { repository.rugged.rev_parse('master^{tree}') } let(:non_lfs_blob) do Gitlab::Git::Blob.find( diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb index 6d35734d306..6a07a3ca8b8 100644 --- a/spec/lib/gitlab/git/commit_spec.rb +++ b/spec/lib/gitlab/git/commit_spec.rb @@ -55,7 +55,6 @@ describe Gitlab::Git::Commit, seed_helper: true do it { expect(@commit.parents).to eq(@gitlab_parents) } it { expect(@commit.parent_id).to eq(@parents.first.oid) } it { expect(@commit.no_commit_message).to eq("--no commit message") } - it { expect(@commit.tree).to eq(@tree) } after do # Erase the new commit so other tests get the original repo diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 4f02dc33cd8..817254c7d1e 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -181,7 +181,6 @@ eos it { is_expected.to respond_to(:parents) } it { is_expected.to respond_to(:date) } it { is_expected.to respond_to(:diffs) } - it { is_expected.to respond_to(:tree) } it { is_expected.to respond_to(:id) } it { is_expected.to respond_to(:to_patch) } end -- cgit v1.2.1 From dcebe1494e35fcd8870b38f311c5176eab6b2a2f Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 4 Jan 2018 18:05:49 +0100 Subject: rubocop --- lib/gitlab/shell.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb index 1d0eae28f82..bef944ef1f9 100644 --- a/lib/gitlab/shell.rb +++ b/lib/gitlab/shell.rb @@ -102,7 +102,7 @@ module Gitlab # # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387 def import_repository(storage, name, url) - if url.start_with?('.') || url.start_with?('/') + if url.start_with?('.', '/') raise Error.new("don't use disk paths with import_repository: #{url.inspect}") end -- cgit v1.2.1 From 176b60d11055999d56e30b6fe0581fbede2740c4 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 4 Jan 2018 18:38:39 +0100 Subject: Remove the Project#repo method --- app/controllers/projects_controller.rb | 2 +- app/models/project.rb | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 6f609348402..6f229b08c0c 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -353,7 +353,7 @@ class ProjectsController < Projects::ApplicationController end def repo_exists? - project.repository_exists? && !project.empty_repo? && project.repo + project.repository_exists? && !project.empty_repo? rescue Gitlab::Git::Repository::NoRepository project.repository.expire_exists_cache diff --git a/app/models/project.rb b/app/models/project.rb index 9c0bbf697e2..4784bbc8a44 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -992,10 +992,6 @@ class Project < ActiveRecord::Base false end - def repo - repository.rugged - end - def url_to_repo gitlab_shell.url_to_repo(full_path) end @@ -1438,7 +1434,7 @@ class Project < ActiveRecord::Base # We'd need to keep track of project full path otherwise directory tree # created with hashed storage enabled cannot be usefully imported using # the import rake task. - repo.config['gitlab.fullpath'] = gl_full_path + repository.rugged.config['gitlab.fullpath'] = gl_full_path rescue Gitlab::Git::Repository::NoRepository => e Rails.logger.error("Error writing to .git/config for project #{full_path} (#{id}): #{e.message}.") nil -- cgit v1.2.1 From e3f215f676488d74ff8ed61dea8e715e73db2934 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 4 Jan 2018 12:25:48 -0600 Subject: fix missing import of timeWeek which would cause errors in prometheus graphs with deployments --- .../javascripts/monitoring/utils/date_time_formatters.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/monitoring/utils/date_time_formatters.js b/app/assets/javascripts/monitoring/utils/date_time_formatters.js index 48bdec1e030..068813ddee6 100644 --- a/app/assets/javascripts/monitoring/utils/date_time_formatters.js +++ b/app/assets/javascripts/monitoring/utils/date_time_formatters.js @@ -1,8 +1,18 @@ import { timeFormat as time } from 'd3-time-format'; -import { timeSecond, timeMinute, timeHour, timeDay, timeMonth, timeYear } from 'd3-time'; +import { timeSecond, timeMinute, timeHour, timeDay, timeWeek, timeMonth, timeYear } from 'd3-time'; import { bisector } from 'd3-array'; -const d3 = { time, bisector, timeSecond, timeMinute, timeHour, timeDay, timeMonth, timeYear }; +const d3 = { + time, + bisector, + timeSecond, + timeMinute, + timeHour, + timeDay, + timeWeek, + timeMonth, + timeYear, +}; export const dateFormat = d3.time('%b %-d, %Y'); export const timeFormat = d3.time('%-I:%M%p'); -- cgit v1.2.1 From 0a35f372d232a0ac6b9355d27a9fb9e95b1ee959 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Thu, 4 Jan 2018 18:31:05 +0000 Subject: Added multi editor setting on the profile preferences page --- app/assets/images/multi-editor-off.png | Bin 0 -> 4884 bytes app/assets/images/multi-editor-on.png | Bin 0 -> 5464 bytes app/assets/javascripts/profile/profile.js | 21 +++++++++++++++++++++ app/assets/stylesheets/framework/header.scss | 2 +- app/assets/stylesheets/framework/variables.scss | 5 +++++ .../stylesheets/pages/profiles/preferences.scss | 16 ++++++++++++++++ app/views/layouts/header/_default.html.haml | 2 ++ app/views/profiles/preferences/show.html.haml | 17 +++++++++++++++++ .../jivl-activate-repo-cookie-preferences.yml | 5 +++++ .../user_visits_profile_preferences_page_spec.rb | 12 ++++++++++++ spec/features/projects/user_edits_files_spec.rb | 4 +++- spec/support/cookie_helper.rb | 4 ++++ 12 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 app/assets/images/multi-editor-off.png create mode 100644 app/assets/images/multi-editor-on.png create mode 100644 changelogs/unreleased/jivl-activate-repo-cookie-preferences.yml diff --git a/app/assets/images/multi-editor-off.png b/app/assets/images/multi-editor-off.png new file mode 100644 index 00000000000..82a6127f853 Binary files /dev/null and b/app/assets/images/multi-editor-off.png differ diff --git a/app/assets/images/multi-editor-on.png b/app/assets/images/multi-editor-on.png new file mode 100644 index 00000000000..2bcd29abf13 Binary files /dev/null and b/app/assets/images/multi-editor-on.png differ diff --git a/app/assets/javascripts/profile/profile.js b/app/assets/javascripts/profile/profile.js index 0dc02f012e4..ba4ac850346 100644 --- a/app/assets/javascripts/profile/profile.js +++ b/app/assets/javascripts/profile/profile.js @@ -1,4 +1,5 @@ /* eslint-disable comma-dangle, no-unused-vars, class-methods-use-this, quotes, consistent-return, func-names, prefer-arrow-callback, space-before-function-paren, max-len */ +import Cookies from 'js-cookie'; import Flash from '../flash'; import { getPagePath } from '../lib/utils/common_utils'; @@ -7,6 +8,8 @@ import { getPagePath } from '../lib/utils/common_utils'; constructor({ form } = {}) { this.onSubmitForm = this.onSubmitForm.bind(this); this.form = form || $('.edit-user'); + this.newRepoActivated = Cookies.get('new_repo'); + this.setRepoRadio(); this.bindEvents(); this.initAvatarGlCrop(); } @@ -25,6 +28,7 @@ import { getPagePath } from '../lib/utils/common_utils'; bindEvents() { $('.js-preferences-form').on('change.preference', 'input[type=radio]', this.submitForm); + $('input[name="user[multi_file]"]').on('change', this.setNewRepoCookie); $('#user_notification_email').on('change', this.submitForm); $('#user_notified_of_own_activity').on('change', this.submitForm); $('.update-username').on('ajax:before', this.beforeUpdateUsername); @@ -82,6 +86,23 @@ import { getPagePath } from '../lib/utils/common_utils'; } }); } + + setNewRepoCookie() { + if (this.value === 'off') { + Cookies.remove('new_repo'); + } else { + Cookies.set('new_repo', true, { expires_in: 365 }); + } + } + + setRepoRadio() { + const multiEditRadios = $('input[name="user[multi_file]"]'); + if (this.newRepoActivated || this.newRepoActivated === 'true') { + multiEditRadios.filter('[value=on]').prop('checked', true); + } else { + multiEditRadios.filter('[value=off]').prop('checked', true); + } + } } $(function() { diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index 29714e348a0..ad160f37641 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -516,7 +516,7 @@ .header-user { .dropdown-menu-nav { width: auto; - min-width: 140px; + min-width: 160px; margin-top: 4px; color: $gl-text-color; left: auto; diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 1d6c7a5c472..f7853909f56 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -727,3 +727,8 @@ Popup $popup-triangle-size: 15px; $popup-triangle-border-size: 1px; $popup-box-shadow-color: rgba(90, 90, 90, 0.05); + +/* +Multi file editor +*/ +$border-color-settings: #e1e1e1; diff --git a/app/assets/stylesheets/pages/profiles/preferences.scss b/app/assets/stylesheets/pages/profiles/preferences.scss index c197494b152..68d40b56133 100644 --- a/app/assets/stylesheets/pages/profiles/preferences.scss +++ b/app/assets/stylesheets/pages/profiles/preferences.scss @@ -20,6 +20,22 @@ } } +.multi-file-editor-options { + label { + margin-right: 20px; + text-align: center; + } + + .preview { + font-size: 0; + + img { + border: 1px solid $border-color-settings; + border-radius: 4px; + } + } +} + .application-theme { label { margin-right: 20px; diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index 99e7f3b568d..39eb71c2bac 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -56,6 +56,8 @@ = link_to "Profile", current_user, class: 'profile-link', data: { user: current_user.username } %li = link_to "Settings", profile_path + %li + = link_to "Turn on multi edit", profile_preferences_path - if current_user %li = link_to "Help", help_path diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml index 66d1d1e8d44..65328791ce5 100644 --- a/app/views/profiles/preferences/show.html.haml +++ b/app/views/profiles/preferences/show.html.haml @@ -3,6 +3,23 @@ = render 'profiles/head' = form_for @user, url: profile_preferences_path, remote: true, method: :put, html: { class: 'row prepend-top-default js-preferences-form' } do |f| + .col-lg-4 + %h4.prepend-top-0 + GitLab multi file editor + %p Unlock an additional editing experience which makes it possible to edit and commit multiple files + .col-lg-8.multi-file-editor-options + = label_tag do + .preview.append-bottom-10= image_tag "multi-editor-off.png" + = f.radio_button :multi_file, "off", checked: true + Off + = label_tag do + .preview.append-bottom-10= image_tag "multi-editor-on.png" + = f.radio_button :multi_file, "on", checked: false + On + + .col-sm-12 + %hr + .col-lg-4.application-theme %h4.prepend-top-0 GitLab navigation theme diff --git a/changelogs/unreleased/jivl-activate-repo-cookie-preferences.yml b/changelogs/unreleased/jivl-activate-repo-cookie-preferences.yml new file mode 100644 index 00000000000..778eaa84381 --- /dev/null +++ b/changelogs/unreleased/jivl-activate-repo-cookie-preferences.yml @@ -0,0 +1,5 @@ +--- +title: Added option to user preferences to enable the multi file editor +merge_request: 16056 +author: +type: added diff --git a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb index 90d6841af0e..266af8f4e3d 100644 --- a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb +++ b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb @@ -32,6 +32,18 @@ describe 'User visits the profile preferences page' do end end + describe 'User changes their multi file editor preferences', :js do + it 'set the new_repo cookie when the option is ON' do + choose 'user_multi_file_on' + expect(get_cookie('new_repo')).not_to be_nil + end + + it 'deletes the new_repo cookie when the option is OFF' do + choose 'user_multi_file_off' + expect(get_cookie('new_repo')).to be_nil + end + end + describe 'User changes their default dashboard', :js do it 'creates a flash message' do select 'Starred Projects', from: 'user_dashboard' diff --git a/spec/features/projects/user_edits_files_spec.rb b/spec/features/projects/user_edits_files_spec.rb index 5c5c6a398f6..05c2be473da 100644 --- a/spec/features/projects/user_edits_files_spec.rb +++ b/spec/features/projects/user_edits_files_spec.rb @@ -33,7 +33,9 @@ describe 'User edits files' do binary_file = File.join(project.repository.root_ref, 'files/images/logo-black.png') visit(project_blob_path(project, binary_file)) - expect(page).not_to have_link('edit') + page.within '.content' do + expect(page).not_to have_link('edit') + end end it 'commits an edited file', :js do diff --git a/spec/support/cookie_helper.rb b/spec/support/cookie_helper.rb index 224619c899c..d72925e1838 100644 --- a/spec/support/cookie_helper.rb +++ b/spec/support/cookie_helper.rb @@ -8,6 +8,10 @@ module CookieHelper page.driver.browser.manage.add_cookie(name: name, value: value, **options) end + def get_cookie(name) + page.driver.browser.manage.cookie_named(name) + end + private def on_a_page? -- cgit v1.2.1 From 5e148d4e931792733400f59864e1aa886ef55953 Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Wed, 6 Dec 2017 17:07:47 -0200 Subject: EE-BACKPORT group boards --- app/finders/labels_finder.rb | 19 +- app/policies/group_policy.rb | 8 +- doc/api/boards.md | 200 +++++++++++++++++++-- lib/api/api.rb | 4 +- lib/api/boards.rb | 84 ++++----- lib/api/boards_responses.rb | 50 ++++++ lib/api/entities.rb | 2 + lib/api/helpers.rb | 15 +- lib/api/labels.rb | 4 +- lib/api/v3/labels.rb | 2 +- spec/finders/labels_finder_spec.rb | 10 ++ spec/fixtures/api/schemas/public_api/v4/board.json | 86 +++++++++ .../fixtures/api/schemas/public_api/v4/boards.json | 4 + .../api/schemas/public_api/v4/user/basic.json | 2 +- spec/requests/api/boards_spec.rb | 179 ++---------------- spec/support/api/boards_shared_examples.rb | 180 +++++++++++++++++++ 16 files changed, 601 insertions(+), 248 deletions(-) create mode 100644 lib/api/boards_responses.rb create mode 100644 spec/fixtures/api/schemas/public_api/v4/board.json create mode 100644 spec/fixtures/api/schemas/public_api/v4/boards.json create mode 100644 spec/support/api/boards_shared_examples.rb diff --git a/app/finders/labels_finder.rb b/app/finders/labels_finder.rb index ce432ddbfe6..6de9eb89468 100644 --- a/app/finders/labels_finder.rb +++ b/app/finders/labels_finder.rb @@ -1,4 +1,6 @@ class LabelsFinder < UnionFinder + include Gitlab::Utils::StrongMemoize + def initialize(current_user, params = {}) @current_user = current_user @params = params @@ -32,6 +34,8 @@ class LabelsFinder < UnionFinder label_ids << project.labels end end + elsif only_group_labels? + label_ids << Label.where(group_id: group.id) else label_ids << Label.where(group_id: projects.group_ids) label_ids << Label.where(project_id: projects.select(:id)) @@ -51,6 +55,13 @@ class LabelsFinder < UnionFinder items.where(title: title) end + def group + strong_memoize(:group) do + group = Group.find(params[:group_id]) + authorized_to_read_labels?(group) && group + end + end + def group? params[:group_id].present? end @@ -63,6 +74,10 @@ class LabelsFinder < UnionFinder params[:project_ids].present? end + def only_group_labels? + params[:only_group_labels] + end + def title params[:title] || params[:name] end @@ -96,9 +111,9 @@ class LabelsFinder < UnionFinder @projects end - def authorized_to_read_labels?(project) + def authorized_to_read_labels?(label_parent) return true if skip_authorization - Ability.allowed?(current_user, :read_label, project) + Ability.allowed?(current_user, :read_label, label_parent) end end diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb index d2d45e402b0..f0bcba588a2 100644 --- a/app/policies/group_policy.rb +++ b/app/policies/group_policy.rb @@ -28,12 +28,18 @@ class GroupPolicy < BasePolicy with_options scope: :subject, score: 0 condition(:request_access_enabled) { @subject.request_access_enabled } - rule { public_group } .enable :read_group + rule { public_group }.policy do + enable :read_group + enable :read_list + enable :read_label + end + rule { logged_in_viewable }.enable :read_group rule { guest }.policy do enable :read_group enable :upload_file + enable :read_label end rule { admin } .enable :read_group diff --git a/doc/api/boards.md b/doc/api/boards.md index 69c47abc806..a5f455e1c43 100644 --- a/doc/api/boards.md +++ b/doc/api/boards.md @@ -15,10 +15,10 @@ GET /projects/:id/boards | Attribute | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | ```bash -curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/:id/boards +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards ``` Example response: @@ -27,6 +27,19 @@ Example response: [ { "id" : 1, + "project": { + "id": 5, + "name": "Diaspora Project Site", + "name_with_namespace": "Diaspora / Diaspora Project Site", + "path": "diaspora-project-site", + "path_with_namespace": "diaspora/diaspora-project-site", + "http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git", + "web_url": "http://example.com/diaspora/diaspora-project-site" + }, + "milestone": { + "id": 12 + "title": "10.0" + }, "lists" : [ { "id" : 1, @@ -60,6 +73,159 @@ Example response: ] ``` +## Single board + +Get a single board. + +``` +GET /projects/:id/boards/:board_id +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `board_id` | integer | yes | The ID of a board | + +```bash +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1 +``` + +Example response: + +```json + { + "id": 1, + "name:": "project issue board", + "project": { + "id": 5, + "name": "Diaspora Project Site", + "name_with_namespace": "Diaspora / Diaspora Project Site", + "path": "diaspora-project-site", + "path_with_namespace": "diaspora/diaspora-project-site", + "http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git", + "web_url": "http://example.com/diaspora/diaspora-project-site" + }, + "milestone": { + "id": 12 + "title": "10.0" + }, + "lists" : [ + { + "id" : 1, + "label" : { + "name" : "Testing", + "color" : "#F0AD4E", + "description" : null + }, + "position" : 1 + }, + { + "id" : 2, + "label" : { + "name" : "Ready", + "color" : "#FF0000", + "description" : null + }, + "position" : 2 + }, + { + "id" : 3, + "label" : { + "name" : "Production", + "color" : "#FF5F00", + "description" : null + }, + "position" : 3 + } + ] + } +``` + +## Create a board (EES-Only) + +Creates a board. + +``` +POST /projects/:id/boards +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `name` | string | yes | The name of the new board | + +```bash +curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards?name=newboard +``` + +Example response: + +```json + { + "id": 1, + "project": { + "id": 5, + "name": "Diaspora Project Site", + "name_with_namespace": "Diaspora / Diaspora Project Site", + "path": "diaspora-project-site", + "path_with_namespace": "diaspora/diaspora-project-site", + "http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git", + "web_url": "http://example.com/diaspora/diaspora-project-site" + }, + "name": "newboard", + "milestone": { + "id": 12 + "title": "10.0" + }, + "lists" : [ + { + "id" : 1, + "label" : { + "name" : "Testing", + "color" : "#F0AD4E", + "description" : null + }, + "position" : 1 + }, + { + "id" : 2, + "label" : { + "name" : "Ready", + "color" : "#FF0000", + "description" : null + }, + "position" : 2 + }, + { + "id" : 3, + "label" : { + "name" : "Production", + "color" : "#FF5F00", + "description" : null + }, + "position" : 3 + } + ] + } +``` + +## Delete a board (EES-Only) + +Deletes a board. + +``` +DELETE /projects/:id/boards/:board_id +``` + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `board_id` | integer | yes | The ID of a board | + +```bash +curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1 +``` + ## List board lists Get a list of the board's lists. @@ -71,8 +237,8 @@ GET /projects/:id/boards/:board_id/lists | Attribute | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `board_id` | integer | yes | The ID of a board | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `board_id` | integer | yes | The ID of a board | ```bash curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists @@ -122,9 +288,9 @@ GET /projects/:id/boards/:board_id/lists/:list_id | Attribute | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `board_id` | integer | yes | The ID of a board | -| `list_id`| integer | yes | The ID of a board's list | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `board_id` | integer | yes | The ID of a board | +| `list_id`| integer | yes | The ID of a board's list | ```bash curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists/1 @@ -154,9 +320,9 @@ POST /projects/:id/boards/:board_id/lists | Attribute | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `board_id` | integer | yes | The ID of a board | -| `label_id` | integer | yes | The ID of a label | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `board_id` | integer | yes | The ID of a board | +| `label_id` | integer | yes | The ID of a label | ```bash curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists?label_id=5 @@ -186,10 +352,10 @@ PUT /projects/:id/boards/:board_id/lists/:list_id | Attribute | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `board_id` | integer | yes | The ID of a board | -| `list_id` | integer | yes | The ID of a board's list | -| `position` | integer | yes | The position of the list | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `board_id` | integer | yes | The ID of a board | +| `list_id` | integer | yes | The ID of a board's list | +| `position` | integer | yes | The position of the list | ```bash curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists/1?position=2 @@ -219,9 +385,9 @@ DELETE /projects/:id/boards/:board_id/lists/:list_id | Attribute | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `board_id` | integer | yes | The ID of a board | -| `list_id` | integer | yes | The ID of a board's list | +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `board_id` | integer | yes | The ID of a board | +| `list_id` | integer | yes | The ID of a board's list | ```bash curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists/1 diff --git a/lib/api/api.rb b/lib/api/api.rb index 8094597d238..e0d14281c96 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -119,6 +119,7 @@ module API mount ::API::Features mount ::API::Files mount ::API::Groups + mount ::API::GroupMilestones mount ::API::Internal mount ::API::Issues mount ::API::Jobs @@ -129,8 +130,6 @@ module API mount ::API::Members mount ::API::MergeRequestDiffs mount ::API::MergeRequests - mount ::API::ProjectMilestones - mount ::API::GroupMilestones mount ::API::Namespaces mount ::API::Notes mount ::API::NotificationSettings @@ -139,6 +138,7 @@ module API mount ::API::PipelineSchedules mount ::API::ProjectHooks mount ::API::Projects + mount ::API::ProjectMilestones mount ::API::ProjectSnippets mount ::API::ProtectedBranches mount ::API::Repositories diff --git a/lib/api/boards.rb b/lib/api/boards.rb index 366b0dc9a6f..6c706b2b4e1 100644 --- a/lib/api/boards.rb +++ b/lib/api/boards.rb @@ -1,45 +1,46 @@ module API class Boards < Grape::API + include BoardsResponses include PaginationParams before { authenticate! } + helpers do + def board_parent + user_project + end + end + params do requires :id, type: String, desc: 'The ID of a project' end resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do - desc 'Get all project boards' do - detail 'This feature was introduced in 8.13' - success Entities::Board - end - params do - use :pagination - end - get ':id/boards' do - authorize!(:read_board, user_project) - present paginate(user_project.boards), with: Entities::Board + segment ':id/boards' do + desc 'Get all project boards' do + detail 'This feature was introduced in 8.13' + success Entities::Board + end + params do + use :pagination + end + get '/' do + authorize!(:read_board, user_project) + present paginate(board_parent.boards), with: Entities::Board + end + + desc 'Find a project board' do + detail 'This feature was introduced in 10.4' + success Entities::Board + end + get '/:board_id' do + present board, with: Entities::Board + end end params do requires :board_id, type: Integer, desc: 'The ID of a board' end segment ':id/boards/:board_id' do - helpers do - def project_board - board = user_project.boards.first - - if params[:board_id] == board.id - board - else - not_found!('Board') - end - end - - def board_lists - project_board.lists.destroyable - end - end - desc 'Get the lists of a project board' do detail 'Does not include `done` list. This feature was introduced in 8.13' success Entities::List @@ -72,22 +73,13 @@ module API requires :label_id, type: Integer, desc: 'The ID of an existing label' end post '/lists' do - unless available_labels.exists?(params[:label_id]) + unless available_labels_for(user_project).exists?(params[:label_id]) render_api_error!({ error: 'Label not found!' }, 400) end authorize!(:admin_list, user_project) - service = ::Boards::Lists::CreateService.new(user_project, current_user, - { label_id: params[:label_id] }) - - list = service.execute(project_board) - - if list.valid? - present list, with: Entities::List - else - render_validation_error!(list) - end + create_list end desc 'Moves a board list to a new position' do @@ -99,18 +91,11 @@ module API requires :position, type: Integer, desc: 'The position of the list' end put '/lists/:list_id' do - list = project_board.lists.movable.find(params[:list_id]) + list = board_lists.find(params[:list_id]) authorize!(:admin_list, user_project) - service = ::Boards::Lists::MoveService.new(user_project, current_user, - { position: params[:position] }) - - if service.execute(list) - present list, with: Entities::List - else - render_api_error!({ error: "List could not be moved!" }, 400) - end + move_list(list) end desc 'Delete a board list' do @@ -124,12 +109,7 @@ module API authorize!(:admin_list, user_project) list = board_lists.find(params[:list_id]) - destroy_conditionally!(list) do |list| - service = ::Boards::Lists::DestroyService.new(user_project, current_user) - unless service.execute(list) - render_api_error!({ error: 'List could not be deleted!' }, 400) - end - end + destroy_list(list) end end end diff --git a/lib/api/boards_responses.rb b/lib/api/boards_responses.rb new file mode 100644 index 00000000000..ead0943a74d --- /dev/null +++ b/lib/api/boards_responses.rb @@ -0,0 +1,50 @@ +module API + module BoardsResponses + extend ActiveSupport::Concern + + included do + helpers do + def board + board_parent.boards.find(params[:board_id]) + end + + def board_lists + board.lists.destroyable + end + + def create_list + create_list_service = + ::Boards::Lists::CreateService.new(board_parent, current_user, { label_id: params[:label_id] }) + + list = create_list_service.execute(board) + + if list.valid? + present list, with: Entities::List + else + render_validation_error!(list) + end + end + + def move_list(list) + move_list_service = + ::Boards::Lists::MoveService.new(board_parent, current_user, { position: params[:position].to_i }) + + if move_list_service.execute(list) + present list, with: Entities::List + else + render_api_error!({ error: "List could not be moved!" }, 400) + end + end + + def destroy_list(list) + destroy_conditionally!(list) do |list| + service = ::Boards::Lists::DestroyService.new(board_parent, current_user) + unless service.execute(list) + render_api_error!({ error: 'List could not be deleted!' }, 400) + end + end + end + end + end + end +end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 4ad4a1f7867..86ac10c39d0 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -791,6 +791,8 @@ module API class Board < Grape::Entity expose :id + expose :project, using: Entities::BasicProjectDetails + expose :lists, using: Entities::List do |board| board.lists.destroyable end diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 9ba15893f55..c1f5ec2ab14 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -74,8 +74,15 @@ module API page || not_found!('Wiki Page') end - def available_labels - @available_labels ||= LabelsFinder.new(current_user, project_id: user_project.id).execute + def available_labels_for(label_parent) + search_params = + if label_parent.is_a?(Project) + { project_id: label_parent.id } + else + { group_id: label_parent.id, only_group_labels: true } + end + + LabelsFinder.new(current_user, search_params).execute end def find_user(id) @@ -141,7 +148,9 @@ module API end def find_project_label(id) - label = available_labels.find_by_id(id) || available_labels.find_by_title(id) + labels = available_labels_for(user_project) + label = labels.find_by_id(id) || labels.find_by_title(id) + label || not_found!('Label') end diff --git a/lib/api/labels.rb b/lib/api/labels.rb index e41a1720ac1..81eaf56e48e 100644 --- a/lib/api/labels.rb +++ b/lib/api/labels.rb @@ -15,7 +15,7 @@ module API use :pagination end get ':id/labels' do - present paginate(available_labels), with: Entities::Label, current_user: current_user, project: user_project + present paginate(available_labels_for(user_project)), with: Entities::Label, current_user: current_user, project: user_project end desc 'Create a new label' do @@ -30,7 +30,7 @@ module API post ':id/labels' do authorize! :admin_label, user_project - label = available_labels.find_by(title: params[:name]) + label = available_labels_for(user_project).find_by(title: params[:name]) conflict!('Label already exists') if label priority = params.delete(:priority) diff --git a/lib/api/v3/labels.rb b/lib/api/v3/labels.rb index bd5eb2175e8..4157462ec2a 100644 --- a/lib/api/v3/labels.rb +++ b/lib/api/v3/labels.rb @@ -11,7 +11,7 @@ module API success ::API::Entities::Label end get ':id/labels' do - present available_labels, with: ::API::Entities::Label, current_user: current_user, project: user_project + present available_labels_for(user_project), with: ::API::Entities::Label, current_user: current_user, project: user_project end desc 'Delete an existing label' do diff --git a/spec/finders/labels_finder_spec.rb b/spec/finders/labels_finder_spec.rb index d507af3fd3d..06031aee217 100644 --- a/spec/finders/labels_finder_spec.rb +++ b/spec/finders/labels_finder_spec.rb @@ -56,6 +56,16 @@ describe LabelsFinder do expect(finder.execute).to eq [group_label_2, group_label_1, project_label_5] end + + context 'when only_group_labels is true' do + it 'returns only group labels' do + group_1.add_developer(user) + + finder = described_class.new(user, group_id: group_1.id, only_group_labels: true) + + expect(finder.execute).to eq [group_label_2, group_label_1] + end + end end context 'filtering by project_id' do diff --git a/spec/fixtures/api/schemas/public_api/v4/board.json b/spec/fixtures/api/schemas/public_api/v4/board.json new file mode 100644 index 00000000000..d667f1d631c --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/board.json @@ -0,0 +1,86 @@ +{ + "type": "object", + "required" : [ + "id", + "project", + "lists" + ], + "properties" : { + "id": { "type": "integer" }, + "project": { + "type": ["object", "null"], + "required": [ + "id", + "avatar_url", + "description", + "default_branch", + "tag_list", + "ssh_url_to_repo", + "http_url_to_repo", + "web_url", + "name", + "name_with_namespace", + "path", + "path_with_namespace", + "star_count", + "forks_count", + "created_at", + "last_activity_at" + ], + "properties": { + "id": { "type": "integer" }, + "avatar_url": { "type": ["string", "null"] }, + "description": { "type": ["string", "null"] }, + "default_branch": { "type": ["string", "null"] }, + "tag_list": { "type": "array" }, + "ssh_url_to_repo": { "type": "string" }, + "http_url_to_repo": { "type": "string" }, + "web_url": { "type": "string" }, + "name": { "type": "string" }, + "name_with_namespace": { "type": "string" }, + "path": { "type": "string" }, + "path_with_namespace": { "type": "string" }, + "star_count": { "type": "integer" }, + "forks_count": { "type": "integer" }, + "created_at": { "type": "date" }, + "last_activity_at": { "type": "date" } + }, + "additionalProperties": false + }, + "lists": { + "type": "array", + "items": { + "type": "object", + "required" : [ + "id", + "label", + "position" + ], + "properties" : { + "id": { "type": "integer" }, + "label": { + "type": ["object", "null"], + "required": [ + "id", + "color", + "description", + "name" + ], + "properties": { + "id": { "type": "integer" }, + "color": { + "type": "string", + "pattern": "^#[0-9A-Fa-f]{3}{1,2}+$" + }, + "description": { "type": ["string", "null"] }, + "name": { "type": "string" } + } + }, + "position": { "type": ["integer", "null"] } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": true +} diff --git a/spec/fixtures/api/schemas/public_api/v4/boards.json b/spec/fixtures/api/schemas/public_api/v4/boards.json new file mode 100644 index 00000000000..117564ef77a --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/boards.json @@ -0,0 +1,4 @@ +{ + "type": "array", + "items": { "$ref": "board.json" } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/user/basic.json b/spec/fixtures/api/schemas/public_api/v4/user/basic.json index 9f69d31971c..bf330d8278c 100644 --- a/spec/fixtures/api/schemas/public_api/v4/user/basic.json +++ b/spec/fixtures/api/schemas/public_api/v4/user/basic.json @@ -1,5 +1,5 @@ { - "type": "object", + "type": ["object", "null"], "required": [ "id", "state", diff --git a/spec/requests/api/boards_spec.rb b/spec/requests/api/boards_spec.rb index f65af69dc7f..c6c10025f7f 100644 --- a/spec/requests/api/boards_spec.rb +++ b/spec/requests/api/boards_spec.rb @@ -6,18 +6,18 @@ describe API::Boards do set(:non_member) { create(:user) } set(:guest) { create(:user) } set(:admin) { create(:user, :admin) } - set(:project) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) } + set(:board_parent) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) } set(:dev_label) do - create(:label, title: 'Development', color: '#FFAABB', project: project) + create(:label, title: 'Development', color: '#FFAABB', project: board_parent) end set(:test_label) do - create(:label, title: 'Testing', color: '#FFAACC', project: project) + create(:label, title: 'Testing', color: '#FFAACC', project: board_parent) end set(:ux_label) do - create(:label, title: 'UX', color: '#FF0000', project: project) + create(:label, title: 'UX', color: '#FF0000', project: board_parent) end set(:dev_list) do @@ -28,180 +28,25 @@ describe API::Boards do create(:list, label: test_label, position: 2) end - set(:board) do - create(:board, project: project, lists: [dev_list, test_list]) - end - - before do - project.add_reporter(user) - project.add_guest(guest) - end + set(:milestone) { create(:milestone, project: board_parent) } + set(:board_label) { create(:label, project: board_parent) } + set(:board) { create(:board, project: board_parent, lists: [dev_list, test_list]) } - describe "GET /projects/:id/boards" do - let(:base_url) { "/projects/#{project.id}/boards" } + it_behaves_like 'group and project boards', "/projects/:id/boards" - context "when unauthenticated" do - it "returns authentication error" do - get api(base_url) - - expect(response).to have_gitlab_http_status(401) - end - end - - context "when authenticated" do - it "returns the project issue board" do - get api(base_url, user) - - expect(response).to have_gitlab_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(board.id) - expect(json_response.first['lists']).to be_an Array - expect(json_response.first['lists'].length).to eq(2) - expect(json_response.first['lists'].last).to have_key('position') - end - end - end - - describe "GET /projects/:id/boards/:board_id/lists" do - let(:base_url) { "/projects/#{project.id}/boards/#{board.id}/lists" } - - it 'returns issue board lists' do - get api(base_url, user) - - expect(response).to have_gitlab_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) - expect(json_response.first['label']['name']).to eq(dev_label.title) - end - - it 'returns 404 if board not found' do - get api("/projects/#{project.id}/boards/22343/lists", user) - - expect(response).to have_gitlab_http_status(404) - end - end - - describe "GET /projects/:id/boards/:board_id/lists/:list_id" do - let(:base_url) { "/projects/#{project.id}/boards/#{board.id}/lists" } - - it 'returns a list' do - get api("#{base_url}/#{dev_list.id}", user) - - expect(response).to have_gitlab_http_status(200) - expect(json_response['id']).to eq(dev_list.id) - expect(json_response['label']['name']).to eq(dev_label.title) - expect(json_response['position']).to eq(1) - end - - it 'returns 404 if list not found' do - get api("#{base_url}/5324", user) - - expect(response).to have_gitlab_http_status(404) - end - end - - describe "POST /projects/:id/board/lists" do - let(:base_url) { "/projects/#{project.id}/boards/#{board.id}/lists" } + describe "POST /projects/:id/boards/lists" do + let(:url) { "/projects/#{board_parent.id}/boards/#{board.id}/lists" } it 'creates a new issue board list for group labels' do group = create(:group) group_label = create(:group_label, group: group) - project.update(group: group) + board_parent.update(group: group) - post api(base_url, user), label_id: group_label.id + post api(url, user), label_id: group_label.id expect(response).to have_gitlab_http_status(201) expect(json_response['label']['name']).to eq(group_label.title) expect(json_response['position']).to eq(3) end - - it 'creates a new issue board list for project labels' do - post api(base_url, user), label_id: ux_label.id - - expect(response).to have_gitlab_http_status(201) - expect(json_response['label']['name']).to eq(ux_label.title) - expect(json_response['position']).to eq(3) - end - - it 'returns 400 when creating a new list if label_id is invalid' do - post api(base_url, user), label_id: 23423 - - expect(response).to have_gitlab_http_status(400) - end - - it 'returns 403 for project members with guest role' do - put api("#{base_url}/#{test_list.id}", guest), position: 1 - - expect(response).to have_gitlab_http_status(403) - end - end - - describe "PUT /projects/:id/boards/:board_id/lists/:list_id to update only position" do - let(:base_url) { "/projects/#{project.id}/boards/#{board.id}/lists" } - - it "updates a list" do - put api("#{base_url}/#{test_list.id}", user), - position: 1 - - expect(response).to have_gitlab_http_status(200) - expect(json_response['position']).to eq(1) - end - - it "returns 404 error if list id not found" do - put api("#{base_url}/44444", user), - position: 1 - - expect(response).to have_gitlab_http_status(404) - end - - it "returns 403 for project members with guest role" do - put api("#{base_url}/#{test_list.id}", guest), - position: 1 - - expect(response).to have_gitlab_http_status(403) - end - end - - describe "DELETE /projects/:id/board/lists/:list_id" do - let(:base_url) { "/projects/#{project.id}/boards/#{board.id}/lists" } - - it "rejects a non member from deleting a list" do - delete api("#{base_url}/#{dev_list.id}", non_member) - - expect(response).to have_gitlab_http_status(403) - end - - it "rejects a user with guest role from deleting a list" do - delete api("#{base_url}/#{dev_list.id}", guest) - - expect(response).to have_gitlab_http_status(403) - end - - it "returns 404 error if list id not found" do - delete api("#{base_url}/44444", user) - - expect(response).to have_gitlab_http_status(404) - end - - context "when the user is project owner" do - set(:owner) { create(:user) } - - before do - project.update(namespace: owner.namespace) - end - - it "deletes the list if an admin requests it" do - delete api("#{base_url}/#{dev_list.id}", owner) - - expect(response).to have_gitlab_http_status(204) - end - - it_behaves_like '412 response' do - let(:request) { api("#{base_url}/#{dev_list.id}", owner) } - end - end end end diff --git a/spec/support/api/boards_shared_examples.rb b/spec/support/api/boards_shared_examples.rb new file mode 100644 index 00000000000..943c1f6ffd7 --- /dev/null +++ b/spec/support/api/boards_shared_examples.rb @@ -0,0 +1,180 @@ +shared_examples_for 'group and project boards' do |route_definition, ee = false| + let(:root_url) { route_definition.gsub(":id", board_parent.id.to_s) } + + before do + board_parent.add_reporter(user) + board_parent.add_guest(guest) + end + + def expect_schema_match_for(response, schema_file, ee) + if ee + expect(response).to match_response_schema(schema_file, dir: "ee") + else + expect(response).to match_response_schema(schema_file) + end + end + + describe "GET #{route_definition}" do + context "when unauthenticated" do + it "returns authentication error" do + get api(root_url) + + expect(response).to have_gitlab_http_status(401) + end + end + + context "when authenticated" do + it "returns the issue boards" do + get api(root_url, user) + + expect(response).to have_gitlab_http_status(200) + expect(response).to include_pagination_headers + + expect_schema_match_for(response, 'public_api/v4/boards', ee) + end + + describe "GET #{route_definition}/:board_id" do + let(:url) { "#{root_url}/#{board.id}" } + + it 'get a single board by id' do + get api(url, user) + + expect_schema_match_for(response, 'public_api/v4/board', ee) + end + end + end + end + + describe "GET #{route_definition}/:board_id/lists" do + let(:url) { "#{root_url}/#{board.id}/lists" } + + it 'returns issue board lists' do + get api(url, user) + + expect(response).to have_gitlab_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.length).to eq(2) + expect(json_response.first['label']['name']).to eq(dev_label.title) + end + + it 'returns 404 if board not found' do + get api("#{root_url}/22343/lists", user) + + expect(response).to have_gitlab_http_status(404) + end + end + + describe "GET #{route_definition}/:board_id/lists/:list_id" do + let(:url) { "#{root_url}/#{board.id}/lists" } + + it 'returns a list' do + get api("#{url}/#{dev_list.id}", user) + + expect(response).to have_gitlab_http_status(200) + expect(json_response['id']).to eq(dev_list.id) + expect(json_response['label']['name']).to eq(dev_label.title) + expect(json_response['position']).to eq(1) + end + + it 'returns 404 if list not found' do + get api("#{url}/5324", user) + + expect(response).to have_gitlab_http_status(404) + end + end + + describe "POST #{route_definition}/lists" do + let(:url) { "#{root_url}/#{board.id}/lists" } + + it 'creates a new issue board list for labels' do + post api(url, user), label_id: ux_label.id + + expect(response).to have_gitlab_http_status(201) + expect(json_response['label']['name']).to eq(ux_label.title) + expect(json_response['position']).to eq(3) + end + + it 'returns 400 when creating a new list if label_id is invalid' do + post api(url, user), label_id: 23423 + + expect(response).to have_gitlab_http_status(400) + end + + it 'returns 403 for members with guest role' do + put api("#{url}/#{test_list.id}", guest), position: 1 + + expect(response).to have_gitlab_http_status(403) + end + end + + describe "PUT #{route_definition}/:board_id/lists/:list_id to update only position" do + let(:url) { "#{root_url}/#{board.id}/lists" } + + it "updates a list" do + put api("#{url}/#{test_list.id}", user), + position: 1 + + expect(response).to have_gitlab_http_status(200) + expect(json_response['position']).to eq(1) + end + + it "returns 404 error if list id not found" do + put api("#{url}/44444", user), + position: 1 + + expect(response).to have_gitlab_http_status(404) + end + + it "returns 403 for members with guest role" do + put api("#{url}/#{test_list.id}", guest), + position: 1 + + expect(response).to have_gitlab_http_status(403) + end + end + + describe "DELETE #{route_definition}/lists/:list_id" do + let(:url) { "#{root_url}/#{board.id}/lists" } + + it "rejects a non member from deleting a list" do + delete api("#{url}/#{dev_list.id}", non_member) + + expect(response).to have_gitlab_http_status(403) + end + + it "rejects a user with guest role from deleting a list" do + delete api("#{url}/#{dev_list.id}", guest) + + expect(response).to have_gitlab_http_status(403) + end + + it "returns 404 error if list id not found" do + delete api("#{url}/44444", user) + + expect(response).to have_gitlab_http_status(404) + end + + context "when the user is parent owner" do + set(:owner) { create(:user) } + + before do + if board_parent.try(:namespace) + board_parent.update(namespace: owner.namespace) + else + board.parent.add_owner(owner) + end + end + + it "deletes the list if an admin requests it" do + delete api("#{url}/#{dev_list.id}", owner) + + expect(response).to have_gitlab_http_status(204) + end + + it_behaves_like '412 response' do + let(:request) { api("#{url}/#{dev_list.id}", owner) } + end + end + end +end -- cgit v1.2.1 From 18bd8b3bd00ac664c7043e14b02a1fadc8605c16 Mon Sep 17 00:00:00 2001 From: Fatih Acet Date: Thu, 4 Jan 2018 22:16:11 +0100 Subject: Fix issue boards scroll config. --- app/assets/javascripts/boards/components/board_list.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/boards/components/board_list.js b/app/assets/javascripts/boards/components/board_list.js index 29aeb8e84aa..84b76a6f1b1 100644 --- a/app/assets/javascripts/boards/components/board_list.js +++ b/app/assets/javascripts/boards/components/board_list.js @@ -115,7 +115,7 @@ export default { }, mounted() { const options = gl.issueBoards.getBoardSortableDefaultOptions({ - scroll: document.querySelectorAll('.boards-list')[0], + scroll: true, group: 'issues', disabled: this.disabled, filter: '.board-list-count, .is-disabled', -- cgit v1.2.1 From f834e2907d5111f3e2bcd8d0dd126f9e0dd0be7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 4 Jan 2018 19:13:30 +0100 Subject: Move cache reset to ci_cd_settings controller --- .../projects/settings/ci_cd_controller.rb | 9 +++++ app/controllers/projects_controller.rb | 9 ----- app/views/projects/pipelines/index.html.haml | 2 +- config/routes/project.rb | 5 ++- .../projects/settings/ci_cd_controller_spec.rb | 47 ++++++++++++++++++++++ spec/controllers/projects_controller_spec.rb | 47 ---------------------- 6 files changed, 60 insertions(+), 59 deletions(-) diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb index b029b31f9af..1dcebcb15a6 100644 --- a/app/controllers/projects/settings/ci_cd_controller.rb +++ b/app/controllers/projects/settings/ci_cd_controller.rb @@ -11,6 +11,15 @@ module Projects define_auto_devops_variables end + def reset_cache + if ResetProjectCacheService.new(@project, current_user).execute + flash[:notice] = _("Project cache successfully reset.") + else + flash[:error] = _("Unable to reset project cache.") + end + redirect_to project_pipelines_path(@project) + end + private def define_runners_variables diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 928555c200b..6f609348402 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -175,15 +175,6 @@ class ProjectsController < Projects::ApplicationController ) end - def reset_cache - if ResetProjectCacheService.new(@project, current_user).execute - flash[:notice] = _("Project cache successfully reset.") - else - flash[:error] = _("Unable to reset project cache.") - end - redirect_to project_pipelines_path(@project) - end - def export @project.add_export_job(current_user: current_user) diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml index d23cb626312..f8555f11aab 100644 --- a/app/views/projects/pipelines/index.html.haml +++ b/app/views/projects/pipelines/index.html.haml @@ -11,7 +11,7 @@ "can-create-pipeline" => can?(current_user, :create_pipeline, @project).to_s, "has-ci" => @repository.gitlab_ci_yml, "ci-lint-path" => ci_lint_path, - "reset-cache-path" => reset_cache_project_path(@project) } } + "reset-cache-path" => reset_cache_project_settings_ci_cd_path(@project) } } = page_specific_javascript_bundle_tag('common_vue') = page_specific_javascript_bundle_tag('pipelines') diff --git a/config/routes/project.rb b/config/routes/project.rb index d79c6e141c8..905c906b194 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -407,7 +407,9 @@ constraints(ProjectUrlConstrainer.new) do end namespace :settings do get :members, to: redirect("%{namespace_id}/%{project_id}/project_members") - resource :ci_cd, only: [:show], controller: 'ci_cd' + resource :ci_cd, only: [:show], controller: 'ci_cd' do + get :reset_cache + end resource :integrations, only: [:show] resource :repository, only: [:show], controller: :repository end @@ -436,7 +438,6 @@ constraints(ProjectUrlConstrainer.new) do get :download_export get :activity get :refs - get :reset_cache put :new_issuable_address end end diff --git a/spec/controllers/projects/settings/ci_cd_controller_spec.rb b/spec/controllers/projects/settings/ci_cd_controller_spec.rb index b8fe0f46f57..acd40f4a305 100644 --- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb +++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb @@ -17,4 +17,51 @@ describe Projects::Settings::CiCdController do expect(response).to render_template(:show) end end + + describe '#reset_cache' do + before do + sign_in(user) + + project.add_master(user) + + allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(true) + end + + subject { get :reset_cache, namespace_id: project.namespace, project_id: project } + + it 'calls reset project cache service' do + expect(ResetProjectCacheService).to receive_message_chain(:new, :execute) + + subject + end + + it 'redirects to project pipelines path' do + subject + + expect(response).to have_gitlab_http_status(:redirect) + expect(response).to redirect_to(project_pipelines_path(project)) + end + + context 'when service returns successfully' do + it 'sets the flash notice variable' do + subject + + expect(controller).to set_flash[:notice] + expect(controller).not_to set_flash[:error] + end + end + + context 'when service does not return successfully' do + before do + allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(false) + end + + it 'sets the flash error variable' do + subject + + expect(controller).not_to set_flash[:notice] + expect(controller).to set_flash[:error] + end + end + end end diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 2fc827742fe..e61187fb518 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -686,53 +686,6 @@ describe ProjectsController do end end - describe '#reset_cache' do - before do - sign_in(user) - - project.add_master(user) - - allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(true) - end - - subject { get :reset_cache, namespace_id: project.namespace, id: project } - - it 'calls reset project cache service' do - expect(ResetProjectCacheService).to receive_message_chain(:new, :execute) - - subject - end - - it 'redirects to project pipelines path' do - subject - - expect(response).to have_gitlab_http_status(:redirect) - expect(response).to redirect_to(project_pipelines_path(project)) - end - - context 'when service returns successfully' do - it 'sets the flash notice variable' do - subject - - expect(controller).to set_flash[:notice] - expect(controller).not_to set_flash[:error] - end - end - - context 'when service does not return successfully' do - before do - allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(false) - end - - it 'sets the flash error variable' do - subject - - expect(controller).not_to set_flash[:notice] - expect(controller).to set_flash[:error] - end - end - end - describe '#export' do before do sign_in(user) -- cgit v1.2.1 From 7d7d289b159fba332c68dc66b6f9f3b17428c3a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 4 Jan 2018 19:14:37 +0100 Subject: Add missing empty line in #reset_cache --- app/controllers/projects/settings/ci_cd_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb index 1dcebcb15a6..86717bb7242 100644 --- a/app/controllers/projects/settings/ci_cd_controller.rb +++ b/app/controllers/projects/settings/ci_cd_controller.rb @@ -17,6 +17,7 @@ module Projects else flash[:error] = _("Unable to reset project cache.") end + redirect_to project_pipelines_path(@project) end -- cgit v1.2.1 From 8cc14dd5371c33f389211fcee39dbb28686b2021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 4 Jan 2018 19:40:07 +0100 Subject: Rename Project#cache_index to jobs_cache_index --- app/models/ci/build.rb | 4 ++-- app/services/reset_project_cache_service.rb | 2 +- db/migrate/20171222183504_add_cache_index_to_project.rb | 13 ------------- .../20171222183504_add_jobs_cache_index_to_project.rb | 13 +++++++++++++ db/schema.rb | 2 +- spec/models/ci/build_spec.rb | 8 ++++---- spec/services/reset_project_cache_service_spec.rb | 8 ++++---- 7 files changed, 25 insertions(+), 25 deletions(-) delete mode 100644 db/migrate/20171222183504_add_cache_index_to_project.rb create mode 100644 db/migrate/20171222183504_add_jobs_cache_index_to_project.rb diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index e4ca74f87f2..ff903a63c54 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -461,8 +461,8 @@ module Ci end def cache - if options[:cache] && project.cache_index - options[:cache].merge(key: "#{options[:cache][:key]}:#{project.cache_index}") + if options[:cache] && project.jobs_cache_index + options[:cache].merge(key: "#{options[:cache][:key]}:#{project.jobs_cache_index}") else [options[:cache]] end diff --git a/app/services/reset_project_cache_service.rb b/app/services/reset_project_cache_service.rb index 0886c6b8315..a162a6eedb9 100644 --- a/app/services/reset_project_cache_service.rb +++ b/app/services/reset_project_cache_service.rb @@ -1,5 +1,5 @@ class ResetProjectCacheService < BaseService def execute - @project.increment!(:cache_index) + @project.increment!(:jobs_cache_index) end end diff --git a/db/migrate/20171222183504_add_cache_index_to_project.rb b/db/migrate/20171222183504_add_cache_index_to_project.rb deleted file mode 100644 index e1d73db1ab0..00000000000 --- a/db/migrate/20171222183504_add_cache_index_to_project.rb +++ /dev/null @@ -1,13 +0,0 @@ -# See http://doc.gitlab.com/ce/development/migration_style_guide.html -# for more information on how to write migrations for GitLab. - -class AddCacheIndexToProject < ActiveRecord::Migration - include Gitlab::Database::MigrationHelpers - - # Set this constant to true if this migration requires downtime. - DOWNTIME = false - - def change - add_column :projects, :cache_index, :integer - end -end diff --git a/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb b/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb new file mode 100644 index 00000000000..58ac0177420 --- /dev/null +++ b/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb @@ -0,0 +1,13 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddCacheIndexToProject < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + # Set this constant to true if this migration requires downtime. + DOWNTIME = false + + def change + add_column :projects, :jobs_cache_index, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index b7512f293a6..cd3f87062ab 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1447,7 +1447,7 @@ ActiveRecord::Schema.define(version: 20171222183504) do t.boolean "repository_read_only" t.boolean "merge_requests_ff_only_enabled", default: false t.boolean "merge_requests_rebase_enabled", default: false, null: false - t.integer "cache_index" + t.integer "jobs_cache_index" end add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 96513281994..8cecaf16fdf 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -265,17 +265,17 @@ describe Ci::Build do allow(build).to receive(:options).and_return(options) end - context 'when project has cache_index' do + context 'when project has jobs_cache_index' do before do - allow_any_instance_of(Project).to receive(:cache_index).and_return(1) + allow_any_instance_of(Project).to receive(:jobs_cache_index).and_return(1) end it { is_expected.to include(key: "key:1") } end - context 'when project does not have cache_index' do + context 'when project does not have jobs_cache_index' do before do - allow_any_instance_of(Project).to receive(:cache_index).and_return(nil) + allow_any_instance_of(Project).to receive(:jobs_cache_index).and_return(nil) end it { is_expected.to eq([options[:cache]]) } diff --git a/spec/services/reset_project_cache_service_spec.rb b/spec/services/reset_project_cache_service_spec.rb index df969d08f39..de475d16586 100644 --- a/spec/services/reset_project_cache_service_spec.rb +++ b/spec/services/reset_project_cache_service_spec.rb @@ -8,21 +8,21 @@ describe ResetProjectCacheService do context 'when project cache_index is nil' do before do - project.cache_index = nil + project.jobs_cache_index = nil end it 'sets project cache_index to one' do - expect { subject }.to change { project.reload.cache_index }.from(nil).to(1) + expect { subject }.to change { project.reload.jobs_cache_index }.from(nil).to(1) end end context 'when project cache_index is a numeric value' do before do - project.update_attributes(cache_index: 1) + project.update_attributes(jobs_cache_index: 1) end it 'increments project cache index' do - expect { subject }.to change { project.reload.cache_index }.by(1) + expect { subject }.to change { project.reload.jobs_cache_index }.by(1) end end end -- cgit v1.2.1 From 2682966829b49b7fbeee02e5c070c8c14630ea6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 4 Jan 2018 19:43:31 +0100 Subject: Refactor Ci::Build#cache --- app/models/ci/build.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index ff903a63c54..d0ee08ab086 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -461,11 +461,14 @@ module Ci end def cache - if options[:cache] && project.jobs_cache_index - options[:cache].merge(key: "#{options[:cache][:key]}:#{project.jobs_cache_index}") - else - [options[:cache]] + cache = options[:cache] + + if cache && project.jobs_cache_index + cache = cache.merge( + key: "#{cache[:key]}:#{project.jobs_cache_index}") end + + [cache] end def credentials -- cgit v1.2.1 From 0f137d8e9cc4b44ab11c549860bf27e7244ad09d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 4 Jan 2018 21:22:23 +0100 Subject: Fix faulty Ci::Build#cache spec --- spec/models/ci/build_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 8cecaf16fdf..3eaeeebf97d 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -270,7 +270,7 @@ describe Ci::Build do allow_any_instance_of(Project).to receive(:jobs_cache_index).and_return(1) end - it { is_expected.to include(key: "key:1") } + it { is_expected.to be_an(Array).and all(include(key: "key:1")) } end context 'when project does not have jobs_cache_index' do -- cgit v1.2.1 From 6d1548f86922d2489fd601c725a9748e3e563216 Mon Sep 17 00:00:00 2001 From: Winnie Hellmann Date: Wed, 3 Jan 2018 14:51:32 +0100 Subject: Fix Webpack config for ConcatenatedModule --- config/webpack.config.js | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/config/webpack.config.js b/config/webpack.config.js index 5f95255334c..95fa79990e2 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -1,5 +1,6 @@ 'use strict'; +var crypto = require('crypto'); var fs = require('fs'); var path = require('path'); var webpack = require('webpack'); @@ -179,15 +180,34 @@ var config = { if (chunk.name) { return chunk.name; } - return chunk.mapModules((m) => { + + const moduleNames = []; + + function collectModuleNames(m) { + // handle ConcatenatedModule which does not have resource nor context set + if (m.modules) { + m.modules.forEach(collectModuleNames); + return; + } + const pagesBase = path.join(ROOT_PATH, 'app/assets/javascripts/pages'); + if (m.resource.indexOf(pagesBase) === 0) { - return path.relative(pagesBase, m.resource) + moduleNames.push(path.relative(pagesBase, m.resource) .replace(/\/index\.[a-z]+$/, '') - .replace(/\//g, '__'); + .replace(/\//g, '__')); + } else { + moduleNames.push(path.relative(m.context, m.resource)); } - return path.relative(m.context, m.resource); - }).join('_'); + } + + chunk.forEachModule(collectModuleNames); + + const hash = crypto.createHash('sha256') + .update(moduleNames.join('_')) + .digest('hex'); + + return `${moduleNames[0]}-${hash.substr(0, 6)}`; }), // create cacheable common library bundle for all vue chunks -- cgit v1.2.1 From f01295a651ae8172823ce58031492d0b6d5220e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 4 Jan 2018 22:36:11 +0100 Subject: Ignore the Migration/Datetime cop in a migration that fix a column type to datetime_with_timezone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb b/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb index be18c5866ae..eeecc7b1de0 100644 --- a/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb +++ b/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb @@ -1,6 +1,6 @@ # See http://doc.gitlab.com/ce/development/migration_style_guide.html # for more information on how to write migrations for GitLab. - +# rubocop:disable Migration/Datetime class ScheduleIssuesClosedAtTypeChange < ActiveRecord::Migration include Gitlab::Database::MigrationHelpers -- cgit v1.2.1 From 5152cc3bfb8d60814063e86c3776030aa8891e0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Thu, 4 Jan 2018 19:27:37 -0300 Subject: Fix a bug where charlock_holmes was used needlessly to encode strings --- lib/gitlab/encoding_helper.rb | 26 ++++++++++++++++---------- lib/gitlab/git.rb | 2 +- spec/lib/gitlab/encoding_helper_spec.rb | 18 ++++++++++++++++++ 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/lib/gitlab/encoding_helper.rb b/lib/gitlab/encoding_helper.rb index 6b53eb4533d..c0edcabc6fd 100644 --- a/lib/gitlab/encoding_helper.rb +++ b/lib/gitlab/encoding_helper.rb @@ -14,14 +14,7 @@ module Gitlab ENCODING_CONFIDENCE_THRESHOLD = 50 def encode!(message) - return nil unless message.respond_to?(:force_encoding) - return message if message.encoding == Encoding::UTF_8 && message.valid_encoding? - - if message.respond_to?(:frozen?) && message.frozen? - message = message.dup - end - - message.force_encoding("UTF-8") + message = force_encode_utf8(message) return message if message.valid_encoding? # return message if message type is binary @@ -35,6 +28,8 @@ module Gitlab # encode and clean the bad chars message.replace clean(message) + rescue ArgumentError + return nil rescue encoding = detect ? detect[:encoding] : "unknown" "--broken encoding: #{encoding}" @@ -54,8 +49,8 @@ module Gitlab end def encode_utf8(message) - return nil unless message.is_a?(String) - return message if message.encoding == Encoding::UTF_8 && message.valid_encoding? + message = force_encode_utf8(message) + return message if message.valid_encoding? detect = CharlockHolmes::EncodingDetector.detect(message) if detect && detect[:encoding] @@ -69,6 +64,8 @@ module Gitlab else clean(message) end + rescue ArgumentError + return nil end def encode_binary(s) @@ -83,6 +80,15 @@ module Gitlab private + def force_encode_utf8(message) + raise ArgumentError unless message.respond_to?(:force_encoding) + return message if message.encoding == Encoding::UTF_8 && message.valid_encoding? + + message = message.dup if message.respond_to?(:frozen?) && message.frozen? + + message.force_encoding("UTF-8") + end + def clean(message) message.encode("UTF-16BE", undef: :replace, invalid: :replace, replace: "") .encode("UTF-8") diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb index 1f7c35cafaa..71647099f83 100644 --- a/lib/gitlab/git.rb +++ b/lib/gitlab/git.rb @@ -11,7 +11,7 @@ module Gitlab include Gitlab::EncodingHelper def ref_name(ref) - encode_utf8(ref).sub(/\Arefs\/(tags|heads|remotes)\//, '') + encode!(ref).sub(/\Arefs\/(tags|heads|remotes)\//, '') end def branch_name(ref) diff --git a/spec/lib/gitlab/encoding_helper_spec.rb b/spec/lib/gitlab/encoding_helper_spec.rb index 87ec2698fc1..4e9367323cb 100644 --- a/spec/lib/gitlab/encoding_helper_spec.rb +++ b/spec/lib/gitlab/encoding_helper_spec.rb @@ -120,6 +120,24 @@ describe Gitlab::EncodingHelper do it 'returns empty string on conversion errors' do expect { ext_class.encode_utf8('') }.not_to raise_error(ArgumentError) end + + context 'with strings that can be forcefully encoded into utf8' do + let(:test_string) do + "refs/heads/FixSymbolsTitleDropdown".encode("ASCII-8BIT") + end + let(:expected_string) do + "refs/heads/FixSymbolsTitleDropdown".encode("UTF-8") + end + + subject { ext_class.encode_utf8(test_string) } + + it "doesn't use CharlockHolmes if the encoding can be forced into utf_8" do + expect(CharlockHolmes::EncodingDetector).not_to receive(:detect) + + expect(subject).to eq(expected_string) + expect(subject.encoding.name).to eq('UTF-8') + end + end end describe '#clean' do -- cgit v1.2.1 From 6fb4a533b74c861a1e533604da462efb6d309de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 4 Jan 2018 23:33:17 +0100 Subject: Add feature test for resetting runner caches --- spec/features/projects/pipelines/pipelines_spec.rb | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index b87b47d0e1a..69a836292fc 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -545,6 +545,42 @@ describe 'Pipelines', :js do end end end + + describe 'Reset runner caches' do + let(:project) { create(:project, :repository) } + + before do + create(:ci_empty_pipeline, status: 'success', project: project, sha: project.commit.id, ref: 'master') + project.team << [user, :master] + visit project_pipelines_path(project) + end + + it 'has a clear caches button' do + expect(page).to have_link 'Clear runner caches' + end + + describe 'user clicks the button' do + subject { click_link 'Clear runner caches' } + + context 'when project already has jobs_cache_index' do + before do + project.update_attributes(jobs_cache_index: 1) + end + + it 'increments jobs_cache_index' do + expect { subject }.to change { project.reload.jobs_cache_index }.by(1) + expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.' + end + end + + context 'when project does not have jobs_cache_index' do + it 'sets jobs_cache_index to 1' do + expect { subject }.to change { project.reload.jobs_cache_index }.from(nil).to(1) + expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.' + end + end + end + end end context 'when user is not logged in' do -- cgit v1.2.1 From 93e9793ce38bb9b5d519f5ca86cb56201549ef19 Mon Sep 17 00:00:00 2001 From: Mayra Cabrera Date: Thu, 4 Jan 2018 22:35:41 +0000 Subject: Create Kubernetes based on Application Templates --- app/models/concerns/deployment_platform.rb | 47 ++++++++++++++ app/models/project.rb | 7 +-- app/models/service.rb | 5 ++ ...kubernetes-integration-application-template.yml | 5 ++ .../projects/import_export/export_file_spec.rb | 2 +- spec/models/concerns/deployment_platform_spec.rb | 73 ++++++++++++++++++++++ spec/models/project_spec.rb | 19 ------ spec/models/service_spec.rb | 8 +++ 8 files changed, 140 insertions(+), 26 deletions(-) create mode 100644 app/models/concerns/deployment_platform.rb create mode 100644 changelogs/unreleased/41056-create-cluster-from-kubernetes-integration-application-template.yml create mode 100644 spec/models/concerns/deployment_platform_spec.rb diff --git a/app/models/concerns/deployment_platform.rb b/app/models/concerns/deployment_platform.rb new file mode 100644 index 00000000000..e1373455e98 --- /dev/null +++ b/app/models/concerns/deployment_platform.rb @@ -0,0 +1,47 @@ +module DeploymentPlatform + def deployment_platform + @deployment_platform ||= find_cluster_platform_kubernetes + @deployment_platform ||= find_kubernetes_service_integration + @deployment_platform ||= build_cluster_and_deployment_platform + end + + private + + def find_cluster_platform_kubernetes + clusters.find_by(enabled: true)&.platform_kubernetes + end + + def find_kubernetes_service_integration + services.deployment.reorder(nil).find_by(active: true) + end + + def build_cluster_and_deployment_platform + return unless kubernetes_service_template + + cluster = ::Clusters::Cluster.create(cluster_attributes_from_service_template) + cluster.platform_kubernetes if cluster.persisted? + end + + def kubernetes_service_template + @kubernetes_service_template ||= KubernetesService.active.find_by_template + end + + def cluster_attributes_from_service_template + { + name: 'kubernetes-template', + projects: [self], + provider_type: :user, + platform_type: :kubernetes, + platform_kubernetes_attributes: platform_kubernetes_attributes_from_service_template + } + end + + def platform_kubernetes_attributes_from_service_template + { + api_url: kubernetes_service_template.api_url, + ca_pem: kubernetes_service_template.ca_pem, + token: kubernetes_service_template.token, + namespace: kubernetes_service_template.namespace + } + end +end diff --git a/app/models/project.rb b/app/models/project.rb index 9c0bbf697e2..5d6c1b30587 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -19,6 +19,7 @@ class Project < ActiveRecord::Base include Routable include GroupDescendant include Gitlab::SQL::Pattern + include DeploymentPlatform extend Gitlab::ConfigHelper extend Gitlab::CurrentSettings @@ -904,12 +905,6 @@ class Project < ActiveRecord::Base @ci_service ||= ci_services.reorder(nil).find_by(active: true) end - # TODO: This will be extended for multiple enviroment clusters - def deployment_platform - @deployment_platform ||= clusters.find_by(enabled: true)&.platform_kubernetes - @deployment_platform ||= services.where(category: :deployment).reorder(nil).find_by(active: true) - end - def monitoring_services services.where(category: :monitoring) end diff --git a/app/models/service.rb b/app/models/service.rb index 176b472e724..24ba3039707 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -44,6 +44,7 @@ class Service < ActiveRecord::Base scope :pipeline_hooks, -> { where(pipeline_events: true, active: true) } scope :wiki_page_hooks, -> { where(wiki_page_events: true, active: true) } scope :external_issue_trackers, -> { issue_trackers.active.without_defaults } + scope :deployment, -> { where(category: 'deployment') } default_value_for :category, 'common' @@ -271,6 +272,10 @@ class Service < ActiveRecord::Base nil end + def self.find_by_template + find_by(template: true) + end + private def cache_project_has_external_issue_tracker diff --git a/changelogs/unreleased/41056-create-cluster-from-kubernetes-integration-application-template.yml b/changelogs/unreleased/41056-create-cluster-from-kubernetes-integration-application-template.yml new file mode 100644 index 00000000000..2dd6fc5f1b5 --- /dev/null +++ b/changelogs/unreleased/41056-create-cluster-from-kubernetes-integration-application-template.yml @@ -0,0 +1,5 @@ +--- +title: Allow automatic creation of Kubernetes Integration from template +merge_request: 16104 +author: +type: added diff --git a/spec/features/projects/import_export/export_file_spec.rb b/spec/features/projects/import_export/export_file_spec.rb index 461aa39d0ad..6732cf61767 100644 --- a/spec/features/projects/import_export/export_file_spec.rb +++ b/spec/features/projects/import_export/export_file_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' # Integration test that exports a file using the Import/Export feature # 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+ +# we'll 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', :js do include Select2Helper diff --git a/spec/models/concerns/deployment_platform_spec.rb b/spec/models/concerns/deployment_platform_spec.rb new file mode 100644 index 00000000000..7bb89fe41dc --- /dev/null +++ b/spec/models/concerns/deployment_platform_spec.rb @@ -0,0 +1,73 @@ +require 'rails_helper' + +describe DeploymentPlatform do + let(:project) { create(:project) } + + describe '#deployment_platform' do + subject { project.deployment_platform } + + context 'with no Kubernetes configuration on CI/CD, no Kubernetes Service and a Kubernetes template configured' do + let!(:kubernetes_service) { create(:kubernetes_service, template: true) } + + it 'returns a platform kubernetes' do + expect(subject).to be_a_kind_of(Clusters::Platforms::Kubernetes) + end + + it 'creates a cluster and a platform kubernetes' do + expect { subject } + .to change { Clusters::Cluster.count }.by(1) + .and change { Clusters::Platforms::Kubernetes.count }.by(1) + end + + it 'includes appropriate attributes for Cluster' do + cluster = subject.cluster + expect(cluster.name).to eq('kubernetes-template') + expect(cluster.project).to eq(project) + expect(cluster.provider_type).to eq('user') + expect(cluster.platform_type).to eq('kubernetes') + end + + it 'creates a platform kubernetes' do + expect { subject }.to change { Clusters::Platforms::Kubernetes.count }.by(1) + end + + it 'copies attributes from Clusters::Platform::Kubernetes template into the new Cluster::Platforms::Kubernetes' do + expect(subject.api_url).to eq(kubernetes_service.api_url) + expect(subject.ca_pem).to eq(kubernetes_service.ca_pem) + expect(subject.token).to eq(kubernetes_service.token) + expect(subject.namespace).to eq(kubernetes_service.namespace) + end + end + + context 'with no Kubernetes configuration on CI/CD, no Kubernetes Service and no Kubernetes template configured' do + it { is_expected.to be_nil } + end + + context 'when user configured kubernetes from CI/CD > Clusters' do + let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } + let(:platform_kubernetes) { cluster.platform_kubernetes } + + it 'returns the Kubernetes platform' do + expect(subject).to eq(platform_kubernetes) + end + end + + context 'when user configured kubernetes integration from project services' do + let!(:kubernetes_service) { create(:kubernetes_service, project: project) } + + it 'returns the Kubernetes service' do + expect(subject).to eq(kubernetes_service) + end + end + + context 'when the cluster creation fails' do + let!(:kubernetes_service) { create(:kubernetes_service, template: true) } + + before do + allow_any_instance_of(Clusters::Cluster).to receive(:persisted?).and_return(false) + end + + it { is_expected.to be_nil } + end + end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index cea22bbd184..3c2ed043b82 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -3137,25 +3137,6 @@ describe Project do end end - describe '#deployment_platform' do - subject { project.deployment_platform } - - let(:project) { create(:project) } - - context 'when user configured kubernetes from Integration > Kubernetes' do - let!(:kubernetes_service) { create(:kubernetes_service, project: project) } - - it { is_expected.to eq(kubernetes_service) } - end - - context 'when user configured kubernetes from CI/CD > Clusters' do - let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } - let(:platform_kubernetes) { cluster.platform_kubernetes } - - it { is_expected.to eq(platform_kubernetes) } - end - end - describe '#write_repository_config' do set(:project) { create(:project, :repository) } diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index 540615de117..ab6678cab38 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -272,4 +272,12 @@ describe Service do expect(service.deprecation_message).to be_nil end end + + describe '.find_by_template' do + let!(:kubernetes_service) { create(:kubernetes_service, template: true) } + + it 'returns service template' do + expect(KubernetesService.find_by_template).to eq(kubernetes_service) + end + end end -- cgit v1.2.1 From 2cf2df8ea07703852247fdfbde73113d585aeb3d Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 4 Jan 2018 22:40:44 +0000 Subject: Update svg icons --- app/assets/images/icons.json | 2 +- app/assets/images/icons.svg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/images/icons.json b/app/assets/images/icons.json index 1a418c2f88b..38c1faccbf1 100644 --- a/app/assets/images/icons.json +++ b/app/assets/images/icons.json @@ -1 +1 @@ -{"iconCount":186,"spriteSize":84748,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o","folder-open","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-external","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","podcast","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]} +{"iconCount":186,"spriteSize":84748,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","bookmark","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder-o","folder-open","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-external","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","podcast","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]} \ No newline at end of file diff --git a/app/assets/images/icons.svg b/app/assets/images/icons.svg index b426700d315..42f5377a10e 100644 --- a/app/assets/images/icons.svg +++ b/app/assets/images/icons.svg @@ -1 +1 @@ - + \ No newline at end of file -- cgit v1.2.1 From 1859dc867092c1ba31335cf67047c9b6141466b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 5 Jan 2018 00:02:26 +0100 Subject: Add back bottom margins for integration form --- app/views/projects/clusters/_integration_form.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/clusters/_integration_form.html.haml b/app/views/projects/clusters/_integration_form.html.haml index 1eac2c9dc1f..9d593ffc021 100644 --- a/app/views/projects/clusters/_integration_form.html.haml +++ b/app/views/projects/clusters/_integration_form.html.haml @@ -1,6 +1,6 @@ = form_for @cluster, url: namespace_project_cluster_path(@project.namespace, @project, @cluster), as: :cluster do |field| = form_errors(@cluster) - .form-group + .form-group.append-bottom-20 %h5= s_('ClusterIntegration|Integration status') %p - if @cluster.enabled? @@ -10,7 +10,7 @@ = s_('ClusterIntegration|Cluster integration is enabled for this project.') - else = s_('ClusterIntegration|Cluster integration is disabled for this project.') - %label + %label.append-bottom-10 = field.hidden_field :enabled, { class: 'js-toggle-input'} %button{ type: 'button', -- cgit v1.2.1 From ccfd8a1240ddd4255f0dd561940d9325306d2a7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 5 Jan 2018 00:06:43 +0100 Subject: Remove GCP cluster check page placeholder --- app/views/projects/clusters/gcp/check.html.haml | 1 - 1 file changed, 1 deletion(-) delete mode 100644 app/views/projects/clusters/gcp/check.html.haml diff --git a/app/views/projects/clusters/gcp/check.html.haml b/app/views/projects/clusters/gcp/check.html.haml deleted file mode 100644 index e965047ad7c..00000000000 --- a/app/views/projects/clusters/gcp/check.html.haml +++ /dev/null @@ -1 +0,0 @@ -Hello -- cgit v1.2.1 From b4e9e07cdd5cbfdcbcf93c56a3b0b005602b40fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 5 Jan 2018 00:09:33 +0100 Subject: Remove polling interval from GcpController --- app/controllers/projects/clusters/gcp_controller.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/controllers/projects/clusters/gcp_controller.rb b/app/controllers/projects/clusters/gcp_controller.rb index 27c11ce554d..93b44623d3c 100644 --- a/app/controllers/projects/clusters/gcp_controller.rb +++ b/app/controllers/projects/clusters/gcp_controller.rb @@ -4,8 +4,6 @@ class Projects::Clusters::GcpController < Projects::ApplicationController before_action :authorize_google_project_billing, only: [:new] before_action :authorize_create_cluster!, only: [:new, :create] - STATUS_POLLING_INTERVAL = 1.minute.to_i - def login begin state = generate_session_key_redirect(gcp_new_namespace_project_clusters_path.to_s) -- cgit v1.2.1 From 92a72ce43749226a8dc75f7522d09125a5b4b8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 5 Jan 2018 00:10:40 +0100 Subject: Change CheckGcpProjectBillingWorker lease to 15s --- app/workers/check_gcp_project_billing_worker.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/workers/check_gcp_project_billing_worker.rb b/app/workers/check_gcp_project_billing_worker.rb index 254b0959063..5c3a4ff4a35 100644 --- a/app/workers/check_gcp_project_billing_worker.rb +++ b/app/workers/check_gcp_project_billing_worker.rb @@ -1,7 +1,7 @@ class CheckGcpProjectBillingWorker include ApplicationWorker - LEASE_TIMEOUT = 1.minute.to_i + LEASE_TIMEOUT = 15.seconds.to_i def self.redis_shared_state_key_for(token) "gitlab:gcp:#{token}:billing_enabled" -- cgit v1.2.1 From 7d1fdcdc836921d2f2324265752107519f47a6de Mon Sep 17 00:00:00 2001 From: Drew Blessing Date: Wed, 8 Nov 2017 15:32:12 -0600 Subject: Modify `LDAP::Person` to return username value based on attributes `Gitlab::LDAP::Person` did not respect the LDAP attributes username configuration and would simply return the uid value. There are cases where users would like to specify a different username field to allow more friendly GitLab usernames. For example, it's common in AD to have sAMAccountName be an employee ID like `A12345` while the local part of the email address is more human-friendly. --- changelogs/unreleased/ldap_username_attributes.yml | 5 ++ lib/gitlab/ldap/adapter.rb | 2 +- lib/gitlab/ldap/config.rb | 2 +- lib/gitlab/ldap/person.rb | 36 +++++++++-- spec/lib/gitlab/ldap/adapter_spec.rb | 10 ++- spec/lib/gitlab/ldap/person_spec.rb | 73 +++++++++++++++++++++- spec/lib/gitlab/o_auth/user_spec.rb | 20 ++++++ 7 files changed, 135 insertions(+), 13 deletions(-) create mode 100644 changelogs/unreleased/ldap_username_attributes.yml diff --git a/changelogs/unreleased/ldap_username_attributes.yml b/changelogs/unreleased/ldap_username_attributes.yml new file mode 100644 index 00000000000..89bbca58fc9 --- /dev/null +++ b/changelogs/unreleased/ldap_username_attributes.yml @@ -0,0 +1,5 @@ +--- +title: Modify `LDAP::Person` to return username value based on attributes +merge_request: +author: +type: fixed diff --git a/lib/gitlab/ldap/adapter.rb b/lib/gitlab/ldap/adapter.rb index 0afaa2306b5..76863e77dc3 100644 --- a/lib/gitlab/ldap/adapter.rb +++ b/lib/gitlab/ldap/adapter.rb @@ -74,7 +74,7 @@ module Gitlab def user_options(fields, value, limit) options = { - attributes: Gitlab::LDAP::Person.ldap_attributes(config).compact.uniq, + attributes: Gitlab::LDAP::Person.ldap_attributes(config), base: config.base } diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb index c8f19cd52d5..0d9a554fc18 100644 --- a/lib/gitlab/ldap/config.rb +++ b/lib/gitlab/ldap/config.rb @@ -148,7 +148,7 @@ module Gitlab def default_attributes { - 'username' => %w(uid userid sAMAccountName), + 'username' => %w(uid sAMAccountName userid), 'email' => %w(mail email userPrincipalName), 'name' => 'cn', 'first_name' => 'givenName', diff --git a/lib/gitlab/ldap/person.rb b/lib/gitlab/ldap/person.rb index 38d7a9ba2f5..e81cec6ba1a 100644 --- a/lib/gitlab/ldap/person.rb +++ b/lib/gitlab/ldap/person.rb @@ -6,6 +6,8 @@ module Gitlab # Source: http://ctogonewild.com/2009/09/03/bitmask-searches-in-ldap/ AD_USER_DISABLED = Net::LDAP::Filter.ex("userAccountControl:1.2.840.113556.1.4.803", "2") + InvalidEntryError = Class.new(StandardError) + attr_accessor :entry, :provider def self.find_by_uid(uid, adapter) @@ -29,11 +31,12 @@ module Gitlab def self.ldap_attributes(config) [ - 'dn', # Used in `dn` - config.uid, # Used in `uid` - *config.attributes['name'], # Used in `name` - *config.attributes['email'] # Used in `email` - ] + 'dn', + config.uid, + *config.attributes['name'], + *config.attributes['email'], + *config.attributes['username'] + ].compact.uniq end def self.normalize_dn(dn) @@ -60,6 +63,8 @@ module Gitlab Rails.logger.debug { "Instantiating #{self.class.name} with LDIF:\n#{entry.to_ldif}" } @entry = entry @provider = provider + + validate_entry end def name @@ -71,7 +76,13 @@ module Gitlab end def username - uid + username = attribute_value(:username) + + # Depending on the attribute, multiple values may + # be returned. We need only one for username. + # Ex. `uid` returns only one value but `mail` may + # return an array of multiple email addresses. + [username].flatten.first end def email @@ -104,6 +115,19 @@ module Gitlab entry.public_send(selected_attr) # rubocop:disable GitlabSecurity/PublicSend end + + def validate_entry + allowed_attrs = self.class.ldap_attributes(config).map(&:downcase) + + # Net::LDAP::Entry transforms keys to symbols. Change to strings to compare. + entry_attrs = entry.attribute_names.map { |n| n.to_s.downcase } + invalid_attrs = entry_attrs - allowed_attrs + + if invalid_attrs.any? + raise InvalidEntryError, + "#{self.class.name} initialized with Net::LDAP::Entry containing invalid attributes(s): #{invalid_attrs}" + end + end end end end diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb index d9ddb4326be..6132abd9b35 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 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{dn uid cn mail email userPrincipalName}) + expect(arg[:attributes]).to match(ldap_attributes) end.and_return({}) adapter.users('uid', 'johndoe') @@ -26,7 +26,7 @@ describe Gitlab::LDAP::Adapter do expect(adapter).to receive(:ldap_search).with( base: 'uid=johndoe,ou=users,dc=example,dc=com', scope: Net::LDAP::SearchScope_BaseObject, - attributes: %w{dn uid cn mail email userPrincipalName}, + attributes: ldap_attributes, filter: nil ).and_return({}) @@ -63,7 +63,7 @@ describe Gitlab::LDAP::Adapter 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{dn sAMAccountName cn mail email userPrincipalName}) + hash_including(attributes: ldap_attributes) ).and_return({}) adapter.users('sAMAccountName', 'johndoe') @@ -137,4 +137,8 @@ describe Gitlab::LDAP::Adapter do end end end + + def ldap_attributes + Gitlab::LDAP::Person.ldap_attributes(Gitlab::LDAP::Config.new('ldapmain')) + end end diff --git a/spec/lib/gitlab/ldap/person_spec.rb b/spec/lib/gitlab/ldap/person_spec.rb index d204050ef66..ff29d9aa5be 100644 --- a/spec/lib/gitlab/ldap/person_spec.rb +++ b/spec/lib/gitlab/ldap/person_spec.rb @@ -8,13 +8,16 @@ describe Gitlab::LDAP::Person do before do stub_ldap_config( options: { + 'uid' => 'uid', 'attributes' => { - 'name' => 'cn', - 'email' => %w(mail email userPrincipalName) + 'name' => 'cn', + 'email' => %w(mail email userPrincipalName), + 'username' => username_attribute } } ) end + let(:username_attribute) { %w(uid sAMAccountName userid) } describe '.normalize_dn' do subject { described_class.normalize_dn(given) } @@ -44,6 +47,34 @@ describe Gitlab::LDAP::Person do end end + describe '.ldap_attributes' do + it 'returns a compact and unique array' do + stub_ldap_config( + options: { + 'uid' => nil, + 'attributes' => { + 'name' => 'cn', + 'email' => 'mail', + 'username' => %w(uid mail memberof) + } + } + ) + config = Gitlab::LDAP::Config.new('ldapmain') + ldap_attributes = described_class.ldap_attributes(config) + + expect(ldap_attributes).to match_array(%w(dn uid cn mail memberof)) + end + end + + describe '.validate_entry' do + it 'raises InvalidEntryError' do + entry['foo'] = 'bar' + + expect { described_class.new(entry, 'ldapmain') } + .to raise_error(Gitlab::LDAP::Person::InvalidEntryError) + end + end + describe '#name' do it 'uses the configured name attribute and handles values as an array' do name = 'John Doe' @@ -72,6 +103,44 @@ describe Gitlab::LDAP::Person do end end + describe '#username' do + context 'with default uid username attribute' do + let(:username_attribute) { 'uid' } + + it 'returns the proper username value' do + attr_value = 'johndoe' + entry[username_attribute] = attr_value + person = described_class.new(entry, 'ldapmain') + + expect(person.username).to eq(attr_value) + end + end + + context 'with a different username attribute' do + let(:username_attribute) { 'sAMAccountName' } + + it 'returns the proper username value' do + attr_value = 'johndoe' + entry[username_attribute] = attr_value + person = described_class.new(entry, 'ldapmain') + + expect(person.username).to eq(attr_value) + end + end + + context 'with a non-standard username attribute' do + let(:username_attribute) { 'mail' } + + it 'returns the proper username value' do + attr_value = 'john.doe@example.com' + entry[username_attribute] = attr_value + person = described_class.new(entry, 'ldapmain') + + expect(person.username).to eq(attr_value) + end + end + end + def assert_generic_test(test_description, got, expected) test_failure_message = "Failed test description: '#{test_description}'\n\n expected: #{expected}\n got: #{got}" expect(got).to eq(expected), test_failure_message diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb index 6334bcd0156..45fff4c5787 100644 --- a/spec/lib/gitlab/o_auth/user_spec.rb +++ b/spec/lib/gitlab/o_auth/user_spec.rb @@ -275,6 +275,26 @@ describe Gitlab::OAuth::User do end end + context 'and a corresponding LDAP person with a non-default username' do + before do + allow(ldap_user).to receive(:uid) { uid } + allow(ldap_user).to receive(:username) { 'johndoe@example.com' } + allow(ldap_user).to receive(:email) { %w(johndoe@example.com john2@example.com) } + allow(ldap_user).to receive(:dn) { dn } + end + + context 'and no account for the LDAP user' do + it 'creates a user favoring the LDAP username and strips email domain' do + allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user) + + oauth_user.save + + expect(gl_user).to be_valid + expect(gl_user.username).to eql 'johndoe' + end + end + end + context "and no corresponding LDAP person" do before do allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(nil) -- cgit v1.2.1 From 27a590f901fc7504f70069d884c532e9a49a49e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 5 Jan 2018 00:37:00 +0100 Subject: Fix jobs_cache_index migration class name --- db/migrate/20171222183504_add_jobs_cache_index_to_project.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb b/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb index 58ac0177420..607e9d027d7 100644 --- a/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb +++ b/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb @@ -1,7 +1,7 @@ # See http://doc.gitlab.com/ce/development/migration_style_guide.html # for more information on how to write migrations for GitLab. -class AddCacheIndexToProject < ActiveRecord::Migration +class AddJobsCacheIndexToProject < ActiveRecord::Migration include Gitlab::Database::MigrationHelpers # Set this constant to true if this migration requires downtime. -- cgit v1.2.1 From 571db1a27fa9df038eb56a1c6ae049fc01b48a6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 5 Jan 2018 00:35:19 +0100 Subject: Return list of billing enabled projects --- app/services/check_gcp_project_billing_service.rb | 2 +- app/workers/check_gcp_project_billing_worker.rb | 4 ++-- spec/services/check_gcp_project_billing_service_spec.rb | 9 +++++---- spec/workers/check_gcp_project_billing_worker_spec.rb | 4 ++-- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/app/services/check_gcp_project_billing_service.rb b/app/services/check_gcp_project_billing_service.rb index 88e9d7de8de..854adf2177d 100644 --- a/app/services/check_gcp_project_billing_service.rb +++ b/app/services/check_gcp_project_billing_service.rb @@ -1,7 +1,7 @@ class CheckGcpProjectBillingService def execute(token) client = GoogleApi::CloudPlatform::Client.new(token, nil) - client.projects_list.any? do |project| + client.projects_list.select do |project| client.projects_get_billing_info(project.name).billingEnabled end end diff --git a/app/workers/check_gcp_project_billing_worker.rb b/app/workers/check_gcp_project_billing_worker.rb index 5c3a4ff4a35..8d80f9c9be3 100644 --- a/app/workers/check_gcp_project_billing_worker.rb +++ b/app/workers/check_gcp_project_billing_worker.rb @@ -11,9 +11,9 @@ class CheckGcpProjectBillingWorker return unless token return unless try_obtain_lease_for(token) - billing_enabled = CheckGcpProjectBillingService.new.execute(token) + billing_enabled_projects = CheckGcpProjectBillingService.new.execute(token) Gitlab::Redis::SharedState.with do |redis| - redis.set(self.class.redis_shared_state_key_for(token), billing_enabled) + redis.set(self.class.redis_shared_state_key_for(token), !billing_enabled_projects.empty?) end end diff --git a/spec/services/check_gcp_project_billing_service_spec.rb b/spec/services/check_gcp_project_billing_service_spec.rb index 1b23b43b0d5..f0e39ba6f49 100644 --- a/spec/services/check_gcp_project_billing_service_spec.rb +++ b/spec/services/check_gcp_project_billing_service_spec.rb @@ -2,13 +2,14 @@ require 'spec_helper' describe CheckGcpProjectBillingService do let(:service) { described_class.new } + let(:projects) { [double(name: 'first_project'), double(name: 'second_project')] } describe '#execute' do before do expect_any_instance_of(GoogleApi::CloudPlatform::Client) - .to receive(:projects_list).and_return([double(name: 'project_name')]) + .to receive(:projects_list).and_return(projects) - expect_any_instance_of(GoogleApi::CloudPlatform::Client) + allow_any_instance_of(GoogleApi::CloudPlatform::Client) .to receive_message_chain(:projects_get_billing_info, :billingEnabled) .and_return(project_billing_enabled) end @@ -18,13 +19,13 @@ describe CheckGcpProjectBillingService do context 'google account has a billing enabled gcp project' do let(:project_billing_enabled) { true } - it { is_expected.to eq(true) } + it { is_expected.to eq(projects) } end context 'google account does not have a billing enabled gcp project' do let(:project_billing_enabled) { false } - it { is_expected.to eq(false) } + it { is_expected.to eq([]) } end end end diff --git a/spec/workers/check_gcp_project_billing_worker_spec.rb b/spec/workers/check_gcp_project_billing_worker_spec.rb index d7984ad0c1b..cdb114749ee 100644 --- a/spec/workers/check_gcp_project_billing_worker_spec.rb +++ b/spec/workers/check_gcp_project_billing_worker_spec.rb @@ -11,7 +11,7 @@ describe CheckGcpProjectBillingWorker do end it 'calls the service' do - expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute) + expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute).and_return([double]) subject end @@ -19,7 +19,7 @@ describe CheckGcpProjectBillingWorker do it 'stores billing status in redis' do redis_double = double - expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute).and_return(true) + expect(CheckGcpProjectBillingService).to receive_message_chain(:new, :execute).and_return([double]) expect(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis_double) expect(redis_double).to receive(:set).with(described_class.redis_shared_state_key_for(token), anything) -- cgit v1.2.1 From f4c2eeb2a6885821f8b72f46deb49a55a062bd8c Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 4 Jan 2018 16:15:09 -0600 Subject: Fix custom name in branch creation for issue in Firefox Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/41563 `event.srcElement` is non-standard, https://developer.mozilla.org/en-US/docs/Web/API/Event/srcElement --- app/assets/javascripts/create_merge_request_dropdown.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/create_merge_request_dropdown.js b/app/assets/javascripts/create_merge_request_dropdown.js index 23425672b16..eedbd3feeb5 100644 --- a/app/assets/javascripts/create_merge_request_dropdown.js +++ b/app/assets/javascripts/create_merge_request_dropdown.js @@ -276,13 +276,13 @@ export default class CreateMergeRequestDropdown { let target; let value; - if (event.srcElement === this.branchInput) { + if (event.target === this.branchInput) { target = 'branch'; value = this.branchInput.value; - } else if (event.srcElement === this.refInput) { + } else if (event.target === this.refInput) { target = 'ref'; - value = event.srcElement.value.slice(0, event.srcElement.selectionStart) + - event.srcElement.value.slice(event.srcElement.selectionEnd); + value = event.target.value.slice(0, event.target.selectionStart) + + event.target.value.slice(event.target.selectionEnd); } else { return false; } -- cgit v1.2.1 From b27b1e60f0c7c718ae0502d380b1cb0c7fc15700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 5 Jan 2018 01:46:52 +0100 Subject: Rename cache_index in safe_model_attributes --- spec/lib/gitlab/import_export/safe_model_attributes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 7e09f486854..ec577903eb5 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -459,7 +459,7 @@ Project: - delete_error - merge_requests_ff_only_enabled - merge_requests_rebase_enabled -- cache_index +- jobs_cache_index Author: - name ProjectFeature: -- cgit v1.2.1 From 2b00c91a576f922e2f94756567d1e3601ce11248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 5 Jan 2018 03:11:04 +0100 Subject: Fix jobs cache reset functional spec --- spec/features/projects/pipelines/pipelines_spec.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index e8fc56ab11e..592c99fc64a 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -551,7 +551,7 @@ describe 'Pipelines', :js do before do create(:ci_empty_pipeline, status: 'success', project: project, sha: project.commit.id, ref: 'master') - project.team << [user, :master] + project.add_master(user) visit project_pipelines_path(project) end @@ -560,22 +560,20 @@ describe 'Pipelines', :js do end describe 'user clicks the button' do - subject { click_link 'Clear runner caches' } - context 'when project already has jobs_cache_index' do before do project.update_attributes(jobs_cache_index: 1) end it 'increments jobs_cache_index' do - expect { subject }.to change { project.reload.jobs_cache_index }.by(1) + click_link 'Clear runner caches' expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.' end end context 'when project does not have jobs_cache_index' do it 'sets jobs_cache_index to 1' do - expect { subject }.to change { project.reload.jobs_cache_index }.from(nil).to(1) + click_link 'Clear runner caches' expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.' end end -- cgit v1.2.1 From 8b3b28b8d81acc719701a3c2bfc05b6f7c22c4f2 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Fri, 5 Jan 2018 15:32:31 +0800 Subject: Just try to detect and assign once --- app/models/concerns/deployment_platform.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/models/concerns/deployment_platform.rb b/app/models/concerns/deployment_platform.rb index e1373455e98..89d0474a596 100644 --- a/app/models/concerns/deployment_platform.rb +++ b/app/models/concerns/deployment_platform.rb @@ -1,8 +1,9 @@ module DeploymentPlatform def deployment_platform - @deployment_platform ||= find_cluster_platform_kubernetes - @deployment_platform ||= find_kubernetes_service_integration - @deployment_platform ||= build_cluster_and_deployment_platform + @deployment_platform ||= + find_cluster_platform_kubernetes || + find_kubernetes_service_integration || + build_cluster_and_deployment_platform end private -- cgit v1.2.1 From 27a75ea1757d1c1b67bf501ec333221ed5e92d04 Mon Sep 17 00:00:00 2001 From: Jan Provaznik Date: Wed, 20 Dec 2017 10:01:21 +0100 Subject: Backport 'Rebase' feature from EE to CE When a project uses fast-forward merging strategy user has to rebase MRs to target branch before it can be merged. Now user can do rebase in UI by clicking 'Rebase' button instead of doing rebase locally. This feature was already present in EE, this is only backport of the feature to CE. Couple of changes: * removed rebase license check * renamed migration (changed timestamp) Closes #40301 --- .../components/states/mr_widget_rebase.vue | 133 ++++++++++++++++++++ .../vue_merge_request_widget/dependencies.js | 1 + .../vue_merge_request_widget/mr_widget_options.js | 3 + .../services/mr_widget_service.js | 4 + .../stores/get_state_key.js | 2 + .../stores/mr_widget_store.js | 8 ++ .../vue_merge_request_widget/stores/state_maps.js | 3 + .../projects/merge_requests_controller.rb | 17 +++ app/models/merge_request.rb | 9 +- app/models/repository.rb | 7 ++ app/presenters/merge_request_presenter.rb | 18 +++ app/serializers/merge_request_basic_entity.rb | 1 + app/serializers/merge_request_widget_entity.rb | 10 ++ app/services/merge_requests/rebase_service.rb | 30 +++++ .../merge_requests/working_copy_base_service.rb | 24 ++++ .../_merge_request_fast_forward_settings.html.haml | 2 +- .../_merge_request_rebase_settings.html.haml | 2 +- app/workers/all_queues.yml | 1 + app/workers/rebase_worker.rb | 12 ++ changelogs/unreleased/40301-rebase.yml | 5 + config/routes/project.rb | 1 + ...3729_add_rebase_commit_sha_to_merge_requests.rb | 7 ++ db/schema.rb | 3 +- .../project/merge_requests/fast_forward_merge.md | 4 +- .../project/merge_requests/img/ff_merge_mr.png | Bin 21380 -> 0 bytes .../project/merge_requests/img/ff_merge_rebase.png | Bin 0 -> 26945 bytes features/project/ff_merge_requests.feature | 17 +++ features/steps/project/ff_merge_requests.rb | 22 ++++ lib/gitlab/git/operation_service.rb | 5 + .../projects/merge_requests_controller_spec.rb | 58 +++++++++ .../api/schemas/entities/merge_request_basic.json | 1 + .../api/schemas/entities/merge_request_widget.json | 6 +- .../components/mr_widget_rebase_spec.js | 115 ++++++++++++++++++ spec/models/merge_request_spec.rb | 46 +++++++ spec/models/project_spec.rb | 19 ++- spec/presenters/merge_request_presenter_spec.rb | 63 ++++++++++ .../merge_request_widget_entity_spec.rb | 16 +++ .../services/merge_requests/rebase_service_spec.rb | 134 +++++++++++++++++++++ .../projects/merge_requests/show.html.haml_spec.rb | 2 + spec/workers/rebase_worker_spec.rb | 27 +++++ 40 files changed, 825 insertions(+), 13 deletions(-) create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue create mode 100644 app/services/merge_requests/rebase_service.rb create mode 100644 app/services/merge_requests/working_copy_base_service.rb create mode 100644 app/workers/rebase_worker.rb create mode 100644 changelogs/unreleased/40301-rebase.yml create mode 100644 db/migrate/20171230123729_add_rebase_commit_sha_to_merge_requests.rb delete mode 100644 doc/user/project/merge_requests/img/ff_merge_mr.png create mode 100644 doc/user/project/merge_requests/img/ff_merge_rebase.png create mode 100644 spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js create mode 100644 spec/services/merge_requests/rebase_service_spec.rb create mode 100644 spec/workers/rebase_worker_spec.rb diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue new file mode 100644 index 00000000000..09276ba2769 --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue @@ -0,0 +1,133 @@ + + diff --git a/app/assets/javascripts/vue_merge_request_widget/dependencies.js b/app/assets/javascripts/vue_merge_request_widget/dependencies.js index 5bd8b99420a..940f3d9b2d0 100644 --- a/app/assets/javascripts/vue_merge_request_widget/dependencies.js +++ b/app/assets/javascripts/vue_merge_request_widget/dependencies.js @@ -32,6 +32,7 @@ export { default as UnresolvedDiscussionsState } from './components/states/mr_wi export { default as PipelineBlockedState } from './components/states/mr_widget_pipeline_blocked'; export { default as PipelineFailedState } from './components/states/mr_widget_pipeline_failed'; export { default as MergeWhenPipelineSucceedsState } from './components/states/mr_widget_merge_when_pipeline_succeeds'; +export { default as RebaseState } from './components/states/mr_widget_rebase.vue'; export { default as AutoMergeFailed } from './components/states/mr_widget_auto_merge_failed'; export { default as CheckingState } from './components/states/mr_widget_checking'; export { default as MRWidgetStore } from './stores/mr_widget_store'; diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js index fdae06200de..2075f8e4fec 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.js @@ -10,6 +10,7 @@ import { MergedState, ClosedState, MergingState, + RebaseState, WipState, ArchivedState, ConflictsState, @@ -79,6 +80,7 @@ export default { ciEnvironmentsStatusPath: store.ciEnvironmentsStatusPath, statusPath: store.statusPath, mergeActionsContentPath: store.mergeActionsContentPath, + rebasePath: store.rebasePath, }; return new MRWidgetService(endpoints); }, @@ -232,6 +234,7 @@ export default { 'mr-widget-pipeline-failed': PipelineFailedState, 'mr-widget-merge-when-pipeline-succeeds': MergeWhenPipelineSucceedsState, 'mr-widget-auto-merge-failed': AutoMergeFailed, + 'mr-widget-rebase': RebaseState, }, template: `
diff --git a/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js b/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js index 7c0bbdd403f..fecbfec2214 100644 --- a/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js +++ b/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js @@ -37,6 +37,10 @@ export default class MRWidgetService { return axios.get(this.endpoints.mergeActionsContentPath); } + rebase() { + return axios.post(this.endpoints.rebasePath); + } + static stopEnvironment(url) { return axios.post(url); } diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js b/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js index 2bace3311c8..f7f0c1b6cb7 100644 --- a/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js +++ b/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js @@ -25,6 +25,8 @@ export default function deviseState(data) { return this.mergeError ? stateKey.autoMergeFailed : stateKey.mergeWhenPipelineSucceeds; } else if (!this.canMerge) { return stateKey.notAllowedToMerge; + } else if (this.shouldBeRebased) { + return stateKey.rebase; } else if (this.canBeMerged) { return stateKey.readyToMerge; } 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 474c17ec133..ed004b3bb08 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 @@ -26,6 +26,7 @@ export default class MergeRequestStore { this.divergedCommitsCount = data.diverged_commits_count; this.pipeline = data.pipeline || {}; this.deployments = this.deployments || data.deployments || []; + this.initRebase(data); if (data.issues_links) { const links = data.issues_links; @@ -124,6 +125,13 @@ export default class MergeRequestStore { return this.state === stateKey.nothingToMerge; } + initRebase(data) { + this.canPushToSourceBranch = data.can_push_to_source_branch; + this.rebaseInProgress = data.rebase_in_progress; + this.approvalsLeft = !data.approved; + this.rebasePath = data.rebase_path; + } + static buildMetrics(metrics) { if (!metrics) { return {}; diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js b/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js index de980c175fb..29d5bd4a1da 100644 --- a/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js +++ b/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js @@ -17,6 +17,7 @@ const stateToComponentMap = { failedToMerge: 'mr-widget-failed-to-merge', autoMergeFailed: 'mr-widget-auto-merge-failed', shaMismatch: 'mr-widget-sha-mismatch', + rebase: 'mr-widget-rebase', }; const statesToShowHelpWidget = [ @@ -29,6 +30,7 @@ const statesToShowHelpWidget = [ 'pipelineFailed', 'pipelineBlocked', 'autoMergeFailed', + 'rebase', ]; export const stateKey = { @@ -46,6 +48,7 @@ export const stateKey = { mergeWhenPipelineSucceeds: 'mergeWhenPipelineSucceeds', notAllowedToMerge: 'notAllowedToMerge', readyToMerge: 'readyToMerge', + rebase: 'rebase', }; export default { diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 6b59c8461a3..2e8a738b6d9 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -10,6 +10,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo before_action :authorize_update_issuable!, only: [:close, :edit, :update, :remove_wip, :sort] before_action :set_issuables_index, only: [:index] before_action :authenticate_user!, only: [:assign_related_issues] + before_action :check_user_can_push_to_source_branch!, only: [:rebase] def index @merge_requests = @issuables @@ -223,6 +224,12 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo render json: environments end + def rebase + RebaseWorker.perform_async(@merge_request.id, current_user.id) + + render nothing: true, status: 200 + end + protected alias_method :subscribable_resource, :merge_request @@ -322,4 +329,14 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo @finder_type = MergeRequestsFinder super end + + def check_user_can_push_to_source_branch! + return access_denied! unless @merge_request.source_branch_exists? + + access_check = ::Gitlab::UserAccess + .new(current_user, project: @merge_request.source_project) + .can_push_to_branch?(@merge_request.source_branch) + + access_denied! unless access_check + end end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index c39789b047d..ef58816937c 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -156,6 +156,13 @@ class MergeRequest < ActiveRecord::Base '!' end + def rebase_in_progress? + # The source project can be deleted + return false unless source_project + + source_project.repository.rebase_in_progress?(id) + end + # Use this method whenever you need to make sure the head_pipeline is synced with the # branch head commit, for example checking if a merge request can be merged. # For more information check: https://gitlab.com/gitlab-org/gitlab-ce/issues/40004 @@ -607,7 +614,7 @@ class MergeRequest < ActiveRecord::Base check_if_can_be_merged - can_be_merged? + can_be_merged? && !should_be_rebased? end def mergeable_state?(skip_ci_check: false) diff --git a/app/models/repository.rb b/app/models/repository.rb index b1fd981965c..4bedcbfb6a2 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1099,6 +1099,13 @@ class Repository @project.repository_storage_path end + def rebase(user, merge_request) + raw.rebase(user, merge_request.id, branch: merge_request.source_branch, + branch_sha: merge_request.source_branch_sha, + remote_repository: merge_request.target_project.repository.raw, + remote_branch: merge_request.target_branch) + end + private # TODO Generice finder, later split this on finders by Ref or Oid diff --git a/app/presenters/merge_request_presenter.rb b/app/presenters/merge_request_presenter.rb index ab4c87c0169..c6806b7cc26 100644 --- a/app/presenters/merge_request_presenter.rb +++ b/app/presenters/merge_request_presenter.rb @@ -76,6 +76,12 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated end end + def rebase_path + if !rebase_in_progress? && should_be_rebased? && user_can_push_to_source_branch? + rebase_project_merge_request_path(project, merge_request) + end + end + def target_branch_tree_path if target_branch_exists? project_tree_path(project, target_branch) @@ -152,6 +158,10 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated user_can_collaborate_with_project? && can_be_cherry_picked? end + def can_push_to_source_branch? + source_branch_exists? && user_can_push_to_source_branch? + end + private def conflicts @@ -174,6 +184,14 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated end.sort.to_sentence end + def user_can_push_to_source_branch? + return false unless source_branch_exists? + + ::Gitlab::UserAccess + .new(current_user, project: source_project) + .can_push_to_branch?(source_branch) + end + def user_can_collaborate_with_project? can?(current_user, :push_code, project) || (current_user && current_user.already_forked?(project)) diff --git a/app/serializers/merge_request_basic_entity.rb b/app/serializers/merge_request_basic_entity.rb index d54a6516aed..e4aec977f01 100644 --- a/app/serializers/merge_request_basic_entity.rb +++ b/app/serializers/merge_request_basic_entity.rb @@ -4,4 +4,5 @@ class MergeRequestBasicEntity < IssuableSidebarEntity expose :merge_error expose :state expose :source_branch_exists?, as: :source_branch_exists + expose :rebase_in_progress?, as: :rebase_in_progress end diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb index e905e6876c2..48cd2317f46 100644 --- a/app/serializers/merge_request_widget_entity.rb +++ b/app/serializers/merge_request_widget_entity.rb @@ -23,6 +23,16 @@ class MergeRequestWidgetEntity < IssuableEntity MergeRequestMetricsEntity.new(metrics).as_json end + expose :rebase_commit_sha + expose :rebase_in_progress?, as: :rebase_in_progress + + expose :can_push_to_source_branch do |merge_request| + presenter(merge_request).can_push_to_source_branch? + end + expose :rebase_path do |merge_request| + presenter(merge_request).rebase_path + end + # User entities expose :merge_user, using: UserEntity diff --git a/app/services/merge_requests/rebase_service.rb b/app/services/merge_requests/rebase_service.rb new file mode 100644 index 00000000000..0d5a25fa28e --- /dev/null +++ b/app/services/merge_requests/rebase_service.rb @@ -0,0 +1,30 @@ +module MergeRequests + class RebaseService < MergeRequests::WorkingCopyBaseService + def execute(merge_request) + @merge_request = merge_request + + if rebase + success + else + error('Failed to rebase. Should be done manually') + end + end + + def rebase + if merge_request.rebase_in_progress? + log_error('Rebase task canceled: Another rebase is already in progress', save_message_on_model: true) + return false + end + + rebase_sha = repository.rebase(current_user, merge_request) + + merge_request.update_attributes(rebase_commit_sha: rebase_sha) + + true + rescue => e + log_error('Failed to rebase branch:') + log_error(e.message, save_message_on_model: true) + false + end + end +end diff --git a/app/services/merge_requests/working_copy_base_service.rb b/app/services/merge_requests/working_copy_base_service.rb new file mode 100644 index 00000000000..186e05bf966 --- /dev/null +++ b/app/services/merge_requests/working_copy_base_service.rb @@ -0,0 +1,24 @@ +module MergeRequests + class WorkingCopyBaseService < MergeRequests::BaseService + attr_reader :merge_request + + def source_project + @source_project ||= merge_request.source_project + end + + def target_project + @target_project ||= merge_request.target_project + end + + def log_error(message, save_message_on_model: false) + Gitlab::GitLogger.error("#{self.class.name} error (#{merge_request.to_reference(full: true)}): #{message}") + + merge_request.update(merge_error: message) if save_message_on_model + end + + # Don't try to print expensive instance variables. + def inspect + "#<#{self.class} #{merge_request.to_reference(full: true)}>" + end + end +end diff --git a/app/views/projects/_merge_request_fast_forward_settings.html.haml b/app/views/projects/_merge_request_fast_forward_settings.html.haml index 9d357293a2f..8129c72feb2 100644 --- a/app/views/projects/_merge_request_fast_forward_settings.html.haml +++ b/app/views/projects/_merge_request_fast_forward_settings.html.haml @@ -10,4 +10,4 @@ No merge commits are created and all merges are fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded. %br %span.descr - When fast-forward merge is not possible, the user must first rebase locally. + When fast-forward merge is not possible, the user is given the option to rebase. diff --git a/app/views/projects/_merge_request_rebase_settings.html.haml b/app/views/projects/_merge_request_rebase_settings.html.haml index c52e09573a6..54e0b73d24c 100644 --- a/app/views/projects/_merge_request_rebase_settings.html.haml +++ b/app/views/projects/_merge_request_rebase_settings.html.haml @@ -10,4 +10,4 @@ This way you could make sure that if this merge request would build, after merging to target branch it would also build. %br %span.descr - When fast-forward merge is not possible, the user must first rebase locally. + When fast-forward merge is not possible, the user is given the option to rebase. diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index 268b7028fd9..fafd9e5ef00 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -89,6 +89,7 @@ - project_service - propagate_service_template - reactive_caching +- rebase - repository_fork - repository_import - storage_migrator diff --git a/app/workers/rebase_worker.rb b/app/workers/rebase_worker.rb new file mode 100644 index 00000000000..090987778a2 --- /dev/null +++ b/app/workers/rebase_worker.rb @@ -0,0 +1,12 @@ +class RebaseWorker + include ApplicationWorker + + def perform(merge_request_id, current_user_id) + current_user = User.find(current_user_id) + merge_request = MergeRequest.find(merge_request_id) + + MergeRequests::RebaseService + .new(merge_request.source_project, current_user) + .execute(merge_request) + end +end diff --git a/changelogs/unreleased/40301-rebase.yml b/changelogs/unreleased/40301-rebase.yml new file mode 100644 index 00000000000..1c0fc0cd8ae --- /dev/null +++ b/changelogs/unreleased/40301-rebase.yml @@ -0,0 +1,5 @@ +--- +title: Allow user to rebase merge requests. +merge_request: +author: +type: added diff --git a/config/routes/project.rb b/config/routes/project.rb index c3ad53a387f..1354c4c5537 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -96,6 +96,7 @@ constraints(ProjectUrlConstrainer.new) do post :toggle_subscription post :remove_wip post :assign_related_issues + post :rebase scope constraints: { format: nil }, action: :show do get :commits, defaults: { tab: 'commits' } diff --git a/db/migrate/20171230123729_add_rebase_commit_sha_to_merge_requests.rb b/db/migrate/20171230123729_add_rebase_commit_sha_to_merge_requests.rb new file mode 100644 index 00000000000..2ce156fa92e --- /dev/null +++ b/db/migrate/20171230123729_add_rebase_commit_sha_to_merge_requests.rb @@ -0,0 +1,7 @@ +class AddRebaseCommitShaToMergeRequests < ActiveRecord::Migration + DOWNTIME = false + + def change + add_column :merge_requests, :rebase_commit_sha, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 778d66f16b0..740e80ccfd4 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: 20171229225929) do +ActiveRecord::Schema.define(version: 20171230123729) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -1099,6 +1099,7 @@ ActiveRecord::Schema.define(version: 20171229225929) do t.string "merge_jid" t.boolean "discussion_locked" t.integer "latest_merge_request_diff_id" + t.string "rebase_commit_sha" end add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree diff --git a/doc/user/project/merge_requests/fast_forward_merge.md b/doc/user/project/merge_requests/fast_forward_merge.md index 085170d9f03..3cd91a185e3 100644 --- a/doc/user/project/merge_requests/fast_forward_merge.md +++ b/doc/user/project/merge_requests/fast_forward_merge.md @@ -9,7 +9,7 @@ When the fast-forward merge ([`--ff-only`][ffonly]) setting is enabled, no merge commits will be created and all merges are fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded. -When a fast-forward merge is not possible, the user must rebase the branch manually. +When a fast-forward merge is not possible, the user is given the option to rebase. ## Use cases @@ -25,7 +25,7 @@ merge commits. In such cases, the fast-forward merge is the perfect candidate. Now, when you visit the merge request page, you will be able to accept it **only if a fast-forward merge is possible**. -![Fast forward merge request](img/ff_merge_mr.png) +![Fast forward merge request](img/ff_merge_rebase.png) If the target branch is ahead of the source branch, you need to rebase the source branch locally before you will be able to do a fast-forward merge. diff --git a/doc/user/project/merge_requests/img/ff_merge_mr.png b/doc/user/project/merge_requests/img/ff_merge_mr.png deleted file mode 100644 index 241cc990343..00000000000 Binary files a/doc/user/project/merge_requests/img/ff_merge_mr.png and /dev/null differ diff --git a/doc/user/project/merge_requests/img/ff_merge_rebase.png b/doc/user/project/merge_requests/img/ff_merge_rebase.png new file mode 100644 index 00000000000..f6139f189ce Binary files /dev/null and b/doc/user/project/merge_requests/img/ff_merge_rebase.png differ diff --git a/features/project/ff_merge_requests.feature b/features/project/ff_merge_requests.feature index 995e52f9332..39035d551d1 100644 --- a/features/project/ff_merge_requests.feature +++ b/features/project/ff_merge_requests.feature @@ -22,3 +22,20 @@ Feature: Project Ff Merge Requests Then I should see ff-only merge button When I accept this merge request Then I should see merged request + + @javascript + Scenario: I do rebase before ff-only merge + Given ff merge enabled + And rebase before merge enabled + When I visit merge request page "Bug NS-05" + Then I should see rebase button + When I press rebase button + Then I should see rebase in progress message + + @javascript + Scenario: I do rebase before regular merge + Given rebase before merge enabled + When I visit merge request page "Bug NS-05" + Then I should see rebase button + When I press rebase button + Then I should see rebase in progress message diff --git a/features/steps/project/ff_merge_requests.rb b/features/steps/project/ff_merge_requests.rb index d68fe71e16e..27efcfd65b6 100644 --- a/features/steps/project/ff_merge_requests.rb +++ b/features/steps/project/ff_merge_requests.rb @@ -17,6 +17,10 @@ class Spinach::Features::ProjectFfMergeRequests < Spinach::FeatureSteps author: project.users.first) end + step 'merge request is mergeable' do + expect(page).to have_button 'Merge' + end + step 'I should see ff-only merge button' do expect(page).to have_content "Fast-forward merge without a merge commit" expect(page).to have_button 'Merge' @@ -45,6 +49,10 @@ class Spinach::Features::ProjectFfMergeRequests < Spinach::FeatureSteps project.save! end + step 'I should see rebase button' do + expect(page).to have_button "Rebase" + end + step 'merge request "Bug NS-05" is rebased' do merge_request.source_branch = 'flatten-dir' merge_request.target_branch = 'improve/awesome' @@ -59,6 +67,20 @@ class Spinach::Features::ProjectFfMergeRequests < Spinach::FeatureSteps merge_request.save! end + step 'rebase before merge enabled' do + project = merge_request.target_project + project.merge_requests_rebase_enabled = true + project.save! + end + + step 'I press rebase button' do + click_button "Rebase" + end + + step "I should see rebase in progress message" do + expect(page).to have_content("Rebase in progress") + end + def merge_request @merge_request ||= MergeRequest.find_by!(title: "Bug NS-05") end diff --git a/lib/gitlab/git/operation_service.rb b/lib/gitlab/git/operation_service.rb index ef5bdbaf819..3fb0e2eed93 100644 --- a/lib/gitlab/git/operation_service.rb +++ b/lib/gitlab/git/operation_service.rb @@ -97,6 +97,11 @@ module Gitlab end end + def update_branch(branch_name, newrev, oldrev) + ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name + update_ref_in_hooks(ref, newrev, oldrev) + end + private # Returns [newrev, should_run_after_create, should_run_after_create_branch] diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 45c424af8c4..c8cc6b374f6 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -684,4 +684,62 @@ describe Projects::MergeRequestsController do format: :json end end + + describe 'POST #rebase' do + let(:viewer) { user } + + def post_rebase + post :rebase, namespace_id: project.namespace, project_id: project, id: merge_request + end + + def expect_rebase_worker_for(user) + expect(RebaseWorker).to receive(:perform_async).with(merge_request.id, user.id) + end + + context 'successfully' do + it 'enqeues a RebaseWorker' do + expect_rebase_worker_for(viewer) + + post_rebase + + expect(response.status).to eq(200) + end + end + + context 'with a forked project' do + let(:fork_project) { create(:project, :repository, forked_from_project: project) } + let(:fork_owner) { fork_project.owner } + + before do + merge_request.update!(source_project: fork_project) + fork_project.add_reporter(user) + end + + context 'user cannot push to source branch' do + it 'returns 404' do + expect_rebase_worker_for(viewer).never + + post_rebase + + expect(response.status).to eq(404) + end + end + + context 'user can push to source branch' do + before do + project.add_reporter(fork_owner) + + sign_in(fork_owner) + end + + it 'returns 200' do + expect_rebase_worker_for(fork_owner) + + post_rebase + + expect(response.status).to eq(200) + end + end + end + end end diff --git a/spec/fixtures/api/schemas/entities/merge_request_basic.json b/spec/fixtures/api/schemas/entities/merge_request_basic.json index 995f13381ad..f1199468d53 100644 --- a/spec/fixtures/api/schemas/entities/merge_request_basic.json +++ b/spec/fixtures/api/schemas/entities/merge_request_basic.json @@ -9,6 +9,7 @@ "human_time_estimate": { "type": ["string", "null"] }, "human_total_time_spent": { "type": ["string", "null"] }, "merge_error": { "type": ["string", "null"] }, + "rebase_in_progress": { "type": "boolean" }, "assignee_id": { "type": ["integer", "null"] }, "subscribed": { "type": ["boolean", "null"] }, "participants": { "type": "array" } diff --git a/spec/fixtures/api/schemas/entities/merge_request_widget.json b/spec/fixtures/api/schemas/entities/merge_request_widget.json index 9de27bee751..7f662098216 100644 --- a/spec/fixtures/api/schemas/entities/merge_request_widget.json +++ b/spec/fixtures/api/schemas/entities/merge_request_widget.json @@ -103,7 +103,11 @@ "remove_source_branch": { "type": ["boolean", "null"] }, "merge_ongoing": { "type": "boolean" }, "ff_only_enabled": { "type": ["boolean", false] }, - "should_be_rebased": { "type": "boolean" } + "should_be_rebased": { "type": "boolean" }, + "rebase_commit_sha": { "type": ["string", "null"] }, + "rebase_in_progress": { "type": "boolean" }, + "can_push_to_source_branch": { "type": "boolean" }, + "rebase_path": { "type": ["string", "null"] } }, "additionalProperties": false } diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js new file mode 100644 index 00000000000..66ecaa316c8 --- /dev/null +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_rebase_spec.js @@ -0,0 +1,115 @@ +import Vue from 'vue'; +import eventHub from '~/vue_merge_request_widget/event_hub'; +import component from '~/vue_merge_request_widget/components/states/mr_widget_rebase.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; + +describe('Merge request widget rebase component', () => { + let Component; + let vm; + beforeEach(() => { + Component = Vue.extend(component); + }); + + afterEach(() => { + vm.$destroy(); + }); + + describe('While rebasing', () => { + it('should show progress message', () => { + vm = mountComponent(Component, { + mr: { rebaseInProgress: true }, + service: {}, + }); + + expect( + vm.$el.querySelector('.rebase-state-find-class-convention span').textContent.trim(), + ).toContain('Rebase in progress'); + }); + }); + + describe('With permissions', () => { + beforeEach(() => { + vm = mountComponent(Component, { + mr: { + rebaseInProgress: false, + canPushToSourceBranch: true, + }, + service: {}, + }); + }); + + it('it should render rebase button and warning message', () => { + const text = vm.$el.querySelector('.rebase-state-find-class-convention span').textContent.trim(); + expect(text).toContain('Fast-forward merge is not possible.'); + expect(text).toContain('Rebase the source branch onto the target branch or merge target'); + expect(text).toContain('branch into source branch to allow this merge request to be merged.'); + }); + + it('it should render error message when it fails', (done) => { + vm.rebasingError = 'Something went wrong!'; + + Vue.nextTick(() => { + expect( + vm.$el.querySelector('.rebase-state-find-class-convention span').textContent.trim(), + ).toContain('Something went wrong!'); + done(); + }); + }); + }); + + describe('Without permissions', () => { + it('should render a message explaining user does not have permissions', () => { + vm = mountComponent(Component, { + mr: { + rebaseInProgress: false, + canPushToSourceBranch: false, + targetBranch: 'foo', + }, + service: {}, + }); + + const text = vm.$el.querySelector('.rebase-state-find-class-convention span').textContent.trim(); + + expect(text).toContain('Fast-forward merge is not possible.'); + expect(text).toContain('Rebase the source branch onto'); + expect(text).toContain('foo'); + expect(text).toContain('to allow this merge request to be merged.'); + }); + }); + + describe('methods', () => { + it('checkRebaseStatus', (done) => { + spyOn(eventHub, '$emit'); + vm = mountComponent(Component, { + mr: {}, + service: { + rebase() { + return Promise.resolve(); + }, + poll() { + return Promise.resolve({ + data: { + rebase_in_progress: false, + merge_error: null, + }, + }); + }, + }, + }); + + vm.rebase(); + + // Wait for the rebase request + vm.$nextTick() + // Wait for the polling request + .then(vm.$nextTick()) + // Wait for the eventHub to be called + .then(vm.$nextTick()) + .then(() => { + expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested'); + }) + .then(done) + .catch(done.fail); + }); + }); +}); diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index d8ebd46faab..07b3e1c1758 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1903,4 +1903,50 @@ describe MergeRequest do end end end + + describe '#should_be_rebased?' do + let(:project) { create(:project, :repository) } + + it 'returns false for the same source and target branches' do + merge_request = create(:merge_request, source_project: project, target_project: project) + + expect(merge_request.should_be_rebased?).to be_falsey + end + end + + describe '#rebase_in_progress?' do + # Create merge request and project before we stub file calls + before do + subject + end + + it 'returns true when there is a current rebase directory' do + allow(File).to receive(:exist?).and_return(true) + allow(File).to receive(:mtime).and_return(Time.now) + + expect(subject.rebase_in_progress?).to be_truthy + end + + it 'returns false when there is no rebase directory' do + allow(File).to receive(:exist?).and_return(false) + + expect(subject.rebase_in_progress?).to be_falsey + end + + it 'returns false when the rebase directory has expired' do + allow(File).to receive(:exist?).and_return(true) + allow(File).to receive(:mtime).and_return(20.minutes.ago) + + expect(subject.rebase_in_progress?).to be_falsey + end + + it 'returns false when the source project has been removed' do + allow(subject).to receive(:source_project).and_return(nil) + allow(File).to receive(:exist?).and_return(true) + allow(File).to receive(:mtime).and_return(Time.now) + + expect(File).not_to have_received(:exist?) + expect(subject.rebase_in_progress?).to be_falsey + end + end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 3c2ed043b82..13e5345ee4c 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -418,14 +418,21 @@ describe Project do end describe '#merge_method' do - it 'returns "ff" merge_method when ff is enabled' do - project = build(:project, merge_requests_ff_only_enabled: true) - expect(project.merge_method).to be :ff + using RSpec::Parameterized::TableSyntax + + where(:ff, :rebase, :method) do + true | true | :ff + true | false | :ff + false | true | :rebase_merge + false | false | :merge end - it 'returns "merge" merge_method when ff is disabled' do - project = build(:project, merge_requests_ff_only_enabled: false) - expect(project.merge_method).to be :merge + with_them do + let(:project) { build(:project, merge_requests_rebase_enabled: rebase, merge_requests_ff_only_enabled: ff) } + + subject { project.merge_method } + + it { is_expected.to eq(method) } end end diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb index 969c4753f33..e3b37739e8e 100644 --- a/spec/presenters/merge_request_presenter_spec.rb +++ b/spec/presenters/merge_request_presenter_spec.rb @@ -404,4 +404,67 @@ describe MergeRequestPresenter do .to eq("#{resource.source_branch}") end end + + describe '#rebase_path' do + before do + allow(resource).to receive(:rebase_in_progress?) { rebase_in_progress } + allow(resource).to receive(:should_be_rebased?) { should_be_rebased } + + allow_any_instance_of(Gitlab::UserAccess::RequestCacheExtension) + .to receive(:can_push_to_branch?) + .with(resource.source_branch) + .and_return(can_push_to_branch) + end + + subject do + described_class.new(resource, current_user: user).rebase_path + end + + context 'when can rebase' do + let(:rebase_in_progress) { false } + let(:can_push_to_branch) { true } + let(:should_be_rebased) { true } + + before do + allow(resource).to receive(:source_branch_exists?) { true } + end + + it 'returns path' do + is_expected + .to eq("/#{project.full_path}/merge_requests/#{resource.iid}/rebase") + end + end + + context 'when cannot rebase' do + context 'when rebase in progress' do + let(:rebase_in_progress) { true } + let(:can_push_to_branch) { true } + let(:should_be_rebased) { true } + + it 'returns nil' do + is_expected.to be_nil + end + end + + context 'when user cannot merge' do + let(:rebase_in_progress) { false } + let(:can_push_to_branch) { false } + let(:should_be_rebased) { true } + + it 'returns nil' do + is_expected.to be_nil + end + end + + context 'should not be rebased' do + let(:rebase_in_progress) { false } + let(:can_push_to_branch) { true } + let(:should_be_rebased) { false } + + it 'returns nil' do + is_expected.to be_nil + end + end + end + end end diff --git a/spec/serializers/merge_request_widget_entity_spec.rb b/spec/serializers/merge_request_widget_entity_spec.rb index e25552eb0d8..80a271ba7fb 100644 --- a/spec/serializers/merge_request_widget_entity_spec.rb +++ b/spec/serializers/merge_request_widget_entity_spec.rb @@ -190,4 +190,20 @@ describe MergeRequestWidgetEntity do end end end + + describe 'when source project is deleted' do + let(:project) { create(:project, :repository) } + let(:fork_project) { create(:project, :repository, forked_from_project: project) } + let(:merge_request) { create(:merge_request, source_project: fork_project, target_project: project) } + + it 'returns a blank rebase_path' do + allow(merge_request).to receive(:should_be_rebased?).and_return(true) + fork_project.destroy + merge_request.reload + + entity = described_class.new(merge_request, request: request).as_json + + expect(entity[:rebase_path]).to be_nil + end + end end diff --git a/spec/services/merge_requests/rebase_service_spec.rb b/spec/services/merge_requests/rebase_service_spec.rb new file mode 100644 index 00000000000..d1b37cdd073 --- /dev/null +++ b/spec/services/merge_requests/rebase_service_spec.rb @@ -0,0 +1,134 @@ +require 'spec_helper' + +describe MergeRequests::RebaseService do + include ProjectForksHelper + + let(:user) { create(:user) } + let(:merge_request) do + create(:merge_request, + source_branch: 'feature_conflict', + target_branch: 'master') + end + let(:project) { merge_request.project } + let(:repository) { project.repository.raw } + + subject(:service) { described_class.new(project, user, {}) } + + before do + project.add_master(user) + end + + describe '#execute' do + context 'when another rebase is already in progress' do + before do + allow(merge_request).to receive(:rebase_in_progress?).and_return(true) + end + + it 'saves the error message' do + subject.execute(merge_request) + + expect(merge_request.reload.merge_error).to eq 'Rebase task canceled: Another rebase is already in progress' + end + + it 'returns an error' do + expect(service.execute(merge_request)).to match(status: :error, + message: 'Failed to rebase. Should be done manually') + end + end + + context 'when unexpected error occurs' do + before do + allow(repository).to receive(:run_git!).and_raise('Something went wrong') + end + + it 'saves the error message' do + subject.execute(merge_request) + + expect(merge_request.reload.merge_error).to eq 'Something went wrong' + end + + it 'returns an error' do + expect(service.execute(merge_request)).to match(status: :error, + message: 'Failed to rebase. Should be done manually') + end + end + + context 'with git command failure' do + before do + allow(repository).to receive(:run_git!).and_raise(Gitlab::Git::Repository::GitError, 'Something went wrong') + end + + it 'saves the error message' do + subject.execute(merge_request) + + expect(merge_request.reload.merge_error).to eq 'Something went wrong' + end + + it 'returns an error' do + expect(service.execute(merge_request)).to match(status: :error, + message: 'Failed to rebase. Should be done manually') + end + end + + context 'valid params' do + before do + service.execute(merge_request) + end + + it 'rebases source branch' do + parent_sha = merge_request.source_project.repository.commit(merge_request.source_branch).parents.first.sha + target_branch_sha = merge_request.target_project.repository.commit(merge_request.target_branch).sha + expect(parent_sha).to eq(target_branch_sha) + end + + it 'records the new SHA on the merge request' do + head_sha = merge_request.source_project.repository.commit(merge_request.source_branch).sha + expect(merge_request.reload.rebase_commit_sha).to eq(head_sha) + end + + it 'logs correct author and commiter' do + head_commit = merge_request.source_project.repository.commit(merge_request.source_branch) + + expect(head_commit.author_email).to eq('dmitriy.zaporozhets@gmail.com') + expect(head_commit.author_name).to eq('Dmitriy Zaporozhets') + expect(head_commit.committer_email).to eq(user.email) + expect(head_commit.committer_name).to eq(user.name) + end + + context 'git commands' do + it 'sets GL_REPOSITORY env variable when calling git commands' do + expect(repository).to receive(:popen).exactly(3) + .with(anything, anything, hash_including('GL_REPOSITORY')) + .and_return(['', 0]) + + service.execute(merge_request) + end + end + + context 'fork' do + let(:forked_project) do + fork_project(project, user, repository: true) + end + + let(:merge_request_from_fork) do + forked_project.repository.create_file( + user, + 'new-file-to-target', + '', + message: 'Add new file to target', + branch_name: 'master') + + create(:merge_request, + source_branch: 'master', source_project: forked_project, + target_branch: 'master', target_project: project) + end + + it 'rebases source branch' do + parent_sha = forked_project.repository.commit(merge_request_from_fork.source_branch).parents.first.sha + target_branch_sha = project.repository.commit(merge_request_from_fork.target_branch).sha + expect(parent_sha).to eq(target_branch_sha) + end + end + end + end +end diff --git a/spec/views/projects/merge_requests/show.html.haml_spec.rb b/spec/views/projects/merge_requests/show.html.haml_spec.rb index 28d54c2fb77..264e0ce0b40 100644 --- a/spec/views/projects/merge_requests/show.html.haml_spec.rb +++ b/spec/views/projects/merge_requests/show.html.haml_spec.rb @@ -54,6 +54,8 @@ describe 'projects/merge_requests/show.html.haml' do it 'closes the merge request if the source project does not exist' do closed_merge_request.update_attributes(state: 'open') forked_project.destroy + # Reload merge request so MergeRequest#source_project turns to `nil` + closed_merge_request.reload render diff --git a/spec/workers/rebase_worker_spec.rb b/spec/workers/rebase_worker_spec.rb new file mode 100644 index 00000000000..20aff020dbb --- /dev/null +++ b/spec/workers/rebase_worker_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe RebaseWorker, '#perform' do + context 'when rebasing an MR from a fork where upstream has protected branches' do + let(:upstream_project) { create(:project, :repository) } + let(:fork_project) { create(:project, :repository) } + + let(:merge_request) do + create(:merge_request, + source_project: fork_project, + source_branch: 'feature_conflict', + target_project: upstream_project, + target_branch: 'master') + end + + before do + create(:forked_project_link, forked_to_project: fork_project, forked_from_project: upstream_project) + end + + it 'sets the correct project for running hooks' do + expect(MergeRequests::RebaseService) + .to receive(:new).with(fork_project, merge_request.author).and_call_original + + subject.perform(merge_request, merge_request.author) + end + end +end -- cgit v1.2.1 From 304851dc90c06d770042bf3cb0af887b6f3497e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarka=20Kadlecova=CC=81?= Date: Thu, 4 Jan 2018 13:29:48 +0100 Subject: Refactor RelativePositioning so that it can be used by other classes --- app/models/concerns/relative_positioning.rb | 18 +++++++++++------- app/models/issue.rb | 6 ++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/app/models/concerns/relative_positioning.rb b/app/models/concerns/relative_positioning.rb index 835f26aa57b..afacdb8cb12 100644 --- a/app/models/concerns/relative_positioning.rb +++ b/app/models/concerns/relative_positioning.rb @@ -10,12 +10,12 @@ module RelativePositioning after_save :save_positionable_neighbours end - def project_ids - [project.id] + def min_relative_position + self.class.in_parents(parent_ids).minimum(:relative_position) end def max_relative_position - self.class.in_projects(project_ids).maximum(:relative_position) + self.class.in_parents(parent_ids).maximum(:relative_position) end def prev_relative_position @@ -23,7 +23,7 @@ module RelativePositioning if self.relative_position prev_pos = self.class - .in_projects(project_ids) + .in_parents(parent_ids) .where('relative_position < ?', self.relative_position) .maximum(:relative_position) end @@ -36,7 +36,7 @@ module RelativePositioning if self.relative_position next_pos = self.class - .in_projects(project_ids) + .in_parents(parent_ids) .where('relative_position > ?', self.relative_position) .minimum(:relative_position) end @@ -63,7 +63,7 @@ module RelativePositioning pos_after = before.next_relative_position if before.shift_after? - issue_to_move = self.class.in_projects(project_ids).find_by!(relative_position: pos_after) + issue_to_move = self.class.in_parents(parent_ids).find_by!(relative_position: pos_after) issue_to_move.move_after @positionable_neighbours = [issue_to_move] # rubocop:disable Gitlab/ModuleWithInstanceVariables @@ -78,7 +78,7 @@ module RelativePositioning pos_before = after.prev_relative_position if after.shift_before? - issue_to_move = self.class.in_projects(project_ids).find_by!(relative_position: pos_before) + issue_to_move = self.class.in_parents(parent_ids).find_by!(relative_position: pos_before) issue_to_move.move_before @positionable_neighbours = [issue_to_move] # rubocop:disable Gitlab/ModuleWithInstanceVariables @@ -92,6 +92,10 @@ module RelativePositioning self.relative_position = position_between(max_relative_position || START_POSITION, MAX_POSITION) end + def move_to_start + self.relative_position = position_between(min_relative_position || START_POSITION, MIN_POSITION) + end + # Indicates if there is an issue that should be shifted to free the place def shift_after? next_pos = next_relative_position diff --git a/app/models/issue.rb b/app/models/issue.rb index 4eafc1316d6..f2d111ba926 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -35,6 +35,8 @@ class Issue < ActiveRecord::Base validates :project, presence: true + alias_attribute :parent_id, :project_id + scope :in_projects, ->(project_ids) { where(project_id: project_ids) } scope :assigned, -> { where('EXISTS (SELECT TRUE FROM issue_assignees WHERE issue_id = issues.id)') } @@ -78,6 +80,10 @@ class Issue < ActiveRecord::Base acts_as_paranoid + class << self + alias_method :in_parents, :in_projects + end + def self.reference_prefix '#' end -- cgit v1.2.1 From 6b15784ce7d893ed509c00d9f51a4702787799ed Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Fri, 5 Jan 2018 09:41:05 +0000 Subject: Fix typos in a code comment --- lib/gitlab/git/blob.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb index bd91125d3b6..a1755143abe 100644 --- a/lib/gitlab/git/blob.rb +++ b/lib/gitlab/git/blob.rb @@ -138,8 +138,8 @@ module Gitlab # Gitaly will think that setting the limit to 0 means unlimited, while # the client might only need the metadata and thus set the limit to 0. - # In this method we'll than set the limit to 1, but clear the byte of data - # that we got back so fot the outside world it looks like the limit was + # In this method we'll then set the limit to 1, but clear the byte of data + # that we got back so for the outside world it looks like the limit was # actually 0. req_limit = limit == 0 ? 1 : limit -- cgit v1.2.1 From 3514b7248cf00bcee8a6b3133e4e157f656d30c6 Mon Sep 17 00:00:00 2001 From: Alessio Caiazza Date: Tue, 13 Jun 2017 22:03:34 +0200 Subject: Add status attribute to runner api entity --- .../unreleased/feature-api_runners_online.yml | 5 +++-- doc/api/runners.md | 23 ++++++++++++++++------ lib/api/entities.rb | 1 + 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/changelogs/unreleased/feature-api_runners_online.yml b/changelogs/unreleased/feature-api_runners_online.yml index f5077507e5b..08f4dd16f28 100644 --- a/changelogs/unreleased/feature-api_runners_online.yml +++ b/changelogs/unreleased/feature-api_runners_online.yml @@ -1,4 +1,5 @@ --- -title: Add online attribute to runner api entity +title: Add online and status attribute to runner api entity merge_request: 11750 -author: Alessio Caiazza +author: +type: added diff --git a/doc/api/runners.md b/doc/api/runners.md index 50981ed96bc..7495c6cdedb 100644 --- a/doc/api/runners.md +++ b/doc/api/runners.md @@ -31,7 +31,8 @@ Example response: "id": 6, "is_shared": false, "name": null, - "online": true + "online": true, + "status": "online" }, { "active": true, @@ -39,7 +40,8 @@ Example response: "id": 8, "is_shared": false, "name": null, - "online": false + "online": false, + "status": "offline" } ] ``` @@ -72,7 +74,8 @@ Example response: "id": 1, "is_shared": true, "name": null, - "online": true + "online": true, + "status": "online" }, { "active": true, @@ -81,6 +84,7 @@ Example response: "is_shared": true, "name": null, "online": false + "status": "offline" }, { "active": true, @@ -89,6 +93,7 @@ Example response: "is_shared": false, "name": null, "online": true + "status": "paused" }, { "active": true, @@ -96,7 +101,8 @@ Example response: "id": 8, "is_shared": false, "name": null, - "online": false + "online": false, + "status": "offline" } ] ``` @@ -129,6 +135,7 @@ Example response: "contacted_at": "2016-01-25T16:39:48.066Z", "name": null, "online": true, + "status": "online", "platform": null, "projects": [ { @@ -184,6 +191,7 @@ Example response: "contacted_at": "2016-01-25T16:39:48.066Z", "name": null, "online": true, + "status": "online", "platform": null, "projects": [ { @@ -336,7 +344,8 @@ Example response: "id": 8, "is_shared": false, "name": null, - "online": false + "online": false, + "status": "offline" }, { "active": true, @@ -345,6 +354,7 @@ Example response: "is_shared": true, "name": null, "online": true + "status": "paused" } ] ``` @@ -375,7 +385,8 @@ Example response: "id": 9, "is_shared": false, "name": null, - "online": true + "online": true, + "status": "online" } ``` diff --git a/lib/api/entities.rb b/lib/api/entities.rb index c612dde7f73..f5fa5fef389 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -863,6 +863,7 @@ module API expose :is_shared expose :name expose :online?, as: :online + expose :status end class RunnerDetails < Runner -- cgit v1.2.1 From 13926246020fb41599e1a7b908912bb2e61f114f Mon Sep 17 00:00:00 2001 From: James Lopez Date: Fri, 5 Jan 2018 11:16:18 +0100 Subject: add deprecation and removal issue to docs --- doc/administration/raketasks/check.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/administration/raketasks/check.md b/doc/administration/raketasks/check.md index 7dabc014bad..831b73237b6 100644 --- a/doc/administration/raketasks/check.md +++ b/doc/administration/raketasks/check.md @@ -28,6 +28,12 @@ exactly which repositories are causing the trouble. ### Check all GitLab repositories +>**Note:** +> +> - `gitlab:repo:check` has been deprecated in favour of `gitlab:git:fsck` +> - [Deprecated][ce-15931] in GitLab 10.4. +> - `gitlab:repo:check` will be removed in the future. [Removal issue][ce-41699] + This task loops through all repositories on the GitLab server and runs the 3 integrity checks described previously. @@ -76,3 +82,6 @@ The LDAP check Rake task will test the bind_dn and password credentials (if configured) and will list a sample of LDAP users. This task is also executed as part of the `gitlab:check` task, but can run independently. See [LDAP Rake Tasks - LDAP Check](ldap.md#check) for details. + +[ce-15931]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15931 +[ce-41699]: https://gitlab.com/gitlab-org/gitlab-ce/issues/41699 -- cgit v1.2.1 From 0feb2437e1318fa1b3157bf322d6759bb32bc01a Mon Sep 17 00:00:00 2001 From: James Lopez Date: Fri, 5 Jan 2018 10:30:57 +0000 Subject: Update check.md --- doc/administration/raketasks/check.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/administration/raketasks/check.md b/doc/administration/raketasks/check.md index 831b73237b6..c39cb49b1c6 100644 --- a/doc/administration/raketasks/check.md +++ b/doc/administration/raketasks/check.md @@ -30,7 +30,7 @@ exactly which repositories are causing the trouble. >**Note:** > -> - `gitlab:repo:check` has been deprecated in favour of `gitlab:git:fsck` +> - `gitlab:repo:check` has been deprecated in favor of `gitlab:git:fsck` > - [Deprecated][ce-15931] in GitLab 10.4. > - `gitlab:repo:check` will be removed in the future. [Removal issue][ce-41699] -- cgit v1.2.1 From 7c91863b43dbb4027e9b888d5064a3c1d3dabcf4 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 5 Jan 2018 10:56:09 +0000 Subject: Use computed prop in expand button --- app/assets/javascripts/vue_shared/components/expand_button.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/vue_shared/components/expand_button.vue b/app/assets/javascripts/vue_shared/components/expand_button.vue index 96991c4e268..05e48ed297f 100644 --- a/app/assets/javascripts/vue_shared/components/expand_button.vue +++ b/app/assets/javascripts/vue_shared/components/expand_button.vue @@ -35,7 +35,7 @@ type="button" v-show="isCollapsed" class="text-expander btn-blank" - aria-label="Click to Expand Text" + :aria-label="ariaLabel" @click="onClick"> ... -- cgit v1.2.1 From 5d1391b6818b61e3b7ba4742d6487382484f9643 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Fri, 5 Jan 2018 12:29:01 +0100 Subject: Fix specs --- spec/models/namespace_spec.rb | 10 +++++++--- spec/models/project_spec.rb | 8 ++++---- spec/services/projects/create_service_spec.rb | 2 +- .../projects/hashed_storage/migrate_repository_service_spec.rb | 2 +- spec/services/projects/transfer_service_spec.rb | 4 ++-- 5 files changed, 15 insertions(+), 11 deletions(-) diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 0678cae9b93..b3f160f3119 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -250,9 +250,13 @@ describe Namespace do parent.update(path: 'mygroup_new') - expect(project_in_parent_group.repo.config['gitlab.fullpath']).to eq "mygroup_new/#{project_in_parent_group.path}" - expect(hashed_project_in_subgroup.repo.config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{hashed_project_in_subgroup.path}" - expect(legacy_project_in_subgroup.repo.config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{legacy_project_in_subgroup.path}" + expect(project_rugged(project_in_parent_group).config['gitlab.fullpath']).to eq "mygroup_new/#{project_in_parent_group.path}" + expect(project_rugged(hashed_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{hashed_project_in_subgroup.path}" + expect(project_rugged(legacy_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{legacy_project_in_subgroup.path}" + end + + def project_rugged(project) + project.repository.rugged end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index cea22bbd184..8111365bed1 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -2632,7 +2632,7 @@ describe Project do project.rename_repo - expect(project.repo.config['gitlab.fullpath']).to eq(project.full_path) + expect(project.repository.rugged.config['gitlab.fullpath']).to eq(project.full_path) end end @@ -2793,7 +2793,7 @@ describe Project do it 'updates project full path in .git/config' do project.rename_repo - expect(project.repo.config['gitlab.fullpath']).to eq(project.full_path) + expect(project.repository.rugged.config['gitlab.fullpath']).to eq(project.full_path) end end @@ -3162,13 +3162,13 @@ describe Project do it 'writes full path in .git/config when key is missing' do project.write_repository_config - expect(project.repo.config['gitlab.fullpath']).to eq project.full_path + expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path end it 'updates full path in .git/config when key is present' do project.write_repository_config(gl_full_path: 'old/path') - expect { project.write_repository_config }.to change { project.repo.config['gitlab.fullpath'] }.from('old/path').to(project.full_path) + expect { project.write_repository_config }.to change { project.repository.rugged.config['gitlab.fullpath'] }.from('old/path').to(project.full_path) end it 'does not raise an error with an empty repository' do diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb index 1833078f37c..9a44dfde41b 100644 --- a/spec/services/projects/create_service_spec.rb +++ b/spec/services/projects/create_service_spec.rb @@ -255,7 +255,7 @@ describe Projects::CreateService, '#execute' do it 'writes project full path to .git/config' do project = create_project(user, opts) - expect(project.repo.config['gitlab.fullpath']).to eq project.full_path + expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path end def create_project(user, opts) diff --git a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb index ded864beb1d..7b536cc05cb 100644 --- a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb +++ b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb @@ -37,7 +37,7 @@ describe Projects::HashedStorage::MigrateRepositoryService do it 'writes project full path to .git/config' do service.execute - expect(project.repo.config['gitlab.fullpath']).to eq project.full_path + expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path end end diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index 7377c748698..39f6388c25e 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -58,7 +58,7 @@ describe Projects::TransferService do it 'updates project full path in .git/config' do transfer_project(project, user, group) - expect(project.repo.config['gitlab.fullpath']).to eq "#{group.full_path}/#{project.path}" + expect(project.repository.rugged.config['gitlab.fullpath']).to eq "#{group.full_path}/#{project.path}" end end @@ -95,7 +95,7 @@ describe Projects::TransferService do it 'rolls back project full path in .git/config' do attempt_project_transfer - expect(project.repo.config['gitlab.fullpath']).to eq project.full_path + expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path end it "doesn't send move notifications" do -- cgit v1.2.1 From c5e2c0665fe7e4937689cfedaa064aa64f538c8b Mon Sep 17 00:00:00 2001 From: "Jacob Vosmaer (GitLab)" Date: Fri, 5 Jan 2018 11:31:12 +0000 Subject: Allow local tests to use a modified Gitaly --- doc/development/gitaly.md | 23 +++++++++++++++++ lib/gitlab/setup_helper.rb | 61 ++++++++++++++++++++++++++++++++++++++++++++ lib/tasks/gitlab/gitaly.rake | 57 ++--------------------------------------- spec/support/test_env.rb | 7 +++++ 4 files changed, 93 insertions(+), 55 deletions(-) create mode 100644 lib/gitlab/setup_helper.rb diff --git a/doc/development/gitaly.md b/doc/development/gitaly.md index ca2048c7019..26abf967dcf 100644 --- a/doc/development/gitaly.md +++ b/doc/development/gitaly.md @@ -97,6 +97,29 @@ describe 'Gitaly Request count tests' do end ``` +## Running tests with a locally modified version of Gitaly + +Normally, gitlab-ce/ee tests use a local clone of Gitaly in `tmp/tests/gitaly` +pinned at the version specified in GITALY_SERVER_VERSION. If you want +to run tests locally against a modified version of Gitaly you can +replace `tmp/tests/gitaly` with a symlink. + +```shell +rm -rf tmp/tests/gitaly +ln -s /path/to/gitaly tmp/tests/gitaly +``` + +Make sure you run `make` in your local Gitaly directory before running +tests. Otherwise, Gitaly will fail to boot. + +If you make changes to your local Gitaly in between test runs you need +to manually run `make` again. + +Note that CI tests will not use your locally modified version of +Gitaly. To use a custom Gitaly version in CI you need to update +GITALY_SERVER_VERSION. You can use the format `=revision` to use a +non-tagged commit from https://gitlab.com/gitlab-org/gitaly in CI. + --- [Return to Development documentation](README.md) diff --git a/lib/gitlab/setup_helper.rb b/lib/gitlab/setup_helper.rb new file mode 100644 index 00000000000..d01213bb6e0 --- /dev/null +++ b/lib/gitlab/setup_helper.rb @@ -0,0 +1,61 @@ +module Gitlab + module SetupHelper + class << self + # We cannot create config.toml files for all possible Gitaly configuations. + # For instance, if Gitaly is running on another machine then it makes no + # sense to write a config.toml file on the current machine. This method will + # 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. + # For development and testing purposes, an extra storage is added to gitaly, + # which is not known to Rails, but must be explicitly stubbed. + def gitaly_configuration_toml(gitaly_dir, gitaly_ruby: true) + storages = [] + address = nil + + Gitlab.config.repositories.storages.each do |key, val| + if address + if address != val['gitaly_address'] + raise ArgumentError, "Your gitlab.yml contains more than one gitaly_address." + end + elsif URI(val['gitaly_address']).scheme != 'unix' + raise ArgumentError, "Automatic config.toml generation only supports 'unix:' addresses." + else + address = val['gitaly_address'] + end + + storages << { name: key, path: val['path'] } + end + + if Rails.env.test? + storages << { name: 'test_second_storage', path: Rails.root.join('tmp', 'tests', 'second_storage').to_s } + end + + config = { socket_path: address.sub(%r{\Aunix:}, ''), storage: storages } + config[:auth] = { token: 'secret' } if Rails.env.test? + config[:'gitaly-ruby'] = { dir: File.join(gitaly_dir, 'ruby') } if gitaly_ruby + config[:'gitlab-shell'] = { dir: Gitlab.config.gitlab_shell.path } + config[:bin_dir] = Gitlab.config.gitaly.client_path + + TOML.dump(config) + end + + # rubocop:disable Rails/Output + def create_gitaly_configuration(dir, force: false) + config_path = File.join(dir, 'config.toml') + FileUtils.rm_f(config_path) if force + + File.open(config_path, File::WRONLY | File::CREAT | File::EXCL) do |f| + f.puts gitaly_configuration_toml(dir) + end + rescue Errno::EEXIST + puts "Skipping config.toml generation:" + puts "A configuration file already exists." + rescue ArgumentError => e + puts "Skipping config.toml generation:" + puts e.message + end + # rubocop:enable Rails/Output + end + end +end diff --git a/lib/tasks/gitlab/gitaly.rake b/lib/tasks/gitlab/gitaly.rake index 4d880c05f99..4507b841964 100644 --- a/lib/tasks/gitlab/gitaly.rake +++ b/lib/tasks/gitlab/gitaly.rake @@ -21,8 +21,8 @@ namespace :gitlab do command << 'BUNDLE_FLAGS=--no-deployment' if Rails.env.test? + Gitlab::SetupHelper.create_gitaly_configuration(args.dir) Dir.chdir(args.dir) do - create_gitaly_configuration # In CI we run scripts/gitaly-test-build instead of this command unless ENV['CI'].present? Bundler.with_original_env { run_command!(command) } @@ -39,60 +39,7 @@ namespace :gitlab do # Exclude gitaly-ruby configuration because that depends on the gitaly # installation directory. - puts gitaly_configuration_toml(gitaly_ruby: false) - end - - private - - # We cannot create config.toml files for all possible Gitaly configuations. - # For instance, if Gitaly is running on another machine then it makes no - # sense to write a config.toml file on the current machine. This method will - # 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. - # For development and testing purposes, an extra storage is added to gitaly, - # which is not known to Rails, but must be explicitly stubbed. - def gitaly_configuration_toml(gitaly_ruby: true) - storages = [] - address = nil - - Gitlab.config.repositories.storages.each do |key, val| - if address - if address != val['gitaly_address'] - raise ArgumentError, "Your gitlab.yml contains more than one gitaly_address." - end - elsif URI(val['gitaly_address']).scheme != 'unix' - raise ArgumentError, "Automatic config.toml generation only supports 'unix:' addresses." - else - address = val['gitaly_address'] - end - - storages << { name: key, path: val['path'] } - end - - if Rails.env.test? - storages << { name: 'test_second_storage', path: Rails.root.join('tmp', 'tests', 'second_storage').to_s } - 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 - config[:'gitlab-shell'] = { dir: Gitlab.config.gitlab_shell.path } - config[:bin_dir] = Gitlab.config.gitaly.client_path - - TOML.dump(config) - end - - def create_gitaly_configuration - File.open("config.toml", File::WRONLY | File::CREAT | File::EXCL) do |f| - f.puts gitaly_configuration_toml - end - rescue Errno::EEXIST - puts "Skipping config.toml generation:" - puts "A configuration file already exists." - rescue ArgumentError => e - puts "Skipping config.toml generation:" - puts e.message + puts Gitlab::SetupHelper.gitaly_configuration_toml('', gitaly_ruby: false) end end end diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 1d99746b09f..664698fcbaf 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -1,4 +1,5 @@ require 'rspec/mocks' +require 'toml' module TestEnv extend self @@ -147,6 +148,9 @@ module TestEnv version: Gitlab::GitalyClient.expected_server_version, task: "gitlab:gitaly:install[#{gitaly_dir}]") do + # Always re-create config, in case it's outdated. This is fast anyway. + Gitlab::SetupHelper.create_gitaly_configuration(gitaly_dir, force: true) + start_gitaly(gitaly_dir) end end @@ -347,6 +351,9 @@ module TestEnv end def component_needs_update?(component_folder, expected_version) + # Allow local overrides of the component for tests during development + return false if Rails.env.test? && File.symlink?(component_folder) + version = File.read(File.join(component_folder, 'VERSION')).strip # Notice that this will always yield true when using branch versions -- cgit v1.2.1 From 2c47f0924fc5534035905746046ab0f5e9c99f23 Mon Sep 17 00:00:00 2001 From: Winnie Hellmann Date: Wed, 3 Jan 2018 10:21:17 +0100 Subject: Add id to modal.vue to support data-toggle="modal" --- .../javascripts/groups/components/item_actions.vue | 6 +- .../ide/components/new_dropdown/index.vue | 8 +- .../ide/components/new_dropdown/modal.vue | 8 +- .../ide/components/repo_commit_section.vue | 2 +- .../ide/components/repo_edit_button.vue | 2 +- .../account/components/delete_account_modal.vue | 111 +++++++++------------ app/assets/javascripts/profile/account/index.js | 8 ++ .../javascripts/vue_shared/components/modal.vue | 30 ++++-- .../vue_shared/components/recaptcha_modal.vue | 2 +- app/views/profiles/accounts/show.html.haml | 6 +- changelogs/unreleased/winh-modal-target-id.yml | 5 + .../groups/components/item_actions_spec.js | 12 +-- .../components/delete_account_modal_spec.js | 8 +- .../repo/components/new_dropdown/index_spec.js | 13 +-- .../vue_shared/components/modal_spec.js | 62 +++++++++++- 15 files changed, 168 insertions(+), 115 deletions(-) create mode 100644 changelogs/unreleased/winh-modal-target-id.yml diff --git a/app/assets/javascripts/groups/components/item_actions.vue b/app/assets/javascripts/groups/components/item_actions.vue index 58ba5aff7cf..b98cfcf7563 100644 --- a/app/assets/javascripts/groups/components/item_actions.vue +++ b/app/assets/javascripts/groups/components/item_actions.vue @@ -45,11 +45,9 @@ export default { onLeaveGroup() { this.modalStatus = true; }, - leaveGroup(leaveConfirmed) { + leaveGroup() { this.modalStatus = false; - if (leaveConfirmed) { - eventHub.$emit('leaveGroup', this.group, this.parentGroup); - } + eventHub.$emit('leaveGroup', this.group, this.parentGroup); }, }, }; diff --git a/app/assets/javascripts/ide/components/new_dropdown/index.vue b/app/assets/javascripts/ide/components/new_dropdown/index.vue index 6e67e99a70f..d475813c4f7 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/index.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/index.vue @@ -32,10 +32,10 @@ methods: { createNewItem(type) { this.modalType = type; - this.toggleModalOpen(); + this.openModal = true; }, - toggleModalOpen() { - this.openModal = !this.openModal; + hideModal() { + this.openModal = false; }, }, }; @@ -95,7 +95,7 @@ :branch-id="branch" :path="path" :parent="parent" - @toggle="toggleModalOpen" + @hide="hideModal" />
diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue index a0650d37690..0312f56efbd 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue @@ -43,10 +43,10 @@ type: this.type, }); - this.toggleModalOpen(); + this.hideModal(); }, - toggleModalOpen() { - this.$emit('toggle'); + hideModal() { + this.$emit('hide'); }, }, computed: { @@ -86,7 +86,7 @@ :title="modalTitle" :primary-button-label="buttonLabel" kind="success" - @toggle="toggleModalOpen" + @cancel="hideModal" @submit="createEntryInStore" >
diff --git a/app/assets/javascripts/profile/account/components/delete_account_modal.vue b/app/assets/javascripts/profile/account/components/delete_account_modal.vue index 78be6b6e884..36ad618aa46 100644 --- a/app/assets/javascripts/profile/account/components/delete_account_modal.vue +++ b/app/assets/javascripts/profile/account/components/delete_account_modal.vue @@ -1,7 +1,7 @@ diff --git a/app/assets/javascripts/profile/account/index.js b/app/assets/javascripts/profile/account/index.js index 635056e0eeb..a93bc935dd0 100644 --- a/app/assets/javascripts/profile/account/index.js +++ b/app/assets/javascripts/profile/account/index.js @@ -1,7 +1,12 @@ import Vue from 'vue'; +import Translate from '~/vue_shared/translate'; + import deleteAccountModal from './components/delete_account_modal.vue'; +Vue.use(Translate); + +const deleteAccountButton = document.getElementById('delete-account-button'); const deleteAccountModalEl = document.getElementById('delete-account-modal'); // eslint-disable-next-line no-new new Vue({ @@ -9,6 +14,9 @@ new Vue({ components: { deleteAccountModal, }, + mounted() { + deleteAccountButton.classList.remove('disabled'); + }, render(createElement) { return createElement('delete-account-modal', { props: { diff --git a/app/assets/javascripts/vue_shared/components/modal.vue b/app/assets/javascripts/vue_shared/components/modal.vue index 55f466b7b41..00089dfef38 100644 --- a/app/assets/javascripts/vue_shared/components/modal.vue +++ b/app/assets/javascripts/vue_shared/components/modal.vue @@ -3,6 +3,10 @@ export default { name: 'modal', props: { + id: { + type: String, + required: false, + }, title: { type: String, required: false, @@ -62,11 +66,11 @@ export default { }, methods: { - close() { - this.$emit('toggle', false); + emitCancel(event) { + this.$emit('cancel', event); }, - emitSubmit(status) { - this.$emit('submit', status); + emitSubmit(event) { + this.$emit('submit', event); }, }, }; @@ -75,7 +79,9 @@ export default { diff --git a/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue b/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue index 8053c65d498..16d60bb2876 100644 --- a/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue +++ b/app/assets/javascripts/vue_shared/components/recaptcha_modal.vue @@ -70,7 +70,7 @@ export default { class="recaptcha-modal js-recaptcha-modal" :hide-footer="true" :title="__('Please solve the reCAPTCHA')" - @toggle="close" + @cancel="close" >

diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index f1313b79589..79e197ad08b 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -84,11 +84,13 @@ = s_('Profiles|Deleting an account has the following effects:') = render 'users/deletion_guidance', user: current_user + %button#delete-account-button.btn.btn-danger.disabled{ data: { toggle: 'modal', + target: '#delete-account-modal' } } + = s_('Profiles|Delete account') + #delete-account-modal{ data: { action_url: user_registration_path, confirm_with_password: ('true' if current_user.confirm_deletion_with_password?), username: current_user.username } } - %button.btn.btn-danger.disabled - = s_('Profiles|Delete account') - else - if @user.solo_owned_groups.present? %p diff --git a/changelogs/unreleased/winh-modal-target-id.yml b/changelogs/unreleased/winh-modal-target-id.yml new file mode 100644 index 00000000000..f8d5b72be50 --- /dev/null +++ b/changelogs/unreleased/winh-modal-target-id.yml @@ -0,0 +1,5 @@ +--- +title: Add id to modal.vue to support data-toggle="modal" +merge_request: 16189 +author: +type: other diff --git a/spec/javascripts/groups/components/item_actions_spec.js b/spec/javascripts/groups/components/item_actions_spec.js index 7a5c1da4d1d..6d6fb410859 100644 --- a/spec/javascripts/groups/components/item_actions_spec.js +++ b/spec/javascripts/groups/components/item_actions_spec.js @@ -47,17 +47,11 @@ describe('ItemActionsComponent', () => { it('should change `modalStatus` prop to `false` and emit `leaveGroup` event with required params when called with `leaveConfirmed` as `true`', () => { spyOn(eventHub, '$emit'); vm.modalStatus = true; - vm.leaveGroup(true); - expect(vm.modalStatus).toBeFalsy(); - expect(eventHub.$emit).toHaveBeenCalledWith('leaveGroup', vm.group, vm.parentGroup); - }); - it('should change `modalStatus` prop to `false` and should NOT emit `leaveGroup` event when called with `leaveConfirmed` as `false`', () => { - spyOn(eventHub, '$emit'); - vm.modalStatus = true; - vm.leaveGroup(false); + vm.leaveGroup(); + expect(vm.modalStatus).toBeFalsy(); - expect(eventHub.$emit).not.toHaveBeenCalled(); + expect(eventHub.$emit).toHaveBeenCalledWith('leaveGroup', vm.group, vm.parentGroup); }); }); }); diff --git a/spec/javascripts/profile/account/components/delete_account_modal_spec.js b/spec/javascripts/profile/account/components/delete_account_modal_spec.js index 2e94948cfb2..588b61196a5 100644 --- a/spec/javascripts/profile/account/components/delete_account_modal_spec.js +++ b/spec/javascripts/profile/account/components/delete_account_modal_spec.js @@ -51,7 +51,7 @@ describe('DeleteAccountModal component', () => { Vue.nextTick() .then(() => { expect(vm.enteredPassword).toBe(input.value); - expect(submitButton).toHaveClass('disabled'); + expect(submitButton).toHaveAttr('disabled', 'disabled'); submitButton.click(); expect(form.submit).not.toHaveBeenCalled(); }) @@ -68,7 +68,7 @@ describe('DeleteAccountModal component', () => { Vue.nextTick() .then(() => { expect(vm.enteredPassword).toBe(input.value); - expect(submitButton).not.toHaveClass('disabled'); + expect(submitButton).not.toHaveAttr('disabled', 'disabled'); submitButton.click(); expect(form.submit).toHaveBeenCalled(); }) @@ -101,7 +101,7 @@ describe('DeleteAccountModal component', () => { Vue.nextTick() .then(() => { expect(vm.enteredUsername).toBe(input.value); - expect(submitButton).toHaveClass('disabled'); + expect(submitButton).toHaveAttr('disabled', 'disabled'); submitButton.click(); expect(form.submit).not.toHaveBeenCalled(); }) @@ -118,7 +118,7 @@ describe('DeleteAccountModal component', () => { Vue.nextTick() .then(() => { expect(vm.enteredUsername).toBe(input.value); - expect(submitButton).not.toHaveClass('disabled'); + expect(submitButton).not.toHaveAttr('disabled', 'disabled'); submitButton.click(); expect(form.submit).toHaveBeenCalled(); }) diff --git a/spec/javascripts/repo/components/new_dropdown/index_spec.js b/spec/javascripts/repo/components/new_dropdown/index_spec.js index b001c1655b4..6efbbf6d75e 100644 --- a/spec/javascripts/repo/components/new_dropdown/index_spec.js +++ b/spec/javascripts/repo/components/new_dropdown/index_spec.js @@ -57,15 +57,16 @@ describe('new dropdown component', () => { }); }); - describe('toggleModalOpen', () => { + describe('hideModal', () => { + beforeAll((done) => { + vm.openModal = true; + Vue.nextTick(done); + }); + it('closes modal after toggling', (done) => { - vm.toggleModalOpen(); + vm.hideModal(); Vue.nextTick() - .then(() => { - expect(vm.$el.querySelector('.modal')).not.toBeNull(); - }) - .then(vm.toggleModalOpen) .then(() => { expect(vm.$el.querySelector('.modal')).toBeNull(); }) diff --git a/spec/javascripts/vue_shared/components/modal_spec.js b/spec/javascripts/vue_shared/components/modal_spec.js index 721f4044659..fe75a86cac8 100644 --- a/spec/javascripts/vue_shared/components/modal_spec.js +++ b/spec/javascripts/vue_shared/components/modal_spec.js @@ -2,11 +2,65 @@ import Vue from 'vue'; import modal from '~/vue_shared/components/modal.vue'; import mountComponent from '../../helpers/vue_mount_component_helper'; +const modalComponent = Vue.extend(modal); + describe('Modal', () => { - it('does not render a primary button if no primaryButtonLabel', () => { - const modalComponent = Vue.extend(modal); - const vm = mountComponent(modalComponent); + let vm; + + afterEach(() => { + vm.$destroy(); + }); + + describe('props', () => { + describe('without primaryButtonLabel', () => { + beforeEach(() => { + vm = mountComponent(modalComponent, { + primaryButtonLabel: null, + }); + }); + + it('does not render a primary button', () => { + expect(vm.$el.querySelector('.js-primary-button')).toBeNull(); + }); + }); + + describe('with id', () => { + it('does not render a primary button', () => { + beforeEach(() => { + vm = mountComponent(modalComponent, { + id: 'my-modal', + }); + }); + + it('assigns the id to the modal', () => { + expect(vm.$el.querySelector('#my-modal.modal')).not.toBeNull(); + }); + + it('does not show the modal immediately', () => { + expect(vm.$el.querySelector('#my-modal.modal')).not.toHaveClass('show'); + }); + + it('does not show a backdrop', () => { + expect(vm.$el.querySelector('modal-backdrop')).toBeNull(); + }); + }); + }); + + it('works with data-toggle="modal"', (done) => { + setFixtures(` + +

+ `); + + const modalContainer = document.getElementById('modal-container'); + const modalButton = document.getElementById('modal-button'); + vm = mountComponent(modalComponent, { + id: 'my-modal', + }, modalContainer); + const modalElement = vm.$el.querySelector('#my-modal'); + $(modalElement).on('shown.bs.modal', () => done()); - expect(vm.$el.querySelector('.js-primary-button')).toBeNull(); + modalButton.click(); + }); }); }); -- cgit v1.2.1 From 153ea1830153b7d7c3be5ac2e7ca60486c9b2700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarka=20Kadlecova=CC=81?= Date: Fri, 5 Jan 2018 10:15:03 +0100 Subject: Refactor matchers for background migrations --- app/models/issue.rb | 2 +- .../prepare_untracked_uploads_spec.rb | 13 +------------ .../migrate_stage_id_reference_in_background_spec.rb | 6 +++--- spec/migrations/migrate_stages_statuses_spec.rb | 6 +++--- .../schedule_create_gpg_key_subkeys_from_gpg_keys_spec.rb | 12 ------------ .../schedule_merge_request_diff_migrations_spec.rb | 6 +++--- ...chedule_merge_request_diff_migrations_take_two_spec.rb | 6 +++--- ...equest_latest_merge_request_diff_id_migrations_spec.rb | 6 +++--- ...opulate_merge_request_metrics_with_events_data_spec.rb | 4 ++-- spec/migrations/track_untracked_uploads_spec.rb | 12 ------------ spec/support/background_migrations_matchers.rb | 15 ++++++++++++++- 11 files changed, 33 insertions(+), 55 deletions(-) diff --git a/app/models/issue.rb b/app/models/issue.rb index f2d111ba926..ad4a3c737ff 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -35,7 +35,7 @@ class Issue < ActiveRecord::Base validates :project, presence: true - alias_attribute :parent_id, :project_id + alias_attribute :parent_ids, :project_id scope :in_projects, ->(project_ids) { where(project_id: project_ids) } diff --git a/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb b/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb index cd3f1a45270..8bb9ebe0419 100644 --- a/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb +++ b/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb @@ -2,21 +2,10 @@ require 'spec_helper' describe Gitlab::BackgroundMigration::PrepareUntrackedUploads, :sidekiq do include TrackUntrackedUploadsHelpers + include MigrationsHelpers let!(:untracked_files_for_uploads) { described_class::UntrackedFile } - matcher :be_scheduled_migration do |*expected| - match do |migration| - BackgroundMigrationWorker.jobs.any? do |job| - job['args'] == [migration, expected] - end - end - - failure_message do |migration| - "Migration `#{migration}` with args `#{expected.inspect}` not scheduled!" - end - end - before do DatabaseCleaner.clean diff --git a/spec/migrations/migrate_stage_id_reference_in_background_spec.rb b/spec/migrations/migrate_stage_id_reference_in_background_spec.rb index 9b92f4b70b0..a837498e1b1 100644 --- a/spec/migrations/migrate_stage_id_reference_in_background_spec.rb +++ b/spec/migrations/migrate_stage_id_reference_in_background_spec.rb @@ -35,9 +35,9 @@ describe MigrateStageIdReferenceInBackground, :migration, :sidekiq do Timecop.freeze do migrate! - expect(described_class::MIGRATION).to be_scheduled_migration(2.minutes, 1, 2) - expect(described_class::MIGRATION).to be_scheduled_migration(2.minutes, 3, 3) - expect(described_class::MIGRATION).to be_scheduled_migration(4.minutes, 4, 5) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2.minutes, 1, 2) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2.minutes, 3, 3) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, 4, 5) expect(BackgroundMigrationWorker.jobs.size).to eq 3 end end diff --git a/spec/migrations/migrate_stages_statuses_spec.rb b/spec/migrations/migrate_stages_statuses_spec.rb index 094c9bc604e..79d2708f9ad 100644 --- a/spec/migrations/migrate_stages_statuses_spec.rb +++ b/spec/migrations/migrate_stages_statuses_spec.rb @@ -50,9 +50,9 @@ describe MigrateStagesStatuses, :migration do Timecop.freeze do migrate! - expect(described_class::MIGRATION).to be_scheduled_migration(5.minutes, 1, 1) - expect(described_class::MIGRATION).to be_scheduled_migration(5.minutes, 2, 2) - expect(described_class::MIGRATION).to be_scheduled_migration(10.minutes, 3, 3) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, 1, 1) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, 2, 2) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(10.minutes, 3, 3) expect(BackgroundMigrationWorker.jobs.size).to eq 3 end end diff --git a/spec/migrations/schedule_create_gpg_key_subkeys_from_gpg_keys_spec.rb b/spec/migrations/schedule_create_gpg_key_subkeys_from_gpg_keys_spec.rb index 0e884a7d910..65ec07da31c 100644 --- a/spec/migrations/schedule_create_gpg_key_subkeys_from_gpg_keys_spec.rb +++ b/spec/migrations/schedule_create_gpg_key_subkeys_from_gpg_keys_spec.rb @@ -2,18 +2,6 @@ require 'spec_helper' require Rails.root.join('db', 'post_migrate', '20171005130944_schedule_create_gpg_key_subkeys_from_gpg_keys') describe ScheduleCreateGpgKeySubkeysFromGpgKeys, :migration, :sidekiq do - matcher :be_scheduled_migration do |*expected| - match do |migration| - BackgroundMigrationWorker.jobs.any? do |job| - job['args'] == [migration, expected] - end - end - - failure_message do |migration| - "Migration `#{migration}` with args `#{expected.inspect}` not scheduled!" - end - end - before do create(:gpg_key, id: 1, key: GpgHelpers::User1.public_key) create(:gpg_key, id: 2, key: GpgHelpers::User3.public_key) diff --git a/spec/migrations/schedule_merge_request_diff_migrations_spec.rb b/spec/migrations/schedule_merge_request_diff_migrations_spec.rb index 76afb6c19cf..d230f064444 100644 --- a/spec/migrations/schedule_merge_request_diff_migrations_spec.rb +++ b/spec/migrations/schedule_merge_request_diff_migrations_spec.rb @@ -24,9 +24,9 @@ describe ScheduleMergeRequestDiffMigrations, :migration, :sidekiq do Timecop.freeze do migrate! - expect(described_class::MIGRATION).to be_scheduled_migration(5.minutes, 1, 1) - expect(described_class::MIGRATION).to be_scheduled_migration(10.minutes, 2, 2) - expect(described_class::MIGRATION).to be_scheduled_migration(15.minutes, 4, 4) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, 1, 1) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(10.minutes, 2, 2) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(15.minutes, 4, 4) expect(BackgroundMigrationWorker.jobs.size).to eq 3 end end diff --git a/spec/migrations/schedule_merge_request_diff_migrations_take_two_spec.rb b/spec/migrations/schedule_merge_request_diff_migrations_take_two_spec.rb index cf323973384..1aab4ae1650 100644 --- a/spec/migrations/schedule_merge_request_diff_migrations_take_two_spec.rb +++ b/spec/migrations/schedule_merge_request_diff_migrations_take_two_spec.rb @@ -24,9 +24,9 @@ describe ScheduleMergeRequestDiffMigrationsTakeTwo, :migration, :sidekiq do Timecop.freeze do migrate! - expect(described_class::MIGRATION).to be_scheduled_migration(10.minutes, 1, 1) - expect(described_class::MIGRATION).to be_scheduled_migration(20.minutes, 2, 2) - expect(described_class::MIGRATION).to be_scheduled_migration(30.minutes, 4, 4) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(10.minutes, 1, 1) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(20.minutes, 2, 2) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(30.minutes, 4, 4) expect(BackgroundMigrationWorker.jobs.size).to eq 3 end end diff --git a/spec/migrations/schedule_merge_request_latest_merge_request_diff_id_migrations_spec.rb b/spec/migrations/schedule_merge_request_latest_merge_request_diff_id_migrations_spec.rb index 158d0bc02ed..c9fdbe95d13 100644 --- a/spec/migrations/schedule_merge_request_latest_merge_request_diff_id_migrations_spec.rb +++ b/spec/migrations/schedule_merge_request_latest_merge_request_diff_id_migrations_spec.rb @@ -44,9 +44,9 @@ describe ScheduleMergeRequestLatestMergeRequestDiffIdMigrations, :migration, :si Timecop.freeze do migrate! - expect(described_class::MIGRATION).to be_scheduled_migration(5.minutes, merge_request_1.id, merge_request_1.id) - expect(described_class::MIGRATION).to be_scheduled_migration(10.minutes, merge_request_2.id, merge_request_2.id) - expect(described_class::MIGRATION).to be_scheduled_migration(15.minutes, merge_request_4.id, merge_request_4.id) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, merge_request_1.id, merge_request_1.id) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(10.minutes, merge_request_2.id, merge_request_2.id) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(15.minutes, merge_request_4.id, merge_request_4.id) expect(BackgroundMigrationWorker.jobs.size).to eq 3 end end diff --git a/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb b/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb index 97e089c5cb8..2e6b2cff0ab 100644 --- a/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb +++ b/spec/migrations/schedule_populate_merge_request_metrics_with_events_data_spec.rb @@ -12,10 +12,10 @@ describe SchedulePopulateMergeRequestMetricsWithEventsData, :migration, :sidekiq migrate! expect(described_class::MIGRATION) - .to be_scheduled_migration(10.minutes, mrs.first.id, mrs.second.id) + .to be_scheduled_delayed_migration(10.minutes, mrs.first.id, mrs.second.id) expect(described_class::MIGRATION) - .to be_scheduled_migration(20.minutes, mrs.third.id, mrs.third.id) + .to be_scheduled_delayed_migration(20.minutes, mrs.third.id, mrs.third.id) expect(BackgroundMigrationWorker.jobs.size).to eq(2) end diff --git a/spec/migrations/track_untracked_uploads_spec.rb b/spec/migrations/track_untracked_uploads_spec.rb index 7fe7a140e2f..fe4d5b8a279 100644 --- a/spec/migrations/track_untracked_uploads_spec.rb +++ b/spec/migrations/track_untracked_uploads_spec.rb @@ -4,18 +4,6 @@ require Rails.root.join('db', 'post_migrate', '20171103140253_track_untracked_up describe TrackUntrackedUploads, :migration, :sidekiq do include TrackUntrackedUploadsHelpers - matcher :be_scheduled_migration do - match do |migration| - BackgroundMigrationWorker.jobs.any? do |job| - job['args'] == [migration] - end - end - - failure_message do |migration| - "Migration `#{migration}` with args `#{expected.inspect}` not scheduled!" - end - end - it 'correctly schedules the follow-up background migration' do Sidekiq::Testing.fake! do migrate! diff --git a/spec/support/background_migrations_matchers.rb b/spec/support/background_migrations_matchers.rb index 423c0e4cefc..f4127efc6ae 100644 --- a/spec/support/background_migrations_matchers.rb +++ b/spec/support/background_migrations_matchers.rb @@ -1,4 +1,4 @@ -RSpec::Matchers.define :be_scheduled_migration do |delay, *expected| +RSpec::Matchers.define :be_scheduled_delayed_migration do |delay, *expected| match do |migration| BackgroundMigrationWorker.jobs.any? do |job| job['args'] == [migration, expected] && @@ -11,3 +11,16 @@ RSpec::Matchers.define :be_scheduled_migration do |delay, *expected| 'not scheduled in expected time!' end end + +RSpec::Matchers.define :be_scheduled_migration do |*expected| + match do |migration| + BackgroundMigrationWorker.jobs.any? do |job| + args = job['args'].size == 1 ? [BackgroundMigrationWorker.jobs[0]['args'][0], []] : job['args'] + args == [migration, expected] + end + end + + failure_message do |migration| + "Migration `#{migration}` with args `#{expected.inspect}` not scheduled!" + end +end -- cgit v1.2.1 From c4600805b58e4fc705a6733cd92fa5518a267e9f Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 5 Jan 2018 14:08:17 +0100 Subject: Update redis-rack to 2.0.4 Up until version 2.0.3 redis-rack included a "rake" binary that would overwrite/hijack the one provided by Rake itself. Unfortunately the binary provided by redis-rack would produce errors in many cases. See https://github.com/redis-store/redis-rack/pull/34 for more info. --- Gemfile.lock | 2 +- changelogs/unreleased/update-redis-rack.yml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/update-redis-rack.yml diff --git a/Gemfile.lock b/Gemfile.lock index c510a6da2d7..2a81c81b0f8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -718,7 +718,7 @@ GEM redis-store (>= 1.3, < 2) redis-namespace (1.5.2) redis (~> 3.0, >= 3.0.4) - redis-rack (2.0.3) + redis-rack (2.0.4) rack (>= 1.5, < 3) redis-store (>= 1.2, < 2) redis-rails (5.0.2) diff --git a/changelogs/unreleased/update-redis-rack.yml b/changelogs/unreleased/update-redis-rack.yml new file mode 100644 index 00000000000..6e2e6e203b8 --- /dev/null +++ b/changelogs/unreleased/update-redis-rack.yml @@ -0,0 +1,5 @@ +--- +title: Update redis-rack to 2.0.4 +merge_request: +author: +type: other -- cgit v1.2.1 From 55980c7eca8e82e306fb3b8ade1f4a5b68a60e9f Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Fri, 5 Jan 2018 11:24:24 -0200 Subject: Remove EE only sections from docs --- doc/api/boards.md | 85 ------------------------------------------------------- 1 file changed, 85 deletions(-) diff --git a/doc/api/boards.md b/doc/api/boards.md index a5f455e1c43..246de50323e 100644 --- a/doc/api/boards.md +++ b/doc/api/boards.md @@ -141,91 +141,6 @@ Example response: } ``` -## Create a board (EES-Only) - -Creates a board. - -``` -POST /projects/:id/boards -``` - -| Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `name` | string | yes | The name of the new board | - -```bash -curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards?name=newboard -``` - -Example response: - -```json - { - "id": 1, - "project": { - "id": 5, - "name": "Diaspora Project Site", - "name_with_namespace": "Diaspora / Diaspora Project Site", - "path": "diaspora-project-site", - "path_with_namespace": "diaspora/diaspora-project-site", - "http_url_to_repo": "http://example.com/diaspora/diaspora-project-site.git", - "web_url": "http://example.com/diaspora/diaspora-project-site" - }, - "name": "newboard", - "milestone": { - "id": 12 - "title": "10.0" - }, - "lists" : [ - { - "id" : 1, - "label" : { - "name" : "Testing", - "color" : "#F0AD4E", - "description" : null - }, - "position" : 1 - }, - { - "id" : 2, - "label" : { - "name" : "Ready", - "color" : "#FF0000", - "description" : null - }, - "position" : 2 - }, - { - "id" : 3, - "label" : { - "name" : "Production", - "color" : "#FF5F00", - "description" : null - }, - "position" : 3 - } - ] - } -``` - -## Delete a board (EES-Only) - -Deletes a board. - -``` -DELETE /projects/:id/boards/:board_id -``` - -| Attribute | Type | Required | Description | -| --------- | ---- | -------- | ----------- | -| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | -| `board_id` | integer | yes | The ID of a board | - -```bash -curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1 -``` - ## List board lists Get a list of the board's lists. -- cgit v1.2.1 From 05ddb259958c27506cb075342fae5a70cf8ce257 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 5 Jan 2018 14:48:50 +0100 Subject: Assign stage and pipeline to a status when importing --- app/models/ci/build.rb | 2 +- lib/gitlab/import_export/import_export.yml | 4 +- lib/gitlab/import_export/relation_factory.rb | 18 +- spec/lib/gitlab/import_export/project.json | 758 +++++++++++---------- .../import_export/project_tree_restorer_spec.rb | 12 +- 5 files changed, 426 insertions(+), 368 deletions(-) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 83fe23606d1..fb5ae83ac7b 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -79,7 +79,7 @@ module Ci before_save :ensure_token before_destroy { unscoped_project } - after_create do |build| + after_create unless: :importing? do |build| run_after_commit { BuildHooksWorker.perform_async(build.id) } end diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml index f2b193c79cb..2daed10f678 100644 --- a/lib/gitlab/import_export/import_export.yml +++ b/lib/gitlab/import_export/import_export.yml @@ -49,8 +49,8 @@ project_tree: - :author - events: - :push_event_payload - - :stages - - :statuses + - stages: + - :statuses - :auto_devops - :triggers - :pipeline_schedules diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb index d7d1b05e8b9..05dbaf6322c 100644 --- a/lib/gitlab/import_export/relation_factory.rb +++ b/lib/gitlab/import_export/relation_factory.rb @@ -62,6 +62,7 @@ module Gitlab when :notes then setup_note when :project_label, :project_labels then setup_label when :milestone, :milestones then setup_milestone + when 'Ci::Pipeline' then setup_pipeline else @relation_hash['project_id'] = @project.id end @@ -112,9 +113,7 @@ module Gitlab @relation_hash.delete('trace') # old export files have trace @relation_hash.delete('token') - imported_object do |object| - object.commit_id = nil - end + imported_object elsif @relation_name == :merge_requests MergeRequestParser.new(@project, @relation_hash.delete('diff_head_sha'), imported_object, @relation_hash).parse! else @@ -182,8 +181,9 @@ module Gitlab end def imported_object - yield(existing_or_new_object) if block_given? - existing_or_new_object.importing = true if existing_or_new_object.respond_to?(:importing) + if existing_or_new_object.respond_to?(:importing) + existing_or_new_object.importing = true + end existing_or_new_object rescue ActiveRecord::RecordNotUnique @@ -211,6 +211,14 @@ module Gitlab @relation_hash['diff'] = @relation_hash.delete('utf8_diff') end + def setup_pipeline + @relation_hash.fetch('stages').each do |stage| + stage.statuses.each do |status| + status.pipeline = imported_object + end + end + end + def existing_or_new_object # Only find existing records to avoid mapping tables such as milestones # Otherwise always create the record, skipping the extra SELECT clause. diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json index 6778b23ee7f..7580b62cfc0 100644 --- a/spec/lib/gitlab/import_export/project.json +++ b/spec/lib/gitlab/import_export/project.json @@ -6473,7 +6473,83 @@ "name": "test", "status": 1, "created_at": "2016-03-22T15:44:44.772Z", - "updated_at": "2016-03-29T06:44:44.634Z" + "updated_at": "2016-03-29T06:44:44.634Z", + "statuses": [ + { + "id": 71, + "project_id": 5, + "status": "failed", + "finished_at": "2016-03-29T06:28:12.630Z", + "trace": null, + "created_at": "2016-03-22T15:20:35.772Z", + "updated_at": "2016-03-29T06:28:12.634Z", + "started_at": null, + "runner_id": null, + "coverage": null, + "commit_id": 36, + "commands": "$ build command", + "job_id": null, + "name": "test build 1", + "deploy": false, + "options": null, + "allow_failure": false, + "stage": "test", + "trigger_request_id": null, + "stage_idx": 1, + "stage_id": 11, + "tag": null, + "ref": "master", + "user_id": null, + "target_url": null, + "description": null, + "artifacts_file": { + "url": null + }, + "artifacts_metadata": { + "url": null + }, + "erased_by_id": null, + "erased_at": null, + "type": "Ci::Build", + "token": "abcd" + }, + { + "id": 72, + "project_id": 5, + "status": "success", + "finished_at": null, + "trace": "Porro ea qui ut dolores. Labore ab nemo explicabo aspernatur quis voluptates corporis. Et quasi delectus est sit aperiam perspiciatis asperiores. Repudiandae cum aut consectetur accusantium officia sunt.\n\nQuidem dolore iusto quaerat ut aut inventore et molestiae. Libero voluptates atque nemo qui. Nulla temporibus ipsa similique facere.\n\nAliquam ipsam perferendis qui fugit accusantium omnis id voluptatum. Dignissimos aliquid dicta eos voluptatem assumenda quia. Sed autem natus unde dolor et non nisi et. Consequuntur nihil consequatur rerum est.\n\nSimilique neque est iste ducimus qui fuga cupiditate. Libero autem est aut fuga. Consectetur natus quis non ducimus ut dolore. Magni voluptatibus eius et maxime aut.\n\nAd officiis tempore voluptate vitae corrupti explicabo labore est. Consequatur expedita et sunt nihil aut. Deleniti porro iusto molestiae et beatae.\n\nDeleniti modi nulla qui et labore sequi corrupti. Qui voluptatem assumenda eum cupiditate et. Nesciunt ipsam ut ea possimus eum. Consectetur quidem suscipit atque dolore itaque voluptatibus et cupiditate.", + "created_at": "2016-03-22T15:20:35.777Z", + "updated_at": "2016-03-22T15:20:35.777Z", + "started_at": null, + "runner_id": null, + "coverage": null, + "commit_id": 36, + "commands": "$ deploy command", + "job_id": null, + "name": "test build 2", + "deploy": false, + "options": null, + "allow_failure": false, + "stage": "deploy", + "trigger_request_id": null, + "stage_idx": 1, + "stage_id": 12, + "tag": null, + "ref": "master", + "user_id": null, + "target_url": null, + "description": null, + "artifacts_file": { + "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts.zip" + }, + "artifacts_metadata": { + "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts_metadata.gz" + }, + "erased_by_id": null, + "erased_at": null + } + ] }, { "id": 12, @@ -6484,82 +6560,6 @@ "created_at": "2016-03-22T15:45:45.772Z", "updated_at": "2016-03-29T06:45:45.634Z" } - ], - "statuses": [ - { - "id": 71, - "project_id": 5, - "status": "failed", - "finished_at": "2016-03-29T06:28:12.630Z", - "trace": null, - "created_at": "2016-03-22T15:20:35.772Z", - "updated_at": "2016-03-29T06:28:12.634Z", - "started_at": null, - "runner_id": null, - "coverage": null, - "commit_id": 36, - "commands": "$ build command", - "job_id": null, - "name": "test build 1", - "deploy": false, - "options": null, - "allow_failure": false, - "stage": "test", - "trigger_request_id": null, - "stage_idx": 1, - "stage_id": 11, - "tag": null, - "ref": "master", - "user_id": null, - "target_url": null, - "description": null, - "artifacts_file": { - "url": null - }, - "artifacts_metadata": { - "url": null - }, - "erased_by_id": null, - "erased_at": null, - "type": "Ci::Build", - "token": "abcd" - }, - { - "id": 72, - "project_id": 5, - "status": "success", - "finished_at": null, - "trace": "Porro ea qui ut dolores. Labore ab nemo explicabo aspernatur quis voluptates corporis. Et quasi delectus est sit aperiam perspiciatis asperiores. Repudiandae cum aut consectetur accusantium officia sunt.\n\nQuidem dolore iusto quaerat ut aut inventore et molestiae. Libero voluptates atque nemo qui. Nulla temporibus ipsa similique facere.\n\nAliquam ipsam perferendis qui fugit accusantium omnis id voluptatum. Dignissimos aliquid dicta eos voluptatem assumenda quia. Sed autem natus unde dolor et non nisi et. Consequuntur nihil consequatur rerum est.\n\nSimilique neque est iste ducimus qui fuga cupiditate. Libero autem est aut fuga. Consectetur natus quis non ducimus ut dolore. Magni voluptatibus eius et maxime aut.\n\nAd officiis tempore voluptate vitae corrupti explicabo labore est. Consequatur expedita et sunt nihil aut. Deleniti porro iusto molestiae et beatae.\n\nDeleniti modi nulla qui et labore sequi corrupti. Qui voluptatem assumenda eum cupiditate et. Nesciunt ipsam ut ea possimus eum. Consectetur quidem suscipit atque dolore itaque voluptatibus et cupiditate.", - "created_at": "2016-03-22T15:20:35.777Z", - "updated_at": "2016-03-22T15:20:35.777Z", - "started_at": null, - "runner_id": null, - "coverage": null, - "commit_id": 36, - "commands": "$ deploy command", - "job_id": null, - "name": "test build 2", - "deploy": false, - "options": null, - "allow_failure": false, - "stage": "deploy", - "trigger_request_id": null, - "stage_idx": 1, - "stage_id": 12, - "tag": null, - "ref": "master", - "user_id": null, - "target_url": null, - "description": null, - "artifacts_file": { - "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts.zip" - }, - "artifacts_metadata": { - "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts_metadata.gz" - }, - "erased_by_id": null, - "erased_at": null - } ] }, { @@ -6578,76 +6578,87 @@ "started_at": null, "finished_at": null, "duration": null, - "statuses": [ - { - "id": 74, - "project_id": 5, - "status": "success", - "finished_at": null, - "trace": "Ad ut quod repudiandae iste dolor doloribus. Adipisci consequuntur deserunt omnis quasi eveniet et sed fugit. Aut nemo omnis molestiae impedit ex consequatur ducimus. Voluptatum exercitationem quia aut est et hic dolorem.\n\nQuasi repellendus et eaque magni eum facilis. Dolorem aperiam nam nihil pariatur praesentium ad aliquam. Commodi enim et eos tenetur. Odio voluptatibus laboriosam mollitia rerum exercitationem magnam consequuntur. Tenetur ea vel eum corporis.\n\nVoluptatibus optio in aliquid est voluptates. Ad a ut ab placeat vero blanditiis. Earum aspernatur quia beatae expedita voluptatem dignissimos provident. Quis minima id nemo ut aut est veritatis provident.\n\nRerum voluptatem quidem eius maiores magnam veniam. Voluptatem aperiam aut voluptate et nulla deserunt voluptas. Quaerat aut accusantium laborum est dolorem architecto reiciendis. Aliquam asperiores doloribus omnis maxime enim nesciunt. Eum aut rerum repellendus debitis et ut eius.\n\nQuaerat assumenda ea sit consequatur autem in. Cum eligendi voluptatem quo sed. Ut fuga iusto cupiditate autem sint.\n\nOfficia totam officiis architecto corporis molestiae amet ut. Tempora sed dolorum rerum omnis voluptatem accusantium sit eum. Quia debitis ipsum quidem aliquam inventore sunt consequatur qui.", - "created_at": "2016-03-22T15:20:35.846Z", - "updated_at": "2016-03-22T15:20:35.846Z", - "started_at": null, - "runner_id": null, - "coverage": null, - "commit_id": 37, - "commands": "$ build command", - "job_id": null, - "name": "test build 2", - "deploy": false, - "options": null, - "allow_failure": false, - "stage": "test", - "trigger_request_id": null, - "stage_idx": 1, - "tag": null, - "ref": "master", - "user_id": null, - "target_url": null, - "description": null, - "artifacts_file": { - "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts.zip" - }, - "artifacts_metadata": { - "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts_metadata.gz" - }, - "erased_by_id": null, - "erased_at": null - }, - { - "id": 73, - "project_id": 5, - "status": "canceled", - "finished_at": null, - "trace": null, - "created_at": "2016-03-22T15:20:35.842Z", - "updated_at": "2016-03-22T15:20:35.842Z", - "started_at": null, - "runner_id": null, - "coverage": null, - "commit_id": 37, - "commands": "$ build command", - "job_id": null, - "name": "test build 1", - "deploy": false, - "options": null, - "allow_failure": false, - "stage": "test", - "trigger_request_id": null, - "stage_idx": 1, - "tag": null, - "ref": "master", - "user_id": null, - "target_url": null, - "description": null, - "artifacts_file": { - "url": null - }, - "artifacts_metadata": { - "url": null - }, - "erased_by_id": null, - "erased_at": null + "stages": [ + { + "id": 21, + "project_id": 5, + "pipeline_id": 37, + "name": "test", + "status": 1, + "created_at": "2016-03-22T15:44:44.772Z", + "updated_at": "2016-03-29T06:44:44.634Z", + "statuses": [ + { + "id": 74, + "project_id": 5, + "status": "success", + "finished_at": null, + "trace": "Ad ut quod repudiandae iste dolor doloribus. Adipisci consequuntur deserunt omnis quasi eveniet et sed fugit. Aut nemo omnis molestiae impedit ex consequatur ducimus. Voluptatum exercitationem quia aut est et hic dolorem.\n\nQuasi repellendus et eaque magni eum facilis. Dolorem aperiam nam nihil pariatur praesentium ad aliquam. Commodi enim et eos tenetur. Odio voluptatibus laboriosam mollitia rerum exercitationem magnam consequuntur. Tenetur ea vel eum corporis.\n\nVoluptatibus optio in aliquid est voluptates. Ad a ut ab placeat vero blanditiis. Earum aspernatur quia beatae expedita voluptatem dignissimos provident. Quis minima id nemo ut aut est veritatis provident.\n\nRerum voluptatem quidem eius maiores magnam veniam. Voluptatem aperiam aut voluptate et nulla deserunt voluptas. Quaerat aut accusantium laborum est dolorem architecto reiciendis. Aliquam asperiores doloribus omnis maxime enim nesciunt. Eum aut rerum repellendus debitis et ut eius.\n\nQuaerat assumenda ea sit consequatur autem in. Cum eligendi voluptatem quo sed. Ut fuga iusto cupiditate autem sint.\n\nOfficia totam officiis architecto corporis molestiae amet ut. Tempora sed dolorum rerum omnis voluptatem accusantium sit eum. Quia debitis ipsum quidem aliquam inventore sunt consequatur qui.", + "created_at": "2016-03-22T15:20:35.846Z", + "updated_at": "2016-03-22T15:20:35.846Z", + "started_at": null, + "runner_id": null, + "coverage": null, + "commit_id": 37, + "commands": "$ build command", + "job_id": null, + "name": "test build 2", + "deploy": false, + "options": null, + "allow_failure": false, + "stage": "test", + "trigger_request_id": null, + "stage_idx": 1, + "tag": null, + "ref": "master", + "user_id": null, + "target_url": null, + "description": null, + "artifacts_file": { + "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts.zip" + }, + "artifacts_metadata": { + "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts_metadata.gz" + }, + "erased_by_id": null, + "erased_at": null + }, + { + "id": 73, + "project_id": 5, + "status": "canceled", + "finished_at": null, + "trace": null, + "created_at": "2016-03-22T15:20:35.842Z", + "updated_at": "2016-03-22T15:20:35.842Z", + "started_at": null, + "runner_id": null, + "coverage": null, + "commit_id": 37, + "commands": "$ build command", + "job_id": null, + "name": "test build 1", + "deploy": false, + "options": null, + "allow_failure": false, + "stage": "test", + "trigger_request_id": null, + "stage_idx": 1, + "tag": null, + "ref": "master", + "user_id": null, + "target_url": null, + "description": null, + "artifacts_file": { + "url": null + }, + "artifacts_metadata": { + "url": null + }, + "erased_by_id": null, + "erased_at": null + } + ] } ] }, @@ -6667,76 +6678,87 @@ "started_at": null, "finished_at": null, "duration": null, - "statuses": [ - { - "id": 76, - "project_id": 5, - "status": "success", - "finished_at": null, - "trace": "Et rerum quia ea cumque ut modi non. Libero eaque ipsam architecto maiores expedita deleniti. Ratione quia qui est id.\n\nQuod sit officiis sed unde inventore veniam quisquam velit. Ea harum cum quibusdam quisquam minima quo possimus non. Temporibus itaque aliquam aut rerum veritatis at.\n\nMagnam ipsum eius recusandae qui quis sit maiores eum. Et animi iusto aut itaque. Doloribus harum deleniti nobis accusantium et libero.\n\nRerum fuga perferendis magni commodi officiis id repudiandae. Consequatur ratione consequatur suscipit facilis sunt iure est dicta. Qui unde quasi facilis et quae nesciunt. Magnam iste et nobis officiis tenetur. Aspernatur quo et temporibus non in.\n\nNisi rerum velit est ad enim sint molestiae consequuntur. Quaerat nisi nesciunt quasi officiis. Possimus non blanditiis laborum quos.\n\nRerum laudantium facere animi qui. Ipsa est iusto magnam nihil. Enim omnis occaecati non dignissimos ut recusandae eum quasi. Qui maxime dolor et nemo voluptates incidunt quia.", - "created_at": "2016-03-22T15:20:35.882Z", - "updated_at": "2016-03-22T15:20:35.882Z", - "started_at": null, - "runner_id": null, - "coverage": null, - "commit_id": 38, - "commands": "$ build command", - "job_id": null, - "name": "test build 2", - "deploy": false, - "options": null, - "allow_failure": false, - "stage": "test", - "trigger_request_id": null, - "stage_idx": 1, - "tag": null, - "ref": "master", - "user_id": null, - "target_url": null, - "description": null, - "artifacts_file": { - "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts.zip" - }, - "artifacts_metadata": { - "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts_metadata.gz" - }, - "erased_by_id": null, - "erased_at": null - }, - { - "id": 75, - "project_id": 5, - "status": "failed", - "finished_at": null, - "trace": "Sed et iste recusandae dicta corporis. Sunt alias porro fugit sunt. Fugiat omnis nihil dignissimos aperiam explicabo doloremque sit aut. Harum fugit expedita quia rerum ut consequatur laboriosam aliquam.\n\nNatus libero ut ut tenetur earum. Tempora omnis autem omnis et libero dolores illum autem. Deleniti eos sunt mollitia ipsam. Cum dolor repellendus dolorum sequi officia. Ullam sunt in aut pariatur excepturi.\n\nDolor nihil debitis et est eos. Cumque eos eum saepe ducimus autem. Alias architecto consequatur aut pariatur possimus. Aut quos aut incidunt quam velit et. Quas voluptatum ad dolorum dignissimos.\n\nUt voluptates consectetur illo et. Est commodi accusantium vel quo. Eos qui fugiat soluta porro.\n\nRatione possimus alias vel maxime sint totam est repellat. Ipsum corporis eos sint voluptatem eos odit. Temporibus libero nulla harum eligendi labore similique ratione magnam. Suscipit sequi in omnis neque.\n\nLaudantium dolor amet omnis placeat mollitia aut molestiae. Aut rerum similique ipsum quod illo quas unde. Sunt aut veritatis eos omnis porro. Rem veritatis mollitia praesentium dolorem. Consequatur sequi ad cumque earum omnis quia necessitatibus.", - "created_at": "2016-03-22T15:20:35.864Z", - "updated_at": "2016-03-22T15:20:35.864Z", - "started_at": null, - "runner_id": null, - "coverage": null, - "commit_id": 38, - "commands": "$ build command", - "job_id": null, - "name": "test build 1", - "deploy": false, - "options": null, - "allow_failure": false, - "stage": "test", - "trigger_request_id": null, - "stage_idx": 1, - "tag": null, - "ref": "master", - "user_id": null, - "target_url": null, - "description": null, - "artifacts_file": { - "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts.zip" - }, - "artifacts_metadata": { - "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts_metadata.gz" - }, - "erased_by_id": null, - "erased_at": null + "stages": [ + { + "id": 22, + "project_id": 5, + "pipeline_id": 38, + "name": "test", + "status": 1, + "created_at": "2016-03-22T15:44:44.772Z", + "updated_at": "2016-03-29T06:44:44.634Z", + "statuses": [ + { + "id": 76, + "project_id": 5, + "status": "success", + "finished_at": null, + "trace": "Et rerum quia ea cumque ut modi non. Libero eaque ipsam architecto maiores expedita deleniti. Ratione quia qui est id.\n\nQuod sit officiis sed unde inventore veniam quisquam velit. Ea harum cum quibusdam quisquam minima quo possimus non. Temporibus itaque aliquam aut rerum veritatis at.\n\nMagnam ipsum eius recusandae qui quis sit maiores eum. Et animi iusto aut itaque. Doloribus harum deleniti nobis accusantium et libero.\n\nRerum fuga perferendis magni commodi officiis id repudiandae. Consequatur ratione consequatur suscipit facilis sunt iure est dicta. Qui unde quasi facilis et quae nesciunt. Magnam iste et nobis officiis tenetur. Aspernatur quo et temporibus non in.\n\nNisi rerum velit est ad enim sint molestiae consequuntur. Quaerat nisi nesciunt quasi officiis. Possimus non blanditiis laborum quos.\n\nRerum laudantium facere animi qui. Ipsa est iusto magnam nihil. Enim omnis occaecati non dignissimos ut recusandae eum quasi. Qui maxime dolor et nemo voluptates incidunt quia.", + "created_at": "2016-03-22T15:20:35.882Z", + "updated_at": "2016-03-22T15:20:35.882Z", + "started_at": null, + "runner_id": null, + "coverage": null, + "commit_id": 38, + "commands": "$ build command", + "job_id": null, + "name": "test build 2", + "deploy": false, + "options": null, + "allow_failure": false, + "stage": "test", + "trigger_request_id": null, + "stage_idx": 1, + "tag": null, + "ref": "master", + "user_id": null, + "target_url": null, + "description": null, + "artifacts_file": { + "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts.zip" + }, + "artifacts_metadata": { + "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts_metadata.gz" + }, + "erased_by_id": null, + "erased_at": null + }, + { + "id": 75, + "project_id": 5, + "status": "failed", + "finished_at": null, + "trace": "Sed et iste recusandae dicta corporis. Sunt alias porro fugit sunt. Fugiat omnis nihil dignissimos aperiam explicabo doloremque sit aut. Harum fugit expedita quia rerum ut consequatur laboriosam aliquam.\n\nNatus libero ut ut tenetur earum. Tempora omnis autem omnis et libero dolores illum autem. Deleniti eos sunt mollitia ipsam. Cum dolor repellendus dolorum sequi officia. Ullam sunt in aut pariatur excepturi.\n\nDolor nihil debitis et est eos. Cumque eos eum saepe ducimus autem. Alias architecto consequatur aut pariatur possimus. Aut quos aut incidunt quam velit et. Quas voluptatum ad dolorum dignissimos.\n\nUt voluptates consectetur illo et. Est commodi accusantium vel quo. Eos qui fugiat soluta porro.\n\nRatione possimus alias vel maxime sint totam est repellat. Ipsum corporis eos sint voluptatem eos odit. Temporibus libero nulla harum eligendi labore similique ratione magnam. Suscipit sequi in omnis neque.\n\nLaudantium dolor amet omnis placeat mollitia aut molestiae. Aut rerum similique ipsum quod illo quas unde. Sunt aut veritatis eos omnis porro. Rem veritatis mollitia praesentium dolorem. Consequatur sequi ad cumque earum omnis quia necessitatibus.", + "created_at": "2016-03-22T15:20:35.864Z", + "updated_at": "2016-03-22T15:20:35.864Z", + "started_at": null, + "runner_id": null, + "coverage": null, + "commit_id": 38, + "commands": "$ build command", + "job_id": null, + "name": "test build 1", + "deploy": false, + "options": null, + "allow_failure": false, + "stage": "test", + "trigger_request_id": null, + "stage_idx": 1, + "tag": null, + "ref": "master", + "user_id": null, + "target_url": null, + "description": null, + "artifacts_file": { + "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts.zip" + }, + "artifacts_metadata": { + "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts_metadata.gz" + }, + "erased_by_id": null, + "erased_at": null + } + ] } ] }, @@ -6756,76 +6778,87 @@ "started_at": null, "finished_at": null, "duration": null, - "statuses": [ - { - "id": 78, - "project_id": 5, - "status": "success", - "finished_at": null, - "trace": "Dolorem deserunt quas quia error hic quo cum vel. Natus voluptatem cumque expedita numquam odit. Eos expedita nostrum corporis consequatur est recusandae.\n\nCulpa blanditiis rerum repudiandae alias voluptatem. Velit iusto est ullam consequatur doloribus porro. Corporis voluptas consectetur est veniam et quia quae.\n\nEt aut magni fuga nesciunt officiis molestias. Quaerat et nam necessitatibus qui rerum. Architecto quia officiis voluptatem laborum est recusandae. Quasi ducimus soluta odit necessitatibus labore numquam dignissimos. Quia facere sint temporibus inventore sunt nihil saepe dolorum.\n\nFacere dolores quis dolores a. Est minus nostrum nihil harum. Earum laborum et ipsum unde neque sit nemo. Corrupti est consequatur minima fugit. Illum voluptatem illo error ducimus officia qui debitis.\n\nDignissimos porro a autem harum aut. Aut id reprehenderit et exercitationem. Est et quisquam ipsa temporibus molestiae. Architecto natus dolore qui fugiat incidunt. Autem odit veniam excepturi et voluptatibus culpa ipsum eos.\n\nAmet quo quisquam dignissimos soluta modi dolores. Sint omnis eius optio corporis dolor. Eligendi animi porro quia placeat ut.", - "created_at": "2016-03-22T15:20:35.927Z", - "updated_at": "2016-03-22T15:20:35.927Z", - "started_at": null, - "runner_id": null, - "coverage": null, - "commit_id": 39, - "commands": "$ build command", - "job_id": null, - "name": "test build 2", - "deploy": false, - "options": null, - "allow_failure": false, - "stage": "test", - "trigger_request_id": null, - "stage_idx": 1, - "tag": null, - "ref": "master", - "user_id": null, - "target_url": null, - "description": null, - "artifacts_file": { - "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts.zip" - }, - "artifacts_metadata": { - "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts_metadata.gz" - }, - "erased_by_id": null, - "erased_at": null - }, - { - "id": 77, - "project_id": 5, - "status": "failed", - "finished_at": null, - "trace": "Rerum ut et suscipit est perspiciatis. Inventore debitis cum eius vitae. Ex incidunt id velit aut quo nisi. Laboriosam repellat deserunt eius reiciendis architecto et. Est harum quos nesciunt nisi consectetur.\n\nAlias esse omnis sint officia est consequatur in nobis. Dignissimos dolorum vel eligendi nesciunt dolores sit. Veniam mollitia ducimus et exercitationem molestiae libero sed. Atque omnis debitis laudantium voluptatibus qui. Repellendus tempore est commodi pariatur.\n\nExpedita voluptate illum est alias non. Modi nesciunt ab assumenda laborum nulla consequatur molestias doloremque. Magnam quod officia vel explicabo accusamus ut voluptatem incidunt. Rerum ut aliquid ullam saepe. Est eligendi debitis beatae blanditiis reiciendis.\n\nQui fuga sit dolores libero maiores et suscipit. Consectetur asperiores omnis minima impedit eos fugiat. Similique omnis nisi sed vero inventore ipsum aliquam exercitationem.\n\nBlanditiis magni iure dolorum omnis ratione delectus molestiae. Atque officia dolor voluptatem culpa quod. Incidunt suscipit quidem possimus veritatis non vel. Iusto aliquid et id quia quasi.\n\nVel facere velit blanditiis incidunt cupiditate sed maiores consequuntur. Quasi quia dicta consequuntur et quia voluptatem iste id. Incidunt et rerum fuga esse sint.", - "created_at": "2016-03-22T15:20:35.905Z", - "updated_at": "2016-03-22T15:20:35.905Z", - "started_at": null, - "runner_id": null, - "coverage": null, - "commit_id": 39, - "commands": "$ build command", - "job_id": null, - "name": "test build 1", - "deploy": false, - "options": null, - "allow_failure": false, - "stage": "test", - "trigger_request_id": null, - "stage_idx": 1, - "tag": null, - "ref": "master", - "user_id": null, - "target_url": null, - "description": null, - "artifacts_file": { - "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts.zip" - }, - "artifacts_metadata": { - "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts_metadata.gz" - }, - "erased_by_id": null, - "erased_at": null + "stages": [ + { + "id": 23, + "project_id": 5, + "pipeline_id": 39, + "name": "test", + "status": 1, + "created_at": "2016-03-22T15:44:44.772Z", + "updated_at": "2016-03-29T06:44:44.634Z", + "statuses": [ + { + "id": 78, + "project_id": 5, + "status": "success", + "finished_at": null, + "trace": "Dolorem deserunt quas quia error hic quo cum vel. Natus voluptatem cumque expedita numquam odit. Eos expedita nostrum corporis consequatur est recusandae.\n\nCulpa blanditiis rerum repudiandae alias voluptatem. Velit iusto est ullam consequatur doloribus porro. Corporis voluptas consectetur est veniam et quia quae.\n\nEt aut magni fuga nesciunt officiis molestias. Quaerat et nam necessitatibus qui rerum. Architecto quia officiis voluptatem laborum est recusandae. Quasi ducimus soluta odit necessitatibus labore numquam dignissimos. Quia facere sint temporibus inventore sunt nihil saepe dolorum.\n\nFacere dolores quis dolores a. Est minus nostrum nihil harum. Earum laborum et ipsum unde neque sit nemo. Corrupti est consequatur minima fugit. Illum voluptatem illo error ducimus officia qui debitis.\n\nDignissimos porro a autem harum aut. Aut id reprehenderit et exercitationem. Est et quisquam ipsa temporibus molestiae. Architecto natus dolore qui fugiat incidunt. Autem odit veniam excepturi et voluptatibus culpa ipsum eos.\n\nAmet quo quisquam dignissimos soluta modi dolores. Sint omnis eius optio corporis dolor. Eligendi animi porro quia placeat ut.", + "created_at": "2016-03-22T15:20:35.927Z", + "updated_at": "2016-03-22T15:20:35.927Z", + "started_at": null, + "runner_id": null, + "coverage": null, + "commit_id": 39, + "commands": "$ build command", + "job_id": null, + "name": "test build 2", + "deploy": false, + "options": null, + "allow_failure": false, + "stage": "test", + "trigger_request_id": null, + "stage_idx": 1, + "tag": null, + "ref": "master", + "user_id": null, + "target_url": null, + "description": null, + "artifacts_file": { + "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts.zip" + }, + "artifacts_metadata": { + "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts_metadata.gz" + }, + "erased_by_id": null, + "erased_at": null + }, + { + "id": 77, + "project_id": 5, + "status": "failed", + "finished_at": null, + "trace": "Rerum ut et suscipit est perspiciatis. Inventore debitis cum eius vitae. Ex incidunt id velit aut quo nisi. Laboriosam repellat deserunt eius reiciendis architecto et. Est harum quos nesciunt nisi consectetur.\n\nAlias esse omnis sint officia est consequatur in nobis. Dignissimos dolorum vel eligendi nesciunt dolores sit. Veniam mollitia ducimus et exercitationem molestiae libero sed. Atque omnis debitis laudantium voluptatibus qui. Repellendus tempore est commodi pariatur.\n\nExpedita voluptate illum est alias non. Modi nesciunt ab assumenda laborum nulla consequatur molestias doloremque. Magnam quod officia vel explicabo accusamus ut voluptatem incidunt. Rerum ut aliquid ullam saepe. Est eligendi debitis beatae blanditiis reiciendis.\n\nQui fuga sit dolores libero maiores et suscipit. Consectetur asperiores omnis minima impedit eos fugiat. Similique omnis nisi sed vero inventore ipsum aliquam exercitationem.\n\nBlanditiis magni iure dolorum omnis ratione delectus molestiae. Atque officia dolor voluptatem culpa quod. Incidunt suscipit quidem possimus veritatis non vel. Iusto aliquid et id quia quasi.\n\nVel facere velit blanditiis incidunt cupiditate sed maiores consequuntur. Quasi quia dicta consequuntur et quia voluptatem iste id. Incidunt et rerum fuga esse sint.", + "created_at": "2016-03-22T15:20:35.905Z", + "updated_at": "2016-03-22T15:20:35.905Z", + "started_at": null, + "runner_id": null, + "coverage": null, + "commit_id": 39, + "commands": "$ build command", + "job_id": null, + "name": "test build 1", + "deploy": false, + "options": null, + "allow_failure": false, + "stage": "test", + "trigger_request_id": null, + "stage_idx": 1, + "tag": null, + "ref": "master", + "user_id": null, + "target_url": null, + "description": null, + "artifacts_file": { + "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts.zip" + }, + "artifacts_metadata": { + "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts_metadata.gz" + }, + "erased_by_id": null, + "erased_at": null + } + ] } ] }, @@ -6845,76 +6878,87 @@ "started_at": null, "finished_at": null, "duration": null, - "statuses": [ - { - "id": 79, - "project_id": 5, - "status": "failed", - "finished_at": "2016-03-29T06:28:12.695Z", - "trace": "Sed culpa est et facere saepe vel id ab. Quas temporibus aut similique dolorem consequatur corporis aut praesentium. Cum officia molestiae sit earum excepturi.\n\nSint possimus aut ratione quia. Quis nesciunt ratione itaque illo. Tenetur est dolor assumenda possimus voluptatem quia minima. Accusamus reprehenderit ut et itaque non reiciendis incidunt.\n\nRerum suscipit quibusdam dolore nam omnis. Consequatur ipsa nihil ut enim blanditiis delectus. Nulla quis hic occaecati mollitia qui placeat. Quo rerum sed perferendis a accusantium consequatur commodi ut. Sit quae et cumque vel eius tempora nostrum.\n\nUllam dolorem et itaque sint est. Ea molestias quia provident dolorem vitae error et et. Ea expedita officiis iste non. Qui vitae odit saepe illum. Dolores enim ratione deserunt tempore expedita amet non neque.\n\nEligendi asperiores voluptatibus omnis repudiandae expedita distinctio qui aliquid. Autem aut doloremque distinctio ab. Nostrum sapiente repudiandae aspernatur ea et quae voluptas. Officiis perspiciatis nisi laudantium asperiores error eligendi ab. Eius quia amet magni omnis exercitationem voluptatum et.\n\nVoluptatem ullam labore quas dicta est ex voluptas. Pariatur ea modi voluptas consequatur dolores perspiciatis similique. Numquam in distinctio perspiciatis ut qui earum. Quidem omnis mollitia facere aut beatae. Ea est iure et voluptatem.", - "created_at": "2016-03-22T15:20:35.950Z", - "updated_at": "2016-03-29T06:28:12.696Z", - "started_at": null, - "runner_id": null, - "coverage": null, - "commit_id": 40, - "commands": "$ build command", - "job_id": null, - "name": "test build 1", - "deploy": false, - "options": null, - "allow_failure": false, - "stage": "test", - "trigger_request_id": null, - "stage_idx": 1, - "tag": null, - "ref": "master", - "user_id": null, - "target_url": null, - "description": null, - "artifacts_file": { - "url": null - }, - "artifacts_metadata": { - "url": null - }, - "erased_by_id": null, - "erased_at": null - }, - { - "id": 80, - "project_id": 5, - "status": "success", - "finished_at": null, - "trace": "Impedit et optio nemo ipsa. Non ad non quis ut sequi laudantium omnis velit. Corporis a enim illo eos. Quia totam tempore inventore ad est.\n\nNihil recusandae cupiditate eaque voluptatem molestias sint. Consequatur id voluptatem cupiditate harum. Consequuntur iusto quaerat reiciendis aut autem libero est. Quisquam dolores veritatis rerum et sint maxime ullam libero. Id quas porro ut perspiciatis rem amet vitae.\n\nNemo inventore minus blanditiis magnam. Modi consequuntur nostrum aut voluptatem ex. Sunt rerum rem optio mollitia qui aliquam officiis officia. Aliquid eos et id aut minus beatae reiciendis.\n\nDolores non in temporibus dicta. Fugiat voluptatem est aspernatur expedita voluptatum nam qui. Quia et eligendi sit quae sint tempore exercitationem eos. Est sapiente corrupti quidem at. Qui magni odio repudiandae saepe tenetur optio dolore.\n\nEos placeat soluta at dolorem adipisci provident. Quo commodi id reprehenderit possimus quo tenetur. Ipsum et quae eligendi laborum. Et qui nesciunt at quasi quidem voluptatem cum rerum. Excepturi non facilis aut sunt vero sed.\n\nQui explicabo ratione ut eligendi recusandae. Quis quasi quas molestiae consequatur voluptatem et voluptatem. Ex repellat saepe occaecati aperiam ea eveniet dignissimos facilis.", - "created_at": "2016-03-22T15:20:35.966Z", - "updated_at": "2016-03-22T15:20:35.966Z", - "started_at": null, - "runner_id": null, - "coverage": null, - "commit_id": 40, - "commands": "$ build command", - "job_id": null, - "name": "test build 2", - "deploy": false, - "options": null, - "allow_failure": false, - "stage": "test", - "trigger_request_id": null, - "stage_idx": 1, - "tag": null, - "ref": "master", - "user_id": null, - "target_url": null, - "description": null, - "artifacts_file": { - "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts.zip" - }, - "artifacts_metadata": { - "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts_metadata.gz" - }, - "erased_by_id": null, - "erased_at": null + "stages": [ + { + "id": 24, + "project_id": 5, + "pipeline_id": 40, + "name": "test", + "status": 1, + "created_at": "2016-03-22T15:44:44.772Z", + "updated_at": "2016-03-29T06:44:44.634Z", + "statuses": [ + { + "id": 79, + "project_id": 5, + "status": "failed", + "finished_at": "2016-03-29T06:28:12.695Z", + "trace": "Sed culpa est et facere saepe vel id ab. Quas temporibus aut similique dolorem consequatur corporis aut praesentium. Cum officia molestiae sit earum excepturi.\n\nSint possimus aut ratione quia. Quis nesciunt ratione itaque illo. Tenetur est dolor assumenda possimus voluptatem quia minima. Accusamus reprehenderit ut et itaque non reiciendis incidunt.\n\nRerum suscipit quibusdam dolore nam omnis. Consequatur ipsa nihil ut enim blanditiis delectus. Nulla quis hic occaecati mollitia qui placeat. Quo rerum sed perferendis a accusantium consequatur commodi ut. Sit quae et cumque vel eius tempora nostrum.\n\nUllam dolorem et itaque sint est. Ea molestias quia provident dolorem vitae error et et. Ea expedita officiis iste non. Qui vitae odit saepe illum. Dolores enim ratione deserunt tempore expedita amet non neque.\n\nEligendi asperiores voluptatibus omnis repudiandae expedita distinctio qui aliquid. Autem aut doloremque distinctio ab. Nostrum sapiente repudiandae aspernatur ea et quae voluptas. Officiis perspiciatis nisi laudantium asperiores error eligendi ab. Eius quia amet magni omnis exercitationem voluptatum et.\n\nVoluptatem ullam labore quas dicta est ex voluptas. Pariatur ea modi voluptas consequatur dolores perspiciatis similique. Numquam in distinctio perspiciatis ut qui earum. Quidem omnis mollitia facere aut beatae. Ea est iure et voluptatem.", + "created_at": "2016-03-22T15:20:35.950Z", + "updated_at": "2016-03-29T06:28:12.696Z", + "started_at": null, + "runner_id": null, + "coverage": null, + "commit_id": 40, + "commands": "$ build command", + "job_id": null, + "name": "test build 1", + "deploy": false, + "options": null, + "allow_failure": false, + "stage": "test", + "trigger_request_id": null, + "stage_idx": 1, + "tag": null, + "ref": "master", + "user_id": null, + "target_url": null, + "description": null, + "artifacts_file": { + "url": null + }, + "artifacts_metadata": { + "url": null + }, + "erased_by_id": null, + "erased_at": null + }, + { + "id": 80, + "project_id": 5, + "status": "success", + "finished_at": null, + "trace": "Impedit et optio nemo ipsa. Non ad non quis ut sequi laudantium omnis velit. Corporis a enim illo eos. Quia totam tempore inventore ad est.\n\nNihil recusandae cupiditate eaque voluptatem molestias sint. Consequatur id voluptatem cupiditate harum. Consequuntur iusto quaerat reiciendis aut autem libero est. Quisquam dolores veritatis rerum et sint maxime ullam libero. Id quas porro ut perspiciatis rem amet vitae.\n\nNemo inventore minus blanditiis magnam. Modi consequuntur nostrum aut voluptatem ex. Sunt rerum rem optio mollitia qui aliquam officiis officia. Aliquid eos et id aut minus beatae reiciendis.\n\nDolores non in temporibus dicta. Fugiat voluptatem est aspernatur expedita voluptatum nam qui. Quia et eligendi sit quae sint tempore exercitationem eos. Est sapiente corrupti quidem at. Qui magni odio repudiandae saepe tenetur optio dolore.\n\nEos placeat soluta at dolorem adipisci provident. Quo commodi id reprehenderit possimus quo tenetur. Ipsum et quae eligendi laborum. Et qui nesciunt at quasi quidem voluptatem cum rerum. Excepturi non facilis aut sunt vero sed.\n\nQui explicabo ratione ut eligendi recusandae. Quis quasi quas molestiae consequatur voluptatem et voluptatem. Ex repellat saepe occaecati aperiam ea eveniet dignissimos facilis.", + "created_at": "2016-03-22T15:20:35.966Z", + "updated_at": "2016-03-22T15:20:35.966Z", + "started_at": null, + "runner_id": null, + "coverage": null, + "commit_id": 40, + "commands": "$ build command", + "job_id": null, + "name": "test build 2", + "deploy": false, + "options": null, + "allow_failure": false, + "stage": "test", + "trigger_request_id": null, + "stage_idx": 1, + "tag": null, + "ref": "master", + "user_id": null, + "target_url": null, + "description": null, + "artifacts_file": { + "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts.zip" + }, + "artifacts_metadata": { + "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts_metadata.gz" + }, + "erased_by_id": null, + "erased_at": null + } + ] } ] } 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 70a6d1a3c6a..77e57e5ed3e 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -181,14 +181,20 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do end context 'when restoring hierarchy of pipeline, stages and jobs' do - let(:pipeline) { Ci::Pipeline.first } + it 'restores statuses' do + expect(CommitStatus.all.count).to be 10 + end it 'restores pipeline stages' do - expect(pipeline.stages.count).to be 2 + expect(Ci::Stage.all.count).to be 6 end it 'correctly restores association between a stage and a job' do - expect(pipeline.statuses).to all(have_attributes(stage_id: a_value > 0)) + expect(CommitStatus.all).to all(have_attributes(stage_id: a_value > 0)) + end + + it 'correctly restores association between a stage and a pipeline' do + expect(CommitStatus.all).to all(have_attributes(pipeline_id: a_value > 0)) end end end -- cgit v1.2.1 From bf8c5643a9cb665467deea0106fa35b91b2fa938 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 5 Jan 2018 15:18:17 +0100 Subject: Bump import/export version to 2.2.0 We need to bump import/export version because we introduced a new object's hierarchy that is not backwards compatible. --- doc/user/project/settings/import_export.md | 3 ++- lib/gitlab/import_export.rb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md index 1b8a84c9599..b8f865679a2 100644 --- a/doc/user/project/settings/import_export.md +++ b/doc/user/project/settings/import_export.md @@ -30,7 +30,8 @@ with all their related data and be moved into a new GitLab instance. | GitLab version | Import/Export version | | ---------------- | --------------------- | -| 10.3 to current | 0.2.1 | +| 10.4 to current | 0.2.2 | +| 10.3 | 0.2.1 | | 10.0 | 0.2.0 | | 9.4.0 | 0.1.8 | | 9.2.0 | 0.1.7 | diff --git a/lib/gitlab/import_export.rb b/lib/gitlab/import_export.rb index 2066005dddc..af203ff711d 100644 --- a/lib/gitlab/import_export.rb +++ b/lib/gitlab/import_export.rb @@ -3,7 +3,7 @@ module Gitlab extend self # For every version update, the version history in import_export.md has to be kept up to date. - VERSION = '0.2.1'.freeze + VERSION = '0.2.2'.freeze FILENAME_LIMIT = 50 def export_path(relative_path:) -- cgit v1.2.1 From adc9e13d279cec7f18c47b771bbd5c734ab2731a Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 5 Jan 2018 15:19:05 +0100 Subject: Fix import/export project tree saver specs --- .../lib/gitlab/import_export/project_tree_restorer_spec.rb | 14 +++++++++----- spec/lib/gitlab/import_export/project_tree_saver_spec.rb | 12 ++++++++++-- 2 files changed, 19 insertions(+), 7 deletions(-) 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 77e57e5ed3e..45e983a8604 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -181,19 +181,23 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do end context 'when restoring hierarchy of pipeline, stages and jobs' do - it 'restores statuses' do - expect(CommitStatus.all.count).to be 10 - end - it 'restores pipeline stages' do expect(Ci::Stage.all.count).to be 6 end + it 'correctly restores association between stage and a pipeline' do + expect(Ci::Stage.all).to all(have_attributes(pipeline_id: a_value > 0)) + end + + it 'restores statuses' do + expect(CommitStatus.all.count).to be 10 + end + it 'correctly restores association between a stage and a job' do expect(CommitStatus.all).to all(have_attributes(stage_id: a_value > 0)) end - it 'correctly restores association between a stage and a pipeline' do + it 'correctly restores association between a pipeline and a job' do expect(CommitStatus.all).to all(have_attributes(pipeline_id: a_value > 0)) end end 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 6faf3d82981..08e5bbbd400 100644 --- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb @@ -109,12 +109,20 @@ describe Gitlab::ImportExport::ProjectTreeSaver do expect(saved_project_json['merge_requests'].first['notes'].first['author']).not_to be_empty end + it 'has pipeline stages' do + expect(saved_project_json.dig('pipelines', 0, 'stages')).not_to be_empty + end + it 'has pipeline statuses' do - expect(saved_project_json['pipelines'].first['statuses']).not_to be_empty + expect(saved_project_json.dig('pipelines', 0, 'stages', 0, 'statuses')).not_to be_empty end it 'has pipeline builds' do - expect(saved_project_json['pipelines'].first['statuses'].count { |hash| hash['type'] == 'Ci::Build' }).to eq(1) + builds_count = saved_project_json + .dig('pipelines', 0, 'stages', 0, 'statuses') + .count { |hash| hash['type'] == 'Ci::Build' } + + expect(builds_count).to eq(1) end it 'has no when YML attributes but only the DB column' do -- cgit v1.2.1 From a01994bf075ccade4487b398bb59ef7f9ef21522 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 5 Jan 2018 15:20:41 +0100 Subject: Add changelog entry for import/export associations fix --- .../unreleased/fix-gb-fix-import-export-restoring-associations.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 changelogs/unreleased/fix-gb-fix-import-export-restoring-associations.yml diff --git a/changelogs/unreleased/fix-gb-fix-import-export-restoring-associations.yml b/changelogs/unreleased/fix-gb-fix-import-export-restoring-associations.yml new file mode 100644 index 00000000000..58df0024d61 --- /dev/null +++ b/changelogs/unreleased/fix-gb-fix-import-export-restoring-associations.yml @@ -0,0 +1,6 @@ +--- +title: Fix missing references to pipeline objects when restoring project with import/export + feature +merge_request: 16221 +author: +type: fixed -- cgit v1.2.1 From 8bdc6c74e82445048d66f6bf4be9dd0db7dc4737 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 5 Jan 2018 15:32:41 +0100 Subject: Rephrase paragraph about e2e tests in merge requests in docs --- doc/development/testing_guide/end_to_end_tests.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/doc/development/testing_guide/end_to_end_tests.md b/doc/development/testing_guide/end_to_end_tests.md index 30efe3e3b76..abe5b06e0f0 100644 --- a/doc/development/testing_guide/end_to_end_tests.md +++ b/doc/development/testing_guide/end_to_end_tests.md @@ -20,15 +20,13 @@ You can find these nightly pipelines at [GitLab QA pipelines page][gitlab-qa-pip ### Testing code in merge requests -It is also possible to trigger build of GitLab packages and then pass these -package to GitLab QA to run tests in a [pipeline][gitlab-qa-pipelines]. +It is possible to run end-to-end tests (eventually being run within a +[GitLab QA pipeline][gitlab-qa-pipelines]) for a merge request by triggering +the `package-qa` manual action, that should be present in a merge request +widget. -Developers can trigger the `package-qa` manual action, that should be present in -the merge request widget. - -It is also possible to trigger Gitlab QA pipeline from merge requests in -Omnibus GitLab project. You can find a manual action that is similar to -`package-qa`, mentioned above, in your Omnibus-related merge requests as well. +Mmanual action that starts end-to-end tests is also available in merge requests +in Omnibus GitLab project. Below you can read more about how to use it and how does it work. -- cgit v1.2.1 From 7e117b4c9d7fe51215fc2af46c2429db7b71f32c Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 5 Jan 2018 15:38:56 +0100 Subject: Assert on correctly restoring pipelines after an import --- spec/lib/gitlab/import_export/project_tree_restorer_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) 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 45e983a8604..9dfd879a1bc 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -181,6 +181,10 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do end context 'when restoring hierarchy of pipeline, stages and jobs' do + it 'restores pipelines' do + expect(Ci::Pipeline.all.count).to be 5 + end + it 'restores pipeline stages' do expect(Ci::Stage.all.count).to be 6 end -- cgit v1.2.1 From 288b276077987bc77f191d2cb93eb2f764c5c1ef Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 20 Dec 2017 14:48:09 +0100 Subject: Copy Mermaid graphs as GFM --- app/assets/javascripts/behaviors/copy_as_gfm.js | 12 ++++ app/assets/javascripts/render_mermaid.js | 20 +++++- lib/banzai/filter/mermaid_filter.rb | 11 +-- spec/features/copy_as_gfm_spec.rb | 96 +++++++++++++++++++++++++ spec/features/markdown_spec.rb | 2 +- spec/lib/banzai/filter/mermaid_filter_spec.rb | 4 +- 6 files changed, 131 insertions(+), 14 deletions(-) diff --git a/app/assets/javascripts/behaviors/copy_as_gfm.js b/app/assets/javascripts/behaviors/copy_as_gfm.js index e7dc4ef8304..c6eca72c51b 100644 --- a/app/assets/javascripts/behaviors/copy_as_gfm.js +++ b/app/assets/javascripts/behaviors/copy_as_gfm.js @@ -74,6 +74,18 @@ const gfmRules = { return `![${el.dataset.title}](${el.getAttribute('src')})`; }, }, + MermaidFilter: { + 'svg.mermaid'(el, text) { + const sourceEl = el.querySelector('text.source'); + if (!sourceEl) return false; + + return `\`\`\`mermaid\n${CopyAsGFM.nodeToGFM(sourceEl)}\n\`\`\``; + }, + 'svg.mermaid style, svg.mermaid g'(el, text) { + // We don't want to include the content of these elements in the copied text. + return ''; + }, + }, MathFilter: { 'pre.code.math[data-math-style=display]'(el, text) { return `\`\`\`math\n${text.trim()}\n\`\`\``; diff --git a/app/assets/javascripts/render_mermaid.js b/app/assets/javascripts/render_mermaid.js index 41942c04a4e..b7cde6fb092 100644 --- a/app/assets/javascripts/render_mermaid.js +++ b/app/assets/javascripts/render_mermaid.js @@ -24,7 +24,25 @@ export default function renderMermaid($els) { }); $els.each((i, el) => { - mermaid.init(undefined, el); + const source = el.textContent; + + mermaid.init(undefined, el, (id) => { + const svg = document.getElementById(id); + + svg.classList.add('mermaid'); + + // pre > code > svg + svg.closest('pre').replaceWith(svg); + + // We need to add the original source into the DOM to allow Copy-as-GFM + // to access it. + const sourceEl = document.createElement('text'); + sourceEl.classList.add('source'); + sourceEl.setAttribute('display', 'none'); + sourceEl.textContent = source; + + svg.appendChild(sourceEl); + }); }); }).catch((err) => { Flash(`Can't load mermaid module: ${err}`); diff --git a/lib/banzai/filter/mermaid_filter.rb b/lib/banzai/filter/mermaid_filter.rb index b545b947a2c..65c131e08d9 100644 --- a/lib/banzai/filter/mermaid_filter.rb +++ b/lib/banzai/filter/mermaid_filter.rb @@ -2,16 +2,7 @@ module Banzai module Filter class MermaidFilter < HTML::Pipeline::Filter def call - doc.css('pre[lang="mermaid"]').add_class('mermaid') - doc.css('pre[lang="mermaid"]').add_class('js-render-mermaid') - - # The `` blocks are added in the lib/banzai/filter/syntax_highlight_filter.rb - # We want to keep context and consistency, so we the blocks are added for all filters. - # Details: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15107/diffs?diff_id=7962900#note_45495859 - doc.css('pre[lang="mermaid"]').each do |pre| - document = pre.at('code') - document.replace(document.content) - end + doc.css('pre[lang="mermaid"] > code').add_class('js-render-mermaid') doc end diff --git a/spec/features/copy_as_gfm_spec.rb b/spec/features/copy_as_gfm_spec.rb index 1fcb8d5bc67..d8f1a919522 100644 --- a/spec/features/copy_as_gfm_spec.rb +++ b/spec/features/copy_as_gfm_spec.rb @@ -284,6 +284,102 @@ describe 'Copy as GFM', :js do expect(output_gfm.strip).to eq(gfm.strip) end + verify( + 'MermaidFilter: mermaid as converted from GFM to HTML', + + <<-GFM.strip_heredoc + ```mermaid + graph TD; + A-->B; + ``` + GFM + ) + + aggregate_failures('MermaidFilter: mermaid as transformed from HTML to SVG') do + gfm = <<-GFM.strip_heredoc + ```mermaid + graph TD; + A-->B; + ``` + GFM + + html = <<-HTML.strip_heredoc + + + + + + + + + + + + + + + + + + + +
+ +
+
+
+
+
+ + + + + + +
A
+
+
+
+
+ + + + + + +
B
+
+
+
+
+
+
+
+ graph TD; + A-->B; + +
+ HTML + + output_gfm = html_to_gfm(html) + expect(output_gfm.strip).to eq(gfm.strip) + end + verify( 'SanitizationFilter', diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb index e285befc66f..a2b78a5e021 100644 --- a/spec/features/markdown_spec.rb +++ b/spec/features/markdown_spec.rb @@ -71,7 +71,7 @@ describe 'GitLab Markdown' do it 'parses mermaid code block' do aggregate_failures do - expect(doc).to have_selector('pre.code.js-render-mermaid') + expect(doc).to have_selector('pre[lang=mermaid] > code.js-render-mermaid') end end diff --git a/spec/lib/banzai/filter/mermaid_filter_spec.rb b/spec/lib/banzai/filter/mermaid_filter_spec.rb index 532d25e121d..f6474c8936d 100644 --- a/spec/lib/banzai/filter/mermaid_filter_spec.rb +++ b/spec/lib/banzai/filter/mermaid_filter_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' describe Banzai::Filter::MermaidFilter do include FilterSpecHelper - it 'adds `js-render-mermaid` class to the `pre` tag' do + it 'adds `js-render-mermaid` class to the `code` tag' do doc = filter("
graph TD;\n  A-->B;\n
") - result = doc.xpath('descendant-or-self::pre').first + result = doc.css('code').first expect(result[:class]).to include('js-render-mermaid') end -- cgit v1.2.1 From 34b9cc9674554155af49c9a7fe60aaeba72bb23d Mon Sep 17 00:00:00 2001 From: Brent Greeff Date: Fri, 5 Jan 2018 15:21:53 +0000 Subject: API: get participants from merge_requests & issues --- ...s-40986-get-participants-from-issues-mr-api.yml | 5 +++ doc/api/issues.md | 39 ++++++++++++++++++++++ doc/api/merge_requests.md | 35 +++++++++++++++++++ lib/api/issues.rb | 13 ++++++++ lib/api/merge_requests.rb | 10 ++++++ spec/requests/api/issues_spec.rb | 12 +++++++ spec/requests/api/merge_requests_spec.rb | 6 ++++ .../requests/api/issuable_participants_examples.rb | 29 ++++++++++++++++ 8 files changed, 149 insertions(+) create mode 100644 changelogs/unreleased/issues-40986-get-participants-from-issues-mr-api.yml create mode 100644 spec/support/shared_examples/requests/api/issuable_participants_examples.rb diff --git a/changelogs/unreleased/issues-40986-get-participants-from-issues-mr-api.yml b/changelogs/unreleased/issues-40986-get-participants-from-issues-mr-api.yml new file mode 100644 index 00000000000..4cac87b0cdb --- /dev/null +++ b/changelogs/unreleased/issues-40986-get-participants-from-issues-mr-api.yml @@ -0,0 +1,5 @@ +--- +title: 'API: get participants from merge_requests & issues' +merge_request: 16187 +author: Brent Greeff +type: added diff --git a/doc/api/issues.md b/doc/api/issues.md index d2fefbe68aa..da89db17cd9 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -1124,6 +1124,45 @@ Example response: ``` +## Participants on issues + +``` +GET /projects/:id/issues/:issue_iid/participants +``` + +| Attribute | Type | Required | Description | +|-------------|---------|----------|--------------------------------------| +| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | +| `issue_iid` | integer | yes | The internal ID of a project's issue | + +```bash +curl --request GET --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/participants +``` + +Example response: + +```json +[ + { + "id": 1, + "name": "John Doe1", + "username": "user1", + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon", + "web_url": "http://localhost/user1" + }, + { + "id": 5, + "name": "John Doe5", + "username": "user5", + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/4aea8cf834ed91844a2da4ff7ae6b491?s=80&d=identicon", + "web_url": "http://localhost/user5" + } +] +``` + + ## Comments on issues Comments are done via the [notes](notes.md) resource. diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 4d3592e8f71..24afcef9a31 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -308,6 +308,41 @@ Parameters: } ``` +## Get single MR participants + +Get a list of merge request participants. + +``` +GET /projects/:id/merge_requests/:merge_request_iid/participants +``` + +Parameters: + +- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user +- `merge_request_iid` (required) - The internal ID of the merge request + + +```json +[ + { + "id": 1, + "name": "John Doe1", + "username": "user1", + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/c922747a93b40d1ea88262bf1aebee62?s=80&d=identicon", + "web_url": "http://localhost/user1" + }, + { + "id": 2, + "name": "John Doe2", + "username": "user2", + "state": "active", + "avatar_url": "http://www.gravatar.com/avatar/10fc7f102be8de7657fb4d80898bbfe3?s=80&d=identicon", + "web_url": "http://localhost/user2" + }, +] +``` + ## Get single MR commits Get a list of merge request commits. diff --git a/lib/api/issues.rb b/lib/api/issues.rb index b29c5848aef..7aa10631d53 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -277,6 +277,19 @@ module API present paginate(merge_requests), with: Entities::MergeRequestBasic, current_user: current_user, project: user_project end + desc 'List participants for an issue' do + success Entities::UserBasic + end + params do + requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue' + end + get ':id/issues/:issue_iid/participants' do + issue = find_project_issue(params[:issue_iid]) + participants = ::Kaminari.paginate_array(issue.participants) + + present paginate(participants), with: Entities::UserBasic, current_user: current_user, project: user_project + end + desc 'Get the user agent details for an issue' do success Entities::UserAgentDetail end diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 02f2b75ab9d..8f665b39fa8 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -185,6 +185,16 @@ module API present merge_request, with: Entities::MergeRequest, current_user: current_user, project: user_project end + desc 'Get the participants of a merge request' do + success Entities::UserBasic + end + get ':id/merge_requests/:merge_request_iid/participants' do + merge_request = find_merge_request_with_access(params[:merge_request_iid]) + participants = ::Kaminari.paginate_array(merge_request.participants) + + present paginate(participants), with: Entities::UserBasic + end + desc 'Get the commits of a merge request' do success Entities::Commit end diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 00d9c795619..320217f2032 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -1582,4 +1582,16 @@ describe API::Issues, :mailer do expect(json_response).to be_an Array expect(json_response.length).to eq(size) if size end + + describe 'GET projects/:id/issues/:issue_iid/participants' do + it_behaves_like 'issuable participants endpoint' do + let(:entity) { issue } + end + + it 'returns 404 if the issue is confidential' do + post api("/projects/#{project.id}/issues/#{confidential_issue.iid}/participants", non_member) + + expect(response).to have_gitlab_http_status(404) + end + end end diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index ef3f610740d..0c9fbb1f187 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -500,6 +500,12 @@ describe API::MergeRequests do end end + describe 'GET /projects/:id/merge_requests/:merge_request_iid/participants' do + it_behaves_like 'issuable participants endpoint' do + let(:entity) { merge_request } + end + end + describe 'GET /projects/:id/merge_requests/:merge_request_iid/commits' do it 'returns a 200 when merge request is valid' do get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/commits", user) diff --git a/spec/support/shared_examples/requests/api/issuable_participants_examples.rb b/spec/support/shared_examples/requests/api/issuable_participants_examples.rb new file mode 100644 index 00000000000..96d59e0c472 --- /dev/null +++ b/spec/support/shared_examples/requests/api/issuable_participants_examples.rb @@ -0,0 +1,29 @@ +shared_examples 'issuable participants endpoint' do + let(:area) { entity.class.name.underscore.pluralize } + + it 'returns participants' do + get api("/projects/#{project.id}/#{area}/#{entity.iid}/participants", user) + + expect(response).to have_gitlab_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.size).to eq(entity.participants.size) + + last_participant = entity.participants.last + expect(json_response.last['id']).to eq(last_participant.id) + expect(json_response.last['name']).to eq(last_participant.name) + expect(json_response.last['username']).to eq(last_participant.username) + end + + it 'returns a 404 when iid does not exist' do + get api("/projects/#{project.id}/#{area}/999/participants", user) + + expect(response).to have_gitlab_http_status(404) + end + + it 'returns a 404 when id is used instead of iid' do + get api("/projects/#{project.id}/#{area}/#{entity.id}/participants", user) + + expect(response).to have_gitlab_http_status(404) + end +end -- cgit v1.2.1 From 7f30bb9c29bc1ff0c903a16bbf678db31c7408ec Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 4 Jan 2018 16:49:15 +0100 Subject: Run background migrations with a minimum interval This adds a minimum interval to BackgroundMigrationWorker, ensuring background migrations of the same class only run once every 5 minutes. This prevents a thundering herd problem where scheduled migrations all run at once due to their delays having been expired (e.g. as the result of a queue being paused for a long time). If a job was recently executed it's rescheduled with a delay that equals the remaining time of the job's lease. This means that if the lease expires in two minutes we only need to wait two minutes, instead of five. Fixes https://gitlab.com/gitlab-org/gitlab-ce/issues/41624 --- app/workers/background_migration_worker.rb | 45 +++++++++++++++++++++- .../unreleased/delay-background-migrations.yml | 5 +++ lib/gitlab/database/migration_helpers.rb | 6 +++ lib/gitlab/exclusive_lease.rb | 11 ++++++ spec/lib/gitlab/database/migration_helpers_spec.rb | 10 ++--- spec/lib/gitlab/exclusive_lease_spec.rb | 15 ++++++++ spec/migrations/normalize_ldap_extern_uids_spec.rb | 6 +-- spec/workers/background_migration_worker_spec.rb | 23 ++++++++++- 8 files changed, 110 insertions(+), 11 deletions(-) create mode 100644 changelogs/unreleased/delay-background-migrations.yml diff --git a/app/workers/background_migration_worker.rb b/app/workers/background_migration_worker.rb index aeb3bc019b9..376703f6319 100644 --- a/app/workers/background_migration_worker.rb +++ b/app/workers/background_migration_worker.rb @@ -1,10 +1,53 @@ class BackgroundMigrationWorker include ApplicationWorker + # The minimum amount of time between processing two jobs of the same migration + # class. + # + # This interval is set to 5 minutes so autovacuuming and other maintenance + # related tasks have plenty of time to clean up after a migration has been + # performed. + MIN_INTERVAL = 5.minutes.to_i + # Performs the background migration. # # See Gitlab::BackgroundMigration.perform for more information. + # + # class_name - The class name of the background migration to run. + # arguments - The arguments to pass to the migration class. def perform(class_name, arguments = []) - Gitlab::BackgroundMigration.perform(class_name, arguments) + should_perform, ttl = perform_and_ttl(class_name) + + if should_perform + Gitlab::BackgroundMigration.perform(class_name, arguments) + else + # If the lease could not be obtained this means either another process is + # running a migration of this class or we ran one recently. In this case + # we'll reschedule the job in such a way that it is picked up again around + # the time the lease expires. + self.class.perform_in(ttl || MIN_INTERVAL, class_name, arguments) + end + end + + def perform_and_ttl(class_name) + if always_perform? + # In test environments `perform_in` will run right away. This can then + # lead to stack level errors in the above `#perform`. To work around this + # we'll just perform the migration right away in the test environment. + [true, nil] + else + lease = lease_for(class_name) + + [lease.try_obtain, lease.ttl] + end + end + + def lease_for(class_name) + Gitlab::ExclusiveLease + .new("#{self.class.name}:#{class_name}", timeout: MIN_INTERVAL) + end + + def always_perform? + Rails.env.test? end end diff --git a/changelogs/unreleased/delay-background-migrations.yml b/changelogs/unreleased/delay-background-migrations.yml new file mode 100644 index 00000000000..aa12591e7d2 --- /dev/null +++ b/changelogs/unreleased/delay-background-migrations.yml @@ -0,0 +1,5 @@ +--- +title: Run background migrations with a minimum interval +merge_request: +author: +type: changed diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb index 33171f83692..7b35c24d153 100644 --- a/lib/gitlab/database/migration_helpers.rb +++ b/lib/gitlab/database/migration_helpers.rb @@ -842,6 +842,12 @@ into similar problems in the future (e.g. when new tables are created). def queue_background_migration_jobs_by_range_at_intervals(model_class, job_class_name, delay_interval, batch_size: BACKGROUND_MIGRATION_BATCH_SIZE) raise "#{model_class} does not have an ID to use for batch ranges" unless model_class.column_names.include?('id') + # To not overload the worker too much we enforce a minimum interval both + # when scheduling and performing jobs. + if delay_interval < BackgroundMigrationWorker::MIN_INTERVAL + delay_interval = BackgroundMigrationWorker::MIN_INTERVAL + end + model_class.each_batch(of: batch_size) do |relation, index| start_id, end_id = relation.pluck('MIN(id), MAX(id)').first diff --git a/lib/gitlab/exclusive_lease.rb b/lib/gitlab/exclusive_lease.rb index 3f7b42456af..dbb8f317afe 100644 --- a/lib/gitlab/exclusive_lease.rb +++ b/lib/gitlab/exclusive_lease.rb @@ -71,5 +71,16 @@ module Gitlab redis.exists(@redis_shared_state_key) end end + + # Returns the TTL of the Redis key. + # + # This method will return `nil` if no TTL could be obtained. + def ttl + Gitlab::Redis::SharedState.with do |redis| + ttl = redis.ttl(@redis_shared_state_key) + + ttl if ttl.positive? + end + end end end diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index 7727a1d81b1..43761c2fe0c 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -1006,12 +1006,12 @@ describe Gitlab::Database::MigrationHelpers do context 'with batch_size option' do it 'queues jobs correctly' do Sidekiq::Testing.fake! do - model.queue_background_migration_jobs_by_range_at_intervals(User, 'FooJob', 10.seconds, batch_size: 2) + model.queue_background_migration_jobs_by_range_at_intervals(User, 'FooJob', 10.minutes, batch_size: 2) expect(BackgroundMigrationWorker.jobs[0]['args']).to eq(['FooJob', [id1, id2]]) - expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.seconds.from_now.to_f) + expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.minutes.from_now.to_f) expect(BackgroundMigrationWorker.jobs[1]['args']).to eq(['FooJob', [id3, id3]]) - expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(20.seconds.from_now.to_f) + expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(20.minutes.from_now.to_f) end end end @@ -1019,10 +1019,10 @@ describe Gitlab::Database::MigrationHelpers do context 'without batch_size option' do it 'queues jobs correctly' do Sidekiq::Testing.fake! do - model.queue_background_migration_jobs_by_range_at_intervals(User, 'FooJob', 10.seconds) + model.queue_background_migration_jobs_by_range_at_intervals(User, 'FooJob', 10.minutes) expect(BackgroundMigrationWorker.jobs[0]['args']).to eq(['FooJob', [id1, id3]]) - expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.seconds.from_now.to_f) + expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.minutes.from_now.to_f) end end end diff --git a/spec/lib/gitlab/exclusive_lease_spec.rb b/spec/lib/gitlab/exclusive_lease_spec.rb index 7322a326b01..6193e177668 100644 --- a/spec/lib/gitlab/exclusive_lease_spec.rb +++ b/spec/lib/gitlab/exclusive_lease_spec.rb @@ -73,4 +73,19 @@ describe Gitlab::ExclusiveLease, :clean_gitlab_redis_shared_state do described_class.new(key, timeout: 3600).try_obtain end end + + describe '#ttl' do + it 'returns the TTL of the Redis key' do + lease = described_class.new('kittens', timeout: 100) + lease.try_obtain + + expect(lease.ttl <= 100).to eq(true) + end + + it 'returns nil when the lease does not exist' do + lease = described_class.new('kittens', timeout: 10) + + expect(lease.ttl).to be_nil + end + end end diff --git a/spec/migrations/normalize_ldap_extern_uids_spec.rb b/spec/migrations/normalize_ldap_extern_uids_spec.rb index 262d7742aaf..56a78f52802 100644 --- a/spec/migrations/normalize_ldap_extern_uids_spec.rb +++ b/spec/migrations/normalize_ldap_extern_uids_spec.rb @@ -27,11 +27,11 @@ describe NormalizeLdapExternUids, :migration, :sidekiq do migrate! expect(BackgroundMigrationWorker.jobs[0]['args']).to eq([described_class::MIGRATION, [1, 2]]) - expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.seconds.from_now.to_f) + expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(5.minutes.from_now.to_f) expect(BackgroundMigrationWorker.jobs[1]['args']).to eq([described_class::MIGRATION, [3, 4]]) - expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(20.seconds.from_now.to_f) + expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(10.minutes.from_now.to_f) expect(BackgroundMigrationWorker.jobs[2]['args']).to eq([described_class::MIGRATION, [5, 5]]) - expect(BackgroundMigrationWorker.jobs[2]['at']).to eq(30.seconds.from_now.to_f) + expect(BackgroundMigrationWorker.jobs[2]['at']).to eq(15.minutes.from_now.to_f) expect(BackgroundMigrationWorker.jobs.size).to eq 3 end end diff --git a/spec/workers/background_migration_worker_spec.rb b/spec/workers/background_migration_worker_spec.rb index 1c54cf55fa0..d67e7698635 100644 --- a/spec/workers/background_migration_worker_spec.rb +++ b/spec/workers/background_migration_worker_spec.rb @@ -1,13 +1,32 @@ require 'spec_helper' -describe BackgroundMigrationWorker, :sidekiq do +describe BackgroundMigrationWorker, :sidekiq, :clean_gitlab_redis_shared_state do + let(:worker) { described_class.new } + describe '.perform' do it 'performs a background migration' do expect(Gitlab::BackgroundMigration) .to receive(:perform) .with('Foo', [10, 20]) - described_class.new.perform('Foo', [10, 20]) + worker.perform('Foo', [10, 20]) + end + + it 'reschedules a migration if it was performed recently' do + expect(worker) + .to receive(:always_perform?) + .and_return(false) + + worker.lease_for('Foo').try_obtain + + expect(Gitlab::BackgroundMigration) + .not_to receive(:perform) + + expect(described_class) + .to receive(:perform_in) + .with(a_kind_of(Numeric), 'Foo', [10, 20]) + + worker.perform('Foo', [10, 20]) end end end -- cgit v1.2.1 From 06d4f07a041a70fe9462bcae47b1b191908347ab Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Tue, 26 Dec 2017 17:16:43 -0200 Subject: Improve filtering issues by label performance --- app/controllers/concerns/issues_action.rb | 2 - app/controllers/concerns/merge_requests_action.rb | 1 - app/finders/issuable_finder.rb | 15 +-- changelogs/unreleased/issue_40500.yml | 5 + db/fixtures/development/22_labeled_issues_seed.rb | 112 ++++++++++++++++++++++ 5 files changed, 122 insertions(+), 13 deletions(-) create mode 100644 changelogs/unreleased/issue_40500.yml create mode 100644 db/fixtures/development/22_labeled_issues_seed.rb diff --git a/app/controllers/concerns/issues_action.rb b/app/controllers/concerns/issues_action.rb index d4cccbe6442..3ba1235cee0 100644 --- a/app/controllers/concerns/issues_action.rb +++ b/app/controllers/concerns/issues_action.rb @@ -5,8 +5,6 @@ module IssuesAction # rubocop:disable Gitlab/ModuleWithInstanceVariables def issues @finder_type = IssuesFinder - @label = finder.labels.first - @issues = issuables_collection .non_archived .page(params[:page]) diff --git a/app/controllers/concerns/merge_requests_action.rb b/app/controllers/concerns/merge_requests_action.rb index 4d44df3bba9..a9cc13038bf 100644 --- a/app/controllers/concerns/merge_requests_action.rb +++ b/app/controllers/concerns/merge_requests_action.rb @@ -5,7 +5,6 @@ module MergeRequestsAction # rubocop:disable Gitlab/ModuleWithInstanceVariables def merge_requests @finder_type = MergeRequestsFinder - @label = finder.labels.first @merge_requests = issuables_collection.page(params[:page]) diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb index b46ec5e5350..493e7985d75 100644 --- a/app/finders/issuable_finder.rb +++ b/app/finders/issuable_finder.rb @@ -374,19 +374,14 @@ class IssuableFinder end def by_label(items) - if labels? + return items unless labels? + + items = if filter_by_no_label? - items = items.without_label + items.without_label else - items = items.with_label(label_names, params[:sort]) - items_projects = projects(items) - - if items_projects - label_ids = LabelsFinder.new(current_user, project_ids: items_projects).execute(skip_authorization: true).select(:id) - items = items.where(labels: { id: label_ids }) - end + items.with_label(label_names, params[:sort]) end - end items end diff --git a/changelogs/unreleased/issue_40500.yml b/changelogs/unreleased/issue_40500.yml new file mode 100644 index 00000000000..35e8938fdad --- /dev/null +++ b/changelogs/unreleased/issue_40500.yml @@ -0,0 +1,5 @@ +--- +title: Fix timeout when filtering issues by label +merge_request: +author: +type: performance diff --git a/db/fixtures/development/22_labeled_issues_seed.rb b/db/fixtures/development/22_labeled_issues_seed.rb new file mode 100644 index 00000000000..3e4485c7a73 --- /dev/null +++ b/db/fixtures/development/22_labeled_issues_seed.rb @@ -0,0 +1,112 @@ +# Creates a project with labeled issues for a user. +# Run this single seed file using: rake db:seed_fu FILTER=labeled USER_ID=74. +# If an USER_ID is not provided it will use the last created user. +require './spec/support/sidekiq' + +class Gitlab::Seeder::LabeledIssues + include ::Gitlab::Utils + + def initialize(user) + @user = user + end + + def seed! + Sidekiq::Testing.inline! do + group = create_group + puts '.' + + create_projects(group) + puts '.' + + create_labels(group) + puts '.' + + create_issues(group) + puts '.' + end + + print '.' + end + + private + + def create_group + group_name = "group_of_#{@user.name}#{SecureRandom.hex(4)}" + + group = Group.new( + name: group_name, + path: group_name, + description: FFaker::Lorem.sentence + ) + + group.save + + group.add_owner(@user) + + group + end + + def create_projects(group) + 5.times do + project_name = "project_#{SecureRandom.hex(6)}" + params = { + namespace_id: group.id, + name: project_name, + description: FFaker::Lorem.sentence, + visibility_level: Gitlab::VisibilityLevel.values.sample + } + + Projects::CreateService.new(@user, params).execute + end + end + + def create_labels(group) + group.projects.each do |project| + 5.times do + label_title = FFaker::Vehicle.model + Labels::CreateService.new(title: label_title).execute(project: project) + end + end + + 10.times do + label_title = FFaker::Product.brand + Labels::CreateService.new(title: label_title).execute(group: group) + end + end + + def create_issues(group) + # Get only group labels + group_labels = + LabelsFinder.new(@user, group_id: group.id).execute.where.not(group_id: nil) + + group.projects.each do |project| + label_ids = project.labels.pluck(:id).sample(5) + label_ids.push(*group.labels.sample(4)) + + 50.times do + issue_params = { + title: FFaker::Lorem.sentence(6), + description: FFaker::Lorem.sentence, + state: 'opened', + label_ids: label_ids + + } + + Issues::CreateService.new(project, @user, issue_params).execute if project.project_feature.present? + end + end + end +end + +Gitlab::Seeder.quiet do + user_id = ENV['USER_ID'] + + user = + if user_id.present? + User.find(user_id) + else + User.last + end + + Gitlab::Seeder::LabeledIssues.new(user).seed! +end -- cgit v1.2.1 From fb2ca26f523f7dd4422b4d82f18e92a234ed4c05 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Fri, 5 Jan 2018 23:45:12 +0800 Subject: Remove unused push_code_to_protected_branches --- app/assets/javascripts/users_select.js | 2 -- app/helpers/selects_helper.rb | 1 - app/policies/project_policy.rb | 1 - 3 files changed, 4 deletions(-) diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js index 759cc9925f4..f249bd036d6 100644 --- a/app/assets/javascripts/users_select.js +++ b/app/assets/javascripts/users_select.js @@ -541,7 +541,6 @@ function UsersSelect(currentUser, els, options = {}) { options.projectId = $(select).data('project-id'); options.groupId = $(select).data('group-id'); options.showCurrentUser = $(select).data('current-user'); - options.pushCodeToProtectedBranches = $(select).data('push-code-to-protected-branches'); options.authorId = $(select).data('author-id'); options.skipUsers = $(select).data('skip-users'); showNullUser = $(select).data('null-user'); @@ -688,7 +687,6 @@ UsersSelect.prototype.users = function(query, options, callback) { todo_filter: options.todoFilter || null, todo_state_filter: options.todoStateFilter || null, current_user: options.showCurrentUser || null, - push_code_to_protected_branches: options.pushCodeToProtectedBranches || null, author_id: options.authorId || null, skip_users: options.skipUsers || null }, diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb index 1a4f1431bdc..6cefcde558a 100644 --- a/app/helpers/selects_helper.rb +++ b/app/helpers/selects_helper.rb @@ -73,7 +73,6 @@ module SelectsHelper email_user: opts[:email_user] || false, first_user: opts[:first_user] && current_user ? current_user.username : false, current_user: opts[:current_user] || false, - "push-code-to-protected-branches" => opts[:push_code_to_protected_branches], author_id: opts[:author_id] || '', skip_users: opts[:skip_users] ? opts[:skip_users].map(&:id) : nil } diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index f599eab42f2..1dd8f0a25a9 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -241,7 +241,6 @@ class ProjectPolicy < BasePolicy rule { repository_disabled }.policy do prevent :push_code - prevent :push_code_to_protected_branches prevent :download_code prevent :fork_project prevent :read_commit_status -- cgit v1.2.1 From f40373329f34b56647945522fccad3202ceafcde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 5 Jan 2018 16:54:07 +0100 Subject: Add CHANGELOG entry --- changelogs/unreleased/41249-clearing-the-cache.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/41249-clearing-the-cache.yml diff --git a/changelogs/unreleased/41249-clearing-the-cache.yml b/changelogs/unreleased/41249-clearing-the-cache.yml new file mode 100644 index 00000000000..221589a1239 --- /dev/null +++ b/changelogs/unreleased/41249-clearing-the-cache.yml @@ -0,0 +1,5 @@ +--- +title: Implement project jobs cache reset +merge_request: 16067 +author: +type: added -- cgit v1.2.1 From 17b44dce06c2a70639bbad45bee696075fa21598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 5 Jan 2018 17:44:41 +0100 Subject: Use token hash for redis key --- app/workers/check_gcp_project_billing_worker.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/workers/check_gcp_project_billing_worker.rb b/app/workers/check_gcp_project_billing_worker.rb index 8d80f9c9be3..24575f84509 100644 --- a/app/workers/check_gcp_project_billing_worker.rb +++ b/app/workers/check_gcp_project_billing_worker.rb @@ -4,7 +4,7 @@ class CheckGcpProjectBillingWorker LEASE_TIMEOUT = 15.seconds.to_i def self.redis_shared_state_key_for(token) - "gitlab:gcp:#{token}:billing_enabled" + "gitlab:gcp:#{token.hash}:billing_enabled" end def perform(token) @@ -21,7 +21,7 @@ class CheckGcpProjectBillingWorker def try_obtain_lease_for(token) Gitlab::ExclusiveLease - .new("check_gcp_project_billing_worker:#{token}", timeout: LEASE_TIMEOUT) + .new("check_gcp_project_billing_worker:#{token.hash}", timeout: LEASE_TIMEOUT) .try_obtain end end -- cgit v1.2.1 From 12984a73029408ef4ca10446131613e9ac371eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 5 Jan 2018 17:48:40 +0100 Subject: Move worker to gcp_project namespace --- app/workers/all_queues.yml | 2 +- app/workers/check_gcp_project_billing_worker.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index 142e33e8325..5da0de89d12 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -22,6 +22,7 @@ - gcp_cluster:cluster_provision - gcp_cluster:cluster_wait_for_app_installation - gcp_cluster:wait_for_cluster_creation +- gcp_cluster:check_gcp_project_billing - github_import_advance_stage - github_importer:github_import_import_diff_note @@ -97,4 +98,3 @@ - update_user_activity - upload_checksum - web_hook -- check_gcp_project_billing diff --git a/app/workers/check_gcp_project_billing_worker.rb b/app/workers/check_gcp_project_billing_worker.rb index 24575f84509..42aa6b39d86 100644 --- a/app/workers/check_gcp_project_billing_worker.rb +++ b/app/workers/check_gcp_project_billing_worker.rb @@ -1,5 +1,6 @@ class CheckGcpProjectBillingWorker include ApplicationWorker + include ClusterQueue LEASE_TIMEOUT = 15.seconds.to_i -- cgit v1.2.1 From 33c5630b02a783a749cc0bf63474f643652cdeeb Mon Sep 17 00:00:00 2001 From: "Lin Jen-Shin (godfat)" Date: Fri, 5 Jan 2018 16:52:06 +0000 Subject: Use --left-right and --max-count for counting diverging commits --- app/helpers/branches_helper.rb | 8 +++ app/models/repository.rb | 12 ++-- app/views/projects/branches/_branch.html.haml | 8 +-- .../40622-use-left-right-and-max-count.yml | 6 ++ lib/gitlab/git/repository.rb | 75 ++++++++++++++++++++-- spec/lib/gitlab/git/repository_spec.rb | 40 +++++++++++- spec/models/repository_spec.rb | 9 +++ 7 files changed, 141 insertions(+), 17 deletions(-) create mode 100644 changelogs/unreleased/40622-use-left-right-and-max-count.yml diff --git a/app/helpers/branches_helper.rb b/app/helpers/branches_helper.rb index 686437fc99a..2641a98e29e 100644 --- a/app/helpers/branches_helper.rb +++ b/app/helpers/branches_helper.rb @@ -23,4 +23,12 @@ module BranchesHelper def protected_branch?(project, branch) ProtectedBranch.protected?(project, branch.name) end + + def diverging_count_label(count) + if count >= Repository::MAX_DIVERGING_COUNT + "#{Repository::MAX_DIVERGING_COUNT - 1}+" + else + count.to_s + end + end end diff --git a/app/models/repository.rb b/app/models/repository.rb index 4bedcbfb6a2..7b8f5794a87 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -4,6 +4,7 @@ class Repository REF_MERGE_REQUEST = 'merge-requests'.freeze REF_KEEP_AROUND = 'keep-around'.freeze REF_ENVIRONMENTS = 'environments'.freeze + MAX_DIVERGING_COUNT = 1000 RESERVED_REFS_NAMES = %W[ heads @@ -278,11 +279,12 @@ class Repository cache.fetch(:"diverging_commit_counts_#{branch.name}") do # Rugged seems to throw a `ReferenceError` when given branch_names rather # than SHA-1 hashes - number_commits_behind = raw_repository - .count_commits_between(branch.dereferenced_target.sha, root_ref_hash) - - number_commits_ahead = raw_repository - .count_commits_between(root_ref_hash, branch.dereferenced_target.sha) + number_commits_behind, number_commits_ahead = + raw_repository.count_commits_between( + root_ref_hash, + branch.dereferenced_target.sha, + left_right: true, + max_count: MAX_DIVERGING_COUNT) { behind: number_commits_behind, ahead: number_commits_ahead } end diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml index acf67b83890..1da0e865a41 100644 --- a/app/views/projects/branches/_branch.html.haml +++ b/app/views/projects/branches/_branch.html.haml @@ -66,16 +66,16 @@ = icon("trash-o") - if branch.name != @repository.root_ref - .divergence-graph{ title: s_('%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead') % { number_commits_behind: number_commits_behind, + .divergence-graph{ title: s_('%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead') % { number_commits_behind: diverging_count_label(number_commits_behind), default_branch: @repository.root_ref, - number_commits_ahead: number_commits_ahead } } + number_commits_ahead: diverging_count_label(number_commits_ahead) } } .graph-side .bar.bar-behind{ style: "width: #{number_commits_behind * bar_graph_width_factor}%" } - %span.count.count-behind= number_commits_behind + %span.count.count-behind= diverging_count_label(number_commits_behind) .graph-separator .graph-side .bar.bar-ahead{ style: "width: #{number_commits_ahead * bar_graph_width_factor}%" } - %span.count.count-ahead= number_commits_ahead + %span.count.count-ahead= diverging_count_label(number_commits_ahead) - if commit diff --git a/changelogs/unreleased/40622-use-left-right-and-max-count.yml b/changelogs/unreleased/40622-use-left-right-and-max-count.yml new file mode 100644 index 00000000000..c4c8f271cbe --- /dev/null +++ b/changelogs/unreleased/40622-use-left-right-and-max-count.yml @@ -0,0 +1,6 @@ +--- +title: Improve the performance for counting diverging commits. Show 999+ + if it is more than 1000 commits +merge_request: 15963 +author: +type: performance diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 17c05c44d7e..e8b1788e140 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -498,11 +498,13 @@ module Gitlab end def count_commits(options) + count_commits_options = process_count_commits_options(options) + gitaly_migrate(:count_commits) do |is_enabled| if is_enabled - count_commits_by_gitaly(options) + count_commits_by_gitaly(count_commits_options) else - count_commits_by_shelling_out(options) + count_commits_by_shelling_out(count_commits_options) end end end @@ -540,8 +542,8 @@ module Gitlab end # Counts the amount of commits between `from` and `to`. - def count_commits_between(from, to) - count_commits(ref: "#{from}..#{to}") + def count_commits_between(from, to, options = {}) + count_commits(from: from, to: to, **options) end # Returns the SHA of the most recent common ancestor of +from+ and +to+ @@ -1468,6 +1470,26 @@ module Gitlab end end + def process_count_commits_options(options) + if options[:from] || options[:to] + ref = + if options[:left_right] # Compare with merge-base for left-right + "#{options[:from]}...#{options[:to]}" + else + "#{options[:from]}..#{options[:to]}" + end + + options.merge(ref: ref) + + elsif options[:ref] && options[:left_right] + from, to = options[:ref].match(/\A([^\.]*)\.{2,3}([^\.]*)\z/)[1..2] + + options.merge(from: from, to: to) + else + options + end + end + def log_using_shell?(options) options[:path].present? || options[:disable_walk] || @@ -1690,20 +1712,59 @@ module Gitlab end def count_commits_by_gitaly(options) - gitaly_commit_client.commit_count(options[:ref], options) + if options[:left_right] + from = options[:from] + to = options[:to] + + right_count = gitaly_commit_client + .commit_count("#{from}..#{to}", options) + left_count = gitaly_commit_client + .commit_count("#{to}..#{from}", options) + + [left_count, right_count] + else + gitaly_commit_client.commit_count(options[:ref], options) + end end def count_commits_by_shelling_out(options) + cmd = count_commits_shelling_command(options) + + raw_output = IO.popen(cmd) { |io| io.read } + + process_count_commits_raw_output(raw_output, options) + end + + def count_commits_shelling_command(options) cmd = %W[#{Gitlab.config.git.bin_path} --git-dir=#{path} rev-list] cmd << "--after=#{options[:after].iso8601}" if options[:after] cmd << "--before=#{options[:before].iso8601}" if options[:before] cmd << "--max-count=#{options[:max_count]}" if options[:max_count] + cmd << "--left-right" if options[:left_right] cmd += %W[--count #{options[:ref]}] cmd += %W[-- #{options[:path]}] if options[:path].present? + cmd + end - raw_output = IO.popen(cmd) { |io| io.read } + def process_count_commits_raw_output(raw_output, options) + if options[:left_right] + result = raw_output.scan(/\d+/).map(&:to_i) + + if result.sum != options[:max_count] + result + else # Reaching max count, right is not accurate + right_option = + process_count_commits_options(options + .except(:left_right, :from, :to) + .merge(ref: options[:to])) + + right = count_commits_by_shelling_out(right_option) - raw_output.to_i + [result.first, right] # left should be accurate in the first call + end + else + raw_output.to_i + end end def gitaly_ls_files(ref) diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index faccc2c8e00..f94234f6010 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -1030,12 +1030,50 @@ describe Gitlab::Git::Repository, seed_helper: true do end end + context 'with max_count' do + it 'returns the number of commits with path ' do + options = { ref: 'master', max_count: 5 } + + expect(repository.count_commits(options)).to eq(5) + end + end + context 'with path' do it 'returns the number of commits with path ' do - options = { ref: 'master', path: "encoding" } + options = { ref: 'master', path: 'encoding' } + + expect(repository.count_commits(options)).to eq(2) + end + end + + context 'with option :from and option :to' do + it 'returns the number of commits ahead for fix-mode..fix-blob-path' do + options = { from: 'fix-mode', to: 'fix-blob-path' } expect(repository.count_commits(options)).to eq(2) end + + it 'returns the number of commits ahead for fix-blob-path..fix-mode' do + options = { from: 'fix-blob-path', to: 'fix-mode' } + + expect(repository.count_commits(options)).to eq(1) + end + + context 'with option :left_right' do + it 'returns the number of commits for fix-mode...fix-blob-path' do + options = { from: 'fix-mode', to: 'fix-blob-path', left_right: true } + + expect(repository.count_commits(options)).to eq([1, 2]) + end + + context 'with max_count' do + it 'returns the number of commits with path ' do + options = { from: 'fix-mode', to: 'fix-blob-path', left_right: true, max_count: 1 } + + expect(repository.count_commits(options)).to eq([1, 1]) + end + end + end end context 'with max_count' do diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 9a68ae086ea..48a75c9885b 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -2215,6 +2215,15 @@ describe Repository do end end + describe '#diverging_commit_counts' do + it 'returns the commit counts behind and ahead of default branch' do + result = repository.diverging_commit_counts( + repository.find_branch('fix')) + + expect(result).to eq(behind: 29, ahead: 2) + end + end + describe '#cache_method_output', :use_clean_rails_memory_store_caching do let(:fallback) { 10 } -- cgit v1.2.1 From b7053244a7e21da4177c8550a92b0f66affd5cde Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 5 Jan 2018 13:29:05 +0000 Subject: Merge branch 'master-i18n' into 'master' New Crowdin translations See merge request gitlab-org/gitlab-ee!3930 --- locale/bg/gitlab.po | 573 +++++++++++++++++++++++++++-- locale/de/gitlab.po | 573 +++++++++++++++++++++++++++-- locale/eo/gitlab.po | 561 ++++++++++++++++++++++++++-- locale/es/gitlab.po | 561 ++++++++++++++++++++++++++-- locale/fr/gitlab.po | 613 +++++++++++++++++++++++++++--- locale/it/gitlab.po | 981 +++++++++++++++++++++++++++++++++++++------------ locale/ja/gitlab.po | 560 ++++++++++++++++++++++++++-- locale/ko/gitlab.po | 560 ++++++++++++++++++++++++++-- locale/nl_NL/gitlab.po | 565 ++++++++++++++++++++++++++-- locale/pl_PL/gitlab.po | 562 ++++++++++++++++++++++++++-- locale/pt_BR/gitlab.po | 685 +++++++++++++++++++++++++++++----- locale/ru/gitlab.po | 712 +++++++++++++++++++++++++++++------ locale/uk/gitlab.po | 780 ++++++++++++++++++++++++++++++++------- locale/zh_CN/gitlab.po | 632 +++++++++++++++++++++++++++---- locale/zh_HK/gitlab.po | 560 ++++++++++++++++++++++++++-- locale/zh_TW/gitlab.po | 722 ++++++++++++++++++++++++++++++------ 16 files changed, 9141 insertions(+), 1059 deletions(-) diff --git a/locale/bg/gitlab.po b/locale/bg/gitlab.po index 374164cbe65..8432914d6a7 100644 --- a/locale/bg/gitlab.po +++ b/locale/bg/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-03 12:29-0400\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 04:42-0500\n" "Last-Translator: gitlab \n" "Language-Team: Bulgarian\n" "Language: bg_BG\n" @@ -56,6 +56,9 @@ msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts msgstr[0] "" msgstr[1] "" +msgid "%{text} is available" +msgstr "" + msgid "(checkout the %{link} for information on how to install it)." msgstr "" @@ -115,9 +118,6 @@ msgstr "" msgid "Add License" msgstr "Добавяне на лиценз" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "Добавете SSH ключ в профила си, за да можете да изтегляте или изпращате промени чрез SSH." - msgid "Add new directory" msgstr "Добавяне на нова папка" @@ -130,6 +130,15 @@ msgstr "" msgid "All" msgstr "" +msgid "An error occurred when toggling the notification subscription" +msgstr "" + +msgid "An error occurred when updating the issue weight" +msgstr "" + +msgid "An error occurred while fetching sidebar data" +msgstr "" + msgid "An error occurred. Please try again." msgstr "" @@ -139,6 +148,12 @@ msgstr "" msgid "Applications" msgstr "" +msgid "Apr" +msgstr "" + +msgid "April" +msgstr "" + msgid "Archived project! Repository is read-only" msgstr "Архивиран проект! Хранилището е само за четене" @@ -166,6 +181,12 @@ msgstr "" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "Прикачете файл чрез влачене и пускане или %{upload_link}" +msgid "Aug" +msgstr "" + +msgid "August" +msgstr "" + msgid "Authentication Log" msgstr "" @@ -199,6 +220,9 @@ msgstr "" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." msgstr "" +msgid "Available" +msgstr "" + msgid "Billing" msgstr "" @@ -256,7 +280,7 @@ msgstr "" msgid "Branch" msgid_plural "Branches" msgstr[0] "Клон" -msgstr[1] "Клонове" +msgstr[1] "Клони" msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}" msgstr "Клонът %{branch_name} беше създаден. За да настроите автоматичното внедряване, изберете Yaml шаблон за GitLab CI и подайте промените си. %{link_to_autodeploy_doc}" @@ -264,14 +288,20 @@ msgstr "Клонът %{branch_name} беше създаден. msgid "Branch has changed" msgstr "" +msgid "Branch is already taken" +msgstr "" + +msgid "Branch name" +msgstr "" + msgid "BranchSwitcherPlaceholder|Search branches" -msgstr "Търсете в клоновете" +msgstr "Търсете в клоните" msgid "BranchSwitcherTitle|Switch branch" msgstr "Превключване на клона" msgid "Branches" -msgstr "Клонове" +msgstr "Клони" msgid "Branches|Cant find HEAD commit for this branch" msgstr "" @@ -411,6 +441,12 @@ msgstr "Графики" msgid "Chat" msgstr "" +msgid "Checking %{text} availability…" +msgstr "" + +msgid "Checking branch availability..." +msgstr "" + msgid "Cherry-pick this commit" msgstr "Подбиране на това подаване" @@ -486,7 +522,40 @@ msgstr "" msgid "Cluster" msgstr "" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "" + +msgid "ClusterIntegration|API URL" +msgstr "" + +msgid "ClusterIntegration|Active" +msgstr "" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "" + +msgid "ClusterIntegration|Add cluster" +msgstr "" + +msgid "ClusterIntegration|All" +msgstr "" + +msgid "ClusterIntegration|Applications" +msgstr "" + +msgid "ClusterIntegration|CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "" + +msgid "ClusterIntegration|Cluster" msgstr "" msgid "ClusterIntegration|Cluster details" @@ -510,21 +579,54 @@ msgstr "" msgid "ClusterIntegration|Cluster name" msgstr "" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" +msgstr "" + +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "" + +msgid "ClusterIntegration|Copy API URL" +msgstr "" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Copy Token" msgstr "" msgid "ClusterIntegration|Copy cluster name" msgstr "" +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "" + msgid "ClusterIntegration|Create cluster" msgstr "" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Create on GKE" msgstr "" msgid "ClusterIntegration|Enable cluster integration" msgstr "" +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "" + +msgid "ClusterIntegration|Environment pattern" +msgstr "" + +msgid "ClusterIntegration|GKE pricing" +msgstr "" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "" + msgid "ClusterIntegration|Google Cloud Platform project ID" msgstr "" @@ -534,27 +636,75 @@ msgstr "" msgid "ClusterIntegration|Google Kubernetes Engine project" msgstr "" +msgid "ClusterIntegration|Helm Tiller" +msgstr "" + +msgid "ClusterIntegration|Inactive" +msgstr "" + +msgid "ClusterIntegration|Ingress" +msgstr "" + +msgid "ClusterIntegration|Install" +msgstr "" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "" + +msgid "ClusterIntegration|Installed" +msgstr "" + +msgid "ClusterIntegration|Installing" +msgstr "" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "" + msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "" + msgid "ClusterIntegration|Machine type" msgstr "" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" msgstr "" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" msgstr "" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" msgstr "" +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "" + +msgid "ClusterIntegration|Note:" +msgstr "" + msgid "ClusterIntegration|Number of nodes" msgstr "" +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" +msgstr "" + msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgstr "" +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "" + +msgid "ClusterIntegration|Project ID" +msgstr "" + +msgid "ClusterIntegration|Project namespace" +msgstr "" + msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "" @@ -567,7 +717,13 @@ msgstr "" msgid "ClusterIntegration|Remove integration" msgstr "" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "" + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "" + +msgid "ClusterIntegration|Save changes" msgstr "" msgid "ClusterIntegration|See and edit the details for your cluster" @@ -582,15 +738,33 @@ msgstr "" msgid "ClusterIntegration|See zones" msgstr "" +msgid "ClusterIntegration|Service token" +msgstr "" + +msgid "ClusterIntegration|Show" +msgstr "" + msgid "ClusterIntegration|Something went wrong on our end." msgstr "" msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" msgstr "" +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "" + msgid "ClusterIntegration|Toggle Cluster" msgstr "" +msgid "ClusterIntegration|Token" +msgstr "" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "" @@ -606,9 +780,15 @@ msgstr "" msgid "ClusterIntegration|cluster" msgstr "" +msgid "ClusterIntegration|documentation" +msgstr "" + msgid "ClusterIntegration|help page" msgstr "" +msgid "ClusterIntegration|installing applications" +msgstr "" + msgid "ClusterIntegration|meets the requirements" msgstr "" @@ -623,11 +803,6 @@ msgid_plural "Commits" msgstr[0] "Подаване" msgstr[1] "Подавания" -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "" -msgstr[1] "" - msgid "Commit Message" msgstr "" @@ -709,6 +884,15 @@ msgstr "Ръководство за сътрудничество" msgid "Contributors" msgstr "Сътрудници" +msgid "ContributorsPage|Building repository graph." +msgstr "" + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "" + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "" + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" msgstr "" @@ -736,6 +920,9 @@ msgstr "Създаване на папка" msgid "Create empty bare repository" msgstr "Създаване на празно хранилище" +msgid "Create epic" +msgstr "" + msgid "Create file" msgstr "" @@ -763,6 +950,9 @@ msgstr "Етикет" msgid "CreateTokenToCloneLink|create a personal access token" msgstr "си създадете личен жетон за достъп" +msgid "Creating epic" +msgstr "" + msgid "Cron Timezone" msgstr "Часова зона за „Cron“" @@ -808,6 +998,12 @@ msgstr "" msgid "DashboardProjects|Personal" msgstr "" +msgid "Dec" +msgstr "" + +msgid "December" +msgstr "" + msgid "Define a custom pattern with cron syntax" msgstr "Задайте потребителски шаблон, използвайки синтаксиса на „Cron“" @@ -882,6 +1078,72 @@ msgstr "Редактиране на плана %{id} за схема" msgid "Emails" msgstr "" +msgid "Environments|An error occurred while fetching the environments." +msgstr "" + +msgid "Environments|An error occurred while making the request." +msgstr "" + +msgid "Environments|Commit" +msgstr "" + +msgid "Environments|Deployment" +msgstr "" + +msgid "Environments|Environment" +msgstr "" + +msgid "Environments|Environments" +msgstr "" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "" + +msgid "Environments|Job" +msgstr "" + +msgid "Environments|New environment" +msgstr "" + +msgid "Environments|No deployments yet" +msgstr "" + +msgid "Environments|Open" +msgstr "" + +msgid "Environments|Re-deploy" +msgstr "" + +msgid "Environments|Read more about environments" +msgstr "" + +msgid "Environments|Rollback" +msgstr "" + +msgid "Environments|Show all" +msgstr "" + +msgid "Environments|Updated" +msgstr "" + +msgid "Environments|You don't have any environments right now." +msgstr "" + +msgid "Epic will be removed! Are you sure?" +msgstr "" + +msgid "Epics" +msgstr "" + +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" +msgstr "" + +msgid "Error creating epic" +msgstr "" + +msgid "Error occurred when toggling the notification subscription" +msgstr "" + msgid "EventFilterBy|Filter by all" msgstr "" @@ -921,6 +1183,12 @@ msgstr "Собственикът не може да бъде променен" msgid "Failed to remove the pipeline schedule" msgstr "Планът за схема не може да бъде премахнат" +msgid "Feb" +msgstr "" + +msgid "February" +msgstr "" + msgid "File name" msgstr "" @@ -968,6 +1236,21 @@ msgstr "" msgid "Geo Nodes" msgstr "" +msgid "GeoNodeSyncStatus|Failed" +msgstr "" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "" + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "" + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "" + msgid "Geo|File sync capacity" msgstr "" @@ -1031,9 +1314,6 @@ msgstr "" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "" -msgid "GroupsTreeRole|as" -msgstr "" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "" @@ -1064,6 +1344,9 @@ msgstr "" msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "" +msgid "Have your users email" +msgstr "" + msgid "Health Check" msgstr "" @@ -1123,9 +1406,6 @@ msgstr "Представяме Ви анализа на циклите" msgid "Issue board focus mode" msgstr "" -msgid "Issue boards with milestones" -msgstr "" - msgid "Issue events" msgstr "" @@ -1138,6 +1418,24 @@ msgstr "" msgid "Issues" msgstr "" +msgid "Jan" +msgstr "" + +msgid "January" +msgstr "" + +msgid "Jul" +msgstr "" + +msgid "July" +msgstr "" + +msgid "Jun" +msgstr "" + +msgid "June" +msgstr "" + msgid "LFSStatus|Disabled" msgstr "Изключено" @@ -1211,9 +1509,18 @@ msgstr "" msgid "Login" msgstr "" +msgid "Mar" +msgstr "" + +msgid "March" +msgstr "" + msgid "Maximum git storage failures" msgstr "" +msgid "May" +msgstr "" + msgid "Median" msgstr "Медиана" @@ -1258,9 +1565,15 @@ msgstr "Нов план за схема" msgid "New branch" msgstr "Нов клон" +msgid "New branch unavailable" +msgstr "" + msgid "New directory" msgstr "Нова папка" +msgid "New epic" +msgstr "" + msgid "New file" msgstr "Нов файл" @@ -1297,6 +1610,9 @@ msgstr "Няма хранилище" msgid "No schedules" msgstr "Няма планове" +msgid "No time spent" +msgstr "" + msgid "None" msgstr "" @@ -1363,18 +1679,33 @@ msgstr "Наблюдение" msgid "Notifications" msgstr "" +msgid "Nov" +msgstr "" + +msgid "November" +msgstr "" + msgid "Number of access attempts" msgstr "" msgid "Number of failures before backing off" msgstr "" +msgid "Oct" +msgstr "" + +msgid "October" +msgstr "" + msgid "OfSearchInADropdown|Filter" msgstr "Филтър" msgid "Only project members can comment." msgstr "" +msgid "Opened" +msgstr "" + msgid "OpenedNDaysAgo|Opened" msgstr "Отворен" @@ -1507,6 +1838,9 @@ msgstr "с етап" msgid "Pipeline|with stages" msgstr "с етапи" +msgid "Please solve the reCAPTCHA" +msgstr "" + msgid "Preferences" msgstr "" @@ -1612,9 +1946,15 @@ msgstr "Графика" msgid "ProjectSettings|Contact an admin to change this setting." msgstr "" +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "" + msgid "ProjectSettings|Only signed commits can be pushed to this repository." msgstr "" +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "" + msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." msgstr "" @@ -1651,6 +1991,39 @@ msgstr "" msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "" +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "" + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "" + +msgid "PrometheusService|Metrics" +msgstr "" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "" + +msgid "PrometheusService|Missing environment variable" +msgstr "" + +msgid "PrometheusService|Monitored" +msgstr "" + +msgid "PrometheusService|More information" +msgstr "" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "" + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" +msgstr "" + +msgid "PrometheusService|Prometheus monitoring" +msgstr "" + +msgid "PrometheusService|View environments" +msgstr "" + msgid "Public - The group and any public projects can be viewed without any authentication." msgstr "" @@ -1673,7 +2046,7 @@ msgid "Readme" msgstr "ПрочетиМе" msgid "RefSwitcher|Branches" -msgstr "Клонове" +msgstr "Клони" msgid "RefSwitcher|Tags" msgstr "Етикети" @@ -1747,8 +2120,11 @@ msgstr "" msgid "Scheduling Pipelines" msgstr "Планиране на схемите" +msgid "Scoped issue boards" +msgstr "" + msgid "Search branches and tags" -msgstr "Търсете в клоновете и етикетите" +msgstr "Търсете в клоните и етикетите" msgid "Seconds before reseting failure information" msgstr "" @@ -1768,6 +2144,12 @@ msgstr "Изберете часова зона" msgid "Select target branch" msgstr "Изберете целеви клон" +msgid "Sep" +msgstr "" + +msgid "September" +msgstr "" + msgid "Service Templates" msgstr "" @@ -1800,13 +2182,28 @@ msgid_plural "Showing %d events" msgstr[0] "Показване на %d събитие" msgstr[1] "Показване на %d събития" +msgid "Sidebar|Change weight" +msgstr "" + +msgid "Sidebar|Edit" +msgstr "" + +msgid "Sidebar|No" +msgstr "" + +msgid "Sidebar|None" +msgstr "" + +msgid "Sidebar|Weight" +msgstr "" + msgid "Snippets" msgstr "" msgid "Something went wrong on our end." msgstr "" -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" msgstr "" msgid "Something went wrong while fetching the projects." @@ -1914,9 +2311,15 @@ msgstr "" msgid "SortOptions|Weight" msgstr "" +msgid "Source" +msgstr "" + msgid "Source code" msgstr "Изходен код" +msgid "Source is not available" +msgstr "" + msgid "Spam Logs" msgstr "" @@ -1935,6 +2338,9 @@ msgstr "Създайте %{new_merge_request} с тези промени" msgid "Start the Runner!" msgstr "" +msgid "Stopped" +msgstr "" + msgid "Subgroups" msgstr "" @@ -1955,6 +2361,75 @@ msgstr[1] "Етикети" msgid "Tags" msgstr "Етикети" +msgid "TagsPage|Browse commits" +msgstr "" + +msgid "TagsPage|Browse files" +msgstr "" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "" + +msgid "TagsPage|Cancel" +msgstr "" + +msgid "TagsPage|Create tag" +msgstr "" + +msgid "TagsPage|Delete tag" +msgstr "" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "" + +msgid "TagsPage|Edit release notes" +msgstr "" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "" + +msgid "TagsPage|Filter by tag name" +msgstr "" + +msgid "TagsPage|New Tag" +msgstr "" + +msgid "TagsPage|New tag" +msgstr "" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "" + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "" + +msgid "TagsPage|Release notes" +msgstr "" + +msgid "TagsPage|Repository has no tags yet." +msgstr "" + +msgid "TagsPage|Sort by" +msgstr "" + +msgid "TagsPage|Tags" +msgstr "" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "" + +msgid "TagsPage|This tag has no release notes." +msgstr "" + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "" + +msgid "TagsPage|protected" +msgstr "" + msgid "Target Branch" msgstr "Целеви клон" @@ -1995,7 +2470,7 @@ msgid "The phase of the development lifecycle." msgstr "Етапът от цикъла на разработка" msgid "The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user." -msgstr "Планът за схемата ще изпълнява схемите в бъдеще, периодично, за определени клонове или етикети. Тези планирани схеми ще наследят ограниченията на достъпа до проекта на свързания с тях потребител." +msgstr "Планът за схемата ще изпълнява схемите в бъдеще, периодично, за определени клони или етикети. Тези планирани схеми ще наследят ограниченията на достъпа до проекта на свързания с тях потребител." msgid "The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit." msgstr "Етапът на планиране показва колко е времето от преходната стъпка до изпращането на първото подаване. Това време ще бъде добавено автоматично след като изпратите първото си подаване." @@ -2036,6 +2511,9 @@ msgstr "Стойността, която се намира в средата н msgid "There are problems accessing Git storage: " msgstr "" +msgid "This board\\'s scope is reduced" +msgstr "" + msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "" @@ -2057,6 +2535,9 @@ msgstr "Това означава, че няма да можете да изпр msgid "This merge request is locked." msgstr "" +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "Време преди един проблем да бъде планиран за работа" @@ -2205,15 +2686,27 @@ msgstr[1] "мин" msgid "Time|s" msgstr "сек" +msgid "Title" +msgstr "" + msgid "Total Time" msgstr "Общо време" +msgid "Total issue time spent" +msgstr "" + msgid "Total test time for all commits/merges" msgstr "Общо време за тестване на всички подавания/сливания" msgid "Track activity with Contribution Analytics." msgstr "" +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "" + +msgid "Turn on Service Desk" +msgstr "" + msgid "Unlock" msgstr "" @@ -2250,6 +2743,9 @@ msgstr "Качване на файл" msgid "UploadLink|click to upload" msgstr "щракнете за качване" +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "" + msgid "Use the following registration token during setup:" msgstr "" @@ -2283,6 +2779,9 @@ msgstr "Искате ли да видите данните? Помолете а msgid "We don't have enough data to show this stage." msgstr "Няма достатъчно данни за този етап." +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "" + msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." msgstr "" @@ -2412,12 +2911,6 @@ msgstr "На път сте да премахнете връзката на ра msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "На път сте да прехвърлите „%{project_name_with_namespace}“ към друг собственик. НАИСТИНА ли искате това?" -msgid "You are on a read-only GitLab instance." -msgstr "" - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "" - msgid "You can only add files when you are on a branch" msgstr "Можете да добавяте файлове само когато се намирате в клон" @@ -2457,6 +2950,9 @@ msgstr "Няма да можете да изтегляте или изпраща msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" msgstr "Няма да можете да изтегляте или изпращате код в проекта чрез SSH, докато не %{add_ssh_key_link} в профила си" +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "" + msgid "Your comment will not be visible to the public." msgstr "" @@ -2469,6 +2965,12 @@ msgstr "Вашето име" msgid "Your projects" msgstr "" +msgid "branch name" +msgstr "" + +msgid "by" +msgstr "" + msgid "commit" msgstr "" @@ -2494,6 +2996,9 @@ msgstr "" msgid "personal access token" msgstr "" +msgid "source" +msgstr "" + msgid "to help your contributors communicate effectively!" msgstr "" diff --git a/locale/de/gitlab.po b/locale/de/gitlab.po index a79a7d1a353..db7f41c5476 100644 --- a/locale/de/gitlab.po +++ b/locale/de/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-28 11:32-0500\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 04:41-0500\n" "Last-Translator: gitlab \n" "Language-Team: German\n" "Language: de_DE\n" @@ -56,6 +56,9 @@ msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts msgstr[0] "%{storage_name}: fehlgeschlagener Speicherzugriff auf Host:" msgstr[1] "%{storage_name}: %{failed_attempts} fehlgeschlagene Speicherzugriffe:" +msgid "%{text} is available" +msgstr "" + msgid "(checkout the %{link} for information on how to install it)." msgstr "(beachte die Informationen zur Installation auf %{link})." @@ -115,9 +118,6 @@ msgstr "" msgid "Add License" msgstr "Lizenz hinzufügen" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "Füge einen SSH Schlüssel zu deinem Profil hinzu, um mittels SSH zu übertragen (push) oder abzurufen (pull)." - msgid "Add new directory" msgstr "Erstelle eine neues Verzeichnis" @@ -130,6 +130,15 @@ msgstr "" msgid "All" msgstr "Alle" +msgid "An error occurred when toggling the notification subscription" +msgstr "" + +msgid "An error occurred when updating the issue weight" +msgstr "" + +msgid "An error occurred while fetching sidebar data" +msgstr "" + msgid "An error occurred. Please try again." msgstr "" @@ -139,6 +148,12 @@ msgstr "" msgid "Applications" msgstr "Anwendungen" +msgid "Apr" +msgstr "" + +msgid "April" +msgstr "" + msgid "Archived project! Repository is read-only" msgstr "Archiviertes Projekt! Repository ist nicht änderbar." @@ -166,6 +181,12 @@ msgstr "" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "Datei mittels Drag & Drop oder %{upload_link} hinzufügen" +msgid "Aug" +msgstr "" + +msgid "August" +msgstr "" + msgid "Authentication Log" msgstr "" @@ -199,8 +220,11 @@ msgstr "" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." msgstr "" +msgid "Available" +msgstr "" + msgid "Billing" -msgstr "Abrechnung" +msgstr "" msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan." msgstr "" @@ -264,6 +288,12 @@ msgstr "Branch %{branch_name} wurde erstellt. Um die automatisc msgid "Branch has changed" msgstr "" +msgid "Branch is already taken" +msgstr "" + +msgid "Branch name" +msgstr "" + msgid "BranchSwitcherPlaceholder|Search branches" msgstr "Branches durchsuchen" @@ -411,6 +441,12 @@ msgstr "Diagramme" msgid "Chat" msgstr "Chat" +msgid "Checking %{text} availability…" +msgstr "" + +msgid "Checking branch availability..." +msgstr "" + msgid "Cherry-pick this commit" msgstr "Diesen Commit herauspicken " @@ -481,12 +517,45 @@ msgid "Clone repository" msgstr "" msgid "Close" -msgstr "Schließen" +msgstr "" msgid "Cluster" msgstr "" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "" + +msgid "ClusterIntegration|API URL" +msgstr "" + +msgid "ClusterIntegration|Active" +msgstr "" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "" + +msgid "ClusterIntegration|Add cluster" +msgstr "" + +msgid "ClusterIntegration|All" +msgstr "" + +msgid "ClusterIntegration|Applications" +msgstr "" + +msgid "ClusterIntegration|CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "" + +msgid "ClusterIntegration|Cluster" msgstr "" msgid "ClusterIntegration|Cluster details" @@ -510,21 +579,54 @@ msgstr "" msgid "ClusterIntegration|Cluster name" msgstr "" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" +msgstr "" + +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "" + +msgid "ClusterIntegration|Copy API URL" +msgstr "" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Copy Token" msgstr "" msgid "ClusterIntegration|Copy cluster name" msgstr "" +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "" + msgid "ClusterIntegration|Create cluster" msgstr "" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Create on GKE" msgstr "" msgid "ClusterIntegration|Enable cluster integration" msgstr "" +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "" + +msgid "ClusterIntegration|Environment pattern" +msgstr "" + +msgid "ClusterIntegration|GKE pricing" +msgstr "" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "" + msgid "ClusterIntegration|Google Cloud Platform project ID" msgstr "" @@ -534,27 +636,75 @@ msgstr "" msgid "ClusterIntegration|Google Kubernetes Engine project" msgstr "" +msgid "ClusterIntegration|Helm Tiller" +msgstr "" + +msgid "ClusterIntegration|Inactive" +msgstr "" + +msgid "ClusterIntegration|Ingress" +msgstr "" + +msgid "ClusterIntegration|Install" +msgstr "" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "" + +msgid "ClusterIntegration|Installed" +msgstr "" + +msgid "ClusterIntegration|Installing" +msgstr "" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "" + msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "" + msgid "ClusterIntegration|Machine type" msgstr "" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" msgstr "" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" msgstr "" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" msgstr "" +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "" + +msgid "ClusterIntegration|Note:" +msgstr "" + msgid "ClusterIntegration|Number of nodes" msgstr "" +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" +msgstr "" + msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgstr "" +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "" + +msgid "ClusterIntegration|Project ID" +msgstr "" + +msgid "ClusterIntegration|Project namespace" +msgstr "" + msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "" @@ -567,7 +717,13 @@ msgstr "" msgid "ClusterIntegration|Remove integration" msgstr "" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "" + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "" + +msgid "ClusterIntegration|Save changes" msgstr "" msgid "ClusterIntegration|See and edit the details for your cluster" @@ -582,15 +738,33 @@ msgstr "" msgid "ClusterIntegration|See zones" msgstr "" +msgid "ClusterIntegration|Service token" +msgstr "" + +msgid "ClusterIntegration|Show" +msgstr "" + msgid "ClusterIntegration|Something went wrong on our end." msgstr "" msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" msgstr "" +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "" + msgid "ClusterIntegration|Toggle Cluster" msgstr "" +msgid "ClusterIntegration|Token" +msgstr "" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "" @@ -606,9 +780,15 @@ msgstr "" msgid "ClusterIntegration|cluster" msgstr "" +msgid "ClusterIntegration|documentation" +msgstr "" + msgid "ClusterIntegration|help page" msgstr "" +msgid "ClusterIntegration|installing applications" +msgstr "" + msgid "ClusterIntegration|meets the requirements" msgstr "" @@ -623,11 +803,6 @@ msgid_plural "Commits" msgstr[0] "Commit" msgstr[1] "Commits" -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "" -msgstr[1] "" - msgid "Commit Message" msgstr "" @@ -709,6 +884,15 @@ msgstr "Mitarbeitsanleitung" msgid "Contributors" msgstr "Mitarbeiter" +msgid "ContributorsPage|Building repository graph." +msgstr "" + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "" + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "" + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" msgstr "" @@ -716,7 +900,7 @@ msgid "Control the maximum concurrency of repository backfill for this secondary msgstr "" msgid "Copy SSH public key to clipboard" -msgstr "Öffentlichen SSH-Schlüssel in die Zwischenablage kopieren" +msgstr "" msgid "Copy URL to clipboard" msgstr "Kopiere URL in die Zwischenablage" @@ -736,6 +920,9 @@ msgstr "Erstelle Verzeichnis" msgid "Create empty bare repository" msgstr "Erstelle leeres Repository" +msgid "Create epic" +msgstr "" + msgid "Create file" msgstr "" @@ -763,6 +950,9 @@ msgstr "Tag " msgid "CreateTokenToCloneLink|create a personal access token" msgstr "Erstelle einen persönlichen Zugriffstoken" +msgid "Creating epic" +msgstr "" + msgid "Cron Timezone" msgstr "Cron Zeitzone" @@ -808,6 +998,12 @@ msgstr "" msgid "DashboardProjects|Personal" msgstr "" +msgid "Dec" +msgstr "" + +msgid "December" +msgstr "" + msgid "Define a custom pattern with cron syntax" msgstr "Erstelle ein individuelles Muster mittels Cron Syntax" @@ -882,6 +1078,72 @@ msgstr "Pipeline Zeitplan bearbeiten %{id}" msgid "Emails" msgstr "E-Mails" +msgid "Environments|An error occurred while fetching the environments." +msgstr "" + +msgid "Environments|An error occurred while making the request." +msgstr "" + +msgid "Environments|Commit" +msgstr "" + +msgid "Environments|Deployment" +msgstr "" + +msgid "Environments|Environment" +msgstr "" + +msgid "Environments|Environments" +msgstr "" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "" + +msgid "Environments|Job" +msgstr "" + +msgid "Environments|New environment" +msgstr "" + +msgid "Environments|No deployments yet" +msgstr "" + +msgid "Environments|Open" +msgstr "" + +msgid "Environments|Re-deploy" +msgstr "" + +msgid "Environments|Read more about environments" +msgstr "" + +msgid "Environments|Rollback" +msgstr "" + +msgid "Environments|Show all" +msgstr "" + +msgid "Environments|Updated" +msgstr "" + +msgid "Environments|You don't have any environments right now." +msgstr "" + +msgid "Epic will be removed! Are you sure?" +msgstr "" + +msgid "Epics" +msgstr "" + +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" +msgstr "" + +msgid "Error creating epic" +msgstr "" + +msgid "Error occurred when toggling the notification subscription" +msgstr "" + msgid "EventFilterBy|Filter by all" msgstr "Filtere alle" @@ -921,6 +1183,12 @@ msgstr "Wechsel des Besitzers fehlgeschlagen" msgid "Failed to remove the pipeline schedule" msgstr "Entfernung der Pipelineplanung fehlgeschlagen" +msgid "Feb" +msgstr "" + +msgid "February" +msgstr "" + msgid "File name" msgstr "" @@ -968,6 +1236,21 @@ msgstr "" msgid "Geo Nodes" msgstr "" +msgid "GeoNodeSyncStatus|Failed" +msgstr "" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "" + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "" + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "" + msgid "Geo|File sync capacity" msgstr "" @@ -1031,9 +1314,6 @@ msgstr "" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "" -msgid "GroupsTreeRole|as" -msgstr "" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "" @@ -1064,6 +1344,9 @@ msgstr "" msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "" +msgid "Have your users email" +msgstr "" + msgid "Health Check" msgstr "Systemzustand" @@ -1123,9 +1406,6 @@ msgstr "Arbeitsablaufsanalysen vorgestellt" msgid "Issue board focus mode" msgstr "" -msgid "Issue boards with milestones" -msgstr "" - msgid "Issue events" msgstr "Ticketereignisse" @@ -1138,6 +1418,24 @@ msgstr "" msgid "Issues" msgstr "" +msgid "Jan" +msgstr "" + +msgid "January" +msgstr "" + +msgid "Jul" +msgstr "" + +msgid "July" +msgstr "" + +msgid "Jun" +msgstr "" + +msgid "June" +msgstr "" + msgid "LFSStatus|Disabled" msgstr "Deaktiviert" @@ -1192,7 +1490,7 @@ msgid "Leave project" msgstr "Verlasse das Projekt" msgid "License" -msgstr "Lizenz" +msgstr "" msgid "Limited to showing %d event at most" msgid_plural "Limited to showing %d events at most" @@ -1206,14 +1504,23 @@ msgid "Locked" msgstr "" msgid "Locked Files" -msgstr "Gesperrte Dateien" +msgstr "" msgid "Login" msgstr "" +msgid "Mar" +msgstr "" + +msgid "March" +msgstr "" + msgid "Maximum git storage failures" msgstr "" +msgid "May" +msgstr "" + msgid "Median" msgstr "Median" @@ -1258,9 +1565,15 @@ msgstr "Neuer Pipeline Zeitplan" msgid "New branch" msgstr "Neuer Branch" +msgid "New branch unavailable" +msgstr "" + msgid "New directory" msgstr "Neues Verzeichnis" +msgid "New epic" +msgstr "" + msgid "New file" msgstr "Neue Datei" @@ -1297,6 +1610,9 @@ msgstr "Kein Repository" msgid "No schedules" msgstr "Keine Zeitpläne" +msgid "No time spent" +msgstr "" + msgid "None" msgstr "" @@ -1363,18 +1679,33 @@ msgstr "Beobachten" msgid "Notifications" msgstr "Benachrichtigungen" +msgid "Nov" +msgstr "" + +msgid "November" +msgstr "" + msgid "Number of access attempts" msgstr "" msgid "Number of failures before backing off" msgstr "" +msgid "Oct" +msgstr "" + +msgid "October" +msgstr "" + msgid "OfSearchInADropdown|Filter" msgstr "Filter" msgid "Only project members can comment." msgstr "" +msgid "Opened" +msgstr "" + msgid "OpenedNDaysAgo|Opened" msgstr "Ungelöst" @@ -1507,6 +1838,9 @@ msgstr "mit Stage" msgid "Pipeline|with stages" msgstr "mit Stages" +msgid "Please solve the reCAPTCHA" +msgstr "" + msgid "Preferences" msgstr "" @@ -1612,9 +1946,15 @@ msgstr "Diagramm" msgid "ProjectSettings|Contact an admin to change this setting." msgstr "" +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "" + msgid "ProjectSettings|Only signed commits can be pushed to this repository." msgstr "" +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "" + msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." msgstr "" @@ -1651,6 +1991,39 @@ msgstr "" msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "" +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "" + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "" + +msgid "PrometheusService|Metrics" +msgstr "" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "" + +msgid "PrometheusService|Missing environment variable" +msgstr "" + +msgid "PrometheusService|Monitored" +msgstr "" + +msgid "PrometheusService|More information" +msgstr "" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "" + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" +msgstr "" + +msgid "PrometheusService|Prometheus monitoring" +msgstr "" + +msgid "PrometheusService|View environments" +msgstr "" + msgid "Public - The group and any public projects can be viewed without any authentication." msgstr "" @@ -1747,6 +2120,9 @@ msgstr "" msgid "Scheduling Pipelines" msgstr "Pipelines planen" +msgid "Scoped issue boards" +msgstr "" + msgid "Search branches and tags" msgstr "Suche nach Branches und Tags" @@ -1768,6 +2144,12 @@ msgstr "Zeitzone auswählen" msgid "Select target branch" msgstr "Zielbranch auswählen" +msgid "Sep" +msgstr "" + +msgid "September" +msgstr "" + msgid "Service Templates" msgstr "" @@ -1800,13 +2182,28 @@ msgid_plural "Showing %d events" msgstr[0] "Zeige %d Ereignis" msgstr[1] "Zeige %d Ereignisse" +msgid "Sidebar|Change weight" +msgstr "" + +msgid "Sidebar|Edit" +msgstr "" + +msgid "Sidebar|No" +msgstr "" + +msgid "Sidebar|None" +msgstr "" + +msgid "Sidebar|Weight" +msgstr "" + msgid "Snippets" msgstr "" msgid "Something went wrong on our end." msgstr "" -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" msgstr "" msgid "Something went wrong while fetching the projects." @@ -1914,9 +2311,15 @@ msgstr "" msgid "SortOptions|Weight" msgstr "" +msgid "Source" +msgstr "" + msgid "Source code" msgstr "Quellcode" +msgid "Source is not available" +msgstr "" + msgid "Spam Logs" msgstr "Spam-Protokolle" @@ -1935,6 +2338,9 @@ msgstr "Beginne einen %{new_merge_request} mit diesen Änderungen" msgid "Start the Runner!" msgstr "Starte den Runner!" +msgid "Stopped" +msgstr "" + msgid "Subgroups" msgstr "" @@ -1955,6 +2361,75 @@ msgstr[1] "" msgid "Tags" msgstr "" +msgid "TagsPage|Browse commits" +msgstr "" + +msgid "TagsPage|Browse files" +msgstr "" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "" + +msgid "TagsPage|Cancel" +msgstr "" + +msgid "TagsPage|Create tag" +msgstr "" + +msgid "TagsPage|Delete tag" +msgstr "" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "" + +msgid "TagsPage|Edit release notes" +msgstr "" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "" + +msgid "TagsPage|Filter by tag name" +msgstr "" + +msgid "TagsPage|New Tag" +msgstr "" + +msgid "TagsPage|New tag" +msgstr "" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "" + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "" + +msgid "TagsPage|Release notes" +msgstr "" + +msgid "TagsPage|Repository has no tags yet." +msgstr "" + +msgid "TagsPage|Sort by" +msgstr "" + +msgid "TagsPage|Tags" +msgstr "" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "" + +msgid "TagsPage|This tag has no release notes." +msgstr "" + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "" + +msgid "TagsPage|protected" +msgstr "" + msgid "Target Branch" msgstr "Zielbranch" @@ -2036,6 +2511,9 @@ msgstr "Der mittlere aller erfassten Werte. Zum Beispiel ist für 3, 5, 9 der Me msgid "There are problems accessing Git storage: " msgstr "Es gibt ein Problem beim Zugriff auf den Gitspeicher:" +msgid "This board\\'s scope is reduced" +msgstr "" + msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "" @@ -2057,6 +2535,9 @@ msgstr "Dies bedeutet, dass Du keinen Code übertragen kannst, bevor Du kein lee msgid "This merge request is locked." msgstr "" +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "Zeit bis ein Ticket geplant wird" @@ -2205,15 +2686,27 @@ msgstr[1] "Min." msgid "Time|s" msgstr "Sek." +msgid "Title" +msgstr "" + msgid "Total Time" msgstr "Gesamtzeit" +msgid "Total issue time spent" +msgstr "" + msgid "Total test time for all commits/merges" msgstr "Gesamte Testzeit für alle Commits/Merges" msgid "Track activity with Contribution Analytics." msgstr "" +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "" + +msgid "Turn on Service Desk" +msgstr "" + msgid "Unlock" msgstr "" @@ -2250,6 +2743,9 @@ msgstr "Eine Datei hochladen" msgid "UploadLink|click to upload" msgstr "Zum Upload klicken" +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "" + msgid "Use the following registration token during setup:" msgstr "Benutze den folgenden Registrierungstoken während des Setups:" @@ -2283,6 +2779,9 @@ msgstr "Du möchtest diese Daten sehen? Bitte frage einen Administrator nach dem msgid "We don't have enough data to show this stage." msgstr "Es liegen nicht genügend Daten vor, um diese Phase anzuzeigen." +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "" + msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." msgstr "" @@ -2412,12 +2911,6 @@ msgstr "Du bist dabei, die Beziehung des Ablegers zum Ursprungsprojekt %{forked_ msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "Du bist dabei %{project_name_with_namespace} einem andere Besitzer zu übergeben. Bist Du dir WIRKLICH sicher?" -msgid "You are on a read-only GitLab instance." -msgstr "" - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "" - msgid "You can only add files when you are on a branch" msgstr "Du kannst Dateien nur hinzufügen, wenn Du dich auf einem Branch befindest." @@ -2457,6 +2950,9 @@ msgstr "Du kannst erst mittels '%{protocol}' übertragen (push) oder abrufen (pu msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" msgstr "Du kannst erst mittels SSH übertragen (push) oder abrufen (pull), nachdem Du Deinem Konto '%{add_ssh_key_link}'." +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "" + msgid "Your comment will not be visible to the public." msgstr "" @@ -2469,8 +2965,14 @@ msgstr "Dein Name" msgid "Your projects" msgstr "Deine Projekte" +msgid "branch name" +msgstr "" + +msgid "by" +msgstr "" + msgid "commit" -msgstr "Commit" +msgstr "" msgid "day" msgid_plural "days" @@ -2494,6 +2996,9 @@ msgstr "" msgid "personal access token" msgstr "" +msgid "source" +msgstr "" + msgid "to help your contributors communicate effectively!" msgstr "" diff --git a/locale/eo/gitlab.po b/locale/eo/gitlab.po index f7be343c4e1..be7cfa6e4b5 100644 --- a/locale/eo/gitlab.po +++ b/locale/eo/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-03 12:30-0400\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 04:42-0500\n" "Last-Translator: gitlab \n" "Language-Team: Esperanto\n" "Language: eo_UY\n" @@ -56,6 +56,9 @@ msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts msgstr[0] "" msgstr[1] "" +msgid "%{text} is available" +msgstr "" + msgid "(checkout the %{link} for information on how to install it)." msgstr "" @@ -115,9 +118,6 @@ msgstr "" msgid "Add License" msgstr "Aldoni rajtigilon" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "Aldonu SSH-ŝlosilon al via profilo por ebligi al vi eltiri kaj alpuŝi per SSH." - msgid "Add new directory" msgstr "Aldoni novan dosierujon" @@ -130,6 +130,15 @@ msgstr "" msgid "All" msgstr "" +msgid "An error occurred when toggling the notification subscription" +msgstr "" + +msgid "An error occurred when updating the issue weight" +msgstr "" + +msgid "An error occurred while fetching sidebar data" +msgstr "" + msgid "An error occurred. Please try again." msgstr "" @@ -139,6 +148,12 @@ msgstr "" msgid "Applications" msgstr "" +msgid "Apr" +msgstr "" + +msgid "April" +msgstr "" + msgid "Archived project! Repository is read-only" msgstr "Arkivita projekto! La deponejo permesas nur legadon" @@ -166,6 +181,12 @@ msgstr "" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "Alkroĉu dosieron per ŝovmetado aŭ %{upload_link}" +msgid "Aug" +msgstr "" + +msgid "August" +msgstr "" + msgid "Authentication Log" msgstr "" @@ -199,6 +220,9 @@ msgstr "" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." msgstr "" +msgid "Available" +msgstr "" + msgid "Billing" msgstr "" @@ -264,6 +288,12 @@ msgstr "La branĉo %{branch_name} estis kreita. Por agordi aŭt msgid "Branch has changed" msgstr "" +msgid "Branch is already taken" +msgstr "" + +msgid "Branch name" +msgstr "" + msgid "BranchSwitcherPlaceholder|Search branches" msgstr "Serĉu branĉon" @@ -411,6 +441,12 @@ msgstr "Diagramoj" msgid "Chat" msgstr "" +msgid "Checking %{text} availability…" +msgstr "" + +msgid "Checking branch availability..." +msgstr "" + msgid "Cherry-pick this commit" msgstr "Precize elekti ĉi tiun kunmetadon" @@ -486,7 +522,40 @@ msgstr "" msgid "Cluster" msgstr "" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "" + +msgid "ClusterIntegration|API URL" +msgstr "" + +msgid "ClusterIntegration|Active" +msgstr "" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "" + +msgid "ClusterIntegration|Add cluster" +msgstr "" + +msgid "ClusterIntegration|All" +msgstr "" + +msgid "ClusterIntegration|Applications" +msgstr "" + +msgid "ClusterIntegration|CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "" + +msgid "ClusterIntegration|Cluster" msgstr "" msgid "ClusterIntegration|Cluster details" @@ -510,21 +579,54 @@ msgstr "" msgid "ClusterIntegration|Cluster name" msgstr "" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" +msgstr "" + +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "" + +msgid "ClusterIntegration|Copy API URL" +msgstr "" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Copy Token" msgstr "" msgid "ClusterIntegration|Copy cluster name" msgstr "" +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "" + msgid "ClusterIntegration|Create cluster" msgstr "" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Create on GKE" msgstr "" msgid "ClusterIntegration|Enable cluster integration" msgstr "" +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "" + +msgid "ClusterIntegration|Environment pattern" +msgstr "" + +msgid "ClusterIntegration|GKE pricing" +msgstr "" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "" + msgid "ClusterIntegration|Google Cloud Platform project ID" msgstr "" @@ -534,27 +636,75 @@ msgstr "" msgid "ClusterIntegration|Google Kubernetes Engine project" msgstr "" +msgid "ClusterIntegration|Helm Tiller" +msgstr "" + +msgid "ClusterIntegration|Inactive" +msgstr "" + +msgid "ClusterIntegration|Ingress" +msgstr "" + +msgid "ClusterIntegration|Install" +msgstr "" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "" + +msgid "ClusterIntegration|Installed" +msgstr "" + +msgid "ClusterIntegration|Installing" +msgstr "" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "" + msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "" + msgid "ClusterIntegration|Machine type" msgstr "" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" msgstr "" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" msgstr "" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" msgstr "" +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "" + +msgid "ClusterIntegration|Note:" +msgstr "" + msgid "ClusterIntegration|Number of nodes" msgstr "" +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" +msgstr "" + msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgstr "" +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "" + +msgid "ClusterIntegration|Project ID" +msgstr "" + +msgid "ClusterIntegration|Project namespace" +msgstr "" + msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "" @@ -567,7 +717,13 @@ msgstr "" msgid "ClusterIntegration|Remove integration" msgstr "" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "" + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "" + +msgid "ClusterIntegration|Save changes" msgstr "" msgid "ClusterIntegration|See and edit the details for your cluster" @@ -582,15 +738,33 @@ msgstr "" msgid "ClusterIntegration|See zones" msgstr "" +msgid "ClusterIntegration|Service token" +msgstr "" + +msgid "ClusterIntegration|Show" +msgstr "" + msgid "ClusterIntegration|Something went wrong on our end." msgstr "" msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" msgstr "" +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "" + msgid "ClusterIntegration|Toggle Cluster" msgstr "" +msgid "ClusterIntegration|Token" +msgstr "" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "" @@ -606,9 +780,15 @@ msgstr "" msgid "ClusterIntegration|cluster" msgstr "" +msgid "ClusterIntegration|documentation" +msgstr "" + msgid "ClusterIntegration|help page" msgstr "" +msgid "ClusterIntegration|installing applications" +msgstr "" + msgid "ClusterIntegration|meets the requirements" msgstr "" @@ -623,11 +803,6 @@ msgid_plural "Commits" msgstr[0] "Enmetado" msgstr[1] "Enmetadoj" -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "" -msgstr[1] "" - msgid "Commit Message" msgstr "" @@ -709,6 +884,15 @@ msgstr "Gvidlinioj por kontribuado" msgid "Contributors" msgstr "Kontribuantoj" +msgid "ContributorsPage|Building repository graph." +msgstr "" + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "" + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "" + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" msgstr "" @@ -736,6 +920,9 @@ msgstr "Krei dosierujon" msgid "Create empty bare repository" msgstr "Krei malplenan deponejon" +msgid "Create epic" +msgstr "" + msgid "Create file" msgstr "" @@ -763,6 +950,9 @@ msgstr "Etikedo" msgid "CreateTokenToCloneLink|create a personal access token" msgstr "kreos propran atingoĵetonon" +msgid "Creating epic" +msgstr "" + msgid "Cron Timezone" msgstr "Horzono por Cron" @@ -808,6 +998,12 @@ msgstr "" msgid "DashboardProjects|Personal" msgstr "" +msgid "Dec" +msgstr "" + +msgid "December" +msgstr "" + msgid "Define a custom pattern with cron syntax" msgstr "Difini propran ŝablonon, uzante la sintakson de Cron" @@ -882,6 +1078,72 @@ msgstr "Redakti ĉenstablan planon %{id}" msgid "Emails" msgstr "" +msgid "Environments|An error occurred while fetching the environments." +msgstr "" + +msgid "Environments|An error occurred while making the request." +msgstr "" + +msgid "Environments|Commit" +msgstr "" + +msgid "Environments|Deployment" +msgstr "" + +msgid "Environments|Environment" +msgstr "" + +msgid "Environments|Environments" +msgstr "" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "" + +msgid "Environments|Job" +msgstr "" + +msgid "Environments|New environment" +msgstr "" + +msgid "Environments|No deployments yet" +msgstr "" + +msgid "Environments|Open" +msgstr "" + +msgid "Environments|Re-deploy" +msgstr "" + +msgid "Environments|Read more about environments" +msgstr "" + +msgid "Environments|Rollback" +msgstr "" + +msgid "Environments|Show all" +msgstr "" + +msgid "Environments|Updated" +msgstr "" + +msgid "Environments|You don't have any environments right now." +msgstr "" + +msgid "Epic will be removed! Are you sure?" +msgstr "" + +msgid "Epics" +msgstr "" + +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" +msgstr "" + +msgid "Error creating epic" +msgstr "" + +msgid "Error occurred when toggling the notification subscription" +msgstr "" + msgid "EventFilterBy|Filter by all" msgstr "" @@ -921,6 +1183,12 @@ msgstr "Ne eblas ŝanĝi la posedanton" msgid "Failed to remove the pipeline schedule" msgstr "Ne eblas forigi la ĉenstablan planon" +msgid "Feb" +msgstr "" + +msgid "February" +msgstr "" + msgid "File name" msgstr "" @@ -968,6 +1236,21 @@ msgstr "" msgid "Geo Nodes" msgstr "" +msgid "GeoNodeSyncStatus|Failed" +msgstr "" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "" + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "" + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "" + msgid "Geo|File sync capacity" msgstr "" @@ -1031,9 +1314,6 @@ msgstr "" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "" -msgid "GroupsTreeRole|as" -msgstr "" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "" @@ -1064,6 +1344,9 @@ msgstr "" msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "" +msgid "Have your users email" +msgstr "" + msgid "Health Check" msgstr "" @@ -1123,9 +1406,6 @@ msgstr "Ni prezentas al vi la ciklan analizon" msgid "Issue board focus mode" msgstr "" -msgid "Issue boards with milestones" -msgstr "" - msgid "Issue events" msgstr "" @@ -1138,6 +1418,24 @@ msgstr "" msgid "Issues" msgstr "" +msgid "Jan" +msgstr "" + +msgid "January" +msgstr "" + +msgid "Jul" +msgstr "" + +msgid "July" +msgstr "" + +msgid "Jun" +msgstr "" + +msgid "June" +msgstr "" + msgid "LFSStatus|Disabled" msgstr "Malŝaltita" @@ -1211,9 +1509,18 @@ msgstr "" msgid "Login" msgstr "" +msgid "Mar" +msgstr "" + +msgid "March" +msgstr "" + msgid "Maximum git storage failures" msgstr "" +msgid "May" +msgstr "" + msgid "Median" msgstr "Mediano" @@ -1258,9 +1565,15 @@ msgstr "Nova ĉenstabla plano" msgid "New branch" msgstr "Nova branĉo" +msgid "New branch unavailable" +msgstr "" + msgid "New directory" msgstr "Nova dosierujo" +msgid "New epic" +msgstr "" + msgid "New file" msgstr "Nova dosiero" @@ -1297,6 +1610,9 @@ msgstr "Ne estas deponejo" msgid "No schedules" msgstr "Ne estas planoj" +msgid "No time spent" +msgstr "" + msgid "None" msgstr "" @@ -1363,18 +1679,33 @@ msgstr "Rigardado" msgid "Notifications" msgstr "" +msgid "Nov" +msgstr "" + +msgid "November" +msgstr "" + msgid "Number of access attempts" msgstr "" msgid "Number of failures before backing off" msgstr "" +msgid "Oct" +msgstr "" + +msgid "October" +msgstr "" + msgid "OfSearchInADropdown|Filter" msgstr "Filtrilo" msgid "Only project members can comment." msgstr "" +msgid "Opened" +msgstr "" + msgid "OpenedNDaysAgo|Opened" msgstr "Malfermita" @@ -1507,6 +1838,9 @@ msgstr "kun etapo" msgid "Pipeline|with stages" msgstr "kun etapoj" +msgid "Please solve the reCAPTCHA" +msgstr "" + msgid "Preferences" msgstr "" @@ -1612,9 +1946,15 @@ msgstr "Grafeo" msgid "ProjectSettings|Contact an admin to change this setting." msgstr "" +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "" + msgid "ProjectSettings|Only signed commits can be pushed to this repository." msgstr "" +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "" + msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." msgstr "" @@ -1651,6 +1991,39 @@ msgstr "" msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "" +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "" + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "" + +msgid "PrometheusService|Metrics" +msgstr "" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "" + +msgid "PrometheusService|Missing environment variable" +msgstr "" + +msgid "PrometheusService|Monitored" +msgstr "" + +msgid "PrometheusService|More information" +msgstr "" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "" + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" +msgstr "" + +msgid "PrometheusService|Prometheus monitoring" +msgstr "" + +msgid "PrometheusService|View environments" +msgstr "" + msgid "Public - The group and any public projects can be viewed without any authentication." msgstr "" @@ -1747,6 +2120,9 @@ msgstr "" msgid "Scheduling Pipelines" msgstr "Planado de la ĉenstabloj" +msgid "Scoped issue boards" +msgstr "" + msgid "Search branches and tags" msgstr "Serĉu branĉon aŭ etikedon" @@ -1768,6 +2144,12 @@ msgstr "Elektu horzonon" msgid "Select target branch" msgstr "Elektu celan branĉon" +msgid "Sep" +msgstr "" + +msgid "September" +msgstr "" + msgid "Service Templates" msgstr "" @@ -1800,13 +2182,28 @@ msgid_plural "Showing %d events" msgstr[0] "Estas montrata %d evento" msgstr[1] "Estas montrataj %d eventoj" +msgid "Sidebar|Change weight" +msgstr "" + +msgid "Sidebar|Edit" +msgstr "" + +msgid "Sidebar|No" +msgstr "" + +msgid "Sidebar|None" +msgstr "" + +msgid "Sidebar|Weight" +msgstr "" + msgid "Snippets" msgstr "" msgid "Something went wrong on our end." msgstr "" -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" msgstr "" msgid "Something went wrong while fetching the projects." @@ -1914,9 +2311,15 @@ msgstr "" msgid "SortOptions|Weight" msgstr "" +msgid "Source" +msgstr "" + msgid "Source code" msgstr "Kodo" +msgid "Source is not available" +msgstr "" + msgid "Spam Logs" msgstr "" @@ -1935,6 +2338,9 @@ msgstr "Kreu %{new_merge_request} kun ĉi tiuj ŝanĝoj" msgid "Start the Runner!" msgstr "" +msgid "Stopped" +msgstr "" + msgid "Subgroups" msgstr "" @@ -1955,6 +2361,75 @@ msgstr[1] "Etikedoj" msgid "Tags" msgstr "Etikedoj" +msgid "TagsPage|Browse commits" +msgstr "" + +msgid "TagsPage|Browse files" +msgstr "" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "" + +msgid "TagsPage|Cancel" +msgstr "" + +msgid "TagsPage|Create tag" +msgstr "" + +msgid "TagsPage|Delete tag" +msgstr "" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "" + +msgid "TagsPage|Edit release notes" +msgstr "" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "" + +msgid "TagsPage|Filter by tag name" +msgstr "" + +msgid "TagsPage|New Tag" +msgstr "" + +msgid "TagsPage|New tag" +msgstr "" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "" + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "" + +msgid "TagsPage|Release notes" +msgstr "" + +msgid "TagsPage|Repository has no tags yet." +msgstr "" + +msgid "TagsPage|Sort by" +msgstr "" + +msgid "TagsPage|Tags" +msgstr "" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "" + +msgid "TagsPage|This tag has no release notes." +msgstr "" + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "" + +msgid "TagsPage|protected" +msgstr "" + msgid "Target Branch" msgstr "Cela branĉo" @@ -2036,6 +2511,9 @@ msgstr "La valoro, kiu troviĝas en la mezo de aro da rigardataj valoroj. Ekzemp msgid "There are problems accessing Git storage: " msgstr "" +msgid "This board\\'s scope is reduced" +msgstr "" + msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "" @@ -2057,6 +2535,9 @@ msgstr "Ĉi tiu signifas, ke vi ne povos alpuŝi kodon, antaŭ ol vi kreos malpl msgid "This merge request is locked." msgstr "" +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "Tempo antaŭ problemo estas planita por ellabori" @@ -2205,15 +2686,27 @@ msgstr[1] "min" msgid "Time|s" msgstr "s" +msgid "Title" +msgstr "" + msgid "Total Time" msgstr "Totala tempo" +msgid "Total issue time spent" +msgstr "" + msgid "Total test time for all commits/merges" msgstr "Totala tempo por la testado de ĉiuj enmetadoj/kunfandoj" msgid "Track activity with Contribution Analytics." msgstr "" +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "" + +msgid "Turn on Service Desk" +msgstr "" + msgid "Unlock" msgstr "" @@ -2250,6 +2743,9 @@ msgstr "Alŝuti dosieron" msgid "UploadLink|click to upload" msgstr "alklaku por alŝuti" +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "" + msgid "Use the following registration token during setup:" msgstr "" @@ -2283,6 +2779,9 @@ msgstr "Ĉu vi volas vidi la datenojn? Bonvolu peti atingeblon de administranto. msgid "We don't have enough data to show this stage." msgstr "Ne estas sufiĉe da datenoj por montri ĉi tiun etapon." +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "" + msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." msgstr "" @@ -2412,12 +2911,6 @@ msgstr "Vi forigos la rilaton de la disbranĉigo al la originala projekto, „%{ msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "Vi estas transigonta „%{project_name_with_namespace}“ al alia posedanto. Ĉu vi estas ABSOLUTE certa?" -msgid "You are on a read-only GitLab instance." -msgstr "" - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "" - msgid "You can only add files when you are on a branch" msgstr "Oni povas aldoni dosierojn nur kiam oni estas en branĉo" @@ -2457,6 +2950,9 @@ msgstr "Vi ne povos eltiri aŭ alpuŝi kodon per %{protocol} antaŭ ol vi %{set_ msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" msgstr "Vi ne povos eltiri aŭ alpuŝi kodon per SSH antaŭ ol vi %{add_ssh_key_link} al via profilo" +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "" + msgid "Your comment will not be visible to the public." msgstr "" @@ -2469,6 +2965,12 @@ msgstr "Via nomo" msgid "Your projects" msgstr "" +msgid "branch name" +msgstr "" + +msgid "by" +msgstr "" + msgid "commit" msgstr "" @@ -2494,6 +2996,9 @@ msgstr "" msgid "personal access token" msgstr "" +msgid "source" +msgstr "" + msgid "to help your contributors communicate effectively!" msgstr "" diff --git a/locale/es/gitlab.po b/locale/es/gitlab.po index c35a3503019..44ad3d4633a 100644 --- a/locale/es/gitlab.po +++ b/locale/es/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-03 12:31-0400\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 04:41-0500\n" "Last-Translator: gitlab \n" "Language-Team: Spanish\n" "Language: es_ES\n" @@ -56,6 +56,9 @@ msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts msgstr[0] "" msgstr[1] "" +msgid "%{text} is available" +msgstr "" + msgid "(checkout the %{link} for information on how to install it)." msgstr "" @@ -115,9 +118,6 @@ msgstr "" msgid "Add License" msgstr "Agregar Licencia" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "Agregar una clave SSH a tu perfil para actualizar o enviar a través de SSH." - msgid "Add new directory" msgstr "Agregar nuevo directorio" @@ -130,6 +130,15 @@ msgstr "" msgid "All" msgstr "" +msgid "An error occurred when toggling the notification subscription" +msgstr "" + +msgid "An error occurred when updating the issue weight" +msgstr "" + +msgid "An error occurred while fetching sidebar data" +msgstr "" + msgid "An error occurred. Please try again." msgstr "" @@ -139,6 +148,12 @@ msgstr "" msgid "Applications" msgstr "" +msgid "Apr" +msgstr "" + +msgid "April" +msgstr "" + msgid "Archived project! Repository is read-only" msgstr "¡Proyecto archivado! El repositorio es de solo lectura" @@ -166,6 +181,12 @@ msgstr "" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "Adjunte un archivo arrastrando & soltando o %{upload_link}" +msgid "Aug" +msgstr "" + +msgid "August" +msgstr "" + msgid "Authentication Log" msgstr "" @@ -199,6 +220,9 @@ msgstr "" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." msgstr "" +msgid "Available" +msgstr "" + msgid "Billing" msgstr "" @@ -264,6 +288,12 @@ msgstr "La rama %{branch_name} fue creada. Para configurar el a msgid "Branch has changed" msgstr "" +msgid "Branch is already taken" +msgstr "" + +msgid "Branch name" +msgstr "" + msgid "BranchSwitcherPlaceholder|Search branches" msgstr "Buscar ramas" @@ -411,6 +441,12 @@ msgstr "Gráficos" msgid "Chat" msgstr "" +msgid "Checking %{text} availability…" +msgstr "" + +msgid "Checking branch availability..." +msgstr "" + msgid "Cherry-pick this commit" msgstr "Escoger este cambio" @@ -486,7 +522,40 @@ msgstr "" msgid "Cluster" msgstr "" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "" + +msgid "ClusterIntegration|API URL" +msgstr "" + +msgid "ClusterIntegration|Active" +msgstr "" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "" + +msgid "ClusterIntegration|Add cluster" +msgstr "" + +msgid "ClusterIntegration|All" +msgstr "" + +msgid "ClusterIntegration|Applications" +msgstr "" + +msgid "ClusterIntegration|CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "" + +msgid "ClusterIntegration|Cluster" msgstr "" msgid "ClusterIntegration|Cluster details" @@ -510,21 +579,54 @@ msgstr "" msgid "ClusterIntegration|Cluster name" msgstr "" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" +msgstr "" + +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "" + +msgid "ClusterIntegration|Copy API URL" +msgstr "" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Copy Token" msgstr "" msgid "ClusterIntegration|Copy cluster name" msgstr "" +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "" + msgid "ClusterIntegration|Create cluster" msgstr "" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Create on GKE" msgstr "" msgid "ClusterIntegration|Enable cluster integration" msgstr "" +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "" + +msgid "ClusterIntegration|Environment pattern" +msgstr "" + +msgid "ClusterIntegration|GKE pricing" +msgstr "" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "" + msgid "ClusterIntegration|Google Cloud Platform project ID" msgstr "" @@ -534,27 +636,75 @@ msgstr "" msgid "ClusterIntegration|Google Kubernetes Engine project" msgstr "" +msgid "ClusterIntegration|Helm Tiller" +msgstr "" + +msgid "ClusterIntegration|Inactive" +msgstr "" + +msgid "ClusterIntegration|Ingress" +msgstr "" + +msgid "ClusterIntegration|Install" +msgstr "" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "" + +msgid "ClusterIntegration|Installed" +msgstr "" + +msgid "ClusterIntegration|Installing" +msgstr "" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "" + msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "" + msgid "ClusterIntegration|Machine type" msgstr "" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" msgstr "" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" msgstr "" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" msgstr "" +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "" + +msgid "ClusterIntegration|Note:" +msgstr "" + msgid "ClusterIntegration|Number of nodes" msgstr "" +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" +msgstr "" + msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgstr "" +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "" + +msgid "ClusterIntegration|Project ID" +msgstr "" + +msgid "ClusterIntegration|Project namespace" +msgstr "" + msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "" @@ -567,7 +717,13 @@ msgstr "" msgid "ClusterIntegration|Remove integration" msgstr "" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "" + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "" + +msgid "ClusterIntegration|Save changes" msgstr "" msgid "ClusterIntegration|See and edit the details for your cluster" @@ -582,15 +738,33 @@ msgstr "" msgid "ClusterIntegration|See zones" msgstr "" +msgid "ClusterIntegration|Service token" +msgstr "" + +msgid "ClusterIntegration|Show" +msgstr "" + msgid "ClusterIntegration|Something went wrong on our end." msgstr "" msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" msgstr "" +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "" + msgid "ClusterIntegration|Toggle Cluster" msgstr "" +msgid "ClusterIntegration|Token" +msgstr "" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "" @@ -606,9 +780,15 @@ msgstr "" msgid "ClusterIntegration|cluster" msgstr "" +msgid "ClusterIntegration|documentation" +msgstr "" + msgid "ClusterIntegration|help page" msgstr "" +msgid "ClusterIntegration|installing applications" +msgstr "" + msgid "ClusterIntegration|meets the requirements" msgstr "" @@ -623,11 +803,6 @@ msgid_plural "Commits" msgstr[0] "Cambio" msgstr[1] "Cambios" -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "" -msgstr[1] "" - msgid "Commit Message" msgstr "" @@ -709,6 +884,15 @@ msgstr "Guía de contribución" msgid "Contributors" msgstr "Contribuidores" +msgid "ContributorsPage|Building repository graph." +msgstr "" + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "" + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "" + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" msgstr "" @@ -736,6 +920,9 @@ msgstr "Crear directorio" msgid "Create empty bare repository" msgstr "Crear repositorio vacío" +msgid "Create epic" +msgstr "" + msgid "Create file" msgstr "" @@ -763,6 +950,9 @@ msgstr "Etiqueta" msgid "CreateTokenToCloneLink|create a personal access token" msgstr "crear un token de acceso personal" +msgid "Creating epic" +msgstr "" + msgid "Cron Timezone" msgstr "Zona horaria del Cron" @@ -808,6 +998,12 @@ msgstr "" msgid "DashboardProjects|Personal" msgstr "" +msgid "Dec" +msgstr "" + +msgid "December" +msgstr "" + msgid "Define a custom pattern with cron syntax" msgstr "Definir un patrón personalizado con la sintaxis de cron" @@ -882,6 +1078,72 @@ msgstr "Editar Programación del Pipeline %{id}" msgid "Emails" msgstr "" +msgid "Environments|An error occurred while fetching the environments." +msgstr "" + +msgid "Environments|An error occurred while making the request." +msgstr "" + +msgid "Environments|Commit" +msgstr "" + +msgid "Environments|Deployment" +msgstr "" + +msgid "Environments|Environment" +msgstr "" + +msgid "Environments|Environments" +msgstr "" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "" + +msgid "Environments|Job" +msgstr "" + +msgid "Environments|New environment" +msgstr "" + +msgid "Environments|No deployments yet" +msgstr "" + +msgid "Environments|Open" +msgstr "" + +msgid "Environments|Re-deploy" +msgstr "" + +msgid "Environments|Read more about environments" +msgstr "" + +msgid "Environments|Rollback" +msgstr "" + +msgid "Environments|Show all" +msgstr "" + +msgid "Environments|Updated" +msgstr "" + +msgid "Environments|You don't have any environments right now." +msgstr "" + +msgid "Epic will be removed! Are you sure?" +msgstr "" + +msgid "Epics" +msgstr "" + +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" +msgstr "" + +msgid "Error creating epic" +msgstr "" + +msgid "Error occurred when toggling the notification subscription" +msgstr "" + msgid "EventFilterBy|Filter by all" msgstr "" @@ -921,6 +1183,12 @@ msgstr "Error al cambiar el propietario" msgid "Failed to remove the pipeline schedule" msgstr "Error al eliminar la programación del pipeline" +msgid "Feb" +msgstr "" + +msgid "February" +msgstr "" + msgid "File name" msgstr "" @@ -968,6 +1236,21 @@ msgstr "" msgid "Geo Nodes" msgstr "" +msgid "GeoNodeSyncStatus|Failed" +msgstr "" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "" + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "" + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "" + msgid "Geo|File sync capacity" msgstr "" @@ -1031,9 +1314,6 @@ msgstr "" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "" -msgid "GroupsTreeRole|as" -msgstr "" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "" @@ -1064,6 +1344,9 @@ msgstr "" msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "" +msgid "Have your users email" +msgstr "" + msgid "Health Check" msgstr "" @@ -1123,9 +1406,6 @@ msgstr "Introducción a Cycle Analytics" msgid "Issue board focus mode" msgstr "" -msgid "Issue boards with milestones" -msgstr "" - msgid "Issue events" msgstr "" @@ -1138,6 +1418,24 @@ msgstr "" msgid "Issues" msgstr "" +msgid "Jan" +msgstr "" + +msgid "January" +msgstr "" + +msgid "Jul" +msgstr "" + +msgid "July" +msgstr "" + +msgid "Jun" +msgstr "" + +msgid "June" +msgstr "" + msgid "LFSStatus|Disabled" msgstr "Deshabilitado" @@ -1211,9 +1509,18 @@ msgstr "" msgid "Login" msgstr "" +msgid "Mar" +msgstr "" + +msgid "March" +msgstr "" + msgid "Maximum git storage failures" msgstr "" +msgid "May" +msgstr "" + msgid "Median" msgstr "Mediana" @@ -1258,9 +1565,15 @@ msgstr "Nueva Programación del Pipeline" msgid "New branch" msgstr "Nueva rama" +msgid "New branch unavailable" +msgstr "" + msgid "New directory" msgstr "Nuevo directorio" +msgid "New epic" +msgstr "" + msgid "New file" msgstr "Nuevo archivo" @@ -1297,6 +1610,9 @@ msgstr "No hay repositorio" msgid "No schedules" msgstr "No hay programaciones" +msgid "No time spent" +msgstr "" + msgid "None" msgstr "" @@ -1363,18 +1679,33 @@ msgstr "Vigilancia" msgid "Notifications" msgstr "" +msgid "Nov" +msgstr "" + +msgid "November" +msgstr "" + msgid "Number of access attempts" msgstr "" msgid "Number of failures before backing off" msgstr "" +msgid "Oct" +msgstr "" + +msgid "October" +msgstr "" + msgid "OfSearchInADropdown|Filter" msgstr "Filtrar" msgid "Only project members can comment." msgstr "" +msgid "Opened" +msgstr "" + msgid "OpenedNDaysAgo|Opened" msgstr "Abierto" @@ -1507,6 +1838,9 @@ msgstr "con etapa" msgid "Pipeline|with stages" msgstr "con etapas" +msgid "Please solve the reCAPTCHA" +msgstr "" + msgid "Preferences" msgstr "" @@ -1612,9 +1946,15 @@ msgstr "Historial gráfico" msgid "ProjectSettings|Contact an admin to change this setting." msgstr "" +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "" + msgid "ProjectSettings|Only signed commits can be pushed to this repository." msgstr "" +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "" + msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." msgstr "" @@ -1651,6 +1991,39 @@ msgstr "" msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "" +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "" + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "" + +msgid "PrometheusService|Metrics" +msgstr "" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "" + +msgid "PrometheusService|Missing environment variable" +msgstr "" + +msgid "PrometheusService|Monitored" +msgstr "" + +msgid "PrometheusService|More information" +msgstr "" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "" + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" +msgstr "" + +msgid "PrometheusService|Prometheus monitoring" +msgstr "" + +msgid "PrometheusService|View environments" +msgstr "" + msgid "Public - The group and any public projects can be viewed without any authentication." msgstr "" @@ -1747,6 +2120,9 @@ msgstr "" msgid "Scheduling Pipelines" msgstr "Programación de Pipelines" +msgid "Scoped issue boards" +msgstr "" + msgid "Search branches and tags" msgstr "Buscar ramas y etiquetas" @@ -1768,6 +2144,12 @@ msgstr "Selecciona una zona horaria" msgid "Select target branch" msgstr "Selecciona una rama de destino" +msgid "Sep" +msgstr "" + +msgid "September" +msgstr "" + msgid "Service Templates" msgstr "" @@ -1800,13 +2182,28 @@ msgid_plural "Showing %d events" msgstr[0] "Mostrando %d evento" msgstr[1] "Mostrando %d eventos" +msgid "Sidebar|Change weight" +msgstr "" + +msgid "Sidebar|Edit" +msgstr "" + +msgid "Sidebar|No" +msgstr "" + +msgid "Sidebar|None" +msgstr "" + +msgid "Sidebar|Weight" +msgstr "" + msgid "Snippets" msgstr "" msgid "Something went wrong on our end." msgstr "" -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" msgstr "" msgid "Something went wrong while fetching the projects." @@ -1914,9 +2311,15 @@ msgstr "" msgid "SortOptions|Weight" msgstr "" +msgid "Source" +msgstr "" + msgid "Source code" msgstr "Código fuente" +msgid "Source is not available" +msgstr "" + msgid "Spam Logs" msgstr "" @@ -1935,6 +2338,9 @@ msgstr "Iniciar una %{new_merge_request} con estos cambios" msgid "Start the Runner!" msgstr "" +msgid "Stopped" +msgstr "" + msgid "Subgroups" msgstr "" @@ -1955,6 +2361,75 @@ msgstr[1] "Etiquetas" msgid "Tags" msgstr "Etiquetas" +msgid "TagsPage|Browse commits" +msgstr "" + +msgid "TagsPage|Browse files" +msgstr "" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "" + +msgid "TagsPage|Cancel" +msgstr "" + +msgid "TagsPage|Create tag" +msgstr "" + +msgid "TagsPage|Delete tag" +msgstr "" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "" + +msgid "TagsPage|Edit release notes" +msgstr "" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "" + +msgid "TagsPage|Filter by tag name" +msgstr "" + +msgid "TagsPage|New Tag" +msgstr "" + +msgid "TagsPage|New tag" +msgstr "" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "" + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "" + +msgid "TagsPage|Release notes" +msgstr "" + +msgid "TagsPage|Repository has no tags yet." +msgstr "" + +msgid "TagsPage|Sort by" +msgstr "" + +msgid "TagsPage|Tags" +msgstr "" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "" + +msgid "TagsPage|This tag has no release notes." +msgstr "" + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "" + +msgid "TagsPage|protected" +msgstr "" + msgid "Target Branch" msgstr "Rama de destino" @@ -2036,6 +2511,9 @@ msgstr "El valor en el punto medio de una serie de valores observados. Por ejemp msgid "There are problems accessing Git storage: " msgstr "" +msgid "This board\\'s scope is reduced" +msgstr "" + msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "" @@ -2057,6 +2535,9 @@ msgstr "Esto significa que no puede enviar código hasta que cree un repositorio msgid "This merge request is locked." msgstr "" +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "Tiempo antes de que una incidencia sea programada" @@ -2205,15 +2686,27 @@ msgstr[1] "mins" msgid "Time|s" msgstr "s" +msgid "Title" +msgstr "" + msgid "Total Time" msgstr "Tiempo Total" +msgid "Total issue time spent" +msgstr "" + msgid "Total test time for all commits/merges" msgstr "Tiempo total de pruebas para todos los cambios o integraciones" msgid "Track activity with Contribution Analytics." msgstr "" +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "" + +msgid "Turn on Service Desk" +msgstr "" + msgid "Unlock" msgstr "" @@ -2250,6 +2743,9 @@ msgstr "Subir archivo" msgid "UploadLink|click to upload" msgstr "Hacer clic para subir" +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "" + msgid "Use the following registration token during setup:" msgstr "" @@ -2283,6 +2779,9 @@ msgstr "¿Quieres ver los datos? Por favor pide acceso al administrador." msgid "We don't have enough data to show this stage." msgstr "No hay suficientes datos para mostrar en esta etapa." +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "" + msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." msgstr "" @@ -2412,12 +2911,6 @@ msgstr "Vas a eliminar el enlace de la bifurcación con el proyecto original %{f msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "Vas a transferir %{project_name_with_namespace} a otro propietario. ¿Estás TOTALMENTE seguro?" -msgid "You are on a read-only GitLab instance." -msgstr "" - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "" - msgid "You can only add files when you are on a branch" msgstr "Solo puedes agregar archivos cuando estás en una rama" @@ -2457,6 +2950,9 @@ msgstr "No podrás actualizar o enviar código al proyecto a través de %{protoc msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" msgstr "No podrás actualizar o enviar código al proyecto a través de SSH hasta que %{add_ssh_key_link} en su perfil" +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "" + msgid "Your comment will not be visible to the public." msgstr "" @@ -2469,6 +2965,12 @@ msgstr "Tu nombre" msgid "Your projects" msgstr "" +msgid "branch name" +msgstr "" + +msgid "by" +msgstr "" + msgid "commit" msgstr "" @@ -2494,6 +2996,9 @@ msgstr "" msgid "personal access token" msgstr "" +msgid "source" +msgstr "" + msgid "to help your contributors communicate effectively!" msgstr "" diff --git a/locale/fr/gitlab.po b/locale/fr/gitlab.po index a0e523339db..ace6a5d2f66 100644 --- a/locale/fr/gitlab.po +++ b/locale/fr/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-21 16:43-0500\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 04:40-0500\n" "Last-Translator: gitlab \n" "Language-Team: French\n" "Language: fr_FR\n" @@ -56,6 +56,9 @@ msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts msgstr[0] "%{storage_name} : la tentative d’accès au stockage a échouée sur l’hôte :" msgstr[1] "%{storage_name} : %{failed_attempts} tentatives d’accès au stockage ont échouées :" +msgid "%{text} is available" +msgstr "%{text} est disponible" + msgid "(checkout the %{link} for information on how to install it)." msgstr "(Lisez %{link} pour savoir comment l'installer)." @@ -115,9 +118,6 @@ msgstr "Ajouter des Webhooks de groupe et GitLab Enterprise Edition." msgid "Add License" msgstr "Ajouter une licence" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "Ajoutez une clef SSH à votre profil pour pouvoir récupérer et pousser par SSH." - msgid "Add new directory" msgstr "Ajouter un nouveau dossier" @@ -130,6 +130,15 @@ msgstr "Paramètres avancés" msgid "All" msgstr "Tous" +msgid "An error occurred when toggling the notification subscription" +msgstr "Une erreur s’est produite lors de l’activation/désactivation de l’abonnement aux notifications" + +msgid "An error occurred when updating the issue weight" +msgstr "Une erreur s'est produite lors de la mise à jour du poids du ticket" + +msgid "An error occurred while fetching sidebar data" +msgstr "Une erreur s'est produite lors de la récupération des données de la barre latérale" + msgid "An error occurred. Please try again." msgstr "Une erreur est survenue. Merci de réessayer." @@ -139,6 +148,12 @@ msgstr "Apparence" msgid "Applications" msgstr "Applications" +msgid "Apr" +msgstr "Avr." + +msgid "April" +msgstr "Avril" + msgid "Archived project! Repository is read-only" msgstr "Projet archivé ! Le dépôt est en lecture seule" @@ -166,6 +181,12 @@ msgstr "Artéfacts" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "Attachez un fichier par glisser & déposer ou %{upload_link}" +msgid "Aug" +msgstr "Août" + +msgid "August" +msgstr "Août" + msgid "Authentication Log" msgstr "Journal d'authentification" @@ -199,6 +220,9 @@ msgstr "En savoir plus dans %{link_to_documentation}" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." msgstr "Vous pouvez activer %{link_to_settings} pour ce projet." +msgid "Available" +msgstr "Disponible" + msgid "Billing" msgstr "Facturation" @@ -218,7 +242,7 @@ msgid "BillingPlans|Downgrade" msgstr "Retour à un forfait inférieur" msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}." -msgstr "En savoir plus sur chaque abonnement en lisant nos %{faq_link}." +msgstr "En savoir plus sur chaque forfait en lisant nos %{faq_link}." msgid "BillingPlans|Manage plan" msgstr "Gérer l'abonnement" @@ -227,13 +251,13 @@ msgid "BillingPlans|Please contact %{customer_support_link} in that case." msgstr "Merci de contacter %{customer_support_link} à ce sujet." msgid "BillingPlans|See all %{plan_name} features" -msgstr "Voir toutes les fonctionnalités de l’abonnement %{plan_name}" +msgstr "Voir toutes les fonctionnalités du forfait %{plan_name}" msgid "BillingPlans|This group uses the plan associated with its parent group." -msgstr "Ce groupe utilise l’abonnement associé à son groupe parent." +msgstr "Ce groupe utilise le forfait associé à son groupe parent." msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}." -msgstr "Pour gérer le plan de ce groupe, visitez la section facturation de %{parent_billing_page_link}." +msgstr "Pour gérer l‘abonnement de ce groupe, visitez la section facturation de %{parent_billing_page_link}." msgid "BillingPlans|Upgrade" msgstr "Mise à niveau" @@ -242,13 +266,13 @@ msgid "BillingPlans|You are currently on the %{plan_link} plan." msgstr "Vous êtes actuellement abonné·e au forfait %{plan_link}." msgid "BillingPlans|frequently asked questions" -msgstr "Foire aux questions" +msgstr "foire aux questions" msgid "BillingPlans|monthly" -msgstr "Mensuellement" +msgstr "mensuel" msgid "BillingPlans|paid annually at %{price_per_year}" -msgstr "au prix annuel de %{price_per_year}" +msgstr "payé annuellement pour %{price_per_year}" msgid "BillingPlans|per user" msgstr "par utilisateur" @@ -264,6 +288,12 @@ msgstr "La branche %{branch_name} a été créée. Pour mettre msgid "Branch has changed" msgstr "La branche a été modifiée" +msgid "Branch is already taken" +msgstr "Ce nom de branche existe déjà" + +msgid "Branch name" +msgstr "Nom de la branche" + msgid "BranchSwitcherPlaceholder|Search branches" msgstr "Rechercher la branche" @@ -411,6 +441,12 @@ msgstr "Statistiques" msgid "Chat" msgstr "Chat" +msgid "Checking %{text} availability…" +msgstr "Vérification de la disponibilité de %{text}…" + +msgid "Checking branch availability..." +msgstr "Vérification de la disponibilité du nom de branche..." + msgid "Cherry-pick this commit" msgstr "Picorer cette validation" @@ -486,8 +522,41 @@ msgstr "Fermer" msgid "Cluster" msgstr "Cluster" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" -msgstr "Un %{link_to_container_project} doit avoir été créé pour ce compte" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "%{appList} a été installé avec succès sur votre cluster" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "%{boldNotice} Cela va ajouter des ressources supplémentaires comme un répartiteur de charge, qui engendrent des coûts supplémentaires. Voir %{pricingLink}" + +msgid "ClusterIntegration|API URL" +msgstr "URL de l'API" + +msgid "ClusterIntegration|Active" +msgstr "Actif" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "Ajouter un cluster existant" + +msgid "ClusterIntegration|Add cluster" +msgstr "Ajoutez le cluster" + +msgid "ClusterIntegration|All" +msgstr "Tous" + +msgid "ClusterIntegration|Applications" +msgstr "Applications" + +msgid "ClusterIntegration|CA Certificate" +msgstr "Certificat d‘autorité de certification" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "Paquet de l‘Autorité de certification (format PEM)" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "Choisissez comment configurer l‘intégration de cluster" + +msgid "ClusterIntegration|Cluster" +msgstr "" msgid "ClusterIntegration|Cluster details" msgstr "Détails du cluster" @@ -505,56 +574,137 @@ msgid "ClusterIntegration|Cluster integration is enabled for this project. Disab msgstr "L'intégration de cluster est activée pour ce projet. La désactivation de cette intégration n’affectera pas votre cluster, il coupera temporairement la connexion de GitLab à celui-ci." msgid "ClusterIntegration|Cluster is being created on Google Kubernetes Engine..." -msgstr "Le cluster est en cours de création sur Google Kubernetes Engine…" +msgstr "" msgid "ClusterIntegration|Cluster name" msgstr "Nom du cluster" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" -msgstr "Le cluster a été correctement créé sur Google Kubernetes Engine" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" +msgstr "" + +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "" + +msgid "ClusterIntegration|Copy API URL" +msgstr "" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Copy Token" +msgstr "" msgid "ClusterIntegration|Copy cluster name" msgstr "Copier le nom du cluster" +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "" + msgid "ClusterIntegration|Create cluster" msgstr "Créer le cluster" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" -msgstr "Créer un nouveau cluster sur Google Kubernetes Engine" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Create on GKE" +msgstr "" msgid "ClusterIntegration|Enable cluster integration" msgstr "Activer l’intégration du cluster" +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "" + +msgid "ClusterIntegration|Environment pattern" +msgstr "" + +msgid "ClusterIntegration|GKE pricing" +msgstr "" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "" + msgid "ClusterIntegration|Google Cloud Platform project ID" msgstr "ID de projet Google Cloud Platform" msgid "ClusterIntegration|Google Kubernetes Engine" -msgstr "Google Kubernetes Engine" +msgstr "" msgid "ClusterIntegration|Google Kubernetes Engine project" -msgstr "Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Helm Tiller" +msgstr "" + +msgid "ClusterIntegration|Inactive" +msgstr "" + +msgid "ClusterIntegration|Ingress" +msgstr "" + +msgid "ClusterIntegration|Install" +msgstr "" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "" + +msgid "ClusterIntegration|Installed" +msgstr "" + +msgid "ClusterIntegration|Installing" +msgstr "" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "" msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "En savoir plus sur %{link_to_documentation}" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "" + msgid "ClusterIntegration|Machine type" msgstr "Type de machine" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" msgstr "Assurez-vous que votre compte %{link_to_requirements} pour créer des clusters" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" -msgstr "Gérer l’intégration du cluster sur votre projet GitLab" +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" +msgstr "" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" msgstr "Gérer votre cluster en visitant le lien %{link_gke}" +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "" + +msgid "ClusterIntegration|Note:" +msgstr "" + msgid "ClusterIntegration|Number of nodes" msgstr "Nombre de nœuds" +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" +msgstr "" + msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgstr "Veuillez vous assurer que votre compte Google répond aux exigences suivantes : " +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "" + +msgid "ClusterIntegration|Project ID" +msgstr "" + +msgid "ClusterIntegration|Project namespace" +msgstr "" + msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "Espace de noms du projet (facultatif, unique)" @@ -567,8 +717,14 @@ msgstr "Retirer l’intégration du cluster" msgid "ClusterIntegration|Remove integration" msgstr "Retirer l’intégration" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." -msgstr "Supprimer l'intégration du cluster supprimera sa configuration que vous avez ajoutée pour ce projet. Cela ne supprimera pas votre projet." +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "" + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "" + +msgid "ClusterIntegration|Save changes" +msgstr "" msgid "ClusterIntegration|See and edit the details for your cluster" msgstr "Voir et modifier les détails de votre cluster" @@ -582,33 +738,57 @@ msgstr "Voir vos projets" msgid "ClusterIntegration|See zones" msgstr "Voir les zones" +msgid "ClusterIntegration|Service token" +msgstr "" + +msgid "ClusterIntegration|Show" +msgstr "" + msgid "ClusterIntegration|Something went wrong on our end." msgstr "Un problème est survenu de notre côté." msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" -msgstr "Un problème est survenu lors de la création de votre cluster sur Google Kubernetes Engine." +msgstr "" + +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "" msgid "ClusterIntegration|Toggle Cluster" msgstr "Activer/désactiver le cluster" +msgid "ClusterIntegration|Token" +msgstr "" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "Avec un cluster associé à ce projet, vous pouvez utiliser des applications de revue, déployer vos applications, exécuter vos pipelines et bien plus encore, de manière très simple." msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}" -msgstr "Votre compte doit disposer de %{link_to_kubernetes_engine}" +msgstr "" msgid "ClusterIntegration|Zone" msgstr "Zone" msgid "ClusterIntegration|access to Google Kubernetes Engine" -msgstr "Accéder à Google Kubernetes Engine" +msgstr "" msgid "ClusterIntegration|cluster" msgstr "cluster" +msgid "ClusterIntegration|documentation" +msgstr "" + msgid "ClusterIntegration|help page" msgstr "page d’aide" +msgid "ClusterIntegration|installing applications" +msgstr "" + msgid "ClusterIntegration|meets the requirements" msgstr "répond aux exigences" @@ -623,11 +803,6 @@ msgid_plural "Commits" msgstr[0] "Validation" msgstr[1] "Validations" -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "Valider %d fichier" -msgstr[1] "Valider %d fichiers" - msgid "Commit Message" msgstr "Message de validation" @@ -709,11 +884,20 @@ msgstr "Guide de contribution" msgid "Contributors" msgstr "Contributeurs" +msgid "ContributorsPage|Building repository graph." +msgstr "" + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "" + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "" + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" -msgstr "Contrôler la concurrence maximale des remplacements de fichier-joint LFS pour ce nœud secondaire" +msgstr "" msgid "Control the maximum concurrency of repository backfill for this secondary node" -msgstr "Contrôler la concurrence maximale des remplacements de dépôt pour ce nœud secondaire" +msgstr "" msgid "Copy SSH public key to clipboard" msgstr "Copier la clé publique SSH dans le presse-papier" @@ -736,6 +920,9 @@ msgstr "Créer un dossier" msgid "Create empty bare repository" msgstr "Créer un dépôt vide" +msgid "Create epic" +msgstr "" + msgid "Create file" msgstr "Créer un fichier" @@ -763,6 +950,9 @@ msgstr "Tag" msgid "CreateTokenToCloneLink|create a personal access token" msgstr "Créer un jeton d'accès personnel" +msgid "Creating epic" +msgstr "" + msgid "Cron Timezone" msgstr "Fuseau horaire de Cron" @@ -808,6 +998,12 @@ msgstr "Tous" msgid "DashboardProjects|Personal" msgstr "Personnels" +msgid "Dec" +msgstr "Déc." + +msgid "December" +msgstr "Décembre" + msgid "Define a custom pattern with cron syntax" msgstr "Définir un schéma personnalisé avec une syntaxe Cron" @@ -882,6 +1078,72 @@ msgstr "Éditer le pipeline programmé %{id}" msgid "Emails" msgstr "Courriels" +msgid "Environments|An error occurred while fetching the environments." +msgstr "Une erreur s‘est produite lors de la récupération des environnements." + +msgid "Environments|An error occurred while making the request." +msgstr "Une erreur s’est produite lors de la requête." + +msgid "Environments|Commit" +msgstr "Validation" + +msgid "Environments|Deployment" +msgstr "Déploiement" + +msgid "Environments|Environment" +msgstr "Environnement" + +msgid "Environments|Environments" +msgstr "Environnements" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "Les environnements sont des lieux où le code est déployé, comme staging ou production." + +msgid "Environments|Job" +msgstr "Tâche" + +msgid "Environments|New environment" +msgstr "Nouvel environnement" + +msgid "Environments|No deployments yet" +msgstr "Aucun déploiement pour le moment" + +msgid "Environments|Open" +msgstr "Ouvert" + +msgid "Environments|Re-deploy" +msgstr "Re-déployer" + +msgid "Environments|Read more about environments" +msgstr "En savoir plus sur les environnements" + +msgid "Environments|Rollback" +msgstr "Revenir en arrière" + +msgid "Environments|Show all" +msgstr "Afficher tous" + +msgid "Environments|Updated" +msgstr "Mise à jour" + +msgid "Environments|You don't have any environments right now." +msgstr "Vous n’avez aucun environnement pour le moment." + +msgid "Epic will be removed! Are you sure?" +msgstr "" + +msgid "Epics" +msgstr "" + +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" +msgstr "" + +msgid "Error creating epic" +msgstr "" + +msgid "Error occurred when toggling the notification subscription" +msgstr "Une erreur s’est produite lors de l’activation/désactivation de l’abonnement aux notifications" + msgid "EventFilterBy|Filter by all" msgstr "Aucun filtre" @@ -921,6 +1183,12 @@ msgstr "Échec du changement de propriétaire" msgid "Failed to remove the pipeline schedule" msgstr "Échec de la suppression du pipeline programmé" +msgid "Feb" +msgstr "Févr." + +msgid "February" +msgstr "Février" + msgid "File name" msgstr "Nom du fichier" @@ -968,6 +1236,21 @@ msgstr "Clés GPG" msgid "Geo Nodes" msgstr "Nœuds Geo" +msgid "GeoNodeSyncStatus|Failed" +msgstr "Échec" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "Le nœud est défaillant ou cassé." + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "Le nœud est lent, surchargé, ou il vient juste de récupérer après un problème." + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "Désynchronisé" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "Synchronisé" + msgid "Geo|File sync capacity" msgstr "Capacité de synchronisation de fichier" @@ -1031,9 +1314,6 @@ msgstr "Aucun groupe trouvé" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "Vous pouvez gérer les autorisations des membres de votre groupe et accéder à chacun de ses projets." -msgid "GroupsTreeRole|as" -msgstr "comme" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "Êtes-vous sûr·e de vouloir quitter le groupe « ${this.group.fullName} » ?" @@ -1064,6 +1344,9 @@ msgstr "Désolé, aucun groupe ne correspond à vos critères de recherche" msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "Désolé, aucun groupe ni projet ne correspond à vos critères de recherche" +msgid "Have your users email" +msgstr "" + msgid "Health Check" msgstr "État des services" @@ -1092,7 +1375,7 @@ msgid "Import repository" msgstr "Importer un dépôt" msgid "Improve Issue boards with GitLab Enterprise Edition." -msgstr "Améliorer le tableau de tickets avec GitLab Entreprise Edition." +msgstr "Améliorer les tableaux de tickets avec Gitlab Entreprise Edition." msgid "Improve issues management with Issue weight and GitLab Enterprise Edition." msgstr "Améliorer la gestion des tickets avec les poids de ticket et GitLab Entreprise Edition." @@ -1123,9 +1406,6 @@ msgstr "Introduction à l'analyseur de cycle" msgid "Issue board focus mode" msgstr "Mode focus du tableau de tickets" -msgid "Issue boards with milestones" -msgstr "Tableaux des tickets avec leurs jalons" - msgid "Issue events" msgstr "Événements du ticket" @@ -1138,6 +1418,24 @@ msgstr "Tableaux" msgid "Issues" msgstr "Tickets" +msgid "Jan" +msgstr "Janv." + +msgid "January" +msgstr "Janvier" + +msgid "Jul" +msgstr "Juill." + +msgid "July" +msgstr "Juillet" + +msgid "Jun" +msgstr "Juin" + +msgid "June" +msgstr "Juin" + msgid "LFSStatus|Disabled" msgstr "Désactivé" @@ -1211,9 +1509,18 @@ msgstr "Fichiers verrouillés" msgid "Login" msgstr "Se connecter" +msgid "Mar" +msgstr "Mars" + +msgid "March" +msgstr "Mars" + msgid "Maximum git storage failures" msgstr "Nombre maximum d’échecs du stockage git" +msgid "May" +msgstr "Mai" + msgid "Median" msgstr "Médian" @@ -1258,9 +1565,15 @@ msgstr "Nouveau pipeline programmé" msgid "New branch" msgstr "Nouvelle branche" +msgid "New branch unavailable" +msgstr "Nouvelle branche indisponible" + msgid "New directory" msgstr "Nouveau dossier" +msgid "New epic" +msgstr "" + msgid "New file" msgstr "Nouveau fichier" @@ -1297,6 +1610,9 @@ msgstr "Pas de dépôt" msgid "No schedules" msgstr "Aucun programme" +msgid "No time spent" +msgstr "Pas de temps passé" + msgid "None" msgstr "Aucun·e" @@ -1363,18 +1679,33 @@ msgstr "Surveillé" msgid "Notifications" msgstr "Notifications" +msgid "Nov" +msgstr "Nov." + +msgid "November" +msgstr "Novembre" + msgid "Number of access attempts" msgstr "Nombre de tentatives d'accès" msgid "Number of failures before backing off" msgstr "Nombre d'échecs avant annulation" +msgid "Oct" +msgstr "Oct." + +msgid "October" +msgstr "Octobre" + msgid "OfSearchInADropdown|Filter" msgstr "Filtre" msgid "Only project members can comment." msgstr "Seuls les membres du projet peuvent commenter." +msgid "Opened" +msgstr "Ouvert" + msgid "OpenedNDaysAgo|Opened" msgstr "Ouvert" @@ -1507,6 +1838,9 @@ msgstr "avec l'étape" msgid "Pipeline|with stages" msgstr "avec les étapes" +msgid "Please solve the reCAPTCHA" +msgstr "Veuillez résoudre le reCAPTCHA" + msgid "Preferences" msgstr "Préférences" @@ -1612,9 +1946,15 @@ msgstr "Graphes" msgid "ProjectSettings|Contact an admin to change this setting." msgstr "Contactez un administrateur pour modifier ce paramètre." +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "Exécuter immédiatement un pipeline sur la branche par défaut" + msgid "ProjectSettings|Only signed commits can be pushed to this repository." msgstr "Seules les validations signées peuvent être poussées sur ce dépôt." +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "Problème lors de la configuration des paramètres CI/CD JavaScript" + msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." msgstr "Ce paramètre est appliqué au niveau du serveur et peut être modifié par un administrateur." @@ -1622,7 +1962,7 @@ msgid "ProjectSettings|This setting is applied on the server level but has been msgstr "Ce paramètre est appliqué au niveau du serveur mais il a été modifié pour ce projet." msgid "ProjectSettings|This setting will be applied to all projects unless overridden by an admin." -msgstr "Ce paramètre s’appliquera à tous les projets à moins qu’un administrateur ne le modifie." +msgstr "Ce paramètre s’appliquera à tous les projets à moins qu’un•e administrat•eur•rice ne le modifie." msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails." msgstr "Les utilisateurs peuvent uniquement pousser sur ce dépôt des validations qui ont été validées avec une de leurs adresses courriels vérifiées." @@ -1651,6 +1991,39 @@ msgstr "Désolé, aucun projet ne correspond à votre recherche" msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "Cette fonctionnalité requiert le support du localStorage par votre navigateur" +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "" + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "" + +msgid "PrometheusService|Metrics" +msgstr "" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "" + +msgid "PrometheusService|Missing environment variable" +msgstr "" + +msgid "PrometheusService|Monitored" +msgstr "" + +msgid "PrometheusService|More information" +msgstr "" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "" + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" +msgstr "" + +msgid "PrometheusService|Prometheus monitoring" +msgstr "" + +msgid "PrometheusService|View environments" +msgstr "" + msgid "Public - The group and any public projects can be viewed without any authentication." msgstr "Public - Le groupe ainsi que n’importe quel projet public est accessible sans authentification." @@ -1747,6 +2120,9 @@ msgstr "Programmes" msgid "Scheduling Pipelines" msgstr "Programmer des pipelines" +msgid "Scoped issue boards" +msgstr "" + msgid "Search branches and tags" msgstr "Rechercher dans les branches et les étiquettes" @@ -1768,6 +2144,12 @@ msgstr "Sélectionnez un fuseau horaire" msgid "Select target branch" msgstr "Sélectionnez une branche cible" +msgid "Sep" +msgstr "Sept." + +msgid "September" +msgstr "Septembre" + msgid "Service Templates" msgstr "Modèles de service" @@ -1800,14 +2182,29 @@ msgid_plural "Showing %d events" msgstr[0] "Affichage de %d évènement" msgstr[1] "Affichage de %d évènements" +msgid "Sidebar|Change weight" +msgstr "Changer le poids" + +msgid "Sidebar|Edit" +msgstr "Modifier" + +msgid "Sidebar|No" +msgstr "Non" + +msgid "Sidebar|None" +msgstr "Aucun" + +msgid "Sidebar|Weight" +msgstr "Poids" + msgid "Snippets" msgstr "Extraits de code" msgid "Something went wrong on our end." msgstr "Une erreur est survenue de notre côté." -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" -msgstr "Quelque chose ne s'est pas bien passé en essayant de changer l’état de verrouillage de cet ${this.issuableDisplayName(this.issuableType)}" +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" +msgstr "Quelque chose ne s‘est pas bien passé en essayant de changer l’état de verrouillage de cette ${this.issuableDisplayName}" msgid "Something went wrong while fetching the projects." msgstr "Une erreur s'est produite lors de la récupération des projets." @@ -1914,9 +2311,15 @@ msgstr "Commence bientôt" msgid "SortOptions|Weight" msgstr "Poids" +msgid "Source" +msgstr "Source" + msgid "Source code" msgstr "Code source" +msgid "Source is not available" +msgstr "" + msgid "Spam Logs" msgstr "Journaux des messages indésirables" @@ -1935,6 +2338,9 @@ msgstr "Créer une %{new_merge_request} avec ces changements" msgid "Start the Runner!" msgstr "Démarrer l'Exécuteur !" +msgid "Stopped" +msgstr "Arrêté" + msgid "Subgroups" msgstr "Sous-groupes" @@ -1955,6 +2361,75 @@ msgstr[1] "Tags" msgid "Tags" msgstr "Tags" +msgid "TagsPage|Browse commits" +msgstr "Parcourir les validations" + +msgid "TagsPage|Browse files" +msgstr "Parcourir les fichiers" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "Impossible de trouver la validation HEAD pour ce tag" + +msgid "TagsPage|Cancel" +msgstr "Annuler" + +msgid "TagsPage|Create tag" +msgstr "Créer le tag" + +msgid "TagsPage|Delete tag" +msgstr "Supprimer le tag" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "La suppression du tag %{tag_name} ne peut être annulée. Êtes-vous sûr•e ?" + +msgid "TagsPage|Edit release notes" +msgstr "Modifier les notes de version" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "Nom de branche, tag, ou SHA de validation existant" + +msgid "TagsPage|Filter by tag name" +msgstr "Filtrer par nom de tag" + +msgid "TagsPage|New Tag" +msgstr "Nouveau tag" + +msgid "TagsPage|New tag" +msgstr "Nouveau tag" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "Éventuellement, ajoutez un message au tag." + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "Éventuellement, ajouter des notes de version pour le tag. Elles seront stockées dans la base de données de GitLab et affichées sur la page des tags." + +msgid "TagsPage|Release notes" +msgstr "Notes de version" + +msgid "TagsPage|Repository has no tags yet." +msgstr "Le dépôt n‘a pas de tags pour le moment." + +msgid "TagsPage|Sort by" +msgstr "Trier par" + +msgid "TagsPage|Tags" +msgstr "Tags" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "Les tags permettent de marquer des validations spécifiques commes importantes dans l‘historique du project" + +msgid "TagsPage|This tag has no release notes." +msgstr "Ce tag n‘a pas de notes de version." + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "Utilisez la commande git tag pour en ajouter un nouveau :" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "Écrivez les notes de version ou faîtes glisser des fichiers ici…" + +msgid "TagsPage|protected" +msgstr "protégé" + msgid "Target Branch" msgstr "Branche cible" @@ -1962,10 +2437,10 @@ msgid "Team" msgstr "Équipe" msgid "Thanks! Don't show me this again" -msgstr "Merci de ne plus afficher ce message" +msgstr "Merci ! Ne plus afficher ce message" msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project." -msgstr "La Recherche Globale Avancée de GitLab est un outils qui vous fait gagner du temps. Au lieu de créer du code similaire et perdre du temps, vous pouvez maintenant chercher dans le code d'autres équipes pour vous aider sur votre projet." +msgstr "La Recherche Globale Avancée de Gitlab est un outils puissant qui vous fait gagner du temps. Au lieu de créer du code similaire et perdre du temps, vous pouvez maintenant chercher dans le code d'autres équipes pour vous aider sur votre projet." msgid "The circuitbreaker backoff threshold should be lower than the failure count threshold" msgstr "Le seuil d’interruption du disjoncteur devrait être inférieur au seuil de nombre de défaillance" @@ -2036,6 +2511,9 @@ msgstr "La valeur située au point médian d’une série de valeur observée. C msgid "There are problems accessing Git storage: " msgstr "Il y a des difficultés à accéder aux données Git : " +msgid "This board\\'s scope is reduced" +msgstr "" + msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "Cette branche a changé depuis le début de l’édition. Souhaitez-vous créer une nouvelle branche ?" @@ -2057,6 +2535,9 @@ msgstr "Cela signifie que vous ne pouvez pas pousser du code tant que vous n’a msgid "This merge request is locked." msgstr "Cette demande de fusion est verrouillée." +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "Temps avant qu’un ticket ne soit planifié" @@ -2205,15 +2686,27 @@ msgstr[1] "mins" msgid "Time|s" msgstr "s" +msgid "Title" +msgstr "Titre" + msgid "Total Time" msgstr "Temps total" +msgid "Total issue time spent" +msgstr "Temps total passé sur les tickets" + msgid "Total test time for all commits/merges" msgstr "Temps total de test pour toutes les validations/fusions" msgid "Track activity with Contribution Analytics." msgstr "Suivre l’activité avec Contribution Analytics." +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "" + +msgid "Turn on Service Desk" +msgstr "" + msgid "Unlock" msgstr "Déverrouiller" @@ -2239,7 +2732,7 @@ msgid "Upgrade your plan to activate Issue weight." msgstr "Mettez à niveau votre abonnement pour activer les poids de ticket." msgid "Upgrade your plan to improve Issue boards." -msgstr "Mettez à niveau votre abonnement pour améliorer les tableaux de tickets." +msgstr "Mettez à niveau votre forfait pour améliorer les tableaux de tickets." msgid "Upload New File" msgstr "Téléverser un nouveau fichier" @@ -2250,6 +2743,9 @@ msgstr "Téléverser un fichier" msgid "UploadLink|click to upload" msgstr "Cliquez pour envoyer" +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "" + msgid "Use the following registration token during setup:" msgstr "Utiliser le jeton d’inscription suivant pendant l’installation :" @@ -2283,6 +2779,9 @@ msgstr "Vous voulez voir les données ? Merci de contacter un administrateur pou msgid "We don't have enough data to show this stage." msgstr "Nous n'avons pas suffisamment de données pour afficher cette étape." +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "" + msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." msgstr "Les webhooks vous permettent d’appeler une URL si, par exemple, du nouveau code est poussé ou un nouveau ticket est créé. Vous pouvez configurer les webhooks pour écouter les événements spécifiques comme des poussées de code, des tickets ou des demandes de fusion. Les webhooks de groupes s’appliqueront à tous les projets dans un groupe, ce qui vous permet de normaliser la fonctionnalité du webhook dans votre groupe entier." @@ -2412,12 +2911,6 @@ msgstr "Vous allez supprimer la relation de fourche avec le projet source %{fork msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "Vous allez transférer %{project_name_with_namespace} à un nouveau propriétaire. Êtes vous ABSOLUMENT sûr·e ?" -msgid "You are on a read-only GitLab instance." -msgstr "Vous êtes sur une instance GitLab en lecture seule." - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "Vous êtes sur une instance GitLab en lecture seule. Si vous souhaitez apporter des modifications, vous devez aller sur %{link_to_primary_node}." - msgid "You can only add files when you are on a branch" msgstr "Vous ne pouvez ajouter de fichier que dans une branche" @@ -2457,6 +2950,9 @@ msgstr "Vous ne pourrez pas récupérer ou pousser de code par %{protocol} tant msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" msgstr "Vous ne pourrez pas récupérer ou pousser de code par SSH tant que vous n’aurez pas %{add_ssh_key_link} dans votre profil" +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "Vous ne pourrez pas récupérer ou pousser de code par SSH tant que vous n’aurez pas ajouté de clé SSH à votre profil" + msgid "Your comment will not be visible to the public." msgstr "Votre commentaire ne sera pas visible publiquement." @@ -2469,6 +2965,12 @@ msgstr "Votre nom" msgid "Your projects" msgstr "Vos projets" +msgid "branch name" +msgstr "nom de la branche" + +msgid "by" +msgstr "par" + msgid "commit" msgstr "validation" @@ -2494,6 +2996,9 @@ msgstr "mot de passe" msgid "personal access token" msgstr "jeton d’accès personnel" +msgid "source" +msgstr "source" + msgid "to help your contributors communicate effectively!" msgstr "pour aider vos contributeurs à communiquer efficacement !" diff --git a/locale/it/gitlab.po b/locale/it/gitlab.po index 8a987129452..52bbc28ac10 100644 --- a/locale/it/gitlab.po +++ b/locale/it/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-20 03:59-0500\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 04:42-0500\n" "Last-Translator: gitlab \n" "Language-Team: Italian\n" "Language: it_IT\n" @@ -18,13 +18,13 @@ msgstr "" msgid "%d commit" msgid_plural "%d commits" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d commit" +msgstr[1] "%d commits" msgid "%d layer" msgid_plural "%d layers" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%d livello" +msgstr[1] "%d livelli" msgid "%s additional commit has been omitted to prevent performance issues." msgid_plural "%s additional commits have been omitted to prevent performance issues." @@ -36,45 +36,48 @@ msgstr "%{commit_author_link} ha committato %{commit_timeago}" msgid "%{count} participant" msgid_plural "%{count} participants" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%{count} partecipante" +msgstr[1] "%{count} partecipanti" msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead" -msgstr "" +msgstr "%{number_commits_behind} commits precedenti %{default_branch}, %{number_commits_ahead} commits avanti" msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will allow access on the next attempt." -msgstr "" +msgstr "%{number_of_failures} di %{maximum_failures} fallimenti. GitLab consentirà l'accesso al prossimo tentativo." msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will block access for %{number_of_seconds} seconds." -msgstr "" +msgstr "%{number_of_failures} di %{maximum_failures} fallimenti. Gitlab bloccherà l'accesso per %{number_of_seconds} secondi." msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved." -msgstr "" +msgstr "%{number_of_failures} di %{maximum_failures} fallimenti. Gitlab non ritenterà automaticamente. Ripristina l'informazioni d'archiviazione quando il problema è risolto." msgid "%{storage_name}: failed storage access attempt on host:" msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "%{storage_name}: tentativo d'accesso all'archiviazione fallito da parte dell'host:" +msgstr[1] "%{storage_name}: %{failed_attempts} tentativi d'accesso all'archiviazione falliti:" + +msgid "%{text} is available" +msgstr "%{text} è disponibile" msgid "(checkout the %{link} for information on how to install it)." -msgstr "" +msgstr "(vedi il %{link} su come installarlo)." msgid "+ %{moreCount} more" -msgstr "" +msgstr "+ %{moreCount} più" msgid "- show less" -msgstr "" +msgstr "- riduci" msgid "1 pipeline" msgid_plural "%d pipelines" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "1 pipeline" +msgstr[1] "%d pipeline" msgid "1st contribution!" -msgstr "" +msgstr "Primo contributo!" msgid "2FA enabled" -msgstr "" +msgstr "2FA abilitata" msgid "A collection of graphs regarding Continuous Integration" msgstr "Un insieme di grafici riguardo la Continuous Integration" @@ -83,16 +86,16 @@ msgid "About auto deploy" msgstr "Riguardo il rilascio automatico" msgid "Abuse Reports" -msgstr "" +msgstr "Segnalazioni di abuso" msgid "Access Tokens" -msgstr "" +msgstr "Token di accesso" msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again." -msgstr "" +msgstr "L'accesso agli storages è stato temporaneamente disabilitato per consentire il mount di ripristino. Resetta le info d'archiviazione dopo che l'issue è stato risolto per consentire nuovamente l'accesso." msgid "Account" -msgstr "" +msgstr "Account" msgid "Active" msgstr "Attivo" @@ -115,29 +118,41 @@ msgstr "" msgid "Add License" msgstr "Aggiungi Licenza" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "Aggiungi una chiave SSH al tuo profilo per eseguire pull o push tramite SSH" - msgid "Add new directory" msgstr "Aggiungi una directory (cartella)" msgid "AdminHealthPageLink|health page" -msgstr "" +msgstr "Pagina di stato" msgid "Advanced settings" -msgstr "" +msgstr "Impostazioni Avanzate" msgid "All" +msgstr "Tutto" + +msgid "An error occurred when toggling the notification subscription" +msgstr "Errore durante l'attivazione/disattivazione della sottoscrizione per l'iscrizione" + +msgid "An error occurred when updating the issue weight" msgstr "" +msgid "An error occurred while fetching sidebar data" +msgstr "Errore durante il recupero dei dati della barra laterale" + msgid "An error occurred. Please try again." -msgstr "" +msgstr "Si è verificato un errore. Riprova." msgid "Appearance" -msgstr "" +msgstr "Aspetto" msgid "Applications" -msgstr "" +msgstr "Applicazioni" + +msgid "Apr" +msgstr "Apr" + +msgid "April" +msgstr "Aprile" msgid "Archived project! Repository is read-only" msgstr "Progetto archiviato! La Repository è sola-lettura" @@ -146,58 +161,67 @@ msgid "Are you sure you want to delete this pipeline schedule?" msgstr "Sei sicuro di voler cancellare questa pipeline programmata?" msgid "Are you sure you want to discard your changes?" -msgstr "" +msgstr "Vuoi davvero ignorare le modifiche?" msgid "Are you sure you want to leave this group?" -msgstr "" +msgstr "Vuoi davvero lasciare questo gruppo?" msgid "Are you sure you want to reset registration token?" -msgstr "" +msgstr "Sei sicuro di voler ripristinare il token di registrazione?" msgid "Are you sure you want to reset the health check token?" -msgstr "" +msgstr "Confermi di voler resettare il token di controllo di stato?" msgid "Are you sure?" -msgstr "" +msgstr "Sei sicuro?" msgid "Artifacts" -msgstr "" +msgstr "Artefatti" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "Aggiungi un file tramite trascina & rilascia ( drag & drop) o %{upload_link}" +msgid "Aug" +msgstr "Ago" + +msgid "August" +msgstr "Agosto" + msgid "Authentication Log" -msgstr "" +msgstr "Log di autenticazione" msgid "Author" -msgstr "" +msgstr "Autore" msgid "Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly." -msgstr "" +msgstr "Le app d'auto-review e l'Auto Deploy (rilascio automatico) necessita di un nome dominio e il servizio %{kubernetes} per funzionare correttamente." msgid "Auto Review Apps and Auto Deploy need a domain name to work correctly." -msgstr "" +msgstr "Le app d'auto-review e l'Auto Deploy (rilascio automatico) necessita di un nome dominio per funzionare correttamente." msgid "Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly." -msgstr "" +msgstr "Le app d'auto-review e l'Auto Deploy (rilascio automatico) necessita del servizio %{kubernetes} per funzionare correttamente." msgid "AutoDevOps|Auto DevOps (Beta)" -msgstr "" +msgstr "Auto DevOps (Béta)" msgid "AutoDevOps|Auto DevOps documentation" -msgstr "" +msgstr "Documentazione Auto DevOps" msgid "AutoDevOps|Enable in settings" -msgstr "" +msgstr "Attiva in impostazioni" msgid "AutoDevOps|It will automatically build, test, and deploy your application based on a predefined CI/CD configuration." -msgstr "" +msgstr "Farà automaticamente le build, i test e i rilasci della tua applicazione basato sulla tua configurazione CI/CD." msgid "AutoDevOps|Learn more in the %{link_to_documentation}" -msgstr "" +msgstr "Approfondisci: %{link_to_documentation}" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." -msgstr "" +msgstr "Puoi attivare %{link_to_settings} per questo progetto." + +msgid "Available" +msgstr "Disponibile" msgid "Billing" msgstr "" @@ -262,7 +286,13 @@ msgid "Branch %{branch_name} was created. To set up auto deploy msgstr "La branch %{branch_name} è stata creata. Per impostare un rilascio automatico scegli un template CI di Gitlab e committa le tue modifiche %{link_to_autodeploy_doc}" msgid "Branch has changed" -msgstr "" +msgstr "La branche è cambiata" + +msgid "Branch is already taken" +msgstr "La Branch esiste già" + +msgid "Branch name" +msgstr "Nome Branch" msgid "BranchSwitcherPlaceholder|Search branches" msgstr "Cerca branches" @@ -271,91 +301,91 @@ msgid "BranchSwitcherTitle|Switch branch" msgstr "Cambia branch" msgid "Branches" -msgstr "" +msgstr "Branch" msgid "Branches|Cant find HEAD commit for this branch" -msgstr "" +msgstr "Impossibile trovare l'HEAD commit per questa branch" msgid "Branches|Compare" -msgstr "" +msgstr "Confronta" msgid "Branches|Delete all branches that are merged into '%{default_branch}'" -msgstr "" +msgstr "Elimina tutte le branches che sono state mergiate in '%{default_branch}'" msgid "Branches|Delete branch" -msgstr "" +msgstr "Elimina Branch" msgid "Branches|Delete merged branches" -msgstr "" +msgstr "Elimina branch mergiate" msgid "Branches|Delete protected branch" -msgstr "" +msgstr "Elimina la branch protetta" msgid "Branches|Delete protected branch '%{branch_name}'?" -msgstr "" +msgstr "Eliminare la branch protetta %{branch_name}?" msgid "Branches|Deleting the '%{branch_name}' branch cannot be undone. Are you sure?" -msgstr "" +msgstr "Eliminando la branch %{branch_name} è un'operazione irreversibile. Sicuro di voler procedere?" msgid "Branches|Deleting the merged branches cannot be undone. Are you sure?" -msgstr "" +msgstr "Eliminare le branch mergiate è un'operazione irreversibile. Sicuro di voler procedere?" msgid "Branches|Filter by branch name" -msgstr "" +msgstr "Filtra per nome branch" msgid "Branches|Merged into %{default_branch}" -msgstr "" +msgstr "Mergiata in %{default_branch}" msgid "Branches|New branch" -msgstr "" +msgstr "Nuova branch" msgid "Branches|No branches to show" -msgstr "" +msgstr "Nessuna branch da mostrare" msgid "Branches|Once you confirm and press %{delete_protected_branch}, it cannot be undone or recovered." -msgstr "" +msgstr "Una volta confermato e premuto %{delete_protected_branch} non sarà possibile ripristinare allo stato precedente." msgid "Branches|Only a project master or owner can delete a protected branch" -msgstr "" +msgstr "Solo gli Owner e i Master possono eliminare una branch protetta" msgid "Branches|Protected branches can be managed in %{project_settings_link}" -msgstr "" +msgstr "Le branch protette possono esser gestite in %{project_settings_link}" msgid "Branches|Sort by" -msgstr "" +msgstr "Ordina per" msgid "Branches|The branch could not be updated automatically because it has diverged from its upstream counterpart." msgstr "" msgid "Branches|The default branch cannot be deleted" -msgstr "" +msgstr "La branch predefinita non può esser eliminata" msgid "Branches|This branch hasn’t been merged into %{default_branch}." -msgstr "" +msgstr "Questa branch non è stata mergiata in %{default_branch}." msgid "Branches|To avoid data loss, consider merging this branch before deleting it." -msgstr "" +msgstr "Per evitare perdita di dati considera di mergiare questa branch prima di eliminarla." msgid "Branches|To confirm, type %{branch_name_confirmation}:" -msgstr "" +msgstr "Per confermare, scrivi %{branch_name_confirmation}:" msgid "Branches|To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above." msgstr "" msgid "Branches|You’re about to permanently delete the protected branch %{branch_name}." -msgstr "" +msgstr "Stai per eliminare la branch protetta (%{branch_name}) in maniera permanente." msgid "Branches|diverged from upstream" msgstr "" msgid "Branches|merged" -msgstr "" +msgstr "mergiata" msgid "Branches|project settings" -msgstr "" +msgstr "Impostazioni" msgid "Branches|protected" -msgstr "" +msgstr "Protetta" msgid "Browse Directory" msgstr "Naviga direttori" @@ -373,19 +403,19 @@ msgid "ByAuthor|by" msgstr "per" msgid "CI / CD" -msgstr "" +msgstr "CI / CD" msgid "CI configuration" msgstr "Configurazione CI (Integrazione Continua)" msgid "CICD|Jobs" -msgstr "" +msgstr "Jobs" msgid "Cancel" msgstr "Cancella" msgid "Cancel edit" -msgstr "" +msgstr "Annulla modifica" msgid "Change Weight" msgstr "" @@ -403,16 +433,22 @@ msgid "ChangeTypeAction|Revert" msgstr "Ripristina" msgid "Changelog" -msgstr "" +msgstr "Changelog" msgid "Charts" msgstr "Grafici" msgid "Chat" -msgstr "" +msgstr "Chat" + +msgid "Checking %{text} availability…" +msgstr "Controllo disponibilità per %{text}…" + +msgid "Checking branch availability..." +msgstr "Controllo disponibilità branch..." msgid "Cherry-pick this commit" -msgstr "" +msgstr "Cherry-pick di questo commit" msgid "Cherry-pick this merge request" msgstr "Cherry-pick questa richiesta di merge" @@ -475,58 +511,124 @@ msgid "CiStatus|running" msgstr "in corso" msgid "CircuitBreakerApiLink|circuitbreaker api" -msgstr "" +msgstr "api circuitbreaker" msgid "Clone repository" -msgstr "" +msgstr "Clona repository" msgid "Close" msgstr "" msgid "Cluster" -msgstr "" +msgstr "Cluster" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" -msgstr "" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "%{appList} è stata installata con successo nel tuo cluster" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "%{boldNotice} Ciò richiederà delle risorse extra come un load balancer, dove si applicheranno costi aggiuntivi. Consulta %{pricingLink}" + +msgid "ClusterIntegration|API URL" +msgstr "API URL" + +msgid "ClusterIntegration|Active" +msgstr "Attivo" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "Aggiungi un cluster esistente" + +msgid "ClusterIntegration|Add cluster" +msgstr "Aggiungi cluster" + +msgid "ClusterIntegration|All" +msgstr "Tutti" + +msgid "ClusterIntegration|Applications" +msgstr "Applicazioni" + +msgid "ClusterIntegration|CA Certificate" +msgstr "Certificato CA" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "Certificate Authority bundle (formato PEM)" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "Scegli come impostare l'integrazione cluster" + +msgid "ClusterIntegration|Cluster" +msgstr "Cluster" msgid "ClusterIntegration|Cluster details" -msgstr "" +msgstr "Dettagli Cluster" msgid "ClusterIntegration|Cluster integration" -msgstr "" +msgstr "Integrazione Cluster" msgid "ClusterIntegration|Cluster integration is disabled for this project." -msgstr "" +msgstr "L'integrazione dei cluster è disabilitata per questo progetto." msgid "ClusterIntegration|Cluster integration is enabled for this project." -msgstr "" +msgstr "L'integrazione dei cluster è abilitata per questo progetto." msgid "ClusterIntegration|Cluster integration is enabled for this project. Disabling this integration will not affect your cluster, it will only temporarily turn off GitLab's connection to it." -msgstr "" +msgstr "L'integrazione dei cluster è abilitata per questo progetto. Se la disabiliti il tuo cluster non sarà modificato, sarà solo spenta la connessione a Gitlab." msgid "ClusterIntegration|Cluster is being created on Google Kubernetes Engine..." msgstr "" msgid "ClusterIntegration|Cluster name" -msgstr "" +msgstr "Nome Cluster" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" msgstr "" +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "I cluster di consentono di revisionare le app, effettuare rilasci, eseguire pipelines, e molto altro in modo semplice. %{link_to_help_page}" + +msgid "ClusterIntegration|Copy API URL" +msgstr "Copia URL API" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "Copia Certificato CA" + +msgid "ClusterIntegration|Copy Token" +msgstr "Copia Token" + msgid "ClusterIntegration|Copy cluster name" -msgstr "" +msgstr "Copia nome del cluster" + +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "Crea un nuovo cluster su Google Engine direttamente da Gitlab" msgid "ClusterIntegration|Create cluster" -msgstr "" +msgstr "Crea cluster" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" msgstr "" +msgid "ClusterIntegration|Create on GKE" +msgstr "Crea su GKE" + msgid "ClusterIntegration|Enable cluster integration" -msgstr "" +msgstr "Abilita integrazione cluster" + +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "Inserisci i dettagli per un cluster Kubernetes esistente" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "Inserisci i dettagli per il tuo cluster" + +msgid "ClusterIntegration|Environment pattern" +msgstr "Environment pattern" + +msgid "ClusterIntegration|GKE pricing" +msgstr "Prezzi GKE" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "Gitlab Runner" msgid "ClusterIntegration|Google Cloud Platform project ID" -msgstr "" +msgstr "ID Progetto di Google Cloud Platform" msgid "ClusterIntegration|Google Kubernetes Engine" msgstr "" @@ -534,27 +636,75 @@ msgstr "" msgid "ClusterIntegration|Google Kubernetes Engine project" msgstr "" +msgid "ClusterIntegration|Helm Tiller" +msgstr "Helm Tiller" + +msgid "ClusterIntegration|Inactive" +msgstr "Inattivo" + +msgid "ClusterIntegration|Ingress" +msgstr "Ingresso" + +msgid "ClusterIntegration|Install" +msgstr "Installa" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "Installa applicazioni sul tuo cluster. Leggi di più a riguardo %{helpLink}" + +msgid "ClusterIntegration|Installed" +msgstr "Installato" + +msgid "ClusterIntegration|Installing" +msgstr "" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "" + msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "Approfondisci riguardo i Clusters" + msgid "ClusterIntegration|Machine type" -msgstr "" +msgstr "Tipo di macchina" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" -msgstr "" +msgstr "Assicurati che il tuo account %{link_to_requirements} per creare i cluster" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" -msgstr "" +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" +msgstr "Gestisci l'integrazione dei cluster nel tuo progetto GitLab" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" -msgstr "" +msgstr "Gestisci i tuoi cluster visitando %{link_gke}" + +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "I cluster multipli sono disponibili nell'edizione Enterprise di Gitlab (Premium e Ultimate)" + +msgid "ClusterIntegration|Note:" +msgstr "Nota:" msgid "ClusterIntegration|Number of nodes" +msgstr "Numero di nodi" + +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" msgstr "" msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgstr "" +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "" + +msgid "ClusterIntegration|Project ID" +msgstr "" + +msgid "ClusterIntegration|Project namespace" +msgstr "" + msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "" @@ -567,7 +717,13 @@ msgstr "" msgid "ClusterIntegration|Remove integration" msgstr "" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "" + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "" + +msgid "ClusterIntegration|Save changes" msgstr "" msgid "ClusterIntegration|See and edit the details for your cluster" @@ -582,15 +738,33 @@ msgstr "" msgid "ClusterIntegration|See zones" msgstr "" +msgid "ClusterIntegration|Service token" +msgstr "" + +msgid "ClusterIntegration|Show" +msgstr "" + msgid "ClusterIntegration|Something went wrong on our end." msgstr "" msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" msgstr "" +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "" + msgid "ClusterIntegration|Toggle Cluster" msgstr "" +msgid "ClusterIntegration|Token" +msgstr "" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "" @@ -606,9 +780,15 @@ msgstr "" msgid "ClusterIntegration|cluster" msgstr "" +msgid "ClusterIntegration|documentation" +msgstr "" + msgid "ClusterIntegration|help page" msgstr "" +msgid "ClusterIntegration|installing applications" +msgstr "" + msgid "ClusterIntegration|meets the requirements" msgstr "" @@ -616,20 +796,15 @@ msgid "ClusterIntegration|properly configured" msgstr "" msgid "Comments" -msgstr "" +msgstr "Commenti" msgid "Commit" msgid_plural "Commits" msgstr[0] "" msgstr[1] "" -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "" -msgstr[1] "" - msgid "Commit Message" -msgstr "" +msgstr "Messaggio di commit" msgid "Commit duration in minutes for last 30 commits" msgstr "Durata del commit (in minuti) per gli ultimi 30 commit" @@ -644,7 +819,7 @@ msgid "CommitMessage|Add %{file_name}" msgstr "Aggiungi %{file_name}" msgid "Commits" -msgstr "" +msgstr "Commits" msgid "Commits feed" msgstr "Feed dei Commits" @@ -689,19 +864,19 @@ msgid "ContainerRegistry|Remove tag" msgstr "" msgid "ContainerRegistry|Size" -msgstr "" +msgstr "Dimensione" msgid "ContainerRegistry|Tag" -msgstr "" +msgstr "Tag" msgid "ContainerRegistry|Tag ID" -msgstr "" +msgstr "Tag ID" msgid "ContainerRegistry|Use different image names" -msgstr "" +msgstr "Utilizza nomi d'immagine differenti" msgid "ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images." -msgstr "" +msgstr "Con il Docker Container Registry integrato in Gitlab, ogni progetto può avere il suo spazio d'archiviazione sulle immagini Docker." msgid "Contribution guide" msgstr "Guida per contribuire" @@ -709,6 +884,15 @@ msgstr "Guida per contribuire" msgid "Contributors" msgstr "Collaboratori" +msgid "ContributorsPage|Building repository graph." +msgstr "Genero grafico della repository." + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "Esegui i commit su %{branch_name}, escludendo i commit di merge. Limitati a 6000 commits." + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "Attendere prego, questa pagina si ricaricherà automaticamente appena pronta." + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" msgstr "" @@ -736,20 +920,23 @@ msgstr "Crea cartella" msgid "Create empty bare repository" msgstr "Crea una repository vuota" -msgid "Create file" +msgid "Create epic" msgstr "" +msgid "Create file" +msgstr "Crea file" + msgid "Create merge request" msgstr "Crea una richiesta di merge" msgid "Create new branch" -msgstr "" +msgstr "Crea un nuova branch" msgid "Create new directory" -msgstr "" +msgstr "Crea una nuova cartella" msgid "Create new file" -msgstr "" +msgstr "Crea un nuovo File" msgid "Create new..." msgstr "Crea nuovo..." @@ -763,9 +950,12 @@ msgstr "Tag" msgid "CreateTokenToCloneLink|create a personal access token" msgstr "Crea token d'accesso personale" -msgid "Cron Timezone" +msgid "Creating epic" msgstr "" +msgid "Cron Timezone" +msgstr "Timezone del Cron" + msgid "Cron syntax" msgstr "Sintassi Cron" @@ -803,10 +993,16 @@ msgid "CycleAnalyticsStage|Test" msgstr "Test" msgid "DashboardProjects|All" -msgstr "" +msgstr "Tutti" msgid "DashboardProjects|Personal" -msgstr "" +msgstr "Personale" + +msgid "Dec" +msgstr "Dic" + +msgid "December" +msgstr "Dicembre" msgid "Define a custom pattern with cron syntax" msgstr "Definisci un patter personalizzato mediante la sintassi cron" @@ -820,7 +1016,7 @@ msgstr[0] "Rilascio" msgstr[1] "Rilasci" msgid "Deploy Keys" -msgstr "" +msgstr "Chiavi di Deploy (rilascio)" msgid "Description" msgstr "Descrizione" @@ -829,16 +1025,16 @@ msgid "Description templates allow you to define context-specific templates for msgstr "" msgid "Details" -msgstr "" +msgstr "Dettagli" msgid "Directory name" msgstr "Nome cartella" msgid "Discard changes" -msgstr "" +msgstr "Annulla modifiche" msgid "Dismiss Cycle Analytics introduction box" -msgstr "" +msgstr "Chiudi l'introduzione alle Analisi Cicliche" msgid "Dismiss Merge Request promotion" msgstr "" @@ -880,25 +1076,91 @@ msgid "Edit Pipeline Schedule %{id}" msgstr "Cambia programmazione della pipeline %{id}" msgid "Emails" +msgstr "E-mail" + +msgid "Environments|An error occurred while fetching the environments." +msgstr "Errore durante il fetch degli ambienti." + +msgid "Environments|An error occurred while making the request." +msgstr "Errore durante l'esecuzione della richiesta." + +msgid "Environments|Commit" +msgstr "Commit" + +msgid "Environments|Deployment" +msgstr "Rilascio" + +msgid "Environments|Environment" +msgstr "Ambiente" + +msgid "Environments|Environments" +msgstr "Ambienti" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "Gli ambienti sono gli spazi dove il codice viene rilasciato, come staging o produzione." + +msgid "Environments|Job" +msgstr "Job" + +msgid "Environments|New environment" +msgstr "Nuovo ambiente" + +msgid "Environments|No deployments yet" +msgstr "Ancora nessuna chiave di rilascio" + +msgid "Environments|Open" +msgstr "Apri" + +msgid "Environments|Re-deploy" +msgstr "Rilascia di nuovo" + +msgid "Environments|Read more about environments" +msgstr "Leggi di più sugli ambienti" + +msgid "Environments|Rollback" +msgstr "Rollback (ripristina)" + +msgid "Environments|Show all" +msgstr "Mostra tutti" + +msgid "Environments|Updated" +msgstr "Aggiornato" + +msgid "Environments|You don't have any environments right now." +msgstr "Attualmente non hai alcun ambiente." + +msgid "Epic will be removed! Are you sure?" msgstr "" -msgid "EventFilterBy|Filter by all" +msgid "Epics" msgstr "" -msgid "EventFilterBy|Filter by comments" +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" msgstr "" -msgid "EventFilterBy|Filter by issue events" +msgid "Error creating epic" msgstr "" +msgid "Error occurred when toggling the notification subscription" +msgstr "Errore durante l'attivazione/disattivazione della sottoscrizione per l'iscrizione" + +msgid "EventFilterBy|Filter by all" +msgstr "Filtra per tutti" + +msgid "EventFilterBy|Filter by comments" +msgstr "Filtra per commenti" + +msgid "EventFilterBy|Filter by issue events" +msgstr "Filtra per eventi di issue" + msgid "EventFilterBy|Filter by merge events" -msgstr "" +msgstr "Filtra per eventi di merge" msgid "EventFilterBy|Filter by push events" -msgstr "" +msgstr "Filtra per eventi di push" msgid "EventFilterBy|Filter by team" -msgstr "" +msgstr "Filtra per team" msgid "Every day (at 4:00am)" msgstr "Ogni giorno (alle 4 del mattino)" @@ -910,10 +1172,10 @@ msgid "Every week (Sundays at 4:00am)" msgstr "Ogni settimana (Di domenica alle 4 del mattino)" msgid "Explore projects" -msgstr "" +msgstr "Esplora progetti" msgid "Explore public groups" -msgstr "" +msgstr "Esplora gruppi pubblici" msgid "Failed to change the owner" msgstr "Impossibile cambiare owner" @@ -921,11 +1183,17 @@ msgstr "Impossibile cambiare owner" msgid "Failed to remove the pipeline schedule" msgstr "Impossibile rimuovere la pipeline pianificata" +msgid "Feb" +msgstr "Feb" + +msgid "February" +msgstr "Febbraio" + msgid "File name" -msgstr "" +msgstr "Nome file" msgid "Files" -msgstr "" +msgstr "Files" msgid "Filter by commit message" msgstr "Filtra per messaggio di commit" @@ -944,17 +1212,17 @@ msgstr "Push di" msgid "Fork" msgid_plural "Forks" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Fork" +msgstr[1] "Forks" msgid "ForkedFromProjectPath|Forked from" msgstr "Fork da" msgid "ForkedFromProjectPath|Forked from %{project_name} (deleted)" -msgstr "" +msgstr "Fork da %{project_name} (eliminato)" msgid "Format" -msgstr "" +msgstr "Formato" msgid "From issue creation until deploy to production" msgstr "Dalla creazione di un issue fino al rilascio in produzione" @@ -963,11 +1231,26 @@ msgid "From merge request merge until deploy to production" msgstr "Dalla richiesta di merge fino effettua il merge fino al rilascio in produzione" msgid "GPG Keys" -msgstr "" +msgstr "Chiavi GPG" msgid "Geo Nodes" msgstr "" +msgid "GeoNodeSyncStatus|Failed" +msgstr "" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "" + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "" + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "" + msgid "Geo|File sync capacity" msgstr "" @@ -981,10 +1264,10 @@ msgid "Geo|Select groups to replicate." msgstr "" msgid "Git storage health information has been reset" -msgstr "" +msgstr "Le informazioni sullo stato dell'archiviazione Git è stata ripristinata" msgid "GitLab Runner section" -msgstr "" +msgstr "Sezione Gitlab Runner" msgid "Go to your fork" msgstr "Vai il tuo fork" @@ -993,22 +1276,22 @@ msgid "GoToYourFork|Fork" msgstr "Fork" msgid "Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service." -msgstr "" +msgstr "L'autenticazione Google non è %{link_to_documentation}. Richiedi al tuo amministratore Gitlab se desideri utilizzare il servizio." msgid "GroupSettings|Prevent sharing a project within %{group} with other groups" -msgstr "" +msgstr "Blocca la condivisione di un progetto di %{group} con altri gruppi" msgid "GroupSettings|Share with group lock" -msgstr "" +msgstr "Condividi con il gruppo chiuso" msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been overridden on this subgroup." -msgstr "" +msgstr "Questa modifica è stata applicata su %{ancestor_group} ed è stata ignorata nel sottogruppo." msgid "GroupSettings|This setting is applied on %{ancestor_group}. To share projects in this group with another group, ask the owner to override the setting or %{remove_ancestor_share_with_group_lock}." -msgstr "" +msgstr "Questa impostazione è stata applicata a %{ancestor_group}. Per condividere i progetti con altri gruppi chiedi all'owner di eseguire l'override delle impostazioni oppure %{remove_ancestor_share_with_group_lock}." msgid "GroupSettings|This setting is applied on %{ancestor_group}. You can override the setting or %{remove_ancestor_share_with_group_lock}." -msgstr "" +msgstr "Questa impostazione è stata applicata a %{ancestor_group}. Puoi eseguire l'override delle impostazioni o %{remove_ancestor_share_with_group_lock}." msgid "GroupSettings|This setting will be applied to all subgroups unless overridden by a group owner. Groups that already have access to the project will continue to have access unless removed manually." msgstr "" @@ -1031,9 +1314,6 @@ msgstr "" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "" -msgid "GroupsTreeRole|as" -msgstr "" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "" @@ -1064,9 +1344,12 @@ msgstr "" msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "" -msgid "Health Check" +msgid "Have your users email" msgstr "" +msgid "Health Check" +msgstr "Verifica stato" + msgid "Health information can be retrieved from the following endpoints. More information is available" msgstr "" @@ -1083,7 +1366,7 @@ msgid "HealthCheck|Unhealthy" msgstr "" msgid "History" -msgstr "" +msgstr "Cronologia" msgid "Housekeeping successfully started" msgstr "Housekeeping iniziato con successo" @@ -1123,9 +1406,6 @@ msgstr "Introduzione delle Analisi Cicliche" msgid "Issue board focus mode" msgstr "" -msgid "Issue boards with milestones" -msgstr "" - msgid "Issue events" msgstr "" @@ -1138,6 +1418,24 @@ msgstr "" msgid "Issues" msgstr "" +msgid "Jan" +msgstr "Gen" + +msgid "January" +msgstr "Gennaio" + +msgid "Jul" +msgstr "Lug" + +msgid "July" +msgstr "Luglio" + +msgid "Jun" +msgstr "Giu" + +msgid "June" +msgstr "Giugno" + msgid "LFSStatus|Disabled" msgstr "Disabilitato" @@ -1159,16 +1457,16 @@ msgid "Last commit" msgstr "Ultimo Commit" msgid "Last edited %{date}" -msgstr "" +msgstr "Ultima modifica %{date}" msgid "Last edited by %{name}" -msgstr "" +msgstr "Modificato da %{name}" msgid "Last update" -msgstr "" +msgstr "Ultimo aggiornamento" msgid "Last updated" -msgstr "" +msgstr "Ultimo aggiornamento" msgid "LastPushEvent|You pushed to" msgstr "" @@ -1203,49 +1501,58 @@ msgid "Lock" msgstr "" msgid "Locked" -msgstr "" +msgstr "Bloccato" msgid "Locked Files" msgstr "" msgid "Login" -msgstr "" +msgstr "Login" + +msgid "Mar" +msgstr "Mar" + +msgid "March" +msgstr "Marzo" msgid "Maximum git storage failures" msgstr "" +msgid "May" +msgstr "" + msgid "Median" msgstr "Mediano" msgid "Members" -msgstr "" +msgstr "Membri" msgid "Merge Requests" -msgstr "" +msgstr "Richieste di merge" msgid "Merge events" msgstr "" msgid "Merge request" -msgstr "" +msgstr "Richiesta di merge" msgid "Messages" -msgstr "" +msgstr "Messaggi" msgid "MissingSSHKeyWarningLink|add an SSH key" msgstr "aggiungi una chiave SSH" msgid "Monitoring" -msgstr "" +msgstr "Monitoraggio" msgid "More information is available|here" -msgstr "" +msgstr "Ulteriori informazioni sono disponibili | qui" msgid "Multiple issue boards" msgstr "" msgid "New Cluster" -msgstr "" +msgstr "Nuovo Cluster" msgid "New Issue" msgid_plural "New Issues" @@ -1258,14 +1565,20 @@ msgstr "Nuova pianificazione Pipeline" msgid "New branch" msgstr "Nuova Branch" +msgid "New branch unavailable" +msgstr "" + msgid "New directory" msgstr "Nuova directory" +msgid "New epic" +msgstr "" + msgid "New file" msgstr "Nuovo file" msgid "New group" -msgstr "" +msgstr "Nuovo gruppo" msgid "New issue" msgstr "Nuovo Issue" @@ -1274,7 +1587,7 @@ msgid "New merge request" msgstr "Nuova richiesta di merge" msgid "New project" -msgstr "" +msgstr "Nuovo progetto" msgid "New schedule" msgstr "Nuova pianficazione" @@ -1283,7 +1596,7 @@ msgid "New snippet" msgstr "Nuovo snippet" msgid "New subgroup" -msgstr "" +msgstr "Nuovo sottogruppo" msgid "New tag" msgstr "Nuovo tag" @@ -1297,9 +1610,12 @@ msgstr "Nessuna Repository" msgid "No schedules" msgstr "Nessuna pianificazione" -msgid "None" +msgid "No time spent" msgstr "" +msgid "None" +msgstr "Nessuno" + msgid "Not available" msgstr "Non disponibile" @@ -1361,55 +1677,70 @@ msgid "NotificationLevel|Watch" msgstr "Osserva" msgid "Notifications" -msgstr "" +msgstr "Notifiche" + +msgid "Nov" +msgstr "Nov" + +msgid "November" +msgstr "Novembre" msgid "Number of access attempts" -msgstr "" +msgstr "Numero di tentativi di accesso raggiunto" msgid "Number of failures before backing off" msgstr "" +msgid "Oct" +msgstr "Ott" + +msgid "October" +msgstr "Ottobre" + msgid "OfSearchInADropdown|Filter" msgstr "Filtra" msgid "Only project members can comment." +msgstr "Solo i membri del progetto possono commentare." + +msgid "Opened" msgstr "" msgid "OpenedNDaysAgo|Opened" msgstr "Aperto" msgid "Opens in a new window" -msgstr "" +msgstr "Si apre in una nuova finestra" msgid "Options" msgstr "Opzioni" msgid "Overview" -msgstr "" +msgstr "Panoramica" msgid "Owner" -msgstr "" +msgstr "Proprietario" msgid "Pagination|Last »" -msgstr "" +msgstr "Ultima »" msgid "Pagination|Next" -msgstr "" +msgstr "Successiva" msgid "Pagination|Prev" -msgstr "" +msgstr "Precedente" msgid "Pagination|« First" -msgstr "" +msgstr "« Prima" msgid "Password" -msgstr "" +msgstr "Password" msgid "People without permission will never get a notification and won\\'t be able to comment." -msgstr "" +msgstr "Le persone che non hanno il permesso non saranno notificate e non potranno commentare." msgid "Pipeline" -msgstr "" +msgstr "Pipeline" msgid "Pipeline Health" msgstr "Stato della Pipeline" @@ -1487,13 +1818,13 @@ msgid "Pipelines charts" msgstr "Grafici pipeline" msgid "Pipelines for last month" -msgstr "" +msgstr "Pipeline per il mese scorso" msgid "Pipelines for last week" -msgstr "" +msgstr "Pipeline per la settimana scorsa" msgid "Pipelines for last year" -msgstr "" +msgstr "Pipeline per l'ultimo anno" msgid "Pipeline|all" msgstr "tutto" @@ -1507,56 +1838,59 @@ msgstr "con stadio" msgid "Pipeline|with stages" msgstr "con più stadi" -msgid "Preferences" +msgid "Please solve the reCAPTCHA" msgstr "" +msgid "Preferences" +msgstr "Preferenze" + msgid "Private - Project access must be granted explicitly to each user." -msgstr "" +msgstr "Privato - L'accesso al progetto deve essere fornito esplicitamente ad ogni utente." msgid "Private - The group and its projects can only be viewed by members." -msgstr "" +msgstr "Privato - Il gruppo e i suoi progetti possono essere visualizzati solo dai membri." msgid "Profile" -msgstr "" +msgstr "Profilo" msgid "Profiles|Account scheduled for removal." -msgstr "" +msgstr "Account pianificato per la rimozione." msgid "Profiles|Delete Account" -msgstr "" +msgstr "Elimina account" msgid "Profiles|Delete account" -msgstr "" +msgstr "Elimina account" msgid "Profiles|Delete your account?" -msgstr "" +msgstr "Eliminare il tuo account?" msgid "Profiles|Deleting an account has the following effects:" msgstr "" msgid "Profiles|Invalid password" -msgstr "" +msgstr "Password non valida" msgid "Profiles|Invalid username" -msgstr "" +msgstr "Username non valido" msgid "Profiles|Type your %{confirmationValue} to confirm:" -msgstr "" +msgstr "Inserisci il tuo %{confirmationValue} per confermare:" msgid "Profiles|You don't have access to delete this user." -msgstr "" +msgstr "Non hai i permessi per eliminare questo utente." msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account." -msgstr "" +msgstr "Devi trasferire la proprietà o eliminare questi gruppi prima che tu possa eliminare l'account." msgid "Profiles|Your account is currently an owner in these groups:" -msgstr "" +msgstr "Il tuo account è attualmente proprietario in questi gruppi:" msgid "Profiles|your account" -msgstr "" +msgstr "il tuo account" msgid "Project '%{project_name}' is in the process of being deleted." -msgstr "" +msgstr "Il progetto '%{project_name}' è in fase di eliminazione." msgid "Project '%{project_name}' queued for deletion." msgstr "Il Progetto '%{project_name}' in coda di eliminazione." @@ -1571,7 +1905,7 @@ msgid "Project access must be granted explicitly to each user." msgstr "L'accesso al progetto dev'esser fornito esplicitamente ad ogni utente" msgid "Project details" -msgstr "" +msgstr "Dettagli del progetto" msgid "Project export could not be deleted." msgstr "L'esportazione del progetto non può essere eliminata." @@ -1586,7 +1920,7 @@ msgid "Project export started. A download link will be sent by email." msgstr "Esportazione del progetto iniziata. Un link di download sarà inviato via email." msgid "ProjectActivityRSS|Subscribe" -msgstr "" +msgstr "Iscriviti" msgid "ProjectFeature|Disabled" msgstr "Disabilitato" @@ -1612,9 +1946,15 @@ msgstr "Grafico" msgid "ProjectSettings|Contact an admin to change this setting." msgstr "" +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "Esegui subito una pipeline sulla branch di default" + msgid "ProjectSettings|Only signed commits can be pushed to this repository." msgstr "" +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "Problemi durante l'impostazione delle CI/CD JavaScript settings" + msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." msgstr "" @@ -1628,35 +1968,68 @@ msgid "ProjectSettings|Users can only push commits to this repository that were msgstr "" msgid "Projects" -msgstr "" +msgstr "Progetti" msgid "ProjectsDropdown|Frequently visited" -msgstr "" +msgstr "Visitati di frequente" msgid "ProjectsDropdown|Loading projects" -msgstr "" +msgstr "Caricamento progetti" msgid "ProjectsDropdown|Projects you visit often will appear here" -msgstr "" +msgstr "I progetti che visiti spesso appariranno qui" msgid "ProjectsDropdown|Search your projects" -msgstr "" +msgstr "Cerca tra i tuoi progetti" msgid "ProjectsDropdown|Something went wrong on our end." -msgstr "" +msgstr "Qualcosa è andato storto dalla nostra parte." msgid "ProjectsDropdown|Sorry, no projects matched your search" -msgstr "" +msgstr "Siamo spiacenti, non ci sono progetti che corrispondono alla tua ricerca" msgid "ProjectsDropdown|This feature requires browser localStorage support" +msgstr "Questa feature richiede il supporto del localStorage del browser" + +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "Di default, Prometheus è in ascolto su ‘http://localhost:9090‘. Non è consigliabile cambiare l'indirizzo e la porta di default in quanto ciò potrebbe influenzare o causare conflitto con altri servizi in esecuzione sul server GitLab." + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "Ricerco e configuro le metriche..." + +msgid "PrometheusService|Metrics" +msgstr "Metriche" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "Le metriche sono configurate automaticamente e monitorate sulla base di una libreria di metriche di esportatori popolari." + +msgid "PrometheusService|Missing environment variable" +msgstr "Variabile d'ambiente mancante" + +msgid "PrometheusService|Monitored" +msgstr "Monitorato" + +msgid "PrometheusService|More information" +msgstr "Ulteriori informazioni" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "Nessuna metrica è stata monitorata. Per iniziare a monitorare, rilascia su un ambiente." + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" msgstr "" -msgid "Public - The group and any public projects can be viewed without any authentication." +msgid "PrometheusService|Prometheus monitoring" msgstr "" -msgid "Public - The project can be accessed without any authentication." +msgid "PrometheusService|View environments" msgstr "" +msgid "Public - The group and any public projects can be viewed without any authentication." +msgstr "Pubblico - il gruppo e tutti i progetti pubblici possono essere visualizzati senza alcuna autenticazione." + +msgid "Public - The project can be accessed without any authentication." +msgstr "Public - Chiunque può accedere a questo progetto senza alcuna autenticazione." + msgid "Push Rules" msgstr "" @@ -1727,13 +2100,13 @@ msgid "Revert this merge request" msgstr "Ripristina questa richiesta di merge" msgid "SSH Keys" -msgstr "" +msgstr "Chiavi SSH" msgid "Save" -msgstr "" +msgstr "Salva" msgid "Save changes" -msgstr "" +msgstr "Salva modifiche" msgid "Save pipeline schedule" msgstr "Salva pianificazione pipeline" @@ -1747,6 +2120,9 @@ msgstr "" msgid "Scheduling Pipelines" msgstr "Pianificazione pipelines" +msgid "Scoped issue boards" +msgstr "" + msgid "Search branches and tags" msgstr "Ricerca branches e tags" @@ -1768,6 +2144,12 @@ msgstr "Seleziona una timezone" msgid "Select target branch" msgstr "Seleziona una branch di destinazione" +msgid "Sep" +msgstr "Set" + +msgid "September" +msgstr "Settembre" + msgid "Service Templates" msgstr "" @@ -1787,7 +2169,7 @@ msgid "SetPasswordToCloneLink|set a password" msgstr "imposta una password" msgid "Settings" -msgstr "" +msgstr "Impostazioni" msgid "Show parent pages" msgstr "" @@ -1800,24 +2182,39 @@ msgid_plural "Showing %d events" msgstr[0] "Visualizza %d evento" msgstr[1] "Visualizza %d eventi" -msgid "Snippets" +msgid "Sidebar|Change weight" msgstr "" -msgid "Something went wrong on our end." +msgid "Sidebar|Edit" msgstr "" -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" +msgid "Sidebar|No" msgstr "" -msgid "Something went wrong while fetching the projects." +msgid "Sidebar|None" msgstr "" -msgid "Something went wrong while fetching the registry list." +msgid "Sidebar|Weight" msgstr "" -msgid "Sort by" +msgid "Snippets" +msgstr "Snippet" + +msgid "Something went wrong on our end." +msgstr "Si è verificato un problema con il nostro server." + +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" msgstr "" +msgid "Something went wrong while fetching the projects." +msgstr "Qualcosa è andato storto durante il fetch dei progetti." + +msgid "Something went wrong while fetching the registry list." +msgstr "Qualcosa è andato storto durante il recupero dell'elenco dei registri." + +msgid "Sort by" +msgstr "Ordina per" + msgid "SortOptions|Access level, ascending" msgstr "" @@ -1849,7 +2246,7 @@ msgid "SortOptions|Last created" msgstr "" msgid "SortOptions|Last joined" -msgstr "" +msgstr "Ultimo che ha Joinato" msgid "SortOptions|Last updated" msgstr "" @@ -1888,7 +2285,7 @@ msgid "SortOptions|Oldest created" msgstr "" msgid "SortOptions|Oldest joined" -msgstr "" +msgstr "Dal primo Joinato" msgid "SortOptions|Oldest sign in" msgstr "" @@ -1914,9 +2311,15 @@ msgstr "" msgid "SortOptions|Weight" msgstr "" +msgid "Source" +msgstr "" + msgid "Source code" msgstr "Codice Sorgente" +msgid "Source is not available" +msgstr "" + msgid "Spam Logs" msgstr "" @@ -1935,6 +2338,9 @@ msgstr "inizia una %{new_merge_request} con queste modifiche" msgid "Start the Runner!" msgstr "" +msgid "Stopped" +msgstr "" + msgid "Subgroups" msgstr "" @@ -1955,6 +2361,75 @@ msgstr[1] "" msgid "Tags" msgstr "" +msgid "TagsPage|Browse commits" +msgstr "" + +msgid "TagsPage|Browse files" +msgstr "" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "" + +msgid "TagsPage|Cancel" +msgstr "" + +msgid "TagsPage|Create tag" +msgstr "" + +msgid "TagsPage|Delete tag" +msgstr "" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "" + +msgid "TagsPage|Edit release notes" +msgstr "" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "" + +msgid "TagsPage|Filter by tag name" +msgstr "" + +msgid "TagsPage|New Tag" +msgstr "" + +msgid "TagsPage|New tag" +msgstr "" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "" + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "" + +msgid "TagsPage|Release notes" +msgstr "" + +msgid "TagsPage|Repository has no tags yet." +msgstr "" + +msgid "TagsPage|Sort by" +msgstr "" + +msgid "TagsPage|Tags" +msgstr "" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "" + +msgid "TagsPage|This tag has no release notes." +msgstr "" + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "" + +msgid "TagsPage|protected" +msgstr "" + msgid "Target Branch" msgstr "Branch di destinazione" @@ -2036,6 +2511,9 @@ msgstr "Il valore falsato nel mezzo di una serie di dati osservati. ES: tra 3,5, msgid "There are problems accessing Git storage: " msgstr "" +msgid "This board\\'s scope is reduced" +msgstr "" + msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "" @@ -2057,6 +2535,9 @@ msgstr "Questo significa che non è possibile effettuare push di codice fino a c msgid "This merge request is locked." msgstr "" +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "Il tempo che impiega un issue per esser pianificato" @@ -2205,15 +2686,27 @@ msgstr[1] "mins" msgid "Time|s" msgstr "s" +msgid "Title" +msgstr "" + msgid "Total Time" msgstr "Tempo Totale" +msgid "Total issue time spent" +msgstr "" + msgid "Total test time for all commits/merges" msgstr "Tempo totale di test per tutti i commits/merges" msgid "Track activity with Contribution Analytics." msgstr "" +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "" + +msgid "Turn on Service Desk" +msgstr "" + msgid "Unlock" msgstr "" @@ -2250,6 +2743,9 @@ msgstr "Carica file" msgid "UploadLink|click to upload" msgstr "clicca per caricare" +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "" + msgid "Use the following registration token during setup:" msgstr "" @@ -2283,6 +2779,9 @@ msgstr "Vuoi visualizzare i dati? Richiedi l'accesso ad un amministratore, grazi msgid "We don't have enough data to show this stage." msgstr "Non ci sono sufficienti dati da mostrare su questo stadio" +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "" + msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." msgstr "" @@ -2412,12 +2911,6 @@ msgstr "Stai per rimuovere la relazione con il progetto sorgente %{forked_from_p msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "Stai per trasferire %{project_name_with_namespace} ad un altro owner. Sei ASSOLUTAMENTE sicuro?" -msgid "You are on a read-only GitLab instance." -msgstr "" - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "" - msgid "You can only add files when you are on a branch" msgstr "Puoi aggiungere files solo quando sei in una branch" @@ -2457,6 +2950,9 @@ msgstr "Non sarai in grado di eseguire pull o push di codice tramite %{protocol} msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" msgstr "Non sarai in grado di effettuare push o pull tramite SSH fino a che %{add_ssh_key_link} al tuo profilo" +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "" + msgid "Your comment will not be visible to the public." msgstr "" @@ -2469,6 +2965,12 @@ msgstr "Il tuo nome" msgid "Your projects" msgstr "" +msgid "branch name" +msgstr "" + +msgid "by" +msgstr "" + msgid "commit" msgstr "" @@ -2494,6 +2996,9 @@ msgstr "" msgid "personal access token" msgstr "" +msgid "source" +msgstr "" + msgid "to help your contributors communicate effectively!" msgstr "" diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po index 8d93a936be9..1314bad87fe 100644 --- a/locale/ja/gitlab.po +++ b/locale/ja/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-03 12:31-0400\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 04:40-0500\n" "Last-Translator: gitlab \n" "Language-Team: Japanese\n" "Language: ja_JP\n" @@ -51,6 +51,9 @@ msgid "%{storage_name}: failed storage access attempt on host:" msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:" msgstr[0] "" +msgid "%{text} is available" +msgstr "" + msgid "(checkout the %{link} for information on how to install it)." msgstr "" @@ -109,9 +112,6 @@ msgstr "" msgid "Add License" msgstr "ライセンスを追加" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "SSHでプルやプッシュする場合は、プロフィールにSSH鍵を追加してください。" - msgid "Add new directory" msgstr "新規ディレクトリを追加" @@ -124,6 +124,15 @@ msgstr "" msgid "All" msgstr "" +msgid "An error occurred when toggling the notification subscription" +msgstr "" + +msgid "An error occurred when updating the issue weight" +msgstr "" + +msgid "An error occurred while fetching sidebar data" +msgstr "" + msgid "An error occurred. Please try again." msgstr "" @@ -133,6 +142,12 @@ msgstr "" msgid "Applications" msgstr "" +msgid "Apr" +msgstr "" + +msgid "April" +msgstr "" + msgid "Archived project! Repository is read-only" msgstr "アーカイブ済みプロジェクト!(レポジトリーは読み取り専用です)" @@ -160,6 +175,12 @@ msgstr "" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "ドラッグ&ドロップまたは %{upload_link} でファイルを添付" +msgid "Aug" +msgstr "" + +msgid "August" +msgstr "" + msgid "Authentication Log" msgstr "" @@ -193,6 +214,9 @@ msgstr "" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." msgstr "" +msgid "Available" +msgstr "" + msgid "Billing" msgstr "" @@ -257,6 +281,12 @@ msgstr "%{branch_name} ブランチが作成されました。 msgid "Branch has changed" msgstr "" +msgid "Branch is already taken" +msgstr "" + +msgid "Branch name" +msgstr "" + msgid "BranchSwitcherPlaceholder|Search branches" msgstr "ブランチを検索" @@ -404,6 +434,12 @@ msgstr "チャート" msgid "Chat" msgstr "" +msgid "Checking %{text} availability…" +msgstr "" + +msgid "Checking branch availability..." +msgstr "" + msgid "Cherry-pick this commit" msgstr "このコミットをチェリーピック" @@ -479,7 +515,40 @@ msgstr "" msgid "Cluster" msgstr "" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "" + +msgid "ClusterIntegration|API URL" +msgstr "" + +msgid "ClusterIntegration|Active" +msgstr "" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "" + +msgid "ClusterIntegration|Add cluster" +msgstr "" + +msgid "ClusterIntegration|All" +msgstr "" + +msgid "ClusterIntegration|Applications" +msgstr "" + +msgid "ClusterIntegration|CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "" + +msgid "ClusterIntegration|Cluster" msgstr "" msgid "ClusterIntegration|Cluster details" @@ -503,21 +572,54 @@ msgstr "" msgid "ClusterIntegration|Cluster name" msgstr "" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" +msgstr "" + +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "" + +msgid "ClusterIntegration|Copy API URL" +msgstr "" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Copy Token" msgstr "" msgid "ClusterIntegration|Copy cluster name" msgstr "" +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "" + msgid "ClusterIntegration|Create cluster" msgstr "" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Create on GKE" msgstr "" msgid "ClusterIntegration|Enable cluster integration" msgstr "" +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "" + +msgid "ClusterIntegration|Environment pattern" +msgstr "" + +msgid "ClusterIntegration|GKE pricing" +msgstr "" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "" + msgid "ClusterIntegration|Google Cloud Platform project ID" msgstr "" @@ -527,27 +629,75 @@ msgstr "" msgid "ClusterIntegration|Google Kubernetes Engine project" msgstr "" +msgid "ClusterIntegration|Helm Tiller" +msgstr "" + +msgid "ClusterIntegration|Inactive" +msgstr "" + +msgid "ClusterIntegration|Ingress" +msgstr "" + +msgid "ClusterIntegration|Install" +msgstr "" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "" + +msgid "ClusterIntegration|Installed" +msgstr "" + +msgid "ClusterIntegration|Installing" +msgstr "" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "" + msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "" + msgid "ClusterIntegration|Machine type" msgstr "" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" msgstr "" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" msgstr "" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" msgstr "" +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "" + +msgid "ClusterIntegration|Note:" +msgstr "" + msgid "ClusterIntegration|Number of nodes" msgstr "" +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" +msgstr "" + msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgstr "" +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "" + +msgid "ClusterIntegration|Project ID" +msgstr "" + +msgid "ClusterIntegration|Project namespace" +msgstr "" + msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "" @@ -560,7 +710,13 @@ msgstr "" msgid "ClusterIntegration|Remove integration" msgstr "" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "" + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "" + +msgid "ClusterIntegration|Save changes" msgstr "" msgid "ClusterIntegration|See and edit the details for your cluster" @@ -575,15 +731,33 @@ msgstr "" msgid "ClusterIntegration|See zones" msgstr "" +msgid "ClusterIntegration|Service token" +msgstr "" + +msgid "ClusterIntegration|Show" +msgstr "" + msgid "ClusterIntegration|Something went wrong on our end." msgstr "" msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" msgstr "" +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "" + msgid "ClusterIntegration|Toggle Cluster" msgstr "" +msgid "ClusterIntegration|Token" +msgstr "" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "" @@ -599,9 +773,15 @@ msgstr "" msgid "ClusterIntegration|cluster" msgstr "" +msgid "ClusterIntegration|documentation" +msgstr "" + msgid "ClusterIntegration|help page" msgstr "" +msgid "ClusterIntegration|installing applications" +msgstr "" + msgid "ClusterIntegration|meets the requirements" msgstr "" @@ -615,10 +795,6 @@ msgid "Commit" msgid_plural "Commits" msgstr[0] "コミット" -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "" - msgid "Commit Message" msgstr "" @@ -700,6 +876,15 @@ msgstr "貢献者向けガイド" msgid "Contributors" msgstr "貢献者" +msgid "ContributorsPage|Building repository graph." +msgstr "" + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "" + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "" + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" msgstr "" @@ -727,6 +912,9 @@ msgstr "ディレクトリを作成" msgid "Create empty bare repository" msgstr "空のbareレポジトリーを作成" +msgid "Create epic" +msgstr "" + msgid "Create file" msgstr "" @@ -754,6 +942,9 @@ msgstr "タグ" msgid "CreateTokenToCloneLink|create a personal access token" msgstr "個人用アクセストークンを作成" +msgid "Creating epic" +msgstr "" + msgid "Cron Timezone" msgstr "Cron のタイムゾーン" @@ -799,6 +990,12 @@ msgstr "" msgid "DashboardProjects|Personal" msgstr "" +msgid "Dec" +msgstr "" + +msgid "December" +msgstr "" + msgid "Define a custom pattern with cron syntax" msgstr "Cron 構文でカスタムなパターンを指定する" @@ -872,6 +1069,72 @@ msgstr "パイプラインスケジュール %{id} を編集" msgid "Emails" msgstr "" +msgid "Environments|An error occurred while fetching the environments." +msgstr "" + +msgid "Environments|An error occurred while making the request." +msgstr "" + +msgid "Environments|Commit" +msgstr "" + +msgid "Environments|Deployment" +msgstr "" + +msgid "Environments|Environment" +msgstr "" + +msgid "Environments|Environments" +msgstr "" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "" + +msgid "Environments|Job" +msgstr "" + +msgid "Environments|New environment" +msgstr "" + +msgid "Environments|No deployments yet" +msgstr "" + +msgid "Environments|Open" +msgstr "" + +msgid "Environments|Re-deploy" +msgstr "" + +msgid "Environments|Read more about environments" +msgstr "" + +msgid "Environments|Rollback" +msgstr "" + +msgid "Environments|Show all" +msgstr "" + +msgid "Environments|Updated" +msgstr "" + +msgid "Environments|You don't have any environments right now." +msgstr "" + +msgid "Epic will be removed! Are you sure?" +msgstr "" + +msgid "Epics" +msgstr "" + +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" +msgstr "" + +msgid "Error creating epic" +msgstr "" + +msgid "Error occurred when toggling the notification subscription" +msgstr "" + msgid "EventFilterBy|Filter by all" msgstr "" @@ -911,6 +1174,12 @@ msgstr "オーナーを変更できませんでした" msgid "Failed to remove the pipeline schedule" msgstr "パイプラインスケジュールを削除できませんでした" +msgid "Feb" +msgstr "" + +msgid "February" +msgstr "" + msgid "File name" msgstr "" @@ -957,6 +1226,21 @@ msgstr "" msgid "Geo Nodes" msgstr "" +msgid "GeoNodeSyncStatus|Failed" +msgstr "" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "" + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "" + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "" + msgid "Geo|File sync capacity" msgstr "" @@ -1020,9 +1304,6 @@ msgstr "" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "" -msgid "GroupsTreeRole|as" -msgstr "" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "" @@ -1053,6 +1334,9 @@ msgstr "" msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "" +msgid "Have your users email" +msgstr "" + msgid "Health Check" msgstr "" @@ -1111,9 +1395,6 @@ msgstr "サイクル分析のご紹介" msgid "Issue board focus mode" msgstr "" -msgid "Issue boards with milestones" -msgstr "" - msgid "Issue events" msgstr "" @@ -1126,6 +1407,24 @@ msgstr "" msgid "Issues" msgstr "" +msgid "Jan" +msgstr "" + +msgid "January" +msgstr "" + +msgid "Jul" +msgstr "" + +msgid "July" +msgstr "" + +msgid "Jun" +msgstr "" + +msgid "June" +msgstr "" + msgid "LFSStatus|Disabled" msgstr "無効" @@ -1197,9 +1496,18 @@ msgstr "" msgid "Login" msgstr "" +msgid "Mar" +msgstr "" + +msgid "March" +msgstr "" + msgid "Maximum git storage failures" msgstr "" +msgid "May" +msgstr "" + msgid "Median" msgstr "中央値" @@ -1243,9 +1551,15 @@ msgstr "新規パイプラインスケジュール" msgid "New branch" msgstr "新規ブランチ" +msgid "New branch unavailable" +msgstr "" + msgid "New directory" msgstr "新規ディレクトリ" +msgid "New epic" +msgstr "" + msgid "New file" msgstr "新規ファイル" @@ -1282,6 +1596,9 @@ msgstr "レポジトリーはありません" msgid "No schedules" msgstr "スケジュールなし" +msgid "No time spent" +msgstr "" + msgid "None" msgstr "" @@ -1348,18 +1665,33 @@ msgstr "すべて通知" msgid "Notifications" msgstr "" +msgid "Nov" +msgstr "" + +msgid "November" +msgstr "" + msgid "Number of access attempts" msgstr "" msgid "Number of failures before backing off" msgstr "" +msgid "Oct" +msgstr "" + +msgid "October" +msgstr "" + msgid "OfSearchInADropdown|Filter" msgstr "フィルター" msgid "Only project members can comment." msgstr "" +msgid "Opened" +msgstr "" + msgid "OpenedNDaysAgo|Opened" msgstr "オープンされたのは" @@ -1492,6 +1824,9 @@ msgstr "ステージあり" msgid "Pipeline|with stages" msgstr "ステージあり" +msgid "Please solve the reCAPTCHA" +msgstr "" + msgid "Preferences" msgstr "" @@ -1597,9 +1932,15 @@ msgstr "ネットワークグラフ" msgid "ProjectSettings|Contact an admin to change this setting." msgstr "" +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "" + msgid "ProjectSettings|Only signed commits can be pushed to this repository." msgstr "" +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "" + msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." msgstr "" @@ -1636,6 +1977,39 @@ msgstr "" msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "" +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "" + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "" + +msgid "PrometheusService|Metrics" +msgstr "" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "" + +msgid "PrometheusService|Missing environment variable" +msgstr "" + +msgid "PrometheusService|Monitored" +msgstr "" + +msgid "PrometheusService|More information" +msgstr "" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "" + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" +msgstr "" + +msgid "PrometheusService|Prometheus monitoring" +msgstr "" + +msgid "PrometheusService|View environments" +msgstr "" + msgid "Public - The group and any public projects can be viewed without any authentication." msgstr "" @@ -1732,6 +2106,9 @@ msgstr "" msgid "Scheduling Pipelines" msgstr "パイプラインスケジューリング" +msgid "Scoped issue boards" +msgstr "" + msgid "Search branches and tags" msgstr "ブランチまたはタグを検索" @@ -1753,6 +2130,12 @@ msgstr "タイムゾーンを選択" msgid "Select target branch" msgstr "ターゲットブランチを選択" +msgid "Sep" +msgstr "" + +msgid "September" +msgstr "" + msgid "Service Templates" msgstr "" @@ -1784,13 +2167,28 @@ msgid "Showing %d event" msgid_plural "Showing %d events" msgstr[0] "%d のイベントを表示中" +msgid "Sidebar|Change weight" +msgstr "" + +msgid "Sidebar|Edit" +msgstr "" + +msgid "Sidebar|No" +msgstr "" + +msgid "Sidebar|None" +msgstr "" + +msgid "Sidebar|Weight" +msgstr "" + msgid "Snippets" msgstr "" msgid "Something went wrong on our end." msgstr "" -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" msgstr "" msgid "Something went wrong while fetching the projects." @@ -1898,9 +2296,15 @@ msgstr "" msgid "SortOptions|Weight" msgstr "" +msgid "Source" +msgstr "" + msgid "Source code" msgstr "ソースコード" +msgid "Source is not available" +msgstr "" + msgid "Spam Logs" msgstr "" @@ -1919,6 +2323,9 @@ msgstr "この変更で %{new_merge_request} を作成する" msgid "Start the Runner!" msgstr "" +msgid "Stopped" +msgstr "" + msgid "Subgroups" msgstr "" @@ -1938,6 +2345,75 @@ msgstr[0] "タグ" msgid "Tags" msgstr "タグ" +msgid "TagsPage|Browse commits" +msgstr "" + +msgid "TagsPage|Browse files" +msgstr "" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "" + +msgid "TagsPage|Cancel" +msgstr "" + +msgid "TagsPage|Create tag" +msgstr "" + +msgid "TagsPage|Delete tag" +msgstr "" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "" + +msgid "TagsPage|Edit release notes" +msgstr "" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "" + +msgid "TagsPage|Filter by tag name" +msgstr "" + +msgid "TagsPage|New Tag" +msgstr "" + +msgid "TagsPage|New tag" +msgstr "" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "" + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "" + +msgid "TagsPage|Release notes" +msgstr "" + +msgid "TagsPage|Repository has no tags yet." +msgstr "" + +msgid "TagsPage|Sort by" +msgstr "" + +msgid "TagsPage|Tags" +msgstr "" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "" + +msgid "TagsPage|This tag has no release notes." +msgstr "" + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "" + +msgid "TagsPage|protected" +msgstr "" + msgid "Target Branch" msgstr "ターゲットブランチ" @@ -2019,6 +2495,9 @@ msgstr "得られた一連のデータを小さい順に並べたときに中央 msgid "There are problems accessing Git storage: " msgstr "" +msgid "This board\\'s scope is reduced" +msgstr "" + msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "" @@ -2040,6 +2519,9 @@ msgstr "空レポジトリーを作成または既存レポジトリーをイン msgid "This merge request is locked." msgstr "" +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "課題が計画されるまでの時間" @@ -2186,15 +2668,27 @@ msgstr[0] "分" msgid "Time|s" msgstr "秒" +msgid "Title" +msgstr "" + msgid "Total Time" msgstr "合計時間" +msgid "Total issue time spent" +msgstr "" + msgid "Total test time for all commits/merges" msgstr "すべてのコミット/マージの合計テスト時間" msgid "Track activity with Contribution Analytics." msgstr "" +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "" + +msgid "Turn on Service Desk" +msgstr "" + msgid "Unlock" msgstr "" @@ -2231,6 +2725,9 @@ msgstr "ファイルをアップロード" msgid "UploadLink|click to upload" msgstr "クリックしてアップロード" +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "" + msgid "Use the following registration token during setup:" msgstr "" @@ -2264,6 +2761,9 @@ msgstr "このデータを参照したいですか?アクセスするには管 msgid "We don't have enough data to show this stage." msgstr "データ不足のため、このステージの表示はできません。" +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "" + msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." msgstr "" @@ -2393,12 +2893,6 @@ msgstr "元のプロジェクト (%{forked_from_project}) とのリレーショ msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "%{project_name_with_namespace} プロジェクトを別のオーナーに移譲しようとしています。本当によろしいですか?" -msgid "You are on a read-only GitLab instance." -msgstr "" - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "" - msgid "You can only add files when you are on a branch" msgstr "ファイルを追加するには、どこかのブランチにいなければいけません" @@ -2438,6 +2932,9 @@ msgstr "%{set_password_link} でアカウントのパスワードがセットさ msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" msgstr "%{add_ssh_key_link} をプロファイルに追加していないので、プロジェクトにソースコードをプッシュ、プルできません" +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "" + msgid "Your comment will not be visible to the public." msgstr "" @@ -2450,6 +2947,12 @@ msgstr "名前" msgid "Your projects" msgstr "" +msgid "branch name" +msgstr "" + +msgid "by" +msgstr "" + msgid "commit" msgstr "" @@ -2473,6 +2976,9 @@ msgstr "" msgid "personal access token" msgstr "" +msgid "source" +msgstr "" + msgid "to help your contributors communicate effectively!" msgstr "" diff --git a/locale/ko/gitlab.po b/locale/ko/gitlab.po index d6c1ff2deeb..9ec3d395c15 100644 --- a/locale/ko/gitlab.po +++ b/locale/ko/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-03 12:31-0400\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 04:41-0500\n" "Last-Translator: gitlab \n" "Language-Team: Korean\n" "Language: ko_KR\n" @@ -51,6 +51,9 @@ msgid "%{storage_name}: failed storage access attempt on host:" msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:" msgstr[0] "" +msgid "%{text} is available" +msgstr "" + msgid "(checkout the %{link} for information on how to install it)." msgstr "설치 방법에 대한 정보를 얻기 위해 %{link} 를 체크아웃하세요." @@ -109,9 +112,6 @@ msgstr "" msgid "Add License" msgstr "라이선스 추가" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "프로필에 SSH 키를 추가하여 SSH를 통해 Pull 하거나 Push합니다." - msgid "Add new directory" msgstr "새 디렉토리 추가" @@ -124,6 +124,15 @@ msgstr "" msgid "All" msgstr "전체" +msgid "An error occurred when toggling the notification subscription" +msgstr "" + +msgid "An error occurred when updating the issue weight" +msgstr "" + +msgid "An error occurred while fetching sidebar data" +msgstr "" + msgid "An error occurred. Please try again." msgstr "" @@ -133,6 +142,12 @@ msgstr "" msgid "Applications" msgstr "" +msgid "Apr" +msgstr "" + +msgid "April" +msgstr "" + msgid "Archived project! Repository is read-only" msgstr "프로젝트가 보관되었습니다! 저장소는 읽기만 가능합니다." @@ -160,6 +175,12 @@ msgstr "" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "드래그 & 드롭 또는 %{upload_link}" +msgid "Aug" +msgstr "" + +msgid "August" +msgstr "" + msgid "Authentication Log" msgstr "" @@ -193,6 +214,9 @@ msgstr "" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." msgstr "" +msgid "Available" +msgstr "" + msgid "Billing" msgstr "" @@ -257,6 +281,12 @@ msgstr "%{branch_name} 브랜치가 생성되었습니다. 자 msgid "Branch has changed" msgstr "" +msgid "Branch is already taken" +msgstr "" + +msgid "Branch name" +msgstr "" + msgid "BranchSwitcherPlaceholder|Search branches" msgstr "브랜치 검색" @@ -404,6 +434,12 @@ msgstr "차트" msgid "Chat" msgstr "" +msgid "Checking %{text} availability…" +msgstr "" + +msgid "Checking branch availability..." +msgstr "" + msgid "Cherry-pick this commit" msgstr "이 커밋을 Cherry-pick" @@ -479,7 +515,40 @@ msgstr "" msgid "Cluster" msgstr "" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "" + +msgid "ClusterIntegration|API URL" +msgstr "" + +msgid "ClusterIntegration|Active" +msgstr "" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "" + +msgid "ClusterIntegration|Add cluster" +msgstr "" + +msgid "ClusterIntegration|All" +msgstr "" + +msgid "ClusterIntegration|Applications" +msgstr "" + +msgid "ClusterIntegration|CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "" + +msgid "ClusterIntegration|Cluster" msgstr "" msgid "ClusterIntegration|Cluster details" @@ -503,21 +572,54 @@ msgstr "" msgid "ClusterIntegration|Cluster name" msgstr "" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" +msgstr "" + +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "" + +msgid "ClusterIntegration|Copy API URL" +msgstr "" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Copy Token" msgstr "" msgid "ClusterIntegration|Copy cluster name" msgstr "" +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "" + msgid "ClusterIntegration|Create cluster" msgstr "" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Create on GKE" msgstr "" msgid "ClusterIntegration|Enable cluster integration" msgstr "" +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "" + +msgid "ClusterIntegration|Environment pattern" +msgstr "" + +msgid "ClusterIntegration|GKE pricing" +msgstr "" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "" + msgid "ClusterIntegration|Google Cloud Platform project ID" msgstr "" @@ -527,27 +629,75 @@ msgstr "" msgid "ClusterIntegration|Google Kubernetes Engine project" msgstr "" +msgid "ClusterIntegration|Helm Tiller" +msgstr "" + +msgid "ClusterIntegration|Inactive" +msgstr "" + +msgid "ClusterIntegration|Ingress" +msgstr "" + +msgid "ClusterIntegration|Install" +msgstr "" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "" + +msgid "ClusterIntegration|Installed" +msgstr "" + +msgid "ClusterIntegration|Installing" +msgstr "" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "" + msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "" + msgid "ClusterIntegration|Machine type" msgstr "" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" msgstr "" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" msgstr "" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" msgstr "" +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "" + +msgid "ClusterIntegration|Note:" +msgstr "" + msgid "ClusterIntegration|Number of nodes" msgstr "" +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" +msgstr "" + msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgstr "" +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "" + +msgid "ClusterIntegration|Project ID" +msgstr "" + +msgid "ClusterIntegration|Project namespace" +msgstr "" + msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "" @@ -560,7 +710,13 @@ msgstr "" msgid "ClusterIntegration|Remove integration" msgstr "" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "" + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "" + +msgid "ClusterIntegration|Save changes" msgstr "" msgid "ClusterIntegration|See and edit the details for your cluster" @@ -575,15 +731,33 @@ msgstr "" msgid "ClusterIntegration|See zones" msgstr "" +msgid "ClusterIntegration|Service token" +msgstr "" + +msgid "ClusterIntegration|Show" +msgstr "" + msgid "ClusterIntegration|Something went wrong on our end." msgstr "" msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" msgstr "" +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "" + msgid "ClusterIntegration|Toggle Cluster" msgstr "" +msgid "ClusterIntegration|Token" +msgstr "" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "" @@ -599,9 +773,15 @@ msgstr "" msgid "ClusterIntegration|cluster" msgstr "" +msgid "ClusterIntegration|documentation" +msgstr "" + msgid "ClusterIntegration|help page" msgstr "" +msgid "ClusterIntegration|installing applications" +msgstr "" + msgid "ClusterIntegration|meets the requirements" msgstr "" @@ -615,10 +795,6 @@ msgid "Commit" msgid_plural "Commits" msgstr[0] "커밋" -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "" - msgid "Commit Message" msgstr "" @@ -700,6 +876,15 @@ msgstr "기여에 대한 안내" msgid "Contributors" msgstr "기여해 주신 분들" +msgid "ContributorsPage|Building repository graph." +msgstr "" + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "" + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "" + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" msgstr "" @@ -727,6 +912,9 @@ msgstr "디렉토리 만들기" msgid "Create empty bare repository" msgstr "빈 bare 저장소 만들기" +msgid "Create epic" +msgstr "" + msgid "Create file" msgstr "" @@ -754,6 +942,9 @@ msgstr "태그" msgid "CreateTokenToCloneLink|create a personal access token" msgstr "개인 액세스 토큰 만들기" +msgid "Creating epic" +msgstr "" + msgid "Cron Timezone" msgstr "Cron 시간대" @@ -799,6 +990,12 @@ msgstr "" msgid "DashboardProjects|Personal" msgstr "" +msgid "Dec" +msgstr "" + +msgid "December" +msgstr "" + msgid "Define a custom pattern with cron syntax" msgstr "cron 구문을 사용하여 사용자 정의 패턴 정의" @@ -872,6 +1069,72 @@ msgstr "파이프라인 스케줄 편집 %{id}" msgid "Emails" msgstr "" +msgid "Environments|An error occurred while fetching the environments." +msgstr "" + +msgid "Environments|An error occurred while making the request." +msgstr "" + +msgid "Environments|Commit" +msgstr "" + +msgid "Environments|Deployment" +msgstr "" + +msgid "Environments|Environment" +msgstr "" + +msgid "Environments|Environments" +msgstr "" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "" + +msgid "Environments|Job" +msgstr "" + +msgid "Environments|New environment" +msgstr "" + +msgid "Environments|No deployments yet" +msgstr "" + +msgid "Environments|Open" +msgstr "" + +msgid "Environments|Re-deploy" +msgstr "" + +msgid "Environments|Read more about environments" +msgstr "" + +msgid "Environments|Rollback" +msgstr "" + +msgid "Environments|Show all" +msgstr "" + +msgid "Environments|Updated" +msgstr "" + +msgid "Environments|You don't have any environments right now." +msgstr "" + +msgid "Epic will be removed! Are you sure?" +msgstr "" + +msgid "Epics" +msgstr "" + +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" +msgstr "" + +msgid "Error creating epic" +msgstr "" + +msgid "Error occurred when toggling the notification subscription" +msgstr "" + msgid "EventFilterBy|Filter by all" msgstr "모든 값을 기준으로 필터" @@ -911,6 +1174,12 @@ msgstr "소유자를 변경하지 못했습니다" msgid "Failed to remove the pipeline schedule" msgstr "파이프라인 스케줄을 제거하지 못했습니다." +msgid "Feb" +msgstr "" + +msgid "February" +msgstr "" + msgid "File name" msgstr "" @@ -957,6 +1226,21 @@ msgstr "" msgid "Geo Nodes" msgstr "" +msgid "GeoNodeSyncStatus|Failed" +msgstr "" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "" + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "" + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "" + msgid "Geo|File sync capacity" msgstr "" @@ -1020,9 +1304,6 @@ msgstr "" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "" -msgid "GroupsTreeRole|as" -msgstr "" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "" @@ -1053,6 +1334,9 @@ msgstr "" msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "" +msgid "Have your users email" +msgstr "" + msgid "Health Check" msgstr "헬스 체크" @@ -1111,9 +1395,6 @@ msgstr "Cycle Analytics 소개" msgid "Issue board focus mode" msgstr "" -msgid "Issue boards with milestones" -msgstr "" - msgid "Issue events" msgstr "이슈 이벤트" @@ -1126,6 +1407,24 @@ msgstr "" msgid "Issues" msgstr "" +msgid "Jan" +msgstr "" + +msgid "January" +msgstr "" + +msgid "Jul" +msgstr "" + +msgid "July" +msgstr "" + +msgid "Jun" +msgstr "" + +msgid "June" +msgstr "" + msgid "LFSStatus|Disabled" msgstr "Disabled" @@ -1197,9 +1496,18 @@ msgstr "" msgid "Login" msgstr "" +msgid "Mar" +msgstr "" + +msgid "March" +msgstr "" + msgid "Maximum git storage failures" msgstr "" +msgid "May" +msgstr "" + msgid "Median" msgstr "중앙값" @@ -1243,9 +1551,15 @@ msgstr "새로운 파이프라인 일정" msgid "New branch" msgstr "새 브랜치" +msgid "New branch unavailable" +msgstr "" + msgid "New directory" msgstr "새 디렉토리" +msgid "New epic" +msgstr "" + msgid "New file" msgstr "새 파일" @@ -1282,6 +1596,9 @@ msgstr "저장소 없음" msgid "No schedules" msgstr "일정 없음" +msgid "No time spent" +msgstr "" + msgid "None" msgstr "" @@ -1348,18 +1665,33 @@ msgstr "Watch" msgid "Notifications" msgstr "" +msgid "Nov" +msgstr "" + +msgid "November" +msgstr "" + msgid "Number of access attempts" msgstr "" msgid "Number of failures before backing off" msgstr "" +msgid "Oct" +msgstr "" + +msgid "October" +msgstr "" + msgid "OfSearchInADropdown|Filter" msgstr "필터" msgid "Only project members can comment." msgstr "" +msgid "Opened" +msgstr "" + msgid "OpenedNDaysAgo|Opened" msgstr "열린" @@ -1492,6 +1824,9 @@ msgstr "스테이징" msgid "Pipeline|with stages" msgstr "스테이징" +msgid "Please solve the reCAPTCHA" +msgstr "" + msgid "Preferences" msgstr "" @@ -1597,9 +1932,15 @@ msgstr "그래프" msgid "ProjectSettings|Contact an admin to change this setting." msgstr "" +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "" + msgid "ProjectSettings|Only signed commits can be pushed to this repository." msgstr "" +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "" + msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." msgstr "" @@ -1636,6 +1977,39 @@ msgstr "" msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "" +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "" + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "" + +msgid "PrometheusService|Metrics" +msgstr "" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "" + +msgid "PrometheusService|Missing environment variable" +msgstr "" + +msgid "PrometheusService|Monitored" +msgstr "" + +msgid "PrometheusService|More information" +msgstr "" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "" + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" +msgstr "" + +msgid "PrometheusService|Prometheus monitoring" +msgstr "" + +msgid "PrometheusService|View environments" +msgstr "" + msgid "Public - The group and any public projects can be viewed without any authentication." msgstr "" @@ -1732,6 +2106,9 @@ msgstr "" msgid "Scheduling Pipelines" msgstr "파이프라인 스케줄링" +msgid "Scoped issue boards" +msgstr "" + msgid "Search branches and tags" msgstr "브랜치 및 태그 검색" @@ -1753,6 +2130,12 @@ msgstr "시간대 선택" msgid "Select target branch" msgstr "대상 브랜치 선택" +msgid "Sep" +msgstr "" + +msgid "September" +msgstr "" + msgid "Service Templates" msgstr "" @@ -1784,13 +2167,28 @@ msgid "Showing %d event" msgid_plural "Showing %d events" msgstr[0] "%d 개의 이벤트 표시 중" +msgid "Sidebar|Change weight" +msgstr "" + +msgid "Sidebar|Edit" +msgstr "" + +msgid "Sidebar|No" +msgstr "" + +msgid "Sidebar|None" +msgstr "" + +msgid "Sidebar|Weight" +msgstr "" + msgid "Snippets" msgstr "" msgid "Something went wrong on our end." msgstr "" -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" msgstr "" msgid "Something went wrong while fetching the projects." @@ -1898,9 +2296,15 @@ msgstr "" msgid "SortOptions|Weight" msgstr "" +msgid "Source" +msgstr "" + msgid "Source code" msgstr "소스 코드" +msgid "Source is not available" +msgstr "" + msgid "Spam Logs" msgstr "" @@ -1919,6 +2323,9 @@ msgstr "이 변경 사항으로 %{new_merge_request} 을 시작하십시오." msgid "Start the Runner!" msgstr "Runner 시작!" +msgid "Stopped" +msgstr "" + msgid "Subgroups" msgstr "" @@ -1938,6 +2345,75 @@ msgstr[0] "태그" msgid "Tags" msgstr "태그 " +msgid "TagsPage|Browse commits" +msgstr "" + +msgid "TagsPage|Browse files" +msgstr "" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "" + +msgid "TagsPage|Cancel" +msgstr "" + +msgid "TagsPage|Create tag" +msgstr "" + +msgid "TagsPage|Delete tag" +msgstr "" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "" + +msgid "TagsPage|Edit release notes" +msgstr "" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "" + +msgid "TagsPage|Filter by tag name" +msgstr "" + +msgid "TagsPage|New Tag" +msgstr "" + +msgid "TagsPage|New tag" +msgstr "" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "" + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "" + +msgid "TagsPage|Release notes" +msgstr "" + +msgid "TagsPage|Repository has no tags yet." +msgstr "" + +msgid "TagsPage|Sort by" +msgstr "" + +msgid "TagsPage|Tags" +msgstr "" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "" + +msgid "TagsPage|This tag has no release notes." +msgstr "" + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "" + +msgid "TagsPage|protected" +msgstr "" + msgid "Target Branch" msgstr "대상 브랜치" @@ -2019,6 +2495,9 @@ msgstr "값은 일련의 관측 값 중점에 있습니다. 예를 들어, 3, 5, msgid "There are problems accessing Git storage: " msgstr "git storage에 접근하는데 문제가 발생했습니다. " +msgid "This board\\'s scope is reduced" +msgstr "" + msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "" @@ -2040,6 +2519,9 @@ msgstr "즉, 빈 저장소를 만들거나 기존 저장소를 가져올 때까 msgid "This merge request is locked." msgstr "" +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "이슈가 스케줄되기 전의 시간" @@ -2186,15 +2668,27 @@ msgstr[0] "분" msgid "Time|s" msgstr "초" +msgid "Title" +msgstr "" + msgid "Total Time" msgstr "시간 합계:" +msgid "Total issue time spent" +msgstr "" + msgid "Total test time for all commits/merges" msgstr "모든 커밋 / 머지의 총 테스트 시간" msgid "Track activity with Contribution Analytics." msgstr "" +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "" + +msgid "Turn on Service Desk" +msgstr "" + msgid "Unlock" msgstr "" @@ -2231,6 +2725,9 @@ msgstr "파일 업로드" msgid "UploadLink|click to upload" msgstr "업로드하려면 클릭하십시오." +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "" + msgid "Use the following registration token during setup:" msgstr "설정 중에 다음 등록 토큰 이용 : " @@ -2264,6 +2761,9 @@ msgstr "이 데이터를 보고 싶은가요? 관리자에게 액세스 권한 msgid "We don't have enough data to show this stage." msgstr "이 단계를 보여주기에 충분한 데이터가 없습니다." +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "" + msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." msgstr "" @@ -2393,12 +2893,6 @@ msgstr "포크 관계를 소스 프로젝트 %{forked_from_project}에 대해 msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "%{project_name_with_namespace}을 다른 소유자에게 이전하려고합니다. \"정말로\" 확실합니까?" -msgid "You are on a read-only GitLab instance." -msgstr "" - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "" - msgid "You can only add files when you are on a branch" msgstr "브랜치에 있을 때에만 파일을 추가 할 수 있습니다." @@ -2438,6 +2932,9 @@ msgstr "당신의 계정에 %{set_password_link} 을 하기 전에는 %{protocol msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" msgstr "당신의 프로필에 %{add_ssh_key_link} 를 하기 전에는 SSH를 통해 프로젝트 코드를 Pull 하거나 Push 할 수 없습니다" +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "" + msgid "Your comment will not be visible to the public." msgstr "" @@ -2450,6 +2947,12 @@ msgstr "귀하의 이름" msgid "Your projects" msgstr "" +msgid "branch name" +msgstr "" + +msgid "by" +msgstr "" + msgid "commit" msgstr "" @@ -2473,6 +2976,9 @@ msgstr "" msgid "personal access token" msgstr "" +msgid "source" +msgstr "" + msgid "to help your contributors communicate effectively!" msgstr "" diff --git a/locale/nl_NL/gitlab.po b/locale/nl_NL/gitlab.po index 68d1f809bb4..0abb727037c 100644 --- a/locale/nl_NL/gitlab.po +++ b/locale/nl_NL/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-03 12:31-0400\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 04:42-0500\n" "Last-Translator: gitlab \n" "Language-Team: Dutch\n" "Language: nl_NL\n" @@ -56,6 +56,9 @@ msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts msgstr[0] "" msgstr[1] "" +msgid "%{text} is available" +msgstr "" + msgid "(checkout the %{link} for information on how to install it)." msgstr "(bekijk de %{link} voor meer info over hoe je het kan installeren)." @@ -101,7 +104,7 @@ msgid "Activity" msgstr "Activiteit" msgid "Add" -msgstr "Voeg toe" +msgstr "" msgid "Add Changelog" msgstr "Changelog toevoegen" @@ -115,9 +118,6 @@ msgstr "" msgid "Add License" msgstr "Licentie toevoegen" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "" - msgid "Add new directory" msgstr "Nieuwe map toevoegen" @@ -130,6 +130,15 @@ msgstr "" msgid "All" msgstr "Alles" +msgid "An error occurred when toggling the notification subscription" +msgstr "" + +msgid "An error occurred when updating the issue weight" +msgstr "" + +msgid "An error occurred while fetching sidebar data" +msgstr "" + msgid "An error occurred. Please try again." msgstr "" @@ -139,6 +148,12 @@ msgstr "Uiterlijk" msgid "Applications" msgstr "Applicaties" +msgid "Apr" +msgstr "" + +msgid "April" +msgstr "" + msgid "Archived project! Repository is read-only" msgstr "" @@ -166,6 +181,12 @@ msgstr "" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "" +msgid "Aug" +msgstr "" + +msgid "August" +msgstr "" + msgid "Authentication Log" msgstr "" @@ -199,8 +220,11 @@ msgstr "" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." msgstr "" +msgid "Available" +msgstr "" + msgid "Billing" -msgstr "Facturatie" +msgstr "" msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan." msgstr "" @@ -264,6 +288,12 @@ msgstr "" msgid "Branch has changed" msgstr "" +msgid "Branch is already taken" +msgstr "" + +msgid "Branch name" +msgstr "" + msgid "BranchSwitcherPlaceholder|Search branches" msgstr "BranchSwitcherPlaceholder|Zoek branches" @@ -411,6 +441,12 @@ msgstr "Grafieken" msgid "Chat" msgstr "Chat" +msgid "Checking %{text} availability…" +msgstr "" + +msgid "Checking branch availability..." +msgstr "" + msgid "Cherry-pick this commit" msgstr "Cherry-pick deze commit" @@ -486,7 +522,40 @@ msgstr "" msgid "Cluster" msgstr "" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "" + +msgid "ClusterIntegration|API URL" +msgstr "" + +msgid "ClusterIntegration|Active" +msgstr "" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "" + +msgid "ClusterIntegration|Add cluster" +msgstr "" + +msgid "ClusterIntegration|All" +msgstr "" + +msgid "ClusterIntegration|Applications" +msgstr "" + +msgid "ClusterIntegration|CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "" + +msgid "ClusterIntegration|Cluster" msgstr "" msgid "ClusterIntegration|Cluster details" @@ -510,21 +579,54 @@ msgstr "" msgid "ClusterIntegration|Cluster name" msgstr "" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" +msgstr "" + +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "" + +msgid "ClusterIntegration|Copy API URL" +msgstr "" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Copy Token" msgstr "" msgid "ClusterIntegration|Copy cluster name" msgstr "" +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "" + msgid "ClusterIntegration|Create cluster" msgstr "" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Create on GKE" msgstr "" msgid "ClusterIntegration|Enable cluster integration" msgstr "" +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "" + +msgid "ClusterIntegration|Environment pattern" +msgstr "" + +msgid "ClusterIntegration|GKE pricing" +msgstr "" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "" + msgid "ClusterIntegration|Google Cloud Platform project ID" msgstr "" @@ -534,27 +636,75 @@ msgstr "" msgid "ClusterIntegration|Google Kubernetes Engine project" msgstr "" +msgid "ClusterIntegration|Helm Tiller" +msgstr "" + +msgid "ClusterIntegration|Inactive" +msgstr "" + +msgid "ClusterIntegration|Ingress" +msgstr "" + +msgid "ClusterIntegration|Install" +msgstr "" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "" + +msgid "ClusterIntegration|Installed" +msgstr "" + +msgid "ClusterIntegration|Installing" +msgstr "" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "" + msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "" + msgid "ClusterIntegration|Machine type" msgstr "" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" msgstr "" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" msgstr "" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" msgstr "" +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "" + +msgid "ClusterIntegration|Note:" +msgstr "" + msgid "ClusterIntegration|Number of nodes" msgstr "" +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" +msgstr "" + msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgstr "" +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "" + +msgid "ClusterIntegration|Project ID" +msgstr "" + +msgid "ClusterIntegration|Project namespace" +msgstr "" + msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "" @@ -567,7 +717,13 @@ msgstr "" msgid "ClusterIntegration|Remove integration" msgstr "" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "" + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "" + +msgid "ClusterIntegration|Save changes" msgstr "" msgid "ClusterIntegration|See and edit the details for your cluster" @@ -582,15 +738,33 @@ msgstr "" msgid "ClusterIntegration|See zones" msgstr "" +msgid "ClusterIntegration|Service token" +msgstr "" + +msgid "ClusterIntegration|Show" +msgstr "" + msgid "ClusterIntegration|Something went wrong on our end." msgstr "" msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" msgstr "" +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "" + msgid "ClusterIntegration|Toggle Cluster" msgstr "" +msgid "ClusterIntegration|Token" +msgstr "" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "" @@ -606,9 +780,15 @@ msgstr "" msgid "ClusterIntegration|cluster" msgstr "" +msgid "ClusterIntegration|documentation" +msgstr "" + msgid "ClusterIntegration|help page" msgstr "" +msgid "ClusterIntegration|installing applications" +msgstr "" + msgid "ClusterIntegration|meets the requirements" msgstr "" @@ -623,11 +803,6 @@ msgid_plural "Commits" msgstr[0] "" msgstr[1] "" -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "" -msgstr[1] "" - msgid "Commit Message" msgstr "" @@ -709,6 +884,15 @@ msgstr "" msgid "Contributors" msgstr "" +msgid "ContributorsPage|Building repository graph." +msgstr "" + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "" + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "" + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" msgstr "" @@ -736,6 +920,9 @@ msgstr "Maak map aan" msgid "Create empty bare repository" msgstr "" +msgid "Create epic" +msgstr "" + msgid "Create file" msgstr "" @@ -763,6 +950,9 @@ msgstr "" msgid "CreateTokenToCloneLink|create a personal access token" msgstr "" +msgid "Creating epic" +msgstr "" + msgid "Cron Timezone" msgstr "" @@ -808,6 +998,12 @@ msgstr "" msgid "DashboardProjects|Personal" msgstr "" +msgid "Dec" +msgstr "" + +msgid "December" +msgstr "" + msgid "Define a custom pattern with cron syntax" msgstr "" @@ -882,6 +1078,72 @@ msgstr "" msgid "Emails" msgstr "" +msgid "Environments|An error occurred while fetching the environments." +msgstr "" + +msgid "Environments|An error occurred while making the request." +msgstr "" + +msgid "Environments|Commit" +msgstr "" + +msgid "Environments|Deployment" +msgstr "" + +msgid "Environments|Environment" +msgstr "" + +msgid "Environments|Environments" +msgstr "" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "" + +msgid "Environments|Job" +msgstr "" + +msgid "Environments|New environment" +msgstr "" + +msgid "Environments|No deployments yet" +msgstr "" + +msgid "Environments|Open" +msgstr "" + +msgid "Environments|Re-deploy" +msgstr "" + +msgid "Environments|Read more about environments" +msgstr "" + +msgid "Environments|Rollback" +msgstr "" + +msgid "Environments|Show all" +msgstr "" + +msgid "Environments|Updated" +msgstr "" + +msgid "Environments|You don't have any environments right now." +msgstr "" + +msgid "Epic will be removed! Are you sure?" +msgstr "" + +msgid "Epics" +msgstr "" + +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" +msgstr "" + +msgid "Error creating epic" +msgstr "" + +msgid "Error occurred when toggling the notification subscription" +msgstr "" + msgid "EventFilterBy|Filter by all" msgstr "" @@ -921,6 +1183,12 @@ msgstr "" msgid "Failed to remove the pipeline schedule" msgstr "" +msgid "Feb" +msgstr "" + +msgid "February" +msgstr "" + msgid "File name" msgstr "" @@ -968,6 +1236,21 @@ msgstr "" msgid "Geo Nodes" msgstr "" +msgid "GeoNodeSyncStatus|Failed" +msgstr "" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "" + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "" + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "" + msgid "Geo|File sync capacity" msgstr "" @@ -1031,9 +1314,6 @@ msgstr "" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "" -msgid "GroupsTreeRole|as" -msgstr "" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "" @@ -1064,6 +1344,9 @@ msgstr "" msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "" +msgid "Have your users email" +msgstr "" + msgid "Health Check" msgstr "" @@ -1123,9 +1406,6 @@ msgstr "" msgid "Issue board focus mode" msgstr "" -msgid "Issue boards with milestones" -msgstr "" - msgid "Issue events" msgstr "" @@ -1138,6 +1418,24 @@ msgstr "" msgid "Issues" msgstr "" +msgid "Jan" +msgstr "" + +msgid "January" +msgstr "" + +msgid "Jul" +msgstr "" + +msgid "July" +msgstr "" + +msgid "Jun" +msgstr "" + +msgid "June" +msgstr "" + msgid "LFSStatus|Disabled" msgstr "" @@ -1211,9 +1509,18 @@ msgstr "" msgid "Login" msgstr "" +msgid "Mar" +msgstr "" + +msgid "March" +msgstr "" + msgid "Maximum git storage failures" msgstr "" +msgid "May" +msgstr "" + msgid "Median" msgstr "" @@ -1258,9 +1565,15 @@ msgstr "" msgid "New branch" msgstr "" +msgid "New branch unavailable" +msgstr "" + msgid "New directory" msgstr "" +msgid "New epic" +msgstr "" + msgid "New file" msgstr "" @@ -1297,6 +1610,9 @@ msgstr "" msgid "No schedules" msgstr "" +msgid "No time spent" +msgstr "" + msgid "None" msgstr "" @@ -1363,18 +1679,33 @@ msgstr "" msgid "Notifications" msgstr "" +msgid "Nov" +msgstr "" + +msgid "November" +msgstr "" + msgid "Number of access attempts" msgstr "" msgid "Number of failures before backing off" msgstr "" +msgid "Oct" +msgstr "" + +msgid "October" +msgstr "" + msgid "OfSearchInADropdown|Filter" msgstr "" msgid "Only project members can comment." msgstr "" +msgid "Opened" +msgstr "" + msgid "OpenedNDaysAgo|Opened" msgstr "Geopend" @@ -1507,6 +1838,9 @@ msgstr "" msgid "Pipeline|with stages" msgstr "" +msgid "Please solve the reCAPTCHA" +msgstr "" + msgid "Preferences" msgstr "" @@ -1612,9 +1946,15 @@ msgstr "" msgid "ProjectSettings|Contact an admin to change this setting." msgstr "" +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "" + msgid "ProjectSettings|Only signed commits can be pushed to this repository." msgstr "" +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "" + msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." msgstr "" @@ -1651,6 +1991,39 @@ msgstr "" msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "" +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "" + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "" + +msgid "PrometheusService|Metrics" +msgstr "" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "" + +msgid "PrometheusService|Missing environment variable" +msgstr "" + +msgid "PrometheusService|Monitored" +msgstr "" + +msgid "PrometheusService|More information" +msgstr "" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "" + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" +msgstr "" + +msgid "PrometheusService|Prometheus monitoring" +msgstr "" + +msgid "PrometheusService|View environments" +msgstr "" + msgid "Public - The group and any public projects can be viewed without any authentication." msgstr "" @@ -1747,6 +2120,9 @@ msgstr "" msgid "Scheduling Pipelines" msgstr "" +msgid "Scoped issue boards" +msgstr "" + msgid "Search branches and tags" msgstr "" @@ -1768,6 +2144,12 @@ msgstr "" msgid "Select target branch" msgstr "" +msgid "Sep" +msgstr "" + +msgid "September" +msgstr "" + msgid "Service Templates" msgstr "" @@ -1800,13 +2182,28 @@ msgid_plural "Showing %d events" msgstr[0] "" msgstr[1] "" +msgid "Sidebar|Change weight" +msgstr "" + +msgid "Sidebar|Edit" +msgstr "" + +msgid "Sidebar|No" +msgstr "" + +msgid "Sidebar|None" +msgstr "" + +msgid "Sidebar|Weight" +msgstr "" + msgid "Snippets" msgstr "" msgid "Something went wrong on our end." msgstr "" -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" msgstr "" msgid "Something went wrong while fetching the projects." @@ -1914,9 +2311,15 @@ msgstr "" msgid "SortOptions|Weight" msgstr "" +msgid "Source" +msgstr "" + msgid "Source code" msgstr "" +msgid "Source is not available" +msgstr "" + msgid "Spam Logs" msgstr "" @@ -1935,6 +2338,9 @@ msgstr "" msgid "Start the Runner!" msgstr "" +msgid "Stopped" +msgstr "" + msgid "Subgroups" msgstr "" @@ -1955,6 +2361,75 @@ msgstr[1] "" msgid "Tags" msgstr "" +msgid "TagsPage|Browse commits" +msgstr "" + +msgid "TagsPage|Browse files" +msgstr "" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "" + +msgid "TagsPage|Cancel" +msgstr "" + +msgid "TagsPage|Create tag" +msgstr "" + +msgid "TagsPage|Delete tag" +msgstr "" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "" + +msgid "TagsPage|Edit release notes" +msgstr "" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "" + +msgid "TagsPage|Filter by tag name" +msgstr "" + +msgid "TagsPage|New Tag" +msgstr "" + +msgid "TagsPage|New tag" +msgstr "" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "" + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "" + +msgid "TagsPage|Release notes" +msgstr "" + +msgid "TagsPage|Repository has no tags yet." +msgstr "" + +msgid "TagsPage|Sort by" +msgstr "" + +msgid "TagsPage|Tags" +msgstr "" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "" + +msgid "TagsPage|This tag has no release notes." +msgstr "" + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "" + +msgid "TagsPage|protected" +msgstr "" + msgid "Target Branch" msgstr "" @@ -2036,6 +2511,9 @@ msgstr "" msgid "There are problems accessing Git storage: " msgstr "" +msgid "This board\\'s scope is reduced" +msgstr "" + msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "" @@ -2057,6 +2535,9 @@ msgstr "" msgid "This merge request is locked." msgstr "" +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "" @@ -2205,15 +2686,27 @@ msgstr[1] "" msgid "Time|s" msgstr "s" +msgid "Title" +msgstr "" + msgid "Total Time" msgstr "" +msgid "Total issue time spent" +msgstr "" + msgid "Total test time for all commits/merges" msgstr "" msgid "Track activity with Contribution Analytics." msgstr "" +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "" + +msgid "Turn on Service Desk" +msgstr "" + msgid "Unlock" msgstr "" @@ -2250,6 +2743,9 @@ msgstr "" msgid "UploadLink|click to upload" msgstr "" +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "" + msgid "Use the following registration token during setup:" msgstr "" @@ -2283,6 +2779,9 @@ msgstr "" msgid "We don't have enough data to show this stage." msgstr "" +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "" + msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." msgstr "" @@ -2412,12 +2911,6 @@ msgstr "" msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "" -msgid "You are on a read-only GitLab instance." -msgstr "" - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "" - msgid "You can only add files when you are on a branch" msgstr "" @@ -2457,6 +2950,9 @@ msgstr "" msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" msgstr "" +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "" + msgid "Your comment will not be visible to the public." msgstr "" @@ -2469,6 +2965,12 @@ msgstr "" msgid "Your projects" msgstr "" +msgid "branch name" +msgstr "" + +msgid "by" +msgstr "" + msgid "commit" msgstr "" @@ -2494,6 +2996,9 @@ msgstr "" msgid "personal access token" msgstr "" +msgid "source" +msgstr "" + msgid "to help your contributors communicate effectively!" msgstr "" diff --git a/locale/pl_PL/gitlab.po b/locale/pl_PL/gitlab.po index c48909540b1..5b65c42097e 100644 --- a/locale/pl_PL/gitlab.po +++ b/locale/pl_PL/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-20 11:16-0500\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 04:41-0500\n" "Last-Translator: gitlab \n" "Language-Team: Polish\n" "Language: pl_PL\n" @@ -61,6 +61,9 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" +msgid "%{text} is available" +msgstr "" + msgid "(checkout the %{link} for information on how to install it)." msgstr "" @@ -121,9 +124,6 @@ msgstr "" msgid "Add License" msgstr "" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "" - msgid "Add new directory" msgstr "" @@ -136,6 +136,15 @@ msgstr "" msgid "All" msgstr "" +msgid "An error occurred when toggling the notification subscription" +msgstr "" + +msgid "An error occurred when updating the issue weight" +msgstr "" + +msgid "An error occurred while fetching sidebar data" +msgstr "" + msgid "An error occurred. Please try again." msgstr "" @@ -145,6 +154,12 @@ msgstr "" msgid "Applications" msgstr "" +msgid "Apr" +msgstr "" + +msgid "April" +msgstr "" + msgid "Archived project! Repository is read-only" msgstr "" @@ -172,6 +187,12 @@ msgstr "" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "" +msgid "Aug" +msgstr "" + +msgid "August" +msgstr "" + msgid "Authentication Log" msgstr "" @@ -205,6 +226,9 @@ msgstr "" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." msgstr "" +msgid "Available" +msgstr "" + msgid "Billing" msgstr "" @@ -271,6 +295,12 @@ msgstr "" msgid "Branch has changed" msgstr "" +msgid "Branch is already taken" +msgstr "" + +msgid "Branch name" +msgstr "" + msgid "BranchSwitcherPlaceholder|Search branches" msgstr "" @@ -418,6 +448,12 @@ msgstr "" msgid "Chat" msgstr "" +msgid "Checking %{text} availability…" +msgstr "" + +msgid "Checking branch availability..." +msgstr "" + msgid "Cherry-pick this commit" msgstr "" @@ -493,7 +529,40 @@ msgstr "" msgid "Cluster" msgstr "" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "" + +msgid "ClusterIntegration|API URL" +msgstr "" + +msgid "ClusterIntegration|Active" +msgstr "" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "" + +msgid "ClusterIntegration|Add cluster" +msgstr "" + +msgid "ClusterIntegration|All" +msgstr "" + +msgid "ClusterIntegration|Applications" +msgstr "" + +msgid "ClusterIntegration|CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "" + +msgid "ClusterIntegration|Cluster" msgstr "" msgid "ClusterIntegration|Cluster details" @@ -517,21 +586,54 @@ msgstr "" msgid "ClusterIntegration|Cluster name" msgstr "" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" +msgstr "" + +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "" + +msgid "ClusterIntegration|Copy API URL" +msgstr "" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Copy Token" msgstr "" msgid "ClusterIntegration|Copy cluster name" msgstr "" +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "" + msgid "ClusterIntegration|Create cluster" msgstr "" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Create on GKE" msgstr "" msgid "ClusterIntegration|Enable cluster integration" msgstr "" +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "" + +msgid "ClusterIntegration|Environment pattern" +msgstr "" + +msgid "ClusterIntegration|GKE pricing" +msgstr "" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "" + msgid "ClusterIntegration|Google Cloud Platform project ID" msgstr "" @@ -541,27 +643,75 @@ msgstr "" msgid "ClusterIntegration|Google Kubernetes Engine project" msgstr "" +msgid "ClusterIntegration|Helm Tiller" +msgstr "" + +msgid "ClusterIntegration|Inactive" +msgstr "" + +msgid "ClusterIntegration|Ingress" +msgstr "" + +msgid "ClusterIntegration|Install" +msgstr "" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "" + +msgid "ClusterIntegration|Installed" +msgstr "" + +msgid "ClusterIntegration|Installing" +msgstr "" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "" + msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "" + msgid "ClusterIntegration|Machine type" msgstr "" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" msgstr "" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" msgstr "" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" msgstr "" +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "" + +msgid "ClusterIntegration|Note:" +msgstr "" + msgid "ClusterIntegration|Number of nodes" msgstr "" +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" +msgstr "" + msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgstr "" +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "" + +msgid "ClusterIntegration|Project ID" +msgstr "" + +msgid "ClusterIntegration|Project namespace" +msgstr "" + msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "" @@ -574,7 +724,13 @@ msgstr "" msgid "ClusterIntegration|Remove integration" msgstr "" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "" + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "" + +msgid "ClusterIntegration|Save changes" msgstr "" msgid "ClusterIntegration|See and edit the details for your cluster" @@ -589,15 +745,33 @@ msgstr "" msgid "ClusterIntegration|See zones" msgstr "" +msgid "ClusterIntegration|Service token" +msgstr "" + +msgid "ClusterIntegration|Show" +msgstr "" + msgid "ClusterIntegration|Something went wrong on our end." msgstr "" msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" msgstr "" +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "" + msgid "ClusterIntegration|Toggle Cluster" msgstr "" +msgid "ClusterIntegration|Token" +msgstr "" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "" @@ -613,9 +787,15 @@ msgstr "" msgid "ClusterIntegration|cluster" msgstr "" +msgid "ClusterIntegration|documentation" +msgstr "" + msgid "ClusterIntegration|help page" msgstr "" +msgid "ClusterIntegration|installing applications" +msgstr "" + msgid "ClusterIntegration|meets the requirements" msgstr "" @@ -631,12 +811,6 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "" -msgstr[1] "" -msgstr[2] "" - msgid "Commit Message" msgstr "" @@ -718,6 +892,15 @@ msgstr "" msgid "Contributors" msgstr "" +msgid "ContributorsPage|Building repository graph." +msgstr "" + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "" + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "" + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" msgstr "" @@ -745,6 +928,9 @@ msgstr "" msgid "Create empty bare repository" msgstr "" +msgid "Create epic" +msgstr "" + msgid "Create file" msgstr "" @@ -772,6 +958,9 @@ msgstr "" msgid "CreateTokenToCloneLink|create a personal access token" msgstr "" +msgid "Creating epic" +msgstr "" + msgid "Cron Timezone" msgstr "" @@ -817,6 +1006,12 @@ msgstr "" msgid "DashboardProjects|Personal" msgstr "" +msgid "Dec" +msgstr "" + +msgid "December" +msgstr "" + msgid "Define a custom pattern with cron syntax" msgstr "" @@ -892,6 +1087,72 @@ msgstr "" msgid "Emails" msgstr "" +msgid "Environments|An error occurred while fetching the environments." +msgstr "" + +msgid "Environments|An error occurred while making the request." +msgstr "" + +msgid "Environments|Commit" +msgstr "" + +msgid "Environments|Deployment" +msgstr "" + +msgid "Environments|Environment" +msgstr "" + +msgid "Environments|Environments" +msgstr "" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "" + +msgid "Environments|Job" +msgstr "" + +msgid "Environments|New environment" +msgstr "" + +msgid "Environments|No deployments yet" +msgstr "" + +msgid "Environments|Open" +msgstr "" + +msgid "Environments|Re-deploy" +msgstr "" + +msgid "Environments|Read more about environments" +msgstr "" + +msgid "Environments|Rollback" +msgstr "" + +msgid "Environments|Show all" +msgstr "" + +msgid "Environments|Updated" +msgstr "" + +msgid "Environments|You don't have any environments right now." +msgstr "" + +msgid "Epic will be removed! Are you sure?" +msgstr "" + +msgid "Epics" +msgstr "" + +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" +msgstr "" + +msgid "Error creating epic" +msgstr "" + +msgid "Error occurred when toggling the notification subscription" +msgstr "" + msgid "EventFilterBy|Filter by all" msgstr "" @@ -931,6 +1192,12 @@ msgstr "" msgid "Failed to remove the pipeline schedule" msgstr "" +msgid "Feb" +msgstr "" + +msgid "February" +msgstr "" + msgid "File name" msgstr "" @@ -979,6 +1246,21 @@ msgstr "" msgid "Geo Nodes" msgstr "" +msgid "GeoNodeSyncStatus|Failed" +msgstr "" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "" + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "" + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "" + msgid "Geo|File sync capacity" msgstr "" @@ -1042,9 +1324,6 @@ msgstr "" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "" -msgid "GroupsTreeRole|as" -msgstr "" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "" @@ -1075,6 +1354,9 @@ msgstr "" msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "" +msgid "Have your users email" +msgstr "" + msgid "Health Check" msgstr "" @@ -1135,9 +1417,6 @@ msgstr "" msgid "Issue board focus mode" msgstr "" -msgid "Issue boards with milestones" -msgstr "" - msgid "Issue events" msgstr "" @@ -1150,6 +1429,24 @@ msgstr "" msgid "Issues" msgstr "" +msgid "Jan" +msgstr "" + +msgid "January" +msgstr "" + +msgid "Jul" +msgstr "" + +msgid "July" +msgstr "" + +msgid "Jun" +msgstr "" + +msgid "June" +msgstr "" + msgid "LFSStatus|Disabled" msgstr "" @@ -1225,9 +1522,18 @@ msgstr "" msgid "Login" msgstr "" +msgid "Mar" +msgstr "" + +msgid "March" +msgstr "" + msgid "Maximum git storage failures" msgstr "" +msgid "May" +msgstr "" + msgid "Median" msgstr "" @@ -1273,9 +1579,15 @@ msgstr "" msgid "New branch" msgstr "" +msgid "New branch unavailable" +msgstr "" + msgid "New directory" msgstr "" +msgid "New epic" +msgstr "" + msgid "New file" msgstr "" @@ -1312,6 +1624,9 @@ msgstr "" msgid "No schedules" msgstr "" +msgid "No time spent" +msgstr "" + msgid "None" msgstr "" @@ -1378,18 +1693,33 @@ msgstr "" msgid "Notifications" msgstr "" +msgid "Nov" +msgstr "" + +msgid "November" +msgstr "" + msgid "Number of access attempts" msgstr "" msgid "Number of failures before backing off" msgstr "" +msgid "Oct" +msgstr "" + +msgid "October" +msgstr "" + msgid "OfSearchInADropdown|Filter" msgstr "" msgid "Only project members can comment." msgstr "" +msgid "Opened" +msgstr "" + msgid "OpenedNDaysAgo|Opened" msgstr "" @@ -1522,6 +1852,9 @@ msgstr "" msgid "Pipeline|with stages" msgstr "" +msgid "Please solve the reCAPTCHA" +msgstr "" + msgid "Preferences" msgstr "" @@ -1627,9 +1960,15 @@ msgstr "" msgid "ProjectSettings|Contact an admin to change this setting." msgstr "" +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "" + msgid "ProjectSettings|Only signed commits can be pushed to this repository." msgstr "" +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "" + msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." msgstr "" @@ -1666,6 +2005,39 @@ msgstr "" msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "" +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "" + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "" + +msgid "PrometheusService|Metrics" +msgstr "" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "" + +msgid "PrometheusService|Missing environment variable" +msgstr "" + +msgid "PrometheusService|Monitored" +msgstr "" + +msgid "PrometheusService|More information" +msgstr "" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "" + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" +msgstr "" + +msgid "PrometheusService|Prometheus monitoring" +msgstr "" + +msgid "PrometheusService|View environments" +msgstr "" + msgid "Public - The group and any public projects can be viewed without any authentication." msgstr "" @@ -1762,6 +2134,9 @@ msgstr "" msgid "Scheduling Pipelines" msgstr "" +msgid "Scoped issue boards" +msgstr "" + msgid "Search branches and tags" msgstr "" @@ -1783,6 +2158,12 @@ msgstr "" msgid "Select target branch" msgstr "" +msgid "Sep" +msgstr "" + +msgid "September" +msgstr "" + msgid "Service Templates" msgstr "" @@ -1816,13 +2197,28 @@ msgstr[0] "" msgstr[1] "" msgstr[2] "" +msgid "Sidebar|Change weight" +msgstr "" + +msgid "Sidebar|Edit" +msgstr "" + +msgid "Sidebar|No" +msgstr "" + +msgid "Sidebar|None" +msgstr "" + +msgid "Sidebar|Weight" +msgstr "" + msgid "Snippets" msgstr "" msgid "Something went wrong on our end." msgstr "" -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" msgstr "" msgid "Something went wrong while fetching the projects." @@ -1930,9 +2326,15 @@ msgstr "" msgid "SortOptions|Weight" msgstr "" +msgid "Source" +msgstr "" + msgid "Source code" msgstr "" +msgid "Source is not available" +msgstr "" + msgid "Spam Logs" msgstr "" @@ -1951,6 +2353,9 @@ msgstr "" msgid "Start the Runner!" msgstr "" +msgid "Stopped" +msgstr "" + msgid "Subgroups" msgstr "" @@ -1972,6 +2377,75 @@ msgstr[2] "" msgid "Tags" msgstr "" +msgid "TagsPage|Browse commits" +msgstr "" + +msgid "TagsPage|Browse files" +msgstr "" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "" + +msgid "TagsPage|Cancel" +msgstr "" + +msgid "TagsPage|Create tag" +msgstr "" + +msgid "TagsPage|Delete tag" +msgstr "" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "" + +msgid "TagsPage|Edit release notes" +msgstr "" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "" + +msgid "TagsPage|Filter by tag name" +msgstr "" + +msgid "TagsPage|New Tag" +msgstr "" + +msgid "TagsPage|New tag" +msgstr "" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "" + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "" + +msgid "TagsPage|Release notes" +msgstr "" + +msgid "TagsPage|Repository has no tags yet." +msgstr "" + +msgid "TagsPage|Sort by" +msgstr "" + +msgid "TagsPage|Tags" +msgstr "" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "" + +msgid "TagsPage|This tag has no release notes." +msgstr "" + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "" + +msgid "TagsPage|protected" +msgstr "" + msgid "Target Branch" msgstr "" @@ -2053,6 +2527,9 @@ msgstr "" msgid "There are problems accessing Git storage: " msgstr "" +msgid "This board\\'s scope is reduced" +msgstr "" + msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "" @@ -2074,6 +2551,9 @@ msgstr "" msgid "This merge request is locked." msgstr "" +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "" @@ -2224,15 +2704,27 @@ msgstr[2] "" msgid "Time|s" msgstr "" +msgid "Title" +msgstr "" + msgid "Total Time" msgstr "" +msgid "Total issue time spent" +msgstr "" + msgid "Total test time for all commits/merges" msgstr "" msgid "Track activity with Contribution Analytics." msgstr "" +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "" + +msgid "Turn on Service Desk" +msgstr "" + msgid "Unlock" msgstr "" @@ -2269,6 +2761,9 @@ msgstr "" msgid "UploadLink|click to upload" msgstr "" +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "" + msgid "Use the following registration token during setup:" msgstr "" @@ -2302,6 +2797,9 @@ msgstr "" msgid "We don't have enough data to show this stage." msgstr "" +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "" + msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." msgstr "" @@ -2431,12 +2929,6 @@ msgstr "" msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "" -msgid "You are on a read-only GitLab instance." -msgstr "" - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "" - msgid "You can only add files when you are on a branch" msgstr "" @@ -2476,6 +2968,9 @@ msgstr "" msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" msgstr "" +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "" + msgid "Your comment will not be visible to the public." msgstr "" @@ -2488,6 +2983,12 @@ msgstr "" msgid "Your projects" msgstr "" +msgid "branch name" +msgstr "" + +msgid "by" +msgstr "" + msgid "commit" msgstr "" @@ -2515,6 +3016,9 @@ msgstr "" msgid "personal access token" msgstr "" +msgid "source" +msgstr "" + msgid "to help your contributors communicate effectively!" msgstr "" diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po index 78e0967c3bc..9fe1cc3c11a 100644 --- a/locale/pt_BR/gitlab.po +++ b/locale/pt_BR/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-18 12:51-0500\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 04:41-0500\n" "Last-Translator: gitlab \n" "Language-Team: Portuguese, Brazilian\n" "Language: pt_BR\n" @@ -56,6 +56,9 @@ msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts msgstr[0] "%{storage_name}: falha na tentativa de acesso ao storage no host:" msgstr[1] "%{storage_name}: %{failed_attempts} falhas de acesso ao storage:" +msgid "%{text} is available" +msgstr "%{text} está disponível" + msgid "(checkout the %{link} for information on how to install it)." msgstr "(veja o %{link} para informações de como instalar)." @@ -110,14 +113,11 @@ msgid "Add Contribution guide" msgstr "Adicionar Guia de contribuição" msgid "Add Group Webhooks and GitLab Enterprise Edition." -msgstr "Adicione o grupo de Webhooks e GitLab Enterprise Edition." +msgstr "Adicione o Webhooks de Grupos e GitLab Enterprise Edition." msgid "Add License" msgstr "Adicionar Licença" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "Adicionar chave SSH ao seu perfil para fazer pull ou push via SSH." - msgid "Add new directory" msgstr "Adicionar novo diretório" @@ -130,6 +130,15 @@ msgstr "Configurações avançadas" msgid "All" msgstr "Todos" +msgid "An error occurred when toggling the notification subscription" +msgstr "Erro ao modificar notificação de assinatura" + +msgid "An error occurred when updating the issue weight" +msgstr "Um erro aconteceu ao atualizar o peso da issue" + +msgid "An error occurred while fetching sidebar data" +msgstr "Erro ao recuperar informações da barra lateral" + msgid "An error occurred. Please try again." msgstr "Ocorreu um erro. Tente novamente." @@ -139,6 +148,12 @@ msgstr "Aparência" msgid "Applications" msgstr "Aplicações" +msgid "Apr" +msgstr "Abr" + +msgid "April" +msgstr "Abril" + msgid "Archived project! Repository is read-only" msgstr "Projeto arquivado! O repositório é somente leitura" @@ -166,6 +181,12 @@ msgstr "Artefatos" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "Para anexar arquivo, arraste e solte ou %{upload_link}" +msgid "Aug" +msgstr "Ago" + +msgid "August" +msgstr "Agosto" + msgid "Authentication Log" msgstr "Log de autenticação" @@ -199,6 +220,9 @@ msgstr "Saiba mais em %{link_to_documentation}" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." msgstr "Você pode ativar %{link_to_settings} para esse projeto." +msgid "Available" +msgstr "Disponível" + msgid "Billing" msgstr "Cobrança" @@ -218,28 +242,28 @@ msgid "BillingPlans|Downgrade" msgstr "Downgrade" msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}." -msgstr "Aprenda mais sobre cada plano lendo nossa %{faq_link}." +msgstr "Saiba mais sobre cada plano lendo nossa %{faq_link}." msgid "BillingPlans|Manage plan" msgstr "Gerenciar plano" msgid "BillingPlans|Please contact %{customer_support_link} in that case." -msgstr "Por favor contacte o %{customer_support_link} para resolver seu caso." +msgstr "Por favor, entre em contato com %{customer_support_link} para resolver seu caso." msgid "BillingPlans|See all %{plan_name} features" -msgstr "Veja todas as funcionalidades do seu plano %{plan_name}" +msgstr "Veja todas as funcionalidades de %{plan_name}" msgid "BillingPlans|This group uses the plan associated with its parent group." msgstr "Esse grupo utiliza o plano associado ao seu grupo pai." msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}." -msgstr "Para gerenciar o plano para esse grupo, visite a sessão de cobrança de %{parent_billing_page_link}." +msgstr "Para gerenciar o plano desse grupo, visite a sessão de cobrança de %{parent_billing_page_link}." msgid "BillingPlans|Upgrade" -msgstr "Atualizar" +msgstr "Upgrade" msgid "BillingPlans|You are currently on the %{plan_link} plan." -msgstr "Vocês está utilizando o plano %{plan_link}." +msgstr "Você está atualmente no plano %{plan_link}." msgid "BillingPlans|frequently asked questions" msgstr "perguntas frequentes" @@ -264,6 +288,12 @@ msgstr "O branch %{branch_name} foi criado. Para configurar o d msgid "Branch has changed" msgstr "Branch foi alterado" +msgid "Branch is already taken" +msgstr "Branch já utilizada" + +msgid "Branch name" +msgstr "Nome da branch" + msgid "BranchSwitcherPlaceholder|Search branches" msgstr "Procurar por branches" @@ -325,7 +355,7 @@ msgid "Branches|Sort by" msgstr "Ordernar por" msgid "Branches|The branch could not be updated automatically because it has diverged from its upstream counterpart." -msgstr "A branch não pode ser atualizada automaticamente porque diverge do seu upstream." +msgstr "O branch não pode ser atualizado automaticamente porque diverge do seu upstream." msgid "Branches|The default branch cannot be deleted" msgstr "A branch padrão não pode ser apagada" @@ -340,13 +370,13 @@ msgid "Branches|To confirm, type %{branch_name_confirmation}:" msgstr "Para confirmar, digite %{branch_name_confirmation}:" msgid "Branches|To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above." -msgstr "Para descartar as mudanças locais e sobrescrever a branch com a versão de upstream, apague-o aqui e escolha 'Atualizar agora', acima." +msgstr "" msgid "Branches|You’re about to permanently delete the protected branch %{branch_name}." msgstr "Você irá apagar irreparavelmente a branch protegida '%{branch_name}'." msgid "Branches|diverged from upstream" -msgstr "divergiu do upstream" +msgstr "" msgid "Branches|merged" msgstr "merge realizado" @@ -388,7 +418,7 @@ msgid "Cancel edit" msgstr "Cancelar edição" msgid "Change Weight" -msgstr "Mudar peso" +msgstr "Alterar peso" msgid "ChangeTypeActionLabel|Pick into branch" msgstr "Pick para um branch" @@ -411,6 +441,12 @@ msgstr "Gráficos" msgid "Chat" msgstr "Bate-papo" +msgid "Checking %{text} availability…" +msgstr "Verificando disponibilidade de %{text}…" + +msgid "Checking branch availability..." +msgstr "Verificando disponibilidade de branch..." + msgid "Cherry-pick this commit" msgstr "Cherry-pick esse commit" @@ -418,7 +454,7 @@ msgid "Cherry-pick this merge request" msgstr "Cherry-pick esse merge request" msgid "Choose which groups you wish to replicate to this secondary node. Leave blank to replicate all." -msgstr "Escolha quais os grupos que você deseja replicar para este nó secundário. Deixe em branco para replicar todos." +msgstr "Escolha quais grupos você deseja replicar para este nó secundário. Deixe em branco para replicar tudo." msgid "CiStatusLabel|canceled" msgstr "cancelado" @@ -486,8 +522,41 @@ msgstr "Fechar" msgid "Cluster" msgstr "Cluster" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" -msgstr "Um %{link_to_container_project} deve ter sido criado com essa conta" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "%{appList} foi instalado no seu cluster" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "%{boldNotice} isso irá adicionar recursos extras como balanceamento de carga, que acarretará em custos adicionais. Veja %{pricingLink}" + +msgid "ClusterIntegration|API URL" +msgstr "API URL" + +msgid "ClusterIntegration|Active" +msgstr "Ativo" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "Adicionar um cluster existente" + +msgid "ClusterIntegration|Add cluster" +msgstr "Adicionar cluster" + +msgid "ClusterIntegration|All" +msgstr "Tudo" + +msgid "ClusterIntegration|Applications" +msgstr "Aplicações" + +msgid "ClusterIntegration|CA Certificate" +msgstr "Certificado CA" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "Pacote de autoridade certificadora (Formato PEM)" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "Escolher como configurar a integração de cluster" + +msgid "ClusterIntegration|Cluster" +msgstr "Cluster" msgid "ClusterIntegration|Cluster details" msgstr "Detalhes do cluster" @@ -505,56 +574,137 @@ msgid "ClusterIntegration|Cluster integration is enabled for this project. Disab msgstr "Integração do cluster está ativada para esse projeto. Desabilitar a integração não afetará seu cluster, mas desligará temporariamente a conexão do Gitlab com ele." msgid "ClusterIntegration|Cluster is being created on Google Kubernetes Engine..." -msgstr "O cluster está sendo criado no Google Kubernetes Engine..." +msgstr "O Cluster está sendo criado no Google Kubernetes Engine..." msgid "ClusterIntegration|Cluster name" msgstr "Nome do cluster" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" -msgstr "O cluster foi criado com sucesso no Google Kubernetes Engine" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" +msgstr "" + +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "Clusters permitem que você utilize review apps, faça deploy de suas aplicações, rode pipelines, e muito mais de um jeito simples. %{link_to_help_page}" + +msgid "ClusterIntegration|Copy API URL" +msgstr "Copiar URL da API" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "Copiar certificado CA" + +msgid "ClusterIntegration|Copy Token" +msgstr "Copiar token" msgid "ClusterIntegration|Copy cluster name" msgstr "Copiar nome do cluster" +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "Criar um novo cluster do Google Engine pelo GitLab" + msgid "ClusterIntegration|Create cluster" msgstr "Criar cluster" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" -msgstr "Criar novo cluster no Google Kubernetes Engine" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Create on GKE" +msgstr "Criar no GKE" msgid "ClusterIntegration|Enable cluster integration" msgstr "Ativar integração com o cluster" +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "Insira os detalhes para o cluster Kubernetes existente" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "Insira os detalhes para seu cluster" + +msgid "ClusterIntegration|Environment pattern" +msgstr "Padrão de ambiente" + +msgid "ClusterIntegration|GKE pricing" +msgstr "Preços do GKE" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "Gitlab Runner" + msgid "ClusterIntegration|Google Cloud Platform project ID" msgstr "ID do projeto no Google Cloud Platform" msgid "ClusterIntegration|Google Kubernetes Engine" -msgstr "Google Kubernetes Engine" +msgstr "" msgid "ClusterIntegration|Google Kubernetes Engine project" -msgstr "Projeto no Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Helm Tiller" +msgstr "Helm Tiller" + +msgid "ClusterIntegration|Inactive" +msgstr "Inativo" + +msgid "ClusterIntegration|Ingress" +msgstr "Ingressar" + +msgid "ClusterIntegration|Install" +msgstr "Instalar" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "Instalar aplicações no seu cluster. Leia mais em %{helpLink}" + +msgid "ClusterIntegration|Installed" +msgstr "Instalado" + +msgid "ClusterIntegration|Installing" +msgstr "Instalando" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "Integrar cluster de automação" msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "Leia mais sobre %{link_to_documentation}" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "Ler mais sobre clusters" + msgid "ClusterIntegration|Machine type" msgstr "Tipo de máquina" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" msgstr "Confira se sua conta %{link_to_requirements} para criar clusters" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" -msgstr "Gerenciar integração de cluster com o projeto no GitLab" +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" +msgstr "Gerenciar cluster de integração no projeto do GitLab" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" msgstr "Gerencie seu cluster visitando %{link_gke}" +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "Múltiplos clusters estão disponíveis no GitLab Enterprise Premium e Ultimate" + +msgid "ClusterIntegration|Note:" +msgstr "Nota:" + msgid "ClusterIntegration|Number of nodes" msgstr "Número de nós" +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" +msgstr "Por favor, insira informações de acesso para seu cluster. Se precisar de ajuda, você pode ler %{link_to_help_page} em cluster" + msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgstr "Por favor, tenha certeza que sua conta no Google cumpre com os requisitos:" +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "Problema ao configurar o cluster" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "Problema ao configurar a lista de cluster" + +msgid "ClusterIntegration|Project ID" +msgstr "ID do projeto" + +msgid "ClusterIntegration|Project namespace" +msgstr "Namespace do projeto" + msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "Namespace do projeto (opcional, único)" @@ -567,8 +717,14 @@ msgstr "Remover integração com cluster" msgid "ClusterIntegration|Remove integration" msgstr "Remover integração" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." -msgstr "Remover integração com o cluster irá apagar a configuração de cluster que você adicionou à esse projeto. Não excluirá seu projeto." +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "" + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "Solicitação para início de instalação falhou" + +msgid "ClusterIntegration|Save changes" +msgstr "Salvar alterações" msgid "ClusterIntegration|See and edit the details for your cluster" msgstr "Ver e editar os detalhes para seu cluster" @@ -582,33 +738,57 @@ msgstr "Ver seus projetos" msgid "ClusterIntegration|See zones" msgstr "Ver zonas" +msgid "ClusterIntegration|Service token" +msgstr "Token de serviço" + +msgid "ClusterIntegration|Show" +msgstr "Mostrar" + msgid "ClusterIntegration|Something went wrong on our end." msgstr "Alguma coisa deu errado do nosso lado." msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" -msgstr "Algo deu errado ao criar seu cluster no Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "Algo deu errado ao instalar %{title}" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "Não há clusters para mostrar" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "Essa conta precisa de permissão para criar um cluster no %{link_to_container_project} especificado." msgid "ClusterIntegration|Toggle Cluster" msgstr "Alternar cluster" +msgid "ClusterIntegration|Token" +msgstr "Token" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "Com um cluster associado à esse projeto, você pode usar revisão de apps, fazer deploy de suas aplicações, rodar suas pipelines e muito mais de um jeito simples." msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}" -msgstr "Sua conta precisa ter %{link_to_kubernetes_engine}" +msgstr "" msgid "ClusterIntegration|Zone" msgstr "Zona" msgid "ClusterIntegration|access to Google Kubernetes Engine" -msgstr "Acesso ao Google Kubernetes Engine" +msgstr "" msgid "ClusterIntegration|cluster" msgstr "cluster" +msgid "ClusterIntegration|documentation" +msgstr "documentação" + msgid "ClusterIntegration|help page" msgstr "ajuda" +msgid "ClusterIntegration|installing applications" +msgstr "Instalando aplicações" + msgid "ClusterIntegration|meets the requirements" msgstr "atende aos requisitos" @@ -623,11 +803,6 @@ msgid_plural "Commits" msgstr[0] "Commit" msgstr[1] "Commits" -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "Commit %d arquivo" -msgstr[1] "Commit %d arquivos" - msgid "Commit Message" msgstr "Mensagem de Commit" @@ -709,14 +884,23 @@ msgstr "Guia de contribuição" msgid "Contributors" msgstr "Contribuidores" +msgid "ContributorsPage|Building repository graph." +msgstr "Gerando gráfico do repositório." + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "Commits à %{branch_name}, excluindo commits de merge. Limitado à 6000 commits." + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "Por favor, espere um momento, essa página será atualizada automaticamente." + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" -msgstr "Controle a concorrência máxima de LFS/preenchimento de anexos para o nó secundário" +msgstr "" msgid "Control the maximum concurrency of repository backfill for this secondary node" -msgstr "Controle a concorrência máxima de preenchimento de repositórios para o nó secundário" +msgstr "" msgid "Copy SSH public key to clipboard" -msgstr "Copiar chave SSH pública para área de transferência" +msgstr "" msgid "Copy URL to clipboard" msgstr "Copiar URL para área de transferência" @@ -736,6 +920,9 @@ msgstr "Criar diretório" msgid "Create empty bare repository" msgstr "Criar repositório bruto vazio" +msgid "Create epic" +msgstr "Criar épico" + msgid "Create file" msgstr "Criar arquivo" @@ -763,6 +950,9 @@ msgstr "Tag" msgid "CreateTokenToCloneLink|create a personal access token" msgstr "criar um token de acesso pessoal" +msgid "Creating epic" +msgstr "Criando épico" + msgid "Cron Timezone" msgstr "Fuso horário do cron" @@ -808,6 +998,12 @@ msgstr "Todos" msgid "DashboardProjects|Personal" msgstr "Pessoal" +msgid "Dec" +msgstr "Dez" + +msgid "December" +msgstr "Dezembro" + msgid "Define a custom pattern with cron syntax" msgstr "Defina um padrão personalizado utilizando a sintaxe do cron" @@ -826,7 +1022,7 @@ msgid "Description" msgstr "Descrição" msgid "Description templates allow you to define context-specific templates for issue and merge request description fields for your project." -msgstr "Modelos de descrição permitem que você defina modelos de contextos específicos para issue e descrição de merge requests para seu projeto." +msgstr "Modelos de descrição permitem que você defina modelos de contextos específicos para issue e campos de descrição de merge requests para seu projeto." msgid "Details" msgstr "Detalhes" @@ -882,6 +1078,72 @@ msgstr "Alterar Agendamento do Pipeline %{id}" msgid "Emails" msgstr "Emails" +msgid "Environments|An error occurred while fetching the environments." +msgstr "Um erro ocorreu ao recuperar ambientes." + +msgid "Environments|An error occurred while making the request." +msgstr "Um erro ocorreu ao fazer a requisição." + +msgid "Environments|Commit" +msgstr "Commit" + +msgid "Environments|Deployment" +msgstr "Deploy" + +msgid "Environments|Environment" +msgstr "Ambiente" + +msgid "Environments|Environments" +msgstr "Ambientes" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "Ambientes são lugares onde códigos são implantados (deploy), como homologação ou produção." + +msgid "Environments|Job" +msgstr "Job" + +msgid "Environments|New environment" +msgstr "Novo ambiente" + +msgid "Environments|No deployments yet" +msgstr "Nenhum deploy" + +msgid "Environments|Open" +msgstr "Abrir" + +msgid "Environments|Re-deploy" +msgstr "Refazer" + +msgid "Environments|Read more about environments" +msgstr "Ler mais sobre ambiente" + +msgid "Environments|Rollback" +msgstr "Rollback" + +msgid "Environments|Show all" +msgstr "Mostrar tudo" + +msgid "Environments|Updated" +msgstr "Atualizado" + +msgid "Environments|You don't have any environments right now." +msgstr "Você não tem nenhum ambiente." + +msgid "Epic will be removed! Are you sure?" +msgstr "Épico será removido! Tem certeza?" + +msgid "Epics" +msgstr "Épicos" + +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" +msgstr "Epics permite que você gerencie seu portfólio de projetos de forma mais eficiente e com menos esforço" + +msgid "Error creating epic" +msgstr "Erro ao criar épico" + +msgid "Error occurred when toggling the notification subscription" +msgstr "Erro ao alterar configuração de notificação de assinatura" + msgid "EventFilterBy|Filter by all" msgstr "EventFilterBy|Filtrar por tudo" @@ -921,6 +1183,12 @@ msgstr "Erro ao alterar o proprietário" msgid "Failed to remove the pipeline schedule" msgstr "Erro ao excluir o agendamento do pipeline" +msgid "Feb" +msgstr "Fev" + +msgid "February" +msgstr "Fevereiro" + msgid "File name" msgstr "Nome do arquivo" @@ -968,17 +1236,32 @@ msgstr "Chaves GPG" msgid "Geo Nodes" msgstr "Nós de geo" +msgid "GeoNodeSyncStatus|Failed" +msgstr "Falhou" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "Nó está falhando ou quebrado." + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "Nó está lento, sobrecarregado, ou acabou de recuperar após uma interrupção." + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "Sem sincronia" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "Sincronizado" + msgid "Geo|File sync capacity" -msgstr "Capacidade de sincronização de arquivo" +msgstr "Capacidade de sincronização de arquivos" msgid "Geo|Groups to replicate" -msgstr "Grupos para replicar" +msgstr "Grupos para replicação" msgid "Geo|Repository sync capacity" -msgstr "Capacidade de sincronização de repositório" +msgstr "Capacidade de sincronização do repositório" msgid "Geo|Select groups to replicate." -msgstr "Selecione grupos para replicar." +msgstr "" msgid "Git storage health information has been reset" msgstr "Informações sobre o status de saúde do storage Git foram reiniciadas" @@ -1031,9 +1314,6 @@ msgstr "Nenhum grupo encontrado" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "Você pode gerenciar permissões de membros e acesso do seu grupo para cada projeto no grupo." -msgid "GroupsTreeRole|as" -msgstr "como" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "Você tem certeza que deseja sair do grupo \"${this.group.fullName}\"?" @@ -1064,6 +1344,9 @@ msgstr "Desculpe, nenhum grupo corresponde à sua pesquisa" msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "Desculpe, nenhum grupo ou projeto correspondem à sua pesquisa" +msgid "Have your users email" +msgstr "" + msgid "Health Check" msgstr "Status de Saúde" @@ -1092,21 +1375,21 @@ msgid "Import repository" msgstr "Importar repositório" msgid "Improve Issue boards with GitLab Enterprise Edition." -msgstr "Melhorar issue boards com o GitLab Enterprise Edition." +msgstr "" msgid "Improve issues management with Issue weight and GitLab Enterprise Edition." -msgstr "Melhore gestão das issues com os pesos no GitLab Enterprise Edition." +msgstr "" msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition." -msgstr "Encontre o que precisa mais facilmente com a pesquisa global avançada com GitLab Enterprise Edition." +msgstr "" msgid "Install a Runner compatible with GitLab CI" msgstr "Instalar um Runner compatível com o GitLab CI" msgid "Instance" msgid_plural "Instances" -msgstr[0] "Instância" -msgstr[1] "Instâncias" +msgstr[0] "" +msgstr[1] "" msgid "Internal - The group and any internal projects can be viewed by any logged in user." msgstr "Interno - O grupo e projetos internos podem ser visualizados por qualquer usuário autenticado." @@ -1121,10 +1404,7 @@ msgid "Introducing Cycle Analytics" msgstr "Apresentando a Análise de Ciclo" msgid "Issue board focus mode" -msgstr "Modo de foco no issue board" - -msgid "Issue boards with milestones" -msgstr "Issue board com milestone" +msgstr "" msgid "Issue events" msgstr "Eventos de issue" @@ -1133,11 +1413,29 @@ msgid "IssueBoards|Board" msgstr "Board" msgid "IssueBoards|Boards" -msgstr "Boards" +msgstr "" msgid "Issues" msgstr "Issues" +msgid "Jan" +msgstr "Jan" + +msgid "January" +msgstr "Janeiro" + +msgid "Jul" +msgstr "Jul" + +msgid "July" +msgstr "Julho" + +msgid "Jun" +msgstr "Jun" + +msgid "June" +msgstr "Junho" + msgid "LFSStatus|Disabled" msgstr "Desabilitado" @@ -1192,7 +1490,7 @@ msgid "Leave project" msgstr "Sair do projeto" msgid "License" -msgstr "Licença" +msgstr "" msgid "Limited to showing %d event at most" msgid_plural "Limited to showing %d events at most" @@ -1206,14 +1504,23 @@ msgid "Locked" msgstr "Bloqueado" msgid "Locked Files" -msgstr "Arquivos bloqueados" +msgstr "" msgid "Login" msgstr "Entrar" +msgid "Mar" +msgstr "Mar" + +msgid "March" +msgstr "Março" + msgid "Maximum git storage failures" msgstr "Máximo de falhas do git storage" +msgid "May" +msgstr "Mai" + msgid "Median" msgstr "Mediana" @@ -1242,7 +1549,7 @@ msgid "More information is available|here" msgstr "Mais informações estão disponíveis|aqui" msgid "Multiple issue boards" -msgstr "Múltiplos issue boards" +msgstr "" msgid "New Cluster" msgstr "Novo cluster" @@ -1258,9 +1565,15 @@ msgstr "Novo Agendamento de Pipeline" msgid "New branch" msgstr "Novo branch" +msgid "New branch unavailable" +msgstr "Novo branch indisponível" + msgid "New directory" msgstr "Novo diretório" +msgid "New epic" +msgstr "" + msgid "New file" msgstr "Novo arquivo" @@ -1297,6 +1610,9 @@ msgstr "Nenhum repositório" msgid "No schedules" msgstr "Nenhum agendamento" +msgid "No time spent" +msgstr "Nenhum tempo gasto" + msgid "None" msgstr "Nenhum" @@ -1363,18 +1679,33 @@ msgstr "Observar" msgid "Notifications" msgstr "Notificações" +msgid "Nov" +msgstr "Nov" + +msgid "November" +msgstr "Novembro" + msgid "Number of access attempts" msgstr "Número de tentativas de acesso" msgid "Number of failures before backing off" msgstr "Número de falhas antes de reverter" +msgid "Oct" +msgstr "Out" + +msgid "October" +msgstr "Outubro" + msgid "OfSearchInADropdown|Filter" msgstr "Filtrar" msgid "Only project members can comment." msgstr "Somente membros do projeto podem comentar." +msgid "Opened" +msgstr "" + msgid "OpenedNDaysAgo|Opened" msgstr "Aberto" @@ -1421,7 +1752,7 @@ msgid "Pipeline Schedules" msgstr "Agendamentos da Pipeline" msgid "Pipeline quota" -msgstr "Cota de pipeline" +msgstr "" msgid "PipelineCharts|Failed:" msgstr "Falhou:" @@ -1507,6 +1838,9 @@ msgstr "com etapa" msgid "Pipeline|with stages" msgstr "com etapas" +msgid "Please solve the reCAPTCHA" +msgstr "" + msgid "Preferences" msgstr "Preferências" @@ -1610,22 +1944,28 @@ msgid "ProjectNetworkGraph|Graph" msgstr "Árvore" msgid "ProjectSettings|Contact an admin to change this setting." -msgstr "Fale com um administrador para mudar essa configuração." +msgstr "" + +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "Rodar pipeline na branch default imediatamente" msgid "ProjectSettings|Only signed commits can be pushed to this repository." -msgstr "Esse repositório só aceita push de commits assinados." +msgstr "" + +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "Problema ao definir configurações de CI/CD Javascript" msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." -msgstr "Essa configuração está aplicada à nivel de servidor e pode ser sobrescrita por um adminstrador." +msgstr "" msgid "ProjectSettings|This setting is applied on the server level but has been overridden for this project." -msgstr "Essa configuração está aplicada à nivel de servidor mas pode ser sobrescrita para esse projeto." +msgstr "" msgid "ProjectSettings|This setting will be applied to all projects unless overridden by an admin." -msgstr "Essa configuração será aplicada à todos os projetos, a não ser que sejam sobrescritos pelo administrador." +msgstr "" msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails." -msgstr "Nesse repositório, usuários só podem fazer push de commits verificados pelos seus e-mails." +msgstr "" msgid "Projects" msgstr "Projetos" @@ -1651,6 +1991,39 @@ msgstr "Desculpe, nenhum projeto corresponde a sua pesquisa" msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "Esta funcionalidade necessita de suporte à localStorage do navegador" +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "Por padrão, Prometheus escuta em 'http://localhost:9090'. Não é recomendado mudar o endereço padrão e sua porta, porque pode conflitar com outros serviços que estão executando no sevidor do Gitlab." + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "Encontrando e configurando métricas..." + +msgid "PrometheusService|Metrics" +msgstr "Métricas" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "Métricas são automaticamente configuradas e monitoradas baseadas na biblioteca de métricas de exportadores populares." + +msgid "PrometheusService|Missing environment variable" +msgstr "Variável de ambiente ausente" + +msgid "PrometheusService|Monitored" +msgstr "Monitorado" + +msgid "PrometheusService|More information" +msgstr "Mais informações" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "Nenhuma métrica está sendo monitorada. Para inicar o monitoramento, faça deploy em um ambiente." + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" +msgstr "URL da API base do Prometheus. como http://prometheus.example.com/" + +msgid "PrometheusService|Prometheus monitoring" +msgstr "Monitoramento com Prometheus" + +msgid "PrometheusService|View environments" +msgstr "Ver ambientes" + msgid "Public - The group and any public projects can be viewed without any authentication." msgstr "Público - O grupo e seus projetos podem ser visualizados por todos sem autenticação." @@ -1658,13 +2031,13 @@ msgid "Public - The project can be accessed without any authentication." msgstr "Público - O projeto pode ser acessado sem nenhuma autenticação." msgid "Push Rules" -msgstr "Regras de push" +msgstr "" msgid "Push events" msgstr "Eventos de push" msgid "PushRule|Committer restriction" -msgstr "Restrição de commit" +msgstr "" msgid "Read more" msgstr "Leia mais" @@ -1679,7 +2052,7 @@ msgid "RefSwitcher|Tags" msgstr "Tags" msgid "Registry" -msgstr "Registry" +msgstr "Registro" msgid "Related Commits" msgstr "Commits Relacionados" @@ -1747,6 +2120,9 @@ msgstr "Agendamentos" msgid "Scheduling Pipelines" msgstr "Agendando pipelines" +msgid "Scoped issue boards" +msgstr "" + msgid "Search branches and tags" msgstr "Procurar branch e tags" @@ -1768,6 +2144,12 @@ msgstr "Selecionar fuso horário" msgid "Select target branch" msgstr "Selecionar branch de destino" +msgid "Sep" +msgstr "Set" + +msgid "September" +msgstr "Setembro" + msgid "Service Templates" msgstr "Modelos de serviço" @@ -1800,14 +2182,29 @@ msgid_plural "Showing %d events" msgstr[0] "Mostrando %d evento" msgstr[1] "Mostrando %d eventos" +msgid "Sidebar|Change weight" +msgstr "" + +msgid "Sidebar|Edit" +msgstr "" + +msgid "Sidebar|No" +msgstr "" + +msgid "Sidebar|None" +msgstr "" + +msgid "Sidebar|Weight" +msgstr "" + msgid "Snippets" msgstr "Snippets" msgid "Something went wrong on our end." msgstr "Algo deu errado do nosso lado." -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" -msgstr "Algo deu errado ao tentar mudar o estado de bloqueio de ${this.issuableDisplayName(this.issuableType)}" +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" +msgstr "Algo deu errado ao tentar mudar o estado de ${this.issuableDisplayName}" msgid "Something went wrong while fetching the projects." msgstr "Algo deu errado ao recuperar os projetos." @@ -1858,7 +2255,7 @@ msgid "SortOptions|Least popular" msgstr "Menos populares" msgid "SortOptions|Less weight" -msgstr "Menor peso" +msgstr "" msgid "SortOptions|Milestone" msgstr "Milestone" @@ -1870,7 +2267,7 @@ msgid "SortOptions|Milestone due soon" msgstr "Milestone de fim mais próximo" msgid "SortOptions|More weight" -msgstr "Mais peso" +msgstr "" msgid "SortOptions|Most popular" msgstr "Mais populares" @@ -1912,11 +2309,17 @@ msgid "SortOptions|Start soon" msgstr "Iniciar mais próximo" msgid "SortOptions|Weight" -msgstr "Peso" +msgstr "" + +msgid "Source" +msgstr "Origem" msgid "Source code" msgstr "Código-fonte" +msgid "Source is not available" +msgstr "Origem não está disponível" + msgid "Spam Logs" msgstr "Logs de spam" @@ -1935,6 +2338,9 @@ msgstr "Iniciar um %{new_merge_request} a partir dessas alterações" msgid "Start the Runner!" msgstr "Inicie o Runner!" +msgid "Stopped" +msgstr "Parado" + msgid "Subgroups" msgstr "Subgrupos" @@ -1955,6 +2361,75 @@ msgstr[1] "Tags" msgid "Tags" msgstr "Tags" +msgid "TagsPage|Browse commits" +msgstr "Navegar nos commits" + +msgid "TagsPage|Browse files" +msgstr "Navegar nos arquivos" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "Não foi possível encontrar o commit HEAD para esse tag" + +msgid "TagsPage|Cancel" +msgstr "Cancelar" + +msgid "TagsPage|Create tag" +msgstr "Criar tag" + +msgid "TagsPage|Delete tag" +msgstr "Apagar tag" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "Apagar a tag %{tag_name} é uma ação destrutiva e irreversível. Tem certeza?" + +msgid "TagsPage|Edit release notes" +msgstr "Editar o release notes" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "Nome de branch, tag ou SHA do commit existente" + +msgid "TagsPage|Filter by tag name" +msgstr "Filtrar tag por nome" + +msgid "TagsPage|New Tag" +msgstr "Novo tag" + +msgid "TagsPage|New tag" +msgstr "Novo tag" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "Opcionalmente, adicionar a mensagem à essa tag." + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "Opcionalmente, adicionar release notes à tag. Eles serão armazenados no banco de dados do GitLab e mostrado na página de tags." + +msgid "TagsPage|Release notes" +msgstr "Release notes" + +msgid "TagsPage|Repository has no tags yet." +msgstr "Repositório ainda não tem tags." + +msgid "TagsPage|Sort by" +msgstr "Ordenar por" + +msgid "TagsPage|Tags" +msgstr "Tags" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "Tags dão capacidade de marcar pontos específicos na história como sendo importantes" + +msgid "TagsPage|This tag has no release notes." +msgstr "Essa tag não tem release notes." + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "Use o comando \"git tag\" para adiciona uma nova tag:" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "Escreve seu release notes ou arraste o arquivo aqui..." + +msgid "TagsPage|protected" +msgstr "protegido" + msgid "Target Branch" msgstr "Branch de destino" @@ -1962,10 +2437,10 @@ msgid "Team" msgstr "Equipe" msgid "Thanks! Don't show me this again" -msgstr "Obrigado! Não mostrar novamente" +msgstr "" msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project." -msgstr "A pesquisa global avançado no GitLab é um serviço poderoso de pesquisa que poupa seu tempo. Ao invés de criar código duplicado e perder seu tempo, você pode agora pesquisar por código de outros times que podem ajudar no seu próprio projeto." +msgstr "" msgid "The circuitbreaker backoff threshold should be lower than the failure count threshold" msgstr "O limite do recuso do circuitbreaker deve ser inferior ao limite de contagem de falhas" @@ -2036,6 +2511,9 @@ msgstr "O valor situado no ponto médio de uma série de valores observados. Ex. msgid "There are problems accessing Git storage: " msgstr "Há problemas para acessar o storage Git: " +msgid "This board\\'s scope is reduced" +msgstr "" + msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "Esse branch mudou desde quando você começou sua edição. Você quer criar um novo branch?" @@ -2057,6 +2535,9 @@ msgstr "Isto significa que você não pode entregar código até que crie um rep msgid "This merge request is locked." msgstr "Esse merge request está bloqueado." +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "Tempo até que uma issue seja agendada" @@ -2205,14 +2686,26 @@ msgstr[1] "mins" msgid "Time|s" msgstr "s" +msgid "Title" +msgstr "Título" + msgid "Total Time" msgstr "Tempo Total" +msgid "Total issue time spent" +msgstr "Tempo total gasto" + msgid "Total test time for all commits/merges" msgstr "Tempo de teste total para todos os commits/merges" msgid "Track activity with Contribution Analytics." -msgstr "Acompanhar atividade com o Contribution Analytics." +msgstr "Acompanhe a atividade com o Contribution Analytics." + +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "Acompanhe grupos de questões que compartilhem um tema, em projetos e milestones" + +msgid "Turn on Service Desk" +msgstr "Ativar Service Desk" msgid "Unlock" msgstr "Desbloquear" @@ -2227,13 +2720,13 @@ msgid "Unsubscribe" msgstr "Desassinar" msgid "Upgrade your plan to activate Advanced Global Search." -msgstr "Atualize seu plano para ativar a pesquisa global avançada." +msgstr "Atualize seu plano para ativar a Pesquisa Global Avançada." msgid "Upgrade your plan to activate Contribution Analytics." msgstr "Atualize seu plano para ativar o Contribution Analytics." msgid "Upgrade your plan to activate Group Webhooks." -msgstr "Atualize seu plano para ativar Webhooks de grupo." +msgstr "Atualize seu plano para ativar Webhooks do grupo." msgid "Upgrade your plan to activate Issue weight." msgstr "Atualize seu plano para ativar peso nas issues." @@ -2250,6 +2743,9 @@ msgstr "Enviar arquivo" msgid "UploadLink|click to upload" msgstr "clique para fazer upload" +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "Use o Service Desk para se conectar com seus usuários (por exemplo, para oferecer suporte ao cliente) por email dentro do GitLab" + msgid "Use the following registration token during setup:" msgstr "Use o seguinte token de registro durante a configuração:" @@ -2283,8 +2779,11 @@ msgstr "Precisa visualizar os dados? Solicite acesso ao administrador." msgid "We don't have enough data to show this stage." msgstr "Esta etapa não possui dados suficientes para exibição." +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "Queremos ter certeza de que é você, confirme que você não é um robô." + msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." -msgstr "Webhooks permitem que você acione uma URL se, por exemplo, um novo código for feito push ou uma nova issue criada. Você pode configurar os webhooks para escutar eventos específicos como push, issue ou merge request. Webhooks de grupo aplicarão para todos os projetos no grupo, permitindo você padronizar o funcionamento em todo o grupo." +msgstr "Webhooks permitem que você acione uma URL se, por exemplo, quando um novo código for feito push ou uma nova issue criada. Você pode configurar os webhooks para escutar eventos específicos como push, issue ou merge request. Webhooks de grupo aplicarão para todos os projetos no grupo, permitindo você padronizar o funcionamento em todo o grupo." msgid "Weight" msgstr "Peso" @@ -2395,7 +2894,7 @@ msgid "Wiki|Wiki Pages" msgstr "Páginas Wiki" msgid "With contribution analytics you can have an overview for the activity of issues, merge requests and push events of your organization and its members." -msgstr "Com o contribution analytics você pode ter uma visão geral da atividade em issue, merge request e evento de push para sua organização e seus membros." +msgstr "Com a análise de contribuição, você pode ter uma visão geral da atividade de issues, merge requests e eventos push de sua organização e seus membros." msgid "Withdraw Access Request" msgstr "Remover Requisição de Acesso" @@ -2412,12 +2911,6 @@ msgstr "Você está prestes a remover a relação de fork do projeto original %{ msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "Você irá transferir %{project_name_with_namespace} para outro proprietário. Tem certeza ABSOLUTA?" -msgid "You are on a read-only GitLab instance." -msgstr "Você está em uma instância somente-leitura do GitLab." - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "Você está em uma instância somente-leitura do GitLab. Se você quiser fazer qualquer alteração visite %{link_to_primary_node}." - msgid "You can only add files when you are on a branch" msgstr "Você somente pode adicionar arquivos quando estiver em um branch" @@ -2457,6 +2950,9 @@ msgstr "Você não poderá fazer pull ou push via %{protocol} até que %{set_pas msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" msgstr "Você não conseguirá fazer pull ou push no projeto via SSH até que adicione %{add_ssh_key_link} ao seu perfil" +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "Você não poderá fazer push ou pull do código via SSH enquanto não adicionar sua chave SSH no seu perfil" + msgid "Your comment will not be visible to the public." msgstr "Seu comentário não estará visível ao público." @@ -2469,6 +2965,12 @@ msgstr "Seu nome" msgid "Your projects" msgstr "Seus projetos" +msgid "branch name" +msgstr "nome da branch" + +msgid "by" +msgstr "por" + msgid "commit" msgstr "commit" @@ -2494,6 +2996,9 @@ msgstr "senha" msgid "personal access token" msgstr "token de acesso pessoal" +msgid "source" +msgstr "origem" + msgid "to help your contributors communicate effectively!" msgstr "para ajudar seus contribuintes à se comunicar de maneira eficaz!" diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po index b25a5d1e75b..898d55e7d4e 100644 --- a/locale/ru/gitlab.po +++ b/locale/ru/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-17 07:55-0500\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 04:40-0500\n" "Last-Translator: gitlab \n" "Language-Team: Russian\n" "Language: ru_RU\n" @@ -61,6 +61,9 @@ msgstr[0] "%{storage_name}: неудачная попытка доступа к msgstr[1] "%{storage_name}: %{failed_attempts} - неудачные попытки доступа к хранилищу:" msgstr[2] "%{storage_name}: %{failed_attempts} - неудачные попытки доступа к хранилищу:" +msgid "%{text} is available" +msgstr "" + msgid "(checkout the %{link} for information on how to install it)." msgstr "(перейдите по ссылке %{link} для получения информации об установке)." @@ -107,7 +110,7 @@ msgid "Activity" msgstr "Активность" msgid "Add" -msgstr "Добавить" +msgstr "" msgid "Add Changelog" msgstr "Добавить Журнал Изменений" @@ -116,14 +119,11 @@ msgid "Add Contribution guide" msgstr "Добавить Руководство участника" msgid "Add Group Webhooks and GitLab Enterprise Edition." -msgstr "Добавить групповые веб-обработчики и GitLab Enterprise Edition." +msgstr "" msgid "Add License" msgstr "Добавить Лицензию" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "Добавьте ключ SSH в свой профиль, чтобы отправлять или получать код через SSH." - msgid "Add new directory" msgstr "Добавить новый каталог" @@ -136,6 +136,15 @@ msgstr "Расширенные настройки" msgid "All" msgstr "Все" +msgid "An error occurred when toggling the notification subscription" +msgstr "" + +msgid "An error occurred when updating the issue weight" +msgstr "" + +msgid "An error occurred while fetching sidebar data" +msgstr "" + msgid "An error occurred. Please try again." msgstr "Произошла ошибка. Пожалуйста, попробуйте снова." @@ -145,6 +154,12 @@ msgstr "Оформление" msgid "Applications" msgstr "Приложения" +msgid "Apr" +msgstr "Апр." + +msgid "April" +msgstr "Апрель" + msgid "Archived project! Repository is read-only" msgstr "Архивный проект! Репозиторий доступен только для чтения" @@ -172,6 +187,12 @@ msgstr "Артефакты" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "Приложить файл через drag & drop или %{upload_link}" +msgid "Aug" +msgstr "Авг." + +msgid "August" +msgstr "Август" + msgid "Authentication Log" msgstr "Журнал аутентификации" @@ -191,7 +212,7 @@ msgid "AutoDevOps|Auto DevOps (Beta)" msgstr "Auto DevOps (бета)" msgid "AutoDevOps|Auto DevOps documentation" -msgstr "" +msgstr "Документация по Auto DevOps" msgid "AutoDevOps|Enable in settings" msgstr "Включить в настройках" @@ -205,14 +226,17 @@ msgstr "Подробнее по ссылке %{link_to_documentation}" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." msgstr "Вы можете активировать %{link_to_settings} для этого проекта." +msgid "Available" +msgstr "" + msgid "Billing" -msgstr "Тариф" +msgstr "" msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan." msgstr "%{group_name} использует тарифный план %{plan_link}." msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available." -msgstr "Автоматическое повышение или понижение недоступно для некоторых тарифных планов в настоящее время." +msgstr "В настоящее время автоматическое повышение или понижение недоступно для некоторых тарифных планов." msgid "BillingPlans|Current plan" msgstr "Текущий тарифный план" @@ -221,10 +245,10 @@ msgid "BillingPlans|Customer Support" msgstr "Поддержка Клиентов" msgid "BillingPlans|Downgrade" -msgstr "Понижение" +msgstr "Понизить" msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}." -msgstr "Узнайте больше о каждом тарифном плане прочитав наш %{faq_link}." +msgstr "Узнайте больше о каждом тарифном плане, прочитав нашу страницу %{faq_link}." msgid "BillingPlans|Manage plan" msgstr "Управление тарифным планом" @@ -236,19 +260,19 @@ msgid "BillingPlans|See all %{plan_name} features" msgstr "Посмотреть возможности %{plan_name} полностью" msgid "BillingPlans|This group uses the plan associated with its parent group." -msgstr "Эта группа использует тарифный план связанный с родительской группой." +msgstr "Эта группа использует тарифный план, связанный с родительской группой." msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}." msgstr "Для управления тарифным планом этой группы посетите раздел тарификации %{parent_billing_page_link}." msgid "BillingPlans|Upgrade" -msgstr "Повышение" +msgstr "Повысить" msgid "BillingPlans|You are currently on the %{plan_link} plan." msgstr "В настоящее время вы используете тарифный план %{plan_link}." msgid "BillingPlans|frequently asked questions" -msgstr "Часто задаваемые вопросы" +msgstr "часто задаваемых вопросов" msgid "BillingPlans|monthly" msgstr "ежемесячно" @@ -271,6 +295,12 @@ msgstr "Ветка %{branch_name} создана. Для нас msgid "Branch has changed" msgstr "Ветка была изменена" +msgid "Branch is already taken" +msgstr "" + +msgid "Branch name" +msgstr "" + msgid "BranchSwitcherPlaceholder|Search branches" msgstr "Поиск веток" @@ -332,7 +362,7 @@ msgid "Branches|Sort by" msgstr "Сортировать по" msgid "Branches|The branch could not be updated automatically because it has diverged from its upstream counterpart." -msgstr "Ветка не может быть обновлена автоматически, потому что она имеет расхождения с её двойником в родительском репозитории." +msgstr "" msgid "Branches|The default branch cannot be deleted" msgstr "Ветка \"по умолчанию\" не может быть удалена" @@ -347,13 +377,13 @@ msgid "Branches|To confirm, type %{branch_name_confirmation}:" msgstr "Для подтверждения, введите %{branch_name_confirmation}:" msgid "Branches|To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above." -msgstr "Чтобы отменить локальные изменения и перезаписать ветку версией из родительского репозитория, удалите её здесь и выберите \"Обновить сейчас\" выше." +msgstr "" msgid "Branches|You’re about to permanently delete the protected branch %{branch_name}." msgstr "Вы собираетесь безвозвратно удалить защищённую ветку %{branch_name}." msgid "Branches|diverged from upstream" -msgstr "расходятся с родительским репозиторием" +msgstr "" msgid "Branches|merged" msgstr "влита" @@ -395,7 +425,7 @@ msgid "Cancel edit" msgstr "Отменить редактирование" msgid "Change Weight" -msgstr "Изменить Вес" +msgstr "" msgid "ChangeTypeActionLabel|Pick into branch" msgstr "Выбрать в ветке" @@ -418,6 +448,12 @@ msgstr "Диаграммы" msgid "Chat" msgstr "Чат" +msgid "Checking %{text} availability…" +msgstr "" + +msgid "Checking branch availability..." +msgstr "" + msgid "Cherry-pick this commit" msgstr "Подобрать в этом коммите" @@ -425,7 +461,7 @@ msgid "Cherry-pick this merge request" msgstr "Подобрать этот запрос на слияние" msgid "Choose which groups you wish to replicate to this secondary node. Leave blank to replicate all." -msgstr "Выберите группы, которые хотите скопировать на вторичный узел. Оставьте пустым для копирование всего." +msgstr "" msgid "CiStatusLabel|canceled" msgstr "отменено" @@ -488,13 +524,46 @@ msgid "Clone repository" msgstr "Клонировать репозиторий" msgid "Close" -msgstr "Закрыть" +msgstr "" msgid "Cluster" msgstr "Кластер" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" -msgstr "%{link_to_container_project} должен быть создан под этой учетной записью" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "" + +msgid "ClusterIntegration|API URL" +msgstr "" + +msgid "ClusterIntegration|Active" +msgstr "" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "" + +msgid "ClusterIntegration|Add cluster" +msgstr "" + +msgid "ClusterIntegration|All" +msgstr "" + +msgid "ClusterIntegration|Applications" +msgstr "" + +msgid "ClusterIntegration|CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "" + +msgid "ClusterIntegration|Cluster" +msgstr "" msgid "ClusterIntegration|Cluster details" msgstr "Параметры кластера" @@ -512,56 +581,137 @@ msgid "ClusterIntegration|Cluster integration is enabled for this project. Disab msgstr "Для этого проекта включена интеграция кластеров. Отключение интеграции не повлияет на кластер, но соединение с GitLab будет временно отключено." msgid "ClusterIntegration|Cluster is being created on Google Kubernetes Engine..." -msgstr "Создается кластер в Google Kubernetes Engine..." +msgstr "" msgid "ClusterIntegration|Cluster name" msgstr "Название кластера" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" -msgstr "Кластер был успешно создан в Google Kubernetes Engine" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" +msgstr "" + +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "" + +msgid "ClusterIntegration|Copy API URL" +msgstr "" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Copy Token" +msgstr "" msgid "ClusterIntegration|Copy cluster name" msgstr "Копировать название кластера" +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "" + msgid "ClusterIntegration|Create cluster" msgstr "Создать кластер" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" -msgstr "Создать новый кластер в Google Kubernetes Engine" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Create on GKE" +msgstr "" msgid "ClusterIntegration|Enable cluster integration" msgstr "Включить интеграцию с кластерами" +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "" + +msgid "ClusterIntegration|Environment pattern" +msgstr "" + +msgid "ClusterIntegration|GKE pricing" +msgstr "" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "" + msgid "ClusterIntegration|Google Cloud Platform project ID" msgstr "Идентификатор проекта в Google Cloud Platform" msgid "ClusterIntegration|Google Kubernetes Engine" -msgstr "Google Kubernetes Engine" +msgstr "" msgid "ClusterIntegration|Google Kubernetes Engine project" -msgstr "Проект Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Helm Tiller" +msgstr "" + +msgid "ClusterIntegration|Inactive" +msgstr "" + +msgid "ClusterIntegration|Ingress" +msgstr "" + +msgid "ClusterIntegration|Install" +msgstr "" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "" + +msgid "ClusterIntegration|Installed" +msgstr "" + +msgid "ClusterIntegration|Installing" +msgstr "" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "" msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "Узнайте больше на %{link_to_documentation}" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "" + msgid "ClusterIntegration|Machine type" msgstr "Тип машины" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" msgstr "Убедитесь, что ваша учетная запись %{link_to_requirements} для создания кластеров" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" -msgstr "Управление интеграцией кластера на вашем проекте Gitlab" +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" +msgstr "" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" msgstr "Управляйте кластером, перейдя по ссылке %{link_gke}" +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "" + +msgid "ClusterIntegration|Note:" +msgstr "Примечание:" + msgid "ClusterIntegration|Number of nodes" msgstr "Количество узлов" +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" +msgstr "" + msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgstr "Пожалуйста, убедитесь, что ваш аккаунт Google отвечает следующим требованиям:" +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "" + +msgid "ClusterIntegration|Project ID" +msgstr "" + +msgid "ClusterIntegration|Project namespace" +msgstr "" + msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "Пространство имен проекта (необязательное, уникальное)" @@ -574,8 +724,14 @@ msgstr "Удалить интеграцию с кластером" msgid "ClusterIntegration|Remove integration" msgstr "Удалить интеграцию" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." -msgstr "При удалении интеграции с кластером будет удалена конфигурация кластера, которую вы добавили в этот проект. Данное действие не удалит сам проект." +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "" + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "" + +msgid "ClusterIntegration|Save changes" +msgstr "" msgid "ClusterIntegration|See and edit the details for your cluster" msgstr "Просмотреть и отредактировать параметры для вашего кластера" @@ -589,33 +745,57 @@ msgstr "См. ваши проекты" msgid "ClusterIntegration|See zones" msgstr "См. зоны" +msgid "ClusterIntegration|Service token" +msgstr "" + +msgid "ClusterIntegration|Show" +msgstr "" + msgid "ClusterIntegration|Something went wrong on our end." msgstr " У нас что-то пошло не так." msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" -msgstr "Что-то пошло не так во время создания кластера в Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "" msgid "ClusterIntegration|Toggle Cluster" msgstr "Переключить Кластер" +msgid "ClusterIntegration|Token" +msgstr "" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "Если привязать кластер к этому проекту, вы с лёгкостью сможете использовать приложения для ревью, развертывать ваши приложения, запускать сборочные линии и многое другое." msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}" -msgstr "Ваша учетная запись должна иметь %{link_to_kubernetes_engine}" +msgstr "" msgid "ClusterIntegration|Zone" msgstr "Зона" msgid "ClusterIntegration|access to Google Kubernetes Engine" -msgstr "доступ к Google Kubernetes Engine" +msgstr "" msgid "ClusterIntegration|cluster" msgstr "кластер" +msgid "ClusterIntegration|documentation" +msgstr "" + msgid "ClusterIntegration|help page" msgstr "страница справки" +msgid "ClusterIntegration|installing applications" +msgstr "" + msgid "ClusterIntegration|meets the requirements" msgstr "отвечает требованиям" @@ -631,12 +811,6 @@ msgstr[0] "Коммит" msgstr[1] "Коммиты" msgstr[2] "Коммиты" -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "Зафиксировать %d файл" -msgstr[1] "Зафиксировать %d файла" -msgstr[2] "Зафиксировать %d файлов" - msgid "Commit Message" msgstr "Описание Коммита" @@ -718,14 +892,23 @@ msgstr "Руководство участника" msgid "Contributors" msgstr "Участники" +msgid "ContributorsPage|Building repository graph." +msgstr "" + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "" + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "" + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" -msgstr "Контролировать максимальное количество потоков фоновой загрузки LFS/вложений для этого вторичного узла" +msgstr "" msgid "Control the maximum concurrency of repository backfill for this secondary node" -msgstr "Контролировать максимальное количество потоков фоновой загрузки хранилища для этого вторичного узла" +msgstr "" msgid "Copy SSH public key to clipboard" -msgstr "Скопировать публичный ключ SSH в буфер обмена" +msgstr "" msgid "Copy URL to clipboard" msgstr "Копировать URL в буфер обмена" @@ -745,6 +928,9 @@ msgstr "Создать каталог" msgid "Create empty bare repository" msgstr "Создать пустой репозиторий" +msgid "Create epic" +msgstr "" + msgid "Create file" msgstr "Создать файл" @@ -772,6 +958,9 @@ msgstr "Тег" msgid "CreateTokenToCloneLink|create a personal access token" msgstr "создать персональный токен доступа" +msgid "Creating epic" +msgstr "" + msgid "Cron Timezone" msgstr "Временная зона Cron" @@ -817,6 +1006,12 @@ msgstr "Все" msgid "DashboardProjects|Personal" msgstr "Личные" +msgid "Dec" +msgstr "Дек." + +msgid "December" +msgstr "Декабрь" + msgid "Define a custom pattern with cron syntax" msgstr "Определить настраиваемый шаблон с синтаксисом cron" @@ -836,7 +1031,7 @@ msgid "Description" msgstr "Описание" msgid "Description templates allow you to define context-specific templates for issue and merge request description fields for your project." -msgstr "Шаблоны описаний позволяют вам определить специфичные шаблоны заполнения обсуждений и запросов на слияние в вашем проекте." +msgstr "" msgid "Details" msgstr "Подробная информация" @@ -851,7 +1046,7 @@ msgid "Dismiss Cycle Analytics introduction box" msgstr "Отключить блок введения в Аналитику Цикла" msgid "Dismiss Merge Request promotion" -msgstr "Отключить анонсы для Запросов на Слияние" +msgstr "" msgid "Don't show again" msgstr "Не показывать снова" @@ -892,6 +1087,72 @@ msgstr "Изменить расписание сборочной линии %{id msgid "Emails" msgstr "Email-адреса" +msgid "Environments|An error occurred while fetching the environments." +msgstr "" + +msgid "Environments|An error occurred while making the request." +msgstr "" + +msgid "Environments|Commit" +msgstr "" + +msgid "Environments|Deployment" +msgstr "" + +msgid "Environments|Environment" +msgstr "" + +msgid "Environments|Environments" +msgstr "" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "" + +msgid "Environments|Job" +msgstr "" + +msgid "Environments|New environment" +msgstr "" + +msgid "Environments|No deployments yet" +msgstr "" + +msgid "Environments|Open" +msgstr "" + +msgid "Environments|Re-deploy" +msgstr "" + +msgid "Environments|Read more about environments" +msgstr "" + +msgid "Environments|Rollback" +msgstr "" + +msgid "Environments|Show all" +msgstr "Показать все" + +msgid "Environments|Updated" +msgstr "" + +msgid "Environments|You don't have any environments right now." +msgstr "" + +msgid "Epic will be removed! Are you sure?" +msgstr "" + +msgid "Epics" +msgstr "" + +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" +msgstr "" + +msgid "Error creating epic" +msgstr "" + +msgid "Error occurred when toggling the notification subscription" +msgstr "" + msgid "EventFilterBy|Filter by all" msgstr "Фильтр по всему" @@ -931,6 +1192,12 @@ msgstr "Не удалось изменить владельца" msgid "Failed to remove the pipeline schedule" msgstr "Не удалось удалить расписание сборочной линии" +msgid "Feb" +msgstr "Фев." + +msgid "February" +msgstr "Февраль" + msgid "File name" msgstr "Имя файла" @@ -977,19 +1244,34 @@ msgid "GPG Keys" msgstr "GPG Ключи" msgid "Geo Nodes" -msgstr "Географические Узлы" +msgstr "" + +msgid "GeoNodeSyncStatus|Failed" +msgstr "" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "" + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "" + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "" msgid "Geo|File sync capacity" -msgstr "Объем хранилища для синхронизации файлов" +msgstr "" msgid "Geo|Groups to replicate" -msgstr "Группы для репликации" +msgstr "" msgid "Geo|Repository sync capacity" -msgstr "Объем хранилища для синхронизации репозитория" +msgstr "" msgid "Geo|Select groups to replicate." -msgstr "Выберите группы для репликации." +msgstr "" msgid "Git storage health information has been reset" msgstr "Информация о стабильности Git хранилища была сброшена" @@ -1042,9 +1324,6 @@ msgstr "Группы не найдены" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "Вы можете управлять правами и доступом участников вашей группы к каждому проекту в группе." -msgid "GroupsTreeRole|as" -msgstr "как" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "Вы уверены, что вы хотите покинуть группу \"${this.group.fullName}\"?" @@ -1075,6 +1354,9 @@ msgstr "К сожалению, по вашему запросу групп не msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "К сожалению, по вашему запросу групп или проектов не найдено" +msgid "Have your users email" +msgstr "" + msgid "Health Check" msgstr "Проверка работоспособности" @@ -1103,22 +1385,22 @@ msgid "Import repository" msgstr "Импорт репозитория" msgid "Improve Issue boards with GitLab Enterprise Edition." -msgstr "Улучшить доски обсуждений с помощью версии GitLab Enterprise Edition." +msgstr "" msgid "Improve issues management with Issue weight and GitLab Enterprise Edition." -msgstr "Улучшить управление обсуждениями с возможностью определения веса обсуждения при помощи GitLab Enterprise Edition." +msgstr "" msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition." -msgstr "Улучшить поиск при помощи Расширенного Глобального Поиска в версии GitLab Enterprise Edition." +msgstr "" msgid "Install a Runner compatible with GitLab CI" msgstr "Установите Gitlab Runner совместимый с Gitlab CI" msgid "Instance" msgid_plural "Instances" -msgstr[0] "Экземпляр" -msgstr[1] "Экземпляры" -msgstr[2] "Экземпляры" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" msgid "Internal - The group and any internal projects can be viewed by any logged in user." msgstr "Внутренний - Группу и включённые в неё проекты может видеть любой зарегистрированный пользователь." @@ -1133,10 +1415,7 @@ msgid "Introducing Cycle Analytics" msgstr "Внедрение Цикла Аналитик" msgid "Issue board focus mode" -msgstr "Режим фокусировки над доской обсуждений" - -msgid "Issue boards with milestones" -msgstr "Доски обсуждений с вехами" +msgstr "" msgid "Issue events" msgstr "События обсуждений" @@ -1145,11 +1424,29 @@ msgid "IssueBoards|Board" msgstr "Доска" msgid "IssueBoards|Boards" -msgstr "Доски" +msgstr "" msgid "Issues" msgstr "Обсуждения" +msgid "Jan" +msgstr "Янв." + +msgid "January" +msgstr "Январь" + +msgid "Jul" +msgstr "Июл." + +msgid "July" +msgstr "Июль" + +msgid "Jun" +msgstr "Июн." + +msgid "June" +msgstr "Июнь" + msgid "LFSStatus|Disabled" msgstr "Отключено" @@ -1205,7 +1502,7 @@ msgid "Leave project" msgstr "Покинуть проект" msgid "License" -msgstr "Лицензия" +msgstr "" msgid "Limited to showing %d event at most" msgid_plural "Limited to showing %d events at most" @@ -1220,14 +1517,23 @@ msgid "Locked" msgstr "Заблокировано" msgid "Locked Files" -msgstr "Заблокированные Файлы" +msgstr "" msgid "Login" msgstr "Войти" +msgid "Mar" +msgstr "Мар." + +msgid "March" +msgstr "Март" + msgid "Maximum git storage failures" msgstr "Максимальное количество сбоев хранилища git" +msgid "May" +msgstr "Май" + msgid "Median" msgstr "Среднее" @@ -1256,7 +1562,7 @@ msgid "More information is available|here" msgstr "Больше информации доступно|тут" msgid "Multiple issue boards" -msgstr "Сводные доски задач" +msgstr "" msgid "New Cluster" msgstr "Новый Кластер" @@ -1273,9 +1579,15 @@ msgstr "Новое Расписание Сборочной Линии" msgid "New branch" msgstr "Новая ветка" +msgid "New branch unavailable" +msgstr "" + msgid "New directory" msgstr "Новый каталог" +msgid "New epic" +msgstr "" + msgid "New file" msgstr "Новый файл" @@ -1312,6 +1624,9 @@ msgstr "Нет репозитория" msgid "No schedules" msgstr "Нет расписаний" +msgid "No time spent" +msgstr "" + msgid "None" msgstr "Пусто" @@ -1378,11 +1693,23 @@ msgstr "Отслеживать" msgid "Notifications" msgstr "Уведомления" +msgid "Nov" +msgstr "Нояб." + +msgid "November" +msgstr "Ноябрь" + msgid "Number of access attempts" msgstr "Количество попыток доступа" msgid "Number of failures before backing off" -msgstr "" +msgstr "Количество ошибок перед откатом" + +msgid "Oct" +msgstr "Окт." + +msgid "October" +msgstr "Октябрь" msgid "OfSearchInADropdown|Filter" msgstr "Фильтр" @@ -1390,6 +1717,9 @@ msgstr "Фильтр" msgid "Only project members can comment." msgstr "Только участники проекта могут оставлять комментарии." +msgid "Opened" +msgstr "" + msgid "OpenedNDaysAgo|Opened" msgstr "Открыто" @@ -1436,7 +1766,7 @@ msgid "Pipeline Schedules" msgstr "Расписания Сборочных Линий" msgid "Pipeline quota" -msgstr "Квота сборочной линии" +msgstr "" msgid "PipelineCharts|Failed:" msgstr "Неудача:" @@ -1522,6 +1852,9 @@ msgstr "со стадией" msgid "Pipeline|with stages" msgstr "со стадиями" +msgid "Please solve the reCAPTCHA" +msgstr "" + msgid "Preferences" msgstr "Предпочтения" @@ -1625,19 +1958,25 @@ msgid "ProjectNetworkGraph|Graph" msgstr "Граф" msgid "ProjectSettings|Contact an admin to change this setting." -msgstr "Обратитесь к администратору для изменения этой настройки." +msgstr "" + +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "" msgid "ProjectSettings|Only signed commits can be pushed to this repository." -msgstr "Только подписанные коммиты могут быть помещены в этот репозиторий." +msgstr "" + +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "" msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." -msgstr "Эта настройка применяется на уровне сервера и может быть переопределена администратором." +msgstr "" msgid "ProjectSettings|This setting is applied on the server level but has been overridden for this project." -msgstr "Эта настройка применяется на уровне сервера, но была переопределена для этого проекта." +msgstr "" msgid "ProjectSettings|This setting will be applied to all projects unless overridden by an admin." -msgstr "Эта настройка будет применена для всех проектов, если иное поведение не переопределено администратором." +msgstr "" msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails." msgstr "" @@ -1666,6 +2005,39 @@ msgstr "К сожалению, по вашему запросу проекты msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "Эта функциональность требует поддержки localStorage в вашем браузере" +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "" + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "" + +msgid "PrometheusService|Metrics" +msgstr "" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "" + +msgid "PrometheusService|Missing environment variable" +msgstr "" + +msgid "PrometheusService|Monitored" +msgstr "" + +msgid "PrometheusService|More information" +msgstr "" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "" + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" +msgstr "" + +msgid "PrometheusService|Prometheus monitoring" +msgstr "" + +msgid "PrometheusService|View environments" +msgstr "" + msgid "Public - The group and any public projects can be viewed without any authentication." msgstr "Публичный - Группу и включённые в неё проекты могут видеть все, без какой-либо проверки подлинности." @@ -1673,7 +2045,7 @@ msgid "Public - The project can be accessed without any authentication." msgstr "Публичный - Доступ к проекту возможен без какой-либо проверки подлинности." msgid "Push Rules" -msgstr "Правила Отправки" +msgstr "" msgid "Push events" msgstr "События отправки" @@ -1694,7 +2066,7 @@ msgid "RefSwitcher|Tags" msgstr "Теги" msgid "Registry" -msgstr "Реестр" +msgstr "" msgid "Related Commits" msgstr "Связанные коммиты" @@ -1762,6 +2134,9 @@ msgstr "Расписания" msgid "Scheduling Pipelines" msgstr "Планирование Сборочных Линий" +msgid "Scoped issue boards" +msgstr "" + msgid "Search branches and tags" msgstr "Найти ветки и теги" @@ -1783,6 +2158,12 @@ msgstr "Выбор временной зоны" msgid "Select target branch" msgstr "Выбор целевой ветки" +msgid "Sep" +msgstr "Сент." + +msgid "September" +msgstr "Сентябрь" + msgid "Service Templates" msgstr "Шаблоны Служб" @@ -1816,14 +2197,29 @@ msgstr[0] "Показано %d событие" msgstr[1] "Показано %d событий" msgstr[2] "Показано %d событий" +msgid "Sidebar|Change weight" +msgstr "" + +msgid "Sidebar|Edit" +msgstr "" + +msgid "Sidebar|No" +msgstr "" + +msgid "Sidebar|None" +msgstr "" + +msgid "Sidebar|Weight" +msgstr "" + msgid "Snippets" msgstr "Сниппеты" msgid "Something went wrong on our end." msgstr "У нас что-то пошло не так." -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" -msgstr "Что-то пошло не так при попытке изменения заблокированного состояния этого ${this.issuableDisplayName(this.issuableType)}" +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" +msgstr "" msgid "Something went wrong while fetching the projects." msgstr "Что-то пошло не так при получении проектов." @@ -1874,7 +2270,7 @@ msgid "SortOptions|Least popular" msgstr "Наименее популярный" msgid "SortOptions|Less weight" -msgstr "Меньший вес" +msgstr "" msgid "SortOptions|Milestone" msgstr "Веха" @@ -1886,7 +2282,7 @@ msgid "SortOptions|Milestone due soon" msgstr "Веха, наступающая раньше" msgid "SortOptions|More weight" -msgstr "Больший вес" +msgstr "" msgid "SortOptions|Most popular" msgstr "Наиболее популярный" @@ -1928,11 +2324,17 @@ msgid "SortOptions|Start soon" msgstr "Начатые недавно" msgid "SortOptions|Weight" -msgstr "Вес" +msgstr "" + +msgid "Source" +msgstr "Источник" msgid "Source code" msgstr "Исходный код" +msgid "Source is not available" +msgstr "" + msgid "Spam Logs" msgstr "Спам Логи" @@ -1951,6 +2353,9 @@ msgstr "Начать %{new_merge_request} с этих изменений" msgid "Start the Runner!" msgstr "Запустить GitLab Runner!" +msgid "Stopped" +msgstr "" + msgid "Subgroups" msgstr "Подгруппы" @@ -1972,6 +2377,75 @@ msgstr[2] "Теги" msgid "Tags" msgstr "Теги" +msgid "TagsPage|Browse commits" +msgstr "" + +msgid "TagsPage|Browse files" +msgstr "" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "" + +msgid "TagsPage|Cancel" +msgstr "" + +msgid "TagsPage|Create tag" +msgstr "" + +msgid "TagsPage|Delete tag" +msgstr "" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "" + +msgid "TagsPage|Edit release notes" +msgstr "" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "" + +msgid "TagsPage|Filter by tag name" +msgstr "" + +msgid "TagsPage|New Tag" +msgstr "" + +msgid "TagsPage|New tag" +msgstr "" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "" + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "" + +msgid "TagsPage|Release notes" +msgstr "" + +msgid "TagsPage|Repository has no tags yet." +msgstr "" + +msgid "TagsPage|Sort by" +msgstr "Сортировать по" + +msgid "TagsPage|Tags" +msgstr "Теги" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "" + +msgid "TagsPage|This tag has no release notes." +msgstr "" + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "" + +msgid "TagsPage|protected" +msgstr "" + msgid "Target Branch" msgstr "Ветка" @@ -1979,10 +2453,10 @@ msgid "Team" msgstr "Команда" msgid "Thanks! Don't show me this again" -msgstr "Спасибо! Больше не показывайте мне это сообщение" +msgstr "" msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project." -msgstr "Расширенный глобальный поиск в GitLab - это серьезный инструмент который сокращает ваше время. Вместо создания дублирующего кода и траты времени, вы можете искать код внутри других команд, который поможет вам в вашем проекте." +msgstr "" msgid "The circuitbreaker backoff threshold should be lower than the failure count threshold" msgstr "Порог срабатывания для СircuitBreaker должен быть меньше, чем порог срабатывания для определения сбоя" @@ -2053,6 +2527,9 @@ msgstr "Среднее значение в ряду. Пример: между 3, msgid "There are problems accessing Git storage: " msgstr "Проблемы с доступом к Git хранилищу: " +msgid "This board\\'s scope is reduced" +msgstr "" + msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "Эта ветка была изменена, пока вы её редактировали. Вы хотите создать новую ветку?" @@ -2074,6 +2551,9 @@ msgstr "Это означает, что вы не можете отправит msgid "This merge request is locked." msgstr "Запрос на слияние заблокирован." +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "Время до начала попадания обсуждения в планировщик" @@ -2224,14 +2704,26 @@ msgstr[2] "мин" msgid "Time|s" msgstr "с" +msgid "Title" +msgstr "" + msgid "Total Time" msgstr "Общее время" +msgid "Total issue time spent" +msgstr "" + msgid "Total test time for all commits/merges" msgstr "Общее время тестирования фиксаций/слияний" msgid "Track activity with Contribution Analytics." -msgstr "Отслеживать активность с помощью Аналитики Участников." +msgstr "" + +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "" + +msgid "Turn on Service Desk" +msgstr "" msgid "Unlock" msgstr "Разблокировать" @@ -2246,19 +2738,19 @@ msgid "Unsubscribe" msgstr "Отписаться" msgid "Upgrade your plan to activate Advanced Global Search." -msgstr "Повысьте ваш тарифный план, чтобы активировать Улучшенный Глобальный Поиск." +msgstr "" msgid "Upgrade your plan to activate Contribution Analytics." -msgstr "Повысьте ваш тарифный план, чтобы активировать Аналитики Участников." +msgstr "" msgid "Upgrade your plan to activate Group Webhooks." -msgstr "Повысьте ваш тарифный план, чтобы активировать Групповые Веб-Обработчики." +msgstr "" msgid "Upgrade your plan to activate Issue weight." -msgstr "Обновите ваш тарифный план для появления веса у обсуждений." +msgstr "" msgid "Upgrade your plan to improve Issue boards." -msgstr "Обновите ваш тарифный план, чтобы улучшить доски обсуждений." +msgstr "" msgid "Upload New File" msgstr "Загрузить новый файл" @@ -2269,6 +2761,9 @@ msgstr "Загрузить файл" msgid "UploadLink|click to upload" msgstr "кликните для загрузки" +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "" + msgid "Use the following registration token during setup:" msgstr "Используйте следующий токен регистрации в процессе установки:" @@ -2302,11 +2797,14 @@ msgstr "Хотите увидеть данные? Обратитесь к адм msgid "We don't have enough data to show this stage." msgstr "Информация по этапу отсутствует." +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "" + msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." -msgstr "Веб-обработчики позволяют вам вызывать адрес URL если, например, отправлен новый код или создано новое обсуждение. Вы можете настроить веб-обработчики так, чтобы они реагировали на определённые события, такие как отправки кода, обсуждения или запросы на слияние. Групповые веб-обработчики применяются ко всем проектам в группе и позволяют вам стандартизовать функциональность веб-обработчиков для всей вашей группы." +msgstr "" msgid "Weight" -msgstr "Вес" +msgstr "" msgid "When access to a storage fails. GitLab will prevent access to the storage for the time specified here. This allows the filesystem to recover. Repositories on failing shards are temporarly unavailable" msgstr "Когда доступ к хранилищу получить не удалось, GitLab приостановит доступ к хранилищу на время, указанное здесь. Это позволит файловой системе восстановиться. Репозитории на сбойных \"шардах\" будут временно недоступны" @@ -2414,7 +2912,7 @@ msgid "Wiki|Wiki Pages" msgstr "Вики Страницы" msgid "With contribution analytics you can have an overview for the activity of issues, merge requests and push events of your organization and its members." -msgstr "С аналитикой участников вы можете изучать активность в обсуждениях, запросах на слияние и событий отправки кода для вашей организации и её участников." +msgstr "" msgid "Withdraw Access Request" msgstr "Отменить запрос доступа" @@ -2431,17 +2929,11 @@ msgstr "Вы собираетесь удалить связь ответвлен msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "Вы собираетесь передать проект %{project_name_with_namespace} другому владельцу. Вы АБСОЛЮТНО уверены?" -msgid "You are on a read-only GitLab instance." -msgstr "Вы находитесь на экземпляре \"только для чтения\" кластера GitLab." - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "Вы находитесь на экземпляре \"только для чтения\" кластера GitLab. Если вы хотите произвести любые изменения, вы должны перейти на \"основной\" экземпляр по ссылке %{link_to_primary_node}." - msgid "You can only add files when you are on a branch" msgstr "Вы можете добавлять только файлы, когда находитесь в ветке" msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead." -msgstr "Вы не можете записывать на подчиненные экземпляры \"только для чтения\" кластера GitLab Geo. Используйте вместо этого %{link_to_primary_node}." +msgstr "" msgid "You cannot write to this read-only GitLab instance." msgstr "Вы не можете записывать на этот экземпляр \"только для чтения\" кластера GitLab." @@ -2476,6 +2968,9 @@ msgstr "Вы не сможете получать и отправлять код msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" msgstr "Вы не сможете получать и отправлять код проекта через SSH пока %{add_ssh_key_link} в ваш профиль." +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "" + msgid "Your comment will not be visible to the public." msgstr "Ваш комментарий не будет виден всем." @@ -2488,8 +2983,14 @@ msgstr "Ваше имя" msgid "Your projects" msgstr "Ваши проекты" +msgid "branch name" +msgstr "" + +msgid "by" +msgstr "" + msgid "commit" -msgstr "коммит" +msgstr "" msgid "day" msgid_plural "days" @@ -2515,8 +3016,11 @@ msgstr "пароль" msgid "personal access token" msgstr "токен для персонального доступа" +msgid "source" +msgstr "" + msgid "to help your contributors communicate effectively!" -msgstr "чтобы помочь вашим участникам взаимодействовать эффективнее!" +msgstr "" msgid "username" msgstr "имя пользователя" diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po index 53054bdaa27..fc62776a7a4 100644 --- a/locale/uk/gitlab.po +++ b/locale/uk/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-21 16:43-0500\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 06:39-0500\n" "Last-Translator: gitlab \n" "Language-Team: Ukrainian\n" "Language: uk_UA\n" @@ -61,6 +61,9 @@ msgstr[0] "%{storage_name}: спроба невдалого доступу до msgstr[1] "%{storage_name}: %{failed_attempts} невдалі спроби доступу до сховища:" msgstr[2] "%{storage_name}: %{failed_attempts} невдалих спроб доступу до сховища:" +msgid "%{text} is available" +msgstr "%{text} доступний" + msgid "(checkout the %{link} for information on how to install it)." msgstr "(перейдіть за посиланням %{link} для отримання інформації стосовно встановлення)." @@ -83,7 +86,7 @@ msgid "2FA enabled" msgstr "Двоетапна аутентифікація увімкнена" msgid "A collection of graphs regarding Continuous Integration" -msgstr "Це набір графічних елементів для безперервної інтеграції" +msgstr "Набір графіків відносно безперервної інтеграції" msgid "About auto deploy" msgstr "Про авто розгортання" @@ -95,7 +98,7 @@ msgid "Access Tokens" msgstr "Токени доступу" msgid "Access to failing storages has been temporarily disabled to allow the mount to recover. Reset storage information after the issue has been resolved to allow access again." -msgstr "Доступ до помилкових сховищ тимчасово відключений для можливості монтування та відновлення. Скиньте інформацію про сховища після усунення проблеми, щоб дозволити доступ." +msgstr "Доступ до сховищ, що вийшли з ладу, тимчасово прибраний задля відновлення монтування. Після вирішення проблеми обнуліть інформацію сховища для відновлення доступу." msgid "Account" msgstr "Обліковий запис" @@ -113,17 +116,14 @@ msgid "Add Changelog" msgstr "Додати список змін (Changelog)" msgid "Add Contribution guide" -msgstr "Додати керівництво для контриб’юторів" +msgstr "" msgid "Add Group Webhooks and GitLab Enterprise Edition." -msgstr "Додайте групу Webhooks та GitLab Enterprise Edition." +msgstr "" msgid "Add License" msgstr "Додати ліцензію" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "Додайте SSH ключ в свій профіль, щоб мати можливість завантажити чи надіслати зміни через SSH." - msgid "Add new directory" msgstr "Додати новий каталог" @@ -136,6 +136,15 @@ msgstr "Додаткові параметри" msgid "All" msgstr "Всі" +msgid "An error occurred when toggling the notification subscription" +msgstr "Виникла помилка під час зміни підписки на сповіщення" + +msgid "An error occurred when updating the issue weight" +msgstr "Збій під час оновлення ваги проблеми" + +msgid "An error occurred while fetching sidebar data" +msgstr "Виникла помилка під час завантаження даних для бічної панелі" + msgid "An error occurred. Please try again." msgstr "Сталась помилка. Спробуйте ще раз." @@ -145,11 +154,17 @@ msgstr "Зовнішній вигляд" msgid "Applications" msgstr "Додатки" +msgid "Apr" +msgstr "квіт." + +msgid "April" +msgstr "квітень" + msgid "Archived project! Repository is read-only" msgstr "Заархівований проект! Репозиторій доступний лише для читання" msgid "Are you sure you want to delete this pipeline schedule?" -msgstr "Ви впевнені, що хочете видалити цей розклад для Конвеєра?" +msgstr "" msgid "Are you sure you want to discard your changes?" msgstr "Ви впевнені, що бажаєте скасувати ваші зміни?" @@ -161,7 +176,7 @@ msgid "Are you sure you want to reset registration token?" msgstr "Ви впевнені, що бажаєте скинути реєстраційний токен?" msgid "Are you sure you want to reset the health check token?" -msgstr "Ви впевнені, що Ви хочете скинути цей ключ перевірки працездатності?" +msgstr "Ви впевнені, що хочете скинути цей ключ перевірки працездатності?" msgid "Are you sure?" msgstr "Ви впевнені?" @@ -172,6 +187,12 @@ msgstr "Артефакти" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "Прикріпити файл за допомогою перетягування або %{upload_link}" +msgid "Aug" +msgstr "серп." + +msgid "August" +msgstr "серпень" + msgid "Authentication Log" msgstr "Журнал автентифікації" @@ -205,6 +226,9 @@ msgstr "Дізнайтеся більше в %{link_to_documentation}" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." msgstr "Ви можете активувати %{link_to_settings} для цього проекту." +msgid "Available" +msgstr "Доступний" + msgid "Billing" msgstr "Білінг" @@ -236,10 +260,10 @@ msgid "BillingPlans|See all %{plan_name} features" msgstr "Подивіться всі можливості %{plan_name}" msgid "BillingPlans|This group uses the plan associated with its parent group." -msgstr "Ця група використовує план, пов'язаний з батьківською групою." +msgstr "Ця група використовує план, пов'язаний із батьківською групою." msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}." -msgstr "Для управління планом цієї групи відвідайте секцію оплати %{parent_billing_page_link}." +msgstr "Щоб керувати планом цієї групи, відвідайте розділ білінгу на %{parent_billing_page_link}." msgid "BillingPlans|Upgrade" msgstr "Підвищити" @@ -257,7 +281,7 @@ msgid "BillingPlans|paid annually at %{price_per_year}" msgstr "Оплачується щорічно %{price_per_year}" msgid "BillingPlans|per user" -msgstr "За користувача" +msgstr "" msgid "Branch" msgid_plural "Branches" @@ -271,11 +295,17 @@ msgstr "Гілка %{branch_name} створена. Для на msgid "Branch has changed" msgstr "Гілка змінилась" +msgid "Branch is already taken" +msgstr "Гілка вже існує" + +msgid "Branch name" +msgstr "Назва гілки" + msgid "BranchSwitcherPlaceholder|Search branches" msgstr "Пошук гілок" msgid "BranchSwitcherTitle|Switch branch" -msgstr "Переключити гілку" +msgstr "" msgid "Branches" msgstr "Гілки" @@ -401,13 +431,13 @@ msgid "ChangeTypeActionLabel|Pick into branch" msgstr "Вибрати в гілці" msgid "ChangeTypeActionLabel|Revert in branch" -msgstr "Скасувати у гілці" +msgstr "Анулювати у гілці" msgid "ChangeTypeAction|Cherry-pick" -msgstr "Cherry-pick" +msgstr "" msgid "ChangeTypeAction|Revert" -msgstr "Скасувати" +msgstr "Анулювати коміт" msgid "Changelog" msgstr "Список змін (Changelog)" @@ -418,14 +448,20 @@ msgstr "Графіки" msgid "Chat" msgstr "Чат" +msgid "Checking %{text} availability…" +msgstr "Перевірка доступності %{text}…" + +msgid "Checking branch availability..." +msgstr "Перевірка доступності гілки..." + msgid "Cherry-pick this commit" -msgstr "Cherry-pick в цьому коміті" +msgstr "" msgid "Cherry-pick this merge request" -msgstr "Cherry-pick в цьому запиті на злиття" +msgstr "" msgid "Choose which groups you wish to replicate to this secondary node. Leave blank to replicate all." -msgstr "Виберіть, які групи ви хочете реплікувати на цю вторинну ноду. Залиште порожнім, щоб реплікувати все." +msgstr "" msgid "CiStatusLabel|canceled" msgstr "скасовано" @@ -493,8 +529,41 @@ msgstr "Закрити" msgid "Cluster" msgstr "Кластер" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" -msgstr "%{link_to_container_project} напевно було створено під цим обліковим записом" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "%{appList} успішно встановлені на вашому кластері" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "%{boldNotice} Це додасть ресурси (наприклад балансер навантаження), що спричинить додаткові витрати. Перегляньте %{pricingLink}" + +msgid "ClusterIntegration|API URL" +msgstr "API URL" + +msgid "ClusterIntegration|Active" +msgstr "Активний" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "Додати існуючий кластер" + +msgid "ClusterIntegration|Add cluster" +msgstr "Додати кластер" + +msgid "ClusterIntegration|All" +msgstr "Всі" + +msgid "ClusterIntegration|Applications" +msgstr "Додатки" + +msgid "ClusterIntegration|CA Certificate" +msgstr "Сертифікат центру сертифікації" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "Набір сертифікатів (формат PEM)" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "Виберіть спосіб налаштування інтеграції з кластером" + +msgid "ClusterIntegration|Cluster" +msgstr "Кластер" msgid "ClusterIntegration|Cluster details" msgstr "Параметри кластера" @@ -509,7 +578,7 @@ msgid "ClusterIntegration|Cluster integration is enabled for this project." msgstr "Інтеграція із кластером увімкнена для цього проекту." msgid "ClusterIntegration|Cluster integration is enabled for this project. Disabling this integration will not affect your cluster, it will only temporarily turn off GitLab's connection to it." -msgstr "Для цього проекту увімкнена інтеграція із кластером. Викнення інтеграції не вплине на кластер, але з'єднання GitLab з ним буде тимчасово розірване." +msgstr "" msgid "ClusterIntegration|Cluster is being created on Google Kubernetes Engine..." msgstr "Створюється кластер в Google Kubernetes Engine..." @@ -517,21 +586,54 @@ msgstr "Створюється кластер в Google Kubernetes Engine..." msgid "ClusterIntegration|Cluster name" msgstr "Ім'я кластера" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" -msgstr "Кластер був успішно створений в Google Kubernetes Engine" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" +msgstr "Кластер був успішно створено в Google Kubernetes Engine. Оновіть сторінку, щоб переглянути додатову інформацію" + +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "Кластери дозволяють вам використовувати Review Apps, розгортати ваші програми, запускати ваші конвеєри і багато іншого простим способом. %{link_to_help_page}" + +msgid "ClusterIntegration|Copy API URL" +msgstr "Скопіювати URL API" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "Скопіювати сертифікат центру сертифікації" + +msgid "ClusterIntegration|Copy Token" +msgstr "Скопіювати Токен" msgid "ClusterIntegration|Copy cluster name" msgstr "Копіювати назву кластера" +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "Створити новий кластер у Google Engine прямо з GitLab" + msgid "ClusterIntegration|Create cluster" msgstr "Створити кластер" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" -msgstr "Створити новий кластер в Google Kubernetes Engine" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" +msgstr "Створити кластер в Google Kubernetes Engine" + +msgid "ClusterIntegration|Create on GKE" +msgstr "Створити в GKE" msgid "ClusterIntegration|Enable cluster integration" msgstr "Увімкнути інтеграцію із кластерами" +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "Вкажіть параметри існуючого кластера Kubernetes" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "Введіть докладний опис вашого кластера" + +msgid "ClusterIntegration|Environment pattern" +msgstr "Шаблон середовища" + +msgid "ClusterIntegration|GKE pricing" +msgstr "Вартість GKE" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "GitLab Runner" + msgid "ClusterIntegration|Google Cloud Platform project ID" msgstr "Ідентифікатор проекту в Google Cloud Platform" @@ -541,29 +643,77 @@ msgstr "Google Kubernetes Engine" msgid "ClusterIntegration|Google Kubernetes Engine project" msgstr "Проект Google Kubernetes Engine" +msgid "ClusterIntegration|Helm Tiller" +msgstr "Helm Tiller" + +msgid "ClusterIntegration|Inactive" +msgstr "Неактивні" + +msgid "ClusterIntegration|Ingress" +msgstr "Ingress" + +msgid "ClusterIntegration|Install" +msgstr "Встановити" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "Встановіть додатки у ваш кластер. Докладніше про %{helpLink}" + +msgid "ClusterIntegration|Installed" +msgstr "Встановлений" + +msgid "ClusterIntegration|Installing" +msgstr "Встановлення" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "Інтеграція кластерної автоматизації" + msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "Дізнайтеся більше про %{link_to_documentation}" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "Дізнайтеся більше про кластери" + msgid "ClusterIntegration|Machine type" msgstr "Тип машини" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" msgstr "Переконайтеся, що ваш обліковий запис %{link_to_requirements} для створення кластерів" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" -msgstr "Управління інтеграцією із кластером у вашому Gitlab-проекті." +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" +msgstr "Управління інтеграцією із кластером у вашому Gitlab-проекті" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" msgstr "Для керування своїм кластером перейдіть на %{link_gke}" +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "Кілька кластерів доступні в GitLab Enterprise Edition Premium і Ultimate" + +msgid "ClusterIntegration|Note:" +msgstr "Примітка:" + msgid "ClusterIntegration|Number of nodes" msgstr "Кількість вузлів" +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" +msgstr "Введіть інформацію про доступ до свого кластера. Якщо вам потрібна допомога, ви можете прочитати наші %{link_to_help_page} по кластерам" + msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" -msgstr "Будь-ласка впевніться, що ваш Google-аккаунт задовольняє наступним вимогам:" +msgstr "" + +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "Проблема налаштування кластера" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "Проблема налаштування списку кластерів" + +msgid "ClusterIntegration|Project ID" +msgstr "" + +msgid "ClusterIntegration|Project namespace" +msgstr "" msgid "ClusterIntegration|Project namespace (optional, unique)" -msgstr "Namespace проекту (не обов’язковий, унікальний)" +msgstr "" msgid "ClusterIntegration|Read our %{link_to_help_page} on cluster integration." msgstr "Прочитайте нашу документацію %{link_to_help_page} по інтеграції із кластером." @@ -574,8 +724,14 @@ msgstr "Видалити інтеграцію з кластером" msgid "ClusterIntegration|Remove integration" msgstr "Видалити інтеграцію" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." -msgstr "При видаленні інтеграції з кластером буде видалена конфігурація кластера, яку ви додали в цей проект. Дана дія не видалить сам проект." +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "Видалення кластерної інтеграції призведе до видалення конфігурації кластера, яку ви додали до цього проекту. Ця дія не буде видаляти ваш кластер у Google Kubernetes Engine." + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "Запит про початок встановлення не виконано" + +msgid "ClusterIntegration|Save changes" +msgstr "Зберегти зміни" msgid "ClusterIntegration|See and edit the details for your cluster" msgstr "Переглянути та редагувати параметри вашого кластера" @@ -589,15 +745,33 @@ msgstr "Переглянути ваші проекти" msgid "ClusterIntegration|See zones" msgstr "Переглянути зони" +msgid "ClusterIntegration|Service token" +msgstr "Токен Сервіса" + +msgid "ClusterIntegration|Show" +msgstr "Показати" + msgid "ClusterIntegration|Something went wrong on our end." msgstr "Щось пішло не так з нашого боку." msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" msgstr "Щось пішло не так під час створення кластера в Google Kubernetes Engine" +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "Під час встановлення %{title} сталася помилка" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "Немає кластерів для відображення" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "Цей обліковий запис має мати дозволи для створення кластера в %{link_to_container_project}, зазначеному нижче" + msgid "ClusterIntegration|Toggle Cluster" msgstr "Переключити Кластер" +msgid "ClusterIntegration|Token" +msgstr "Токен" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "За допомогою підключеного до цього проекту кластера, ви можете використовувати Review Apps, розгортати ваші проекти, запускати конвеєри збірки та багато іншого." @@ -613,9 +787,15 @@ msgstr "доступ до Google Kubernetes Engine" msgid "ClusterIntegration|cluster" msgstr "кластер" +msgid "ClusterIntegration|documentation" +msgstr "документація" + msgid "ClusterIntegration|help page" msgstr "сторінка допомоги" +msgid "ClusterIntegration|installing applications" +msgstr "встановлення додатків" + msgid "ClusterIntegration|meets the requirements" msgstr "задовольняє вимогам" @@ -631,12 +811,6 @@ msgstr[0] "Коміт" msgstr[1] "Коміта" msgstr[2] "Комітів" -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "Закомітити %d файл" -msgstr[1] "Закомітити %d файли" -msgstr[2] "Закомітити %d файлів" - msgid "Commit Message" msgstr "Коміт-повідомелння" @@ -704,7 +878,7 @@ msgid "ContainerRegistry|Tag" msgstr "Тег" msgid "ContainerRegistry|Tag ID" -msgstr "Тег ID" +msgstr "" msgid "ContainerRegistry|Use different image names" msgstr "Використовуйте різні імена образів" @@ -713,11 +887,20 @@ msgid "ContainerRegistry|With the Docker Container Registry integrated into GitL msgstr "За допомогою вбудованого в GitLab реєстру Docker контейнерів кожен проект може мати власне місце для зберігання Docker образів." msgid "Contribution guide" -msgstr "Керівництво контриб’юторів" +msgstr "" msgid "Contributors" msgstr "Контриб’ютори" +msgid "ContributorsPage|Building repository graph." +msgstr "" + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "Коміти в %{branch_name}, за винятком комітів злиття. Обмежено 6000 комітів." + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "Будь ласка, зачекайте, ця сторінка автоматично оновиться, коли буде готова." + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" msgstr "Задати максимальну кількість потоків для фонового завантаження LFS/вкладень для цього вторинного вузла" @@ -737,7 +920,7 @@ msgid "Create New Directory" msgstr "Створити новий каталог" msgid "Create a personal access token on your account to pull or push via %{protocol}." -msgstr "Створити токен доступу для вашого аккауета, щоб відправляти або отримувати через %{protocol}." +msgstr "" msgid "Create directory" msgstr "Створити каталог" @@ -745,6 +928,9 @@ msgstr "Створити каталог" msgid "Create empty bare repository" msgstr "Створити порожній репозиторій" +msgid "Create epic" +msgstr "Створити епік" + msgid "Create file" msgstr "Створити файл" @@ -772,6 +958,9 @@ msgstr "Тег" msgid "CreateTokenToCloneLink|create a personal access token" msgstr "Створити токен для особистого доступу" +msgid "Creating epic" +msgstr "Створення епіку" + msgid "Cron Timezone" msgstr "Часовий пояс Cron" @@ -788,10 +977,10 @@ msgid "Cycle Analytics" msgstr "Аналіз циклу" msgid "Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project." -msgstr "Аналітика циклу дає огляд того, скільки часу потрібно, щоб перейти від ідеї до виробництва у вашому проекті." +msgstr "" msgid "CycleAnalyticsStage|Code" -msgstr "Код" +msgstr "" msgid "CycleAnalyticsStage|Issue" msgstr "Проблема" @@ -800,13 +989,13 @@ msgid "CycleAnalyticsStage|Plan" msgstr "Планування" msgid "CycleAnalyticsStage|Production" -msgstr "ПРОД" +msgstr "" msgid "CycleAnalyticsStage|Review" msgstr "Затвердження" msgid "CycleAnalyticsStage|Staging" -msgstr "ДЕВ" +msgstr "Staging" msgid "CycleAnalyticsStage|Test" msgstr "Тестування" @@ -817,6 +1006,12 @@ msgstr "Всі" msgid "DashboardProjects|Personal" msgstr "Особисті" +msgid "Dec" +msgstr "груд." + +msgid "December" +msgstr "грудень" + msgid "Define a custom pattern with cron syntax" msgstr "Визначте власний шаблон за допомогою синтаксису cron" @@ -830,13 +1025,13 @@ msgstr[1] "Розгортання" msgstr[2] "Розгортань" msgid "Deploy Keys" -msgstr "Ключи для розгортування" +msgstr "" msgid "Description" msgstr "Опис" msgid "Description templates allow you to define context-specific templates for issue and merge request description fields for your project." -msgstr "Шаблони опису дозволяють визначити конкретні шаблони обговорень та запитів на зливання для вашого проекту." +msgstr "" msgid "Details" msgstr "Деталі" @@ -851,7 +1046,7 @@ msgid "Dismiss Cycle Analytics introduction box" msgstr "Відмінити блок вступу до Аналитики Циклу" msgid "Dismiss Merge Request promotion" -msgstr "Не показувати промоушн запитів на злиття" +msgstr "Відхилити рекламу для Запитів на злиття" msgid "Don't show again" msgstr "Не показувати знову" @@ -878,7 +1073,7 @@ msgid "DownloadCommit|Email Patches" msgstr "Email-патчи" msgid "DownloadCommit|Plain Diff" -msgstr "Plain Diff" +msgstr "" msgid "DownloadSource|Download" msgstr "Завантажити" @@ -892,6 +1087,72 @@ msgstr "Редагувати Розклад Конвеєра %{id}" msgid "Emails" msgstr "Адреси електронної пошти" +msgid "Environments|An error occurred while fetching the environments." +msgstr "Виникла помилка при завантаженні середовищ." + +msgid "Environments|An error occurred while making the request." +msgstr "Під час виконання запиту сталася помилка." + +msgid "Environments|Commit" +msgstr "Коміт" + +msgid "Environments|Deployment" +msgstr "Розгортання" + +msgid "Environments|Environment" +msgstr "Середовище" + +msgid "Environments|Environments" +msgstr "Середовища" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "" + +msgid "Environments|Job" +msgstr "Завдання" + +msgid "Environments|New environment" +msgstr "Нове середовище" + +msgid "Environments|No deployments yet" +msgstr "Ще немає розгортань" + +msgid "Environments|Open" +msgstr "Відкрити" + +msgid "Environments|Re-deploy" +msgstr "Повторно розгорнути" + +msgid "Environments|Read more about environments" +msgstr "Дізнайтеся більше про середовища" + +msgid "Environments|Rollback" +msgstr "Відкотити" + +msgid "Environments|Show all" +msgstr "Показати всі" + +msgid "Environments|Updated" +msgstr "Оновлено" + +msgid "Environments|You don't have any environments right now." +msgstr "Ви поки не налаштували жодного середовища." + +msgid "Epic will be removed! Are you sure?" +msgstr "Епік буде видалено! Ви впевнені?" + +msgid "Epics" +msgstr "Епіки" + +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" +msgstr "Епіки дозволяють керувати вашим портфелем проектів ефективніше та з меншими зусиллями" + +msgid "Error creating epic" +msgstr "Помилка при створенні епіку" + +msgid "Error occurred when toggling the notification subscription" +msgstr "Сталася помилка під час підключення підписки на сповіщення" + msgid "EventFilterBy|Filter by all" msgstr "Фільтрувати по всім" @@ -905,7 +1166,7 @@ msgid "EventFilterBy|Filter by merge events" msgstr "Фільтрувати по запитам на злиття" msgid "EventFilterBy|Filter by push events" -msgstr "Фільтрувати по push-подіях" +msgstr "" msgid "EventFilterBy|Filter by team" msgstr "Фільтрувати по команді" @@ -929,7 +1190,13 @@ msgid "Failed to change the owner" msgstr "Не вдалося змінити власника" msgid "Failed to remove the pipeline schedule" -msgstr "Не вдалося видалити розклад Конвеєра" +msgstr "" + +msgid "Feb" +msgstr "лют." + +msgid "February" +msgstr "лютий" msgid "File name" msgstr "Ім'я файлу" @@ -950,7 +1217,7 @@ msgid "FirstPushedBy|First" msgstr "Перший" msgid "FirstPushedBy|pushed by" -msgstr "Надіслані зміни від" +msgstr "" msgid "Fork" msgid_plural "Forks" @@ -968,10 +1235,10 @@ msgid "Format" msgstr "Формат" msgid "From issue creation until deploy to production" -msgstr "З моменту створення проблеми до розгортання на ПРОД" +msgstr "" msgid "From merge request merge until deploy to production" -msgstr "З об'єднання запиту злиття до розгортання на ПРОД" +msgstr "" msgid "GPG Keys" msgstr "GPG ключі" @@ -979,6 +1246,21 @@ msgstr "GPG ключі" msgid "Geo Nodes" msgstr "Гео-Вузли" +msgid "GeoNodeSyncStatus|Failed" +msgstr "Невдало" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "Вузол не працює або зламаний." + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "Вузол працює повільно, перевантажений або тільки що відновився після збою." + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "Несинхронізовано" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "Синхронізовано" + msgid "Geo|File sync capacity" msgstr "Пропускна здатність синхронізації файлів" @@ -1042,9 +1324,6 @@ msgstr "Групи не знайдені" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "Ви можете керувати правами доступу членів групи мати доступ до кожного проекту в ній." -msgid "GroupsTreeRole|as" -msgstr "як" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "Ви впевнені, що хочете залишити групу \"${this.group.fullName}\"?" @@ -1075,6 +1354,9 @@ msgstr "На жаль жодна группа не задовольняє пар msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "На жаль жодна группа чи проект не задовольняє параметрам вашого запиту" +msgid "Have your users email" +msgstr "Електронна пошта для звертань користувачів" + msgid "Health Check" msgstr "Перевірки працездатності" @@ -1100,10 +1382,10 @@ msgid "Housekeeping successfully started" msgstr "Очищення успішно розпочато" msgid "Import repository" -msgstr "Імпорт репозеторія" +msgstr "" msgid "Improve Issue boards with GitLab Enterprise Edition." -msgstr "Покращити дошки обговорень за допомогою версії GitLab Enterprise Edition." +msgstr "" msgid "Improve issues management with Issue weight and GitLab Enterprise Edition." msgstr "Покращити управління проблемами з можливістю визначення ваги проблеми за допомогою GitLab Enterprise Edition." @@ -1117,7 +1399,7 @@ msgstr "Встановіть Runner, сумісний з GitLab CI" msgid "Instance" msgid_plural "Instances" msgstr[0] "Інстанс" -msgstr[1] "Інстанса" +msgstr[1] "Iнстанси" msgstr[2] "Інстансів" msgid "Internal - The group and any internal projects can be viewed by any logged in user." @@ -1133,10 +1415,7 @@ msgid "Introducing Cycle Analytics" msgstr "Представляємо аналітику циклу" msgid "Issue board focus mode" -msgstr "Режим фокусування над дошкою обговорень" - -msgid "Issue boards with milestones" -msgstr "Дошка обговорень із етапами" +msgstr "Режим фокусування для дошки обговорень" msgid "Issue events" msgstr "Проблеми" @@ -1150,6 +1429,24 @@ msgstr "Дошки" msgid "Issues" msgstr "Проблеми" +msgid "Jan" +msgstr "січ." + +msgid "January" +msgstr "січень" + +msgid "Jul" +msgstr "лип." + +msgid "July" +msgstr "липень" + +msgid "Jun" +msgstr "чер." + +msgid "June" +msgstr "червень" + msgid "LFSStatus|Disabled" msgstr "Вимкнено" @@ -1184,7 +1481,7 @@ msgid "Last updated" msgstr "Востаннє оновленно" msgid "LastPushEvent|You pushed to" -msgstr "Ви надіслали зміни до" +msgstr "" msgid "LastPushEvent|at" msgstr "в" @@ -1225,9 +1522,18 @@ msgstr "Заблоковані файли" msgid "Login" msgstr "Вхід" +msgid "Mar" +msgstr "бер." + +msgid "March" +msgstr "березень" + msgid "Maximum git storage failures" msgstr "Максимальна кількість невдач в сховищі даних git" +msgid "May" +msgstr "травень" + msgid "Median" msgstr "Медіана" @@ -1238,7 +1544,7 @@ msgid "Merge Requests" msgstr "Запити на злиття" msgid "Merge events" -msgstr "Запити на злиття" +msgstr "" msgid "Merge request" msgstr "Запит на злиття" @@ -1256,7 +1562,7 @@ msgid "More information is available|here" msgstr "тут" msgid "Multiple issue boards" -msgstr "Зведені дошки обговорення" +msgstr "Кілька дошок обговорення" msgid "New Cluster" msgstr "Новий кластер" @@ -1273,9 +1579,15 @@ msgstr "Новий розклад Конвеєра" msgid "New branch" msgstr "Нова гілка" +msgid "New branch unavailable" +msgstr "Нова гілка недоступна" + msgid "New directory" msgstr "Новий каталог" +msgid "New epic" +msgstr "Новий епік" + msgid "New file" msgstr "Новий файл" @@ -1295,7 +1607,7 @@ msgid "New schedule" msgstr "Новий Розклад" msgid "New snippet" -msgstr "Новий сніппет" +msgstr "" msgid "New subgroup" msgstr "Нова підгрупа" @@ -1307,11 +1619,14 @@ msgid "No container images stored for this project. Add one by following the ins msgstr "В цьому проекті немає жодного образа контейнера. Додайте його за інструкціями вище." msgid "No repository" -msgstr "Немає репозеторія" +msgstr "" msgid "No schedules" msgstr "немає Розкладів" +msgid "No time spent" +msgstr "Немає витраченого часу" + msgid "None" msgstr "Жоден" @@ -1328,13 +1643,13 @@ msgid "NotificationEvent|Close issue" msgstr "Проблема закрита" msgid "NotificationEvent|Close merge request" -msgstr "Запит на об'єднання закритий" +msgstr "" msgid "NotificationEvent|Failed pipeline" msgstr "Невдача в конвеєрі" msgid "NotificationEvent|Merge merge request" -msgstr "Об'єднати запит на злиття" +msgstr "" msgid "NotificationEvent|New issue" msgstr "Нова проблема" @@ -1349,7 +1664,7 @@ msgid "NotificationEvent|Reassign issue" msgstr "Перепризначити проблему" msgid "NotificationEvent|Reassign merge request" -msgstr "Перепризначити запит на злиття" +msgstr "" msgid "NotificationEvent|Reopen issue" msgstr "Повторне відкриття проблему" @@ -1378,18 +1693,33 @@ msgstr "Відстежувати" msgid "Notifications" msgstr "Сповіщення" +msgid "Nov" +msgstr "лист." + +msgid "November" +msgstr "листопад" + msgid "Number of access attempts" msgstr "Кількість спроб доступу" msgid "Number of failures before backing off" msgstr "Кількість помилок до призупинення" +msgid "Oct" +msgstr "жовт." + +msgid "October" +msgstr "жовтень" + msgid "OfSearchInADropdown|Filter" msgstr "Фільтр" msgid "Only project members can comment." msgstr "Тільки учасники проекту можуть залишати коментарі." +msgid "Opened" +msgstr "Відкрито" + msgid "OpenedNDaysAgo|Opened" msgstr "Відкрито" @@ -1469,7 +1799,7 @@ msgid "PipelineSchedules|Input variable key" msgstr "Введіть ім'я змінної" msgid "PipelineSchedules|Input variable value" -msgstr "Вхідні значення змінних" +msgstr "" msgid "PipelineSchedules|Next Run" msgstr "Наступний запуск" @@ -1478,7 +1808,7 @@ msgid "PipelineSchedules|None" msgstr "Немає" msgid "PipelineSchedules|Provide a short description for this pipeline" -msgstr "Задайте короткий опис для цього Конвеєру" +msgstr "" msgid "PipelineSchedules|Remove variable row" msgstr "Видалити змінні" @@ -1493,7 +1823,7 @@ msgid "PipelineSchedules|Variables" msgstr "Змінні" msgid "PipelineSheduleIntervalPattern|Custom" -msgstr "Власні" +msgstr "" msgid "Pipelines" msgstr "Конвеєри" @@ -1522,11 +1852,14 @@ msgstr "зі стадією" msgid "Pipeline|with stages" msgstr "зі стадіями" +msgid "Please solve the reCAPTCHA" +msgstr "Будь ласка, пройдіть reCAPTCHA" + msgid "Preferences" msgstr "Налаштування" msgid "Private - Project access must be granted explicitly to each user." -msgstr "Приватний — доступ до проекту повинен надаватися кожному користувачеві." +msgstr "" msgid "Private - The group and its projects can only be viewed by members." msgstr "Приватна — цю групу та її проекти можуть бачити тільки її користувачі." @@ -1583,7 +1916,7 @@ msgid "Project '%{project_name}' was successfully updated." msgstr "Проект '%{project_name}' успішно оновлено." msgid "Project access must be granted explicitly to each user." -msgstr "Доступ до проекту повинен надаватися кожному користувачеві." +msgstr "" msgid "Project details" msgstr "Деталі проекту" @@ -1607,7 +1940,7 @@ msgid "ProjectFeature|Disabled" msgstr "Вимкнено" msgid "ProjectFeature|Everyone with access" -msgstr "Все з доступом" +msgstr "" msgid "ProjectFeature|Only team members" msgstr "Тільки члени команди" @@ -1619,7 +1952,7 @@ msgid "ProjectLastActivity|Never" msgstr "Ніколи" msgid "ProjectLifecycle|Stage" -msgstr "Етап" +msgstr "Стадія" msgid "ProjectNetworkGraph|Graph" msgstr "Історія" @@ -1627,9 +1960,15 @@ msgstr "Історія" msgid "ProjectSettings|Contact an admin to change this setting." msgstr "Зверніться до адміністратора, щоб змінити це налаштування." +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "Зразу запускати конвеєр у гілкці за замовчуванням" + msgid "ProjectSettings|Only signed commits can be pushed to this repository." msgstr "Тільки підписані коміти можуть бути надіслані в цей репозиторій." +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "Проблема налаштування параметрів CI / CD JavaScript" + msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." msgstr "Цей параметр застосовується на рівні сервера та може бути перевизначений адміністратором." @@ -1640,7 +1979,7 @@ msgid "ProjectSettings|This setting will be applied to all projects unless overr msgstr "Цей параметр буде застосовано до всіх проектів, якщо адміністратор не змінить його." msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails." -msgstr "Користувачі можуть виконувати push в цей репозиторій лише тих комітів, які містять одну із підтверджених адрес електронної пошти." +msgstr "" msgid "Projects" msgstr "Проекти" @@ -1666,6 +2005,39 @@ msgstr "На жаль, по вашоу запиту проектів не зна msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "Ця функція потребує підтримки localStorage вашим браузером" +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "За замовчуванням, Prometheus запускається за адресою ‘http://localhost:9090’. Не рекомендується змінювати цю адресу і порт, бо це може призвести до конфлікту з іншими сервісами запущеними на GitLab сервері." + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "Пошук та налаштування метрик..." + +msgid "PrometheusService|Metrics" +msgstr "Метрики" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "Метрики автоматично налаштовуються та контролюються на основі набору метрик від популярних експортерів." + +msgid "PrometheusService|Missing environment variable" +msgstr "Пропущена змінна середовища" + +msgid "PrometheusService|Monitored" +msgstr "Моніторинг підключено" + +msgid "PrometheusService|More information" +msgstr "Додаткова інформація" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "Жодні метрики не відслідковуються. Для початку моніторингу, розгорніть середовище." + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" +msgstr "Базова адреса Prometheus API, наприклад http://prometheus.example.com/" + +msgid "PrometheusService|Prometheus monitoring" +msgstr "Моніторинг Prometheus" + +msgid "PrometheusService|View environments" +msgstr "Перегляд середовищ" + msgid "Public - The group and any public projects can be viewed without any authentication." msgstr "Публічна — група та всі публічні проекти можуть переглядатися без автентифікації." @@ -1673,10 +2045,10 @@ msgid "Public - The project can be accessed without any authentication." msgstr "Публічний — проект может переглядатися без автентифікації." msgid "Push Rules" -msgstr "Push-правила" +msgstr "" msgid "Push events" -msgstr "Push-події" +msgstr "" msgid "PushRule|Committer restriction" msgstr "Обмеження для коміттера" @@ -1685,7 +2057,7 @@ msgid "Read more" msgstr "Докладніше" msgid "Readme" -msgstr "Прочитай Мене" +msgstr "Інструкція" msgid "RefSwitcher|Branches" msgstr "Гілки" @@ -1700,19 +2072,19 @@ msgid "Related Commits" msgstr "Пов'язані Коміти" msgid "Related Deployed Jobs" -msgstr "Пов’язані розгорнуті задачі (Jobs)" +msgstr "Пов’язані розгорнуті завдання (Jobs)" msgid "Related Issues" msgstr "Пов’язані Проблеми (Issues)" msgid "Related Jobs" -msgstr "Пов’язані Задачі (Jobs)" +msgstr "Пов’язані Завдання (Jobs)" msgid "Related Merge Requests" msgstr "Пов'язані запити на злиття" msgid "Related Merged Requests" -msgstr "Пов'язані об'єднані запити" +msgstr "" msgid "Remind later" msgstr "Нагадати пізніше" @@ -1736,10 +2108,10 @@ msgid "Reset runners registration token" msgstr "Скинути реєстраційний токен runner-ів" msgid "Revert this commit" -msgstr "Скасувати цей коміт" +msgstr "Анулювати цей коміт" msgid "Revert this merge request" -msgstr "Скасувати цей запит на злиття" +msgstr "Анулювати цей запит на злиття" msgid "SSH Keys" msgstr "Ключі SSH" @@ -1751,7 +2123,7 @@ msgid "Save changes" msgstr "Зберегти зміни" msgid "Save pipeline schedule" -msgstr "Зберегти Розклад Конвеєра" +msgstr "" msgid "Schedule a new pipeline" msgstr "Розклад нового конвеєра" @@ -1762,6 +2134,9 @@ msgstr "Розклади" msgid "Scheduling Pipelines" msgstr "Планування конвеєрів" +msgid "Scoped issue boards" +msgstr "Тематичні дошки проблем" + msgid "Search branches and tags" msgstr "Пошук гілок та тегів" @@ -1783,11 +2158,17 @@ msgstr "Вибрати часовий пояс" msgid "Select target branch" msgstr "Вибір цільової гілки" +msgid "Sep" +msgstr "вер." + +msgid "September" +msgstr "вересень" + msgid "Service Templates" msgstr "Сервіс шаблонів" msgid "Set a password on your account to pull or push via %{protocol}." -msgstr "Встановіть пароль свого облікового запису, щоб відправляти або отримувати код через %{protocol}." +msgstr "" msgid "Set up CI" msgstr "Налаштування CI" @@ -1816,14 +2197,29 @@ msgstr[0] "Показано %d подію" msgstr[1] "Показано %d події" msgstr[2] "Показано %d подій" +msgid "Sidebar|Change weight" +msgstr "Змінити вагу" + +msgid "Sidebar|Edit" +msgstr "Редагувати" + +msgid "Sidebar|No" +msgstr "Ні" + +msgid "Sidebar|None" +msgstr "Немає" + +msgid "Sidebar|Weight" +msgstr "Вага" + msgid "Snippets" -msgstr "Фрагменти" +msgstr "" msgid "Something went wrong on our end." msgstr "Щось пішло не так з нашого боку" -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" -msgstr "Щось пішло не так, намагаючись змінити статус блокування цього ${this.issuableDisplayName(this.issuableType)}" +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" +msgstr "Щось пішло не так, при спробі зміни стану блокування ${this.issuableDisplayName}" msgid "Something went wrong while fetching the projects." msgstr "Щось пішло не так під час отримання проектів" @@ -1874,7 +2270,7 @@ msgid "SortOptions|Least popular" msgstr "Найменш популярний" msgid "SortOptions|Less weight" -msgstr "Найменша вага" +msgstr "Менша вага" msgid "SortOptions|Milestone" msgstr "Етап" @@ -1886,7 +2282,7 @@ msgid "SortOptions|Milestone due soon" msgstr "Етап запланований незабаром" msgid "SortOptions|More weight" -msgstr "Найбільша вага" +msgstr "Більша вага" msgid "SortOptions|Most popular" msgstr "Найбільш популярний" @@ -1930,9 +2326,15 @@ msgstr "Розпочатий нещодавно" msgid "SortOptions|Weight" msgstr "Вага" +msgid "Source" +msgstr "Джерело" + msgid "Source code" msgstr "Код" +msgid "Source is not available" +msgstr "Джерело недоступне" + msgid "Spam Logs" msgstr "Спам-журнал" @@ -1951,6 +2353,9 @@ msgstr "Почати %{new_merge_request} з цими змінами" msgid "Start the Runner!" msgstr "Запустіть Runner!" +msgid "Stopped" +msgstr "Зупинено" + msgid "Subgroups" msgstr "Підгрупи" @@ -1958,10 +2363,10 @@ msgid "Subscribe" msgstr "Підписатися" msgid "Switch branch/tag" -msgstr "тег" +msgstr "" msgid "System Hooks" -msgstr "Системні Hook'и" +msgstr "" msgid "Tag" msgid_plural "Tags" @@ -1972,6 +2377,75 @@ msgstr[2] "Тегів" msgid "Tags" msgstr "Теги" +msgid "TagsPage|Browse commits" +msgstr "Переглянути коміти" + +msgid "TagsPage|Browse files" +msgstr "Переглянути файли" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "Неможливо знайти HEAD коміт до цього тегу" + +msgid "TagsPage|Cancel" +msgstr "Скасувати" + +msgid "TagsPage|Create tag" +msgstr "Створити тег" + +msgid "TagsPage|Delete tag" +msgstr "Видалити тег" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "Видалення тега %{tag_name} не може бути скасовано. Ви впевнені?" + +msgid "TagsPage|Edit release notes" +msgstr "Редагувати опис релізу" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "Ім'я існуючої гілки, тега або SHA коміта" + +msgid "TagsPage|Filter by tag name" +msgstr "Фільтр по імені тега" + +msgid "TagsPage|New Tag" +msgstr "Новий тег" + +msgid "TagsPage|New tag" +msgstr "Новий тег" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "При бажанні Ви можете додати повідомлення в тег." + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "" + +msgid "TagsPage|Release notes" +msgstr "Опис релізу" + +msgid "TagsPage|Repository has no tags yet." +msgstr "Репозиторій не містить тегів." + +msgid "TagsPage|Sort by" +msgstr "Сортувати за" + +msgid "TagsPage|Tags" +msgstr "Теги" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "Теги дають можливість позначати певні моменти в історії як важливі" + +msgid "TagsPage|This tag has no release notes." +msgstr "Цей тег не містить опису релізу." + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "Використовуйте команду git tag, щоб додати новий:" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "Напишіть свій опис релізу або перетягніть файли сюди..." + +msgid "TagsPage|protected" +msgstr "захищений" + msgid "Target Branch" msgstr "Цільова гілка" @@ -1982,22 +2456,22 @@ msgid "Thanks! Don't show me this again" msgstr "Дякую! Більше не показувати це повідомлення" msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project." -msgstr "Розширений глобальний пошук в GitLab - це потужний інструмент який заощаджує ваш час. Замість дублювання коду і витрати часу, ви можете шукати код всередині інших команд, який може допомогти у вашому проекті." +msgstr "Розширений глобальний пошук в GitLab - це потужний інструмент який заощаджує ваш час. Замість дублювання коду і витрати часу, ви можете шукати код інших команд, який може допомогти у вашому проекті." msgid "The circuitbreaker backoff threshold should be lower than the failure count threshold" msgstr "Поріг призупинення circuitbreaker має бути нижчий за поріг повного відключення" msgid "The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request." -msgstr "На стадії написання коду, показує час першого коміту до створення запиту на об'єднання. Дані будуть автоматично додані після створення вашого першого запиту на об'єднання." +msgstr "" msgid "The collection of events added to the data gathered for that stage." -msgstr "Колекція подій додана до даних, зібраних для цього етапу." +msgstr "" msgid "The fork relationship has been removed." -msgstr "Зв'язок форка видалена." +msgstr "" msgid "The issue stage shows the time it takes from creating an issue to assigning 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 "Етап випуску показує, скільки часу потрібно від створення проблеми до присвоєння випуску, або додавання проблеми в вашу дошку проблем. Почніть створювати проблеми, щоб переглядати дані для цього етапу." +msgstr "" msgid "The number of attempts GitLab will make to access a storage." msgstr "Кількість спроб, які зробить GitLab для отримання доступу до сховища даних." @@ -2015,10 +2489,10 @@ msgid "The pipelines schedule runs pipelines in the future, repeatedly, for spec msgstr "Розклад конвеєрів запускає в майбутньому конвеєри, для певних гілок або тегів. Заплановані конвеєри успадковують обмеження на доступ до проекту на основі пов'язаного з ними користувача." msgid "The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit." -msgstr "На етапі планування відображається час від попереднього кроку до першого коміту. Додається автоматично, як тільки відправится перший коміт." +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 "Стадія ПРОДакшин показує загальний час між створенням проблеми та розгортанням коду у ПРОДакшині. Дані будуть автоматично додані після завершення повної ідеї до ПРОДакшин циклу." +msgstr "" msgid "The project can be accessed by any logged in user." msgstr "Доступ до проекту можливий будь-яким зареєстрованим користувачем." @@ -2030,13 +2504,13 @@ msgid "The repository for this project does not exist." msgstr "Репозиторій для цього проекту не існує." msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request." -msgstr "Стадія огляду показує час від створення запиту про об'єднання до його виконання. Дані будуть автоматично додані після завершення першого запиту на злиття." +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\" та розгортанням коду у ПРОДакшин. Дані автоматично додаються після розгортання у ПРОДакшин вперше." +msgstr "" 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 виконує для запуску кожного конвеєра для відповідного запиту злиття. Дані будуть автоматично додані після завершення першого конвеєра." +msgstr "" msgid "The time in seconds GitLab will keep failure information. When no failures occur during this time, information about the mount is reset." msgstr "Кількість секунд, протягом якої GitLab зберігає інформацію про збої. Якщо протягом цього періоду жодних збоїв не відбувається, інформація про точку монтування скидається." @@ -2045,13 +2519,16 @@ msgid "The time in seconds GitLab will try to access storage. After this time a msgstr "Кількість секунд, протягом якої GitLab намагатиметься отримати доступ до сховища даних. По завершенню цього періоду буде згенерована помилка про перевищення ліміту часу." 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 "There are problems accessing Git storage: " -msgstr "Є проблеми з доступом до сховища: " +msgstr "" + +msgid "This board\\'s scope is reduced" +msgstr "Видимість цієї дошки обмежена" msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "Ця гілка була змінена після того моменту, коли ви почали її редагувати. Ви хотіли б створити нову?" @@ -2069,11 +2546,14 @@ msgid "This issue is locked." msgstr "Ця проблема заблокована." msgid "This means you can not push code until you create an empty repository or import existing one." -msgstr "Це означає, що ви не можете відправляти код, поки не створите порожній репозиторій або НЕ імпортуєте існуючий." +msgstr "" msgid "This merge request is locked." msgstr "Цей запит на злиття заблоковано." +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "Час до початку потрапляння проблеми в планувальник" @@ -2081,7 +2561,7 @@ msgid "Time before an issue starts implementation" msgstr "Час до початку роботи над проблемою" msgid "Time between merge request creation and merge/close" -msgstr "Час між створенням запиту злиття і злиттям або закриттям" +msgstr "" msgid "Time until first merge request" msgstr "Час до першого запиту на злиття" @@ -2224,14 +2704,26 @@ msgstr[2] "хвилин" msgid "Time|s" msgstr "секунд(а)" +msgid "Title" +msgstr "Назва" + msgid "Total Time" msgstr "Загальний час" +msgid "Total issue time spent" +msgstr "Загальний витрачений час на проблему" + msgid "Total test time for all commits/merges" msgstr "Загальний час, щоб перевірити всі коміти/злиття" msgid "Track activity with Contribution Analytics." -msgstr "Відстежувати активність за допомогою Аналітики контриб’юторів." +msgstr "" + +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "Відстежуйте групи проблем зі спільною темою з різних проектів та етапів" + +msgid "Turn on Service Desk" +msgstr "Ввімкнути Service Desk" msgid "Unlock" msgstr "Розблокувати" @@ -2249,16 +2741,16 @@ msgid "Upgrade your plan to activate Advanced Global Search." msgstr "Перейдіть на вищий тарифний план щоб активувати Покращений Глобальний Пошук." msgid "Upgrade your plan to activate Contribution Analytics." -msgstr "Перейдіть на вищий тарифний план для активації Аналітики контриб’юторів." +msgstr "" msgid "Upgrade your plan to activate Group Webhooks." -msgstr "Перейдіть на вищий тарифний план щоб активувати Групові Webhook’и." +msgstr "" msgid "Upgrade your plan to activate Issue weight." -msgstr "Підвищіть план щоб активувати вагу обговорень." +msgstr "" msgid "Upgrade your plan to improve Issue boards." -msgstr "Підвищіть свій план, щоб покращити дошки обговорень." +msgstr "" msgid "Upload New File" msgstr "Завантажити новий файл" @@ -2269,6 +2761,9 @@ msgstr "Завантажити файл" msgid "UploadLink|click to upload" msgstr "Натисніть, щоб завантажити" +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "Використовуйте Service Desk для зв’язку з вашими користувачами (наприклад, щоб запропонувати клієнтську підтримку) через електронну пошту безпосередньо із GitLab" + msgid "Use the following registration token during setup:" msgstr "Використовувати токен під час установки:" @@ -2300,10 +2795,13 @@ msgid "Want to see the data? Please ask an administrator for access." msgstr "Хочете побачити дані? Будь ласка, попросить у адміністратора доступ." msgid "We don't have enough data to show this stage." -msgstr "Ми не маємо достатньо даних для показу цього етапу." +msgstr "" + +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "Ми хочемо бути впевнені, що це ви, будь ласка, підтвердіть, що ви не робот." msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." -msgstr "Webhook дозволяють вам викликати адресу URL якщо, наприклад, відправлений новий код або створено нову тему повідомлення. Ви можете налаштувати Webhook так, щоб він реагував на певні події, такі як відправки коду, обговорення або запити на злиття. Групові Webhook’и застосовуються до всіх проектів в групі і дозволяють вам стандартизувати функціональність Webhook’ів для всієї вашої групи." +msgstr "" msgid "Weight" msgstr "Вага" @@ -2330,7 +2828,7 @@ msgid "WikiClone|Start Gollum and edit locally" msgstr "Запустіть Gollum і редагуйте локально" msgid "WikiEmptyPageError|You are not allowed to create wiki pages" -msgstr "Ви не можете створювати вікі-сторінки" +msgstr "" msgid "WikiHistoricalPage|This is an old version of this page." msgstr "Це — стара версія сторінки." @@ -2360,7 +2858,7 @@ msgid "WikiNewPageTip|Tip: You can specify the full path for the new file. We wi msgstr "Порада: можна вказати повний шлях до нового файлу. Ми автоматично створимо всі відсутні каталоги." msgid "WikiNewPageTitle|New Wiki Page" -msgstr "Нова Вікі-сторінка" +msgstr "" msgid "WikiPageConfirmDelete|Are you sure you want to delete this page?" msgstr "Ви дійсно бажаєте видалити цю сторінку?" @@ -2390,7 +2888,7 @@ msgid "Wiki|Create page" msgstr "Створити сторінку" msgid "Wiki|Edit Page" -msgstr "Редагувати сторінку" +msgstr "Редагування cторінки" msgid "Wiki|Empty page" msgstr "Порожня сторінка" @@ -2411,10 +2909,10 @@ msgid "Wiki|Pages" msgstr "Сторінки" msgid "Wiki|Wiki Pages" -msgstr "Вікі-сторінки" +msgstr "" msgid "With contribution analytics you can have an overview for the activity of issues, merge requests and push events of your organization and its members." -msgstr "З аналітикою контриб’юторів ви може вивчати активність в обговореннях, запитах на злиття і подій відправки коду для вашої організації і її учасників." +msgstr "" msgid "Withdraw Access Request" msgstr "Скасувати запит доступу" @@ -2431,14 +2929,8 @@ msgstr "Ви збираєтеся видалити зв'язок з форка msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "Ви збираєтеся передати проект %{project_name_with_namespace} іншому власнику. Ви АБСОЛЮТНО впевнені?" -msgid "You are on a read-only GitLab instance." -msgstr "Ви знаходитеся на інстансі Gitlab \"тільки для читання\"." - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "Ви знаходитеся на інстансі Gitlab \"тільки для читання\". Якщо ви хочете внести зміни, вам необхідно перейти на %{link_to_primary_node}." - msgid "You can only add files when you are on a branch" -msgstr "Ви можете додавати тільки файли, коли перебуваєте в гілці" +msgstr "" msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead." msgstr "Ви не можете записувати на вторинні інстанси \"тільки для читання\" GitLab Geo. Будь ласка використовуйте %{link_to_primary_node}." @@ -2471,10 +2963,13 @@ msgid "You will receive notifications only for comments in which you were @menti msgstr "Ви будете отримувати повідомлення тільки для коментарів, в яких ви були @згадані" msgid "You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account" -msgstr "Ви не зможете отримувати і відправляти код проекту через %{protocol} поки %{set_password_link} в ваш аккаунт" +msgstr "" msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" -msgstr "Ви не зможете отримувати і відправляти код проекту через SSH поки %{add_ssh_key_link} в ваш профіль." +msgstr "" + +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "" msgid "Your comment will not be visible to the public." msgstr "Ваш коментар не буде видимим для всіх." @@ -2488,6 +2983,12 @@ msgstr "Ваше ім'я" msgid "Your projects" msgstr "Ваші проекти" +msgid "branch name" +msgstr "ім'я гілки" + +msgid "by" +msgstr "від" + msgid "commit" msgstr "коміт" @@ -2505,9 +3006,9 @@ msgstr "Повідомлення електронною поштою" msgid "parent" msgid_plural "parents" -msgstr[0] "джерело" -msgstr[1] "джерела" -msgstr[2] "джерел" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" msgid "password" msgstr "пароль" @@ -2515,8 +3016,11 @@ msgstr "пароль" msgid "personal access token" msgstr "особистий токен доступу" +msgid "source" +msgstr "джерело" + msgid "to help your contributors communicate effectively!" -msgstr "щоб допомогти вашим контриб’юторам ефективно спілкуватися!" +msgstr "" msgid "username" msgstr "ім'я користувача" diff --git a/locale/zh_CN/gitlab.po b/locale/zh_CN/gitlab.po index e1bc9219908..f0a5453f224 100644 --- a/locale/zh_CN/gitlab.po +++ b/locale/zh_CN/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-23 02:44-0500\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 04:42-0500\n" "Last-Translator: gitlab \n" "Language-Team: Chinese Simplified\n" "Language: zh_CN\n" @@ -51,6 +51,9 @@ msgid "%{storage_name}: failed storage access attempt on host:" msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:" msgstr[0] "%{storage_name}:已 %{failed_attempts} 次尝试访问存储失败:" +msgid "%{text} is available" +msgstr "%{text}可用" + msgid "(checkout the %{link} for information on how to install it)." msgstr "(如需了解更多的安装信息,请查看 %{link})" @@ -104,14 +107,11 @@ msgid "Add Contribution guide" msgstr "添加贡献指南" msgid "Add Group Webhooks and GitLab Enterprise Edition." -msgstr "添加来自 Webhooks 或者 GitLab 企业版的团队。" +msgstr "添加组Webhooks和GitLab企业版。" msgid "Add License" msgstr "添加许可证" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "新建一个用于推送或拉取的 SSH 秘钥到账号中。" - msgid "Add new directory" msgstr "添加目录" @@ -124,6 +124,15 @@ msgstr "高级设置" msgid "All" msgstr "全部" +msgid "An error occurred when toggling the notification subscription" +msgstr "切换通知订阅时发生错误" + +msgid "An error occurred when updating the issue weight" +msgstr "更新议题权重时发生错误" + +msgid "An error occurred while fetching sidebar data" +msgstr "获取侧边栏数据时发生错误" + msgid "An error occurred. Please try again." msgstr "发生了错误,请再试一次。" @@ -133,6 +142,12 @@ msgstr "外观" msgid "Applications" msgstr "应用程序" +msgid "Apr" +msgstr "四" + +msgid "April" +msgstr "四月" + msgid "Archived project! Repository is read-only" msgstr "项目已归档!存储库为只读状态" @@ -160,6 +175,12 @@ msgstr "产物" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "拖放文件到此处或者 %{upload_link}" +msgid "Aug" +msgstr "八" + +msgid "August" +msgstr "八月" + msgid "Authentication Log" msgstr "认证日志" @@ -193,50 +214,53 @@ msgstr "想了解更多请访问 %{link_to_documentation}" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." msgstr "您可以为此项目激活 %{link_to_settings}。" +msgid "Available" +msgstr "可用的" + msgid "Billing" msgstr "账单" msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan." -msgstr "%{group_name} 正在使用 %{plan_link} 方案。" +msgstr "%{group_name}目前位于%{plan_link}计划中。" msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available." -msgstr "在当前方案中不可使用自动降级或自动升级。" +msgstr "自动降级、升级到某些计划目前不可用。" msgid "BillingPlans|Current plan" -msgstr "当前方案" +msgstr "当前计划" msgid "BillingPlans|Customer Support" -msgstr "用户支持" +msgstr "客户支持" msgid "BillingPlans|Downgrade" msgstr "降级" msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}." -msgstr "阅读 %{faq_link} 以了解更多信息。" +msgstr "通过阅读我们的%{faq_link}了解有关每个计划的更多信息。" msgid "BillingPlans|Manage plan" -msgstr "管理方案" +msgstr "管理计划" msgid "BillingPlans|Please contact %{customer_support_link} in that case." -msgstr "请联系 %{customer_support_link}" +msgstr "在这种情况下请联系%{customer_support_link}。" msgid "BillingPlans|See all %{plan_name} features" -msgstr "查看所有 %{plan_name} 功能" +msgstr "查看所有%{plan_name}功能" msgid "BillingPlans|This group uses the plan associated with its parent group." -msgstr "使用与其父项目一致的方案" +msgstr "该群组使用其父群组相关联的计划。" msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}." -msgstr "访问 %{parent_billing_page_link} 以管理该项目的计费方案。" +msgstr "要管理此群组的计划,请访问%{parent_billing_page_link}的账单部分。" msgid "BillingPlans|Upgrade" msgstr "升级" msgid "BillingPlans|You are currently on the %{plan_link} plan." -msgstr "您目前正在使用 %{plan_link} 方案。" +msgstr "您目前正在使用%{plan_link}计划。" msgid "BillingPlans|frequently asked questions" -msgstr "常见问题" +msgstr "常问问题" msgid "BillingPlans|monthly" msgstr "每月" @@ -245,7 +269,7 @@ msgid "BillingPlans|paid annually at %{price_per_year}" msgstr "每年支付 %{price_per_year}" msgid "BillingPlans|per user" -msgstr "每个用户" +msgstr "每用户" msgid "Branch" msgid_plural "Branches" @@ -257,6 +281,12 @@ msgstr "已创建分支 %{branch_name} 。如需设置自动部 msgid "Branch has changed" msgstr "分支已有新变更" +msgid "Branch is already taken" +msgstr "分支已被采用" + +msgid "Branch name" +msgstr "分支名称" + msgid "BranchSwitcherPlaceholder|Search branches" msgstr "搜索分支" @@ -318,7 +348,7 @@ msgid "Branches|Sort by" msgstr "排序" msgid "Branches|The branch could not be updated automatically because it has diverged from its upstream counterpart." -msgstr "分支无法自动提交,因为与上游分支冲突。" +msgstr "分支不能自动更新,因为它与上游分支不一致。" msgid "Branches|The default branch cannot be deleted" msgstr "无法删除默认分支" @@ -333,13 +363,13 @@ msgid "Branches|To confirm, type %{branch_name_confirmation}:" msgstr "要确认?请输入 %{branch_name_confirmation} :" msgid "Branches|To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above." -msgstr "若要放弃本地更改并使用上游版本覆盖本分支,请先删除并“立即更新”。" +msgstr "要放弃本地更改并覆盖上游版本的分支,请在此处将其删除,然后选择上面的“立即更新”。" msgid "Branches|You’re about to permanently delete the protected branch %{branch_name}." msgstr "将要永久删除受保护 %{branch_name} 分支。" msgid "Branches|diverged from upstream" -msgstr "与上游存在差异" +msgstr "上游分支" msgid "Branches|merged" msgstr "已合并的" @@ -381,7 +411,7 @@ msgid "Cancel edit" msgstr "取消编辑" msgid "Change Weight" -msgstr "变更权重" +msgstr "改变权重" msgid "ChangeTypeActionLabel|Pick into branch" msgstr "选择分支" @@ -404,6 +434,12 @@ msgstr "统计图" msgid "Chat" msgstr "即时通讯" +msgid "Checking %{text} availability…" +msgstr "正在检查%{text}的可用性..." + +msgid "Checking branch availability..." +msgstr "正在检查分支的可用性..." + msgid "Cherry-pick this commit" msgstr "优选此提交" @@ -479,8 +515,41 @@ msgstr "关闭" msgid "Cluster" msgstr "集群" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" -msgstr "必须在此帐户下创建 %{link_to_container_project}" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "%{appList}已成功安装在您的群集上" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "%{boldNotice}这会增加一些额外的资源,如负载均衡器,这会产生额外的成本。请参阅%{pricingLink}" + +msgid "ClusterIntegration|API URL" +msgstr "API地址" + +msgid "ClusterIntegration|Active" +msgstr "启用" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "添加一个现有的集群" + +msgid "ClusterIntegration|Add cluster" +msgstr "添加集群" + +msgid "ClusterIntegration|All" +msgstr "所有" + +msgid "ClusterIntegration|Applications" +msgstr "应用程序" + +msgid "ClusterIntegration|CA Certificate" +msgstr "CA证书" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "证书授权包(PEM格式)" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "选择如何设置集群集成" + +msgid "ClusterIntegration|Cluster" +msgstr "集群" msgid "ClusterIntegration|Cluster details" msgstr "集群详情" @@ -498,26 +567,59 @@ msgid "ClusterIntegration|Cluster integration is enabled for this project. Disab msgstr "此项目已启用集群集成。禁用此集成不会影响您的集群,它只会暂时关闭 GitLab 的连接。" msgid "ClusterIntegration|Cluster is being created on Google Kubernetes Engine..." -msgstr "集群正在 Google Kubernetes Engine 上创建..." +msgstr "群集正在Google Kubernetes Engine上创建..." msgid "ClusterIntegration|Cluster name" msgstr "集群名称" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" -msgstr "集群已在 Google Kubernetes Engine 上成功创建" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" +msgstr "集群已在Google Kubernetes Engine上成功创建。刷新页面以查看集群的详细信息" + +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "集群允许您使用审阅应用程序、部署应用程序、运行流水线等等。%{link_to_help_page}" + +msgid "ClusterIntegration|Copy API URL" +msgstr "复制API地址" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "复制CA证书" + +msgid "ClusterIntegration|Copy Token" +msgstr "复制令牌" msgid "ClusterIntegration|Copy cluster name" msgstr "复制集群名称" +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "在 GitLab 上创建一个 Google Engine 集群" + msgid "ClusterIntegration|Create cluster" msgstr "创建集群" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" -msgstr "在 Google Kubernetes Engine 上创建新集群" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" +msgstr "在 Google Kubernetes Engine 上创建集群" + +msgid "ClusterIntegration|Create on GKE" +msgstr "在GKE中创建" msgid "ClusterIntegration|Enable cluster integration" msgstr "启用集群集成" +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "输入现有的 Kubernetes 集群详细信息" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "输入您的集群详细信息" + +msgid "ClusterIntegration|Environment pattern" +msgstr "环境模式" + +msgid "ClusterIntegration|GKE pricing" +msgstr "GKE价格" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "GitLab Runner" + msgid "ClusterIntegration|Google Cloud Platform project ID" msgstr "Google 云平台项目ID" @@ -527,27 +629,75 @@ msgstr "Google Kubernetes Engine" msgid "ClusterIntegration|Google Kubernetes Engine project" msgstr "Google Kubernetes Engine 项目" +msgid "ClusterIntegration|Helm Tiller" +msgstr "Helm Tiller" + +msgid "ClusterIntegration|Inactive" +msgstr "待用" + +msgid "ClusterIntegration|Ingress" +msgstr "入口" + +msgid "ClusterIntegration|Install" +msgstr "安装" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "在集群上安装应用程序。阅读更多关于%{helpLink}" + +msgid "ClusterIntegration|Installed" +msgstr "已安装" + +msgid "ClusterIntegration|Installing" +msgstr "安装中" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "集群自动化集成" + msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "了解详细%{link_to_documentation}" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "了解更多集群的信息" + msgid "ClusterIntegration|Machine type" msgstr "机器类型" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" msgstr "确保您的帐户符合创建集群的%{link_to_requirements}" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" -msgstr "管理您的 GitLab 项目集群集成" +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" +msgstr "在 GitLab 项目上管理集群集成" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" msgstr "访问%{link_gke}来管理您的集群" +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "GitLab企业高级版和旗舰版提供了多个集群" + +msgid "ClusterIntegration|Note:" +msgstr "注意:" + msgid "ClusterIntegration|Number of nodes" msgstr "节点数量" +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" +msgstr "请为您的群集输入访问信息。如果您需要帮助,可以阅读我们关于集群的 %{link_to_help_page}" + msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgstr "请确保您的 Google 帐户符合以下要求:" +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "设置集群时出现问题" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "设置集群列表时出现问题" + +msgid "ClusterIntegration|Project ID" +msgstr "项目 ID" + +msgid "ClusterIntegration|Project namespace" +msgstr "项目命名空间" + msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "项目命名空间(可选,唯一)" @@ -560,8 +710,14 @@ msgstr "删除集群集成" msgid "ClusterIntegration|Remove integration" msgstr "删除集成" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." -msgstr "删除集群集成将删除您添加到此项目的集群配置。它不会删除您的项目。" +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "删除集群集成将删除已添加到此项目的集群配置。它不会删除 Google Kubernetes Engine 上的集群。" + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "请求安装失败" + +msgid "ClusterIntegration|Save changes" +msgstr "保存更改" msgid "ClusterIntegration|See and edit the details for your cluster" msgstr "查看并编辑集群的详细信息" @@ -575,20 +731,38 @@ msgstr "看到您的项目" msgid "ClusterIntegration|See zones" msgstr "查看区域" +msgid "ClusterIntegration|Service token" +msgstr "服务令牌" + +msgid "ClusterIntegration|Show" +msgstr "显示" + msgid "ClusterIntegration|Something went wrong on our end." msgstr "发生了内部错误" msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" msgstr "在 Google Kubernetes Engine 上创建集群时发生错误" +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "安装 %{title} 时发生故障" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "没有要显示的集群" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "此帐户必须有权在下面指定的%{link_to_container_project}中创建集群" + msgid "ClusterIntegration|Toggle Cluster" msgstr "切换集群" +msgid "ClusterIntegration|Token" +msgstr "令牌" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "使用与此项目关联的集群,您可以使用审阅应用程序,部署应用程序,运行流水线等等。" msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}" -msgstr "您的帐户必须有%{link_to_kubernetes_engine}" +msgstr "您的帐户必须拥有%{link_to_kubernetes_engine}" msgid "ClusterIntegration|Zone" msgstr "区域" @@ -599,9 +773,15 @@ msgstr "访问 Google Kubernetes Engine" msgid "ClusterIntegration|cluster" msgstr "集群" +msgid "ClusterIntegration|documentation" +msgstr "文档" + msgid "ClusterIntegration|help page" msgstr "帮助页面" +msgid "ClusterIntegration|installing applications" +msgstr "安装应用程序" + msgid "ClusterIntegration|meets the requirements" msgstr "符合要求" @@ -615,10 +795,6 @@ msgid "Commit" msgid_plural "Commits" msgstr[0] "提交" -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "提交 %d 个文件" - msgid "Commit Message" msgstr "提交消息" @@ -700,11 +876,20 @@ msgstr "贡献指南" msgid "Contributors" msgstr "贡献者" +msgid "ContributorsPage|Building repository graph." +msgstr "构建存储库图标。" + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "提交到%{branch_name},排除合并提交。限于6000次提交。" + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "请稍等片刻,这个页面会在准备好时自动刷新。" + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" -msgstr "控制此次要节点的 LFS/attachment 的最大并发性" +msgstr "控制此次要节点的 LFS/attachment 的最大并发" msgid "Control the maximum concurrency of repository backfill for this secondary node" -msgstr "控制此次要节点的存储库的最大并发" +msgstr "控制此次要节点的存储库最大并发" msgid "Copy SSH public key to clipboard" msgstr "复制 SSH 公钥到剪贴板" @@ -727,6 +912,9 @@ msgstr "创建目录" msgid "Create empty bare repository" msgstr "创建空的存储库" +msgid "Create epic" +msgstr "创建EPIC" + msgid "Create file" msgstr "创建文件" @@ -754,6 +942,9 @@ msgstr "标签" msgid "CreateTokenToCloneLink|create a personal access token" msgstr "创建个人访问令牌" +msgid "Creating epic" +msgstr "创建EPIC中" + msgid "Cron Timezone" msgstr "Cron 时区" @@ -799,6 +990,12 @@ msgstr "所有" msgid "DashboardProjects|Personal" msgstr "个人" +msgid "Dec" +msgstr "十二" + +msgid "December" +msgstr "十二月" + msgid "Define a custom pattern with cron syntax" msgstr "使用 Cron 语法定义自定义模式" @@ -816,7 +1013,7 @@ msgid "Description" msgstr "描述" msgid "Description templates allow you to define context-specific templates for issue and merge request description fields for your project." -msgstr "描述模板允许您为项目的议题和合并请求在创建时选择特定的模版。" +msgstr "描述模板允许您为项目的问题和合并请求定义描述字段的特定模板。" msgid "Details" msgstr "详情" @@ -872,6 +1069,72 @@ msgstr "编辑 %{id} 流水线计划" msgid "Emails" msgstr "电子邮件" +msgid "Environments|An error occurred while fetching the environments." +msgstr "获取环境时发生错误。" + +msgid "Environments|An error occurred while making the request." +msgstr "发送请求时发生错误。" + +msgid "Environments|Commit" +msgstr "提交" + +msgid "Environments|Deployment" +msgstr "部署" + +msgid "Environments|Environment" +msgstr "环境" + +msgid "Environments|Environments" +msgstr "环境" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "环境是部署代码的地方,例如预生产或生产。" + +msgid "Environments|Job" +msgstr "作业" + +msgid "Environments|New environment" +msgstr "新建环境" + +msgid "Environments|No deployments yet" +msgstr "未部署" + +msgid "Environments|Open" +msgstr "打开" + +msgid "Environments|Re-deploy" +msgstr "重新部署" + +msgid "Environments|Read more about environments" +msgstr "了解有关环境的更多信息" + +msgid "Environments|Rollback" +msgstr "还原" + +msgid "Environments|Show all" +msgstr "显示全部" + +msgid "Environments|Updated" +msgstr "已更新" + +msgid "Environments|You don't have any environments right now." +msgstr "你还没有设置环境" + +msgid "Epic will be removed! Are you sure?" +msgstr "EPIC将被删除!是否确定?" + +msgid "Epics" +msgstr "EPIC" + +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" +msgstr "EPIC让你更有效率地管理你的项目组合,而且不费吹灰之力" + +msgid "Error creating epic" +msgstr "创建EPIC时出错" + +msgid "Error occurred when toggling the notification subscription" +msgstr "切换通知订阅时发生错误" + msgid "EventFilterBy|Filter by all" msgstr "全部" @@ -911,6 +1174,12 @@ msgstr "无法变更所有者" msgid "Failed to remove the pipeline schedule" msgstr "无法删除流水线计划" +msgid "Feb" +msgstr "二" + +msgid "February" +msgstr "二月" + msgid "File name" msgstr "文件名" @@ -957,14 +1226,29 @@ msgstr "GPG 密钥" msgid "Geo Nodes" msgstr "Geo 节点" +msgid "GeoNodeSyncStatus|Failed" +msgstr "失败" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "节点出现故障或损坏。" + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "节点运行缓慢、超载, 或者在停机后刚刚恢复。" + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "未同步" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "已同步" + msgid "Geo|File sync capacity" -msgstr "文件同步容量" +msgstr "文件同步量" msgid "Geo|Groups to replicate" -msgstr "要复制的群组" +msgstr "复制群组" msgid "Geo|Repository sync capacity" -msgstr "存储库同步容量" +msgstr "存储库同步量" msgid "Geo|Select groups to replicate." msgstr "选择要复制的群组。" @@ -1020,9 +1304,6 @@ msgstr "找不到群组" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "您可以管理群组成员的权限并访问群组中的每个项目。" -msgid "GroupsTreeRole|as" -msgstr "的" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "您确定要离开群组“${this.group.fullName}”吗?" @@ -1053,6 +1334,9 @@ msgstr "对不起,没有搜索到任何符合的群组" msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "对不起,没有任何群组或项目符合您的搜索" +msgid "Have your users email" +msgstr "有你的用户邮件" + msgid "Health Check" msgstr "健康检查" @@ -1111,9 +1395,6 @@ msgstr "周期分析简介" msgid "Issue board focus mode" msgstr "议题看板模式" -msgid "Issue boards with milestones" -msgstr "议题看板与里程碑" - msgid "Issue events" msgstr "议题事件" @@ -1126,6 +1407,24 @@ msgstr "看板" msgid "Issues" msgstr "议题" +msgid "Jan" +msgstr "一" + +msgid "January" +msgstr "一月" + +msgid "Jul" +msgstr "七" + +msgid "July" +msgstr "七月" + +msgid "Jun" +msgstr "六" + +msgid "June" +msgstr "六月" + msgid "LFSStatus|Disabled" msgstr "停用" @@ -1197,9 +1496,18 @@ msgstr "已锁定文件" msgid "Login" msgstr "登录" +msgid "Mar" +msgstr "三" + +msgid "March" +msgstr "三月" + msgid "Maximum git storage failures" msgstr "最大 git 存储失败" +msgid "May" +msgstr "五" + msgid "Median" msgstr "中位数" @@ -1243,9 +1551,15 @@ msgstr "创建流水线计划" msgid "New branch" msgstr "新建分支" +msgid "New branch unavailable" +msgstr "新分支不可用" + msgid "New directory" msgstr "新建目录" +msgid "New epic" +msgstr "新EPIC" + msgid "New file" msgstr "新建文件" @@ -1282,6 +1596,9 @@ msgstr "没有存储库" msgid "No schedules" msgstr "没有计划" +msgid "No time spent" +msgstr "没有花费时间" + msgid "None" msgstr "无" @@ -1348,18 +1665,33 @@ msgstr "关注" msgid "Notifications" msgstr "通知" +msgid "Nov" +msgstr "十一" + +msgid "November" +msgstr "十一月" + msgid "Number of access attempts" msgstr "尝试访问次数" msgid "Number of failures before backing off" msgstr "退出前的失败次数" +msgid "Oct" +msgstr "十" + +msgid "October" +msgstr "十月" + msgid "OfSearchInADropdown|Filter" msgstr "筛选" msgid "Only project members can comment." msgstr "只有项目成员可以发表评论。" +msgid "Opened" +msgstr "已打开" + msgid "OpenedNDaysAgo|Opened" msgstr "创建于" @@ -1492,6 +1824,9 @@ msgstr "于阶段" msgid "Pipeline|with stages" msgstr "于阶段" +msgid "Please solve the reCAPTCHA" +msgstr "请填写验证码。" + msgid "Preferences" msgstr "偏好设置" @@ -1597,9 +1932,15 @@ msgstr "分支图" msgid "ProjectSettings|Contact an admin to change this setting." msgstr "联系管理员更改此设置。" +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "立即在默认分支上运行流水线" + msgid "ProjectSettings|Only signed commits can be pushed to this repository." msgstr "只有已签署提交才可以推送到此存储库。" +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "设置CI/CD时出现JavaScript问题" + msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." msgstr "此设置已应用于服务器级别,可由管理员覆盖。" @@ -1636,6 +1977,39 @@ msgstr "对不起,没有搜索到符合条件的项目" msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "此功能需要浏览器支持 localStorage" +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "默认情况下,Prometheus 侦听 ‘http://localhost:9090’。不建议更改默认地址和端口,因为这可能会影响或冲突在 GitLab 服务器上运行的其他服务。" + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "查找和配置指标..." + +msgid "PrometheusService|Metrics" +msgstr "指标" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "指标会根据指定的指标库自动配置和监控。" + +msgid "PrometheusService|Missing environment variable" +msgstr "没有环境变量" + +msgid "PrometheusService|Monitored" +msgstr "监测" + +msgid "PrometheusService|More information" +msgstr "更多的信息" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "没有监测指标。要开始监测,请部署到环境中。" + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" +msgstr "Prometheus API 地址,例如 http://prometheus.example.com/" + +msgid "PrometheusService|Prometheus monitoring" +msgstr "Prometheus 监测" + +msgid "PrometheusService|View environments" +msgstr "查看环境" + msgid "Public - The group and any public projects can be viewed without any authentication." msgstr "公开 - 群组和任何公共项目可以在没有任何身份验证的情况下查看。" @@ -1732,6 +2106,9 @@ msgstr "日程" msgid "Scheduling Pipelines" msgstr "流水线计划" +msgid "Scoped issue boards" +msgstr "议题看板范围" + msgid "Search branches and tags" msgstr "搜索分支和标签" @@ -1753,6 +2130,12 @@ msgstr "选择时区" msgid "Select target branch" msgstr "选择目标分支" +msgid "Sep" +msgstr "九" + +msgid "September" +msgstr "九月" + msgid "Service Templates" msgstr "服务模板" @@ -1784,14 +2167,29 @@ msgid "Showing %d event" msgid_plural "Showing %d events" msgstr[0] "显示 %d 个事件" +msgid "Sidebar|Change weight" +msgstr "编辑宽度" + +msgid "Sidebar|Edit" +msgstr "编辑" + +msgid "Sidebar|No" +msgstr "无" + +msgid "Sidebar|None" +msgstr "无" + +msgid "Sidebar|Weight" +msgstr "宽度" + msgid "Snippets" msgstr "代码片段" msgid "Something went wrong on our end." msgstr "发生了错误。" -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" -msgstr "尝试更改 ${this.issuableDisplayName(this.issuableType)} 的锁定状态时发生错误" +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" +msgstr "试图改变 ${this.issuableDisplayName} 的锁定状态时出错了" msgid "Something went wrong while fetching the projects." msgstr "拉取项目时发生错误。" @@ -1854,7 +2252,7 @@ msgid "SortOptions|Milestone due soon" msgstr "即将截止的里程碑" msgid "SortOptions|More weight" -msgstr "更大的权重" +msgstr "最高权重" msgid "SortOptions|Most popular" msgstr "最受欢迎" @@ -1898,9 +2296,15 @@ msgstr "现在开始" msgid "SortOptions|Weight" msgstr "权重" +msgid "Source" +msgstr "源" + msgid "Source code" msgstr "源代码" +msgid "Source is not available" +msgstr "源不可用" + msgid "Spam Logs" msgstr "垃圾信息日志" @@ -1919,6 +2323,9 @@ msgstr "由此更改 %{new_merge_request}" msgid "Start the Runner!" msgstr "启动 Runner!" +msgid "Stopped" +msgstr "已停止" + msgid "Subgroups" msgstr "子群组" @@ -1938,6 +2345,75 @@ msgstr[0] "标签" msgid "Tags" msgstr "标签" +msgid "TagsPage|Browse commits" +msgstr "浏览提交" + +msgid "TagsPage|Browse files" +msgstr "浏览文件" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "无法找到此标记的HEAD提交" + +msgid "TagsPage|Cancel" +msgstr "取消" + +msgid "TagsPage|Create tag" +msgstr "创建标签" + +msgid "TagsPage|Delete tag" +msgstr "删除标签" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "删除 %{tag_name} 后将无法恢复,您确定?" + +msgid "TagsPage|Edit release notes" +msgstr "编辑发行记录" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "已存在分支名称,标记或提交SHA" + +msgid "TagsPage|Filter by tag name" +msgstr "根据标签名称过滤" + +msgid "TagsPage|New Tag" +msgstr "新标签" + +msgid "TagsPage|New tag" +msgstr "新标签" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "(可选)添加一条消息到标签。" + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "(可选)将发行说明添加到标签。它们将被存储在GitLab数据库中并显示在标签页上。" + +msgid "TagsPage|Release notes" +msgstr "发行说明" + +msgid "TagsPage|Repository has no tags yet." +msgstr "版本库还没有标签。" + +msgid "TagsPage|Sort by" +msgstr "排序" + +msgid "TagsPage|Tags" +msgstr "标签" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "标签具有在提交历史上标记特定提交的能力" + +msgid "TagsPage|This tag has no release notes." +msgstr "此标签没有发行说明。" + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "使用git tag命令添加一个:" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "撰写发行说明或拖放文件到这里..." + +msgid "TagsPage|protected" +msgstr "已保护" + msgid "Target Branch" msgstr "目标分支" @@ -1945,10 +2421,10 @@ msgid "Team" msgstr "团队" msgid "Thanks! Don't show me this again" -msgstr "不再显示该提示" +msgstr "谢谢 ! 请不要再显示" msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project." -msgstr "GitLab 中的高级全局搜索功能是非常强大的搜索服务。您可以搜索其他团队的代码以帮助您完善自己项目中的代码。从而避免创建重复的代码或浪费时间。" +msgstr "GitLab 中的高级全局搜索功能是非常强大的搜索服务。您可以搜索其他团队的代码以帮助您完善自己项目中的代码。从而避免创建重复的代码和浪费时间。" msgid "The circuitbreaker backoff threshold should be lower than the failure count threshold" msgstr "断路器关闭阈值应该低于故障计数阈值" @@ -2019,6 +2495,9 @@ msgstr "中位数是一个数列中最中间的值。例如在 3、5、9 之间 msgid "There are problems accessing Git storage: " msgstr "访问 Git 存储时出现问题:" +msgid "This board\\'s scope is reduced" +msgstr "这个看板的范围缩小了" + msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "自您开始编辑后, 此分支已更改。您想创建一个新的分支吗?" @@ -2040,6 +2519,9 @@ msgstr "在创建一个空的存储库或导入现有存储库之前,将无法 msgid "This merge request is locked." msgstr "此合并请求已锁定。" +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "这些电子邮件自动生成为问题(评论生成为电子邮件对话)在这里列出。" + msgid "Time before an issue gets scheduled" msgstr "议题被列入日程表的时间" @@ -2186,14 +2668,26 @@ msgstr[0] "分钟" msgid "Time|s" msgstr "秒" +msgid "Title" +msgstr "标题" + msgid "Total Time" msgstr "总时间" +msgid "Total issue time spent" +msgstr "议题花费时间总计" + msgid "Total test time for all commits/merges" msgstr "所有提交和合并的总测试时间" msgid "Track activity with Contribution Analytics." -msgstr "跟踪分析贡献与活动。" +msgstr "跟踪活动与贡献的分析。" + +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "在项目和里程碑之间跟踪共享主题的议题组" + +msgid "Turn on Service Desk" +msgstr "打开服务台" msgid "Unlock" msgstr "解锁" @@ -2231,6 +2725,9 @@ msgstr "上传文件" msgid "UploadLink|click to upload" msgstr "点击上传" +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "使用服务台在GitLab内部通过电子邮件与用户联系(例如提供客户支持)" + msgid "Use the following registration token during setup:" msgstr "在安装过程中使用以下注册令牌:" @@ -2264,6 +2761,9 @@ msgstr "权限不足。如需查看相关数据,请向管理员申请权限。 msgid "We don't have enough data to show this stage." msgstr "该阶段的数据不足,无法显示。" +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "我们要确定你是不是机器人。" + msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." msgstr "如果有新的推送或新的议题,Webhook将自动触发您设置URL。 您可以配置 Webhook 来监听特定事件,如推送、议题或合并请求。 群组 Webhook 将适用于团队中的所有项目,并允许您设置整个团队中的 Webhook 。" @@ -2393,12 +2893,6 @@ msgstr "即将删除与源项目 %{forked_from_project} 的派生关系。确定 msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "即将 %{project_name_with_namespace} 转移给另一个所有者。确定继续吗?" -msgid "You are on a read-only GitLab instance." -msgstr "您在一个只读 GitLab 实例上。" - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "您在一个只读的 GitLab 实例上。如果您想进行任何更改,您必须访问%{link_to_primary_node}。" - msgid "You can only add files when you are on a branch" msgstr "只能在分支上添加文件" @@ -2438,6 +2932,9 @@ msgstr "在账号中 %{set_password_link} 之前将无法通过 %{protocol} 拉 msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" msgstr "在账号中 %{add_ssh_key_link} 之前将无法通过 SSH 拉取或推送代码。" +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "在您的个人资料中添加SSH密钥之前,您不能通过SSH来拉取或推送项目代码。" + msgid "Your comment will not be visible to the public." msgstr "您的评论将不会公开显示。" @@ -2450,6 +2947,12 @@ msgstr "您的名字" msgid "Your projects" msgstr "您的项目" +msgid "branch name" +msgstr "分支名称" + +msgid "by" +msgstr "来自" + msgid "commit" msgstr "提交" @@ -2473,6 +2976,9 @@ msgstr "密码" msgid "personal access token" msgstr "个人访问令牌" +msgid "source" +msgstr "源" + msgid "to help your contributors communicate effectively!" msgstr "帮助您的贡献者进行有效沟通!" diff --git a/locale/zh_HK/gitlab.po b/locale/zh_HK/gitlab.po index b851809fc7c..b368487ac71 100644 --- a/locale/zh_HK/gitlab.po +++ b/locale/zh_HK/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-15 02:54-0500\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 04:42-0500\n" "Last-Translator: gitlab \n" "Language-Team: Chinese Traditional, Hong Kong\n" "Language: zh_HK\n" @@ -51,6 +51,9 @@ msgid "%{storage_name}: failed storage access attempt on host:" msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:" msgstr[0] "%{storage_name}:已訪問此主機失敗 %{failed_attempts} 次" +msgid "%{text} is available" +msgstr "" + msgid "(checkout the %{link} for information on how to install it)." msgstr "(想了解更多的安裝訊息請查看 %{link})" @@ -109,9 +112,6 @@ msgstr "" msgid "Add License" msgstr "添加許可證" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "新增壹個用於推送或拉取的 SSH 秘鑰到賬號中。" - msgid "Add new directory" msgstr "添加新目錄" @@ -124,6 +124,15 @@ msgstr "" msgid "All" msgstr "全部" +msgid "An error occurred when toggling the notification subscription" +msgstr "" + +msgid "An error occurred when updating the issue weight" +msgstr "" + +msgid "An error occurred while fetching sidebar data" +msgstr "" + msgid "An error occurred. Please try again." msgstr "" @@ -133,6 +142,12 @@ msgstr "" msgid "Applications" msgstr "" +msgid "Apr" +msgstr "" + +msgid "April" +msgstr "" + msgid "Archived project! Repository is read-only" msgstr "歸檔項目!存儲庫為只讀" @@ -160,6 +175,12 @@ msgstr "" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "拖放文件到此處或者 %{upload_link}" +msgid "Aug" +msgstr "" + +msgid "August" +msgstr "" + msgid "Authentication Log" msgstr "" @@ -193,6 +214,9 @@ msgstr "" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." msgstr "" +msgid "Available" +msgstr "" + msgid "Billing" msgstr "" @@ -257,6 +281,12 @@ msgstr "分支 %{branch_name} 已創建。如需設置自動部 msgid "Branch has changed" msgstr "" +msgid "Branch is already taken" +msgstr "" + +msgid "Branch name" +msgstr "" + msgid "BranchSwitcherPlaceholder|Search branches" msgstr "搜索分支" @@ -404,6 +434,12 @@ msgstr "統計圖" msgid "Chat" msgstr "" +msgid "Checking %{text} availability…" +msgstr "" + +msgid "Checking branch availability..." +msgstr "" + msgid "Cherry-pick this commit" msgstr "優選此提交" @@ -479,7 +515,40 @@ msgstr "" msgid "Cluster" msgstr "" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "" + +msgid "ClusterIntegration|API URL" +msgstr "" + +msgid "ClusterIntegration|Active" +msgstr "" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "" + +msgid "ClusterIntegration|Add cluster" +msgstr "" + +msgid "ClusterIntegration|All" +msgstr "" + +msgid "ClusterIntegration|Applications" +msgstr "" + +msgid "ClusterIntegration|CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "" + +msgid "ClusterIntegration|Cluster" msgstr "" msgid "ClusterIntegration|Cluster details" @@ -503,21 +572,54 @@ msgstr "" msgid "ClusterIntegration|Cluster name" msgstr "" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" +msgstr "" + +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "" + +msgid "ClusterIntegration|Copy API URL" +msgstr "" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Copy Token" msgstr "" msgid "ClusterIntegration|Copy cluster name" msgstr "" +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "" + msgid "ClusterIntegration|Create cluster" msgstr "" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Create on GKE" msgstr "" msgid "ClusterIntegration|Enable cluster integration" msgstr "" +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "" + +msgid "ClusterIntegration|Environment pattern" +msgstr "" + +msgid "ClusterIntegration|GKE pricing" +msgstr "" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "" + msgid "ClusterIntegration|Google Cloud Platform project ID" msgstr "" @@ -527,27 +629,75 @@ msgstr "" msgid "ClusterIntegration|Google Kubernetes Engine project" msgstr "" +msgid "ClusterIntegration|Helm Tiller" +msgstr "" + +msgid "ClusterIntegration|Inactive" +msgstr "" + +msgid "ClusterIntegration|Ingress" +msgstr "" + +msgid "ClusterIntegration|Install" +msgstr "" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "" + +msgid "ClusterIntegration|Installed" +msgstr "" + +msgid "ClusterIntegration|Installing" +msgstr "" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "" + msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "" + msgid "ClusterIntegration|Machine type" msgstr "" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" msgstr "" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" msgstr "" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" msgstr "" +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "" + +msgid "ClusterIntegration|Note:" +msgstr "" + msgid "ClusterIntegration|Number of nodes" msgstr "" +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" +msgstr "" + msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgstr "" +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "" + +msgid "ClusterIntegration|Project ID" +msgstr "" + +msgid "ClusterIntegration|Project namespace" +msgstr "" + msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "" @@ -560,7 +710,13 @@ msgstr "" msgid "ClusterIntegration|Remove integration" msgstr "" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "" + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "" + +msgid "ClusterIntegration|Save changes" msgstr "" msgid "ClusterIntegration|See and edit the details for your cluster" @@ -575,15 +731,33 @@ msgstr "" msgid "ClusterIntegration|See zones" msgstr "" +msgid "ClusterIntegration|Service token" +msgstr "" + +msgid "ClusterIntegration|Show" +msgstr "" + msgid "ClusterIntegration|Something went wrong on our end." msgstr "" msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" msgstr "" +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "" + msgid "ClusterIntegration|Toggle Cluster" msgstr "" +msgid "ClusterIntegration|Token" +msgstr "" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "" @@ -599,9 +773,15 @@ msgstr "" msgid "ClusterIntegration|cluster" msgstr "" +msgid "ClusterIntegration|documentation" +msgstr "" + msgid "ClusterIntegration|help page" msgstr "" +msgid "ClusterIntegration|installing applications" +msgstr "" + msgid "ClusterIntegration|meets the requirements" msgstr "" @@ -615,10 +795,6 @@ msgid "Commit" msgid_plural "Commits" msgstr[0] "提交" -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "" - msgid "Commit Message" msgstr "" @@ -700,6 +876,15 @@ msgstr "貢獻指南" msgid "Contributors" msgstr "貢獻者" +msgid "ContributorsPage|Building repository graph." +msgstr "" + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "" + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "" + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" msgstr "" @@ -727,6 +912,9 @@ msgstr "創建目錄" msgid "Create empty bare repository" msgstr "創建空的存儲庫" +msgid "Create epic" +msgstr "" + msgid "Create file" msgstr "" @@ -754,6 +942,9 @@ msgstr "標籤" msgid "CreateTokenToCloneLink|create a personal access token" msgstr "創建個人訪問令牌" +msgid "Creating epic" +msgstr "" + msgid "Cron Timezone" msgstr "Cron 時區" @@ -799,6 +990,12 @@ msgstr "" msgid "DashboardProjects|Personal" msgstr "" +msgid "Dec" +msgstr "" + +msgid "December" +msgstr "" + msgid "Define a custom pattern with cron syntax" msgstr "使用 Cron 語法定義自定義模式" @@ -872,6 +1069,72 @@ msgstr "編輯 %{id} 流水線計劃" msgid "Emails" msgstr "" +msgid "Environments|An error occurred while fetching the environments." +msgstr "" + +msgid "Environments|An error occurred while making the request." +msgstr "" + +msgid "Environments|Commit" +msgstr "" + +msgid "Environments|Deployment" +msgstr "" + +msgid "Environments|Environment" +msgstr "" + +msgid "Environments|Environments" +msgstr "" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "" + +msgid "Environments|Job" +msgstr "" + +msgid "Environments|New environment" +msgstr "" + +msgid "Environments|No deployments yet" +msgstr "" + +msgid "Environments|Open" +msgstr "" + +msgid "Environments|Re-deploy" +msgstr "" + +msgid "Environments|Read more about environments" +msgstr "" + +msgid "Environments|Rollback" +msgstr "" + +msgid "Environments|Show all" +msgstr "" + +msgid "Environments|Updated" +msgstr "" + +msgid "Environments|You don't have any environments right now." +msgstr "" + +msgid "Epic will be removed! Are you sure?" +msgstr "" + +msgid "Epics" +msgstr "" + +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" +msgstr "" + +msgid "Error creating epic" +msgstr "" + +msgid "Error occurred when toggling the notification subscription" +msgstr "" + msgid "EventFilterBy|Filter by all" msgstr "全部" @@ -911,6 +1174,12 @@ msgstr "無法變更所有者" msgid "Failed to remove the pipeline schedule" msgstr "無法刪除流水線計劃" +msgid "Feb" +msgstr "" + +msgid "February" +msgstr "" + msgid "File name" msgstr "" @@ -957,6 +1226,21 @@ msgstr "" msgid "Geo Nodes" msgstr "" +msgid "GeoNodeSyncStatus|Failed" +msgstr "" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "" + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "" + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "" + msgid "Geo|File sync capacity" msgstr "" @@ -1020,9 +1304,6 @@ msgstr "" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "" -msgid "GroupsTreeRole|as" -msgstr "" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "" @@ -1053,6 +1334,9 @@ msgstr "" msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "" +msgid "Have your users email" +msgstr "" + msgid "Health Check" msgstr "健康檢查 (Health Check)" @@ -1111,9 +1395,6 @@ msgstr "週期分析簡介" msgid "Issue board focus mode" msgstr "" -msgid "Issue boards with milestones" -msgstr "" - msgid "Issue events" msgstr "議題事件 (issue event)" @@ -1126,6 +1407,24 @@ msgstr "" msgid "Issues" msgstr "" +msgid "Jan" +msgstr "" + +msgid "January" +msgstr "" + +msgid "Jul" +msgstr "" + +msgid "July" +msgstr "" + +msgid "Jun" +msgstr "" + +msgid "June" +msgstr "" + msgid "LFSStatus|Disabled" msgstr "停用" @@ -1197,9 +1496,18 @@ msgstr "" msgid "Login" msgstr "" +msgid "Mar" +msgstr "" + +msgid "March" +msgstr "" + msgid "Maximum git storage failures" msgstr "" +msgid "May" +msgstr "" + msgid "Median" msgstr "中位數" @@ -1243,9 +1551,15 @@ msgstr "創建流水線計劃" msgid "New branch" msgstr "新增分支" +msgid "New branch unavailable" +msgstr "" + msgid "New directory" msgstr "新增目錄" +msgid "New epic" +msgstr "" + msgid "New file" msgstr "新增文件" @@ -1282,6 +1596,9 @@ msgstr "沒有存儲庫" msgid "No schedules" msgstr "沒有計劃" +msgid "No time spent" +msgstr "" + msgid "None" msgstr "" @@ -1348,18 +1665,33 @@ msgstr "關注" msgid "Notifications" msgstr "" +msgid "Nov" +msgstr "" + +msgid "November" +msgstr "" + msgid "Number of access attempts" msgstr "" msgid "Number of failures before backing off" msgstr "" +msgid "Oct" +msgstr "" + +msgid "October" +msgstr "" + msgid "OfSearchInADropdown|Filter" msgstr "篩選" msgid "Only project members can comment." msgstr "" +msgid "Opened" +msgstr "" + msgid "OpenedNDaysAgo|Opened" msgstr "開始於" @@ -1492,6 +1824,9 @@ msgstr "於階段" msgid "Pipeline|with stages" msgstr "於階段" +msgid "Please solve the reCAPTCHA" +msgstr "" + msgid "Preferences" msgstr "" @@ -1597,9 +1932,15 @@ msgstr "分支圖" msgid "ProjectSettings|Contact an admin to change this setting." msgstr "" +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "" + msgid "ProjectSettings|Only signed commits can be pushed to this repository." msgstr "" +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "" + msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." msgstr "" @@ -1636,6 +1977,39 @@ msgstr "" msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "" +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "" + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "" + +msgid "PrometheusService|Metrics" +msgstr "" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "" + +msgid "PrometheusService|Missing environment variable" +msgstr "" + +msgid "PrometheusService|Monitored" +msgstr "" + +msgid "PrometheusService|More information" +msgstr "" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "" + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" +msgstr "" + +msgid "PrometheusService|Prometheus monitoring" +msgstr "" + +msgid "PrometheusService|View environments" +msgstr "" + msgid "Public - The group and any public projects can be viewed without any authentication." msgstr "" @@ -1732,6 +2106,9 @@ msgstr "" msgid "Scheduling Pipelines" msgstr "流水線計劃" +msgid "Scoped issue boards" +msgstr "" + msgid "Search branches and tags" msgstr "搜索分支和標籤" @@ -1753,6 +2130,12 @@ msgstr "選擇時區" msgid "Select target branch" msgstr "選擇目標分支" +msgid "Sep" +msgstr "" + +msgid "September" +msgstr "" + msgid "Service Templates" msgstr "" @@ -1784,13 +2167,28 @@ msgid "Showing %d event" msgid_plural "Showing %d events" msgstr[0] "顯示 %d 個事件" +msgid "Sidebar|Change weight" +msgstr "" + +msgid "Sidebar|Edit" +msgstr "" + +msgid "Sidebar|No" +msgstr "" + +msgid "Sidebar|None" +msgstr "" + +msgid "Sidebar|Weight" +msgstr "" + msgid "Snippets" msgstr "" msgid "Something went wrong on our end." msgstr "" -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" msgstr "" msgid "Something went wrong while fetching the projects." @@ -1898,9 +2296,15 @@ msgstr "" msgid "SortOptions|Weight" msgstr "" +msgid "Source" +msgstr "" + msgid "Source code" msgstr "源代碼" +msgid "Source is not available" +msgstr "" + msgid "Spam Logs" msgstr "" @@ -1919,6 +2323,9 @@ msgstr "由此更改 %{new_merge_request}" msgid "Start the Runner!" msgstr "運作 Runner!" +msgid "Stopped" +msgstr "" + msgid "Subgroups" msgstr "" @@ -1938,6 +2345,75 @@ msgstr[0] "標籤" msgid "Tags" msgstr "標籤" +msgid "TagsPage|Browse commits" +msgstr "" + +msgid "TagsPage|Browse files" +msgstr "" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "" + +msgid "TagsPage|Cancel" +msgstr "" + +msgid "TagsPage|Create tag" +msgstr "" + +msgid "TagsPage|Delete tag" +msgstr "" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "" + +msgid "TagsPage|Edit release notes" +msgstr "" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "" + +msgid "TagsPage|Filter by tag name" +msgstr "" + +msgid "TagsPage|New Tag" +msgstr "" + +msgid "TagsPage|New tag" +msgstr "" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "" + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "" + +msgid "TagsPage|Release notes" +msgstr "" + +msgid "TagsPage|Repository has no tags yet." +msgstr "" + +msgid "TagsPage|Sort by" +msgstr "" + +msgid "TagsPage|Tags" +msgstr "" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "" + +msgid "TagsPage|This tag has no release notes." +msgstr "" + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "" + +msgid "TagsPage|protected" +msgstr "" + msgid "Target Branch" msgstr "目標分支" @@ -2019,6 +2495,9 @@ msgstr "中位數是壹個數列中最中間的值。例如在 3、5、9 之間 msgid "There are problems accessing Git storage: " msgstr "訪問 Git 存儲時出現問題:" +msgid "This board\\'s scope is reduced" +msgstr "" + msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "" @@ -2040,6 +2519,9 @@ msgstr "在創建壹個空的存儲庫或導入現有存儲庫之前,您將無 msgid "This merge request is locked." msgstr "" +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "議題被列入日程表的時間" @@ -2186,15 +2668,27 @@ msgstr[0] "分鐘" msgid "Time|s" msgstr "秒" +msgid "Title" +msgstr "" + msgid "Total Time" msgstr "總時間" +msgid "Total issue time spent" +msgstr "" + msgid "Total test time for all commits/merges" msgstr "所有提交和合併的總測試時間" msgid "Track activity with Contribution Analytics." msgstr "" +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "" + +msgid "Turn on Service Desk" +msgstr "" + msgid "Unlock" msgstr "" @@ -2231,6 +2725,9 @@ msgstr "上傳文件" msgid "UploadLink|click to upload" msgstr "點擊上傳" +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "" + msgid "Use the following registration token during setup:" msgstr "在安裝過程中使用以下註冊令牌:" @@ -2264,6 +2761,9 @@ msgstr "權限不足。如需查看相關數據,請向管理員申請權限。 msgid "We don't have enough data to show this stage." msgstr "該階段的數據不足,無法顯示。" +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "" + msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." msgstr "" @@ -2393,12 +2893,6 @@ msgstr "即將刪除與源項目 %{forked_from_project} 的派生關系。確定 msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "即將 %{project_name_with_namespace} 轉義給另壹個所有者。確定繼續嗎?" -msgid "You are on a read-only GitLab instance." -msgstr "" - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "" - msgid "You can only add files when you are on a branch" msgstr "只能在分支上添加文件" @@ -2438,6 +2932,9 @@ msgstr "在賬號上 %{set_password_link} 之前將無法通過 %{protocol} 拉 msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" msgstr "在賬號中 %{add_ssh_key_link} 之前將無法通過 SSH 拉取或推送代碼。" +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "" + msgid "Your comment will not be visible to the public." msgstr "" @@ -2450,6 +2947,12 @@ msgstr "您的名字" msgid "Your projects" msgstr "" +msgid "branch name" +msgstr "" + +msgid "by" +msgstr "" + msgid "commit" msgstr "" @@ -2473,6 +2976,9 @@ msgstr "" msgid "personal access token" msgstr "" +msgid "source" +msgstr "" + msgid "to help your contributors communicate effectively!" msgstr "" diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po index b6d4ed27487..76c1e598433 100644 --- a/locale/zh_TW/gitlab.po +++ b/locale/zh_TW/gitlab.po @@ -2,8 +2,8 @@ msgid "" msgstr "" "Project-Id-Version: gitlab-ee\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-11-02 14:42+0100\n" -"PO-Revision-Date: 2017-11-20 03:59-0500\n" +"POT-Creation-Date: 2017-12-12 18:31+0000\n" +"PO-Revision-Date: 2018-01-05 04:42-0500\n" "Last-Translator: gitlab \n" "Language-Team: Chinese Traditional\n" "Language: zh_TW\n" @@ -51,6 +51,9 @@ msgid "%{storage_name}: failed storage access attempt on host:" msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:" msgstr[0] "%{storage_name}:已存取此主機失敗 %{failed_attempts} 次" +msgid "%{text} is available" +msgstr "" + msgid "(checkout the %{link} for information on how to install it)." msgstr "(如何安裝請參閱 %{link})" @@ -95,7 +98,7 @@ msgid "Activity" msgstr "活動" msgid "Add" -msgstr "增加" +msgstr "" msgid "Add Changelog" msgstr "新增更新日誌" @@ -104,14 +107,11 @@ msgid "Add Contribution guide" msgstr "新增協作指南" msgid "Add Group Webhooks and GitLab Enterprise Edition." -msgstr "加入來自 Webhooks 或者是 GitLab 企業版的群組" +msgstr "" msgid "Add License" msgstr "新增授權條款" -msgid "Add an SSH key to your profile to pull or push via SSH." -msgstr "將 SSH 金鑰新增至您的個人帳號後, 即可透過 SSH 來上傳 (push) 或下載 (pull) 。" - msgid "Add new directory" msgstr "新增目錄" @@ -124,6 +124,15 @@ msgstr "進階設定" msgid "All" msgstr "全部" +msgid "An error occurred when toggling the notification subscription" +msgstr "" + +msgid "An error occurred when updating the issue weight" +msgstr "" + +msgid "An error occurred while fetching sidebar data" +msgstr "" + msgid "An error occurred. Please try again." msgstr "發生錯誤,請再試一次。" @@ -133,6 +142,12 @@ msgstr "外觀" msgid "Applications" msgstr "應用程式" +msgid "Apr" +msgstr "" + +msgid "April" +msgstr "" + msgid "Archived project! Repository is read-only" msgstr "此專案已封存!檔案庫 (repository) 為唯讀狀態" @@ -160,6 +175,12 @@ msgstr "" msgid "Attach a file by drag & drop or %{upload_link}" msgstr "拖放檔案到此處或者 %{upload_link}" +msgid "Aug" +msgstr "" + +msgid "August" +msgstr "" + msgid "Authentication Log" msgstr "登入紀錄" @@ -193,59 +214,62 @@ msgstr "了解更多於 %{link_to_documentation}" msgid "AutoDevOps|You can activate %{link_to_settings} for this project." msgstr "你可以為此專案啟動 %{link_to_settings}" +msgid "Available" +msgstr "" + msgid "Billing" -msgstr "方案" +msgstr "" msgid "BillingPlans|%{group_name} is currently on the %{plan_link} plan." -msgstr "%{group_name} 目前使用 %{plan_link} 方案。" +msgstr "" msgid "BillingPlans|Automatic downgrade and upgrade to some plans is currently not available." -msgstr "目前無法自動升級或降級至其他方案。" +msgstr "" msgid "BillingPlans|Current plan" -msgstr "目前方案" +msgstr "" msgid "BillingPlans|Customer Support" -msgstr "客戶服務" +msgstr "" msgid "BillingPlans|Downgrade" -msgstr "降級" +msgstr "" msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}." -msgstr "了解更多我們的方案,或是閱讀 %{faq_link}" +msgstr "" msgid "BillingPlans|Manage plan" -msgstr "管理方案" +msgstr "" msgid "BillingPlans|Please contact %{customer_support_link} in that case." -msgstr "請聯繫 %{customer_support_link}" +msgstr "" msgid "BillingPlans|See all %{plan_name} features" -msgstr "查看更多 %{plan_name} 功能" +msgstr "" msgid "BillingPlans|This group uses the plan associated with its parent group." -msgstr "此群組與上層群組使用相同的方案。" +msgstr "" msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}." -msgstr "請至 %{parent_billing_page_link} 來管理此群組的方案。" +msgstr "" msgid "BillingPlans|Upgrade" -msgstr "升級" +msgstr "" msgid "BillingPlans|You are currently on the %{plan_link} plan." -msgstr "目前使用 %{plan_link} 方案。" +msgstr "" msgid "BillingPlans|frequently asked questions" -msgstr "常見問題" +msgstr "" msgid "BillingPlans|monthly" -msgstr "每個月" +msgstr "" msgid "BillingPlans|paid annually at %{price_per_year}" -msgstr "每年收取 %{price_per_year}" +msgstr "" msgid "BillingPlans|per user" -msgstr "每位使用者" +msgstr "" msgid "Branch" msgid_plural "Branches" @@ -257,6 +281,12 @@ msgstr "已建立分支 (branch) %{branch_name} 。如需設定 msgid "Branch has changed" msgstr "分支(branch)已變更" +msgid "Branch is already taken" +msgstr "" + +msgid "Branch name" +msgstr "" + msgid "BranchSwitcherPlaceholder|Search branches" msgstr "搜尋分支 (branches)" @@ -318,7 +348,7 @@ msgid "Branches|Sort by" msgstr "排序自" msgid "Branches|The branch could not be updated automatically because it has diverged from its upstream counterpart." -msgstr "分支無法自動送交,因為與上游分支衝突。" +msgstr "" msgid "Branches|The default branch cannot be deleted" msgstr "無法刪除預設分支" @@ -339,7 +369,7 @@ msgid "Branches|You’re about to permanently delete the protected branch %{bran msgstr "你將永久刪除受保護的 %{branch_name} 分支。" msgid "Branches|diverged from upstream" -msgstr "與上游分歧" +msgstr "" msgid "Branches|merged" msgstr "已合併" @@ -381,7 +411,7 @@ msgid "Cancel edit" msgstr "取消編輯" msgid "Change Weight" -msgstr "變更權重" +msgstr "" msgid "ChangeTypeActionLabel|Pick into branch" msgstr "挑選到分支 (branch) " @@ -404,6 +434,12 @@ msgstr "統計圖" msgid "Chat" msgstr "即時通訊" +msgid "Checking %{text} availability…" +msgstr "" + +msgid "Checking branch availability..." +msgstr "" + msgid "Cherry-pick this commit" msgstr "挑選此更動記錄 (commit) " @@ -411,7 +447,7 @@ msgid "Cherry-pick this merge request" msgstr "挑選此合併請求 (merge request) " msgid "Choose which groups you wish to replicate to this secondary node. Leave blank to replicate all." -msgstr "選擇你想要複製到第二節點的群組。若留白則會複製全部的群組。" +msgstr "" msgid "CiStatusLabel|canceled" msgstr "已取消" @@ -474,13 +510,46 @@ msgid "Clone repository" msgstr "複製(clone)檔案庫(repository)" msgid "Close" -msgstr "關閉" +msgstr "" msgid "Cluster" msgstr "叢集" -msgid "ClusterIntegration|A %{link_to_container_project} must have been created under this account" -msgstr "必須在此帳號下建立 %{link_to_container_project}" +msgid "ClusterIntegration|%{appList} was successfully installed on your cluster" +msgstr "" + +msgid "ClusterIntegration|%{boldNotice} This will add some extra resources like a load balancer, which incur additional costs. See %{pricingLink}" +msgstr "" + +msgid "ClusterIntegration|API URL" +msgstr "" + +msgid "ClusterIntegration|Active" +msgstr "" + +msgid "ClusterIntegration|Add an existing cluster" +msgstr "" + +msgid "ClusterIntegration|Add cluster" +msgstr "" + +msgid "ClusterIntegration|All" +msgstr "" + +msgid "ClusterIntegration|Applications" +msgstr "" + +msgid "ClusterIntegration|CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Certificate Authority bundle (PEM format)" +msgstr "" + +msgid "ClusterIntegration|Choose how to set up cluster integration" +msgstr "" + +msgid "ClusterIntegration|Cluster" +msgstr "" msgid "ClusterIntegration|Cluster details" msgstr "叢集詳情" @@ -498,56 +567,137 @@ msgid "ClusterIntegration|Cluster integration is enabled for this project. Disab msgstr "此專案已啟用叢集整合。禁止叢集整合不會影響您的叢集,它只是暫時關閉 GitLab 的連接。" msgid "ClusterIntegration|Cluster is being created on Google Kubernetes Engine..." -msgstr "在 Google 容器引擎中建立新的叢集" +msgstr "" msgid "ClusterIntegration|Cluster name" msgstr "叢集名稱" -msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine" -msgstr "在 Google 容器引擎上成功建立叢集" +msgid "ClusterIntegration|Cluster was successfully created on Google Kubernetes Engine. Refresh the page to see cluster's details" +msgstr "" + +msgid "ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}" +msgstr "" + +msgid "ClusterIntegration|Copy API URL" +msgstr "" + +msgid "ClusterIntegration|Copy CA Certificate" +msgstr "" + +msgid "ClusterIntegration|Copy Token" +msgstr "" msgid "ClusterIntegration|Copy cluster name" msgstr "複製叢集名稱" +msgid "ClusterIntegration|Create a new cluster on Google Engine right from GitLab" +msgstr "" + msgid "ClusterIntegration|Create cluster" msgstr "建立叢集" -msgid "ClusterIntegration|Create new cluster on Google Kubernetes Engine" -msgstr "在 Google 容器引擎中建立新的叢集" +msgid "ClusterIntegration|Create cluster on Google Kubernetes Engine" +msgstr "" + +msgid "ClusterIntegration|Create on GKE" +msgstr "" msgid "ClusterIntegration|Enable cluster integration" msgstr "啟動叢集整合" +msgid "ClusterIntegration|Enter the details for an existing Kubernetes cluster" +msgstr "" + +msgid "ClusterIntegration|Enter the details for your cluster" +msgstr "" + +msgid "ClusterIntegration|Environment pattern" +msgstr "" + +msgid "ClusterIntegration|GKE pricing" +msgstr "" + +msgid "ClusterIntegration|GitLab Runner" +msgstr "" + msgid "ClusterIntegration|Google Cloud Platform project ID" msgstr "Google 雲端專案 ID" msgid "ClusterIntegration|Google Kubernetes Engine" -msgstr "Google 容器引擎" +msgstr "" msgid "ClusterIntegration|Google Kubernetes Engine project" -msgstr "Google 容器引擎專案" +msgstr "" + +msgid "ClusterIntegration|Helm Tiller" +msgstr "" + +msgid "ClusterIntegration|Inactive" +msgstr "" + +msgid "ClusterIntegration|Ingress" +msgstr "" + +msgid "ClusterIntegration|Install" +msgstr "" + +msgid "ClusterIntegration|Install applications on your cluster. Read more about %{helpLink}" +msgstr "" + +msgid "ClusterIntegration|Installed" +msgstr "" + +msgid "ClusterIntegration|Installing" +msgstr "" + +msgid "ClusterIntegration|Integrate cluster automation" +msgstr "" msgid "ClusterIntegration|Learn more about %{link_to_documentation}" msgstr "學習更多有關於%{link_to_documentation}" +msgid "ClusterIntegration|Learn more about Clusters" +msgstr "" + msgid "ClusterIntegration|Machine type" msgstr "機器型別" msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create clusters" msgstr "請確認您的帳戶中%{link_to_requirements} 是否建立叢集" -msgid "ClusterIntegration|Manage Cluster integration on your GitLab project" -msgstr "在你的 GitLab 專案上管理叢集整合" +msgid "ClusterIntegration|Manage cluster integration on your GitLab project" +msgstr "" msgid "ClusterIntegration|Manage your cluster by visiting %{link_gke}" msgstr "請至 %{link_gke} 管理你的叢集" +msgid "ClusterIntegration|Multiple clusters are available in GitLab Entreprise Edition Premium and Ultimate" +msgstr "" + +msgid "ClusterIntegration|Note:" +msgstr "" + msgid "ClusterIntegration|Number of nodes" msgstr "所有的端點數量" +msgid "ClusterIntegration|Please enter access information for your cluster. If you need help, you can read our %{link_to_help_page} on clusters" +msgstr "" + msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:" msgstr "請確認你的 Google 帳號是否符合這些條件" +msgid "ClusterIntegration|Problem setting up the cluster" +msgstr "" + +msgid "ClusterIntegration|Problem setting up the clusters list" +msgstr "" + +msgid "ClusterIntegration|Project ID" +msgstr "" + +msgid "ClusterIntegration|Project namespace" +msgstr "" + msgid "ClusterIntegration|Project namespace (optional, unique)" msgstr "專案命名空間(選填,不可重複)" @@ -560,8 +710,14 @@ msgstr "刪除叢集整合" msgid "ClusterIntegration|Remove integration" msgstr "刪除整合" -msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your project." -msgstr "當刪除叢集需要加入專案的定義組態檔,會刪除叢集整合。這並不會刪除你的專案。 刪除叢集的同時,將一起刪除已加入此專案的定義組態檔,但你的專案不會因此被刪除。" +msgid "ClusterIntegration|Removing cluster integration will remove the cluster configuration you have added to this project. It will not delete your cluster on Google Kubernetes Engine." +msgstr "" + +msgid "ClusterIntegration|Request to begin installing failed" +msgstr "" + +msgid "ClusterIntegration|Save changes" +msgstr "" msgid "ClusterIntegration|See and edit the details for your cluster" msgstr "查看與編輯你的叢集內容" @@ -575,33 +731,57 @@ msgstr "查看您的專案" msgid "ClusterIntegration|See zones" msgstr "查看區域" +msgid "ClusterIntegration|Service token" +msgstr "" + +msgid "ClusterIntegration|Show" +msgstr "" + msgid "ClusterIntegration|Something went wrong on our end." msgstr "內部發生了錯誤" msgid "ClusterIntegration|Something went wrong while creating your cluster on Google Kubernetes Engine" -msgstr "在 Google Kubernetes Engine 上建立叢集時發生了錯誤" +msgstr "" + +msgid "ClusterIntegration|Something went wrong while installing %{title}" +msgstr "" + +msgid "ClusterIntegration|There are no clusters to show" +msgstr "" + +msgid "ClusterIntegration|This account must have permissions to create a cluster in the %{link_to_container_project} specified below" +msgstr "" msgid "ClusterIntegration|Toggle Cluster" msgstr "叢集開關" +msgid "ClusterIntegration|Token" +msgstr "" + msgid "ClusterIntegration|With a cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgstr "當叢集連結到此專案,你可以使用複閱應用 (review apps),部署你的應用程式,執行你的流水線 (pipelines),還有更多容易上手的方式可以使用。" msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}" -msgstr "您的帳號必須有 %{link_to_kubernetes_engine}" +msgstr "" msgid "ClusterIntegration|Zone" msgstr "區域" msgid "ClusterIntegration|access to Google Kubernetes Engine" -msgstr "存取 Google Kubernetes Engine" +msgstr "" msgid "ClusterIntegration|cluster" msgstr "叢集" +msgid "ClusterIntegration|documentation" +msgstr "" + msgid "ClusterIntegration|help page" msgstr "說明頁面" +msgid "ClusterIntegration|installing applications" +msgstr "" + msgid "ClusterIntegration|meets the requirements" msgstr "符合需求" @@ -615,10 +795,6 @@ msgid "Commit" msgid_plural "Commits" msgstr[0] "更動記錄 (commit) " -msgid "Commit %d file" -msgid_plural "Commit %d files" -msgstr[0] "提交 %d 個檔案" - msgid "Commit Message" msgstr "更動訊息" @@ -700,14 +876,23 @@ msgstr "協作指南" msgid "Contributors" msgstr "協作者" +msgid "ContributorsPage|Building repository graph." +msgstr "" + +msgid "ContributorsPage|Commits to %{branch_name}, excluding merge commits. Limited to 6,000 commits." +msgstr "" + +msgid "ContributorsPage|Please wait a moment, this page will automatically refresh when ready." +msgstr "" + msgid "Control the maximum concurrency of LFS/attachment backfill for this secondary node" -msgstr "控制次節點 (secondary node) 同步 LFS 和附檔的最大並行率 (concurrency)" +msgstr "" msgid "Control the maximum concurrency of repository backfill for this secondary node" -msgstr "控制次節點 (secondary node) 同步檔案庫 (repository) 的最大並行率 (concurrency)" +msgstr "" msgid "Copy SSH public key to clipboard" -msgstr "複製 SSH 金鑰到剪貼簿" +msgstr "" msgid "Copy URL to clipboard" msgstr "複製網址到剪貼簿" @@ -727,6 +912,9 @@ msgstr "建立目錄" msgid "Create empty bare repository" msgstr "建立一個新的 bare repository" +msgid "Create epic" +msgstr "" + msgid "Create file" msgstr "新增檔案" @@ -754,6 +942,9 @@ msgstr "建立標籤" msgid "CreateTokenToCloneLink|create a personal access token" msgstr "建立個人存取憑證 (access token)" +msgid "Creating epic" +msgstr "" + msgid "Cron Timezone" msgstr "Cron 時區" @@ -799,6 +990,12 @@ msgstr "全部" msgid "DashboardProjects|Personal" msgstr "個人" +msgid "Dec" +msgstr "" + +msgid "December" +msgstr "" + msgid "Define a custom pattern with cron syntax" msgstr "使用 Cron 語法自訂排程" @@ -816,7 +1013,7 @@ msgid "Description" msgstr "描述" msgid "Description templates allow you to define context-specific templates for issue and merge request description fields for your project." -msgstr "描述範本 (Description templates) 讓你在建立專案的議題 (Issue) 和合併請求時可以選擇特定的範本。" +msgstr "" msgid "Details" msgstr "細節" @@ -872,6 +1069,72 @@ msgstr "編輯 %{id} 流水線 (pipeline) 排程" msgid "Emails" msgstr "電子郵件" +msgid "Environments|An error occurred while fetching the environments." +msgstr "" + +msgid "Environments|An error occurred while making the request." +msgstr "" + +msgid "Environments|Commit" +msgstr "" + +msgid "Environments|Deployment" +msgstr "" + +msgid "Environments|Environment" +msgstr "" + +msgid "Environments|Environments" +msgstr "" + +msgid "Environments|Environments are places where code gets deployed, such as staging or production." +msgstr "" + +msgid "Environments|Job" +msgstr "" + +msgid "Environments|New environment" +msgstr "" + +msgid "Environments|No deployments yet" +msgstr "" + +msgid "Environments|Open" +msgstr "" + +msgid "Environments|Re-deploy" +msgstr "" + +msgid "Environments|Read more about environments" +msgstr "" + +msgid "Environments|Rollback" +msgstr "" + +msgid "Environments|Show all" +msgstr "" + +msgid "Environments|Updated" +msgstr "" + +msgid "Environments|You don't have any environments right now." +msgstr "" + +msgid "Epic will be removed! Are you sure?" +msgstr "" + +msgid "Epics" +msgstr "" + +msgid "Epics let you manage your portfolio of projects more efficiently and with less effort" +msgstr "" + +msgid "Error creating epic" +msgstr "" + +msgid "Error occurred when toggling the notification subscription" +msgstr "" + msgid "EventFilterBy|Filter by all" msgstr "顯示全部" @@ -911,6 +1174,12 @@ msgstr "無法變更所有權" msgid "Failed to remove the pipeline schedule" msgstr "無法刪除流水線 (pipeline) 排程" +msgid "Feb" +msgstr "" + +msgid "February" +msgstr "" + msgid "File name" msgstr "檔案名稱" @@ -955,19 +1224,34 @@ msgid "GPG Keys" msgstr "GPG 金鑰" msgid "Geo Nodes" -msgstr "Geo 節點" +msgstr "" + +msgid "GeoNodeSyncStatus|Failed" +msgstr "" + +msgid "GeoNodeSyncStatus|Node is failing or broken." +msgstr "" + +msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage." +msgstr "" + +msgid "GeoNodeSyncStatus|Out of sync" +msgstr "" + +msgid "GeoNodeSyncStatus|Synced" +msgstr "" msgid "Geo|File sync capacity" -msgstr "檔案同步容量" +msgstr "" msgid "Geo|Groups to replicate" -msgstr "要複製的群組" +msgstr "" msgid "Geo|Repository sync capacity" -msgstr "檔案庫(repository)同步量" +msgstr "" msgid "Geo|Select groups to replicate." -msgstr "選擇欲複製之群組。" +msgstr "" msgid "Git storage health information has been reset" msgstr "Git 儲存空間健康指數已重置" @@ -1020,9 +1304,6 @@ msgstr "找不到群組" msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group." msgstr "你可以管理群組內所有成員的每個專案的存取權限" -msgid "GroupsTreeRole|as" -msgstr "的" - msgid "GroupsTree|Are you sure you want to leave the \"${this.group.fullName}\" group?" msgstr "你確定要離開群組 \"${this.group.fullName}\" 嗎?" @@ -1053,6 +1334,9 @@ msgstr "不好意思,沒有搜尋到任何符合條件的群組" msgid "GroupsTree|Sorry, no groups or projects matched your search" msgstr "不好意思,沒有搜尋到任何符合條件的群組或專案" +msgid "Have your users email" +msgstr "" + msgid "Health Check" msgstr "健康檢查" @@ -1081,20 +1365,20 @@ msgid "Import repository" msgstr "匯入檔案庫 (repository)" msgid "Improve Issue boards with GitLab Enterprise Edition." -msgstr "協助改進 GitLab 企業版的議題看板(issue boards)" +msgstr "" msgid "Improve issues management with Issue weight and GitLab Enterprise Edition." -msgstr "協助改進 GitLab 企業版的議題管理與權重。" +msgstr "" msgid "Improve search with Advanced Global Search and GitLab Enterprise Edition." -msgstr "協助改進 GitLab 企業版的搜尋 & 進階全局搜尋。" +msgstr "" msgid "Install a Runner compatible with GitLab CI" msgstr "安裝與 GitLab CI 相容的 Runner" msgid "Instance" msgid_plural "Instances" -msgstr[0] "主機" +msgstr[0] "" msgid "Internal - The group and any internal projects can be viewed by any logged in user." msgstr "內部 - 任何登入的使用者都可以查看該群組及其專案" @@ -1109,10 +1393,7 @@ msgid "Introducing Cycle Analytics" msgstr "週期分析簡介" msgid "Issue board focus mode" -msgstr "議題看板(issue boards)模式" - -msgid "Issue boards with milestones" -msgstr "議題看板(issue boards)與里程碑" +msgstr "" msgid "Issue events" msgstr "議題 (issue) 事件" @@ -1121,11 +1402,29 @@ msgid "IssueBoards|Board" msgstr "看板" msgid "IssueBoards|Boards" -msgstr "看板" +msgstr "" msgid "Issues" msgstr "議題" +msgid "Jan" +msgstr "" + +msgid "January" +msgstr "" + +msgid "Jul" +msgstr "" + +msgid "July" +msgstr "" + +msgid "Jun" +msgstr "" + +msgid "June" +msgstr "" + msgid "LFSStatus|Disabled" msgstr "停用" @@ -1179,7 +1478,7 @@ msgid "Leave project" msgstr "退出專案" msgid "License" -msgstr "授權" +msgstr "" msgid "Limited to showing %d event at most" msgid_plural "Limited to showing %d events at most" @@ -1192,14 +1491,23 @@ msgid "Locked" msgstr "鎖定" msgid "Locked Files" -msgstr "被鎖定的檔案" +msgstr "" msgid "Login" msgstr "登入" +msgid "Mar" +msgstr "" + +msgid "March" +msgstr "" + msgid "Maximum git storage failures" msgstr "最大 git 儲存失敗" +msgid "May" +msgstr "" + msgid "Median" msgstr "中位數" @@ -1228,7 +1536,7 @@ msgid "More information is available|here" msgstr "健康檢查" msgid "Multiple issue boards" -msgstr "多個議題看板 (issue boards)" +msgstr "" msgid "New Cluster" msgstr "新叢集" @@ -1243,9 +1551,15 @@ msgstr "建立流水線 (pipeline) 排程" msgid "New branch" msgstr "新分支 (branch) " +msgid "New branch unavailable" +msgstr "" + msgid "New directory" msgstr "新增目錄" +msgid "New epic" +msgstr "" + msgid "New file" msgstr "新增檔案" @@ -1282,6 +1596,9 @@ msgstr "找不到檔案庫 (repository)" msgid "No schedules" msgstr "沒有排程" +msgid "No time spent" +msgstr "" + msgid "None" msgstr "無" @@ -1348,18 +1665,33 @@ msgstr "關注" msgid "Notifications" msgstr "通知" +msgid "Nov" +msgstr "" + +msgid "November" +msgstr "" + msgid "Number of access attempts" msgstr "嘗試存取的次數" msgid "Number of failures before backing off" msgstr "" +msgid "Oct" +msgstr "" + +msgid "October" +msgstr "" + msgid "OfSearchInADropdown|Filter" msgstr "篩選" msgid "Only project members can comment." msgstr "只有群組成員才能留言。" +msgid "Opened" +msgstr "" + msgid "OpenedNDaysAgo|Opened" msgstr "開始於" @@ -1406,7 +1738,7 @@ msgid "Pipeline Schedules" msgstr "流水線 (pipeline) 排程" msgid "Pipeline quota" -msgstr "流水線額度" +msgstr "" msgid "PipelineCharts|Failed:" msgstr "失敗:" @@ -1492,6 +1824,9 @@ msgstr "於階段" msgid "Pipeline|with stages" msgstr "於階段" +msgid "Please solve the reCAPTCHA" +msgstr "" + msgid "Preferences" msgstr "偏好設定" @@ -1595,22 +1930,28 @@ msgid "ProjectNetworkGraph|Graph" msgstr "分支圖" msgid "ProjectSettings|Contact an admin to change this setting." -msgstr "聯絡管理員以變更設定。" +msgstr "" + +msgid "ProjectSettings|Immediately run a pipeline on the default branch" +msgstr "" msgid "ProjectSettings|Only signed commits can be pushed to this repository." -msgstr "只有已簽章的變更才能被推送到檔案庫(repository)。" +msgstr "" + +msgid "ProjectSettings|Problem setting up the CI/CD settings JavaScript" +msgstr "" msgid "ProjectSettings|This setting is applied on the server level and can be overridden by an admin." -msgstr "此設定已經套用於伺服器層級,並且可被管理員覆寫。" +msgstr "" msgid "ProjectSettings|This setting is applied on the server level but has been overridden for this project." -msgstr "此設定已經套用至伺服器層級,但此專案使用另一個設定。" +msgstr "" msgid "ProjectSettings|This setting will be applied to all projects unless overridden by an admin." -msgstr "此設定將套用至所有專案,除非被管理員覆寫。" +msgstr "" msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails." -msgstr "使用者推送的修改 (commits) 只能使用他們自己的電子郵件。" +msgstr "" msgid "Projects" msgstr "專案" @@ -1636,6 +1977,39 @@ msgstr "抱歉,沒有符合搜尋條件的專案" msgid "ProjectsDropdown|This feature requires browser localStorage support" msgstr "此功能需要瀏覽器支援 localStorage" +msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server." +msgstr "" + +msgid "PrometheusService|Finding and configuring metrics..." +msgstr "" + +msgid "PrometheusService|Metrics" +msgstr "" + +msgid "PrometheusService|Metrics are automatically configured and monitored based on a library of metrics from popular exporters." +msgstr "" + +msgid "PrometheusService|Missing environment variable" +msgstr "" + +msgid "PrometheusService|Monitored" +msgstr "" + +msgid "PrometheusService|More information" +msgstr "" + +msgid "PrometheusService|No metrics are being monitored. To start monitoring, deploy to an environment." +msgstr "" + +msgid "PrometheusService|Prometheus API Base URL, like http://prometheus.example.com/" +msgstr "" + +msgid "PrometheusService|Prometheus monitoring" +msgstr "" + +msgid "PrometheusService|View environments" +msgstr "" + msgid "Public - The group and any public projects can be viewed without any authentication." msgstr "公開 - 未登入的情況下依然可以查看任何公開專案" @@ -1643,13 +2017,13 @@ msgid "Public - The project can be accessed without any authentication." msgstr "公開 - 無須任何身份驗證即可存取該專案" msgid "Push Rules" -msgstr "推送 [Push] 規則" +msgstr "" msgid "Push events" msgstr "推送 (push) 事件" msgid "PushRule|Committer restriction" -msgstr "提交限制" +msgstr "" msgid "Read more" msgstr "瞭解更多" @@ -1664,7 +2038,7 @@ msgid "RefSwitcher|Tags" msgstr "標籤" msgid "Registry" -msgstr "登錄表" +msgstr "" msgid "Related Commits" msgstr "相關的更動記錄 (commit) " @@ -1732,6 +2106,9 @@ msgstr "排程" msgid "Scheduling Pipelines" msgstr "流水線 (pipeline) 排程" +msgid "Scoped issue boards" +msgstr "" + msgid "Search branches and tags" msgstr "搜尋分支 (branch) 和標籤" @@ -1753,6 +2130,12 @@ msgstr "選擇時區" msgid "Select target branch" msgstr "選擇目標分支 (branch) " +msgid "Sep" +msgstr "" + +msgid "September" +msgstr "" + msgid "Service Templates" msgstr "服務範本" @@ -1784,14 +2167,29 @@ msgid "Showing %d event" msgid_plural "Showing %d events" msgstr[0] "顯示 %d 個事件" +msgid "Sidebar|Change weight" +msgstr "" + +msgid "Sidebar|Edit" +msgstr "" + +msgid "Sidebar|No" +msgstr "" + +msgid "Sidebar|None" +msgstr "" + +msgid "Sidebar|Weight" +msgstr "" + msgid "Snippets" msgstr "文字片段" msgid "Something went wrong on our end." msgstr "發生了錯誤。" -msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName(this.issuableType)}" -msgstr "有個地方出錯了,因為他嘗試去變更 ${this.issuableDisplayName(this.issuableType)} 的鎖定狀態。" +msgid "Something went wrong trying to change the locked state of this ${this.issuableDisplayName}" +msgstr "" msgid "Something went wrong while fetching the projects." msgstr "讀取專案時發生錯誤。" @@ -1842,7 +2240,7 @@ msgid "SortOptions|Least popular" msgstr "最不受歡迎" msgid "SortOptions|Less weight" -msgstr "最低權重" +msgstr "" msgid "SortOptions|Milestone" msgstr "里程碑" @@ -1854,7 +2252,7 @@ msgid "SortOptions|Milestone due soon" msgstr "即將截止的里程碑" msgid "SortOptions|More weight" -msgstr "更大的權重" +msgstr "" msgid "SortOptions|Most popular" msgstr "最受歡迎" @@ -1896,11 +2294,17 @@ msgid "SortOptions|Start soon" msgstr "現在開始" msgid "SortOptions|Weight" -msgstr "權重" +msgstr "" + +msgid "Source" +msgstr "" msgid "Source code" msgstr "原始碼" +msgid "Source is not available" +msgstr "" + msgid "Spam Logs" msgstr "垃圾訊息記錄" @@ -1919,6 +2323,9 @@ msgstr "以這些改動建立一個新的 %{new_merge_request} " msgid "Start the Runner!" msgstr "啟動 Runner!" +msgid "Stopped" +msgstr "" + msgid "Subgroups" msgstr "子群組" @@ -1938,6 +2345,75 @@ msgstr[0] "標籤" msgid "Tags" msgstr "標籤" +msgid "TagsPage|Browse commits" +msgstr "" + +msgid "TagsPage|Browse files" +msgstr "" + +msgid "TagsPage|Can't find HEAD commit for this tag" +msgstr "" + +msgid "TagsPage|Cancel" +msgstr "" + +msgid "TagsPage|Create tag" +msgstr "" + +msgid "TagsPage|Delete tag" +msgstr "" + +msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?" +msgstr "" + +msgid "TagsPage|Edit release notes" +msgstr "" + +msgid "TagsPage|Existing branch name, tag, or commit SHA" +msgstr "" + +msgid "TagsPage|Filter by tag name" +msgstr "" + +msgid "TagsPage|New Tag" +msgstr "" + +msgid "TagsPage|New tag" +msgstr "" + +msgid "TagsPage|Optionally, add a message to the tag." +msgstr "" + +msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." +msgstr "" + +msgid "TagsPage|Release notes" +msgstr "" + +msgid "TagsPage|Repository has no tags yet." +msgstr "" + +msgid "TagsPage|Sort by" +msgstr "" + +msgid "TagsPage|Tags" +msgstr "" + +msgid "TagsPage|Tags give the ability to mark specific points in history as being important" +msgstr "" + +msgid "TagsPage|This tag has no release notes." +msgstr "" + +msgid "TagsPage|Use git tag command to add a new one:" +msgstr "" + +msgid "TagsPage|Write your release notes or drag files here..." +msgstr "" + +msgid "TagsPage|protected" +msgstr "" + msgid "Target Branch" msgstr "目標分支 (branch) " @@ -1945,10 +2421,10 @@ msgid "Team" msgstr "團隊" msgid "Thanks! Don't show me this again" -msgstr "感謝!請不要再次顯示" +msgstr "" msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project." -msgstr "GitLab 的進階全局搜尋功能是非常強大的搜尋服務。您可以搜尋其他團隊的代碼以幫助您完善自己項目中的代碼。從而避免建立重複的代碼浪費時間。" +msgstr "" msgid "The circuitbreaker backoff threshold should be lower than the failure count threshold" msgstr "限流阻斷元件的觸發門檻應低於計數錯誤門檻" @@ -2019,6 +2495,9 @@ msgstr "中位數是一個數列中最中間的值。例如在 3、5、9 之間 msgid "There are problems accessing Git storage: " msgstr "存取 Git 儲存空間時出現問題:" +msgid "This board\\'s scope is reduced" +msgstr "" + msgid "This branch has changed since you started editing. Would you like to create a new branch?" msgstr "在您編輯後,此分支已被更改,您想要建立一個新的分支嗎?" @@ -2040,6 +2519,9 @@ msgstr "這代表在您建立一個空的檔案庫 (repository) 或是匯入一 msgid "This merge request is locked." msgstr "這個合併請求已被鎖定。" +msgid "Those emails automatically become issues (with the comments becoming the email conversation) listed here." +msgstr "" + msgid "Time before an issue gets scheduled" msgstr "議題 (issue) 被列入日程表的時間" @@ -2186,14 +2668,26 @@ msgstr[0] "分鐘" msgid "Time|s" msgstr "秒" +msgid "Title" +msgstr "" + msgid "Total Time" msgstr "總時間" +msgid "Total issue time spent" +msgstr "" + msgid "Total test time for all commits/merges" msgstr "合併 (merge) 與更動記錄 (commit) 的總測試時間" msgid "Track activity with Contribution Analytics." -msgstr "追蹤分析貢獻與活動。" +msgstr "" + +msgid "Track groups of issues that share a theme, across projects and milestones" +msgstr "" + +msgid "Turn on Service Desk" +msgstr "" msgid "Unlock" msgstr "解鎖" @@ -2208,19 +2702,19 @@ msgid "Unsubscribe" msgstr "取消訂閱" msgid "Upgrade your plan to activate Advanced Global Search." -msgstr "升級您的方案以啟用進階全局搜尋。" +msgstr "" msgid "Upgrade your plan to activate Contribution Analytics." -msgstr "升級您的方案以啟用貢獻分析。" +msgstr "" msgid "Upgrade your plan to activate Group Webhooks." -msgstr "升級您的方案以啟用群組 Webhooks。" +msgstr "" msgid "Upgrade your plan to activate Issue weight." -msgstr "升級您的方案以啟用問題權重。" +msgstr "" msgid "Upgrade your plan to improve Issue boards." -msgstr "升級您的方案以使用議題看板(issue boards)" +msgstr "" msgid "Upload New File" msgstr "上傳新檔案" @@ -2231,6 +2725,9 @@ msgstr "上傳檔案" msgid "UploadLink|click to upload" msgstr "點擊上傳" +msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab" +msgstr "" + msgid "Use the following registration token during setup:" msgstr "在安裝過程中使用此註冊憑證 (registration token):" @@ -2264,11 +2761,14 @@ msgstr "權限不足。如需查看相關資料,請向管理員申請權限。 msgid "We don't have enough data to show this stage." msgstr "因該階段的資料不足而無法顯示相關資訊" +msgid "We want to be sure it is you, please confirm you are not a robot." +msgstr "" + msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group." msgstr "" msgid "Weight" -msgstr "權重" +msgstr "" msgid "When access to a storage fails. GitLab will prevent access to the storage for the time specified here. This allows the filesystem to recover. Repositories on failing shards are temporarly unavailable" msgstr "當存取檔案庫 (repository) 失敗時, GitLab 將在此處指定的時間內防止檔案庫的存取,以此等待檔案系統恢復。失敗的檔案庫分流 (shard) 會暫時無法使用。" @@ -2376,7 +2876,7 @@ msgid "Wiki|Wiki Pages" msgstr "維基頁面" msgid "With contribution analytics you can have an overview for the activity of issues, merge requests and push events of your organization and its members." -msgstr "透過貢獻分析,您可以分析您的組織及其成員的問題、合併請求和推送活動。" +msgstr "" msgid "Withdraw Access Request" msgstr "取消權限申請" @@ -2393,17 +2893,11 @@ msgstr "將要刪除本分支專案與主幹 %{forked_from_project} 的所有關 msgid "You are going to transfer %{project_name_with_namespace} to another owner. Are you ABSOLUTELY sure?" msgstr "將要把 %{project_name_with_namespace} 的所有權轉移給另一個人。真的「確定」要這麼做嗎?" -msgid "You are on a read-only GitLab instance." -msgstr "您在唯讀的 GitLab 主機上。" - -msgid "You are on a read-only GitLab instance. If you want to make any changes, you must visit the %{link_to_primary_node}." -msgstr "您在唯讀的 GitLab 主機上,如果您想要進行修改,必須到 %{link_to_primary_node}" - msgid "You can only add files when you are on a branch" msgstr "只能在分支 (branch) 上建立檔案" msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead." -msgstr "您不能寫入唯讀的次要 GitLab Geo 主機。請改用 %{link_to_primary_node}。" +msgstr "" msgid "You cannot write to this read-only GitLab instance." msgstr "您不能修改這個唯讀的 GitLab 主機。" @@ -2438,6 +2932,9 @@ msgstr "在帳號上 %{set_password_link} 之前, 將無法使用 %{protocol} msgid "You won't be able to pull or push project code via SSH until you %{add_ssh_key_link} to your profile" msgstr "在個人帳號中 %{add_ssh_key_link} 之前, 將無法使用 SSH 上傳 (push) 或下載 (pull) 程式碼。" +msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile" +msgstr "" + msgid "Your comment will not be visible to the public." msgstr "你的留言將不會被公開。" @@ -2450,8 +2947,14 @@ msgstr "您的名字" msgid "Your projects" msgstr "你的計劃" +msgid "branch name" +msgstr "" + +msgid "by" +msgstr "" + msgid "commit" -msgstr "更動" +msgstr "" msgid "day" msgid_plural "days" @@ -2473,8 +2976,11 @@ msgstr "密碼" msgid "personal access token" msgstr "私人存取憑證 (access token)" +msgid "source" +msgstr "" + msgid "to help your contributors communicate effectively!" -msgstr "幫助你的貢獻者進行有效的溝通!" +msgstr "" msgid "username" msgstr "使用者名稱" -- cgit v1.2.1 From da6af70a22ad34f76923fc8b0c5a1309e0ec541e Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 5 Jan 2018 16:18:01 +0000 Subject: Changes after review --- app/assets/javascripts/jobs/components/header.vue | 6 ++--- .../vue_shared/components/header_ci_component.vue | 4 ++-- app/views/projects/jobs/_empty_state.html.haml | 17 ++++++++++++++ app/views/projects/jobs/show.html.haml | 27 ++++++++++------------ .../components/header_ci_component_spec.js | 6 ++--- 5 files changed, 37 insertions(+), 23 deletions(-) create mode 100644 app/views/projects/jobs/_empty_state.html.haml diff --git a/app/assets/javascripts/jobs/components/header.vue b/app/assets/javascripts/jobs/components/header.vue index 0de823831d9..c660828b30e 100644 --- a/app/assets/javascripts/jobs/components/header.vue +++ b/app/assets/javascripts/jobs/components/header.vue @@ -30,7 +30,7 @@ shouldRenderContent() { return !this.isLoading && Object.keys(this.job).length; }, - wasTriggered() { + jobStarted() { return this.job.started; }, }, @@ -67,8 +67,8 @@ :user="job.user" :actions="actions" :has-sidebar-button="true" - :triggered="wasTriggered" - /> + :should-render-triggered-label="jobStarted" + /> -