summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/stylesheets/pages/container_registry.scss6
-rw-r--r--app/controllers/projects/container_registry_controller.rb1
-rw-r--r--app/models/container_image.rb4
-rw-r--r--app/models/namespace.rb8
-rw-r--r--app/models/project.rb18
-rw-r--r--app/services/auth/container_registry_authentication_service.rb3
-rw-r--r--app/services/container_images/destroy_service.rb1
-rw-r--r--app/services/projects/transfer_service.rb6
-rw-r--r--app/views/projects/container_registry/_image.html.haml2
-rw-r--r--app/views/projects/container_registry/_tag.html.haml2
-rw-r--r--app/views/projects/container_registry/index.html.haml4
-rw-r--r--db/schema.rb6
-rw-r--r--lib/api/registry_events.rb4
-rw-r--r--lib/container_registry/blob.rb4
-rw-r--r--lib/container_registry/registry.rb4
-rw-r--r--lib/container_registry/repository.rb48
-rw-r--r--spec/factories/container_images.rb21
-rw-r--r--spec/features/container_registry_spec.rb32
-rw-r--r--spec/features/security/project/internal_access_spec.rb3
-rw-r--r--spec/features/security/project/private_access_spec.rb3
-rw-r--r--spec/features/security/project/public_access_spec.rb3
-rw-r--r--spec/lib/container_registry/blob_spec.rb15
-rw-r--r--spec/lib/container_registry/registry_spec.rb2
-rw-r--r--spec/lib/container_registry/repository_spec.rb65
-rw-r--r--spec/lib/container_registry/tag_spec.rb11
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml3
-rw-r--r--spec/models/ci/build_spec.rb2
-rw-r--r--spec/models/container_image_spec.rb73
-rw-r--r--spec/models/namespace_spec.rb8
-rw-r--r--spec/models/project_spec.rb41
-rw-r--r--spec/services/projects/destroy_service_spec.rb15
-rw-r--r--spec/services/projects/transfer_service_spec.rb3
32 files changed, 211 insertions, 210 deletions
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 container images in Container Registry for this project') }
+ end
- it { expect(page).to have_content('No images in Container Registry for this project') }
+ 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)
- context 'when there are tags' do
- it { expect(page).to have_content(tag_name) }
- it { expect(page).to have_content('d7a513a66') }
+ 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) }