New upstream version 13.2.3
This commit is contained in:
parent
029fca15f4
commit
4260d77892
22 changed files with 201 additions and 29 deletions
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -2,6 +2,23 @@
|
|||
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||
entry.
|
||||
|
||||
## 13.2.3 (2020-08-05)
|
||||
|
||||
- No changes.
|
||||
|
||||
## 13.2.2 (2020-07-29)
|
||||
|
||||
### Fixed (3 changes)
|
||||
|
||||
- Coerce repository_storages_weighted, removes repository_storages. !36376
|
||||
- Fix JiraImportUsersInput startAt field. !37492
|
||||
- Provide better git error message when the user is unconfirmed. !37944
|
||||
|
||||
### Changed (1 change)
|
||||
|
||||
- Skip mass unconfirming users when send_user_confirmation_email setting is off. !38024
|
||||
|
||||
|
||||
## 13.2.1 (2020-07-23)
|
||||
|
||||
### Fixed (4 changes)
|
||||
|
|
|
@ -1 +1 @@
|
|||
13.2.1
|
||||
13.2.3
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
13.2.1
|
||||
13.2.3
|
||||
|
|
|
@ -104,7 +104,6 @@ export default {
|
|||
variables: {
|
||||
input: {
|
||||
projectPath: this.projectPath,
|
||||
startAt: 1,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
@ -19,10 +19,10 @@ module Mutations
|
|||
required: false,
|
||||
description: 'The index of the record the import should started at, default 0 (50 records returned)'
|
||||
|
||||
def resolve(project_path:, start_at:)
|
||||
def resolve(project_path:, start_at: 0)
|
||||
project = authorized_find!(full_path: project_path)
|
||||
|
||||
service_response = ::JiraImport::UsersImporter.new(context[:current_user], project, start_at).execute
|
||||
service_response = ::JiraImport::UsersImporter.new(context[:current_user], project, start_at.to_i).execute
|
||||
|
||||
{
|
||||
jira_users: service_response.payload,
|
||||
|
|
|
@ -262,7 +262,7 @@ module ApplicationSettingsHelper
|
|||
:login_recaptcha_protection_enabled,
|
||||
:receive_max_input_size,
|
||||
:repository_checks_enabled,
|
||||
:repository_storages,
|
||||
:repository_storages_weighted,
|
||||
:require_two_factor_authentication,
|
||||
:restricted_visibility_levels,
|
||||
:rsa_key_restriction,
|
||||
|
|
|
@ -283,10 +283,6 @@ class ApplicationSetting < ApplicationRecord
|
|||
|
||||
validates :allowed_key_types, presence: true
|
||||
|
||||
repository_storages_weighted_attributes.each do |attribute|
|
||||
validates attribute, allow_nil: true, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 100 }
|
||||
end
|
||||
|
||||
validates_each :restricted_visibility_levels do |record, attr, value|
|
||||
value&.each do |level|
|
||||
unless Gitlab::VisibilityLevel.options.value?(level)
|
||||
|
|
|
@ -451,6 +451,13 @@ module ApplicationSettingImplementation
|
|||
invalid = repository_storages_weighted.keys - Gitlab.config.repositories.storages.keys
|
||||
errors.add(:repository_storages_weighted, "can't include: %{invalid_storages}" % { invalid_storages: invalid.join(", ") }) unless
|
||||
invalid.empty?
|
||||
|
||||
repository_storages_weighted.each do |key, val|
|
||||
next unless val.present?
|
||||
|
||||
errors.add(:"repository_storages_weighted_#{key}", "value must be an integer") unless val.is_a?(Integer)
|
||||
errors.add(:"repository_storages_weighted_#{key}", "value must be between 0 and 100") unless val.between?(0, 100)
|
||||
end
|
||||
end
|
||||
|
||||
def terms_exist
|
||||
|
|
|
@ -12,6 +12,10 @@ class UnconfirmWrongfullyVerifiedEmails < ActiveRecord::Migration[6.0]
|
|||
MIGRATION = 'WrongfullyConfirmedEmailUnconfirmer'
|
||||
EMAIL_INDEX_NAME = 'tmp_index_for_email_unconfirmation_migration'
|
||||
|
||||
class ApplicationSetting < ActiveRecord::Base
|
||||
self.table_name = 'application_settings'
|
||||
end
|
||||
|
||||
class Email < ActiveRecord::Base
|
||||
include EachBatch
|
||||
end
|
||||
|
@ -19,6 +23,11 @@ class UnconfirmWrongfullyVerifiedEmails < ActiveRecord::Migration[6.0]
|
|||
def up
|
||||
add_concurrent_index :emails, :id, where: 'confirmed_at IS NOT NULL', name: EMAIL_INDEX_NAME
|
||||
|
||||
ApplicationSetting.reset_column_information
|
||||
|
||||
setting_record = ApplicationSetting.last
|
||||
return unless setting_record&.send_user_confirmation_email
|
||||
|
||||
queue_background_migration_jobs_by_range_at_intervals(Email,
|
||||
MIGRATION,
|
||||
INTERVAL,
|
||||
|
|
|
@ -57,6 +57,13 @@ You need Developer [permissions](../../permissions.md) or higher to edit an iter
|
|||
|
||||
To edit an iteration, click the three-dot menu (**{ellipsis_v}**) > **Edit iteration**.
|
||||
|
||||
## Add an issue to an iteration
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216158) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.2.
|
||||
|
||||
To learn how to add an issue to an iteration, see the steps in
|
||||
[Managing issues](../../project/issues/managing_issues.md#add-an-issue-to-an-iteration-starter).
|
||||
|
||||
## Disable Iterations **(CORE ONLY)**
|
||||
|
||||
GitLab Iterations feature is deployed with a feature flag that is **enabled by default**.
|
||||
|
|
|
@ -272,9 +272,18 @@ of your installation.
|
|||
|
||||
## Deleting issues
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/2982) in GitLab 8.6
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/2982) in GitLab 8.6.
|
||||
|
||||
Users with [project owner permission](../../permissions.md) can delete an issue by
|
||||
editing it and clicking on the delete button.
|
||||
|
||||
![delete issue - button](img/delete_issue.png)
|
||||
|
||||
## Add an issue to an iteration **(STARTER)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216158) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.2.
|
||||
|
||||
To add an issue to an [iteration](../../group/iterations/index.md):
|
||||
|
||||
1. In an issue sidebar, click **Edit** next to **Iteration**. A dropdown appears.
|
||||
1. Click an iteration you'd like to associate this issue with.
|
||||
|
|
|
@ -114,8 +114,7 @@ module API
|
|||
requires :recaptcha_private_key, type: String, desc: 'Generate private key at http://www.google.com/recaptcha'
|
||||
end
|
||||
optional :repository_checks_enabled, type: Boolean, desc: "GitLab will periodically run 'git fsck' in all project and wiki repositories to look for silent disk corruption issues."
|
||||
optional :repository_storages, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Storage paths for new projects'
|
||||
optional :repository_storages_weighted, type: Hash, desc: 'Storage paths for new projects with a weighted value between 0 and 100'
|
||||
optional :repository_storages_weighted, type: Hash, coerce_with: Validations::Types::HashOfIntegerValues.coerce, desc: 'Storage paths for new projects with a weighted value ranging from 0 to 100'
|
||||
optional :require_two_factor_authentication, type: Boolean, desc: 'Require all users to set up Two-factor authentication'
|
||||
given require_two_factor_authentication: ->(val) { val } do
|
||||
requires :two_factor_grace_period, type: Integer, desc: 'Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication'
|
||||
|
|
20
lib/api/validations/types/hash_of_integer_values.rb
Normal file
20
lib/api/validations/types/hash_of_integer_values.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module API
|
||||
module Validations
|
||||
module Types
|
||||
class HashOfIntegerValues
|
||||
def self.coerce
|
||||
lambda do |value|
|
||||
case value
|
||||
when Hash
|
||||
value.transform_values(&:to_i)
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -17,6 +17,10 @@ module Gitlab
|
|||
when :deactivated
|
||||
"Your account has been deactivated by your administrator. "\
|
||||
"Please log back in from a web browser to reactivate your account at #{Gitlab.config.gitlab.url}"
|
||||
when :unconfirmed
|
||||
"Your primary email address is not confirmed. "\
|
||||
"Please check your inbox for the confirmation instructions. "\
|
||||
"In case the link is expired, you can request a new confirmation email at #{Rails.application.routes.url_helpers.new_user_confirmation_url}"
|
||||
else
|
||||
"Your account has been blocked."
|
||||
end
|
||||
|
@ -31,6 +35,8 @@ module Gitlab
|
|||
:terms_not_accepted
|
||||
elsif @user.deactivated?
|
||||
:deactivated
|
||||
elsif !@user.confirmed?
|
||||
:unconfirmed
|
||||
else
|
||||
:blocked
|
||||
end
|
||||
|
|
|
@ -30,6 +30,7 @@ module Gitlab
|
|||
.where('emails.confirmed_at IS NOT NULL')
|
||||
.where('emails.confirmed_at = users.confirmed_at')
|
||||
.where('emails.email <> users.email')
|
||||
.where('NOT EXISTS (SELECT 1 FROM user_synced_attributes_metadata WHERE user_id=users.id AND email_synced IS true)')
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -306,7 +306,6 @@ describe('JiraImportApp', () => {
|
|||
variables: {
|
||||
input: {
|
||||
projectPath: 'gitlab-org/gitlab-test',
|
||||
startAt: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -41,5 +41,13 @@ RSpec.describe Gitlab::Auth::UserAccessDeniedReason do
|
|||
|
||||
it { is_expected.to eq "Your account has been deactivated by your administrator. Please log back in from a web browser to reactivate your account at #{Gitlab.config.gitlab.url}" }
|
||||
end
|
||||
|
||||
context 'when the user is unconfirmed' do
|
||||
before do
|
||||
user.update!(confirmed_at: nil)
|
||||
end
|
||||
|
||||
it { is_expected.to match /Your primary email address is not confirmed/ }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,6 +5,7 @@ require 'spec_helper'
|
|||
RSpec.describe Gitlab::BackgroundMigration::WrongfullyConfirmedEmailUnconfirmer, schema: 20200615111857 do
|
||||
let(:users) { table(:users) }
|
||||
let(:emails) { table(:emails) }
|
||||
let(:user_synced_attributes_metadata) { table(:user_synced_attributes_metadata) }
|
||||
let(:confirmed_at_2_days_ago) { 2.days.ago }
|
||||
let(:confirmed_at_3_days_ago) { 3.days.ago }
|
||||
let(:one_year_ago) { 1.year.ago }
|
||||
|
@ -14,6 +15,8 @@ RSpec.describe Gitlab::BackgroundMigration::WrongfullyConfirmedEmailUnconfirmer,
|
|||
let!(:user_does_not_need_migration) { users.create!(name: 'user3', email: 'test3@test.com', state: 'active', projects_limit: 1) }
|
||||
let!(:inactive_user) { users.create!(name: 'user4', email: 'test4@test.com', state: 'blocked', projects_limit: 1, confirmed_at: confirmed_at_3_days_ago, confirmation_sent_at: one_year_ago) }
|
||||
let!(:alert_bot_user) { users.create!(name: 'user5', email: 'test5@test.com', state: 'active', user_type: 2, projects_limit: 1, confirmed_at: confirmed_at_3_days_ago, confirmation_sent_at: one_year_ago) }
|
||||
let!(:user_has_synced_email) { users.create!(name: 'user6', email: 'test6@test.com', state: 'active', projects_limit: 1, confirmed_at: confirmed_at_2_days_ago, confirmation_sent_at: one_year_ago) }
|
||||
let!(:synced_attributes_metadata_for_user) { user_synced_attributes_metadata.create!(user_id: user_has_synced_email.id, email_synced: true) }
|
||||
|
||||
let!(:bad_email_1) { emails.create!(user_id: user_needs_migration_1.id, email: 'other1@test.com', confirmed_at: confirmed_at_2_days_ago, confirmation_sent_at: one_year_ago) }
|
||||
let!(:bad_email_2) { emails.create!(user_id: user_needs_migration_2.id, email: 'other2@test.com', confirmed_at: confirmed_at_3_days_ago, confirmation_sent_at: one_year_ago) }
|
||||
|
@ -24,8 +27,10 @@ RSpec.describe Gitlab::BackgroundMigration::WrongfullyConfirmedEmailUnconfirmer,
|
|||
let!(:good_email_2) { emails.create!(user_id: user_needs_migration_2.id, email: 'other4@test.com', confirmed_at: nil) }
|
||||
let!(:good_email_3) { emails.create!(user_id: user_does_not_need_migration.id, email: 'other5@test.com', confirmed_at: confirmed_at_2_days_ago, confirmation_sent_at: one_year_ago) }
|
||||
|
||||
let!(:second_email_for_user_with_synced_email) { emails.create!(user_id: user_has_synced_email.id, email: 'other6@test.com', confirmed_at: confirmed_at_2_days_ago, confirmation_sent_at: one_year_ago) }
|
||||
|
||||
subject do
|
||||
email_ids = [bad_email_1, bad_email_2, good_email_1, good_email_2, good_email_3].map(&:id)
|
||||
email_ids = [bad_email_1, bad_email_2, good_email_1, good_email_2, good_email_3, second_email_for_user_with_synced_email].map(&:id)
|
||||
|
||||
described_class.new.perform(email_ids.min, email_ids.max)
|
||||
end
|
||||
|
@ -61,10 +66,12 @@ RSpec.describe Gitlab::BackgroundMigration::WrongfullyConfirmedEmailUnconfirmer,
|
|||
expect(user_does_not_need_migration.reload.confirmed_at).to be_nil
|
||||
expect(inactive_user.reload.confirmed_at).to be_within(1.second).of(confirmed_at_3_days_ago)
|
||||
expect(alert_bot_user.reload.confirmed_at).to be_within(1.second).of(confirmed_at_3_days_ago)
|
||||
expect(user_has_synced_email.reload.confirmed_at).to be_within(1.second).of(confirmed_at_2_days_ago)
|
||||
|
||||
expect(user_does_not_need_migration.reload.confirmation_sent_at).to be_nil
|
||||
expect(inactive_user.reload.confirmation_sent_at).to be_within(1.second).of(one_year_ago)
|
||||
expect(alert_bot_user.reload.confirmation_sent_at).to be_within(1.second).of(one_year_ago)
|
||||
expect(user_has_synced_email.confirmation_sent_at).to be_within(1.second).of(one_year_ago)
|
||||
end
|
||||
|
||||
it 'updates confirmation_sent_at column' do
|
||||
|
|
|
@ -9,6 +9,11 @@ RSpec.describe UnconfirmWrongfullyVerifiedEmails do
|
|||
table(:emails).create!(email: 'test2@test.com', user_id: user.id)
|
||||
end
|
||||
|
||||
context 'when email confirmation is enabled' do
|
||||
before do
|
||||
table(:application_settings).create!(send_user_confirmation_email: true)
|
||||
end
|
||||
|
||||
it 'enqueues WrongullyConfirmedEmailUnconfirmer job' do
|
||||
Sidekiq::Testing.fake! do
|
||||
migrate!
|
||||
|
@ -18,4 +23,33 @@ RSpec.describe UnconfirmWrongfullyVerifiedEmails do
|
|||
expect(jobs.first["args"].first).to eq(Gitlab::BackgroundMigration::WrongfullyConfirmedEmailUnconfirmer.name.demodulize)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when email confirmation is disabled' do
|
||||
before do
|
||||
table(:application_settings).create!(send_user_confirmation_email: false)
|
||||
end
|
||||
|
||||
it 'does not enqueue WrongullyConfirmedEmailUnconfirmer job' do
|
||||
Sidekiq::Testing.fake! do
|
||||
migrate!
|
||||
|
||||
expect(BackgroundMigrationWorker.jobs.size).to eq(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when email application setting record does not exist' do
|
||||
before do
|
||||
table(:application_settings).delete_all
|
||||
end
|
||||
|
||||
it 'does not enqueue WrongullyConfirmedEmailUnconfirmer job' do
|
||||
Sidekiq::Testing.fake! do
|
||||
migrate!
|
||||
|
||||
expect(BackgroundMigrationWorker.jobs.size).to eq(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -106,6 +106,7 @@ RSpec.describe ApplicationSetting do
|
|||
it { is_expected.not_to allow_value(false).for(:hashed_storage_enabled) }
|
||||
|
||||
it { is_expected.not_to allow_value(101).for(:repository_storages_weighted_default) }
|
||||
it { is_expected.to allow_value('90').for(:repository_storages_weighted_default) }
|
||||
it { is_expected.not_to allow_value(-1).for(:repository_storages_weighted_default) }
|
||||
it { is_expected.to allow_value(100).for(:repository_storages_weighted_default) }
|
||||
it { is_expected.to allow_value(0).for(:repository_storages_weighted_default) }
|
||||
|
|
|
@ -8,15 +8,17 @@ RSpec.describe 'Importing Jira Users' do
|
|||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project) }
|
||||
let(:importer) { instance_double(JiraImport::UsersImporter) }
|
||||
let(:project_path) { project.full_path }
|
||||
let(:start_at) { 7 }
|
||||
|
||||
let(:mutation) do
|
||||
variables = {
|
||||
let(:variables) do
|
||||
{
|
||||
start_at: start_at,
|
||||
project_path: project_path
|
||||
}
|
||||
end
|
||||
|
||||
let(:mutation) do
|
||||
graphql_mutation(:jira_import_users, variables)
|
||||
end
|
||||
|
||||
|
@ -65,9 +67,38 @@ RSpec.describe 'Importing Jira Users' do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when all params and permissions are ok' do
|
||||
let(:importer) { instance_double(JiraImport::UsersImporter) }
|
||||
context 'with start_at' do
|
||||
RSpec.shared_examples 'start users import at zero' do
|
||||
it 'returns imported users' do
|
||||
users = [{ jira_account_id: '12a', jira_display_name: 'user 1' }]
|
||||
result = ServiceResponse.success(payload: users)
|
||||
|
||||
expect(importer).to receive(:execute).and_return(result)
|
||||
expect(JiraImport::UsersImporter).to receive(:new).with(current_user, project, 0).and_return(importer)
|
||||
|
||||
post_graphql_mutation(mutation, current_user: current_user)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when nil' do
|
||||
let(:variables) do
|
||||
{
|
||||
start_at: nil,
|
||||
project_path: project_path
|
||||
}
|
||||
end
|
||||
|
||||
it_behaves_like 'start users import at zero'
|
||||
end
|
||||
|
||||
context 'when not provided' do
|
||||
let(:variables) { { project_path: project_path } }
|
||||
|
||||
it_behaves_like 'start users import at zero'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when all params and permissions are ok' do
|
||||
before do
|
||||
expect(JiraImport::UsersImporter).to receive(:new).with(current_user, project, 7)
|
||||
.and_return(importer)
|
||||
|
|
|
@ -15,7 +15,7 @@ RSpec.describe API::Settings, 'Settings' do
|
|||
expect(json_response).to be_an Hash
|
||||
expect(json_response['default_projects_limit']).to eq(42)
|
||||
expect(json_response['password_authentication_enabled_for_web']).to be_truthy
|
||||
expect(json_response['repository_storages']).to eq(['default'])
|
||||
expect(json_response['repository_storages_weighted']).to eq({ 'default' => 100 })
|
||||
expect(json_response['password_authentication_enabled']).to be_truthy
|
||||
expect(json_response['plantuml_enabled']).to be_falsey
|
||||
expect(json_response['plantuml_url']).to be_nil
|
||||
|
@ -55,6 +55,28 @@ RSpec.describe API::Settings, 'Settings' do
|
|||
stub_feature_flags(sourcegraph: true)
|
||||
end
|
||||
|
||||
it "coerces repository_storages_weighted to an int" do
|
||||
put api("/application/settings", admin),
|
||||
params: {
|
||||
repository_storages_weighted: { 'custom' => '75' }
|
||||
}
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['repository_storages_weighted']).to eq({ 'custom' => 75 })
|
||||
end
|
||||
|
||||
context "repository_storages_weighted value is outside a 0-100 range" do
|
||||
[-1, 101].each do |out_of_range_int|
|
||||
it "returns a :bad_request for #{out_of_range_int}" do
|
||||
put api("/application/settings", admin),
|
||||
params: {
|
||||
repository_storages_weighted: { 'custom' => out_of_range_int }
|
||||
}
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "updates application settings" do
|
||||
put api("/application/settings", admin),
|
||||
params: {
|
||||
|
@ -62,7 +84,7 @@ RSpec.describe API::Settings, 'Settings' do
|
|||
default_projects_limit: 3,
|
||||
default_project_creation: 2,
|
||||
password_authentication_enabled_for_web: false,
|
||||
repository_storages: 'custom',
|
||||
repository_storages_weighted: { 'custom' => 100 },
|
||||
plantuml_enabled: true,
|
||||
plantuml_url: 'http://plantuml.example.com',
|
||||
sourcegraph_enabled: true,
|
||||
|
@ -104,7 +126,7 @@ RSpec.describe API::Settings, 'Settings' do
|
|||
expect(json_response['default_projects_limit']).to eq(3)
|
||||
expect(json_response['default_project_creation']).to eq(::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS)
|
||||
expect(json_response['password_authentication_enabled_for_web']).to be_falsey
|
||||
expect(json_response['repository_storages']).to eq(['custom'])
|
||||
expect(json_response['repository_storages_weighted']).to eq({ 'custom' => 100 })
|
||||
expect(json_response['plantuml_enabled']).to be_truthy
|
||||
expect(json_response['plantuml_url']).to eq('http://plantuml.example.com')
|
||||
expect(json_response['sourcegraph_enabled']).to be_truthy
|
||||
|
|
Loading…
Reference in a new issue