Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
c4e79e91d7
commit
00114c0521
|
@ -109,7 +109,7 @@ export default {
|
|||
</template>
|
||||
<div class="gl-display-flex gl-justify-content-space-between gl-flex-wrap gl-mb-5">
|
||||
<gl-button
|
||||
variant="success"
|
||||
variant="confirm"
|
||||
:loading="isImportingAnyRepo"
|
||||
:disabled="!hasImportableRepos"
|
||||
type="button"
|
||||
|
|
|
@ -15,6 +15,7 @@ module Ci
|
|||
|
||||
validates :file, presence: true, file_size: { maximum: FILE_SIZE_LIMIT }
|
||||
validates :checksum, :file_store, :name, :permissions, :project_id, presence: true
|
||||
validates :name, uniqueness: { scope: :project }
|
||||
|
||||
after_initialize :generate_key_data
|
||||
before_validation :assign_checksum
|
||||
|
|
|
@ -34,7 +34,17 @@ class ContainerRepository < ApplicationRecord
|
|||
|
||||
enum status: { delete_scheduled: 0, delete_failed: 1 }
|
||||
enum expiration_policy_cleanup_status: { cleanup_unscheduled: 0, cleanup_scheduled: 1, cleanup_unfinished: 2, cleanup_ongoing: 3 }
|
||||
enum migration_skipped_reason: { not_in_plan: 0, too_many_retries: 1, too_many_tags: 2, root_namespace_in_deny_list: 3, migration_canceled: 4, not_found: 5, native_import: 6 }
|
||||
|
||||
enum migration_skipped_reason: {
|
||||
not_in_plan: 0,
|
||||
too_many_retries: 1,
|
||||
too_many_tags: 2,
|
||||
root_namespace_in_deny_list: 3,
|
||||
migration_canceled: 4,
|
||||
not_found: 5,
|
||||
native_import: 6,
|
||||
migration_forced_canceled: 7
|
||||
}
|
||||
|
||||
delegate :client, :gitlab_api_client, to: :registry
|
||||
|
||||
|
@ -504,6 +514,19 @@ class ContainerRepository < ApplicationRecord
|
|||
gitlab_api_client.cancel_repository_import(self.path)
|
||||
end
|
||||
|
||||
# This method is not meant for consumption by the code
|
||||
# It is meant for manual use in the case that a migration needs to be
|
||||
# cancelled by an admin or SRE
|
||||
def force_migration_cancel
|
||||
return :error unless gitlab_api_client.supports_gitlab_api?
|
||||
|
||||
response = gitlab_api_client.cancel_repository_import(self.path, force: true)
|
||||
|
||||
skip_import(reason: :migration_forced_canceled) if response[:status] == :ok
|
||||
|
||||
response
|
||||
end
|
||||
|
||||
def self.build_from_path(path)
|
||||
self.new(project: path.repository_project,
|
||||
name: path.repository_name)
|
||||
|
|
|
@ -103,7 +103,7 @@ Supported attributes:
|
|||
| Attribute | Type | Required | Description |
|
||||
|-----------------|----------------|------------------------|-------------|
|
||||
| `project_id` | integer/string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
|
||||
| `name` | string | **{check-circle}** Yes | The `name` of the file being uploaded. |
|
||||
| `name` | string | **{check-circle}** Yes | The `name` of the file being uploaded. The file name must be unique within the project. |
|
||||
| `file` | file | **{check-circle}** Yes | The `file` being uploaded (5 MB limit). |
|
||||
| `permissions` | string | **{dotted-circle}** No | The file is created with the specified permissions when created in the CI/CD job. Available types are: `read_only` (default), `read_write`, and `execute`. |
|
||||
|
||||
|
|
|
@ -58,10 +58,12 @@ module ContainerRegistry
|
|||
IMPORT_RESPONSES.fetch(response.status, :error)
|
||||
end
|
||||
|
||||
# https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs-gitlab/api.md#import-repository
|
||||
def cancel_repository_import(path)
|
||||
# https://gitlab.com/gitlab-org/container-registry/-/blob/master/docs-gitlab/api.md#cancel-repository-import
|
||||
def cancel_repository_import(path, force: false)
|
||||
response = with_import_token_faraday do |faraday_client|
|
||||
faraday_client.delete(import_url_for(path))
|
||||
faraday_client.delete(import_url_for(path)) do |req|
|
||||
req.params['force'] = true if force
|
||||
end
|
||||
end
|
||||
|
||||
status = IMPORT_RESPONSES.fetch(response.status, :error)
|
||||
|
|
|
@ -31,11 +31,11 @@ module QA
|
|||
private
|
||||
|
||||
def check_snowplow_enabled_checkbox
|
||||
check_element(:snowplow_enabled_checkbox)
|
||||
check_element(:snowplow_enabled_checkbox, true)
|
||||
end
|
||||
|
||||
def uncheck_snowplow_enabled_checkbox
|
||||
uncheck_element(:snowplow_enabled_checkbox)
|
||||
uncheck_element(:snowplow_enabled_checkbox, true)
|
||||
end
|
||||
|
||||
def click_save_changes_button
|
||||
|
|
|
@ -31,7 +31,7 @@ describe('ImportProjectsTable', () => {
|
|||
const findImportAllButton = () =>
|
||||
wrapper
|
||||
.findAll(GlButton)
|
||||
.filter((w) => w.props().variant === 'success')
|
||||
.filter((w) => w.props().variant === 'confirm')
|
||||
.at(0);
|
||||
const findImportAllModal = () => wrapper.find({ ref: 'importAllModal' });
|
||||
|
||||
|
|
|
@ -107,7 +107,9 @@ RSpec.describe ContainerRegistry::GitlabApiClient do
|
|||
end
|
||||
|
||||
describe '#cancel_repository_import' do
|
||||
subject { client.cancel_repository_import(path) }
|
||||
let(:force) { false }
|
||||
|
||||
subject { client.cancel_repository_import(path, force: force) }
|
||||
|
||||
where(:status_code, :expected_result) do
|
||||
200 | :already_imported
|
||||
|
@ -124,7 +126,7 @@ RSpec.describe ContainerRegistry::GitlabApiClient do
|
|||
|
||||
with_them do
|
||||
before do
|
||||
stub_import_cancel(path, status_code)
|
||||
stub_import_cancel(path, status_code, force: force)
|
||||
end
|
||||
|
||||
it { is_expected.to eq({ status: expected_result, migration_state: nil }) }
|
||||
|
@ -134,11 +136,21 @@ RSpec.describe ContainerRegistry::GitlabApiClient do
|
|||
let(:status) { 'this_is_a_test' }
|
||||
|
||||
before do
|
||||
stub_import_cancel(path, 400, status: status)
|
||||
stub_import_cancel(path, 400, status: status, force: force)
|
||||
end
|
||||
|
||||
it { is_expected.to eq({ status: :bad_request, migration_state: status }) }
|
||||
end
|
||||
|
||||
context 'force cancel' do
|
||||
let(:force) { true }
|
||||
|
||||
before do
|
||||
stub_import_cancel(path, 202, force: force)
|
||||
end
|
||||
|
||||
it { is_expected.to eq({ status: :ok, migration_state: nil }) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#import_status' do
|
||||
|
@ -330,15 +342,24 @@ RSpec.describe ContainerRegistry::GitlabApiClient do
|
|||
)
|
||||
end
|
||||
|
||||
def stub_import_cancel(path, http_status, status: nil)
|
||||
def stub_import_cancel(path, http_status, status: nil, force: false)
|
||||
body = {}
|
||||
|
||||
if http_status == 400
|
||||
body = { status: status }
|
||||
end
|
||||
|
||||
stub_request(:delete, "#{registry_api_url}/gitlab/v1/import/#{path}/")
|
||||
.with(headers: { 'Accept' => described_class::JSON_TYPE, 'Authorization' => "bearer #{import_token}" })
|
||||
headers = {
|
||||
'Accept' => described_class::JSON_TYPE,
|
||||
'Authorization' => "bearer #{import_token}",
|
||||
'User-Agent' => "GitLab/#{Gitlab::VERSION}",
|
||||
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3'
|
||||
}
|
||||
|
||||
params = force ? '?force=true' : ''
|
||||
|
||||
stub_request(:delete, "#{registry_api_url}/gitlab/v1/import/#{path}/#{params}")
|
||||
.with(headers: headers)
|
||||
.to_return(
|
||||
status: http_status,
|
||||
body: body.to_json,
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Ci::SecureFile do
|
||||
let(:sample_file) { fixture_file('ci_secure_files/upload-keystore.jks') }
|
||||
|
||||
subject { create(:ci_secure_file) }
|
||||
|
||||
before do
|
||||
stub_ci_secure_file_object_storage
|
||||
end
|
||||
|
||||
let(:sample_file) { fixture_file('ci_secure_files/upload-keystore.jks') }
|
||||
|
||||
subject { create(:ci_secure_file, file: CarrierWaveStringFile.new(sample_file)) }
|
||||
|
||||
it { is_expected.to be_a FileStoreMounter }
|
||||
|
||||
it { is_expected.to belong_to(:project).required }
|
||||
|
@ -27,6 +27,26 @@ RSpec.describe Ci::SecureFile do
|
|||
it { is_expected.to validate_presence_of(:name) }
|
||||
it { is_expected.to validate_presence_of(:permissions) }
|
||||
it { is_expected.to validate_presence_of(:project_id) }
|
||||
context 'unique filename' do
|
||||
let_it_be(:project1) { create(:project) }
|
||||
|
||||
it 'ensures the file name is unique within a given project' do
|
||||
file1 = create(:ci_secure_file, project: project1, name: 'file1')
|
||||
expect do
|
||||
create(:ci_secure_file, project: project1, name: 'file1')
|
||||
end.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Name has already been taken')
|
||||
|
||||
expect(project1.secure_files.where(name: 'file1').count).to be 1
|
||||
expect(project1.secure_files.find_by(name: 'file1').id).to eq(file1.id)
|
||||
end
|
||||
|
||||
it 'allows duplicate file names in different projects' do
|
||||
create(:ci_secure_file, project: project1)
|
||||
expect do
|
||||
create(:ci_secure_file, project: create(:project))
|
||||
end.not_to raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#permissions' do
|
||||
|
@ -37,8 +57,6 @@ RSpec.describe Ci::SecureFile do
|
|||
|
||||
describe '#checksum' do
|
||||
it 'computes SHA256 checksum on the file before encrypted' do
|
||||
subject.file = CarrierWaveStringFile.new(sample_file)
|
||||
subject.save!
|
||||
expect(subject.checksum).to eq(Digest::SHA256.hexdigest(sample_file))
|
||||
end
|
||||
end
|
||||
|
@ -51,8 +69,6 @@ RSpec.describe Ci::SecureFile do
|
|||
|
||||
describe '#file' do
|
||||
it 'returns the saved file' do
|
||||
subject.file = CarrierWaveStringFile.new(sample_file)
|
||||
subject.save!
|
||||
expect(Base64.encode64(subject.file.read)).to eq(Base64.encode64(sample_file))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -762,6 +762,61 @@ RSpec.describe ContainerRepository, :aggregate_failures do
|
|||
|
||||
it_behaves_like 'gitlab migration client request', :cancel_repository_import
|
||||
end
|
||||
|
||||
describe '#force_migration_cancel' do
|
||||
subject { repository.force_migration_cancel }
|
||||
|
||||
shared_examples 'returning the same response as the client' do
|
||||
it 'returns the same response' do
|
||||
expect(repository.gitlab_api_client)
|
||||
.to receive(:cancel_repository_import).with(repository.path, force: true).and_return(client_response)
|
||||
|
||||
expect(subject).to eq(client_response)
|
||||
end
|
||||
end
|
||||
|
||||
context 'successful cancellation' do
|
||||
let(:client_response) { { status: :ok } }
|
||||
|
||||
it_behaves_like 'returning the same response as the client'
|
||||
|
||||
it 'skips the migration' do
|
||||
expect(repository.gitlab_api_client)
|
||||
.to receive(:cancel_repository_import).with(repository.path, force: true).and_return(client_response)
|
||||
|
||||
expect { subject }.to change { repository.reload.migration_state }.to('import_skipped')
|
||||
.and change { repository.migration_skipped_reason }.to('migration_forced_canceled')
|
||||
.and change { repository.migration_skipped_at }
|
||||
end
|
||||
end
|
||||
|
||||
context 'failed cancellation' do
|
||||
let(:client_response) { { status: :error } }
|
||||
|
||||
it_behaves_like 'returning the same response as the client'
|
||||
|
||||
it 'does not skip the migration' do
|
||||
expect(repository.gitlab_api_client)
|
||||
.to receive(:cancel_repository_import).with(repository.path, force: true).and_return(client_response)
|
||||
|
||||
expect { subject }.to not_change { repository.reload.migration_state }
|
||||
.and not_change { repository.migration_skipped_reason }
|
||||
.and not_change { repository.migration_skipped_at }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the gitlab_api feature is not supported' do
|
||||
before do
|
||||
allow(repository.gitlab_api_client).to receive(:supports_gitlab_api?).and_return(false)
|
||||
end
|
||||
|
||||
it 'returns :error' do
|
||||
expect(repository.gitlab_api_client).not_to receive(:cancel_repository_import)
|
||||
|
||||
expect(subject).to eq(:error)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.build_from_path' do
|
||||
|
|
|
@ -293,6 +293,20 @@ RSpec.describe API::Ci::SecureFiles do
|
|||
expect(json_response['error']).to eq('name is missing')
|
||||
end
|
||||
|
||||
it 'returns an error when the file name has already been used' do
|
||||
post_params = {
|
||||
name: secure_file.name,
|
||||
file: fixture_file_upload('spec/fixtures/ci_secure_files/upload-keystore.jks')
|
||||
}
|
||||
|
||||
expect do
|
||||
post api("/projects/#{project.id}/secure_files", maintainer), params: post_params
|
||||
end.not_to change { project.secure_files.count }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:bad_request)
|
||||
expect(json_response['message']['name']).to include('has already been taken')
|
||||
end
|
||||
|
||||
it 'returns an error when an unexpected permission is supplied' do
|
||||
post_params = {
|
||||
file: fixture_file_upload('spec/fixtures/ci_secure_files/upload-keystore.jks'),
|
||||
|
|
Loading…
Reference in New Issue