Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
bb4e936684
commit
b28d414aef
14 changed files with 107 additions and 73 deletions
|
@ -1 +1 @@
|
||||||
eda57b4bf0dc87dee85745d48108523f34b8f8b5
|
b3bb31655c67e0fcad90de1c31de58686849a393
|
||||||
|
|
|
@ -39,6 +39,12 @@ class User < ApplicationRecord
|
||||||
MAX_USERNAME_LENGTH = 255
|
MAX_USERNAME_LENGTH = 255
|
||||||
MIN_USERNAME_LENGTH = 2
|
MIN_USERNAME_LENGTH = 2
|
||||||
|
|
||||||
|
SECONDARY_EMAIL_ATTRIBUTES = [
|
||||||
|
:commit_email,
|
||||||
|
:notification_email,
|
||||||
|
:public_email
|
||||||
|
].freeze
|
||||||
|
|
||||||
add_authentication_token_field :incoming_email_token, token_generator: -> { SecureRandom.hex.to_i(16).to_s(36) }
|
add_authentication_token_field :incoming_email_token, token_generator: -> { SecureRandom.hex.to_i(16).to_s(36) }
|
||||||
add_authentication_token_field :feed_token
|
add_authentication_token_field :feed_token
|
||||||
add_authentication_token_field :static_object_token
|
add_authentication_token_field :static_object_token
|
||||||
|
@ -1310,11 +1316,15 @@ class User < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_secondary_emails!
|
def unset_secondary_emails_matching_deleted_email!(deleted_email)
|
||||||
set_notification_email
|
secondary_email_attribute_changed = false
|
||||||
set_public_email
|
SECONDARY_EMAIL_ATTRIBUTES.each do |attribute|
|
||||||
set_commit_email
|
if read_attribute(attribute) == deleted_email
|
||||||
save if notification_email_changed? || public_email_changed? || commit_email_changed?
|
self.write_attribute(attribute, nil)
|
||||||
|
secondary_email_attribute_changed = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
save if secondary_email_attribute_changed
|
||||||
end
|
end
|
||||||
|
|
||||||
def admin_unsubscribe!
|
def admin_unsubscribe!
|
||||||
|
|
|
@ -45,7 +45,12 @@ module Auth
|
||||||
token.expire_time = token_expire_at
|
token.expire_time = token_expire_at
|
||||||
|
|
||||||
token[:access] = names.map do |name|
|
token[:access] = names.map do |name|
|
||||||
{ type: 'repository', name: name, actions: actions }
|
{
|
||||||
|
type: 'repository',
|
||||||
|
name: name,
|
||||||
|
actions: actions,
|
||||||
|
migration_eligible: migration_eligible(repository_path: name)
|
||||||
|
}.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
token.encoded
|
token.encoded
|
||||||
|
@ -119,13 +124,20 @@ module Auth
|
||||||
type: type,
|
type: type,
|
||||||
name: path.to_s,
|
name: path.to_s,
|
||||||
actions: authorized_actions,
|
actions: authorized_actions,
|
||||||
migration_eligible: migration_eligible(requested_project, authorized_actions)
|
migration_eligible: self.class.migration_eligible(project: requested_project)
|
||||||
}.compact
|
}.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
def migration_eligible(project, actions)
|
def self.migration_eligible(project: nil, repository_path: nil)
|
||||||
return unless Feature.enabled?(:container_registry_migration_phase1)
|
return unless Feature.enabled?(:container_registry_migration_phase1)
|
||||||
|
|
||||||
|
# project has precedence over repository_path. If only the latter is provided, we find the corresponding Project.
|
||||||
|
unless project
|
||||||
|
return unless repository_path
|
||||||
|
|
||||||
|
project = ContainerRegistry::Path.new(repository_path).repository_project
|
||||||
|
end
|
||||||
|
|
||||||
# The migration process will start by allowing only specific test and gitlab-org projects using the
|
# The migration process will start by allowing only specific test and gitlab-org projects using the
|
||||||
# `container_registry_migration_phase1_allow` FF. We'll then move on to a percentage rollout using this same FF.
|
# `container_registry_migration_phase1_allow` FF. We'll then move on to a percentage rollout using this same FF.
|
||||||
# To remove the risk of impacting enterprise customers that rely heavily on the registry during the percentage
|
# To remove the risk of impacting enterprise customers that rely heavily on the registry during the percentage
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
module Emails
|
module Emails
|
||||||
class DestroyService < ::Emails::BaseService
|
class DestroyService < ::Emails::BaseService
|
||||||
def execute(email)
|
def execute(email)
|
||||||
email.destroy && update_secondary_emails!
|
email.destroy && update_secondary_emails!(email.email)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def update_secondary_emails!
|
def update_secondary_emails!(deleted_email)
|
||||||
result = ::Users::UpdateService.new(@current_user, user: @user).execute do |user|
|
result = ::Users::UpdateService.new(@current_user, user: @user).execute do |user|
|
||||||
user.update_secondary_emails!
|
user.unset_secondary_emails_matching_deleted_email!(deleted_email)
|
||||||
end
|
end
|
||||||
|
|
||||||
result[:status] == :success
|
result[:status] == :success
|
||||||
|
|
|
@ -10199,6 +10199,7 @@ Describes an incident management on-call schedule.
|
||||||
| <a id="incidentmanagementoncallscheduledescription"></a>`description` | [`String`](#string) | Description of the on-call schedule. |
|
| <a id="incidentmanagementoncallscheduledescription"></a>`description` | [`String`](#string) | Description of the on-call schedule. |
|
||||||
| <a id="incidentmanagementoncallscheduleiid"></a>`iid` | [`ID!`](#id) | Internal ID of the on-call schedule. |
|
| <a id="incidentmanagementoncallscheduleiid"></a>`iid` | [`ID!`](#id) | Internal ID of the on-call schedule. |
|
||||||
| <a id="incidentmanagementoncallschedulename"></a>`name` | [`String!`](#string) | Name of the on-call schedule. |
|
| <a id="incidentmanagementoncallschedulename"></a>`name` | [`String!`](#string) | Name of the on-call schedule. |
|
||||||
|
| <a id="incidentmanagementoncallscheduleoncallusers"></a>`oncallUsers` | [`[UserCore!]`](#usercore) | |
|
||||||
| <a id="incidentmanagementoncallschedulerotations"></a>`rotations` | [`IncidentManagementOncallRotationConnection!`](#incidentmanagementoncallrotationconnection) | On-call rotations for the on-call schedule. (see [Connections](#connections)) |
|
| <a id="incidentmanagementoncallschedulerotations"></a>`rotations` | [`IncidentManagementOncallRotationConnection!`](#incidentmanagementoncallrotationconnection) | On-call rotations for the on-call schedule. (see [Connections](#connections)) |
|
||||||
| <a id="incidentmanagementoncallscheduletimezone"></a>`timezone` | [`String!`](#string) | Time zone of the on-call schedule. |
|
| <a id="incidentmanagementoncallscheduletimezone"></a>`timezone` | [`String!`](#string) | Time zone of the on-call schedule. |
|
||||||
|
|
||||||
|
|
|
@ -361,14 +361,9 @@ you visualize the entire pipeline, including all cross-project inter-dependencie
|
||||||
### View job dependencies in the pipeline graph
|
### View job dependencies in the pipeline graph
|
||||||
|
|
||||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/298973) in GitLab 13.12.
|
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/298973) in GitLab 13.12.
|
||||||
> - [Deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
|
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/328538) in GitLab 14.0.
|
||||||
> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/328538) in GitLab 13.12.
|
|
||||||
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/328538) in GitLab 14.2.
|
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/328538) in GitLab 14.2.
|
||||||
|
|
||||||
This in-development feature might not be available for your use. There can be
|
|
||||||
[risks when enabling features still in development](../../administration/feature_flags.md#risks-when-enabling-features-still-in-development).
|
|
||||||
Refer to this feature's version history for more details.
|
|
||||||
|
|
||||||
You can arrange jobs in the pipeline graph based on their [`needs`](../yaml/index.md#needs)
|
You can arrange jobs in the pipeline graph based on their [`needs`](../yaml/index.md#needs)
|
||||||
dependencies.
|
dependencies.
|
||||||
|
|
||||||
|
|
|
@ -491,13 +491,6 @@ module Gitlab
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns a RefName for a given SHA
|
|
||||||
def ref_name_for_sha(ref_path, sha)
|
|
||||||
raise ArgumentError, "sha can't be empty" unless sha.present?
|
|
||||||
|
|
||||||
gitaly_ref_client.find_ref_name(sha, ref_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get refs hash which key is the commit id
|
# Get refs hash which key is the commit id
|
||||||
# and value is a Gitlab::Git::Tag or Gitlab::Git::Branch
|
# and value is a Gitlab::Git::Tag or Gitlab::Git::Branch
|
||||||
# Note that both inherit from Gitlab::Git::Ref
|
# Note that both inherit from Gitlab::Git::Ref
|
||||||
|
|
|
@ -52,16 +52,6 @@ module Gitlab
|
||||||
consume_refs_response(response) { |name| Gitlab::Git.tag_name(name) }
|
consume_refs_response(response) { |name| Gitlab::Git.tag_name(name) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_ref_name(commit_id, ref_prefix)
|
|
||||||
request = Gitaly::FindRefNameRequest.new(
|
|
||||||
repository: @gitaly_repo,
|
|
||||||
commit_id: commit_id,
|
|
||||||
prefix: ref_prefix
|
|
||||||
)
|
|
||||||
response = GitalyClient.call(@storage, :ref_service, :find_ref_name, request, timeout: GitalyClient.medium_timeout)
|
|
||||||
encode!(response.name.dup)
|
|
||||||
end
|
|
||||||
|
|
||||||
def list_new_blobs(newrev, limit = 0, dynamic_timeout: nil)
|
def list_new_blobs(newrev, limit = 0, dynamic_timeout: nil)
|
||||||
request = Gitaly::ListNewBlobsRequest.new(
|
request = Gitaly::ListNewBlobsRequest.new(
|
||||||
repository: @gitaly_repo,
|
repository: @gitaly_repo,
|
||||||
|
|
|
@ -117,6 +117,10 @@ module QA
|
||||||
'/users'
|
'/users'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def api_put_path
|
||||||
|
"/users/#{id}"
|
||||||
|
end
|
||||||
|
|
||||||
def api_block_path
|
def api_block_path
|
||||||
"/users/#{id}/block"
|
"/users/#{id}/block"
|
||||||
end
|
end
|
||||||
|
@ -153,6 +157,16 @@ module QA
|
||||||
raise ResourceUpdateFailedError, "Failed to block user. Request returned (#{response.code}): `#{response}`."
|
raise ResourceUpdateFailedError, "Failed to block user. Request returned (#{response.code}): `#{response}`."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_public_email
|
||||||
|
response = put(Runtime::API::Request.new(api_client, api_put_path).url, { public_email: email })
|
||||||
|
return if response.code == HTTP_STATUS_OK
|
||||||
|
|
||||||
|
raise(
|
||||||
|
ResourceUpdateFailedError,
|
||||||
|
"Failed to set public email. Request returned (#{response.code}): `#{response}`."
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def ldap_post_body
|
def ldap_post_body
|
||||||
|
|
|
@ -1132,28 +1132,6 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#ref_name_for_sha' do
|
|
||||||
let(:ref_path) { 'refs/heads' }
|
|
||||||
let(:sha) { repository.find_branch('master').dereferenced_target.id }
|
|
||||||
let(:ref_name) { 'refs/heads/master' }
|
|
||||||
|
|
||||||
it 'returns the ref name for the given sha' do
|
|
||||||
expect(repository.ref_name_for_sha(ref_path, sha)).to eq(ref_name)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "returns an empty name if the ref doesn't exist" do
|
|
||||||
expect(repository.ref_name_for_sha(ref_path, "000000")).to eq("")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "raise an exception if the ref is empty" do
|
|
||||||
expect { repository.ref_name_for_sha(ref_path, "") }.to raise_error(ArgumentError)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "raise an exception if the ref is nil" do
|
|
||||||
expect { repository.ref_name_for_sha(ref_path, nil) }.to raise_error(ArgumentError)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#branches' do
|
describe '#branches' do
|
||||||
subject { repository.branches }
|
subject { repository.branches }
|
||||||
|
|
||||||
|
|
|
@ -189,13 +189,6 @@ RSpec.describe Gitlab::GitalyClient::RefService do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#find_ref_name', :seed_helper do
|
|
||||||
subject { client.find_ref_name(SeedRepo::Commit::ID, 'refs/heads/master') }
|
|
||||||
|
|
||||||
it { is_expected.to be_utf8 }
|
|
||||||
it { is_expected.to eq('refs/heads/master') }
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#ref_exists?', :seed_helper do
|
describe '#ref_exists?', :seed_helper do
|
||||||
it 'finds the master branch ref' do
|
it 'finds the master branch ref' do
|
||||||
expect(client.ref_exists?('refs/heads/master')).to eq(true)
|
expect(client.ref_exists?('refs/heads/master')).to eq(true)
|
||||||
|
|
|
@ -142,15 +142,6 @@ RSpec.describe Repository do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#ref_name_for_sha' do
|
|
||||||
it 'returns the ref' do
|
|
||||||
allow(repository.raw_repository).to receive(:ref_name_for_sha)
|
|
||||||
.and_return('refs/environments/production/77')
|
|
||||||
|
|
||||||
expect(repository.ref_name_for_sha('bla', '0' * 40)).to eq 'refs/environments/production/77'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#ref_exists?' do
|
describe '#ref_exists?' do
|
||||||
context 'when ref exists' do
|
context 'when ref exists' do
|
||||||
it 'returns true' do
|
it 'returns true' do
|
||||||
|
|
|
@ -6024,4 +6024,30 @@ RSpec.describe User do
|
||||||
expect(described_class.by_provider_and_extern_uid(:github, 'my_github_id')).to match_array([expected_user])
|
expect(described_class.by_provider_and_extern_uid(:github, 'my_github_id')).to match_array([expected_user])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#unset_secondary_emails_matching_deleted_email!' do
|
||||||
|
let(:deleted_email) { 'kermit@muppets.com' }
|
||||||
|
|
||||||
|
subject { build(:user, commit_email: commit_email) }
|
||||||
|
|
||||||
|
context 'when no secondary email matches the deleted email' do
|
||||||
|
let(:commit_email) { 'fozzie@muppets.com' }
|
||||||
|
|
||||||
|
it 'does nothing' do
|
||||||
|
expect(subject).not_to receive(:save)
|
||||||
|
subject.unset_secondary_emails_matching_deleted_email!(deleted_email)
|
||||||
|
expect(subject.read_attribute(:commit_email)).to eq commit_email
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a secondary email matches the deleted_email' do
|
||||||
|
let(:commit_email) { deleted_email }
|
||||||
|
|
||||||
|
it 'un-sets the secondary email' do
|
||||||
|
expect(subject).to receive(:save)
|
||||||
|
subject.unset_secondary_emails_matching_deleted_email!(deleted_email)
|
||||||
|
expect(subject.read_attribute(:commit_email)).to be nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -84,5 +84,36 @@ RSpec.describe Auth::ContainerRegistryAuthenticationService do
|
||||||
|
|
||||||
it_behaves_like 'a modified token'
|
it_behaves_like 'a modified token'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#access_token' do
|
||||||
|
let(:token) { described_class.access_token(%w[push], [project.full_path]) }
|
||||||
|
|
||||||
|
subject { { token: token } }
|
||||||
|
|
||||||
|
it_behaves_like 'a modified token'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when not in migration mode' do
|
||||||
|
include_context 'container registry auth service context'
|
||||||
|
|
||||||
|
let_it_be(:project) { create(:project) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_feature_flags(container_registry_migration_phase1: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples 'an unmodified token' do
|
||||||
|
it_behaves_like 'a valid token'
|
||||||
|
it { expect(payload['access']).not_to include(have_key('migration_eligible')) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#access_token' do
|
||||||
|
let(:token) { described_class.access_token(%w[push], [project.full_path]) }
|
||||||
|
|
||||||
|
subject { { token: token } }
|
||||||
|
|
||||||
|
it_behaves_like 'an unmodified token'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue