mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-18 08:15:16 +01:00
Merge pull request #10537 from ywk253100/200115_artifact_api
Implement the listing artifact API
This commit is contained in:
commit
a774a19823
@ -18,21 +18,52 @@ securityDefinitions:
|
||||
security:
|
||||
- basicAuth: []
|
||||
paths:
|
||||
/projects/{project_id}/repositories/{repository_id}/artifacts/{artifact_id}:
|
||||
/projects/{project_name}/repositories/{repository_name}/artifacts/{digest}:
|
||||
get:
|
||||
summary: Read artifact by id
|
||||
description: endpoint returns artifact by id
|
||||
summary: Get the specific artifact
|
||||
description: Get the artifact specified by the digest under the project and repository
|
||||
tags:
|
||||
- artifact
|
||||
operationId: readArtifact
|
||||
operationId: getArtifact
|
||||
parameters:
|
||||
- $ref: '#/parameters/requestId'
|
||||
- $ref: '#/parameters/projectId'
|
||||
- $ref: '#/parameters/repositoryId'
|
||||
- $ref: '#/parameters/artifactId'
|
||||
- $ref: '#/parameters/projectName'
|
||||
- $ref: '#/parameters/repositoryName'
|
||||
- $ref: '#/parameters/digest'
|
||||
- name: with_tag
|
||||
in: query
|
||||
description: Specify whether the tags are inclued inside the returning artifacts
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
- name: with_label
|
||||
in: query
|
||||
description: Specify whether the labels are inclued inside the returning artifacts
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
- name: with_scan_overview
|
||||
in: query
|
||||
description: Specify whether the scan overview is inclued inside the returning artifacts
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
# should be in tag level
|
||||
- name: with_signatrue
|
||||
in: query
|
||||
description: Specify whether the signature is inclued inside the returning artifacts
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
- name: with_immutable_status
|
||||
in: query
|
||||
description: Specify whether the immutable status is inclued inside the tags of the returning artifacts. Only works when setting "with_tag=true"
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
description: Success
|
||||
schema:
|
||||
$ref: '#/definitions/Artifact'
|
||||
'401':
|
||||
@ -42,59 +73,78 @@ paths:
|
||||
'500':
|
||||
$ref: '#/responses/500'
|
||||
delete:
|
||||
summary: Delete artifact by id
|
||||
description: endpoint to delete the artifact by id
|
||||
summary: Delete the specific artifact
|
||||
description: Delete the artifact specified by the digest under the project and repository
|
||||
tags:
|
||||
- artifact
|
||||
operationId: deleteArtifact
|
||||
parameters:
|
||||
- $ref: '#/parameters/requestId'
|
||||
- $ref: '#/parameters/projectId'
|
||||
- $ref: '#/parameters/repositoryId'
|
||||
- $ref: '#/parameters/artifactId'
|
||||
- $ref: '#/parameters/projectName'
|
||||
- $ref: '#/parameters/repositoryName'
|
||||
- $ref: '#/parameters/digest'
|
||||
responses:
|
||||
'200':
|
||||
description: Artifact is deleted successfully.
|
||||
description: Success
|
||||
'401':
|
||||
$ref: '#/responses/401'
|
||||
'403':
|
||||
$ref: '#/responses/403'
|
||||
'500':
|
||||
$ref: '#/responses/500'
|
||||
/projects/{project_id}/repositories/{repository_id}/artifacts:
|
||||
/projects/{project_name}/repositories/{repository_name}/artifacts:
|
||||
get:
|
||||
summary: List artifacts of the repository
|
||||
description: endpoint returns all artifacts of the repository.
|
||||
summary: List artifacts
|
||||
description: List artifacts under the specific project and repository.
|
||||
tags:
|
||||
- artifact
|
||||
operationId: listArtifacts
|
||||
parameters:
|
||||
- $ref: '#/parameters/requestId'
|
||||
- $ref: '#/parameters/projectId'
|
||||
- $ref: '#/parameters/repositoryId'
|
||||
- $ref: '#/parameters/projectName'
|
||||
- $ref: '#/parameters/repositoryName'
|
||||
- $ref: '#/parameters/page'
|
||||
- $ref: '#/parameters/pageSize'
|
||||
- name: label
|
||||
- name: type
|
||||
in: query
|
||||
description: Response for artifact include label info when it's true
|
||||
description: Query the artifacts by type. Valid values can be "IMAGE", "CHART", etc.
|
||||
type: string
|
||||
required: false
|
||||
- name: with_tag
|
||||
in: query
|
||||
description: Specify whether the tags are inclued inside the returning artifacts
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
- name: with_label
|
||||
in: query
|
||||
description: Specify whether the labels are inclued inside the returning artifacts
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
- name: signature
|
||||
- name: with_scan_overview
|
||||
in: query
|
||||
description: Response for artifact include signature info when it's true
|
||||
description: Specify whether the scan overview is inclued inside the returning artifacts
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
- name: vulnerability
|
||||
# should be in tag level
|
||||
- name: with_signatrue
|
||||
in: query
|
||||
description: Response for artifact include vulnerability info when it's true
|
||||
description: Specify whether the signature is inclued inside the returning artifacts
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
- name: with_immutable_status
|
||||
in: query
|
||||
description: Specify whether the immutable status is inclued inside the tags of the returning artifacts. Only works when setting "with_tag=true"
|
||||
type: boolean
|
||||
required: false
|
||||
default: false
|
||||
# TODO add other query string: type, ....
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
description: Success
|
||||
headers:
|
||||
X-Total-Count:
|
||||
description: The total count of artifacts
|
||||
@ -115,70 +165,67 @@ paths:
|
||||
parameters:
|
||||
requestId:
|
||||
name: X-Request-Id
|
||||
description: A unique id for the request
|
||||
description: An unique ID for the request
|
||||
in: header
|
||||
type: string
|
||||
required: false
|
||||
minLength: 1
|
||||
projectId:
|
||||
name: project_id
|
||||
projectName:
|
||||
name: project_name
|
||||
in: path
|
||||
description: The id of the project
|
||||
description: The name of the project
|
||||
required: true
|
||||
type: integer
|
||||
format: int64
|
||||
repositoryId:
|
||||
name: repository_id
|
||||
type: string
|
||||
repositoryName:
|
||||
name: repository_name
|
||||
in: path
|
||||
description: The id of the repository
|
||||
description: The name of the repository
|
||||
required: true
|
||||
type: integer
|
||||
format: int64
|
||||
artifactId:
|
||||
name: artifact_id
|
||||
type: string
|
||||
digest:
|
||||
name: digest
|
||||
in: path
|
||||
description: The id of the artifact
|
||||
description: The digest of the artifact
|
||||
required: true
|
||||
type: integer
|
||||
format: int64
|
||||
type: string
|
||||
page:
|
||||
name: page
|
||||
in: query
|
||||
type: integer
|
||||
format: int32
|
||||
format: int64
|
||||
required: false
|
||||
description: 'The page number, default is 1.'
|
||||
description: The page number
|
||||
default: 1
|
||||
pageSize:
|
||||
name: page_size
|
||||
in: query
|
||||
type: integer
|
||||
format: int32
|
||||
format: int64
|
||||
required: false
|
||||
description: 'The size of per page, default is 10, maximum is 100.'
|
||||
description: The size of per page
|
||||
default: 10
|
||||
responses:
|
||||
'401':
|
||||
description: UnauthorizedError
|
||||
description: Unauthorized
|
||||
headers:
|
||||
X-Request-Id:
|
||||
description: The request id this is a response to
|
||||
description: The ID of the corresponding request for the response
|
||||
type: string
|
||||
schema:
|
||||
$ref: '#/definitions/Error'
|
||||
'403':
|
||||
description: ForbiddenError
|
||||
description: Forbidden
|
||||
headers:
|
||||
X-Request-Id:
|
||||
description: The request id this is a response to
|
||||
description: The ID of the corresponding request for the response
|
||||
type: string
|
||||
schema:
|
||||
$ref: '#/definitions/Error'
|
||||
'500':
|
||||
description: InternalServerError
|
||||
description: Internal server error
|
||||
headers:
|
||||
X-Request-Id:
|
||||
description: The request id this is a response to
|
||||
description: The ID of the corresponding request for the response
|
||||
type: string
|
||||
schema:
|
||||
$ref: '#/definitions/Error'
|
||||
@ -204,40 +251,132 @@ definitions:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: The id of the artifact
|
||||
description: The ID of the artifact
|
||||
type:
|
||||
type: string
|
||||
description: The type of the artifact, eg image, chart, etc
|
||||
repository:
|
||||
$ref: '#/definitions/Repository'
|
||||
description: The repository of the artifact
|
||||
tags:
|
||||
description: The list of tags that attached to the artifact
|
||||
description: The type of the artifact, e.g. image, chart, etc
|
||||
media_type:
|
||||
type: string
|
||||
description: The specific media type for the artifact
|
||||
description: The media type of the artifact
|
||||
manifest_media_type:
|
||||
type: string
|
||||
description: The manifest media type of the artifact
|
||||
project_id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: The ID of the project that the artifact belongs to
|
||||
repository_id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: The ID of the repository that the artifact belongs to
|
||||
digest:
|
||||
type: string
|
||||
description: The digest of the artifact
|
||||
size:
|
||||
type: string
|
||||
type: integer
|
||||
format: int64
|
||||
description: The size of the artifact
|
||||
upload_time:
|
||||
push_time:
|
||||
type: string
|
||||
format: date-time
|
||||
description: The upload time for the artifact
|
||||
labels:
|
||||
description: The list of labels that attached to the artifact
|
||||
signature:
|
||||
description: The signature attached to the artifact
|
||||
Repository:
|
||||
description: The push time of the artifact
|
||||
pull_time:
|
||||
type: string
|
||||
format: date-time
|
||||
description: The latest pull time of the artifact
|
||||
extra_attrs:
|
||||
$ref: '#/definitions/ExtraAttrs'
|
||||
annotations:
|
||||
$ref: '#/definitions/Annotations'
|
||||
references:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/Reference'
|
||||
tags:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/Tag'
|
||||
sub_resource_links:
|
||||
$ref: '#/definitions/SubResourceLinks'
|
||||
Tag:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: The id of the repository
|
||||
description: The ID of the tag
|
||||
repository_id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: The ID of the repository that the tag belongs to
|
||||
artifact_id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: The ID of the artifact that the tag attached to
|
||||
name:
|
||||
type: string
|
||||
description: The name of repository.
|
||||
description: The name of the tag
|
||||
push_time:
|
||||
type: string
|
||||
format: date-time
|
||||
description: The push time of the tag
|
||||
pull_time:
|
||||
type: string
|
||||
format: date-time
|
||||
description: The latest pull time of the tag
|
||||
ExtraAttrs:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: object
|
||||
Annotations:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: string
|
||||
SubResourceLinks:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/ResourceLink'
|
||||
ResourceLink:
|
||||
type: object
|
||||
properties:
|
||||
href:
|
||||
type: string
|
||||
description: The link of the resource
|
||||
absolute:
|
||||
type: boolean
|
||||
description: Determine whether the link is an absolute URL or not
|
||||
Reference:
|
||||
type: object
|
||||
properties:
|
||||
parent_id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: The parent ID of the reference
|
||||
child_id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: The child ID of the reference
|
||||
platform:
|
||||
$ref: '#/definitions/Platform'
|
||||
Platform:
|
||||
type: object
|
||||
properties:
|
||||
architecture:
|
||||
type: string
|
||||
description: The architecture that the artifact applys to
|
||||
os:
|
||||
type: string
|
||||
description: The OS that the artifact applys to
|
||||
os.version:
|
||||
type: string
|
||||
description: The version of the OS that the artifact applys to
|
||||
os.features:
|
||||
type: array
|
||||
description: The features of the OS that the artifact applys to
|
||||
items:
|
||||
type: string
|
||||
variant:
|
||||
type: string
|
||||
description: The variant of the CPU
|
||||
|
@ -294,7 +294,13 @@ func (c *controller) assembleArtifact(ctx context.Context, art *artifact.Artifac
|
||||
log.Errorf("failed to list tag of artifact %d: %v", artifact.ID, err)
|
||||
}
|
||||
}
|
||||
// TODO populate other properties: scan, signature etc.
|
||||
if option.WithLabel {
|
||||
// TODO populate label
|
||||
}
|
||||
if option.WithScanOverview {
|
||||
// TODO populate scan overview
|
||||
}
|
||||
// TODO populate signature on artifact or label level?
|
||||
return artifact
|
||||
}
|
||||
|
||||
@ -306,6 +312,9 @@ func (c *controller) assembleTag(ctx context.Context, tag *tm.Tag, option *TagOp
|
||||
if option == nil {
|
||||
return t
|
||||
}
|
||||
// TODO populate label, signature, immutable status for tag
|
||||
if option.WithImmutableStatus {
|
||||
// TODO populate immutable status
|
||||
}
|
||||
// TODO populate signature on tag level?
|
||||
return t
|
||||
}
|
||||
|
@ -68,7 +68,6 @@ func (c *controllerTestSuite) TestAssembleTag() {
|
||||
PullTime: time.Now(),
|
||||
}
|
||||
option := &TagOption{
|
||||
WithLabel: true,
|
||||
WithImmutableStatus: true,
|
||||
}
|
||||
|
||||
@ -85,11 +84,12 @@ func (c *controllerTestSuite) TestAssembleArtifact() {
|
||||
option := &Option{
|
||||
WithTag: true,
|
||||
TagOption: &TagOption{
|
||||
WithLabel: false,
|
||||
|
||||
WithImmutableStatus: false,
|
||||
},
|
||||
WithScanResult: true,
|
||||
WithSignature: true,
|
||||
WithLabel: false,
|
||||
WithScanOverview: true,
|
||||
WithSignature: true,
|
||||
}
|
||||
tg := &tag.Tag{
|
||||
ID: 1,
|
||||
@ -209,9 +209,9 @@ func (c *controllerTestSuite) TestEnsure() {
|
||||
func (c *controllerTestSuite) TestList() {
|
||||
query := &q.Query{}
|
||||
option := &Option{
|
||||
WithTag: true,
|
||||
WithScanResult: true,
|
||||
WithSignature: true,
|
||||
WithTag: true,
|
||||
WithScanOverview: true,
|
||||
WithSignature: true,
|
||||
}
|
||||
c.artMgr.On("List").Return(1, []*artifact.Artifact{
|
||||
{
|
||||
|
@ -15,8 +15,10 @@
|
||||
package artifact
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||
"github.com/goharbor/harbor/src/pkg/tag/model/tag"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/models"
|
||||
)
|
||||
|
||||
// Artifact is the overall view of artifact
|
||||
@ -27,6 +29,62 @@ type Artifact struct {
|
||||
// TODO add other attrs: signature, scan result, etc
|
||||
}
|
||||
|
||||
// ToSwagger converts the artifact to the swagger model
|
||||
func (a *Artifact) ToSwagger() *models.Artifact {
|
||||
art := &models.Artifact{
|
||||
ID: a.ID,
|
||||
Type: a.Type,
|
||||
MediaType: a.MediaType,
|
||||
ManifestMediaType: a.ManifestMediaType,
|
||||
ProjectID: a.ProjectID,
|
||||
RepositoryID: a.RepositoryID,
|
||||
Digest: a.Digest,
|
||||
Size: a.Size,
|
||||
PullTime: strfmt.DateTime(a.PullTime),
|
||||
PushTime: strfmt.DateTime(a.PushTime),
|
||||
ExtraAttrs: a.ExtraAttrs,
|
||||
Annotations: a.Annotations,
|
||||
}
|
||||
for _, reference := range a.References {
|
||||
ref := &models.Reference{
|
||||
ChildID: reference.ChildID,
|
||||
ParentID: reference.ParentID,
|
||||
}
|
||||
if reference.Platform != nil {
|
||||
ref.Platform = &models.Platform{
|
||||
Architecture: reference.Platform.Architecture,
|
||||
Os: reference.Platform.OS,
|
||||
OsFeatures: reference.Platform.OSFeatures,
|
||||
OsVersion: reference.Platform.OSVersion,
|
||||
Variant: reference.Platform.Variant,
|
||||
}
|
||||
}
|
||||
art.References = append(art.References, ref)
|
||||
}
|
||||
for _, tag := range a.Tags {
|
||||
art.Tags = append(art.Tags, &models.Tag{
|
||||
ArtifactID: tag.ArtifactID,
|
||||
ID: tag.ID,
|
||||
Name: tag.Name,
|
||||
PullTime: strfmt.DateTime(tag.PullTime),
|
||||
PushTime: strfmt.DateTime(tag.PushTime),
|
||||
RepositoryID: tag.RepositoryID,
|
||||
})
|
||||
}
|
||||
for resource, links := range a.SubResourceLinks {
|
||||
for _, link := range links {
|
||||
art.SubResourceLinks[resource] = []models.ResourceLink{}
|
||||
if link != nil {
|
||||
art.SubResourceLinks[resource] = append(art.SubResourceLinks[resource], models.ResourceLink{
|
||||
Absolute: link.Absolute,
|
||||
Href: link.HREF,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return art
|
||||
}
|
||||
|
||||
// Tag is the overall view of tag
|
||||
type Tag struct {
|
||||
tag.Tag
|
||||
@ -47,15 +105,16 @@ type ResourceLink struct {
|
||||
|
||||
// Option is used to specify the properties returned when listing/getting artifacts
|
||||
type Option struct {
|
||||
WithTag bool
|
||||
TagOption *TagOption // only works when WithTag is set to true
|
||||
WithScanResult bool
|
||||
WithSignature bool // TODO move it to TagOption?
|
||||
WithTag bool
|
||||
TagOption *TagOption // only works when WithTag is set to true
|
||||
WithLabel bool
|
||||
WithScanOverview bool
|
||||
// TODO move it to TagOption?
|
||||
WithSignature bool
|
||||
}
|
||||
|
||||
// TagOption is used to specify the properties returned when listing/getting tags
|
||||
type TagOption struct {
|
||||
WithLabel bool
|
||||
WithImmutableStatus bool
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,8 @@ func (r *Reference) From(ref *dao.ArtifactReference) {
|
||||
r.ParentID = ref.ParentID
|
||||
r.ChildID = ref.ChildID
|
||||
if len(ref.Platform) > 0 {
|
||||
if err := json.Unmarshal([]byte(ref.Platform), r); err != nil {
|
||||
r.Platform = &v1.Platform{}
|
||||
if err := json.Unmarshal([]byte(ref.Platform), r.Platform); err != nil {
|
||||
log.Errorf("failed to unmarshal the platform of reference: %v", err)
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ package repository
|
||||
import (
|
||||
"context"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||
"github.com/goharbor/harbor/src/pkg/q"
|
||||
"github.com/goharbor/harbor/src/pkg/repository/dao"
|
||||
)
|
||||
@ -30,6 +31,8 @@ type Manager interface {
|
||||
List(ctx context.Context, query *q.Query) (total int64, repositories []*models.RepoRecord, err error)
|
||||
// Get the repository specified by ID
|
||||
Get(ctx context.Context, id int64) (repository *models.RepoRecord, err error)
|
||||
// GetByName gets the repository specified by name
|
||||
GetByName(ctx context.Context, name string) (repository *models.RepoRecord, err error)
|
||||
// Create a repository
|
||||
Create(ctx context.Context, repository *models.RepoRecord) (id int64, err error)
|
||||
// Delete the repository specified by ID
|
||||
@ -65,6 +68,22 @@ func (m *manager) Get(ctx context.Context, id int64) (*models.RepoRecord, error)
|
||||
return m.dao.Get(ctx, id)
|
||||
}
|
||||
|
||||
func (m *manager) GetByName(ctx context.Context, name string) (repository *models.RepoRecord, err error) {
|
||||
_, repositories, err := m.List(ctx, &q.Query{
|
||||
Keywords: map[string]interface{}{
|
||||
"Name": name,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(repositories) == 0 {
|
||||
return nil, ierror.New(nil).WithCode(ierror.NotFoundCode).
|
||||
WithMessage("repository %s not found", name)
|
||||
}
|
||||
return repositories[0], nil
|
||||
}
|
||||
|
||||
func (m *manager) Create(ctx context.Context, repository *models.RepoRecord) (int64, error) {
|
||||
return m.dao.Create(ctx, repository)
|
||||
}
|
||||
|
@ -95,6 +95,21 @@ func (m *managerTestSuite) TestGet() {
|
||||
m.Equal(repository.RepositoryID, repo.RepositoryID)
|
||||
}
|
||||
|
||||
func (m *managerTestSuite) TestGetByName() {
|
||||
repository := &models.RepoRecord{
|
||||
RepositoryID: 1,
|
||||
ProjectID: 1,
|
||||
Name: "library/hello-world",
|
||||
}
|
||||
m.dao.On("Count", mock.Anything).Return(1, nil)
|
||||
m.dao.On("List", mock.Anything).Return([]*models.RepoRecord{repository}, nil)
|
||||
repo, err := m.mgr.GetByName(nil, "library/hello-world")
|
||||
m.Require().Nil(err)
|
||||
m.dao.AssertExpectations(m.T())
|
||||
m.Require().NotNil(repo)
|
||||
m.Equal(repository.RepositoryID, repo.RepositoryID)
|
||||
}
|
||||
|
||||
func (m *managerTestSuite) TestCreate() {
|
||||
m.dao.On("Create", mock.Anything).Return(1, nil)
|
||||
id, err := m.mgr.Create(nil, &models.RepoRecord{
|
||||
|
@ -16,32 +16,98 @@ package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"fmt"
|
||||
"github.com/go-openapi/runtime/middleware"
|
||||
"github.com/goharbor/harbor/src/api/artifact"
|
||||
"github.com/goharbor/harbor/src/pkg/project"
|
||||
"github.com/goharbor/harbor/src/pkg/q"
|
||||
"github.com/goharbor/harbor/src/pkg/repository"
|
||||
"github.com/goharbor/harbor/src/server/v2.0/models"
|
||||
operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/artifact"
|
||||
)
|
||||
|
||||
// ArtifactAPI the api implemention of artifacts
|
||||
type ArtifactAPI struct {
|
||||
BaseAPI
|
||||
func newArtifactAPI() *artifactAPI {
|
||||
return &artifactAPI{
|
||||
artCtl: artifact.Ctl,
|
||||
proMgr: project.Mgr,
|
||||
repoMgr: repository.Mgr,
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteArtifact ...
|
||||
func (api *ArtifactAPI) DeleteArtifact(ctx context.Context, params operation.DeleteArtifactParams) middleware.Responder {
|
||||
type artifactAPI struct {
|
||||
BaseAPI
|
||||
artCtl artifact.Controller
|
||||
proMgr project.Manager
|
||||
repoMgr repository.Manager
|
||||
}
|
||||
|
||||
// TODO do auth in a separate middleware
|
||||
|
||||
func (a *artifactAPI) ListArtifacts(ctx context.Context, params operation.ListArtifactsParams) middleware.Responder {
|
||||
// set query
|
||||
query := &q.Query{
|
||||
Keywords: map[string]interface{}{},
|
||||
}
|
||||
if params.Type != nil {
|
||||
query.Keywords["Type"] = *(params.Type)
|
||||
}
|
||||
if params.Page != nil {
|
||||
query.PageNumber = *(params.Page)
|
||||
}
|
||||
if params.PageSize != nil {
|
||||
query.PageSize = *(params.PageSize)
|
||||
}
|
||||
repository, err := a.repoMgr.GetByName(ctx, fmt.Sprintf("%s/%s", params.ProjectName, params.RepositoryName))
|
||||
if err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
query.Keywords["RepositoryID"] = repository.RepositoryID
|
||||
|
||||
// set option
|
||||
option := &artifact.Option{
|
||||
WithTag: true, // return the tag by default
|
||||
}
|
||||
if params.WithTag != nil {
|
||||
option.WithTag = *(params.WithTag)
|
||||
}
|
||||
if option.WithTag {
|
||||
if params.WithImmutableStatus != nil {
|
||||
option.TagOption = &artifact.TagOption{
|
||||
WithImmutableStatus: *(params.WithImmutableStatus),
|
||||
}
|
||||
}
|
||||
}
|
||||
if params.WithLabel != nil {
|
||||
option.WithLabel = *(params.WithLabel)
|
||||
}
|
||||
if params.WithScanOverview != nil {
|
||||
option.WithScanOverview = *(params.WithScanOverview)
|
||||
}
|
||||
if params.WithSignatrue != nil {
|
||||
option.WithSignature = *(params.WithSignatrue)
|
||||
}
|
||||
|
||||
// list artifacts according to the query and option
|
||||
total, arts, err := a.artCtl.List(ctx, query, option)
|
||||
if err != nil {
|
||||
return a.SendError(ctx, err)
|
||||
}
|
||||
|
||||
var artifacts []*models.Artifact
|
||||
for _, art := range arts {
|
||||
artifacts = append(artifacts, art.ToSwagger())
|
||||
}
|
||||
|
||||
// TODO add link header
|
||||
return operation.NewListArtifactsOK().WithXTotalCount(total).WithLink("").WithPayload(artifacts)
|
||||
}
|
||||
|
||||
func (a *artifactAPI) GetArtifact(ctx context.Context, params operation.GetArtifactParams) middleware.Responder {
|
||||
// TODO implement
|
||||
return operation.NewGetArtifactOK()
|
||||
}
|
||||
|
||||
func (a *artifactAPI) DeleteArtifact(ctx context.Context, params operation.DeleteArtifactParams) middleware.Responder {
|
||||
// TODO implement
|
||||
return operation.NewDeleteArtifactOK()
|
||||
}
|
||||
|
||||
// ListArtifacts ...
|
||||
func (api *ArtifactAPI) ListArtifacts(ctx context.Context, params operation.ListArtifactsParams) middleware.Responder {
|
||||
return operation.NewListArtifactsOK()
|
||||
}
|
||||
|
||||
// ReadArtifact ...
|
||||
func (api *ArtifactAPI) ReadArtifact(ctx context.Context, params operation.ReadArtifactParams) middleware.Responder {
|
||||
return operation.NewReadArtifactOK()
|
||||
}
|
||||
|
||||
// NewArtifactAPI returns API of artifacts
|
||||
func NewArtifactAPI() *ArtifactAPI {
|
||||
return &ArtifactAPI{}
|
||||
}
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
package handler
|
||||
|
||||
// TODO move this file out of v2.0 folder as this is common for all versions of API
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
|
@ -30,7 +30,7 @@ import (
|
||||
// New returns http handler for API V2.0
|
||||
func New() http.Handler {
|
||||
h, api, err := restapi.HandlerAPI(restapi.Config{
|
||||
ArtifactAPI: NewArtifactAPI(),
|
||||
ArtifactAPI: newArtifactAPI(),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -30,13 +30,21 @@ type FakeArtifactManager struct {
|
||||
// List ...
|
||||
func (f *FakeArtifactManager) List(ctx context.Context, query *q.Query) (int64, []*artifact.Artifact, error) {
|
||||
args := f.Called()
|
||||
return int64(args.Int(0)), args.Get(1).([]*artifact.Artifact), args.Error(2)
|
||||
var artifacts []*artifact.Artifact
|
||||
if args.Get(1) != nil {
|
||||
artifacts = args.Get(1).([]*artifact.Artifact)
|
||||
}
|
||||
return int64(args.Int(0)), artifacts, args.Error(2)
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (f *FakeArtifactManager) Get(ctx context.Context, id int64) (*artifact.Artifact, error) {
|
||||
args := f.Called()
|
||||
return args.Get(0).(*artifact.Artifact), args.Error(1)
|
||||
var art *artifact.Artifact
|
||||
if args.Get(0) != nil {
|
||||
art = args.Get(0).(*artifact.Artifact)
|
||||
}
|
||||
return art, args.Error(1)
|
||||
}
|
||||
|
||||
// Create ...
|
||||
|
@ -29,13 +29,31 @@ type FakeRepositoryManager struct {
|
||||
// List ...
|
||||
func (f *FakeRepositoryManager) List(ctx context.Context, query *q.Query) (int64, []*models.RepoRecord, error) {
|
||||
args := f.Called()
|
||||
return int64(args.Int(0)), args.Get(1).([]*models.RepoRecord), args.Error(2)
|
||||
var repositories []*models.RepoRecord
|
||||
if args.Get(1) != nil {
|
||||
repositories = args.Get(1).([]*models.RepoRecord)
|
||||
}
|
||||
return int64(args.Int(0)), repositories, args.Error(2)
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (f *FakeRepositoryManager) Get(ctx context.Context, id int64) (*models.RepoRecord, error) {
|
||||
args := f.Called()
|
||||
return args.Get(0).(*models.RepoRecord), args.Error(1)
|
||||
var repository *models.RepoRecord
|
||||
if args.Get(0) != nil {
|
||||
repository = args.Get(0).(*models.RepoRecord)
|
||||
}
|
||||
return repository, args.Error(1)
|
||||
}
|
||||
|
||||
// GetByName ...
|
||||
func (f *FakeRepositoryManager) GetByName(ctx context.Context, name string) (*models.RepoRecord, error) {
|
||||
args := f.Called()
|
||||
var repository *models.RepoRecord
|
||||
if args.Get(0) != nil {
|
||||
repository = args.Get(0).(*models.RepoRecord)
|
||||
}
|
||||
return repository, args.Error(1)
|
||||
}
|
||||
|
||||
// Delete ...
|
||||
|
@ -29,13 +29,21 @@ type FakeTagManager struct {
|
||||
// List ...
|
||||
func (f *FakeTagManager) List(ctx context.Context, query *q.Query) (int64, []*tag.Tag, error) {
|
||||
args := f.Called()
|
||||
return int64(args.Int(0)), args.Get(1).([]*tag.Tag), args.Error(2)
|
||||
var tags []*tag.Tag
|
||||
if args.Get(1) != nil {
|
||||
tags = args.Get(1).([]*tag.Tag)
|
||||
}
|
||||
return int64(args.Int(0)), tags, args.Error(2)
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (f *FakeTagManager) Get(ctx context.Context, id int64) (*tag.Tag, error) {
|
||||
args := f.Called()
|
||||
return args.Get(0).(*tag.Tag), args.Error(1)
|
||||
var tg *tag.Tag
|
||||
if args.Get(0) != nil {
|
||||
tg = args.Get(0).(*tag.Tag)
|
||||
}
|
||||
return tg, args.Error(1)
|
||||
}
|
||||
|
||||
// Create ...
|
||||
|
Loading…
Reference in New Issue
Block a user