diff --git a/app/assets/stylesheets/pages/container_registry.scss b/app/assets/stylesheets/pages/container_registry.scss index 7d68eae3c97..92543d7d714 100644 --- a/app/assets/stylesheets/pages/container_registry.scss +++ b/app/assets/stylesheets/pages/container_registry.scss @@ -3,14 +3,14 @@ */ .container-image { - border-bottom: 1px solid #f0f0f0; + border-bottom: 1px solid $white-normal; } .container-image-head { - padding: 0px 16px; + padding: 0 16px; line-height: 4; } .table.tags { - margin-bottom: 0px; + margin-bottom: 0; } diff --git a/app/controllers/projects/container_registry_controller.rb b/app/controllers/projects/container_registry_controller.rb index 54bcb5f504a..f656f86fcdb 100644 --- a/app/controllers/projects/container_registry_controller.rb +++ b/app/controllers/projects/container_registry_controller.rb @@ -20,7 +20,6 @@ class Projects::ContainerRegistryController < Projects::ApplicationController redirect_to url, alert: 'Failed to remove image' end end - end private diff --git a/app/models/container_image.rb b/app/models/container_image.rb index 7721c53a6fc..583cb977910 100644 --- a/app/models/container_image.rb +++ b/app/models/container_image.rb @@ -22,7 +22,7 @@ class ContainerImage < ActiveRecord::Base end def name_with_namespace - [container_registry_path_with_namespace, name].compact.join('/') + [container_registry_path_with_namespace, name].reject(&:blank?).join('/') end def tag(tag) @@ -55,6 +55,8 @@ class ContainerImage < ActiveRecord::Base end end + # rubocop:disable RedundantReturn + def self.split_namespace(full_path) image_name = full_path.split('/').last namespace = full_path.gsub(/(.*)(#{Regexp.escape('/' + image_name)})/, '\1') diff --git a/app/models/namespace.rb b/app/models/namespace.rb index bd0336c984a..c8e329044e0 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -118,8 +118,8 @@ class Namespace < ActiveRecord::Base end def move_dir - if any_project_has_container_registry_tags? - raise Gitlab::UpdatePathError.new('Namespace cannot be moved, because at least one project has tags in container registry') + if any_project_has_container_registry_images? + raise Gitlab::UpdatePathError.new('Namespace cannot be moved, because at least one project has images in container registry') end # Move the namespace directory in all storages paths used by member projects @@ -154,8 +154,8 @@ class Namespace < ActiveRecord::Base end end - def any_project_has_container_registry_tags? - projects.any?(&:has_container_registry_tags?) + def any_project_has_container_registry_images? + projects.any? { |project| project.container_images.present? } end def send_update_instructions diff --git a/app/models/project.rb b/app/models/project.rb index afaf2095a4c..d4f5584f53d 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -421,18 +421,12 @@ class Project < ActiveRecord::Base end end - def container_registry_repository_url + def container_registry_url if Gitlab.config.registry.enabled "#{Gitlab.config.registry.host_port}/#{container_registry_path_with_namespace}" end end - def has_container_registry_tags? - return unless container_images - - container_images.first.tags.any? - end - def commit(ref = 'HEAD') repository.commit(ref) end @@ -913,11 +907,11 @@ class Project < ActiveRecord::Base expire_caches_before_rename(old_path_with_namespace) - if has_container_registry_tags? - Rails.logger.error "Project #{old_path_with_namespace} cannot be renamed because container registry tags are present" + if container_images.present? + Rails.logger.error "Project #{old_path_with_namespace} cannot be renamed because container registry images are present" - # we currently doesn't support renaming repository if it contains tags in container registry - raise StandardError.new('Project cannot be renamed, because tags are present in its container registry') + # we currently doesn't support renaming repository if it contains images in container registry + raise StandardError.new('Project cannot be renamed, because images are present in its container registry') end if gitlab_shell.mv_repository(repository_storage_path, old_path_with_namespace, new_path_with_namespace) @@ -1264,7 +1258,7 @@ class Project < ActiveRecord::Base ] if container_registry_enabled? - variables << { key: 'CI_REGISTRY_IMAGE', value: container_registry_repository_url, public: true } + variables << { key: 'CI_REGISTRY_IMAGE', value: container_registry_url, public: true } end variables diff --git a/app/services/auth/container_registry_authentication_service.rb b/app/services/auth/container_registry_authentication_service.rb index 6b83b38fa4d..5b2fcdf3b16 100644 --- a/app/services/auth/container_registry_authentication_service.rb +++ b/app/services/auth/container_registry_authentication_service.rb @@ -16,7 +16,8 @@ module Auth { token: authorized_token(scope).encoded } end - def self.full_access_token(names) + def self.full_access_token(*names) + names = names.flatten registry = Gitlab.config.registry token = JSONWebToken::RSAToken.new(registry.key) token.issuer = registry.issuer diff --git a/app/services/container_images/destroy_service.rb b/app/services/container_images/destroy_service.rb index bc5b53fd055..c73b6cfefba 100644 --- a/app/services/container_images/destroy_service.rb +++ b/app/services/container_images/destroy_service.rb @@ -1,6 +1,5 @@ module ContainerImages class DestroyService < BaseService - class DestroyError < StandardError; end def execute(container_image) diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index 20dfbddc823..3e241b9e7c0 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -36,9 +36,9 @@ module Projects raise TransferError.new("Project with same path in target namespace already exists") end - if project.has_container_registry_tags? - # we currently doesn't support renaming repository if it contains tags in container registry - raise TransferError.new('Project cannot be transferred, because tags are present in its container registry') + unless project.container_images.empty? + # we currently doesn't support renaming repository if it contains images in container registry + raise TransferError.new('Project cannot be transferred, because images are present in its container registry') end project.expire_caches_before_rename(old_path) diff --git a/app/views/projects/container_registry/_image.html.haml b/app/views/projects/container_registry/_image.html.haml index b1d62e34a97..5845efd345a 100644 --- a/app/views/projects/container_registry/_image.html.haml +++ b/app/views/projects/container_registry/_image.html.haml @@ -10,7 +10,7 @@ = escape_once(image.name) = clipboard_button(clipboard_text: "docker pull #{image.path}") .controls.hidden-xs.pull-right - = link_to namespace_project_container_registry_path(@project.namespace, @project, image.id), class: 'btn btn-remove has-tooltip', title: "Remove", data: { confirm: "Are you sure?" }, method: :delete do + = link_to namespace_project_container_registry_path(@project.namespace, @project, image.id), class: 'btn btn-remove has-tooltip', title: "Remove image", data: { confirm: "Are you sure?" }, method: :delete do = icon("trash cred") diff --git a/app/views/projects/container_registry/_tag.html.haml b/app/views/projects/container_registry/_tag.html.haml index 00345ec26de..b35a9cb621f 100644 --- a/app/views/projects/container_registry/_tag.html.haml +++ b/app/views/projects/container_registry/_tag.html.haml @@ -25,5 +25,5 @@ - if can?(current_user, :update_container_image, @project) %td.content .controls.hidden-xs.pull-right - = link_to namespace_project_container_registry_path(@project.namespace, @project, { id: tag.repository.id, tag: tag.name} ), class: 'btn btn-remove has-tooltip', title: "Remove", data: { confirm: "Are you sure?" }, method: :delete do + = link_to namespace_project_container_registry_path(@project.namespace, @project, { id: tag.repository.id, tag: tag.name} ), class: 'btn btn-remove has-tooltip', title: "Remove tag", data: { confirm: "Are you sure?" }, method: :delete do = icon("trash cred") diff --git a/app/views/projects/container_registry/index.html.haml b/app/views/projects/container_registry/index.html.haml index f074ce6be6d..ab6213f03d8 100644 --- a/app/views/projects/container_registry/index.html.haml +++ b/app/views/projects/container_registry/index.html.haml @@ -15,9 +15,9 @@ %br Then you are free to create and upload a container image with build and push commands: %pre - docker build -t #{escape_once(@project.container_registry_repository_url)} . + docker build -t #{escape_once(@project.container_registry_url)} . %br - docker push #{escape_once(@project.container_registry_repository_url)} + docker push #{escape_once(@project.container_registry_url)} - if @images.blank? .nothing-here-block No container images in Container Registry for this project. diff --git a/db/schema.rb b/db/schema.rb index 88aaa6c3c55..36df20fc8f2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -109,6 +109,7 @@ ActiveRecord::Schema.define(version: 20170215200045) do t.boolean "html_emails_enabled", default: true t.string "plantuml_url" t.boolean "plantuml_enabled" + t.string "container_registry_access_token" t.integer "max_pages_size", default: 100, null: false t.integer "terminal_max_session_time", default: 0, null: false end @@ -392,6 +393,11 @@ ActiveRecord::Schema.define(version: 20170215200045) do add_index "ci_variables", ["gl_project_id"], name: "index_ci_variables_on_gl_project_id", using: :btree + create_table "container_images", force: :cascade do |t| + t.integer "project_id" + t.string "name" + end + create_table "deploy_keys_projects", force: :cascade do |t| t.integer "deploy_key_id", null: false t.integer "project_id", null: false diff --git a/lib/api/registry_events.rb b/lib/api/registry_events.rb index e52433339eb..12305a49f0f 100644 --- a/lib/api/registry_events.rb +++ b/lib/api/registry_events.rb @@ -46,9 +46,7 @@ module API if project container_image = project.container_images.find_or_create_by(name: container_image_name) - if container_image.valid? - puts('Valid!') - else + unless container_image.valid? render_api_error!({ error: "Failed to create container image!" }, 400) end else diff --git a/lib/container_registry/blob.rb b/lib/container_registry/blob.rb index eb5a2596177..8db8e483b1d 100644 --- a/lib/container_registry/blob.rb +++ b/lib/container_registry/blob.rb @@ -38,11 +38,11 @@ module ContainerRegistry end def delete - client.delete_blob(repository.name, digest) + client.delete_blob(repository.name_with_namespace, digest) end def data - @data ||= client.blob(repository.name, digest, type) + @data ||= client.blob(repository.name_with_namespace, digest, type) end end end diff --git a/lib/container_registry/registry.rb b/lib/container_registry/registry.rb index 0e634f6b6ef..63bce655f57 100644 --- a/lib/container_registry/registry.rb +++ b/lib/container_registry/registry.rb @@ -8,10 +8,6 @@ module ContainerRegistry @client = ContainerRegistry::Client.new(uri, options) end - def repository(name) - ContainerRegistry::Repository.new(self, name) - end - private def default_path diff --git a/lib/container_registry/repository.rb b/lib/container_registry/repository.rb deleted file mode 100644 index 0e4a7cb3cc9..00000000000 --- a/lib/container_registry/repository.rb +++ /dev/null @@ -1,48 +0,0 @@ -module ContainerRegistry - class Repository - attr_reader :registry, :name - - delegate :client, to: :registry - - def initialize(registry, name) - @registry, @name = registry, name - end - - def path - [registry.path, name].compact.join('/') - end - - def tag(tag) - ContainerRegistry::Tag.new(self, tag) - end - - def manifest - return @manifest if defined?(@manifest) - - @manifest = client.repository_tags(name) - end - - def valid? - manifest.present? - end - - def tags - return @tags if defined?(@tags) - return [] unless manifest && manifest['tags'] - - @tags = manifest['tags'].map do |tag| - ContainerRegistry::Tag.new(self, tag) - end - end - - def blob(config) - ContainerRegistry::Blob.new(self, config) - end - - def delete_tags - return unless tags - - tags.all?(&:delete) - end - end -end diff --git a/spec/factories/container_images.rb b/spec/factories/container_images.rb new file mode 100644 index 00000000000..6141a519a75 --- /dev/null +++ b/spec/factories/container_images.rb @@ -0,0 +1,21 @@ +FactoryGirl.define do + factory :container_image do + name "test_container_image" + project + + transient do + tags ['tag'] + stubbed true + end + + after(:build) do |image, evaluator| + if evaluator.stubbed + allow(Gitlab.config.registry).to receive(:enabled).and_return(true) + allow(image.client).to receive(:repository_tags).and_return({ + name: image.name_with_namespace, + tags: evaluator.tags + }) + end + end + end +end diff --git a/spec/features/container_registry_spec.rb b/spec/features/container_registry_spec.rb index 203e55a36f2..862c9fbf6c0 100644 --- a/spec/features/container_registry_spec.rb +++ b/spec/features/container_registry_spec.rb @@ -2,15 +2,18 @@ require 'spec_helper' describe "Container Registry" do let(:project) { create(:empty_project) } - let(:repository) { project.container_registry_repository } + let(:registry) { project.container_registry } let(:tag_name) { 'latest' } let(:tags) { [tag_name] } + let(:container_image) { create(:container_image) } + let(:image_name) { container_image.name } before do login_as(:user) project.team << [@user, :developer] - stub_container_registry_tags(*tags) stub_container_registry_config(enabled: true) + stub_container_registry_tags(*tags) + project.container_images << container_image unless container_image.nil? allow(Auth::ContainerRegistryAuthenticationService).to receive(:full_access_token).and_return('token') end @@ -19,15 +22,26 @@ describe "Container Registry" do visit namespace_project_container_registry_index_path(project.namespace, project) end - context 'when no tags' do - let(:tags) { [] } + context 'when no images' do + let(:container_image) { } - it { expect(page).to have_content('No images in Container Registry for this project') } + it { expect(page).to have_content('No container images in Container Registry for this project') } end - context 'when there are tags' do - it { expect(page).to have_content(tag_name) } - it { expect(page).to have_content('d7a513a66') } + context 'when there are images' do + it { expect(page).to have_content(image_name) } + end + end + + describe 'DELETE /:project/container_registry/:image_id' do + before do + visit namespace_project_container_registry_index_path(project.namespace, project) + end + + it do + expect_any_instance_of(ContainerImage).to receive(:delete_tags).and_return(true) + + click_on 'Remove image' end end @@ -39,7 +53,7 @@ describe "Container Registry" do it do expect_any_instance_of(::ContainerRegistry::Tag).to receive(:delete).and_return(true) - click_on 'Remove' + click_on 'Remove tag' end end end diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb index 24af062d763..4e7a2c0ecc0 100644 --- a/spec/features/security/project/internal_access_spec.rb +++ b/spec/features/security/project/internal_access_spec.rb @@ -429,9 +429,12 @@ describe "Internal Project Access", feature: true do end describe "GET /:project_path/container_registry" do + let(:container_image) { create(:container_image) } + before do stub_container_registry_tags('latest') stub_container_registry_config(enabled: true) + project.container_images << container_image end subject { namespace_project_container_registry_index_path(project.namespace, project) } diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb index c511dcfa18e..c74cdc05593 100644 --- a/spec/features/security/project/private_access_spec.rb +++ b/spec/features/security/project/private_access_spec.rb @@ -418,9 +418,12 @@ describe "Private Project Access", feature: true do end describe "GET /:project_path/container_registry" do + let(:container_image) { create(:container_image) } + before do stub_container_registry_tags('latest') stub_container_registry_config(enabled: true) + project.container_images << container_image end subject { namespace_project_container_registry_index_path(project.namespace, project) } diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb index d8cc012c27e..485ef335b78 100644 --- a/spec/features/security/project/public_access_spec.rb +++ b/spec/features/security/project/public_access_spec.rb @@ -429,9 +429,12 @@ describe "Public Project Access", feature: true do end describe "GET /:project_path/container_registry" do + let(:container_image) { create(:container_image) } + before do stub_container_registry_tags('latest') stub_container_registry_config(enabled: true) + project.container_images << container_image end subject { namespace_project_container_registry_index_path(project.namespace, project) } diff --git a/spec/lib/container_registry/blob_spec.rb b/spec/lib/container_registry/blob_spec.rb index bbacdc67ebd..f092449c4bd 100644 --- a/spec/lib/container_registry/blob_spec.rb +++ b/spec/lib/container_registry/blob_spec.rb @@ -9,12 +9,19 @@ describe ContainerRegistry::Blob do 'size' => 1000 } end - let(:token) { 'authorization-token' } - - let(:registry) { ContainerRegistry::Registry.new('http://example.com', token: token) } - let(:repository) { registry.repository('group/test') } + let(:token) { 'token' } + + let(:group) { create(:group, name: 'group') } + let(:project) { create(:project, path: 'test', group: group) } + let(:example_host) { 'example.com' } + let(:registry_url) { 'http://' + example_host } + let(:repository) { create(:container_image, name: '', project: project) } let(:blob) { repository.blob(config) } + before do + stub_container_registry_config(enabled: true, api_url: registry_url, host_port: example_host) + end + it { expect(blob).to respond_to(:repository) } it { expect(blob).to delegate_method(:registry).to(:repository) } it { expect(blob).to delegate_method(:client).to(:repository) } diff --git a/spec/lib/container_registry/registry_spec.rb b/spec/lib/container_registry/registry_spec.rb index 4f3f8b24fc4..4d6eea94bf0 100644 --- a/spec/lib/container_registry/registry_spec.rb +++ b/spec/lib/container_registry/registry_spec.rb @@ -10,7 +10,7 @@ describe ContainerRegistry::Registry do it { is_expected.to respond_to(:uri) } it { is_expected.to respond_to(:path) } - it { expect(subject.repository('test')).not_to be_nil } + it { expect(subject).not_to be_nil } context '#path' do subject { registry.path } diff --git a/spec/lib/container_registry/repository_spec.rb b/spec/lib/container_registry/repository_spec.rb deleted file mode 100644 index c364e759108..00000000000 --- a/spec/lib/container_registry/repository_spec.rb +++ /dev/null @@ -1,65 +0,0 @@ -require 'spec_helper' - -describe ContainerRegistry::Repository do - let(:registry) { ContainerRegistry::Registry.new('http://example.com') } - let(:repository) { registry.repository('group/test') } - - it { expect(repository).to respond_to(:registry) } - it { expect(repository).to delegate_method(:client).to(:registry) } - it { expect(repository.tag('test')).not_to be_nil } - - context '#path' do - subject { repository.path } - - it { is_expected.to eq('example.com/group/test') } - end - - context 'manifest processing' do - before do - stub_request(:get, 'http://example.com/v2/group/test/tags/list'). - with(headers: { 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json' }). - to_return( - status: 200, - body: JSON.dump(tags: ['test']), - headers: { 'Content-Type' => 'application/json' }) - end - - context '#manifest' do - subject { repository.manifest } - - it { is_expected.not_to be_nil } - end - - context '#valid?' do - subject { repository.valid? } - - it { is_expected.to be_truthy } - end - - context '#tags' do - subject { repository.tags } - - it { is_expected.not_to be_empty } - end - end - - context '#delete_tags' do - let(:tag) { ContainerRegistry::Tag.new(repository, 'tag') } - - before { expect(repository).to receive(:tags).twice.and_return([tag]) } - - subject { repository.delete_tags } - - context 'succeeds' do - before { expect(tag).to receive(:delete).and_return(true) } - - it { is_expected.to be_truthy } - end - - context 'any fails' do - before { expect(tag).to receive(:delete).and_return(false) } - - it { is_expected.to be_falsey } - end - end -end diff --git a/spec/lib/container_registry/tag_spec.rb b/spec/lib/container_registry/tag_spec.rb index c5e31ae82b6..cdd0fe66bc3 100644 --- a/spec/lib/container_registry/tag_spec.rb +++ b/spec/lib/container_registry/tag_spec.rb @@ -1,11 +1,18 @@ require 'spec_helper' describe ContainerRegistry::Tag do - let(:registry) { ContainerRegistry::Registry.new('http://example.com') } - let(:repository) { registry.repository('group/test') } + let(:group) { create(:group, name: 'group') } + let(:project) { create(:project, path: 'test', group: group) } + let(:example_host) { 'example.com' } + let(:registry_url) { 'http://' + example_host } + let(:repository) { create(:container_image, name: '', project: project) } let(:tag) { repository.tag('tag') } let(:headers) { { 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json' } } + before do + stub_container_registry_config(enabled: true, api_url: registry_url, host_port: example_host) + end + it { expect(tag).to respond_to(:repository) } it { expect(tag).to delegate_method(:registry).to(:repository) } it { expect(tag).to delegate_method(:client).to(:repository) } diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 06617f3b007..9c08f41fe82 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -114,6 +114,8 @@ merge_access_levels: - protected_branch push_access_levels: - protected_branch +container_images: +- name project: - taggings - base_tags @@ -197,6 +199,7 @@ project: - project_authorizations - route - statistics +- container_images award_emoji: - awardable - user diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 2dfca8bcfce..83a2efb55b9 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1397,7 +1397,7 @@ describe Ci::Build, :models do { key: 'CI_REGISTRY', value: 'registry.example.com', public: true } end let(:ci_registry_image) do - { key: 'CI_REGISTRY_IMAGE', value: project.container_registry_repository_url, public: true } + { key: 'CI_REGISTRY_IMAGE', value: project.container_registry_url, public: true } end context 'and is disabled for project' do diff --git a/spec/models/container_image_spec.rb b/spec/models/container_image_spec.rb new file mode 100644 index 00000000000..e0bea737f59 --- /dev/null +++ b/spec/models/container_image_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' + +describe ContainerImage do + let(:group) { create(:group, name: 'group') } + let(:project) { create(:project, path: 'test', group: group) } + let(:example_host) { 'example.com' } + let(:registry_url) { 'http://' + example_host } + let(:container_image) { create(:container_image, name: '', project: project, stubbed: false) } + + before do + stub_container_registry_config(enabled: true, api_url: registry_url, host_port: example_host) + stub_request(:get, 'http://example.com/v2/group/test/tags/list'). + with(headers: { 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json' }). + to_return( + status: 200, + body: JSON.dump(tags: ['test']), + headers: { 'Content-Type' => 'application/json' }) + end + + it { expect(container_image).to respond_to(:project) } + it { expect(container_image).to delegate_method(:container_registry).to(:project) } + it { expect(container_image).to delegate_method(:client).to(:container_registry) } + it { expect(container_image.tag('test')).not_to be_nil } + + context '#path' do + subject { container_image.path } + + it { is_expected.to eq('example.com/group/test') } + end + + context 'manifest processing' do + context '#manifest' do + subject { container_image.manifest } + + it { is_expected.not_to be_nil } + end + + context '#valid?' do + subject { container_image.valid? } + + it { is_expected.to be_truthy } + end + + context '#tags' do + subject { container_image.tags } + + it { is_expected.not_to be_empty } + end + end + + context '#delete_tags' do + let(:tag) { ContainerRegistry::Tag.new(container_image, 'tag') } + + before do + expect(container_image).to receive(:tags).twice.and_return([tag]) + expect(tag).to receive(:digest).and_return('sha256:4c8e63ca4cb663ce6c688cb06f1c3672a172b088dac5b6d7ad7d49cd620d85cf') + end + + subject { container_image.delete_tags } + + context 'succeeds' do + before { expect(container_image.client).to receive(:delete_repository_tag).and_return(true) } + + it { is_expected.to be_truthy } + end + + context 'any fails' do + before { expect(container_image.client).to receive(:delete_repository_tag).and_return(false) } + + it { is_expected.to be_falsey } + end + end +end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 35d932f1c64..aeb4eeb0b55 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -134,18 +134,20 @@ describe Namespace, models: true do expect(@namespace.move_dir).to be_truthy end - context "when any project has container tags" do + context "when any project has container images" do + let(:container_image) { create(:container_image) } + before do stub_container_registry_config(enabled: true) stub_container_registry_tags('tag') - create(:empty_project, namespace: @namespace) + create(:empty_project, namespace: @namespace, container_images: [container_image]) allow(@namespace).to receive(:path_was).and_return(@namespace.path) allow(@namespace).to receive(:path).and_return('new_path') end - it { expect { @namespace.move_dir }.to raise_error('Namespace cannot be moved, because at least one project has tags in container registry') } + it { expect { @namespace.move_dir }.to raise_error('Namespace cannot be moved, because at least one project has images in container registry') } end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index b0087a9e15d..77f2ff3d17b 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1173,10 +1173,13 @@ describe Project, models: true do project.rename_repo end - context 'container registry with tags' do + context 'container registry with images' do + let(:container_image) { create(:container_image) } + before do stub_container_registry_config(enabled: true) stub_container_registry_tags('tag') + project.container_images << container_image end subject { project.rename_repo } @@ -1383,20 +1386,20 @@ describe Project, models: true do it { is_expected.to eq(project.path_with_namespace.downcase) } end - describe '#container_registry_repository' do + describe '#container_registry' do let(:project) { create(:empty_project) } before { stub_container_registry_config(enabled: true) } - subject { project.container_registry_repository } + subject { project.container_registry } it { is_expected.not_to be_nil } end - describe '#container_registry_repository_url' do + describe '#container_registry_url' do let(:project) { create(:empty_project) } - subject { project.container_registry_repository_url } + subject { project.container_registry_url } before { stub_container_registry_config(**registry_settings) } @@ -1422,34 +1425,6 @@ describe Project, models: true do end end - describe '#has_container_registry_tags?' do - let(:project) { create(:empty_project) } - - subject { project.has_container_registry_tags? } - - context 'for enabled registry' do - before { stub_container_registry_config(enabled: true) } - - context 'with tags' do - before { stub_container_registry_tags('test', 'test2') } - - it { is_expected.to be_truthy } - end - - context 'when no tags' do - before { stub_container_registry_tags } - - it { is_expected.to be_falsey } - end - end - - context 'for disabled registry' do - before { stub_container_registry_config(enabled: false) } - - it { is_expected.to be_falsey } - end - end - describe '#latest_successful_builds_for' do def create_pipeline(status = 'success') create(:ci_pipeline, project: project, diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index 74bfba44dfd..270e630e70e 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -90,25 +90,30 @@ describe Projects::DestroyService, services: true do end context 'container registry' do + let(:container_image) { create(:container_image) } + before do stub_container_registry_config(enabled: true) stub_container_registry_tags('tag') + project.container_images << container_image end - context 'tags deletion succeeds' do + context 'images deletion succeeds' do it do - expect_any_instance_of(ContainerRegistry::Tag).to receive(:delete).and_return(true) + expect_any_instance_of(ContainerImage).to receive(:delete_tags).and_return(true) destroy_project(project, user, {}) end end - context 'tags deletion fails' do - before { expect_any_instance_of(ContainerRegistry::Tag).to receive(:delete).and_return(false) } + context 'images deletion fails' do + before do + expect_any_instance_of(ContainerImage).to receive(:delete_tags).and_return(false) + end subject { destroy_project(project, user, {}) } - it { expect{subject}.to raise_error(Projects::DestroyService::DestroyError) } + it { expect{subject}.to raise_error(ActiveRecord::RecordNotDestroyed) } end end diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index 5c6fbea8d0e..5e56226ff91 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -29,9 +29,12 @@ describe Projects::TransferService, services: true do end context 'disallow transfering of project with tags' do + let(:container_image) { create(:container_image) } + before do stub_container_registry_config(enabled: true) stub_container_registry_tags('tag') + project.container_images << container_image end subject { transfer_project(project, user, group) }