Commit d6450eef authored by Steve Abrams's avatar Steve Abrams

Add ContainerRepositories API

Add show endpoint for container repositories not
nested beneath projects or groups.
parent e35ecfeb
---
title: Add container repositories API
merge_request: 46495
author:
type: added
......@@ -124,6 +124,48 @@ Example response:
]
```
## Get details of a single repository
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/209916) in GitLab 13.6.
Get details of a registry repository.
```plaintext
GET /registry/repositories/:id
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID of the registry repository accessible by the authenticated user. |
| `tags` | boolean | no | If the parameter is included as `true`, the response includes an array of `"tags"`. |
| `tags_count` | boolean | no | If the parameter is included as `true`, the response includes `"tags_count"`. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/registry/repositories/2?tags=true&tags_count=true"
```
Example response:
```json
{
"id": 2,
"name": "",
"path": "group/project",
"project_id": 9,
"location": "gitlab.example.com:5000/group/project",
"created_at": "2019-01-10T13:38:57.391Z",
"cleanup_policy_started_at": "2020-08-17T03:12:35.489Z",
"tags_count": 1,
"tags": [
{
"name": "0.0.1",
"path": "group/project:0.0.1",
"location": "gitlab.example.com:5000/group/project:0.0.1"
}
]
}
```
## Delete registry repository
Delete a repository in registry.
......
......@@ -161,6 +161,7 @@ module API
mount ::API::Commits
mount ::API::CommitStatuses
mount ::API::ContainerRegistryEvent
mount ::API::ContainerRepositories
mount ::API::DeployKeys
mount ::API::DeployTokens
mount ::API::Deployments
......
# frozen_string_literal: true
module API
class ContainerRepositories < ::API::Base
include Gitlab::Utils::StrongMemoize
helpers ::API::Helpers::PackagesHelpers
before { authenticate! }
namespace 'registry' do
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :repositories, requirements: { id: /[0-9]*/ } do
desc 'Get a container repository' do
detail 'This feature was introduced in GitLab 13.6.'
success Entities::ContainerRegistry::Repository
end
params do
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
get ':id' do
authorize!(:read_container_image, repository)
present repository, with: Entities::ContainerRegistry::Repository, tags: params[:tags], tags_count: params[:tags_count], user: current_user
end
end
end
helpers do
def repository
strong_memoize(:repository) do
ContainerRepository.find(params[:id])
end
end
end
end
end
......@@ -10,6 +10,8 @@ module API
end
class Repository < Grape::Entity
include ::API::Helpers::RelatedResourcesHelpers
expose :id
expose :name
expose :path
......@@ -19,6 +21,13 @@ module API
expose :expiration_policy_started_at, as: :cleanup_policy_started_at
expose :tags_count, if: -> (_, options) { options[:tags_count] }
expose :tags, using: Tag, if: -> (_, options) { options[:tags] }
expose :delete_api_path, if: ->(object, options) { Ability.allowed?(options[:user], :admin_container_image, object) }
private
def delete_api_path
expose_url api_v4_projects_registry_repositories_path(repository_id: object.id, id: object.project_id)
end
end
class TagDetails < Tag
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::ContainerRepositories do
let_it_be(:project) { create(:project, :private) }
let_it_be(:reporter) { create(:user) }
let_it_be(:guest) { create(:user) }
let_it_be(:repository) { create(:container_repository, project: project) }
let(:users) do
{
anonymous: nil,
guest: guest,
reporter: reporter
}
end
let(:api_user) { reporter }
before do
project.add_reporter(reporter)
project.add_guest(guest)
stub_container_registry_config(enabled: true)
end
describe 'GET /registry/repositories/:id' do
let(:url) { "/registry/repositories/#{repository.id}" }
subject { get api(url, api_user) }
it_behaves_like 'rejected container repository access', :guest, :forbidden
it_behaves_like 'rejected container repository access', :anonymous, :unauthorized
context 'for allowed user' do
it 'returns a repository' do
subject
expect(json_response['id']).to eq(repository.id)
expect(response.body).not_to include('tags')
end
it 'returns a matching schema' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('registry/repository')
end
context 'with tags param' do
let(:url) { "/registry/repositories/#{repository.id}?tags=true" }
before do
stub_container_registry_tags(repository: repository.path, tags: %w(rootA latest), with_manifest: true)
end
it 'returns a repository and its tags' do
subject
expect(json_response['id']).to eq(repository.id)
expect(response.body).to include('tags')
end
end
context 'with tags_count param' do
let(:url) { "/registry/repositories/#{repository.id}?tags_count=true" }
before do
stub_container_registry_tags(repository: repository.path, tags: %w(rootA latest), with_manifest: true)
end
it 'returns a repository and its tags_count' do
subject
expect(response.body).to include('tags_count')
expect(json_response['tags_count']).to eq(2)
end
end
end
context 'with invalid repository id' do
let(:url) { "/registry/repositories/#{non_existing_record_id}" }
it_behaves_like 'returning response status', :not_found
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