Commit 16bb4175 authored by Jan Provaznik's avatar Jan Provaznik

Merge branch '216757-add-tags-count' into 'master'

Add tags_count to container registry api and controller

See merge request gitlab-org/gitlab!32141
parents 7998a3b3 5be97747
...@@ -67,6 +67,12 @@ class ContainerRepository < ApplicationRecord ...@@ -67,6 +67,12 @@ class ContainerRepository < ApplicationRecord
end end
end end
def tags_count
return 0 unless manifest && manifest['tags']
manifest['tags'].size
end
def blob(config) def blob(config)
ContainerRegistry::Blob.new(self, config) ContainerRegistry::Blob.new(self, config)
end end
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
class ContainerRepositoryEntity < Grape::Entity class ContainerRepositoryEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
expose :id, :name, :path, :location, :created_at, :status expose :id, :name, :path, :location, :created_at, :status, :tags_count
expose :tags_path do |repository| expose :tags_path do |repository|
project_registry_repository_tags_path(project, repository, format: :json) project_registry_repository_tags_path(project, repository, format: :json)
......
---
title: Add tags_count to container registry api and controller
merge_request: 32141
author:
type: changed
...@@ -19,6 +19,7 @@ GET /projects/:id/registry/repositories ...@@ -19,6 +19,7 @@ GET /projects/:id/registry/repositories
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) accessible by the authenticated user. | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) accessible by the authenticated user. |
| `tags` | boolean | no | If the parameter is included as true, each repository will include an array of `"tags"` in the response. | | `tags` | boolean | no | If the parameter is included as true, each repository will include an array of `"tags"` in the response. |
| `name` | string | no | Returns a list of repositories with a name that matches the value. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29763) in GitLab 13.0). | | `name` | string | no | Returns a list of repositories with a name that matches the value. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29763) in GitLab 13.0). |
| `tags_count` | boolean | no | If the parameter is included as true, each repository will include `"tags_count"` in the response ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32141) in GitLab 13.1). |
```shell ```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/registry/repositories" curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/registry/repositories"
...@@ -60,9 +61,10 @@ GET /groups/:id/registry/repositories ...@@ -60,9 +61,10 @@ GET /groups/:id/registry/repositories
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) accessible by the authenticated user. | | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) accessible by the authenticated user. |
| `tags` | boolean | no | If the parameter is included as true, each repository will include an array of `"tags"` in the response. | | `tags` | boolean | no | If the parameter is included as true, each repository will include an array of `"tags"` in the response. |
| `name` | string | no | Returns a list of repositories with a name that matches the value. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29763) in GitLab 13.0). | | `name` | string | no | Returns a list of repositories with a name that matches the value. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29763) in GitLab 13.0). |
| `tags_count` | boolean | no | If the parameter is included as true, each repository will include `"tags_count"` in the response ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32141) in GitLab 13.1). |
```shell ```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/2/registry/repositories?tags=1" curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/2/registry/repositories?tags=1&tags_count=true"
``` ```
Example response: Example response:
...@@ -76,6 +78,7 @@ Example response: ...@@ -76,6 +78,7 @@ Example response:
"project_id": 9, "project_id": 9,
"location": "gitlab.example.com:5000/group/project", "location": "gitlab.example.com:5000/group/project",
"created_at": "2019-01-10T13:38:57.391Z", "created_at": "2019-01-10T13:38:57.391Z",
"tags_count": 1,
"tags": [ "tags": [
{ {
"name": "0.0.1", "name": "0.0.1",
...@@ -91,6 +94,7 @@ Example response: ...@@ -91,6 +94,7 @@ Example response:
"project_id": 11, "project_id": 11,
"location": "gitlab.example.com:5000/group/other_project", "location": "gitlab.example.com:5000/group/other_project",
"created_at": "2019-01-10T13:39:08.229Z", "created_at": "2019-01-10T13:39:08.229Z",
"tags_count": 3,
"tags": [ "tags": [
{ {
"name": "0.0.1", "name": "0.0.1",
......
...@@ -16,6 +16,7 @@ module API ...@@ -16,6 +16,7 @@ module API
expose :project_id expose :project_id
expose :location expose :location
expose :created_at expose :created_at
expose :tags_count, if: -> (_, options) { options[:tags_count] }
expose :tags, using: Tag, if: -> (_, options) { options[:tags] } expose :tags, using: Tag, if: -> (_, options) { options[:tags] }
end end
......
...@@ -20,6 +20,7 @@ module API ...@@ -20,6 +20,7 @@ module API
params do params do
use :pagination use :pagination
optional :tags, type: Boolean, default: false, desc: 'Determines if tags should be included' optional :tags, type: Boolean, default: false, desc: 'Determines if tags should be included'
optional :tags_count, type: Boolean, default: false, desc: 'Determines if the tags count should be included'
end end
get ':id/registry/repositories' do get ':id/registry/repositories' do
repositories = ContainerRepositoriesFinder.new( repositories = ContainerRepositoriesFinder.new(
...@@ -28,7 +29,7 @@ module API ...@@ -28,7 +29,7 @@ module API
track_event('list_repositories') track_event('list_repositories')
present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags] present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags], tags_count: params[:tags_count]
end end
end end
......
...@@ -21,6 +21,7 @@ module API ...@@ -21,6 +21,7 @@ module API
params do params do
use :pagination use :pagination
optional :tags, type: Boolean, default: false, desc: 'Determines if tags should be included' optional :tags, type: Boolean, default: false, desc: 'Determines if tags should be included'
optional :tags_count, type: Boolean, default: false, desc: 'Determines if the tags count should be included'
end end
get ':id/registry/repositories' do get ':id/registry/repositories' do
repositories = ContainerRepositoriesFinder.new( repositories = ContainerRepositoriesFinder.new(
...@@ -29,7 +30,7 @@ module API ...@@ -29,7 +30,7 @@ module API
track_event( 'list_repositories') track_event( 'list_repositories')
present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags] present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags], tags_count: params[:tags_count]
end end
desc 'Delete repository' do desc 'Delete repository' do
......
...@@ -17,6 +17,7 @@ describe Groups::Registry::RepositoriesController do ...@@ -17,6 +17,7 @@ describe Groups::Registry::RepositoriesController do
before do before do
stub_container_registry_config(enabled: true) stub_container_registry_config(enabled: true)
stub_container_registry_tags(repository: :any, tags: [])
group.add_owner(user) group.add_owner(user)
group.add_guest(guest) group.add_guest(guest)
sign_in(user) sign_in(user)
......
...@@ -46,7 +46,7 @@ describe Projects::Registry::RepositoriesController do ...@@ -46,7 +46,7 @@ describe Projects::Registry::RepositoriesController do
context 'when root container repository is not created' do context 'when root container repository is not created' do
context 'when there are tags for this repository' do context 'when there are tags for this repository' do
before do before do
stub_container_registry_tags(repository: project.full_path, stub_container_registry_tags(repository: :any,
tags: %w[rc1 latest]) tags: %w[rc1 latest])
end end
......
{ {
"type": "object", "type": "object",
"required" : [ "required": ["id", "name", "path", "location", "created_at"],
"id", "properties": {
"name",
"path",
"location",
"created_at"
],
"properties" : {
"id": { "id": {
"type": "integer" "type": "integer"
}, },
...@@ -38,7 +32,10 @@ ...@@ -38,7 +32,10 @@
{ "type": "string", "enum": ["delete_scheduled", "delete_failed"] } { "type": "string", "enum": ["delete_scheduled", "delete_failed"] }
] ]
}, },
"tags": { "$ref": "tags.json" } "tags": { "$ref": "tags.json" },
"tags_count": {
"type": "integer"
}
}, },
"additionalProperties": false "additionalProperties": false
} }
...@@ -81,6 +81,12 @@ describe ContainerRepository do ...@@ -81,6 +81,12 @@ describe ContainerRepository do
end end
end end
describe '#tags_count' do
it 'returns the count of tags' do
expect(repository.tags_count).to eq(1)
end
end
describe '#has_tags?' do describe '#has_tags?' do
it 'has tags' do it 'has tags' do
expect(repository).to have_tags expect(repository).to have_tags
......
...@@ -8,7 +8,7 @@ describe Groups::Registry::RepositoriesController do ...@@ -8,7 +8,7 @@ describe Groups::Registry::RepositoriesController do
before do before do
stub_container_registry_config(enabled: true) stub_container_registry_config(enabled: true)
stub_container_registry_tags(repository: :any, tags: [])
group.add_reporter(user) group.add_reporter(user)
login_as(user) login_as(user)
end end
......
...@@ -13,12 +13,14 @@ describe ContainerRepositoryEntity do ...@@ -13,12 +13,14 @@ describe ContainerRepositoryEntity do
before do before do
stub_container_registry_config(enabled: true) stub_container_registry_config(enabled: true)
stub_container_registry_tags(repository: :any,
tags: %w[stable latest])
allow(request).to receive(:project).and_return(project) allow(request).to receive(:project).and_return(project)
allow(request).to receive(:current_user).and_return(user) allow(request).to receive(:current_user).and_return(user)
end end
it 'exposes required informations' do it 'exposes required informations' do
expect(subject).to include(:id, :path, :location, :tags_path) expect(subject).to include(:id, :path, :location, :tags_path, :tags_count)
end end
context 'when project is not preset in the request' do context 'when project is not preset in the request' do
......
...@@ -54,6 +54,29 @@ RSpec.shared_examples 'returns repositories for allowed users' do |user_type, sc ...@@ -54,6 +54,29 @@ RSpec.shared_examples 'returns repositories for allowed users' do |user_type, sc
expect(response).to match_response_schema('registry/repositories') expect(response).to match_response_schema('registry/repositories')
end end
end end
context 'with tags_count param' do
let(:url) { "/#{scope}s/#{object.id}/registry/repositories?tags_count=true" }
before do
stub_container_registry_tags(repository: root_repository.path, tags: %w(rootA latest), with_manifest: true)
stub_container_registry_tags(repository: test_repository.path, tags: %w(rootA latest), with_manifest: true)
end
it 'returns a list of repositories and their tags_count' do
subject
expect(response.body).to include('tags_count')
expect(json_response[0]['tags_count']).to eq(2)
end
it 'returns a matching schema' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('registry/repositories')
end
end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment