mirror of
https://github.com/goharbor/harbor
synced 2024-09-20 18:39:52 +00:00
Use the repository name of artifact model
As we store the repository name in the artifact table, we can use it direclty in the code to reduce the database query Signed-off-by: Wenkai Yin <yinw@vmware.com>
This commit is contained in:
parent
7857528e45
commit
02c2647e1e
|
@ -56,9 +56,6 @@ WHERE ordered_art.seq=1;
|
||||||
|
|
||||||
ALTER TABLE artifact DROP COLUMN tag;
|
ALTER TABLE artifact DROP COLUMN tag;
|
||||||
|
|
||||||
/*TODO: remove this after insert the repository_name when create artifact*/
|
|
||||||
ALTER TABLE artifact ALTER COLUMN repository_name DROP NOT NULL;
|
|
||||||
|
|
||||||
/*remove the duplicate artifact rows*/
|
/*remove the duplicate artifact rows*/
|
||||||
DELETE FROM artifact
|
DELETE FROM artifact
|
||||||
WHERE id NOT IN (
|
WHERE id NOT IN (
|
||||||
|
|
|
@ -25,7 +25,6 @@ import (
|
||||||
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
|
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
|
||||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
"github.com/goharbor/harbor/src/pkg/repository"
|
|
||||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -43,24 +42,18 @@ type Abstractor interface {
|
||||||
// NewAbstractor returns an instance of the default abstractor
|
// NewAbstractor returns an instance of the default abstractor
|
||||||
func NewAbstractor() Abstractor {
|
func NewAbstractor() Abstractor {
|
||||||
return &abstractor{
|
return &abstractor{
|
||||||
repoMgr: repository.Mgr,
|
|
||||||
blobFetcher: blob.Fcher,
|
blobFetcher: blob.Fcher,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type abstractor struct {
|
type abstractor struct {
|
||||||
repoMgr repository.Manager
|
|
||||||
blobFetcher blob.Fetcher
|
blobFetcher blob.Fetcher
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO add white list for supported artifact type
|
// TODO add white list for supported artifact type
|
||||||
func (a *abstractor) AbstractMetadata(ctx context.Context, artifact *artifact.Artifact) error {
|
func (a *abstractor) AbstractMetadata(ctx context.Context, artifact *artifact.Artifact) error {
|
||||||
repository, err := a.repoMgr.Get(ctx, artifact.RepositoryID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// read manifest content
|
// read manifest content
|
||||||
manifestMediaType, content, err := a.blobFetcher.FetchManifest(repository.Name, artifact.Digest)
|
manifestMediaType, content, err := a.blobFetcher.FetchManifest(artifact.RepositoryName, artifact.Digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,12 +18,10 @@ import (
|
||||||
"github.com/docker/distribution/manifest/schema1"
|
"github.com/docker/distribution/manifest/schema1"
|
||||||
"github.com/docker/distribution/manifest/schema2"
|
"github.com/docker/distribution/manifest/schema2"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
|
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
|
||||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
"github.com/goharbor/harbor/src/testing/api/artifact/abstractor/blob"
|
"github.com/goharbor/harbor/src/testing/api/artifact/abstractor/blob"
|
||||||
tresolver "github.com/goharbor/harbor/src/testing/api/artifact/abstractor/resolver"
|
tresolver "github.com/goharbor/harbor/src/testing/api/artifact/abstractor/resolver"
|
||||||
"github.com/goharbor/harbor/src/testing/pkg/repository"
|
|
||||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -203,16 +201,13 @@ type abstractorTestSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
abstractor Abstractor
|
abstractor Abstractor
|
||||||
fetcher *blob.FakeFetcher
|
fetcher *blob.FakeFetcher
|
||||||
repoMgr *repository.FakeManager
|
|
||||||
resolver *tresolver.FakeResolver
|
resolver *tresolver.FakeResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *abstractorTestSuite) SetupTest() {
|
func (a *abstractorTestSuite) SetupTest() {
|
||||||
a.fetcher = &blob.FakeFetcher{}
|
a.fetcher = &blob.FakeFetcher{}
|
||||||
a.repoMgr = &repository.FakeManager{}
|
|
||||||
a.resolver = &tresolver.FakeResolver{}
|
a.resolver = &tresolver.FakeResolver{}
|
||||||
a.abstractor = &abstractor{
|
a.abstractor = &abstractor{
|
||||||
repoMgr: a.repoMgr,
|
|
||||||
blobFetcher: a.fetcher,
|
blobFetcher: a.fetcher,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,7 +215,6 @@ func (a *abstractorTestSuite) SetupTest() {
|
||||||
// docker manifest v1
|
// docker manifest v1
|
||||||
func (a *abstractorTestSuite) TestAbstractMetadataOfV1Manifest() {
|
func (a *abstractorTestSuite) TestAbstractMetadataOfV1Manifest() {
|
||||||
resolver.Register(a.resolver, schema1.MediaTypeSignedManifest)
|
resolver.Register(a.resolver, schema1.MediaTypeSignedManifest)
|
||||||
a.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
|
|
||||||
a.fetcher.On("FetchManifest").Return(schema1.MediaTypeSignedManifest, []byte(v1Manifest), nil)
|
a.fetcher.On("FetchManifest").Return(schema1.MediaTypeSignedManifest, []byte(v1Manifest), nil)
|
||||||
a.resolver.On("ArtifactType").Return(fakeArtifactType)
|
a.resolver.On("ArtifactType").Return(fakeArtifactType)
|
||||||
a.resolver.On("ResolveMetadata").Return(nil)
|
a.resolver.On("ResolveMetadata").Return(nil)
|
||||||
|
@ -238,7 +232,6 @@ func (a *abstractorTestSuite) TestAbstractMetadataOfV1Manifest() {
|
||||||
// docker manifest v2
|
// docker manifest v2
|
||||||
func (a *abstractorTestSuite) TestAbstractMetadataOfV2Manifest() {
|
func (a *abstractorTestSuite) TestAbstractMetadataOfV2Manifest() {
|
||||||
resolver.Register(a.resolver, schema2.MediaTypeImageConfig)
|
resolver.Register(a.resolver, schema2.MediaTypeImageConfig)
|
||||||
a.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
|
|
||||||
a.fetcher.On("FetchManifest").Return(schema2.MediaTypeManifest, []byte(v2Manifest), nil)
|
a.fetcher.On("FetchManifest").Return(schema2.MediaTypeManifest, []byte(v2Manifest), nil)
|
||||||
a.resolver.On("ArtifactType").Return(fakeArtifactType)
|
a.resolver.On("ArtifactType").Return(fakeArtifactType)
|
||||||
a.resolver.On("ResolveMetadata").Return(nil)
|
a.resolver.On("ResolveMetadata").Return(nil)
|
||||||
|
@ -257,7 +250,6 @@ func (a *abstractorTestSuite) TestAbstractMetadataOfV2Manifest() {
|
||||||
// OCI index
|
// OCI index
|
||||||
func (a *abstractorTestSuite) TestAbstractMetadataOfIndex() {
|
func (a *abstractorTestSuite) TestAbstractMetadataOfIndex() {
|
||||||
resolver.Register(a.resolver, v1.MediaTypeImageIndex)
|
resolver.Register(a.resolver, v1.MediaTypeImageIndex)
|
||||||
a.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
|
|
||||||
a.fetcher.On("FetchManifest").Return(v1.MediaTypeImageIndex, []byte(index), nil)
|
a.fetcher.On("FetchManifest").Return(v1.MediaTypeImageIndex, []byte(index), nil)
|
||||||
a.resolver.On("ArtifactType").Return(fakeArtifactType)
|
a.resolver.On("ArtifactType").Return(fakeArtifactType)
|
||||||
a.resolver.On("ResolveMetadata").Return(nil)
|
a.resolver.On("ResolveMetadata").Return(nil)
|
||||||
|
@ -275,7 +267,6 @@ func (a *abstractorTestSuite) TestAbstractMetadataOfIndex() {
|
||||||
|
|
||||||
// OCI index
|
// OCI index
|
||||||
func (a *abstractorTestSuite) TestAbstractMetadataOfUnsupported() {
|
func (a *abstractorTestSuite) TestAbstractMetadataOfUnsupported() {
|
||||||
a.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
|
|
||||||
a.fetcher.On("FetchManifest").Return("unsupported-manifest", []byte{}, nil)
|
a.fetcher.On("FetchManifest").Return("unsupported-manifest", []byte{}, nil)
|
||||||
artifact := &artifact.Artifact{
|
artifact := &artifact.Artifact{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
|
|
|
@ -24,7 +24,6 @@ import (
|
||||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
"github.com/goharbor/harbor/src/pkg/chart"
|
"github.com/goharbor/harbor/src/pkg/chart"
|
||||||
"github.com/goharbor/harbor/src/pkg/repository"
|
|
||||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -41,7 +40,6 @@ const (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
resolver := &resolver{
|
resolver := &resolver{
|
||||||
repoMgr: repository.Mgr,
|
|
||||||
blobFetcher: blob.Fcher,
|
blobFetcher: blob.Fcher,
|
||||||
chartOperator: chart.Optr,
|
chartOperator: chart.Optr,
|
||||||
}
|
}
|
||||||
|
@ -56,22 +54,17 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type resolver struct {
|
type resolver struct {
|
||||||
repoMgr repository.Manager
|
|
||||||
blobFetcher blob.Fetcher
|
blobFetcher blob.Fetcher
|
||||||
chartOperator chart.Operator
|
chartOperator chart.Operator
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *resolver) ResolveMetadata(ctx context.Context, manifest []byte, artifact *artifact.Artifact) error {
|
func (r *resolver) ResolveMetadata(ctx context.Context, manifest []byte, artifact *artifact.Artifact) error {
|
||||||
repository, err := r.repoMgr.Get(ctx, artifact.RepositoryID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
m := &v1.Manifest{}
|
m := &v1.Manifest{}
|
||||||
if err := json.Unmarshal(manifest, m); err != nil {
|
if err := json.Unmarshal(manifest, m); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
digest := m.Config.Digest.String()
|
digest := m.Config.Digest.String()
|
||||||
layer, err := r.blobFetcher.FetchLayer(repository.Name, digest)
|
layer, err := r.blobFetcher.FetchLayer(artifact.RepositoryName, digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -95,11 +88,7 @@ func (r *resolver) ResolveAddition(ctx context.Context, artifact *artifact.Artif
|
||||||
WithMessage("addition %s isn't supported for %s", addition, ArtifactTypeChart)
|
WithMessage("addition %s isn't supported for %s", addition, ArtifactTypeChart)
|
||||||
}
|
}
|
||||||
|
|
||||||
repository, err := r.repoMgr.Get(ctx, artifact.RepositoryID)
|
_, content, err := r.blobFetcher.FetchManifest(artifact.RepositoryName, artifact.Digest)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
_, content, err := r.blobFetcher.FetchManifest(repository.Name, artifact.Digest)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -112,7 +101,7 @@ func (r *resolver) ResolveAddition(ctx context.Context, artifact *artifact.Artif
|
||||||
// chart do have two layers, one is config, we should resolve the other one.
|
// chart do have two layers, one is config, we should resolve the other one.
|
||||||
layerDgst := layer.Digest.String()
|
layerDgst := layer.Digest.String()
|
||||||
if layerDgst != manifest.Config.Digest.String() {
|
if layerDgst != manifest.Config.Digest.String() {
|
||||||
content, err = r.blobFetcher.FetchLayer(repository.Name, layerDgst)
|
content, err = r.blobFetcher.FetchLayer(artifact.RepositoryName, layerDgst)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,13 +15,11 @@
|
||||||
package chart
|
package chart
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
|
||||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
chartserver "github.com/goharbor/harbor/src/pkg/chart"
|
chartserver "github.com/goharbor/harbor/src/pkg/chart"
|
||||||
"github.com/goharbor/harbor/src/testing/api/artifact/abstractor/blob"
|
"github.com/goharbor/harbor/src/testing/api/artifact/abstractor/blob"
|
||||||
"github.com/goharbor/harbor/src/testing/pkg/chart"
|
"github.com/goharbor/harbor/src/testing/pkg/chart"
|
||||||
"github.com/goharbor/harbor/src/testing/pkg/repository"
|
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"k8s.io/helm/pkg/chartutil"
|
"k8s.io/helm/pkg/chartutil"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -30,17 +28,14 @@ import (
|
||||||
type resolverTestSuite struct {
|
type resolverTestSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
resolver *resolver
|
resolver *resolver
|
||||||
repoMgr *repository.FakeManager
|
|
||||||
blobFetcher *blob.FakeFetcher
|
blobFetcher *blob.FakeFetcher
|
||||||
chartOptr *chart.FakeOpertaor
|
chartOptr *chart.FakeOpertaor
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *resolverTestSuite) SetupTest() {
|
func (r *resolverTestSuite) SetupTest() {
|
||||||
r.repoMgr = &repository.FakeManager{}
|
|
||||||
r.blobFetcher = &blob.FakeFetcher{}
|
r.blobFetcher = &blob.FakeFetcher{}
|
||||||
r.chartOptr = &chart.FakeOpertaor{}
|
r.chartOptr = &chart.FakeOpertaor{}
|
||||||
r.resolver = &resolver{
|
r.resolver = &resolver{
|
||||||
repoMgr: r.repoMgr,
|
|
||||||
blobFetcher: r.blobFetcher,
|
blobFetcher: r.blobFetcher,
|
||||||
chartOperator: r.chartOptr,
|
chartOperator: r.chartOptr,
|
||||||
}
|
}
|
||||||
|
@ -92,11 +87,9 @@ func (r *resolverTestSuite) TestResolveMetadata() {
|
||||||
"appVersion": "1.8.2"
|
"appVersion": "1.8.2"
|
||||||
}`
|
}`
|
||||||
artifact := &artifact.Artifact{}
|
artifact := &artifact.Artifact{}
|
||||||
r.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
|
|
||||||
r.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
|
r.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
|
||||||
err := r.resolver.ResolveMetadata(nil, []byte(content), artifact)
|
err := r.resolver.ResolveMetadata(nil, []byte(content), artifact)
|
||||||
r.Require().Nil(err)
|
r.Require().Nil(err)
|
||||||
r.repoMgr.AssertExpectations(r.T())
|
|
||||||
r.blobFetcher.AssertExpectations(r.T())
|
r.blobFetcher.AssertExpectations(r.T())
|
||||||
r.Assert().Equal("1.1.2", artifact.ExtraAttrs["version"].(string))
|
r.Assert().Equal("1.1.2", artifact.ExtraAttrs["version"].(string))
|
||||||
r.Assert().Equal("1.8.2", artifact.ExtraAttrs["appVersion"].(string))
|
r.Assert().Equal("1.8.2", artifact.ExtraAttrs["appVersion"].(string))
|
||||||
|
@ -158,7 +151,6 @@ func (r *resolverTestSuite) TestResolveAddition() {
|
||||||
}
|
}
|
||||||
|
|
||||||
artifact := &artifact.Artifact{}
|
artifact := &artifact.Artifact{}
|
||||||
r.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
|
|
||||||
r.blobFetcher.On("FetchManifest").Return("", []byte(chartManifest), nil)
|
r.blobFetcher.On("FetchManifest").Return("", []byte(chartManifest), nil)
|
||||||
r.blobFetcher.On("FetchLayer").Return([]byte(chartYaml), nil)
|
r.blobFetcher.On("FetchLayer").Return([]byte(chartYaml), nil)
|
||||||
r.chartOptr.On("GetDetails").Return(chartDetails, nil)
|
r.chartOptr.On("GetDetails").Return(chartDetails, nil)
|
||||||
|
|
|
@ -23,7 +23,6 @@ import (
|
||||||
"github.com/goharbor/harbor/src/common/utils/log"
|
"github.com/goharbor/harbor/src/common/utils/log"
|
||||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
"github.com/goharbor/harbor/src/pkg/repository"
|
|
||||||
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
v1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,7 +34,6 @@ const (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
resolver := &resolver{
|
resolver := &resolver{
|
||||||
repoMgr: repository.Mgr,
|
|
||||||
argMgr: artifact.Mgr,
|
argMgr: artifact.Mgr,
|
||||||
blobFetcher: blob.Fcher,
|
blobFetcher: blob.Fcher,
|
||||||
}
|
}
|
||||||
|
@ -50,7 +48,6 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type resolver struct {
|
type resolver struct {
|
||||||
repoMgr repository.Manager
|
|
||||||
argMgr artifact.Manager
|
argMgr artifact.Manager
|
||||||
blobFetcher blob.Fetcher
|
blobFetcher blob.Fetcher
|
||||||
}
|
}
|
||||||
|
@ -65,7 +62,7 @@ func (r *resolver) ResolveMetadata(ctx context.Context, manifest []byte, art *ar
|
||||||
for _, mani := range index.Manifests {
|
for _, mani := range index.Manifests {
|
||||||
digest := mani.Digest.String()
|
digest := mani.Digest.String()
|
||||||
// make sure the child artifact exist
|
// make sure the child artifact exist
|
||||||
ar, err := r.argMgr.GetByDigest(ctx, art.RepositoryID, digest)
|
ar, err := r.argMgr.GetByDigest(ctx, art.RepositoryName, digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -84,12 +81,8 @@ func (r *resolver) ResolveMetadata(ctx context.Context, manifest []byte, art *ar
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve the config of CNAB
|
// resolve the config of CNAB
|
||||||
repository, err := r.repoMgr.Get(ctx, art.RepositoryID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// get the manifest that the config layer is referenced by
|
// get the manifest that the config layer is referenced by
|
||||||
_, cfgMani, err := r.blobFetcher.FetchManifest(repository.Name, cfgManiDgt)
|
_, cfgMani, err := r.blobFetcher.FetchManifest(art.RepositoryName, cfgManiDgt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -99,7 +92,7 @@ func (r *resolver) ResolveMetadata(ctx context.Context, manifest []byte, art *ar
|
||||||
}
|
}
|
||||||
cfgDgt := m.Config.Digest.String()
|
cfgDgt := m.Config.Digest.String()
|
||||||
// get the config layer
|
// get the config layer
|
||||||
cfg, err := r.blobFetcher.FetchLayer(repository.Name, cfgDgt)
|
cfg, err := r.blobFetcher.FetchLayer(art.RepositoryName, cfgDgt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,10 @@
|
||||||
package cnab
|
package cnab
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
|
||||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
"github.com/goharbor/harbor/src/testing/api/artifact/abstractor/blob"
|
"github.com/goharbor/harbor/src/testing/api/artifact/abstractor/blob"
|
||||||
testingartifact "github.com/goharbor/harbor/src/testing/pkg/artifact"
|
testingartifact "github.com/goharbor/harbor/src/testing/pkg/artifact"
|
||||||
"github.com/goharbor/harbor/src/testing/pkg/repository"
|
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -28,17 +26,14 @@ import (
|
||||||
type resolverTestSuite struct {
|
type resolverTestSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
resolver *resolver
|
resolver *resolver
|
||||||
repoMgr *repository.FakeManager
|
|
||||||
artMgr *testingartifact.FakeManager
|
artMgr *testingartifact.FakeManager
|
||||||
blobFetcher *blob.FakeFetcher
|
blobFetcher *blob.FakeFetcher
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *resolverTestSuite) SetupTest() {
|
func (r *resolverTestSuite) SetupTest() {
|
||||||
r.repoMgr = &repository.FakeManager{}
|
|
||||||
r.artMgr = &testingartifact.FakeManager{}
|
r.artMgr = &testingartifact.FakeManager{}
|
||||||
r.blobFetcher = &blob.FakeFetcher{}
|
r.blobFetcher = &blob.FakeFetcher{}
|
||||||
r.resolver = &resolver{
|
r.resolver = &resolver{
|
||||||
repoMgr: r.repoMgr,
|
|
||||||
argMgr: r.artMgr,
|
argMgr: r.artMgr,
|
||||||
blobFetcher: r.blobFetcher,
|
blobFetcher: r.blobFetcher,
|
||||||
}
|
}
|
||||||
|
@ -115,7 +110,6 @@ func (r *resolverTestSuite) TestResolveMetadata() {
|
||||||
}`
|
}`
|
||||||
art := &artifact.Artifact{}
|
art := &artifact.Artifact{}
|
||||||
r.artMgr.On("GetByDigest").Return(&artifact.Artifact{ID: 1}, nil)
|
r.artMgr.On("GetByDigest").Return(&artifact.Artifact{ID: 1}, nil)
|
||||||
r.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
|
|
||||||
r.blobFetcher.On("FetchManifest").Return("", []byte(manifest), nil)
|
r.blobFetcher.On("FetchManifest").Return("", []byte(manifest), nil)
|
||||||
r.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
|
r.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
|
||||||
err := r.resolver.ResolveMetadata(nil, []byte(index), art)
|
err := r.resolver.ResolveMetadata(nil, []byte(index), art)
|
||||||
|
|
|
@ -58,7 +58,7 @@ func (i *indexResolver) ResolveMetadata(ctx context.Context, manifest []byte, ar
|
||||||
for _, mani := range index.Manifests {
|
for _, mani := range index.Manifests {
|
||||||
digest := mani.Digest.String()
|
digest := mani.Digest.String()
|
||||||
// make sure the child artifact exist
|
// make sure the child artifact exist
|
||||||
ar, err := i.artMgr.GetByDigest(ctx, art.RepositoryID, digest)
|
ar, err := i.artMgr.GetByDigest(ctx, art.RepositoryName, digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"github.com/goharbor/harbor/src/common/utils/log"
|
"github.com/goharbor/harbor/src/common/utils/log"
|
||||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
"github.com/goharbor/harbor/src/pkg/repository"
|
|
||||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -37,7 +36,6 @@ const (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rslver := &manifestV2Resolver{
|
rslver := &manifestV2Resolver{
|
||||||
repoMgr: repository.Mgr,
|
|
||||||
blobFetcher: blob.Fcher,
|
blobFetcher: blob.Fcher,
|
||||||
}
|
}
|
||||||
mediaTypes := []string{
|
mediaTypes := []string{
|
||||||
|
@ -56,21 +54,16 @@ func init() {
|
||||||
|
|
||||||
// manifestV2Resolver resolve artifact with OCI manifest and docker v2 manifest
|
// manifestV2Resolver resolve artifact with OCI manifest and docker v2 manifest
|
||||||
type manifestV2Resolver struct {
|
type manifestV2Resolver struct {
|
||||||
repoMgr repository.Manager
|
|
||||||
blobFetcher blob.Fetcher
|
blobFetcher blob.Fetcher
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manifestV2Resolver) ResolveMetadata(ctx context.Context, content []byte, artifact *artifact.Artifact) error {
|
func (m *manifestV2Resolver) ResolveMetadata(ctx context.Context, content []byte, artifact *artifact.Artifact) error {
|
||||||
repository, err := m.repoMgr.Get(ctx, artifact.RepositoryID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
manifest := &v1.Manifest{}
|
manifest := &v1.Manifest{}
|
||||||
if err := json.Unmarshal(content, manifest); err != nil {
|
if err := json.Unmarshal(content, manifest); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
digest := manifest.Config.Digest.String()
|
digest := manifest.Config.Digest.String()
|
||||||
layer, err := m.blobFetcher.FetchLayer(repository.Name, digest)
|
layer, err := m.blobFetcher.FetchLayer(artifact.RepositoryName, digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -93,11 +86,7 @@ func (m *manifestV2Resolver) ResolveAddition(ctx context.Context, artifact *arti
|
||||||
return nil, ierror.New(nil).WithCode(ierror.BadRequestCode).
|
return nil, ierror.New(nil).WithCode(ierror.BadRequestCode).
|
||||||
WithMessage("addition %s isn't supported for %s(manifest version 2)", addition, ArtifactTypeImage)
|
WithMessage("addition %s isn't supported for %s(manifest version 2)", addition, ArtifactTypeImage)
|
||||||
}
|
}
|
||||||
repository, err := m.repoMgr.Get(ctx, artifact.RepositoryID)
|
_, content, err := m.blobFetcher.FetchManifest(artifact.RepositoryName, artifact.Digest)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
_, content, err := m.blobFetcher.FetchManifest(repository.Name, artifact.Digest)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -105,7 +94,7 @@ func (m *manifestV2Resolver) ResolveAddition(ctx context.Context, artifact *arti
|
||||||
if err := json.Unmarshal(content, manifest); err != nil {
|
if err := json.Unmarshal(content, manifest); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
content, err = m.blobFetcher.FetchLayer(repository.Name, manifest.Config.Digest.String())
|
content, err = m.blobFetcher.FetchLayer(artifact.RepositoryName, manifest.Config.Digest.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,9 @@
|
||||||
package image
|
package image
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
|
||||||
ierror "github.com/goharbor/harbor/src/internal/error"
|
ierror "github.com/goharbor/harbor/src/internal/error"
|
||||||
"github.com/goharbor/harbor/src/pkg/artifact"
|
"github.com/goharbor/harbor/src/pkg/artifact"
|
||||||
"github.com/goharbor/harbor/src/testing/api/artifact/abstractor/blob"
|
"github.com/goharbor/harbor/src/testing/api/artifact/abstractor/blob"
|
||||||
"github.com/goharbor/harbor/src/testing/pkg/repository"
|
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -123,15 +121,12 @@ var (
|
||||||
type manifestV2ResolverTestSuite struct {
|
type manifestV2ResolverTestSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
resolver *manifestV2Resolver
|
resolver *manifestV2Resolver
|
||||||
repoMgr *repository.FakeManager
|
|
||||||
blobFetcher *blob.FakeFetcher
|
blobFetcher *blob.FakeFetcher
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manifestV2ResolverTestSuite) SetupTest() {
|
func (m *manifestV2ResolverTestSuite) SetupTest() {
|
||||||
m.repoMgr = &repository.FakeManager{}
|
|
||||||
m.blobFetcher = &blob.FakeFetcher{}
|
m.blobFetcher = &blob.FakeFetcher{}
|
||||||
m.resolver = &manifestV2Resolver{
|
m.resolver = &manifestV2Resolver{
|
||||||
repoMgr: m.repoMgr,
|
|
||||||
blobFetcher: m.blobFetcher,
|
blobFetcher: m.blobFetcher,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,11 +134,9 @@ func (m *manifestV2ResolverTestSuite) SetupTest() {
|
||||||
|
|
||||||
func (m *manifestV2ResolverTestSuite) TestResolveMetadata() {
|
func (m *manifestV2ResolverTestSuite) TestResolveMetadata() {
|
||||||
artifact := &artifact.Artifact{}
|
artifact := &artifact.Artifact{}
|
||||||
m.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
|
|
||||||
m.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
|
m.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
|
||||||
err := m.resolver.ResolveMetadata(nil, []byte(manifest), artifact)
|
err := m.resolver.ResolveMetadata(nil, []byte(manifest), artifact)
|
||||||
m.Require().Nil(err)
|
m.Require().Nil(err)
|
||||||
m.repoMgr.AssertExpectations(m.T())
|
|
||||||
m.blobFetcher.AssertExpectations(m.T())
|
m.blobFetcher.AssertExpectations(m.T())
|
||||||
m.Assert().Equal("amd64", artifact.ExtraAttrs["architecture"].(string))
|
m.Assert().Equal("amd64", artifact.ExtraAttrs["architecture"].(string))
|
||||||
m.Assert().Equal("linux", artifact.ExtraAttrs["os"].(string))
|
m.Assert().Equal("linux", artifact.ExtraAttrs["os"].(string))
|
||||||
|
@ -156,7 +149,6 @@ func (m *manifestV2ResolverTestSuite) TestResolveAddition() {
|
||||||
|
|
||||||
// build history
|
// build history
|
||||||
artifact := &artifact.Artifact{}
|
artifact := &artifact.Artifact{}
|
||||||
m.repoMgr.On("Get").Return(&models.RepoRecord{}, nil)
|
|
||||||
m.blobFetcher.On("FetchManifest").Return("", []byte(manifest), nil)
|
m.blobFetcher.On("FetchManifest").Return("", []byte(manifest), nil)
|
||||||
m.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
|
m.blobFetcher.On("FetchLayer").Return([]byte(config), nil)
|
||||||
addition, err := m.resolver.ResolveAddition(nil, artifact, AdditionTypeBuildHistory)
|
addition, err := m.resolver.ResolveAddition(nil, artifact, AdditionTypeBuildHistory)
|
||||||
|
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"github.com/goharbor/harbor/src/api/artifact/abstractor"
|
"github.com/goharbor/harbor/src/api/artifact/abstractor"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
|
"github.com/goharbor/harbor/src/api/artifact/abstractor/resolver"
|
||||||
"github.com/goharbor/harbor/src/api/artifact/descriptor"
|
"github.com/goharbor/harbor/src/api/artifact/descriptor"
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
|
||||||
"github.com/goharbor/harbor/src/common/utils"
|
"github.com/goharbor/harbor/src/common/utils"
|
||||||
"github.com/goharbor/harbor/src/internal"
|
"github.com/goharbor/harbor/src/internal"
|
||||||
"github.com/goharbor/harbor/src/pkg/art"
|
"github.com/goharbor/harbor/src/pkg/art"
|
||||||
|
@ -61,7 +60,7 @@ type Controller interface {
|
||||||
// creates it if it doesn't exist. If tags are provided, ensure they exist
|
// creates it if it doesn't exist. If tags are provided, ensure they exist
|
||||||
// and are attached to the artifact. If the tags don't exist, create them first.
|
// and are attached to the artifact. If the tags don't exist, create them first.
|
||||||
// The "created" will be set as true when the artifact is created
|
// The "created" will be set as true when the artifact is created
|
||||||
Ensure(ctx context.Context, repositoryID int64, digest string, tags ...string) (created bool, id int64, err error)
|
Ensure(ctx context.Context, repository, digest string, tags ...string) (created bool, id int64, err error)
|
||||||
// Count returns the total count of artifacts according to the query.
|
// Count returns the total count of artifacts according to the query.
|
||||||
// The artifacts that referenced by others and without tags are not counted
|
// The artifacts that referenced by others and without tags are not counted
|
||||||
Count(ctx context.Context, query *q.Query) (total int64, err error)
|
Count(ctx context.Context, query *q.Query) (total int64, err error)
|
||||||
|
@ -75,8 +74,8 @@ type Controller interface {
|
||||||
GetByReference(ctx context.Context, repository, reference string, option *Option) (artifact *Artifact, err error)
|
GetByReference(ctx context.Context, repository, reference string, option *Option) (artifact *Artifact, err error)
|
||||||
// Delete the artifact specified by ID. All tags attached to the artifact are deleted as well
|
// Delete the artifact specified by ID. All tags attached to the artifact are deleted as well
|
||||||
Delete(ctx context.Context, id int64) (err error)
|
Delete(ctx context.Context, id int64) (err error)
|
||||||
// Copy the artifact whose ID is specified by "srcArtID" into the repository specified by "dstRepoID"
|
// Copy the artifact specified by "srcRepo" and "reference" into the repository specified by "dstRepo"
|
||||||
Copy(ctx context.Context, srcArtID, dstRepoID int64) (id int64, err error)
|
Copy(ctx context.Context, srcRepo, reference, dstRepo string) (id int64, err error)
|
||||||
// ListTags lists the tags according to the query, specify the properties returned with option
|
// ListTags lists the tags according to the query, specify the properties returned with option
|
||||||
ListTags(ctx context.Context, query *q.Query, option *TagOption) (tags []*Tag, err error)
|
ListTags(ctx context.Context, query *q.Query, option *TagOption) (tags []*Tag, err error)
|
||||||
// CreateTag creates a tag
|
// CreateTag creates a tag
|
||||||
|
@ -127,46 +126,47 @@ type controller struct {
|
||||||
regCli registry.Client
|
regCli registry.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) Ensure(ctx context.Context, repositoryID int64, digest string, tags ...string) (bool, int64, error) {
|
func (c *controller) Ensure(ctx context.Context, repository, digest string, tags ...string) (bool, int64, error) {
|
||||||
created, id, err := c.ensureArtifact(ctx, repositoryID, digest)
|
created, artifact, err := c.ensureArtifact(ctx, repository, digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, 0, err
|
return false, 0, err
|
||||||
}
|
}
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
if err = c.ensureTag(ctx, repositoryID, id, tag); err != nil {
|
if err = c.ensureTag(ctx, artifact.RepositoryID, artifact.ID, tag); err != nil {
|
||||||
return false, 0, err
|
return false, 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return created, id, nil
|
return created, artifact.ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure the artifact exists under the repository, create it if doesn't exist.
|
// ensure the artifact exists under the repository, create it if doesn't exist.
|
||||||
func (c *controller) ensureArtifact(ctx context.Context, repositoryID int64, digest string) (bool, int64, error) {
|
func (c *controller) ensureArtifact(ctx context.Context, repository, digest string) (bool, *artifact.Artifact, error) {
|
||||||
art, err := c.artMgr.GetByDigest(ctx, repositoryID, digest)
|
art, err := c.artMgr.GetByDigest(ctx, repository, digest)
|
||||||
// the artifact already exists under the repository, return directly
|
// the artifact already exists under the repository, return directly
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return false, art.ID, nil
|
return false, art, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// got other error when get the artifact, return the error
|
// got other error when get the artifact, return the error
|
||||||
if !ierror.IsErr(err, ierror.NotFoundCode) {
|
if !ierror.IsErr(err, ierror.NotFoundCode) {
|
||||||
return false, 0, err
|
return false, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// the artifact doesn't exist under the repository, create it first
|
// the artifact doesn't exist under the repository, create it first
|
||||||
repository, err := c.repoMgr.Get(ctx, repositoryID)
|
repo, err := c.repoMgr.GetByName(ctx, repository)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, 0, err
|
return false, nil, err
|
||||||
}
|
}
|
||||||
artifact := &artifact.Artifact{
|
artifact := &artifact.Artifact{
|
||||||
ProjectID: repository.ProjectID,
|
ProjectID: repo.ProjectID,
|
||||||
RepositoryID: repositoryID,
|
RepositoryID: repo.RepositoryID,
|
||||||
Digest: digest,
|
RepositoryName: repository,
|
||||||
PushTime: time.Now(),
|
Digest: digest,
|
||||||
|
PushTime: time.Now(),
|
||||||
}
|
}
|
||||||
// abstract the metadata for the artifact
|
// abstract the metadata for the artifact
|
||||||
if err = c.abstractor.AbstractMetadata(ctx, artifact); err != nil {
|
if err = c.abstractor.AbstractMetadata(ctx, artifact); err != nil {
|
||||||
return false, 0, err
|
return false, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// populate the artifact type
|
// populate the artifact type
|
||||||
|
@ -177,15 +177,16 @@ func (c *controller) ensureArtifact(ctx context.Context, repositoryID int64, dig
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// if got conflict error, try to get the artifact again
|
// if got conflict error, try to get the artifact again
|
||||||
if ierror.IsConflictErr(err) {
|
if ierror.IsConflictErr(err) {
|
||||||
art, err = c.artMgr.GetByDigest(ctx, repositoryID, digest)
|
art, err = c.artMgr.GetByDigest(ctx, repository, digest)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return false, art.ID, nil
|
return false, art, nil
|
||||||
}
|
}
|
||||||
return false, 0, err
|
return false, nil, err
|
||||||
}
|
}
|
||||||
return false, 0, err
|
return false, nil, err
|
||||||
}
|
}
|
||||||
return true, id, nil
|
artifact.ID = id
|
||||||
|
return true, artifact, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) ensureTag(ctx context.Context, repositoryID, artifactID int64, name string) error {
|
func (c *controller) ensureTag(ctx context.Context, repositoryID, artifactID int64, name string) error {
|
||||||
|
@ -236,10 +237,6 @@ func (c *controller) List(ctx context.Context, query *q.Query, option *Option) (
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.populateRepositoryName(ctx, arts...); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var artifacts []*Artifact
|
var artifacts []*Artifact
|
||||||
for _, art := range arts {
|
for _, art := range arts {
|
||||||
artifacts = append(artifacts, c.assembleArtifact(ctx, art, option))
|
artifacts = append(artifacts, c.assembleArtifact(ctx, art, option))
|
||||||
|
@ -265,11 +262,7 @@ func (c *controller) GetByReference(ctx context.Context, repository, reference s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) getByDigest(ctx context.Context, repository, digest string, option *Option) (*Artifact, error) {
|
func (c *controller) getByDigest(ctx context.Context, repository, digest string, option *Option) (*Artifact, error) {
|
||||||
repo, err := c.repoMgr.GetByName(ctx, repository)
|
art, err := c.artMgr.GetByDigest(ctx, repository, digest)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
art, err := c.artMgr.GetByDigest(ctx, repo.RepositoryID, digest)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -377,14 +370,10 @@ func (c *controller) deleteDeeply(ctx context.Context, id int64, isRoot bool) er
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := c.repoMgr.Get(ctx, art.RepositoryID)
|
|
||||||
if err != nil && !ierror.IsErr(err, ierror.NotFoundCode) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = c.artrashMgr.Create(ctx, &model.ArtifactTrash{
|
_, err = c.artrashMgr.Create(ctx, &model.ArtifactTrash{
|
||||||
MediaType: art.MediaType,
|
MediaType: art.MediaType,
|
||||||
ManifestMediaType: art.ManifestMediaType,
|
ManifestMediaType: art.ManifestMediaType,
|
||||||
RepositoryName: repo.Name,
|
RepositoryName: art.RepositoryName,
|
||||||
Digest: art.Digest,
|
Digest: art.Digest,
|
||||||
})
|
})
|
||||||
if err != nil && !ierror.IsErr(err, ierror.ConflictCode) {
|
if err != nil && !ierror.IsErr(err, ierror.ConflictCode) {
|
||||||
|
@ -395,61 +384,63 @@ func (c *controller) deleteDeeply(ctx context.Context, id int64, isRoot bool) er
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) Copy(ctx context.Context, srcArtID, dstRepoID int64) (int64, error) {
|
func (c *controller) Copy(ctx context.Context, srcRepo, reference, dstRepo string) (int64, error) {
|
||||||
srcArt, err := c.Get(ctx, srcArtID, &Option{WithTag: true})
|
return c.copyDeeply(ctx, srcRepo, reference, dstRepo, true)
|
||||||
if err != nil {
|
}
|
||||||
return 0, err
|
|
||||||
|
// as we call the docker registry APIs in the registry client directly,
|
||||||
|
// this bypass our own logic(ensure, fire event, etc.) inside the registry handlers,
|
||||||
|
// these logic must be covered explicitly here.
|
||||||
|
// "copyDeeply" iterates the child artifacts and copy them first
|
||||||
|
func (c *controller) copyDeeply(ctx context.Context, srcRepo, reference, dstRepo string, isRoot bool) (int64, error) {
|
||||||
|
var option *Option
|
||||||
|
// only get the tags of the root parent
|
||||||
|
if isRoot {
|
||||||
|
option = &Option{WithTag: true}
|
||||||
}
|
}
|
||||||
srcRepo, err := c.repoMgr.Get(ctx, srcArt.RepositoryID)
|
|
||||||
if err != nil {
|
srcArt, err := c.GetByReference(ctx, srcRepo, reference, option)
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
dstRepo, err := c.repoMgr.Get(ctx, dstRepoID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = c.artMgr.GetByDigest(ctx, dstRepoID, srcArt.Digest)
|
digest := srcArt.Digest
|
||||||
// the artifact already exists in the destination repository
|
|
||||||
|
// check the existence of artifact in the destination repository
|
||||||
|
dstArt, err := c.GetByReference(ctx, dstRepo, digest, option)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return 0, ierror.New(nil).WithCode(ierror.ConflictCode).
|
// return conflict error if the root parent artifact already exists under the destination repository
|
||||||
WithMessage("the artifact %s already exists under the repository %s",
|
if isRoot {
|
||||||
srcArt.Digest, dstRepo.Name)
|
return 0, ierror.New(nil).WithCode(ierror.ConflictCode).
|
||||||
|
WithMessage("the artifact %s@%s already exists", dstRepo, digest)
|
||||||
|
}
|
||||||
|
// the child artifact already under the destination repository, skip
|
||||||
|
return dstArt.ID, nil
|
||||||
}
|
}
|
||||||
if !ierror.IsErr(err, ierror.NotFoundCode) {
|
if !ierror.IsErr(err, ierror.NotFoundCode) {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the artifact doesn't exist under the destination repository, continue to copy
|
||||||
|
// copy child artifacts if contains any
|
||||||
|
for _, reference := range srcArt.References {
|
||||||
|
if _, err = c.copyDeeply(ctx, srcRepo, reference.ChildDigest, dstRepo, false); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the parent artifact into the backend docker registry
|
||||||
|
if err := c.regCli.Copy(srcRepo, digest, dstRepo, digest, false); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
// only copy the tags of outermost artifact
|
// only copy the tags of outermost artifact
|
||||||
var tags []string
|
var tags []string
|
||||||
for _, tag := range srcArt.Tags {
|
for _, tag := range srcArt.Tags {
|
||||||
tags = append(tags, tag.Name)
|
tags = append(tags, tag.Name)
|
||||||
}
|
}
|
||||||
return c.copyDeeply(ctx, srcRepo, srcArt, dstRepo, tags...)
|
// ensure the parent artifact exist in the database
|
||||||
}
|
_, id, err := c.Ensure(ctx, dstRepo, digest, tags...)
|
||||||
|
|
||||||
// as we call the docker registry APIs in the registry client directly,
|
|
||||||
// this bypass our own logic(ensure, fire event, etc.) inside the registry handlers,
|
|
||||||
// these logic must be covered explicitly here.
|
|
||||||
// "copyDeeply" iterates the child artifacts and copy them first
|
|
||||||
func (c *controller) copyDeeply(ctx context.Context, srcRepo *models.RepoRecord, srcArt *Artifact,
|
|
||||||
dstRepo *models.RepoRecord, tags ...string) (int64, error) {
|
|
||||||
// copy child artifacts if contains any
|
|
||||||
for _, reference := range srcArt.References {
|
|
||||||
childArt, err := c.Get(ctx, reference.ChildID, nil)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if _, err = c.copyDeeply(ctx, srcRepo, childArt, dstRepo); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// copy the parent artifact
|
|
||||||
if err := c.regCli.Copy(srcRepo.Name, srcArt.Digest,
|
|
||||||
dstRepo.Name, srcArt.Digest, false); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
_, id, err := c.Ensure(ctx, dstRepo.RepositoryID, srcArt.Digest, tags...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -468,7 +459,11 @@ func (c *controller) ListTags(ctx context.Context, query *q.Query, option *TagOp
|
||||||
}
|
}
|
||||||
var tags []*Tag
|
var tags []*Tag
|
||||||
for _, tg := range tgs {
|
for _, tg := range tgs {
|
||||||
tags = append(tags, c.assembleTag(ctx, tg, option))
|
art, err := c.artMgr.Get(ctx, tg.ArtifactID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tags = append(tags, c.assembleTag(ctx, art, tg, option))
|
||||||
}
|
}
|
||||||
return tags, nil
|
return tags, nil
|
||||||
}
|
}
|
||||||
|
@ -517,19 +512,9 @@ func (c *controller) assembleArtifact(ctx context.Context, art *artifact.Artifac
|
||||||
artifact := &Artifact{
|
artifact := &Artifact{
|
||||||
Artifact: *art,
|
Artifact: *art,
|
||||||
}
|
}
|
||||||
|
|
||||||
if artifact.RepositoryName == "" {
|
|
||||||
repo, err := c.repoMgr.Get(ctx, artifact.RepositoryID)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("get repository %d failed, error: %v", artifact.RepositoryID, err)
|
|
||||||
return artifact
|
|
||||||
}
|
|
||||||
|
|
||||||
artifact.RepositoryName = repo.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// populate addition links
|
// populate addition links
|
||||||
c.populateAdditionLinks(ctx, artifact)
|
c.populateAdditionLinks(ctx, artifact)
|
||||||
|
|
||||||
if option == nil {
|
if option == nil {
|
||||||
return artifact
|
return artifact
|
||||||
}
|
}
|
||||||
|
@ -539,39 +524,9 @@ func (c *controller) assembleArtifact(ctx context.Context, art *artifact.Artifac
|
||||||
if option.WithLabel {
|
if option.WithLabel {
|
||||||
c.populateLabels(ctx, artifact)
|
c.populateLabels(ctx, artifact)
|
||||||
}
|
}
|
||||||
// populate addition links
|
|
||||||
c.populateAdditionLinks(ctx, artifact)
|
|
||||||
return artifact
|
return artifact
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) populateRepositoryName(ctx context.Context, artifacts ...*artifact.Artifact) error {
|
|
||||||
var ids []int64
|
|
||||||
for _, artifact := range artifacts {
|
|
||||||
ids = append(ids, artifact.RepositoryID)
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories, err := c.repoMgr.List(ctx, &q.Query{Keywords: map[string]interface{}{"repository_id__in": ids}})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
mp := make(map[int64]string, len(repositories))
|
|
||||||
for _, repository := range repositories {
|
|
||||||
mp[repository.RepositoryID] = repository.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, artifact := range artifacts {
|
|
||||||
repositoryName, ok := mp[artifact.RepositoryID]
|
|
||||||
if !ok {
|
|
||||||
return ierror.NotFoundError(nil).WithMessage("repository %d not found", artifact.RepositoryID)
|
|
||||||
}
|
|
||||||
|
|
||||||
artifact.RepositoryName = repositoryName
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *controller) populateTags(ctx context.Context, art *Artifact, option *TagOption) {
|
func (c *controller) populateTags(ctx context.Context, art *Artifact, option *TagOption) {
|
||||||
tags, err := c.tagMgr.List(ctx, &q.Query{
|
tags, err := c.tagMgr.List(ctx, &q.Query{
|
||||||
Keywords: map[string]interface{}{
|
Keywords: map[string]interface{}{
|
||||||
|
@ -583,46 +538,51 @@ func (c *controller) populateTags(ctx context.Context, art *Artifact, option *Ta
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
art.Tags = append(art.Tags, c.assembleTag(ctx, tag, option))
|
art.Tags = append(art.Tags, c.assembleTag(ctx, &art.Artifact, tag, option))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// assemble several part into a single tag
|
// assemble several part into a single tag
|
||||||
func (c *controller) assembleTag(ctx context.Context, tag *tm.Tag, option *TagOption) *Tag {
|
func (c *controller) assembleTag(ctx context.Context, art *artifact.Artifact, tag *tm.Tag, option *TagOption) *Tag {
|
||||||
t := &Tag{
|
t := &Tag{
|
||||||
Tag: *tag,
|
Tag: *tag,
|
||||||
}
|
}
|
||||||
if option == nil {
|
if option == nil {
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
repo, err := c.repoMgr.Get(ctx, tag.RepositoryID)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to get repo for tag: %s, error: %v", tag.Name, err)
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
if option.WithImmutableStatus {
|
if option.WithImmutableStatus {
|
||||||
c.populateImmutableStatus(ctx, t)
|
c.populateImmutableStatus(ctx, art, t)
|
||||||
}
|
}
|
||||||
if option.WithSignature {
|
if option.WithSignature {
|
||||||
if a, err := c.artMgr.Get(ctx, t.ArtifactID); err != nil {
|
c.populateTagSignature(ctx, art, t, option)
|
||||||
log.Errorf("Failed to get artifact for tag: %s, error: %v, skip populating signature", t.Name, err)
|
|
||||||
} else {
|
|
||||||
c.populateTagSignature(ctx, repo.Name, t, a.Digest, option)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) populateTagSignature(ctx context.Context, repo string, tag *Tag, digest string, option *TagOption) {
|
func (c *controller) populateImmutableStatus(ctx context.Context, artifact *artifact.Artifact, tag *Tag) {
|
||||||
|
_, repoName := utils.ParseRepository(artifact.RepositoryName)
|
||||||
|
matched, err := c.immutableMtr.Match(artifact.ProjectID, art.Candidate{
|
||||||
|
Repository: repoName,
|
||||||
|
Tags: []string{tag.Name},
|
||||||
|
NamespaceID: artifact.ProjectID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tag.Immutable = matched
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controller) populateTagSignature(ctx context.Context, artifact *artifact.Artifact, tag *Tag, option *TagOption) {
|
||||||
if option.SignatureChecker == nil {
|
if option.SignatureChecker == nil {
|
||||||
chk, err := signature.GetManager().GetCheckerByRepo(ctx, repo)
|
chk, err := signature.GetManager().GetCheckerByRepo(ctx, artifact.RepositoryName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
option.SignatureChecker = chk
|
option.SignatureChecker = chk
|
||||||
}
|
}
|
||||||
tag.Signed = option.SignatureChecker.IsTagSigned(tag.Name, digest)
|
tag.Signed = option.SignatureChecker.IsTagSigned(tag.Name, artifact.Digest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) populateLabels(ctx context.Context, art *Artifact) {
|
func (c *controller) populateLabels(ctx context.Context, art *Artifact) {
|
||||||
|
@ -634,25 +594,6 @@ func (c *controller) populateLabels(ctx context.Context, art *Artifact) {
|
||||||
art.Labels = labels
|
art.Labels = labels
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) populateImmutableStatus(ctx context.Context, tag *Tag) {
|
|
||||||
repo, err := c.repoMgr.Get(ctx, tag.RepositoryID)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, repoName := utils.ParseRepository(repo.Name)
|
|
||||||
matched, err := c.immutableMtr.Match(repo.ProjectID, art.Candidate{
|
|
||||||
Repository: repoName,
|
|
||||||
Tags: []string{tag.Name},
|
|
||||||
NamespaceID: repo.ProjectID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
tag.Immutable = matched
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *controller) populateAdditionLinks(ctx context.Context, artifact *Artifact) {
|
func (c *controller) populateAdditionLinks(ctx context.Context, artifact *Artifact) {
|
||||||
types := descriptor.ListAdditionTypes(artifact.MediaType)
|
types := descriptor.ListAdditionTypes(artifact.MediaType)
|
||||||
if len(types) > 0 {
|
if len(types) > 0 {
|
||||||
|
|
|
@ -39,6 +39,8 @@ import (
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO find another way to test artifact controller, it's hard to maintain currently
|
||||||
|
|
||||||
type fakeAbstractor struct {
|
type fakeAbstractor struct {
|
||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
@ -107,6 +109,13 @@ func (c *controllerTestSuite) SetupTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controllerTestSuite) TestAssembleTag() {
|
func (c *controllerTestSuite) TestAssembleTag() {
|
||||||
|
art := &artifact.Artifact{
|
||||||
|
ID: 1,
|
||||||
|
ProjectID: 1,
|
||||||
|
RepositoryID: 1,
|
||||||
|
RepositoryName: "library/hello-world",
|
||||||
|
Digest: "sha256:418fb88ec412e340cdbef913b8ca1bbe8f9e8dc705f9617414c1f2c8db980180",
|
||||||
|
}
|
||||||
tg := &tag.Tag{
|
tg := &tag.Tag{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
RepositoryID: 1,
|
RepositoryID: 1,
|
||||||
|
@ -119,13 +128,8 @@ func (c *controllerTestSuite) TestAssembleTag() {
|
||||||
WithImmutableStatus: true,
|
WithImmutableStatus: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
c.repoMgr.On("Get").Return(&models.RepoRecord{
|
|
||||||
ProjectID: 1,
|
|
||||||
Name: "hello-world",
|
|
||||||
}, nil)
|
|
||||||
|
|
||||||
c.immutableMtr.On("Match").Return(true, nil)
|
c.immutableMtr.On("Match").Return(true, nil)
|
||||||
tag := c.ctl.assembleTag(nil, tg, option)
|
tag := c.ctl.assembleTag(nil, art, tg, option)
|
||||||
c.Require().NotNil(tag)
|
c.Require().NotNil(tag)
|
||||||
c.Equal(tag.ID, tg.ID)
|
c.Equal(tag.ID, tg.ID)
|
||||||
c.Equal(true, tag.Immutable)
|
c.Equal(true, tag.Immutable)
|
||||||
|
@ -154,9 +158,6 @@ func (c *controllerTestSuite) TestAssembleArtifact() {
|
||||||
PullTime: time.Now(),
|
PullTime: time.Now(),
|
||||||
}
|
}
|
||||||
c.tagMgr.On("List").Return([]*tag.Tag{tg}, nil)
|
c.tagMgr.On("List").Return([]*tag.Tag{tg}, nil)
|
||||||
c.repoMgr.On("Get").Return(&models.RepoRecord{
|
|
||||||
Name: "library/hello-world",
|
|
||||||
}, nil)
|
|
||||||
ctx := internal.SetAPIVersion(nil, "2.0")
|
ctx := internal.SetAPIVersion(nil, "2.0")
|
||||||
lb := &models.Label{
|
lb := &models.Label{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
|
@ -185,25 +186,25 @@ func (c *controllerTestSuite) TestEnsureArtifact() {
|
||||||
c.artMgr.On("GetByDigest").Return(&artifact.Artifact{
|
c.artMgr.On("GetByDigest").Return(&artifact.Artifact{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
}, nil)
|
}, nil)
|
||||||
created, id, err := c.ctl.ensureArtifact(nil, 1, digest)
|
created, art, err := c.ctl.ensureArtifact(nil, "library/hello-world", digest)
|
||||||
c.Require().Nil(err)
|
c.Require().Nil(err)
|
||||||
c.False(created)
|
c.False(created)
|
||||||
c.Equal(int64(1), id)
|
c.Equal(int64(1), art.ID)
|
||||||
|
|
||||||
// reset the mock
|
// reset the mock
|
||||||
c.SetupTest()
|
c.SetupTest()
|
||||||
|
|
||||||
// the artifact doesn't exist
|
// the artifact doesn't exist
|
||||||
c.repoMgr.On("Get").Return(&models.RepoRecord{
|
c.repoMgr.On("GetByName").Return(&models.RepoRecord{
|
||||||
ProjectID: 1,
|
ProjectID: 1,
|
||||||
}, nil)
|
}, nil)
|
||||||
c.artMgr.On("GetByDigest").Return(nil, ierror.NotFoundError(nil))
|
c.artMgr.On("GetByDigest").Return(nil, ierror.NotFoundError(nil))
|
||||||
c.artMgr.On("Create").Return(1, nil)
|
c.artMgr.On("Create").Return(1, nil)
|
||||||
c.abstractor.On("AbstractMetadata").Return(nil)
|
c.abstractor.On("AbstractMetadata").Return(nil)
|
||||||
created, id, err = c.ctl.ensureArtifact(nil, 1, digest)
|
created, art, err = c.ctl.ensureArtifact(nil, "library/hello-world", digest)
|
||||||
c.Require().Nil(err)
|
c.Require().Nil(err)
|
||||||
c.True(created)
|
c.True(created)
|
||||||
c.Equal(int64(1), id)
|
c.Equal(int64(1), art.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controllerTestSuite) TestEnsureTag() {
|
func (c *controllerTestSuite) TestEnsureTag() {
|
||||||
|
@ -252,7 +253,7 @@ func (c *controllerTestSuite) TestEnsure() {
|
||||||
digest := "sha256:418fb88ec412e340cdbef913b8ca1bbe8f9e8dc705f9617414c1f2c8db980180"
|
digest := "sha256:418fb88ec412e340cdbef913b8ca1bbe8f9e8dc705f9617414c1f2c8db980180"
|
||||||
|
|
||||||
// both the artifact and the tag don't exist
|
// both the artifact and the tag don't exist
|
||||||
c.repoMgr.On("Get").Return(&models.RepoRecord{
|
c.repoMgr.On("GetByName").Return(&models.RepoRecord{
|
||||||
ProjectID: 1,
|
ProjectID: 1,
|
||||||
}, nil)
|
}, nil)
|
||||||
c.artMgr.On("GetByDigest").Return(nil, ierror.NotFoundError(nil))
|
c.artMgr.On("GetByDigest").Return(nil, ierror.NotFoundError(nil))
|
||||||
|
@ -260,7 +261,7 @@ func (c *controllerTestSuite) TestEnsure() {
|
||||||
c.tagMgr.On("List").Return([]*tag.Tag{}, nil)
|
c.tagMgr.On("List").Return([]*tag.Tag{}, nil)
|
||||||
c.tagMgr.On("Create").Return(1, nil)
|
c.tagMgr.On("Create").Return(1, nil)
|
||||||
c.abstractor.On("AbstractMetadata").Return(nil)
|
c.abstractor.On("AbstractMetadata").Return(nil)
|
||||||
_, id, err := c.ctl.Ensure(nil, 1, digest, "latest")
|
_, id, err := c.ctl.Ensure(nil, "library/hello-world", digest, "latest")
|
||||||
c.Require().Nil(err)
|
c.Require().Nil(err)
|
||||||
c.repoMgr.AssertExpectations(c.T())
|
c.repoMgr.AssertExpectations(c.T())
|
||||||
c.artMgr.AssertExpectations(c.T())
|
c.artMgr.AssertExpectations(c.T())
|
||||||
|
@ -508,7 +509,12 @@ func (c *controllerTestSuite) TestDeleteDeeply() {
|
||||||
|
|
||||||
func (c *controllerTestSuite) TestCopy() {
|
func (c *controllerTestSuite) TestCopy() {
|
||||||
c.artMgr.On("Get").Return(&artifact.Artifact{
|
c.artMgr.On("Get").Return(&artifact.Artifact{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
|
Digest: "sha256:418fb88ec412e340cdbef913b8ca1bbe8f9e8dc705f9617414c1f2c8db980180",
|
||||||
|
}, nil)
|
||||||
|
c.repoMgr.On("GetByName").Return(&models.RepoRecord{
|
||||||
|
RepositoryID: 1,
|
||||||
|
Name: "library/hello-world",
|
||||||
}, nil)
|
}, nil)
|
||||||
c.artMgr.On("GetByDigest").Return(nil, ierror.NotFoundError(nil))
|
c.artMgr.On("GetByDigest").Return(nil, ierror.NotFoundError(nil))
|
||||||
c.tagMgr.On("List").Return([]*tag.Tag{
|
c.tagMgr.On("List").Return([]*tag.Tag{
|
||||||
|
@ -525,7 +531,7 @@ func (c *controllerTestSuite) TestCopy() {
|
||||||
c.abstractor.On("AbstractMetadata").Return(nil)
|
c.abstractor.On("AbstractMetadata").Return(nil)
|
||||||
c.artMgr.On("Create").Return(1, nil)
|
c.artMgr.On("Create").Return(1, nil)
|
||||||
c.regCli.On("Copy").Return(nil)
|
c.regCli.On("Copy").Return(nil)
|
||||||
_, err := c.ctl.Copy(nil, 1, 1)
|
_, err := c.ctl.Copy(nil, "library/hello-world", "latest", "library/hello-world2")
|
||||||
c.Require().Nil(err)
|
c.Require().Nil(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,6 +544,7 @@ func (c *controllerTestSuite) TestListTags() {
|
||||||
ArtifactID: 1,
|
ArtifactID: 1,
|
||||||
},
|
},
|
||||||
}, nil)
|
}, nil)
|
||||||
|
c.artMgr.On("Get").Return(&artifact.Artifact{}, nil)
|
||||||
tags, err := c.ctl.ListTags(nil, nil, nil)
|
tags, err := c.ctl.ListTags(nil, nil, nil)
|
||||||
c.Require().Nil(err)
|
c.Require().Nil(err)
|
||||||
c.Len(tags, 1)
|
c.Len(tags, 1)
|
||||||
|
|
|
@ -32,8 +32,8 @@ type DAO interface {
|
||||||
List(ctx context.Context, query *q.Query) (artifacts []*Artifact, err error)
|
List(ctx context.Context, query *q.Query) (artifacts []*Artifact, err error)
|
||||||
// Get the artifact specified by ID
|
// Get the artifact specified by ID
|
||||||
Get(ctx context.Context, id int64) (*Artifact, error)
|
Get(ctx context.Context, id int64) (*Artifact, error)
|
||||||
// GetByDigest returns the artifact specified by repository ID and digest
|
// GetByDigest returns the artifact specified by repository and digest
|
||||||
GetByDigest(ctx context.Context, repositoryID int64, digest string) (artifact *Artifact, err error)
|
GetByDigest(ctx context.Context, repository, digest string) (artifact *Artifact, err error)
|
||||||
// Create the artifact
|
// Create the artifact
|
||||||
Create(ctx context.Context, artifact *Artifact) (id int64, err error)
|
Create(ctx context.Context, artifact *Artifact) (id int64, err error)
|
||||||
// Delete the artifact specified by ID
|
// Delete the artifact specified by ID
|
||||||
|
@ -118,11 +118,11 @@ func (d *dao) Get(ctx context.Context, id int64) (*Artifact, error) {
|
||||||
return artifact, nil
|
return artifact, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dao) GetByDigest(ctx context.Context, repositoryID int64, digest string) (*Artifact, error) {
|
func (d *dao) GetByDigest(ctx context.Context, repository, digest string) (*Artifact, error) {
|
||||||
qs, err := orm.QuerySetter(ctx, &Artifact{}, &q.Query{
|
qs, err := orm.QuerySetter(ctx, &Artifact{}, &q.Query{
|
||||||
Keywords: map[string]interface{}{
|
Keywords: map[string]interface{}{
|
||||||
"RepositoryID": repositoryID,
|
"RepositoryName": repository,
|
||||||
"Digest": digest,
|
"Digest": digest,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -134,7 +134,7 @@ func (d *dao) GetByDigest(ctx context.Context, repositoryID int64, digest string
|
||||||
}
|
}
|
||||||
if len(artifacts) == 0 {
|
if len(artifacts) == 0 {
|
||||||
return nil, ierror.New(nil).WithCode(ierror.NotFoundCode).
|
return nil, ierror.New(nil).WithCode(ierror.NotFoundCode).
|
||||||
WithMessage("artifact %s under the repository %d not found", digest, repositoryID)
|
WithMessage("artifact %s@%s not found", repository, digest)
|
||||||
}
|
}
|
||||||
return artifacts[0], nil
|
return artifacts[0], nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ func (d *daoTestSuite) SetupTest() {
|
||||||
ManifestMediaType: v1.MediaTypeImageIndex,
|
ManifestMediaType: v1.MediaTypeImageIndex,
|
||||||
ProjectID: 1,
|
ProjectID: 1,
|
||||||
RepositoryID: 1,
|
RepositoryID: 1,
|
||||||
|
RepositoryName: "library/hello-world",
|
||||||
Digest: "parent_digest",
|
Digest: "parent_digest",
|
||||||
PushTime: now,
|
PushTime: now,
|
||||||
PullTime: now,
|
PullTime: now,
|
||||||
|
@ -72,6 +73,7 @@ func (d *daoTestSuite) SetupTest() {
|
||||||
ManifestMediaType: v1.MediaTypeImageManifest,
|
ManifestMediaType: v1.MediaTypeImageManifest,
|
||||||
ProjectID: 1,
|
ProjectID: 1,
|
||||||
RepositoryID: 1,
|
RepositoryID: 1,
|
||||||
|
RepositoryName: "library/hello-world",
|
||||||
Digest: "child_digest_01",
|
Digest: "child_digest_01",
|
||||||
Size: 1024,
|
Size: 1024,
|
||||||
PushTime: now,
|
PushTime: now,
|
||||||
|
@ -88,6 +90,7 @@ func (d *daoTestSuite) SetupTest() {
|
||||||
ManifestMediaType: v1.MediaTypeImageManifest,
|
ManifestMediaType: v1.MediaTypeImageManifest,
|
||||||
ProjectID: 1,
|
ProjectID: 1,
|
||||||
RepositoryID: 1,
|
RepositoryID: 1,
|
||||||
|
RepositoryName: "library/hello-world",
|
||||||
Digest: "child_digest_02",
|
Digest: "child_digest_02",
|
||||||
Size: 1024,
|
Size: 1024,
|
||||||
PushTime: now,
|
PushTime: now,
|
||||||
|
@ -324,12 +327,12 @@ func (d *daoTestSuite) TestGet() {
|
||||||
|
|
||||||
func (d *daoTestSuite) TestGetByDigest() {
|
func (d *daoTestSuite) TestGetByDigest() {
|
||||||
// get the non-exist artifact
|
// get the non-exist artifact
|
||||||
_, err := d.dao.GetByDigest(d.ctx, 1, "non_existing_digest")
|
_, err := d.dao.GetByDigest(d.ctx, "library/hello-world", "non_existing_digest")
|
||||||
d.Require().NotNil(err)
|
d.Require().NotNil(err)
|
||||||
d.True(ierror.IsErr(err, ierror.NotFoundCode))
|
d.True(ierror.IsErr(err, ierror.NotFoundCode))
|
||||||
|
|
||||||
// get the exist artifact
|
// get the exist artifact
|
||||||
artifact, err := d.dao.GetByDigest(d.ctx, 1, "child_digest_02")
|
artifact, err := d.dao.GetByDigest(d.ctx, "library/hello-world", "child_digest_02")
|
||||||
d.Require().Nil(err)
|
d.Require().Nil(err)
|
||||||
d.Require().NotNil(artifact)
|
d.Require().NotNil(artifact)
|
||||||
d.Equal(d.childArt02ID, artifact.ID)
|
d.Equal(d.childArt02ID, artifact.ID)
|
||||||
|
|
|
@ -33,6 +33,7 @@ type Artifact struct {
|
||||||
ManifestMediaType string `orm:"column(manifest_media_type)"` // the media type of manifest/index
|
ManifestMediaType string `orm:"column(manifest_media_type)"` // the media type of manifest/index
|
||||||
ProjectID int64 `orm:"column(project_id)"` // needed for quota
|
ProjectID int64 `orm:"column(project_id)"` // needed for quota
|
||||||
RepositoryID int64 `orm:"column(repository_id)"`
|
RepositoryID int64 `orm:"column(repository_id)"`
|
||||||
|
RepositoryName string `orm:"column(repository_name)"`
|
||||||
Digest string `orm:"column(digest)"`
|
Digest string `orm:"column(digest)"`
|
||||||
Size int64 `orm:"column(size)"`
|
Size int64 `orm:"column(size)"`
|
||||||
PushTime time.Time `orm:"column(push_time)"`
|
PushTime time.Time `orm:"column(push_time)"`
|
||||||
|
|
|
@ -37,8 +37,8 @@ type Manager interface {
|
||||||
List(ctx context.Context, query *q.Query) (artifacts []*Artifact, err error)
|
List(ctx context.Context, query *q.Query) (artifacts []*Artifact, err error)
|
||||||
// Get the artifact specified by the ID
|
// Get the artifact specified by the ID
|
||||||
Get(ctx context.Context, id int64) (artifact *Artifact, err error)
|
Get(ctx context.Context, id int64) (artifact *Artifact, err error)
|
||||||
// GetByDigest returns the artifact specified by repository ID and digest
|
// GetByDigest returns the artifact specified by repository and digest
|
||||||
GetByDigest(ctx context.Context, repositoryID int64, digest string) (artifact *Artifact, err error)
|
GetByDigest(ctx context.Context, repository, digest string) (artifact *Artifact, err error)
|
||||||
// Create the artifact. If the artifact is an index, make sure all the artifacts it references
|
// Create the artifact. If the artifact is an index, make sure all the artifacts it references
|
||||||
// already exist
|
// already exist
|
||||||
Create(ctx context.Context, artifact *Artifact) (id int64, err error)
|
Create(ctx context.Context, artifact *Artifact) (id int64, err error)
|
||||||
|
@ -94,8 +94,8 @@ func (m *manager) Get(ctx context.Context, id int64) (*Artifact, error) {
|
||||||
return m.assemble(ctx, art)
|
return m.assemble(ctx, art)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) GetByDigest(ctx context.Context, repositoryID int64, digest string) (*Artifact, error) {
|
func (m *manager) GetByDigest(ctx context.Context, repository, digest string) (*Artifact, error) {
|
||||||
art, err := m.dao.GetByDigest(ctx, repositoryID, digest)
|
art, err := m.dao.GetByDigest(ctx, repository, digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ func (f *fakeDao) Get(ctx context.Context, id int64) (*dao.Artifact, error) {
|
||||||
args := f.Called()
|
args := f.Called()
|
||||||
return args.Get(0).(*dao.Artifact), args.Error(1)
|
return args.Get(0).(*dao.Artifact), args.Error(1)
|
||||||
}
|
}
|
||||||
func (f *fakeDao) GetByDigest(ctx context.Context, repositoryID int64, digest string) (*dao.Artifact, error) {
|
func (f *fakeDao) GetByDigest(ctx context.Context, repository, digest string) (*dao.Artifact, error) {
|
||||||
args := f.Called()
|
args := f.Called()
|
||||||
return args.Get(0).(*dao.Artifact), args.Error(1)
|
return args.Get(0).(*dao.Artifact), args.Error(1)
|
||||||
}
|
}
|
||||||
|
@ -195,7 +195,7 @@ func (m *managerTestSuite) TestGetByDigest() {
|
||||||
}
|
}
|
||||||
m.dao.On("GetByDigest", mock.Anything).Return(art, nil)
|
m.dao.On("GetByDigest", mock.Anything).Return(art, nil)
|
||||||
m.dao.On("ListReferences").Return([]*dao.ArtifactReference{}, nil)
|
m.dao.On("ListReferences").Return([]*dao.ArtifactReference{}, nil)
|
||||||
artifact, err := m.mgr.GetByDigest(nil, 1, "sha256:418fb88ec412e340cdbef913b8ca1bbe8f9e8dc705f9617414c1f2c8db980180")
|
artifact, err := m.mgr.GetByDigest(nil, "library/hello-world", "sha256:418fb88ec412e340cdbef913b8ca1bbe8f9e8dc705f9617414c1f2c8db980180")
|
||||||
m.Require().Nil(err)
|
m.Require().Nil(err)
|
||||||
m.Require().NotNil(artifact)
|
m.Require().NotNil(artifact)
|
||||||
m.Equal(art.ID, artifact.ID)
|
m.Equal(art.ID, artifact.ID)
|
||||||
|
|
|
@ -33,6 +33,7 @@ type Artifact struct {
|
||||||
ManifestMediaType string `json:"manifest_media_type"` // the media type of manifest/index
|
ManifestMediaType string `json:"manifest_media_type"` // the media type of manifest/index
|
||||||
ProjectID int64 `json:"project_id"`
|
ProjectID int64 `json:"project_id"`
|
||||||
RepositoryID int64 `json:"repository_id"`
|
RepositoryID int64 `json:"repository_id"`
|
||||||
|
RepositoryName string `json:"repository_name"`
|
||||||
Digest string `json:"digest"`
|
Digest string `json:"digest"`
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
PushTime time.Time `json:"push_time"`
|
PushTime time.Time `json:"push_time"`
|
||||||
|
@ -40,8 +41,6 @@ type Artifact struct {
|
||||||
ExtraAttrs map[string]interface{} `json:"extra_attrs"` // only contains the simple attributes specific for the different artifact type, most of them should come from the config layer
|
ExtraAttrs map[string]interface{} `json:"extra_attrs"` // only contains the simple attributes specific for the different artifact type, most of them should come from the config layer
|
||||||
Annotations map[string]string `json:"annotations"`
|
Annotations map[string]string `json:"annotations"`
|
||||||
References []*Reference `json:"references"` // child artifacts referenced by the parent artifact if the artifact is an index
|
References []*Reference `json:"references"` // child artifacts referenced by the parent artifact if the artifact is an index
|
||||||
|
|
||||||
RepositoryName string `json:"-"` // repository name, eg: library/photon
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// From converts the database level artifact to the business level object
|
// From converts the database level artifact to the business level object
|
||||||
|
@ -52,6 +51,7 @@ func (a *Artifact) From(art *dao.Artifact) {
|
||||||
a.ManifestMediaType = art.ManifestMediaType
|
a.ManifestMediaType = art.ManifestMediaType
|
||||||
a.ProjectID = art.ProjectID
|
a.ProjectID = art.ProjectID
|
||||||
a.RepositoryID = art.RepositoryID
|
a.RepositoryID = art.RepositoryID
|
||||||
|
a.RepositoryName = art.RepositoryName
|
||||||
a.Digest = art.Digest
|
a.Digest = art.Digest
|
||||||
a.Size = art.Size
|
a.Size = art.Size
|
||||||
a.PushTime = art.PushTime
|
a.PushTime = art.PushTime
|
||||||
|
@ -79,6 +79,7 @@ func (a *Artifact) To() *dao.Artifact {
|
||||||
ManifestMediaType: a.ManifestMediaType,
|
ManifestMediaType: a.ManifestMediaType,
|
||||||
ProjectID: a.ProjectID,
|
ProjectID: a.ProjectID,
|
||||||
RepositoryID: a.RepositoryID,
|
RepositoryID: a.RepositoryID,
|
||||||
|
RepositoryName: a.RepositoryName,
|
||||||
Digest: a.Digest,
|
Digest: a.Digest,
|
||||||
Size: a.Size,
|
Size: a.Size,
|
||||||
PushTime: a.PushTime,
|
PushTime: a.PushTime,
|
||||||
|
|
|
@ -173,7 +173,7 @@ func (suite *DaoTestSuite) TestFindBlobsShouldUnassociatedWithProject() {
|
||||||
artifact1 := suite.DigestString()
|
artifact1 := suite.DigestString()
|
||||||
artifact2 := suite.DigestString()
|
artifact2 := suite.DigestString()
|
||||||
|
|
||||||
sql := `INSERT INTO artifact ("type", media_type, manifest_media_type, digest, project_id, repository_id) VALUES ('image', 'media_type', 'manifest_media_type', ?, ?, ?)`
|
sql := `INSERT INTO artifact ("type", media_type, manifest_media_type, digest, project_id, repository_id, repository_name) VALUES ('image', 'media_type', 'manifest_media_type', ?, ?, ?, 'library/hello-world')`
|
||||||
suite.ExecSQL(sql, artifact1, projectID, 10)
|
suite.ExecSQL(sql, artifact1, projectID, 10)
|
||||||
suite.ExecSQL(sql, artifact2, projectID, 10)
|
suite.ExecSQL(sql, artifact2, projectID, 10)
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ func (suite *ManagerTestSuite) TestCleanupAssociationsForProject() {
|
||||||
artifact1 := suite.DigestString()
|
artifact1 := suite.DigestString()
|
||||||
artifact2 := suite.DigestString()
|
artifact2 := suite.DigestString()
|
||||||
|
|
||||||
sql := `INSERT INTO artifact ("type", media_type, manifest_media_type, digest, project_id, repository_id) VALUES ('image', 'media_type', 'manifest_media_type', ?, ?, ?)`
|
sql := `INSERT INTO artifact ("type", media_type, manifest_media_type, digest, project_id, repository_id, repository_name) VALUES ('image', 'media_type', 'manifest_media_type', ?, ?, ?, 'library/hello-world')`
|
||||||
suite.ExecSQL(sql, artifact1, projectID, 10)
|
suite.ExecSQL(sql, artifact1, projectID, 10)
|
||||||
suite.ExecSQL(sql, artifact2, projectID, 10)
|
suite.ExecSQL(sql, artifact2, projectID, 10)
|
||||||
|
|
||||||
|
|
|
@ -110,15 +110,16 @@ func (suite *HandlerSuite) addProject(projectName string) int64 {
|
||||||
return projectID
|
return projectID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *HandlerSuite) addArt(ctx context.Context, pid, repositoryID int64, dgt string) int64 {
|
func (suite *HandlerSuite) addArt(ctx context.Context, pid, repositoryID int64, repositoryName, dgt string) int64 {
|
||||||
af := &artifact.Artifact{
|
af := &artifact.Artifact{
|
||||||
Type: "Docker-Image",
|
Type: "Docker-Image",
|
||||||
ProjectID: pid,
|
ProjectID: pid,
|
||||||
RepositoryID: repositoryID,
|
RepositoryID: repositoryID,
|
||||||
Digest: dgt,
|
RepositoryName: repositoryName,
|
||||||
Size: 1024,
|
Digest: dgt,
|
||||||
PushTime: time.Now(),
|
Size: 1024,
|
||||||
PullTime: time.Now(),
|
PushTime: time.Now(),
|
||||||
|
PullTime: time.Now(),
|
||||||
}
|
}
|
||||||
afid, err := artifact.Mgr.Create(ctx, af)
|
afid, err := artifact.Mgr.Create(ctx, af)
|
||||||
suite.Nil(err, fmt.Sprintf("Add artifact failed for %d", repositoryID))
|
suite.Nil(err, fmt.Sprintf("Add artifact failed for %d", repositoryID))
|
||||||
|
@ -185,7 +186,7 @@ func (suite *HandlerSuite) TestPutDeleteManifestCreated() {
|
||||||
projectID := suite.addProject(projectName)
|
projectID := suite.addProject(projectName)
|
||||||
immuRuleID := suite.addImmutableRule(projectID)
|
immuRuleID := suite.addImmutableRule(projectID)
|
||||||
repoID := suite.addRepo(ctx, projectID, repoName)
|
repoID := suite.addRepo(ctx, projectID, repoName)
|
||||||
afID := suite.addArt(ctx, projectID, repoID, dgt)
|
afID := suite.addArt(ctx, projectID, repoID, repoName, dgt)
|
||||||
tagID := suite.addTags(ctx, repoID, afID, "release-1.10")
|
tagID := suite.addTags(ctx, repoID, afID, "release-1.10")
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
|
@ -70,7 +70,7 @@ func putManifest(w http.ResponseWriter, req *http.Request) {
|
||||||
reference := router.Param(req.Context(), ":reference")
|
reference := router.Param(req.Context(), ":reference")
|
||||||
|
|
||||||
// make sure the repository exist before pushing the manifest
|
// make sure the repository exist before pushing the manifest
|
||||||
_, repositoryID, err := repository.Ctl.Ensure(req.Context(), repo)
|
_, _, err := repository.Ctl.Ensure(req.Context(), repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
serror.SendError(w, err)
|
serror.SendError(w, err)
|
||||||
return
|
return
|
||||||
|
@ -98,7 +98,7 @@ func putManifest(w http.ResponseWriter, req *http.Request) {
|
||||||
tags = append(tags, reference)
|
tags = append(tags, reference)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = artifact.Ctl.Ensure(req.Context(), repositoryID, dgt, tags...)
|
_, _, err = artifact.Ctl.Ensure(req.Context(), repo, dgt, tags...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
serror.SendError(w, err)
|
serror.SendError(w, err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -81,11 +81,7 @@ func (a *artifactAPI) ListArtifacts(ctx context.Context, params operation.ListAr
|
||||||
if params.PageSize != nil {
|
if params.PageSize != nil {
|
||||||
query.PageSize = *(params.PageSize)
|
query.PageSize = *(params.PageSize)
|
||||||
}
|
}
|
||||||
repository, err := a.repoCtl.GetByName(ctx, fmt.Sprintf("%s/%s", params.ProjectName, params.RepositoryName))
|
query.Keywords["RepositoryName"] = fmt.Sprintf("%s/%s", params.ProjectName, params.RepositoryName)
|
||||||
if err != nil {
|
|
||||||
return a.SendError(ctx, err)
|
|
||||||
}
|
|
||||||
query.Keywords["RepositoryID"] = repository.RepositoryID
|
|
||||||
|
|
||||||
// set option
|
// set option
|
||||||
option := option(params.WithTag, params.WithImmutableStatus,
|
option := option(params.WithTag, params.WithImmutableStatus,
|
||||||
|
@ -155,23 +151,24 @@ func (a *artifactAPI) CopyArtifact(ctx context.Context, params operation.CopyArt
|
||||||
if err := a.RequireProjectAccess(ctx, params.ProjectName, rbac.ActionCreate, rbac.ResourceArtifact); err != nil {
|
if err := a.RequireProjectAccess(ctx, params.ProjectName, rbac.ActionCreate, rbac.ResourceArtifact); err != nil {
|
||||||
return a.SendError(ctx, err)
|
return a.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
srcRepo, srcRef, err := parse(params.From)
|
|
||||||
|
srcRepo, ref, err := parse(params.From)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return a.SendError(ctx, err)
|
return a.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
srcPro, _ := utils.ParseRepository(srcRepo)
|
srcPro, _ := utils.ParseRepository(srcRepo)
|
||||||
if err = a.RequireProjectAccess(ctx, srcPro, rbac.ActionRead, rbac.ResourceArtifact); err != nil {
|
if err = a.RequireProjectAccess(ctx, srcPro, rbac.ActionRead, rbac.ResourceArtifact); err != nil {
|
||||||
return a.SendError(ctx, err)
|
return a.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
srcArt, err := a.artCtl.GetByReference(ctx, srcRepo, srcRef, &artifact.Option{WithTag: true})
|
|
||||||
|
dstRepo := fmt.Sprintf("%s/%s", params.ProjectName, params.RepositoryName)
|
||||||
|
_, id, err := a.repoCtl.Ensure(ctx, dstRepo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return a.SendError(ctx, err)
|
return a.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
_, id, err := a.repoCtl.Ensure(ctx, params.ProjectName+"/"+params.RepositoryName)
|
|
||||||
if err != nil {
|
id, err = a.artCtl.Copy(ctx, srcRepo, ref, dstRepo)
|
||||||
return a.SendError(ctx, err)
|
|
||||||
}
|
|
||||||
id, err = a.artCtl.Copy(ctx, srcArt.ID, id)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return a.SendError(ctx, err)
|
return a.SendError(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ type FakeController struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure ...
|
// Ensure ...
|
||||||
func (f *FakeController) Ensure(ctx context.Context, repositoryID int64, digest string, tags ...string) (bool, int64, error) {
|
func (f *FakeController) Ensure(ctx context.Context, repository, digest string, tags ...string) (bool, int64, error) {
|
||||||
args := f.Called()
|
args := f.Called()
|
||||||
return args.Bool(0), int64(args.Int(1)), args.Error(2)
|
return args.Bool(0), int64(args.Int(1)), args.Error(2)
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ func (f *FakeController) Delete(ctx context.Context, id int64) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy ...
|
// Copy ...
|
||||||
func (f *FakeController) Copy(ctx context.Context, srcArtID, dstRepoID int64) (int64, error) {
|
func (f *FakeController) Copy(ctx context.Context, srcRepo, ref, dstRepo string) (int64, error) {
|
||||||
args := f.Called()
|
args := f.Called()
|
||||||
return int64(args.Int(0)), args.Error(1)
|
return int64(args.Int(0)), args.Error(1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ func (f *FakeManager) Get(ctx context.Context, id int64) (*artifact.Artifact, er
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetByDigest ...
|
// GetByDigest ...
|
||||||
func (f *FakeManager) GetByDigest(ctx context.Context, repositoryID int64, digest string) (*artifact.Artifact, error) {
|
func (f *FakeManager) GetByDigest(ctx context.Context, repository, digest string) (*artifact.Artifact, error) {
|
||||||
args := f.Called()
|
args := f.Called()
|
||||||
var art *artifact.Artifact
|
var art *artifact.Artifact
|
||||||
if args.Get(0) != nil {
|
if args.Get(0) != nil {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user