Merge pull request #10662 from ywk253100/200206_delete_repo

Implement repository deletion API
This commit is contained in:
Wang Yan 2020-02-07 17:51:03 +08:00 committed by GitHub
commit 6bad9f62ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 118 additions and 1 deletions

View File

@ -227,6 +227,28 @@ paths:
$ref: '#/responses/404' $ref: '#/responses/404'
'500': '500':
$ref: '#/responses/500' $ref: '#/responses/500'
/projects/{project_name}/repositories/{repository_name}:
delete:
summary: Delete repository
description: Delete the repository specified by name
tags:
- repository
operationId: deleteRepository
parameters:
- $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectName'
- $ref: '#/parameters/repositoryName'
responses:
'200':
$ref: '#/responses/200'
'401':
$ref: '#/responses/401'
'403':
$ref: '#/responses/403'
'404':
$ref: '#/responses/404'
'500':
$ref: '#/responses/500'
parameters: parameters:
requestId: requestId:
name: X-Request-Id name: X-Request-Id

View File

@ -295,6 +295,7 @@ func (c *controller) Delete(ctx context.Context, id int64) error {
} }
func (c *controller) CreateTag(ctx context.Context, tag *Tag) (int64, error) { func (c *controller) CreateTag(ctx context.Context, tag *Tag) (int64, error) {
// TODO fire event
return c.tagMgr.Create(ctx, &(tag.Tag)) return c.tagMgr.Create(ctx, &(tag.Tag))
} }
func (c *controller) ListTags(ctx context.Context, query *q.Query, option *TagOption) (int64, []*Tag, error) { func (c *controller) ListTags(ctx context.Context, query *q.Query, option *TagOption) (int64, []*Tag, error) {

View File

@ -16,6 +16,7 @@ package repository
import ( import (
"context" "context"
"github.com/goharbor/harbor/src/api/artifact"
"github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/models"
"github.com/goharbor/harbor/src/common/utils" "github.com/goharbor/harbor/src/common/utils"
ierror "github.com/goharbor/harbor/src/internal/error" ierror "github.com/goharbor/harbor/src/internal/error"
@ -41,6 +42,8 @@ type Controller interface {
Get(ctx context.Context, id int64) (repository *models.RepoRecord, err error) Get(ctx context.Context, id int64) (repository *models.RepoRecord, err error)
// GetByName gets the repository specified by name // GetByName gets the repository specified by name
GetByName(ctx context.Context, name string) (repository *models.RepoRecord, err error) GetByName(ctx context.Context, name string) (repository *models.RepoRecord, err error)
// Delete the repository specified by ID
Delete(ctx context.Context, id int64) (err error)
} }
// NewController creates an instance of the default repository controller // NewController creates an instance of the default repository controller
@ -48,12 +51,14 @@ func NewController() Controller {
return &controller{ return &controller{
proMgr: project.Mgr, proMgr: project.Mgr,
repoMgr: repository.Mgr, repoMgr: repository.Mgr,
artCtl: artifact.Ctl,
} }
} }
type controller struct { type controller struct {
proMgr project.Manager proMgr project.Manager
repoMgr repository.Manager repoMgr repository.Manager
artCtl artifact.Controller
} }
func (c *controller) Ensure(ctx context.Context, name string) (bool, int64, error) { func (c *controller) Ensure(ctx context.Context, name string) (bool, int64, error) {
@ -108,3 +113,25 @@ func (c *controller) Get(ctx context.Context, id int64) (*models.RepoRecord, err
func (c *controller) GetByName(ctx context.Context, name string) (*models.RepoRecord, error) { func (c *controller) GetByName(ctx context.Context, name string) (*models.RepoRecord, error) {
return c.repoMgr.GetByName(ctx, name) return c.repoMgr.GetByName(ctx, name)
} }
func (c *controller) Delete(ctx context.Context, id int64) error {
// TODO auth
// TODO how to make sure the logic included by middlewares(immutable, readonly, quota, etc)
// TODO is covered when deleting the artifacts of the repository
_, artifacts, err := c.artCtl.List(ctx, &q.Query{
Keywords: map[string]interface{}{
"RepositoryID": id,
},
}, nil)
if err != nil {
return err
}
for _, artifact := range artifacts {
if err = c.artCtl.Delete(ctx, artifact.ID); err != nil {
return err
}
}
return c.repoMgr.Delete(ctx, id)
// TODO fire event
}

View File

@ -15,7 +15,9 @@
package repository package repository
import ( import (
"github.com/goharbor/harbor/src/api/artifact"
"github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/models"
artifacttesting "github.com/goharbor/harbor/src/testing/api/artifact"
"github.com/goharbor/harbor/src/testing/pkg/project" "github.com/goharbor/harbor/src/testing/pkg/project"
"github.com/goharbor/harbor/src/testing/pkg/repository" "github.com/goharbor/harbor/src/testing/pkg/repository"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
@ -27,14 +29,17 @@ type controllerTestSuite struct {
ctl *controller ctl *controller
proMgr *project.FakeManager proMgr *project.FakeManager
repoMgr *repository.FakeManager repoMgr *repository.FakeManager
artCtl *artifacttesting.FakeController
} }
func (c *controllerTestSuite) SetupTest() { func (c *controllerTestSuite) SetupTest() {
c.proMgr = &project.FakeManager{} c.proMgr = &project.FakeManager{}
c.repoMgr = &repository.FakeManager{} c.repoMgr = &repository.FakeManager{}
c.artCtl = &artifacttesting.FakeController{}
c.ctl = &controller{ c.ctl = &controller{
proMgr: c.proMgr, proMgr: c.proMgr,
repoMgr: c.repoMgr, repoMgr: c.repoMgr,
artCtl: c.artCtl,
} }
} }
@ -104,6 +109,16 @@ func (c *controllerTestSuite) TestGetByName() {
c.Equal(int64(1), repository.RepositoryID) c.Equal(int64(1), repository.RepositoryID)
} }
func (c *controllerTestSuite) TestDelete() {
art := &artifact.Artifact{}
art.ID = 1
c.artCtl.On("List").Return(1, []*artifact.Artifact{art}, nil)
c.artCtl.On("Delete").Return(nil)
c.repoMgr.On("Delete").Return(nil)
err := c.ctl.Delete(nil, 1)
c.Require().Nil(err)
}
func TestControllerTestSuite(t *testing.T) { func TestControllerTestSuite(t *testing.T) {
suite.Run(t, &controllerTestSuite{}) suite.Run(t, &controllerTestSuite{})
} }

View File

@ -30,7 +30,8 @@ import (
// New returns http handler for API V2.0 // New returns http handler for API V2.0
func New() http.Handler { func New() http.Handler {
h, api, err := restapi.HandlerAPI(restapi.Config{ h, api, err := restapi.HandlerAPI(restapi.Config{
ArtifactAPI: newArtifactAPI(), ArtifactAPI: newArtifactAPI(),
RepositoryAPI: newRepositoryAPI(),
}) })
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)

View File

@ -0,0 +1,45 @@
// Copyright Project Harbor Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package handler
import (
"context"
"fmt"
"github.com/go-openapi/runtime/middleware"
"github.com/goharbor/harbor/src/api/repository"
operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/repository"
)
func newRepositoryAPI() *repositoryAPI {
return &repositoryAPI{
repoCtl: repository.Ctl,
}
}
type repositoryAPI struct {
BaseAPI
repoCtl repository.Controller
}
func (r *repositoryAPI) DeleteRepository(ctx context.Context, params operation.DeleteRepositoryParams) middleware.Responder {
repository, err := r.repoCtl.GetByName(ctx, fmt.Sprintf("%s/%s", params.ProjectName, params.RepositoryName))
if err != nil {
return r.SendError(ctx, err)
}
if err := r.repoCtl.Delete(ctx, repository.RepositoryID); err != nil {
return r.SendError(ctx, err)
}
return operation.NewDeleteRepositoryOK()
}

View File

@ -62,3 +62,9 @@ func (f *FakeController) GetByName(ctx context.Context, name string) (*models.Re
} }
return repository, args.Error(1) return repository, args.Error(1)
} }
// Delete ...
func (f *FakeController) Delete(ctx context.Context, id int64) error {
args := f.Called()
return args.Error(0)
}