From c9a5e76d24d367ac9279052c10c1bb885df7fc70 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Wed, 3 Sep 2025 20:57:45 +0300 Subject: [PATCH 1/4] Refactor the API and controller to use the `meta.Artifact` type Signed-off-by: Stefan Prodan --- api/go.mod | 2 +- api/go.sum | 4 +- api/v1/artifact_types.go | 93 ------------ api/v1/bucket_types.go | 4 +- api/v1/gitrepository_types.go | 6 +- api/v1/helmchart_types.go | 4 +- api/v1/helmrepository_types.go | 4 +- api/v1/ocirepository_types.go | 4 +- api/v1/source.go | 4 +- api/v1/zz_generated.deepcopy.go | 42 +----- api/v1beta2/bucket_types.go | 4 +- api/v1beta2/gitrepository_types.go | 8 +- api/v1beta2/helmchart_types.go | 4 +- api/v1beta2/helmrepository_types.go | 6 +- api/v1beta2/ocirepository_types.go | 4 +- api/v1beta2/zz_generated.deepcopy.go | 14 +- .../source.toolkit.fluxcd.io_buckets.yaml | 2 + ...rce.toolkit.fluxcd.io_gitrepositories.yaml | 4 + .../source.toolkit.fluxcd.io_helmcharts.yaml | 2 + ...ce.toolkit.fluxcd.io_helmrepositories.yaml | 2 + ...rce.toolkit.fluxcd.io_ocirepositories.yaml | 2 + docs/api/v1/source.md | 137 ++---------------- go.mod | 4 +- go.sum | 8 +- internal/controller/artifact.go | 6 +- internal/controller/artifact_matchers_test.go | 9 +- internal/controller/bucket_controller_test.go | 40 ++--- .../controller/gitrepository_controller.go | 4 +- .../gitrepository_controller_test.go | 86 +++++------ internal/controller/helmchart_controller.go | 2 +- .../controller/helmchart_controller_test.go | 70 ++++----- .../controller/helmrepository_controller.go | 10 +- .../helmrepository_controller_test.go | 88 +++++------ .../controller/ocirepository_controller.go | 12 +- .../ocirepository_controller_test.go | 122 ++++++++-------- internal/object/object.go | 6 +- internal/object/object_test.go | 4 +- .../helmrepository_type_predicate_test.go | 2 +- internal/storage/storage.go | 84 ++++++----- internal/storage/storage_test.go | 34 ++--- 40 files changed, 371 insertions(+), 576 deletions(-) delete mode 100644 api/v1/artifact_types.go diff --git a/api/go.mod b/api/go.mod index e4413a787..c16cb0b34 100644 --- a/api/go.mod +++ b/api/go.mod @@ -4,7 +4,7 @@ go 1.25.0 require ( github.com/fluxcd/pkg/apis/acl v0.9.0 - github.com/fluxcd/pkg/apis/meta v1.20.0 + github.com/fluxcd/pkg/apis/meta v1.21.0 k8s.io/apimachinery v0.34.0 sigs.k8s.io/controller-runtime v0.22.0 ) diff --git a/api/go.sum b/api/go.sum index 77547bb70..9ab871eca 100644 --- a/api/go.sum +++ b/api/go.sum @@ -4,8 +4,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fluxcd/pkg/apis/acl v0.9.0 h1:wBpgsKT+jcyZEcM//OmZr9RiF8klL3ebrDp2u2ThsnA= github.com/fluxcd/pkg/apis/acl v0.9.0/go.mod h1:TttNS+gocsGLwnvmgVi3/Yscwqrjc17+vhgYfqkfrV4= -github.com/fluxcd/pkg/apis/meta v1.20.0 h1:l9h0kWoDZTcYV0WJkFMgDXq6Q4tSojrJ+bHpFJSsaW0= -github.com/fluxcd/pkg/apis/meta v1.20.0/go.mod h1:XUAEUgT4gkWDAEN79E141tmL+v4SV50tVZ/Ojpc/ueg= +github.com/fluxcd/pkg/apis/meta v1.21.0 h1:R+bN02chcs0HUmyVDQhqe/FHmYLjipVDMLnyYfNX850= +github.com/fluxcd/pkg/apis/meta v1.21.0/go.mod h1:XUAEUgT4gkWDAEN79E141tmL+v4SV50tVZ/Ojpc/ueg= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= diff --git a/api/v1/artifact_types.go b/api/v1/artifact_types.go deleted file mode 100644 index 9342ecfa6..000000000 --- a/api/v1/artifact_types.go +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright 2023 The Flux 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 v1 - -import ( - "path" - "strings" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// Artifact represents the output of a Source reconciliation. -type Artifact struct { - // Path is the relative file path of the Artifact. It can be used to locate - // the file in the root of the Artifact storage on the local file system of - // the controller managing the Source. - // +required - Path string `json:"path"` - - // URL is the HTTP address of the Artifact as exposed by the controller - // managing the Source. It can be used to retrieve the Artifact for - // consumption, e.g. by another controller applying the Artifact contents. - // +required - URL string `json:"url"` - - // Revision is a human-readable identifier traceable in the origin source - // system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. - // +required - Revision string `json:"revision"` - - // Digest is the digest of the file in the form of ':'. - // +optional - // +kubebuilder:validation:Pattern="^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$" - Digest string `json:"digest,omitempty"` - - // LastUpdateTime is the timestamp corresponding to the last update of the - // Artifact. - // +required - LastUpdateTime metav1.Time `json:"lastUpdateTime"` - - // Size is the number of bytes in the file. - // +optional - Size *int64 `json:"size,omitempty"` - - // Metadata holds upstream information such as OCI annotations. - // +optional - Metadata map[string]string `json:"metadata,omitempty"` -} - -// HasRevision returns if the given revision matches the current Revision of -// the Artifact. -func (in *Artifact) HasRevision(revision string) bool { - if in == nil { - return false - } - return in.Revision == revision -} - -// HasDigest returns if the given digest matches the current Digest of the -// Artifact. -func (in *Artifact) HasDigest(digest string) bool { - if in == nil { - return false - } - return in.Digest == digest -} - -// ArtifactDir returns the artifact dir path in the form of -// '//'. -func ArtifactDir(kind, namespace, name string) string { - kind = strings.ToLower(kind) - return path.Join(kind, namespace, name) -} - -// ArtifactPath returns the artifact path in the form of -// '//name>/'. -func ArtifactPath(kind, namespace, name, filename string) string { - return path.Join(ArtifactDir(kind, namespace, name), filename) -} diff --git a/api/v1/bucket_types.go b/api/v1/bucket_types.go index 3e68e5029..bbedcefb3 100644 --- a/api/v1/bucket_types.go +++ b/api/v1/bucket_types.go @@ -209,7 +209,7 @@ type BucketStatus struct { // Artifact represents the last successful Bucket reconciliation. // +optional - Artifact *Artifact `json:"artifact,omitempty"` + Artifact *meta.Artifact `json:"artifact,omitempty"` // ObservedIgnore is the observed exclusion patterns used for constructing // the source artifact. @@ -245,7 +245,7 @@ func (in *Bucket) GetRequeueAfter() time.Duration { } // GetArtifact returns the latest artifact from the source if present in the status sub-resource. -func (in *Bucket) GetArtifact() *Artifact { +func (in *Bucket) GetArtifact() *meta.Artifact { return in.Status.Artifact } diff --git a/api/v1/gitrepository_types.go b/api/v1/gitrepository_types.go index 01efec291..f104fd0f1 100644 --- a/api/v1/gitrepository_types.go +++ b/api/v1/gitrepository_types.go @@ -256,12 +256,12 @@ type GitRepositoryStatus struct { // Artifact represents the last successful GitRepository reconciliation. // +optional - Artifact *Artifact `json:"artifact,omitempty"` + Artifact *meta.Artifact `json:"artifact,omitempty"` // IncludedArtifacts contains a list of the last successfully included // Artifacts as instructed by GitRepositorySpec.Include. // +optional - IncludedArtifacts []*Artifact `json:"includedArtifacts,omitempty"` + IncludedArtifacts []*meta.Artifact `json:"includedArtifacts,omitempty"` // ObservedIgnore is the observed exclusion patterns used for constructing // the source artifact. @@ -319,7 +319,7 @@ func (in GitRepository) GetRequeueAfter() time.Duration { // GetArtifact returns the latest Artifact from the GitRepository if present in // the status sub-resource. -func (in *GitRepository) GetArtifact() *Artifact { +func (in *GitRepository) GetArtifact() *meta.Artifact { return in.Status.Artifact } diff --git a/api/v1/helmchart_types.go b/api/v1/helmchart_types.go index 137b16450..23cb24146 100644 --- a/api/v1/helmchart_types.go +++ b/api/v1/helmchart_types.go @@ -149,7 +149,7 @@ type HelmChartStatus struct { // Artifact represents the output of the last successful reconciliation. // +optional - Artifact *Artifact `json:"artifact,omitempty"` + Artifact *meta.Artifact `json:"artifact,omitempty"` meta.ReconcileRequestStatus `json:",inline"` } @@ -182,7 +182,7 @@ func (in HelmChart) GetRequeueAfter() time.Duration { // GetArtifact returns the latest artifact from the source if present in the // status sub-resource. -func (in *HelmChart) GetArtifact() *Artifact { +func (in *HelmChart) GetArtifact() *meta.Artifact { return in.Status.Artifact } diff --git a/api/v1/helmrepository_types.go b/api/v1/helmrepository_types.go index 2a21f2c52..1c19064a5 100644 --- a/api/v1/helmrepository_types.go +++ b/api/v1/helmrepository_types.go @@ -150,7 +150,7 @@ type HelmRepositoryStatus struct { // Artifact represents the last successful HelmRepository reconciliation. // +optional - Artifact *Artifact `json:"artifact,omitempty"` + Artifact *meta.Artifact `json:"artifact,omitempty"` meta.ReconcileRequestStatus `json:",inline"` } @@ -191,7 +191,7 @@ func (in HelmRepository) GetTimeout() time.Duration { // GetArtifact returns the latest artifact from the source if present in the // status sub-resource. -func (in *HelmRepository) GetArtifact() *Artifact { +func (in *HelmRepository) GetArtifact() *meta.Artifact { return in.Status.Artifact } diff --git a/api/v1/ocirepository_types.go b/api/v1/ocirepository_types.go index b12773a66..8c4d3f0fc 100644 --- a/api/v1/ocirepository_types.go +++ b/api/v1/ocirepository_types.go @@ -200,7 +200,7 @@ type OCIRepositoryStatus struct { // Artifact represents the output of the last successful OCI Repository sync. // +optional - Artifact *Artifact `json:"artifact,omitempty"` + Artifact *meta.Artifact `json:"artifact,omitempty"` // ObservedIgnore is the observed exclusion patterns used for constructing // the source artifact. @@ -241,7 +241,7 @@ func (in OCIRepository) GetRequeueAfter() time.Duration { // GetArtifact returns the latest Artifact from the OCIRepository if present in // the status sub-resource. -func (in *OCIRepository) GetArtifact() *Artifact { +func (in *OCIRepository) GetArtifact() *meta.Artifact { return in.Status.Artifact } diff --git a/api/v1/source.go b/api/v1/source.go index 83040bc22..d879f6034 100644 --- a/api/v1/source.go +++ b/api/v1/source.go @@ -20,6 +20,8 @@ import ( "time" "k8s.io/apimachinery/pkg/runtime" + + "github.com/fluxcd/pkg/apis/meta" ) const ( @@ -41,5 +43,5 @@ type Source interface { GetRequeueAfter() time.Duration // GetArtifact returns the latest artifact from the source if present in // the status sub-resource. - GetArtifact() *Artifact + GetArtifact() *meta.Artifact } diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index ef99d2a39..33ee940ad 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -27,34 +27,6 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Artifact) DeepCopyInto(out *Artifact) { - *out = *in - in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) - if in.Size != nil { - in, out := &in.Size, &out.Size - *out = new(int64) - **out = **in - } - if in.Metadata != nil { - in, out := &in.Metadata, &out.Metadata - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Artifact. -func (in *Artifact) DeepCopy() *Artifact { - if in == nil { - return nil - } - out := new(Artifact) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Bucket) DeepCopyInto(out *Bucket) { *out = *in @@ -197,7 +169,7 @@ func (in *BucketStatus) DeepCopyInto(out *BucketStatus) { } if in.Artifact != nil { in, out := &in.Artifact, &out.Artifact - *out = new(Artifact) + *out = new(meta.Artifact) (*in).DeepCopyInto(*out) } if in.ObservedIgnore != nil { @@ -376,16 +348,16 @@ func (in *GitRepositoryStatus) DeepCopyInto(out *GitRepositoryStatus) { } if in.Artifact != nil { in, out := &in.Artifact, &out.Artifact - *out = new(Artifact) + *out = new(meta.Artifact) (*in).DeepCopyInto(*out) } if in.IncludedArtifacts != nil { in, out := &in.IncludedArtifacts, &out.IncludedArtifacts - *out = make([]*Artifact, len(*in)) + *out = make([]*meta.Artifact, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] - *out = new(Artifact) + *out = new(meta.Artifact) (*in).DeepCopyInto(*out) } } @@ -542,7 +514,7 @@ func (in *HelmChartStatus) DeepCopyInto(out *HelmChartStatus) { } if in.Artifact != nil { in, out := &in.Artifact, &out.Artifact - *out = new(Artifact) + *out = new(meta.Artifact) (*in).DeepCopyInto(*out) } out.ReconcileRequestStatus = in.ReconcileRequestStatus @@ -665,7 +637,7 @@ func (in *HelmRepositoryStatus) DeepCopyInto(out *HelmRepositoryStatus) { } if in.Artifact != nil { in, out := &in.Artifact, &out.Artifact - *out = new(Artifact) + *out = new(meta.Artifact) (*in).DeepCopyInto(*out) } out.ReconcileRequestStatus = in.ReconcileRequestStatus @@ -853,7 +825,7 @@ func (in *OCIRepositoryStatus) DeepCopyInto(out *OCIRepositoryStatus) { } if in.Artifact != nil { in, out := &in.Artifact, &out.Artifact - *out = new(Artifact) + *out = new(meta.Artifact) (*in).DeepCopyInto(*out) } if in.ObservedIgnore != nil { diff --git a/api/v1beta2/bucket_types.go b/api/v1beta2/bucket_types.go index d18fc76f7..6495abdd0 100644 --- a/api/v1beta2/bucket_types.go +++ b/api/v1beta2/bucket_types.go @@ -229,7 +229,7 @@ type BucketStatus struct { // Artifact represents the last successful Bucket reconciliation. // +optional - Artifact *apiv1.Artifact `json:"artifact,omitempty"` + Artifact *meta.Artifact `json:"artifact,omitempty"` // ObservedIgnore is the observed exclusion patterns used for constructing // the source artifact. @@ -265,7 +265,7 @@ func (in Bucket) GetRequeueAfter() time.Duration { } // GetArtifact returns the latest artifact from the source if present in the status sub-resource. -func (in *Bucket) GetArtifact() *apiv1.Artifact { +func (in *Bucket) GetArtifact() *meta.Artifact { return in.Status.Artifact } diff --git a/api/v1beta2/gitrepository_types.go b/api/v1beta2/gitrepository_types.go index 2e8685cda..89beeb9a7 100644 --- a/api/v1beta2/gitrepository_types.go +++ b/api/v1beta2/gitrepository_types.go @@ -23,8 +23,6 @@ import ( "github.com/fluxcd/pkg/apis/acl" "github.com/fluxcd/pkg/apis/meta" - - apiv1 "github.com/fluxcd/source-controller/api/v1" ) const ( @@ -214,12 +212,12 @@ type GitRepositoryStatus struct { // Artifact represents the last successful GitRepository reconciliation. // +optional - Artifact *apiv1.Artifact `json:"artifact,omitempty"` + Artifact *meta.Artifact `json:"artifact,omitempty"` // IncludedArtifacts contains a list of the last successfully included // Artifacts as instructed by GitRepositorySpec.Include. // +optional - IncludedArtifacts []*apiv1.Artifact `json:"includedArtifacts,omitempty"` + IncludedArtifacts []*meta.Artifact `json:"includedArtifacts,omitempty"` // ContentConfigChecksum is a checksum of all the configurations related to // the content of the source artifact: @@ -282,7 +280,7 @@ func (in GitRepository) GetRequeueAfter() time.Duration { // GetArtifact returns the latest Artifact from the GitRepository if present in // the status sub-resource. -func (in *GitRepository) GetArtifact() *apiv1.Artifact { +func (in *GitRepository) GetArtifact() *meta.Artifact { return in.Status.Artifact } diff --git a/api/v1beta2/helmchart_types.go b/api/v1beta2/helmchart_types.go index 6bc7875a8..ac24b1c13 100644 --- a/api/v1beta2/helmchart_types.go +++ b/api/v1beta2/helmchart_types.go @@ -166,7 +166,7 @@ type HelmChartStatus struct { // Artifact represents the output of the last successful reconciliation. // +optional - Artifact *apiv1.Artifact `json:"artifact,omitempty"` + Artifact *meta.Artifact `json:"artifact,omitempty"` meta.ReconcileRequestStatus `json:",inline"` } @@ -199,7 +199,7 @@ func (in HelmChart) GetRequeueAfter() time.Duration { // GetArtifact returns the latest artifact from the source if present in the // status sub-resource. -func (in *HelmChart) GetArtifact() *apiv1.Artifact { +func (in *HelmChart) GetArtifact() *meta.Artifact { return in.Status.Artifact } diff --git a/api/v1beta2/helmrepository_types.go b/api/v1beta2/helmrepository_types.go index 0a618b88b..56cbd928c 100644 --- a/api/v1beta2/helmrepository_types.go +++ b/api/v1beta2/helmrepository_types.go @@ -23,8 +23,6 @@ import ( "github.com/fluxcd/pkg/apis/acl" "github.com/fluxcd/pkg/apis/meta" - - apiv1 "github.com/fluxcd/source-controller/api/v1" ) const ( @@ -152,7 +150,7 @@ type HelmRepositoryStatus struct { // Artifact represents the last successful HelmRepository reconciliation. // +optional - Artifact *apiv1.Artifact `json:"artifact,omitempty"` + Artifact *meta.Artifact `json:"artifact,omitempty"` meta.ReconcileRequestStatus `json:",inline"` } @@ -193,7 +191,7 @@ func (in HelmRepository) GetTimeout() time.Duration { // GetArtifact returns the latest artifact from the source if present in the // status sub-resource. -func (in *HelmRepository) GetArtifact() *apiv1.Artifact { +func (in *HelmRepository) GetArtifact() *meta.Artifact { return in.Status.Artifact } diff --git a/api/v1beta2/ocirepository_types.go b/api/v1beta2/ocirepository_types.go index 55a513410..760f0d8f1 100644 --- a/api/v1beta2/ocirepository_types.go +++ b/api/v1beta2/ocirepository_types.go @@ -205,7 +205,7 @@ type OCIRepositoryStatus struct { // Artifact represents the output of the last successful OCI Repository sync. // +optional - Artifact *apiv1.Artifact `json:"artifact,omitempty"` + Artifact *meta.Artifact `json:"artifact,omitempty"` // ContentConfigChecksum is a checksum of all the configurations related to // the content of the source artifact: @@ -260,7 +260,7 @@ func (in OCIRepository) GetRequeueAfter() time.Duration { // GetArtifact returns the latest Artifact from the OCIRepository if present in // the status sub-resource. -func (in *OCIRepository) GetArtifact() *apiv1.Artifact { +func (in *OCIRepository) GetArtifact() *meta.Artifact { return in.Status.Artifact } diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go index 19c5d6af0..0b874dd7e 100644 --- a/api/v1beta2/zz_generated.deepcopy.go +++ b/api/v1beta2/zz_generated.deepcopy.go @@ -203,7 +203,7 @@ func (in *BucketStatus) DeepCopyInto(out *BucketStatus) { } if in.Artifact != nil { in, out := &in.Artifact, &out.Artifact - *out = new(apiv1.Artifact) + *out = new(meta.Artifact) (*in).DeepCopyInto(*out) } if in.ObservedIgnore != nil { @@ -377,16 +377,16 @@ func (in *GitRepositoryStatus) DeepCopyInto(out *GitRepositoryStatus) { } if in.Artifact != nil { in, out := &in.Artifact, &out.Artifact - *out = new(apiv1.Artifact) + *out = new(meta.Artifact) (*in).DeepCopyInto(*out) } if in.IncludedArtifacts != nil { in, out := &in.IncludedArtifacts, &out.IncludedArtifacts - *out = make([]*apiv1.Artifact, len(*in)) + *out = make([]*meta.Artifact, len(*in)) for i := range *in { if (*in)[i] != nil { in, out := &(*in)[i], &(*out)[i] - *out = new(apiv1.Artifact) + *out = new(meta.Artifact) (*in).DeepCopyInto(*out) } } @@ -538,7 +538,7 @@ func (in *HelmChartStatus) DeepCopyInto(out *HelmChartStatus) { } if in.Artifact != nil { in, out := &in.Artifact, &out.Artifact - *out = new(apiv1.Artifact) + *out = new(meta.Artifact) (*in).DeepCopyInto(*out) } out.ReconcileRequestStatus = in.ReconcileRequestStatus @@ -661,7 +661,7 @@ func (in *HelmRepositoryStatus) DeepCopyInto(out *HelmRepositoryStatus) { } if in.Artifact != nil { in, out := &in.Artifact, &out.Artifact - *out = new(apiv1.Artifact) + *out = new(meta.Artifact) (*in).DeepCopyInto(*out) } out.ReconcileRequestStatus = in.ReconcileRequestStatus @@ -849,7 +849,7 @@ func (in *OCIRepositoryStatus) DeepCopyInto(out *OCIRepositoryStatus) { } if in.Artifact != nil { in, out := &in.Artifact, &out.Artifact - *out = new(apiv1.Artifact) + *out = new(meta.Artifact) (*in).DeepCopyInto(*out) } if in.ObservedIgnore != nil { diff --git a/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml b/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml index 6f89f6662..f578c8da0 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml @@ -289,6 +289,7 @@ spec: consumption, e.g. by another controller applying the Artifact contents. type: string required: + - digest - lastUpdateTime - path - revision @@ -672,6 +673,7 @@ spec: consumption, e.g. by another controller applying the Artifact contents. type: string required: + - digest - lastUpdateTime - path - revision diff --git a/config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml b/config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml index 57d202ec5..10663e473 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml @@ -290,6 +290,7 @@ spec: consumption, e.g. by another controller applying the Artifact contents. type: string required: + - digest - lastUpdateTime - path - revision @@ -398,6 +399,7 @@ spec: consumption, e.g. by another controller applying the Artifact contents. type: string required: + - digest - lastUpdateTime - path - revision @@ -746,6 +748,7 @@ spec: consumption, e.g. by another controller applying the Artifact contents. type: string required: + - digest - lastUpdateTime - path - revision @@ -869,6 +872,7 @@ spec: consumption, e.g. by another controller applying the Artifact contents. type: string required: + - digest - lastUpdateTime - path - revision diff --git a/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml b/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml index b8f0ecd63..0e57c72a5 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml @@ -244,6 +244,7 @@ spec: consumption, e.g. by another controller applying the Artifact contents. type: string required: + - digest - lastUpdateTime - path - revision @@ -613,6 +614,7 @@ spec: consumption, e.g. by another controller applying the Artifact contents. type: string required: + - digest - lastUpdateTime - path - revision diff --git a/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml b/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml index 7aa3c63f1..750a36500 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml @@ -232,6 +232,7 @@ spec: consumption, e.g. by another controller applying the Artifact contents. type: string required: + - digest - lastUpdateTime - path - revision @@ -536,6 +537,7 @@ spec: consumption, e.g. by another controller applying the Artifact contents. type: string required: + - digest - lastUpdateTime - path - revision diff --git a/config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml b/config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml index e91854664..05b7b96ab 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml @@ -299,6 +299,7 @@ spec: consumption, e.g. by another controller applying the Artifact contents. type: string required: + - digest - lastUpdateTime - path - revision @@ -696,6 +697,7 @@ spec: consumption, e.g. by another controller applying the Artifact contents. type: string required: + - digest - lastUpdateTime - path - revision diff --git a/docs/api/v1/source.md b/docs/api/v1/source.md index fc0de3026..3d8232a5d 100644 --- a/docs/api/v1/source.md +++ b/docs/api/v1/source.md @@ -1327,119 +1327,6 @@ OCIRepositoryStatus -

Artifact -

-

-(Appears on: -BucketStatus, -GitRepositoryStatus, -HelmChartStatus, -HelmRepositoryStatus, -OCIRepositoryStatus) -

-

Artifact represents the output of a Source reconciliation.

-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FieldDescription
-path
- -string - -
-

Path is the relative file path of the Artifact. It can be used to locate -the file in the root of the Artifact storage on the local file system of -the controller managing the Source.

-
-url
- -string - -
-

URL is the HTTP address of the Artifact as exposed by the controller -managing the Source. It can be used to retrieve the Artifact for -consumption, e.g. by another controller applying the Artifact contents.

-
-revision
- -string - -
-

Revision is a human-readable identifier traceable in the origin source -system. It can be a Git commit SHA, Git tag, a Helm chart version, etc.

-
-digest
- -string - -
-(Optional) -

Digest is the digest of the file in the form of ‘:’.

-
-lastUpdateTime
- - -Kubernetes meta/v1.Time - - -
-

LastUpdateTime is the timestamp corresponding to the last update of the -Artifact.

-
-size
- -int64 - -
-(Optional) -

Size is the number of bytes in the file.

-
-metadata
- -map[string]string - -
-(Optional) -

Metadata holds upstream information such as OCI annotations.

-
-
-

BucketSTSSpec

@@ -1827,8 +1714,8 @@ BucketStatus.Artifact data is recommended.

artifact
- -Artifact + +github.com/fluxcd/pkg/apis/meta.Artifact @@ -2286,8 +2173,8 @@ object.

artifact
- -Artifact + +github.com/fluxcd/pkg/apis/meta.Artifact @@ -2300,8 +2187,8 @@ Artifact includedArtifacts
- -[]Artifact + +[]github.com/fluxcd/pkg/apis/meta.Artifact @@ -2711,8 +2598,8 @@ BucketStatus.Artifact data is recommended.

artifact
- -Artifact + +github.com/fluxcd/pkg/apis/meta.Artifact @@ -3001,8 +2888,8 @@ HelmRepositoryStatus.Artifact data is recommended.

artifact
- -Artifact + +github.com/fluxcd/pkg/apis/meta.Artifact @@ -3497,8 +3384,8 @@ string artifact
- -Artifact + +github.com/fluxcd/pkg/apis/meta.Artifact diff --git a/go.mod b/go.mod index 683973020..c70642968 100644 --- a/go.mod +++ b/go.mod @@ -23,8 +23,8 @@ require ( github.com/elazarl/goproxy v1.7.2 github.com/fluxcd/cli-utils v0.36.0-flux.15 github.com/fluxcd/pkg/apis/event v0.19.0 - github.com/fluxcd/pkg/apis/meta v1.20.0 - github.com/fluxcd/pkg/auth v0.29.0 + github.com/fluxcd/pkg/apis/meta v1.21.0 + github.com/fluxcd/pkg/auth v0.30.0 github.com/fluxcd/pkg/cache v0.11.0 github.com/fluxcd/pkg/git v0.36.0 github.com/fluxcd/pkg/git/gogit v0.40.0 diff --git a/go.sum b/go.sum index 15a9ba03a..c740d4b4e 100644 --- a/go.sum +++ b/go.sum @@ -376,10 +376,10 @@ github.com/fluxcd/pkg/apis/acl v0.9.0 h1:wBpgsKT+jcyZEcM//OmZr9RiF8klL3ebrDp2u2T github.com/fluxcd/pkg/apis/acl v0.9.0/go.mod h1:TttNS+gocsGLwnvmgVi3/Yscwqrjc17+vhgYfqkfrV4= github.com/fluxcd/pkg/apis/event v0.19.0 h1:ZJU2voontkzp5rNYA4JMOu40S4tRcrWi4Do59EnyFwg= github.com/fluxcd/pkg/apis/event v0.19.0/go.mod h1:deuIyUb6lh+Z1Ccvwwxhm1wNM3kpSo+vF1IgRnpaZfQ= -github.com/fluxcd/pkg/apis/meta v1.20.0 h1:l9h0kWoDZTcYV0WJkFMgDXq6Q4tSojrJ+bHpFJSsaW0= -github.com/fluxcd/pkg/apis/meta v1.20.0/go.mod h1:XUAEUgT4gkWDAEN79E141tmL+v4SV50tVZ/Ojpc/ueg= -github.com/fluxcd/pkg/auth v0.29.0 h1:lLc63zjodqIqg5ydlU/Kp3Qa+wvh6G2khjop5MHALvk= -github.com/fluxcd/pkg/auth v0.29.0/go.mod h1:bjZ+6RMSGgsQQK+aPfVP8HWuBbb+FLlFxMiqd8ywzik= +github.com/fluxcd/pkg/apis/meta v1.21.0 h1:R+bN02chcs0HUmyVDQhqe/FHmYLjipVDMLnyYfNX850= +github.com/fluxcd/pkg/apis/meta v1.21.0/go.mod h1:XUAEUgT4gkWDAEN79E141tmL+v4SV50tVZ/Ojpc/ueg= +github.com/fluxcd/pkg/auth v0.30.0 h1:7JMnY1ClArvOsadt6hOxceu8Q2hLsYHFMt0DV3BQl4Q= +github.com/fluxcd/pkg/auth v0.30.0/go.mod h1:me38o1nDfSLw6YvnkT9Ce/zqJZICZSA7j5pNMR3JUbc= github.com/fluxcd/pkg/cache v0.11.0 h1:fsE8S+una21fSNw4MDXGUIf0Gf1J+pqa4RbsVKf2aTI= github.com/fluxcd/pkg/cache v0.11.0/go.mod h1:2RTIU6PsJniHmfnllQWFEo7fa5V8KQlnMgn4o0sme40= github.com/fluxcd/pkg/git v0.36.0 h1:oakFKxTX5yiLcFzCS1SaV+mMXaODaF1Ic6/oCLfIe7I= diff --git a/internal/controller/artifact.go b/internal/controller/artifact.go index 0de6b3706..bebc8d5ae 100644 --- a/internal/controller/artifact.go +++ b/internal/controller/artifact.go @@ -16,9 +16,11 @@ limitations under the License. package controller -import sourcev1 "github.com/fluxcd/source-controller/api/v1" +import ( + "github.com/fluxcd/pkg/apis/meta" +) -type artifactSet []*sourcev1.Artifact +type artifactSet []*meta.Artifact // Diff returns true if any of the revisions in the artifactSet does not match any of the given artifacts. func (s artifactSet) Diff(set artifactSet) bool { diff --git a/internal/controller/artifact_matchers_test.go b/internal/controller/artifact_matchers_test.go index 39f0c9dd7..af716e086 100644 --- a/internal/controller/artifact_matchers_test.go +++ b/internal/controller/artifact_matchers_test.go @@ -19,24 +19,25 @@ package controller import ( "fmt" - sourcev1 "github.com/fluxcd/source-controller/api/v1" . "github.com/onsi/gomega" "github.com/onsi/gomega/types" + + "github.com/fluxcd/pkg/apis/meta" ) // MatchArtifact returns a custom matcher to check equality of a v1beta1.Artifact, the timestamp and URL are ignored. -func MatchArtifact(expected *sourcev1.Artifact) types.GomegaMatcher { +func MatchArtifact(expected *meta.Artifact) types.GomegaMatcher { return &matchArtifact{ expected: expected, } } type matchArtifact struct { - expected *sourcev1.Artifact + expected *meta.Artifact } func (m matchArtifact) Match(actual interface{}) (success bool, err error) { - actualArtifact, ok := actual.(*sourcev1.Artifact) + actualArtifact, ok := actual.(*meta.Artifact) if !ok { return false, fmt.Errorf("actual should be a pointer to an Artifact") } diff --git a/internal/controller/bucket_controller_test.go b/internal/controller/bucket_controller_test.go index e00541bbe..8770588b5 100644 --- a/internal/controller/bucket_controller_test.go +++ b/internal/controller/bucket_controller_test.go @@ -201,7 +201,7 @@ func TestBucketReconciler_reconcileStorage(t *testing.T) { beforeFunc func(obj *sourcev1.Bucket, storage *storage.Storage) error want sreconcile.Result wantErr bool - assertArtifact *sourcev1.Artifact + assertArtifact *meta.Artifact assertConditions []metav1.Condition assertPaths []string }{ @@ -211,7 +211,7 @@ func TestBucketReconciler_reconcileStorage(t *testing.T) { revisions := []string{"a", "b", "c", "d"} for n := range revisions { v := revisions[n] - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: fmt.Sprintf("/reconcile-storage/%s.txt", v), Revision: v, } @@ -229,7 +229,7 @@ func TestBucketReconciler_reconcileStorage(t *testing.T) { conditions.MarkTrue(obj, meta.ReadyCondition, "foo", "bar") return nil }, - assertArtifact: &sourcev1.Artifact{ + assertArtifact: &meta.Artifact{ Path: "/reconcile-storage/d.txt", Revision: "d", Digest: "sha256:18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e4", @@ -258,7 +258,7 @@ func TestBucketReconciler_reconcileStorage(t *testing.T) { { name: "notices missing artifact in storage", beforeFunc: func(obj *sourcev1.Bucket, storage *storage.Storage) error { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: "/reconcile-storage/invalid.txt", Revision: "d", } @@ -279,7 +279,7 @@ func TestBucketReconciler_reconcileStorage(t *testing.T) { beforeFunc: func(obj *sourcev1.Bucket, storage *storage.Storage) error { f := "empty-digest.txt" - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: fmt.Sprintf("/reconcile-storage/%s.txt", f), Revision: "fake", } @@ -310,7 +310,7 @@ func TestBucketReconciler_reconcileStorage(t *testing.T) { beforeFunc: func(obj *sourcev1.Bucket, storage *storage.Storage) error { f := "digest-mismatch.txt" - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: fmt.Sprintf("/reconcile-storage/%s.txt", f), Revision: "fake", } @@ -339,7 +339,7 @@ func TestBucketReconciler_reconcileStorage(t *testing.T) { { name: "updates hostname on diff from current", beforeFunc: func(obj *sourcev1.Bucket, storage *storage.Storage) error { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: "/reconcile-storage/hostname.txt", Revision: "f", Digest: "sha256:3b9c358f36f0a31b6ad3e14f309c7cf198ac9246e8316f9ce543d5b19ac02b80", @@ -358,7 +358,7 @@ func TestBucketReconciler_reconcileStorage(t *testing.T) { assertPaths: []string{ "/reconcile-storage/hostname.txt", }, - assertArtifact: &sourcev1.Artifact{ + assertArtifact: &meta.Artifact{ Path: "/reconcile-storage/hostname.txt", Revision: "f", Digest: "sha256:3b9c358f36f0a31b6ad3e14f309c7cf198ac9246e8316f9ce543d5b19ac02b80", @@ -827,7 +827,7 @@ func TestBucketReconciler_reconcileSource_generic(t *testing.T) { name: "Up-to-date artifact", bucketName: "dummy", beforeFunc: func(obj *sourcev1.Bucket) { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Revision: "sha256:b4c2a60ce44b67f5b659a95ce4e4cc9e2a86baf13afb72bd397c5384cbc0e479", } conditions.MarkReconciling(obj, meta.ProgressingReason, "foo") @@ -885,7 +885,7 @@ func TestBucketReconciler_reconcileSource_generic(t *testing.T) { }, }, beforeFunc: func(obj *sourcev1.Bucket) { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: "some-path", Revision: "some-rev", } @@ -1219,7 +1219,7 @@ func TestBucketReconciler_reconcileSource_gcs(t *testing.T) { name: "Up-to-date artifact", bucketName: "dummy", beforeFunc: func(obj *sourcev1.Bucket) { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Revision: "sha256:b4c2a60ce44b67f5b659a95ce4e4cc9e2a86baf13afb72bd397c5384cbc0e479", } conditions.MarkReconciling(obj, meta.ProgressingReason, "foo") @@ -1277,7 +1277,7 @@ func TestBucketReconciler_reconcileSource_gcs(t *testing.T) { }, }, beforeFunc: func(obj *sourcev1.Bucket) { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: "some-path", Revision: "some-rev", } @@ -1488,7 +1488,7 @@ func TestBucketReconciler_reconcileArtifact(t *testing.T) { revision := index.Digest(intdigest.Canonical) obj.Spec.Interval = metav1.Duration{Duration: interval} // Incomplete artifact - obj.Status.Artifact = &sourcev1.Artifact{Revision: revision.String()} + obj.Status.Artifact = &meta.Artifact{Revision: revision.String()} conditions.MarkReconciling(obj, meta.ProgressingReason, "foo") conditions.MarkUnknown(obj, meta.ReadyCondition, "foo", "bar") }, @@ -1751,7 +1751,7 @@ func TestBucketReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, newObjBeforeFunc: func(obj *sourcev1.Bucket) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} }, wantEvent: "Normal NewArtifact stored artifact with 2 fetched files from", }, @@ -1760,12 +1760,12 @@ func TestBucketReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.Bucket) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.GitOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, newObjBeforeFunc: func(obj *sourcev1.Bucket) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, wantEvent: "Normal Succeeded stored artifact with 2 fetched files from", @@ -1775,12 +1775,12 @@ func TestBucketReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.Bucket) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.GitOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, newObjBeforeFunc: func(obj *sourcev1.Bucket) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "aaa", Digest: "bbb"} + obj.Status.Artifact = &meta.Artifact{Revision: "aaa", Digest: "bbb"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, wantEvent: "Normal NewArtifact stored artifact with 2 fetched files from", @@ -1790,11 +1790,11 @@ func TestBucketReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.Bucket) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, newObjBeforeFunc: func(obj *sourcev1.Bucket) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, }, diff --git a/internal/controller/gitrepository_controller.go b/internal/controller/gitrepository_controller.go index e704790d3..a80001165 100644 --- a/internal/controller/gitrepository_controller.go +++ b/internal/controller/gitrepository_controller.go @@ -938,7 +938,7 @@ func (r *GitRepositoryReconciler) reconcileInclude(ctx context.Context, sp *patc // such that the index of artifactSet matches with the index of Include. // Hence, index is used here to pick the associated artifact from // includes. - var artifact *sourcev1.Artifact + var artifact *meta.Artifact for j, art := range *includes { if i == j { artifact = art @@ -1271,7 +1271,7 @@ func gitContentConfigChanged(obj *sourcev1.GitRepository, includes *artifactSet) // Convert artifactSet to index addressable artifacts and ensure that it and // the included artifacts include all the include from the spec. - artifacts := []*sourcev1.Artifact(*includes) + artifacts := []*meta.Artifact(*includes) if len(obj.Spec.Include) != len(artifacts) { return true } diff --git a/internal/controller/gitrepository_controller_test.go b/internal/controller/gitrepository_controller_test.go index 23ee80846..1876fa007 100644 --- a/internal/controller/gitrepository_controller_test.go +++ b/internal/controller/gitrepository_controller_test.go @@ -699,7 +699,7 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) { beforeFunc: func(obj *sourcev1.GitRepository) { obj.Spec.SecretRef = &meta.LocalObjectReference{Name: "basic-auth"} obj.Status = sourcev1.GitRepositoryStatus{ - Artifact: &sourcev1.Artifact{ + Artifact: &meta.Artifact{ Revision: "staging/some-revision", Path: randStringRunes(10), }, @@ -1166,7 +1166,7 @@ func TestGitRepositoryReconciler_reconcileSource_checkoutStrategy(t *testing.T) }, beforeFunc: func(obj *sourcev1.GitRepository, latestRev string) { obj.Status = sourcev1.GitRepositoryStatus{ - Artifact: &sourcev1.Artifact{ + Artifact: &meta.Artifact{ Revision: "staging/some-revision", Path: randStringRunes(10), }, @@ -1187,7 +1187,7 @@ func TestGitRepositoryReconciler_reconcileSource_checkoutStrategy(t *testing.T) beforeFunc: func(obj *sourcev1.GitRepository, latestRev string) { // Add existing artifact on the object and storage. obj.Status = sourcev1.GitRepositoryStatus{ - Artifact: &sourcev1.Artifact{ + Artifact: &meta.Artifact{ Revision: "staging@sha1:" + latestRev, Path: randStringRunes(10), }, @@ -1210,7 +1210,7 @@ func TestGitRepositoryReconciler_reconcileSource_checkoutStrategy(t *testing.T) obj.Spec.Ignore = ptr.To("foo") // Add existing artifact on the object and storage. obj.Status = sourcev1.GitRepositoryStatus{ - Artifact: &sourcev1.Artifact{ + Artifact: &meta.Artifact{ Revision: "staging@sha1:" + latestRev, Path: randStringRunes(10), }, @@ -1341,7 +1341,7 @@ func TestGitRepositoryReconciler_reconcileArtifact(t *testing.T) { { name: "Archiving artifact to storage with includes makes ArtifactInStorage=True", dir: "testdata/git/repository", - includes: artifactSet{&sourcev1.Artifact{Revision: "main@sha1:b9b3feadba509cb9b22e968a5d27e96c2bc2ff91"}}, + includes: artifactSet{&meta.Artifact{Revision: "main@sha1:b9b3feadba509cb9b22e968a5d27e96c2bc2ff91"}}, beforeFunc: func(obj *sourcev1.GitRepository) { obj.Spec.Interval = metav1.Duration{Duration: interval} obj.Spec.Include = []sourcev1.GitRepositoryInclude{ @@ -1361,14 +1361,14 @@ func TestGitRepositoryReconciler_reconcileArtifact(t *testing.T) { { name: "Up-to-date artifact should not update status", dir: "testdata/git/repository", - includes: artifactSet{&sourcev1.Artifact{Revision: "main@sha1:b9b3feadba509cb9b22e968a5d27e96c2bc2ff91", Digest: "some-checksum"}}, + includes: artifactSet{&meta.Artifact{Revision: "main@sha1:b9b3feadba509cb9b22e968a5d27e96c2bc2ff91", Digest: "some-checksum"}}, beforeFunc: func(obj *sourcev1.GitRepository) { obj.Spec.Interval = metav1.Duration{Duration: interval} obj.Spec.Include = []sourcev1.GitRepositoryInclude{ {GitRepositoryRef: meta.LocalObjectReference{Name: "foo"}}, } - obj.Status.Artifact = &sourcev1.Artifact{Revision: "main@sha1:b9b3feadba509cb9b22e968a5d27e96c2bc2ff91"} - obj.Status.IncludedArtifacts = []*sourcev1.Artifact{{Revision: "main@sha1:b9b3feadba509cb9b22e968a5d27e96c2bc2ff91", Digest: "some-checksum"}} + obj.Status.Artifact = &meta.Artifact{Revision: "main@sha1:b9b3feadba509cb9b22e968a5d27e96c2bc2ff91"} + obj.Status.IncludedArtifacts = []*meta.Artifact{{Revision: "main@sha1:b9b3feadba509cb9b22e968a5d27e96c2bc2ff91", Digest: "some-checksum"}} obj.Status.ObservedInclude = obj.Spec.Include }, want: sreconcile.ResultSuccess, @@ -1587,7 +1587,7 @@ func TestGitRepositoryReconciler_reconcileInclude(t *testing.T) { }, } if d.withArtifact { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: d.name + ".tar.gz", Revision: d.name, LastUpdateTime: metav1.Now(), @@ -1682,7 +1682,7 @@ func TestGitRepositoryReconciler_reconcileStorage(t *testing.T) { beforeFunc func(obj *sourcev1.GitRepository, storage *storage.Storage) error want sreconcile.Result wantErr bool - assertArtifact *sourcev1.Artifact + assertArtifact *meta.Artifact assertConditions []metav1.Condition assertPaths []string }{ @@ -1692,7 +1692,7 @@ func TestGitRepositoryReconciler_reconcileStorage(t *testing.T) { revisions := []string{"a", "b", "c", "d"} for n := range revisions { v := revisions[n] - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: fmt.Sprintf("/reconcile-storage/%s.txt", v), Revision: v, } @@ -1710,7 +1710,7 @@ func TestGitRepositoryReconciler_reconcileStorage(t *testing.T) { conditions.MarkTrue(obj, meta.ReadyCondition, "foo", "bar") return nil }, - assertArtifact: &sourcev1.Artifact{ + assertArtifact: &meta.Artifact{ Path: "/reconcile-storage/d.txt", Revision: "d", Digest: "sha256:18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e4", @@ -1739,7 +1739,7 @@ func TestGitRepositoryReconciler_reconcileStorage(t *testing.T) { { name: "notices missing artifact in storage", beforeFunc: func(obj *sourcev1.GitRepository, storage *storage.Storage) error { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: "/reconcile-storage/invalid.txt", Revision: "e", } @@ -1760,7 +1760,7 @@ func TestGitRepositoryReconciler_reconcileStorage(t *testing.T) { beforeFunc: func(obj *sourcev1.GitRepository, storage *storage.Storage) error { f := "empty-digest.txt" - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: fmt.Sprintf("/reconcile-storage/%s.txt", f), Revision: "fake", } @@ -1791,7 +1791,7 @@ func TestGitRepositoryReconciler_reconcileStorage(t *testing.T) { beforeFunc: func(obj *sourcev1.GitRepository, storage *storage.Storage) error { f := "digest-mismatch.txt" - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: fmt.Sprintf("/reconcile-storage/%s.txt", f), Revision: "fake", } @@ -1820,7 +1820,7 @@ func TestGitRepositoryReconciler_reconcileStorage(t *testing.T) { { name: "updates hostname on diff from current", beforeFunc: func(obj *sourcev1.GitRepository, storage *storage.Storage) error { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: "/reconcile-storage/hostname.txt", Revision: "f", Digest: "sha256:3b9c358f36f0a31b6ad3e14f309c7cf198ac9246e8316f9ce543d5b19ac02b80", @@ -1839,7 +1839,7 @@ func TestGitRepositoryReconciler_reconcileStorage(t *testing.T) { assertPaths: []string{ "/reconcile-storage/hostname.txt", }, - assertArtifact: &sourcev1.Artifact{ + assertArtifact: &meta.Artifact{ Path: "/reconcile-storage/hostname.txt", Revision: "f", Digest: "sha256:3b9c358f36f0a31b6ad3e14f309c7cf198ac9246e8316f9ce543d5b19ac02b80", @@ -2799,7 +2799,7 @@ func TestGitRepositoryReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, newObjBeforeFunc: func(obj *sourcev1.GitRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} }, commit: concreteCommit, wantEvent: "Normal NewArtifact stored artifact for commit 'test commit'", @@ -2809,12 +2809,12 @@ func TestGitRepositoryReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.GitRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.GitOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, newObjBeforeFunc: func(obj *sourcev1.GitRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, commit: concreteCommit, @@ -2825,12 +2825,12 @@ func TestGitRepositoryReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.GitRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.GitOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, newObjBeforeFunc: func(obj *sourcev1.GitRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "aaa", Digest: "bbb"} + obj.Status.Artifact = &meta.Artifact{Revision: "aaa", Digest: "bbb"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, commit: concreteCommit, @@ -2841,11 +2841,11 @@ func TestGitRepositoryReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.GitRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, newObjBeforeFunc: func(obj *sourcev1.GitRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, }, @@ -2854,12 +2854,12 @@ func TestGitRepositoryReconciler_notify(t *testing.T) { res: sreconcile.ResultEmpty, resErr: noopErr, oldObjBeforeFunc: func(obj *sourcev1.GitRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.GitOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, newObjBeforeFunc: func(obj *sourcev1.GitRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, commit: partialCommit, // no-op will always result in partial commit. @@ -2950,7 +2950,7 @@ func TestGitRepositoryReconciler_fetchIncludes(t *testing.T) { {name: "b", toPath: "b/", shouldExist: true}, }, wantErr: false, - wantArtifactSet: []*sourcev1.Artifact{ + wantArtifactSet: []*meta.Artifact{ {Revision: "a"}, {Revision: "b"}, }, @@ -3008,7 +3008,7 @@ func TestGitRepositoryReconciler_fetchIncludes(t *testing.T) { }, } if d.withArtifact { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: d.name + ".tar.gz", Revision: d.name, LastUpdateTime: metav1.Now(), @@ -3166,7 +3166,7 @@ func TestGitContentConfigChanged(t *testing.T) { tests := []struct { name string obj sourcev1.GitRepository - artifacts []*sourcev1.Artifact + artifacts []*meta.Artifact want bool }{ { @@ -3266,10 +3266,10 @@ func TestGitContentConfigChanged(t *testing.T) { ToPath: "baz", }, }, - IncludedArtifacts: []*sourcev1.Artifact{{Revision: "aaa", Digest: "bbb"}}, + IncludedArtifacts: []*meta.Artifact{{Revision: "aaa", Digest: "bbb"}}, }, }, - artifacts: []*sourcev1.Artifact{ + artifacts: []*meta.Artifact{ {Revision: "aaa", Digest: "bbb"}, }, want: false, @@ -3294,10 +3294,10 @@ func TestGitContentConfigChanged(t *testing.T) { ToPath: "baz", }, }, - IncludedArtifacts: []*sourcev1.Artifact{{Revision: "aaa", Digest: "bbb"}}, + IncludedArtifacts: []*meta.Artifact{{Revision: "aaa", Digest: "bbb"}}, }, }, - artifacts: []*sourcev1.Artifact{ + artifacts: []*meta.Artifact{ {Revision: "ccc", Digest: "bbb"}, }, want: true, @@ -3322,10 +3322,10 @@ func TestGitContentConfigChanged(t *testing.T) { ToPath: "baz", }, }, - IncludedArtifacts: []*sourcev1.Artifact{{Revision: "aaa", Digest: "bbb"}}, + IncludedArtifacts: []*meta.Artifact{{Revision: "aaa", Digest: "bbb"}}, }, }, - artifacts: []*sourcev1.Artifact{ + artifacts: []*meta.Artifact{ {Revision: "aaa", Digest: "ddd"}, }, want: true, @@ -3350,10 +3350,10 @@ func TestGitContentConfigChanged(t *testing.T) { ToPath: "baz", }, }, - IncludedArtifacts: []*sourcev1.Artifact{{Revision: "aaa", Digest: "bbb"}}, + IncludedArtifacts: []*meta.Artifact{{Revision: "aaa", Digest: "bbb"}}, }, }, - artifacts: []*sourcev1.Artifact{ + artifacts: []*meta.Artifact{ {Revision: "aaa", Digest: "bbb"}, }, want: true, @@ -3376,13 +3376,13 @@ func TestGitContentConfigChanged(t *testing.T) { }, }, Status: sourcev1.GitRepositoryStatus{ - IncludedArtifacts: []*sourcev1.Artifact{ + IncludedArtifacts: []*meta.Artifact{ {Revision: "aaa", Digest: "bbb"}, {Revision: "ccc", Digest: "ccc"}, }, }, }, - artifacts: []*sourcev1.Artifact{ + artifacts: []*meta.Artifact{ {Revision: "aaa", Digest: "bbb"}, {Revision: "ccc", Digest: "ddd"}, }, @@ -3418,13 +3418,13 @@ func TestGitContentConfigChanged(t *testing.T) { ToPath: "baz", }, }, - IncludedArtifacts: []*sourcev1.Artifact{ + IncludedArtifacts: []*meta.Artifact{ {Revision: "aaa", Digest: "bbb"}, {Revision: "ccc", Digest: "ccc"}, }, }, }, - artifacts: []*sourcev1.Artifact{ + artifacts: []*meta.Artifact{ {Revision: "aaa", Digest: "bbb"}, }, want: true, @@ -3459,12 +3459,12 @@ func TestGitContentConfigChanged(t *testing.T) { ToPath: "baz", }, }, - IncludedArtifacts: []*sourcev1.Artifact{ + IncludedArtifacts: []*meta.Artifact{ {Revision: "aaa", Digest: "bbb"}, }, }, }, - artifacts: []*sourcev1.Artifact{ + artifacts: []*meta.Artifact{ {Revision: "aaa", Digest: "bbb"}, {Revision: "ccc", Digest: "ccc"}, }, diff --git a/internal/controller/helmchart_controller.go b/internal/controller/helmchart_controller.go index 6559a2528..ef5a995f0 100644 --- a/internal/controller/helmchart_controller.go +++ b/internal/controller/helmchart_controller.go @@ -697,7 +697,7 @@ func (r *HelmChartReconciler) buildFromHelmRepository(ctx context.Context, obj * // v1.Artifact. // In case of a failure it records v1.FetchFailedCondition on the chart // object, and returns early. -func (r *HelmChartReconciler) buildFromTarballArtifact(ctx context.Context, obj *sourcev1.HelmChart, source sourcev1.Artifact, b *chart.Build) (sreconcile.Result, error) { +func (r *HelmChartReconciler) buildFromTarballArtifact(ctx context.Context, obj *sourcev1.HelmChart, source meta.Artifact, b *chart.Build) (sreconcile.Result, error) { // Create temporary working directory tmpDir, err := util.TempDirForObj("", obj) if err != nil { diff --git a/internal/controller/helmchart_controller_test.go b/internal/controller/helmchart_controller_test.go index 303b97a60..dd23c5fee 100644 --- a/internal/controller/helmchart_controller_test.go +++ b/internal/controller/helmchart_controller_test.go @@ -336,7 +336,7 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) { beforeFunc func(obj *sourcev1.HelmChart, storage *storage.Storage) error want sreconcile.Result wantErr bool - assertArtifact *sourcev1.Artifact + assertArtifact *meta.Artifact assertConditions []metav1.Condition assertPaths []string }{ @@ -346,7 +346,7 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) { revisions := []string{"a", "b", "c", "d"} for n := range revisions { v := revisions[n] - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: fmt.Sprintf("/reconcile-storage/%s.txt", v), Revision: v, } @@ -364,7 +364,7 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) { conditions.MarkTrue(obj, meta.ReadyCondition, "foo", "bar") return nil }, - assertArtifact: &sourcev1.Artifact{ + assertArtifact: &meta.Artifact{ Path: "/reconcile-storage/d.txt", Revision: "d", Digest: "sha256:18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e4", @@ -393,7 +393,7 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) { { name: "notices missing artifact in storage", beforeFunc: func(obj *sourcev1.HelmChart, storage *storage.Storage) error { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: "/reconcile-storage/invalid.txt", Revision: "d", } @@ -414,7 +414,7 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) { beforeFunc: func(obj *sourcev1.HelmChart, storage *storage.Storage) error { f := "empty-digest.txt" - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: fmt.Sprintf("/reconcile-storage/%s.txt", f), Revision: "fake", } @@ -445,7 +445,7 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) { beforeFunc: func(obj *sourcev1.HelmChart, storage *storage.Storage) error { f := "digest-mismatch.txt" - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: fmt.Sprintf("/reconcile-storage/%s.txt", f), Revision: "fake", } @@ -474,7 +474,7 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) { { name: "updates hostname on diff from current", beforeFunc: func(obj *sourcev1.HelmChart, storage *storage.Storage) error { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: "/reconcile-storage/hostname.txt", Revision: "f", Digest: "sha256:3b9c358f36f0a31b6ad3e14f309c7cf198ac9246e8316f9ce543d5b19ac02b80", @@ -493,7 +493,7 @@ func TestHelmChartReconciler_reconcileStorage(t *testing.T) { assertPaths: []string{ "/reconcile-storage/hostname.txt", }, - assertArtifact: &sourcev1.Artifact{ + assertArtifact: &meta.Artifact{ Path: "/reconcile-storage/hostname.txt", Revision: "f", Digest: "sha256:3b9c358f36f0a31b6ad3e14f309c7cf198ac9246e8316f9ce543d5b19ac02b80", @@ -574,7 +574,7 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { storage, err := storage.New(tmpDir, "example.com", retentionTTL, retentionRecords) g.Expect(err).ToNot(HaveOccurred()) - gitArtifact := &sourcev1.Artifact{ + gitArtifact := &meta.Artifact{ Revision: "mock-ref/abcdefg12345678", Path: "mock.tgz", } @@ -641,7 +641,7 @@ func TestHelmChartReconciler_reconcileSource(t *testing.T) { Name: "gitrepository", Kind: sourcev1.GitRepositoryKind, } - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: "some-path", Revision: "some-rev", } @@ -919,7 +919,7 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Spec.Chart = chartName obj.Spec.Version = chartVersion - obj.Status.Artifact = &sourcev1.Artifact{Path: chartName + "-" + chartVersion + ".tgz"} + obj.Status.Artifact = &meta.Artifact{Path: chartName + "-" + chartVersion + ".tgz"} }, want: sreconcile.ResultSuccess, assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { @@ -934,7 +934,7 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Spec.Chart = chartName obj.Spec.Version = chartVersion - obj.Status.Artifact = &sourcev1.Artifact{Path: chartName + "-" + chartVersion + ".tgz"} + obj.Status.Artifact = &meta.Artifact{Path: chartName + "-" + chartVersion + ".tgz"} obj.Status.ObservedValuesFiles = []string{"values.yaml", "override.yaml"} }, want: sreconcile.ResultSuccess, @@ -1017,7 +1017,7 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { obj.Spec.Version = chartVersion obj.Status.ObservedGeneration = 2 - obj.Status.Artifact = &sourcev1.Artifact{Path: chartName + "-" + chartVersion + ".tgz"} + obj.Status.Artifact = &meta.Artifact{Path: chartName + "-" + chartVersion + ".tgz"} }, want: sreconcile.ResultSuccess, assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { @@ -1135,7 +1135,7 @@ func TestHelmChartReconciler_buildFromHelmRepository(t *testing.T) { Timeout: &metav1.Duration{Duration: timeout}, }, Status: sourcev1.HelmRepositoryStatus{ - Artifact: &sourcev1.Artifact{ + Artifact: &meta.Artifact{ Path: "index.yaml", }, }, @@ -1191,7 +1191,7 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) { storage, err := storage.New(tmpDir, "example.com", retentionTTL, retentionRecords) g.Expect(err).ToNot(HaveOccurred()) - cachedArtifact := &sourcev1.Artifact{ + cachedArtifact := &meta.Artifact{ Revision: "0.1.0", Path: metadata.Name + "-" + metadata.Version + ".tgz", } @@ -1267,7 +1267,7 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) { beforeFunc: func(obj *sourcev1.HelmChart, repository *sourcev1.HelmRepository) { obj.Spec.Chart = metadata.Name obj.Spec.Version = metadata.Version - obj.Status.Artifact = &sourcev1.Artifact{Path: metadata.Name + "-" + metadata.Version + ".tgz"} + obj.Status.Artifact = &meta.Artifact{Path: metadata.Name + "-" + metadata.Version + ".tgz"} }, want: sreconcile.ResultSuccess, assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { @@ -1286,7 +1286,7 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) { obj.Spec.Version = metadata.Version obj.Status.ObservedGeneration = 2 - obj.Status.Artifact = &sourcev1.Artifact{Path: metadata.Name + "-" + metadata.Version + ".tgz"} + obj.Status.Artifact = &meta.Artifact{Path: metadata.Name + "-" + metadata.Version + ".tgz"} }, want: sreconcile.ResultSuccess, assertFunc: func(g *WithT, obj *sourcev1.HelmChart, build chart.Build) { @@ -1414,17 +1414,17 @@ func TestHelmChartReconciler_buildFromTarballArtifact(t *testing.T) { storage, err := storage.New(tmpDir, "example.com", retentionTTL, retentionRecords) g.Expect(err).ToNot(HaveOccurred()) - chartsArtifact := &sourcev1.Artifact{ + chartsArtifact := &meta.Artifact{ Revision: "mock-ref/abcdefg12345678", Path: "mock.tgz", } g.Expect(storage.Archive(chartsArtifact, "testdata/charts", nil)).To(Succeed()) - yamlArtifact := &sourcev1.Artifact{ + yamlArtifact := &meta.Artifact{ Revision: "9876abcd", Path: "values.yaml", } g.Expect(storage.CopyFromPath(yamlArtifact, "testdata/charts/helmchart/values.yaml")).To(Succeed()) - cachedArtifact := &sourcev1.Artifact{ + cachedArtifact := &meta.Artifact{ Revision: "0.1.0", Path: "cached.tgz", } @@ -1432,7 +1432,7 @@ func TestHelmChartReconciler_buildFromTarballArtifact(t *testing.T) { tests := []struct { name string - source sourcev1.Artifact + source meta.Artifact beforeFunc func(obj *sourcev1.HelmChart) want sreconcile.Result wantErr error @@ -1563,7 +1563,7 @@ func TestHelmChartReconciler_buildFromTarballArtifact(t *testing.T) { }, { name: "Empty source artifact", - source: sourcev1.Artifact{}, + source: meta.Artifact{}, want: sreconcile.ResultEmpty, wantErr: &serror.Generic{Err: errors.New("no such file or directory")}, assertFunc: func(g *WithT, build chart.Build) { @@ -1678,7 +1678,7 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) { Path: filepath.Join(testStorage.BasePath, "testdata/charts/helmchart-0.1.0.tgz"), }, beforeFunc: func(obj *sourcev1.HelmChart) { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: "testdata/charts/helmchart-0.1.0.tgz", } }, @@ -1700,7 +1700,7 @@ func TestHelmChartReconciler_reconcileArtifact(t *testing.T) { }, beforeFunc: func(obj *sourcev1.HelmChart) { obj.Status.ObservedChartName = "helmchart" - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Revision: "0.1.0", Path: "testdata/charts/helmchart-0.1.0.tgz", } @@ -2298,7 +2298,7 @@ func TestHelmChartReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, newObjBeforeFunc: func(obj *sourcev1.HelmChart) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} }, wantEvent: "Normal ChartPackageSucceeded packaged", }, @@ -2307,12 +2307,12 @@ func TestHelmChartReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.HelmChart) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.GitOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, newObjBeforeFunc: func(obj *sourcev1.HelmChart) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, wantEvent: "Normal ChartPackageSucceeded packaged", @@ -2322,12 +2322,12 @@ func TestHelmChartReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.HelmChart) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.GitOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, newObjBeforeFunc: func(obj *sourcev1.HelmChart) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "aaa", Digest: "bbb"} + obj.Status.Artifact = &meta.Artifact{Revision: "aaa", Digest: "bbb"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, wantEvent: "Normal ChartPackageSucceeded packaged", @@ -2337,11 +2337,11 @@ func TestHelmChartReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.HelmChart) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, newObjBeforeFunc: func(obj *sourcev1.HelmChart) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, }, @@ -2901,7 +2901,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t storage, err := storage.New(tmpDir, server.registryHost, retentionTTL, retentionRecords) g.Expect(err).ToNot(HaveOccurred()) - cachedArtifact := &sourcev1.Artifact{ + cachedArtifact := &meta.Artifact{ Revision: "0.1.0", Path: metadata.Name + "-" + metadata.Version + ".tgz", } @@ -3006,7 +3006,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t obj.Spec.Version = metadata.Version obj.Spec.Verify = nil conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, "VerifyFailed", "fail msg") - obj.Status.Artifact = &sourcev1.Artifact{Path: metadata.Name + "-" + metadata.Version + ".tgz"} + obj.Status.Artifact = &meta.Artifact{Path: metadata.Name + "-" + metadata.Version + ".tgz"} }, want: sreconcile.ResultSuccess, assertConditions: []metav1.Condition{ @@ -3225,7 +3225,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureCosign(t *tes storage, err := storage.New(tmpDir, server.registryHost, retentionTTL, retentionRecords) g.Expect(err).ToNot(HaveOccurred()) - cachedArtifact := &sourcev1.Artifact{ + cachedArtifact := &meta.Artifact{ Revision: "0.1.0", Path: metadata.Name + "-" + metadata.Version + ".tgz", } @@ -3318,7 +3318,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureCosign(t *tes obj.Spec.Version = metadata.Version obj.Spec.Verify = nil conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, "VerifyFailed", "fail msg") - obj.Status.Artifact = &sourcev1.Artifact{Path: metadata.Name + "-" + metadata.Version + ".tgz"} + obj.Status.Artifact = &meta.Artifact{Path: metadata.Name + "-" + metadata.Version + ".tgz"} }, want: sreconcile.ResultSuccess, assertConditions: []metav1.Condition{ diff --git a/internal/controller/helmrepository_controller.go b/internal/controller/helmrepository_controller.go index 8c442dbd9..9e052b34d 100644 --- a/internal/controller/helmrepository_controller.go +++ b/internal/controller/helmrepository_controller.go @@ -128,7 +128,7 @@ type HelmRepositoryReconcilerOptions struct { // v1.HelmRepository (sub)reconcile functions. The type implementations // are grouped and executed serially to perform the complete reconcile of the // object. -type helmRepositoryReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) +type helmRepositoryReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *meta.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) func (r *HelmRepositoryReconciler) SetupWithManager(mgr ctrl.Manager) error { return r.SetupWithManagerAndOptions(mgr, HelmRepositoryReconcilerOptions{}) @@ -258,7 +258,7 @@ func (r *HelmRepositoryReconciler) reconcile(ctx context.Context, sp *patch.Seri } var chartRepo repository.ChartRepository - var artifact sourcev1.Artifact + var artifact meta.Artifact // Run the sub-reconcilers and build the result of reconciliation. var res sreconcile.Result @@ -330,7 +330,7 @@ func (r *HelmRepositoryReconciler) notify(ctx context.Context, oldObj, newObj *s // The hostname of any URL in the Status of the object are updated, to ensure // they match the Storage server hostname of current runtime. func (r *HelmRepositoryReconciler) reconcileStorage(ctx context.Context, sp *patch.SerialPatcher, - obj *sourcev1.HelmRepository, _ *sourcev1.Artifact, _ *repository.ChartRepository) (sreconcile.Result, error) { + obj *sourcev1.HelmRepository, _ *meta.Artifact, _ *repository.ChartRepository) (sreconcile.Result, error) { // Garbage collect previous advertised artifact(s) from storage _ = r.garbageCollect(ctx, obj) @@ -393,7 +393,7 @@ func (r *HelmRepositoryReconciler) reconcileStorage(ctx context.Context, sp *pat // v1.FetchFailedCondition is removed, and the repository.ChartRepository // pointer is set to the newly fetched index. func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch.SerialPatcher, - obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, chartRepo *repository.ChartRepository) (sreconcile.Result, error) { + obj *sourcev1.HelmRepository, artifact *meta.Artifact, chartRepo *repository.ChartRepository) (sreconcile.Result, error) { // Ensure it's not an OCI URL. API validation ensures that only // http/https/oci scheme are allowed. if strings.HasPrefix(obj.Spec.URL, helmreg.OCIScheme) { @@ -530,7 +530,7 @@ func (r *HelmRepositoryReconciler) reconcileSource(ctx context.Context, sp *patc // early. // On a successful archive, the Artifact in the Status of the object is set, // and the symlink in the Storage is updated to its path. -func (r *HelmRepositoryReconciler) reconcileArtifact(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, chartRepo *repository.ChartRepository) (sreconcile.Result, error) { +func (r *HelmRepositoryReconciler) reconcileArtifact(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *meta.Artifact, chartRepo *repository.ChartRepository) (sreconcile.Result, error) { // Set the ArtifactInStorageCondition if there's no drift. defer func() { if obj.GetArtifact().HasRevision(artifact.Revision) { diff --git a/internal/controller/helmrepository_controller_test.go b/internal/controller/helmrepository_controller_test.go index 895fc3a9d..3791294e6 100644 --- a/internal/controller/helmrepository_controller_test.go +++ b/internal/controller/helmrepository_controller_test.go @@ -176,7 +176,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { beforeFunc func(obj *sourcev1.HelmRepository, storage *storage.Storage) error want sreconcile.Result wantErr bool - assertArtifact *sourcev1.Artifact + assertArtifact *meta.Artifact assertConditions []metav1.Condition assertPaths []string }{ @@ -186,7 +186,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { revisions := []string{"a", "b", "c", "d"} for n := range revisions { v := revisions[n] - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: fmt.Sprintf("/reconcile-storage/%s.txt", v), Revision: v, } @@ -204,7 +204,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { conditions.MarkTrue(obj, meta.ReadyCondition, "foo", "bar") return nil }, - assertArtifact: &sourcev1.Artifact{ + assertArtifact: &meta.Artifact{ Path: "/reconcile-storage/d.txt", Revision: "d", Digest: "sha256:18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e4", @@ -233,7 +233,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { { name: "notices missing artifact in storage", beforeFunc: func(obj *sourcev1.HelmRepository, storage *storage.Storage) error { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: "/reconcile-storage/invalid.txt", Revision: "d", } @@ -254,7 +254,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { beforeFunc: func(obj *sourcev1.HelmRepository, storage *storage.Storage) error { f := "empty-digest.txt" - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: fmt.Sprintf("/reconcile-storage/%s.txt", f), Revision: "fake", } @@ -285,7 +285,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { beforeFunc: func(obj *sourcev1.HelmRepository, storage *storage.Storage) error { f := "digest-mismatch.txt" - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: fmt.Sprintf("/reconcile-storage/%s.txt", f), Revision: "fake", } @@ -314,7 +314,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { { name: "updates hostname on diff from current", beforeFunc: func(obj *sourcev1.HelmRepository, storage *storage.Storage) error { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: "/reconcile-storage/hostname.txt", Revision: "f", Digest: "sha256:3b9c358f36f0a31b6ad3e14f309c7cf198ac9246e8316f9ce543d5b19ac02b80", @@ -333,7 +333,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { assertPaths: []string{ "/reconcile-storage/hostname.txt", }, - assertArtifact: &sourcev1.Artifact{ + assertArtifact: &meta.Artifact{ Path: "/reconcile-storage/hostname.txt", Revision: "f", Digest: "sha256:3b9c358f36f0a31b6ad3e14f309c7cf198ac9246e8316f9ce543d5b19ac02b80", @@ -375,7 +375,7 @@ func TestHelmRepositoryReconciler_reconcileStorage(t *testing.T) { }() var chartRepo repository.ChartRepository - var artifact sourcev1.Artifact + var artifact meta.Artifact sp := patch.NewSerialPatcher(obj, r.Client) got, err := r.reconcileStorage(context.TODO(), sp, obj, &artifact, &chartRepo) @@ -421,7 +421,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { secret *corev1.Secret beforeFunc func(t *WithT, obj *sourcev1.HelmRepository) revFunc func(t *WithT, server *helmtestserver.HelmServer, secret *corev1.Secret) digest.Digest - afterFunc func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) + afterFunc func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, chartRepo *repository.ChartRepository) want sreconcile.Result wantErr bool assertConditions []metav1.Condition @@ -495,7 +495,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new index revision"), *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new index revision"), }, - afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).ToNot(BeNil()) t.Expect(artifact.Revision).ToNot(BeEmpty()) @@ -547,7 +547,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new index revision"), *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new index revision"), }, - afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).ToNot(BeNil()) t.Expect(artifact.Revision).ToNot(BeEmpty()) @@ -601,7 +601,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new index revision"), *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new index revision"), }, - afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).ToNot(BeNil()) t.Expect(artifact.Revision).ToNot(BeEmpty()) @@ -633,7 +633,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new index revision"), *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new index revision"), }, - afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).ToNot(BeNil()) t.Expect(artifact.Revision).ToNot(BeEmpty()) @@ -686,7 +686,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new index revision"), *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new index revision"), }, - afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).ToNot(BeNil()) t.Expect(artifact.Revision).ToNot(BeEmpty()) @@ -741,7 +741,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new index revision"), *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new index revision"), }, - afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).ToNot(BeNil()) t.Expect(artifact.Revision).ToNot(BeEmpty()) @@ -775,7 +775,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "foo"), *conditions.UnknownCondition(meta.ReadyCondition, "foo", "bar"), }, - afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, chartRepo *repository.ChartRepository) { // No repo index due to fetch fail. t.Expect(chartRepo.Path).To(BeEmpty()) t.Expect(chartRepo.Index).To(BeNil()) @@ -797,7 +797,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "foo"), *conditions.UnknownCondition(meta.ReadyCondition, "foo", "bar"), }, - afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, chartRepo *repository.ChartRepository) { // No repo index due to fetch fail. t.Expect(chartRepo.Path).To(BeEmpty()) t.Expect(chartRepo.Index).To(BeNil()) @@ -819,7 +819,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "foo"), *conditions.UnknownCondition(meta.ReadyCondition, "foo", "bar"), }, - afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, chartRepo *repository.ChartRepository) { // No repo index due to fetch fail. t.Expect(chartRepo.Path).To(BeEmpty()) t.Expect(chartRepo.Index).To(BeNil()) @@ -840,7 +840,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "foo"), *conditions.UnknownCondition(meta.ReadyCondition, "foo", "bar"), }, - afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, chartRepo *repository.ChartRepository) { // No repo index due to fetch fail. t.Expect(chartRepo.Path).To(BeEmpty()) t.Expect(chartRepo.Index).To(BeNil()) @@ -870,7 +870,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "foo"), *conditions.UnknownCondition(meta.ReadyCondition, "foo", "bar"), }, - afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, chartRepo *repository.ChartRepository) { // No repo index due to fetch fail. t.Expect(chartRepo.Path).To(BeEmpty()) t.Expect(chartRepo.Index).To(BeNil()) @@ -907,7 +907,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "foo"), *conditions.UnknownCondition(meta.ReadyCondition, "foo", "bar"), }, - afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).To(BeNil()) @@ -919,7 +919,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { name: "Stored index with different revision", protocol: "http", beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository) { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Revision: "80bb3dd67c63095d985850459834ea727603727a370079de90d221191d375a86", } conditions.MarkReconciling(obj, meta.ProgressingReason, "foo") @@ -931,7 +931,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new index revision"), *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new index revision"), }, - afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, chartRepo *repository.ChartRepository) { + afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, chartRepo *repository.ChartRepository) { t.Expect(chartRepo.Path).ToNot(BeEmpty()) t.Expect(chartRepo.Index).ToNot(BeNil()) @@ -944,7 +944,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { name: "Existing artifact makes ArtifactOutdated=True", protocol: "http", beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository) { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: "some-path", Revision: "some-rev", } @@ -1040,7 +1040,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { // Special handling for tests that need to set revision after calculation if tt.name == "Stored index with same revision" && rev != "" { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Revision: rev.String(), } } @@ -1051,7 +1051,7 @@ func TestHelmRepositoryReconciler_reconcileSource(t *testing.T) { }() var chartRepo repository.ChartRepository - var artifact sourcev1.Artifact + var artifact meta.Artifact sp := patch.NewSerialPatcher(obj, r.Client) got, err := r.reconcileSource(context.TODO(), sp, obj, &artifact, &chartRepo) @@ -1076,7 +1076,7 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { tests := []struct { name string cache *cache.Cache - beforeFunc func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) + beforeFunc func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, index *repository.ChartRepository) afterFunc func(t *WithT, obj *sourcev1.HelmRepository, cache *cache.Cache) want sreconcile.Result wantErr bool @@ -1084,7 +1084,7 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { }{ { name: "Archiving artifact to storage makes ArtifactInStorage=True and artifact is stored as JSON", - beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, index *repository.ChartRepository) { obj.Spec.Interval = metav1.Duration{Duration: interval} }, want: sreconcile.ResultSuccess, @@ -1101,7 +1101,7 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { { name: "Archiving (loaded) artifact to storage adds to cache", cache: cache.New(10, time.Minute), - beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, index *repository.ChartRepository) { index.Index = &repo.IndexFile{ APIVersion: "v1", Generated: time.Now(), @@ -1120,7 +1120,7 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { }, { name: "Up-to-date artifact should not update status", - beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, index *repository.ChartRepository) { obj.Spec.Interval = metav1.Duration{Duration: interval} obj.Status.Artifact = artifact.DeepCopy() }, @@ -1134,7 +1134,7 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { }, { name: "Removes ArtifactOutdatedCondition after creating a new artifact", - beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, index *repository.ChartRepository) { obj.Spec.Interval = metav1.Duration{Duration: interval} conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "Foo", "") }, @@ -1145,7 +1145,7 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { }, { name: "Creates latest symlink to the created artifact", - beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact sourcev1.Artifact, index *repository.ChartRepository) { + beforeFunc: func(t *WithT, obj *sourcev1.HelmRepository, artifact meta.Artifact, index *repository.ChartRepository) { obj.Spec.Interval = metav1.Duration{Duration: interval} }, afterFunc: func(t *WithT, obj *sourcev1.HelmRepository, _ *cache.Cache) { @@ -1227,7 +1227,7 @@ func TestHelmRepositoryReconciler_reconcileArtifact(t *testing.T) { func TestHelmRepositoryReconciler_reconcileSubRecs(t *testing.T) { // Helper to build simple helmRepositoryReconcileFunc with result and error. buildReconcileFuncs := func(r sreconcile.Result, e error) helmRepositoryReconcileFunc { - return func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) { + return func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *meta.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) { return r, e } } @@ -1282,11 +1282,11 @@ func TestHelmRepositoryReconciler_reconcileSubRecs(t *testing.T) { { name: "multiple object status conditions mutations", reconcileFuncs: []helmRepositoryReconcileFunc{ - func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) { + func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *meta.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) { conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "NewRevision", "new index revision") return sreconcile.ResultSuccess, nil }, - func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *sourcev1.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) { + func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.HelmRepository, artifact *meta.Artifact, repo *repository.ChartRepository) (sreconcile.Result, error) { conditions.MarkTrue(obj, meta.ReconcilingCondition, meta.ProgressingReason, "creating artifact") return sreconcile.ResultSuccess, nil }, @@ -1481,7 +1481,7 @@ func TestHelmRepositoryReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, newObjBeforeFunc: func(obj *sourcev1.HelmRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy", Size: nil} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy", Size: nil} }, wantEvent: "Normal NewArtifact stored fetched index of unknown size", }, @@ -1490,7 +1490,7 @@ func TestHelmRepositoryReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, newObjBeforeFunc: func(obj *sourcev1.HelmRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} }, wantEvent: "Normal NewArtifact stored fetched index of size", }, @@ -1499,12 +1499,12 @@ func TestHelmRepositoryReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.HelmRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.GitOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, newObjBeforeFunc: func(obj *sourcev1.HelmRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, wantEvent: "Normal Succeeded stored fetched index of size", @@ -1514,12 +1514,12 @@ func TestHelmRepositoryReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.HelmRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.GitOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, newObjBeforeFunc: func(obj *sourcev1.HelmRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "aaa", Digest: "bbb", Size: &aSize} + obj.Status.Artifact = &meta.Artifact{Revision: "aaa", Digest: "bbb", Size: &aSize} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, wantEvent: "Normal NewArtifact stored fetched index of size", @@ -1529,11 +1529,11 @@ func TestHelmRepositoryReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.HelmRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, newObjBeforeFunc: func(obj *sourcev1.HelmRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy", Size: &aSize} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, }, diff --git a/internal/controller/ocirepository_controller.go b/internal/controller/ocirepository_controller.go index 3a86e61e3..e39230551 100644 --- a/internal/controller/ocirepository_controller.go +++ b/internal/controller/ocirepository_controller.go @@ -132,7 +132,7 @@ func (e invalidOCIURLError) Error() string { // ociRepositoryReconcileFunc is the function type for all the v1.OCIRepository // (sub)reconcile functions. The type implementations are grouped and // executed serially to perform the complete reconcile of the object. -type ociRepositoryReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error) +type ociRepositoryReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.OCIRepository, metadata *meta.Artifact, dir string) (sreconcile.Result, error) // OCIRepositoryReconciler reconciles a v1.OCIRepository object type OCIRepositoryReconciler struct { @@ -301,7 +301,7 @@ func (r *OCIRepositoryReconciler) reconcile(ctx context.Context, sp *patch.Seria var ( res sreconcile.Result resErr error - metadata = sourcev1.Artifact{} + metadata = meta.Artifact{} ) // Run the sub-reconcilers and build the result of reconciliation. @@ -330,7 +330,7 @@ func (r *OCIRepositoryReconciler) reconcile(ctx context.Context, sp *patch.Seria // reconcileSource fetches the upstream OCI artifact metadata and content. // If this fails, it records v1.FetchFailedCondition=True on the object and returns early. func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch.SerialPatcher, - obj *sourcev1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error) { + obj *sourcev1.OCIRepository, metadata *meta.Artifact, dir string) (sreconcile.Result, error) { var authenticator authn.Authenticator ctxTimeout, cancel := context.WithTimeout(ctx, obj.Spec.Timeout.Duration) @@ -455,7 +455,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e) return sreconcile.ResultEmpty, e } - metaArtifact := &sourcev1.Artifact{Revision: revision} + metaArtifact := &meta.Artifact{Revision: revision} metaArtifact.DeepCopyInto(metadata) // Mark observations about the revision on the object @@ -1024,7 +1024,7 @@ func (r *OCIRepositoryReconciler) getTLSConfig(ctx context.Context, obj *sourcev // The hostname of any URL in the Status of the object are updated, to ensure // they match the Storage server hostname of current runtime. func (r *OCIRepositoryReconciler) reconcileStorage(ctx context.Context, sp *patch.SerialPatcher, - obj *sourcev1.OCIRepository, _ *sourcev1.Artifact, _ string) (sreconcile.Result, error) { + obj *sourcev1.OCIRepository, _ *meta.Artifact, _ string) (sreconcile.Result, error) { // Garbage collect previous advertised artifact(s) from storage _ = r.garbageCollect(ctx, obj) @@ -1087,7 +1087,7 @@ func (r *OCIRepositoryReconciler) reconcileStorage(ctx context.Context, sp *patc // On a successful archive, the Artifact in the Status of the object is set, // and the symlink in the Storage is updated to its path. func (r *OCIRepositoryReconciler) reconcileArtifact(ctx context.Context, sp *patch.SerialPatcher, - obj *sourcev1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error) { + obj *sourcev1.OCIRepository, metadata *meta.Artifact, dir string) (sreconcile.Result, error) { // Create artifact artifact := r.Storage.NewArtifactFor(obj.Kind, obj, metadata.Revision, fmt.Sprintf("%s.tar.gz", r.digestFromRevision(metadata.Revision))) diff --git a/internal/controller/ocirepository_controller_test.go b/internal/controller/ocirepository_controller_test.go index f1370b788..e2cea947d 100644 --- a/internal/controller/ocirepository_controller_test.go +++ b/internal/controller/ocirepository_controller_test.go @@ -822,7 +822,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) { sp := patch.NewSerialPatcher(obj, r.Client) tmpDir := t.TempDir() - got, err := r.reconcileSource(ctx, sp, obj, &sourcev1.Artifact{}, tmpDir) + got, err := r.reconcileSource(ctx, sp, obj, &meta.Artifact{}, tmpDir) if tt.wantErr { g.Expect(err).ToNot(BeNil()) } else { @@ -1289,7 +1289,7 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) { sp := patch.NewSerialPatcher(obj, r.Client) - artifact := &sourcev1.Artifact{} + artifact := &meta.Artifact{} tmpDir := t.TempDir() got, err := r.reconcileSource(ctx, sp, obj, artifact, tmpDir) if tt.wantErr { @@ -1356,7 +1356,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi beforeFunc: func(obj *sourcev1.OCIRepository, tag, revision string) { conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, "VerifyFailed", "fail msg") obj.Spec.Verify = nil - obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} + obj.Status.Artifact = &meta.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} }, want: sreconcile.ResultSuccess, }, @@ -1365,7 +1365,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi reference: &sourcev1.OCIRepositoryRef{Tag: "6.1.4"}, shouldSign: true, beforeFunc: func(obj *sourcev1.OCIRepository, tag, revision string) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} + obj.Status.Artifact = &meta.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} // Set Verified with old observed generation and different reason/message. conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, "Verified", "verified") // Set new object generation. @@ -1382,7 +1382,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi shouldSign: true, beforeFunc: func(obj *sourcev1.OCIRepository, tag, revision string) { // Artifact present and custom verified condition reason/message. - obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} + obj.Status.Artifact = &meta.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, "Verified", "verified") }, want: sreconcile.ResultSuccess, @@ -1630,7 +1630,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi sp := patch.NewSerialPatcher(obj, r.Client) - artifact := &sourcev1.Artifact{} + artifact := &meta.Artifact{} got, err := r.reconcileSource(ctx, sp, obj, artifact, tmpDir) if tt.wantErr { tt.wantErrMsg = strings.ReplaceAll(tt.wantErrMsg, "", artifactRef.String()) @@ -1969,7 +1969,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes sp := patch.NewSerialPatcher(obj, r.Client) - artifact := &sourcev1.Artifact{} + artifact := &meta.Artifact{} got, err := r.reconcileSource(ctx, sp, obj, artifact, tmpDir) g.Expect(r.Delete(ctx, secret)).NotTo(HaveOccurred()) if tt.wantErr { @@ -2050,7 +2050,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing beforeFunc: func(obj *sourcev1.OCIRepository, tag, revision string) { conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, "VerifyFailed", "fail msg") obj.Spec.Verify = nil - obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} + obj.Status.Artifact = &meta.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} }, want: sreconcile.ResultSuccess, }, @@ -2059,7 +2059,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing reference: &sourcev1.OCIRepositoryRef{Tag: "6.1.4"}, shouldSign: true, beforeFunc: func(obj *sourcev1.OCIRepository, tag, revision string) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} + obj.Status.Artifact = &meta.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} // Set Verified with old observed generation and different reason/message. conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, "Verified", "verified") // Set new object generation. @@ -2076,7 +2076,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing shouldSign: true, beforeFunc: func(obj *sourcev1.OCIRepository, tag, revision string) { // Artifact present and custom verified condition reason/message. - obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} + obj.Status.Artifact = &meta.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, "Verified", "verified") }, want: sreconcile.ResultSuccess, @@ -2241,7 +2241,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing sp := patch.NewSerialPatcher(obj, r.Client) - artifact := &sourcev1.Artifact{} + artifact := &meta.Artifact{} got, err := r.reconcileSource(ctx, sp, obj, artifact, tmpDir) if tt.wantErr { tt.wantErrMsg = strings.ReplaceAll(tt.wantErrMsg, "", artifactRef.String()) @@ -2416,7 +2416,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature_keyless(t *testi sp := patch.NewSerialPatcher(obj, r.Client) - artifact := &sourcev1.Artifact{} + artifact := &meta.Artifact{} got, err := r.reconcileSource(ctx, sp, obj, artifact, t.TempDir()) if tt.wantErr { g.Expect(err).To(HaveOccurred()) @@ -2452,22 +2452,22 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { tests := []struct { name string beforeFunc func(obj *sourcev1.OCIRepository) - afterFunc func(g *WithT, artifact *sourcev1.Artifact) + afterFunc func(g *WithT, artifact *meta.Artifact) }{ { name: "full reconcile - no existing artifact", - afterFunc: func(g *WithT, artifact *sourcev1.Artifact) { + afterFunc: func(g *WithT, artifact *meta.Artifact) { g.Expect(artifact.Metadata).ToNot(BeEmpty()) }, }, { name: "noop - artifact revisions match", beforeFunc: func(obj *sourcev1.OCIRepository) { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Revision: testRevision, } }, - afterFunc: func(g *WithT, artifact *sourcev1.Artifact) { + afterFunc: func(g *WithT, artifact *meta.Artifact) { g.Expect(artifact.Metadata).To(BeEmpty()) }, }, @@ -2475,11 +2475,11 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { name: "full reconcile - same rev, unobserved ignore", beforeFunc: func(obj *sourcev1.OCIRepository) { obj.Status.ObservedIgnore = ptr.To("aaa") - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Revision: testRevision, } }, - afterFunc: func(g *WithT, artifact *sourcev1.Artifact) { + afterFunc: func(g *WithT, artifact *meta.Artifact) { g.Expect(artifact.Metadata).ToNot(BeEmpty()) }, }, @@ -2488,11 +2488,11 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { beforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.Ignore = ptr.To("aaa") obj.Status.ObservedIgnore = ptr.To("aaa") - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Revision: testRevision, } }, - afterFunc: func(g *WithT, artifact *sourcev1.Artifact) { + afterFunc: func(g *WithT, artifact *meta.Artifact) { g.Expect(artifact.Metadata).To(BeEmpty()) }, }, @@ -2503,11 +2503,11 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { MediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip", Operation: sourcev1.OCILayerCopy, } - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Revision: testRevision, } }, - afterFunc: func(g *WithT, artifact *sourcev1.Artifact) { + afterFunc: func(g *WithT, artifact *meta.Artifact) { g.Expect(artifact.Metadata).ToNot(BeEmpty()) }, }, @@ -2522,11 +2522,11 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { MediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip", Operation: sourcev1.OCILayerCopy, } - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Revision: testRevision, } }, - afterFunc: func(g *WithT, artifact *sourcev1.Artifact) { + afterFunc: func(g *WithT, artifact *meta.Artifact) { g.Expect(artifact.Metadata).To(BeEmpty()) }, }, @@ -2541,11 +2541,11 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { MediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip", Operation: sourcev1.OCILayerCopy, } - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Revision: testRevision, } }, - afterFunc: func(g *WithT, artifact *sourcev1.Artifact) { + afterFunc: func(g *WithT, artifact *meta.Artifact) { g.Expect(artifact.Metadata).ToNot(BeEmpty()) }, }, @@ -2591,7 +2591,7 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { sp := patch.NewSerialPatcher(obj, r.Client) - artifact := &sourcev1.Artifact{} + artifact := &meta.Artifact{} tmpDir := t.TempDir() got, err := r.reconcileSource(ctx, sp, obj, artifact, tmpDir) g.Expect(err).ToNot(HaveOccurred()) @@ -2608,11 +2608,11 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { tests := []struct { name string targetPath string - artifact *sourcev1.Artifact + artifact *meta.Artifact beforeFunc func(obj *sourcev1.OCIRepository) want sreconcile.Result wantErr bool - assertArtifact *sourcev1.Artifact + assertArtifact *meta.Artifact assertPaths []string assertConditions []metav1.Condition afterFunc func(g *WithT, obj *sourcev1.OCIRepository) @@ -2620,7 +2620,7 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { { name: "Archiving Artifact creates correct files and condition", targetPath: "testdata/oci/repository", - artifact: &sourcev1.Artifact{ + artifact: &meta.Artifact{ Revision: "revision", }, beforeFunc: func(obj *sourcev1.OCIRepository) { @@ -2640,7 +2640,7 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { { name: "Artifact with source ignore", targetPath: "testdata/oci/repository", - artifact: &sourcev1.Artifact{Revision: "revision"}, + artifact: &meta.Artifact{Revision: "revision"}, beforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.Ignore = ptr.To("foo.txt") }, @@ -2657,17 +2657,17 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { }, { name: "No status changes if artifact is already present", - artifact: &sourcev1.Artifact{ + artifact: &meta.Artifact{ Revision: "revision", }, targetPath: "testdata/oci/repository", want: sreconcile.ResultSuccess, beforeFunc: func(obj *sourcev1.OCIRepository) { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Revision: "revision", } }, - assertArtifact: &sourcev1.Artifact{ + assertArtifact: &meta.Artifact{ Revision: "revision", }, assertConditions: []metav1.Condition{ @@ -2677,11 +2677,11 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { { name: "Artifact already present, unobserved ignore, rebuild artifact", targetPath: "testdata/oci/repository", - artifact: &sourcev1.Artifact{ + artifact: &meta.Artifact{ Revision: "revision", }, beforeFunc: func(obj *sourcev1.OCIRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "revision"} + obj.Status.Artifact = &meta.Artifact{Revision: "revision"} obj.Spec.Ignore = ptr.To("aaa") }, want: sreconcile.ResultSuccess, @@ -2698,12 +2698,12 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { { name: "Artifact already present, unobserved layer selector, rebuild artifact", targetPath: "testdata/oci/repository", - artifact: &sourcev1.Artifact{ + artifact: &meta.Artifact{ Revision: "revision", }, beforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.LayerSelector = &sourcev1.OCILayerSelector{MediaType: "foo"} - obj.Status.Artifact = &sourcev1.Artifact{Revision: "revision"} + obj.Status.Artifact = &meta.Artifact{Revision: "revision"} }, want: sreconcile.ResultSuccess, assertPaths: []string{ @@ -2719,7 +2719,7 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { { name: "Artifact already present, observed layer selector changed, rebuild artifact", targetPath: "testdata/oci/repository", - artifact: &sourcev1.Artifact{ + artifact: &meta.Artifact{ Revision: "revision", Path: "foo.txt", }, @@ -2728,7 +2728,7 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { MediaType: "foo", Operation: sourcev1.OCILayerCopy, } - obj.Status.Artifact = &sourcev1.Artifact{Revision: "revision"} + obj.Status.Artifact = &meta.Artifact{Revision: "revision"} }, want: sreconcile.ResultSuccess, assertPaths: []string{ @@ -2745,18 +2745,18 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { { name: "Artifact already present, observed ignore and layer selector, up-to-date", targetPath: "testdata/oci/repository", - artifact: &sourcev1.Artifact{ + artifact: &meta.Artifact{ Revision: "revision", }, beforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.Ignore = ptr.To("aaa") obj.Spec.LayerSelector = &sourcev1.OCILayerSelector{MediaType: "foo"} - obj.Status.Artifact = &sourcev1.Artifact{Revision: "revision"} + obj.Status.Artifact = &meta.Artifact{Revision: "revision"} obj.Status.ObservedIgnore = ptr.To("aaa") obj.Status.ObservedLayerSelector = &sourcev1.OCILayerSelector{MediaType: "foo"} }, want: sreconcile.ResultSuccess, - assertArtifact: &sourcev1.Artifact{ + assertArtifact: &meta.Artifact{ Revision: "revision", }, assertConditions: []metav1.Condition{ @@ -2810,7 +2810,7 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { tt.beforeFunc(obj) } - artifact := &sourcev1.Artifact{} + artifact := &meta.Artifact{} if tt.artifact != nil { artifact = tt.artifact } @@ -3089,7 +3089,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { want sreconcile.Result wantErr bool assertConditions []metav1.Condition - assertArtifact *sourcev1.Artifact + assertArtifact *meta.Artifact assertPaths []string }{ { @@ -3099,7 +3099,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { for n := range revisions { v := revisions[n] - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: fmt.Sprintf("/oci-reconcile-storage/%s.txt", v), Revision: v, } @@ -3120,7 +3120,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { conditions.MarkTrue(obj, meta.ReadyCondition, "foo", "bar") return nil }, - assertArtifact: &sourcev1.Artifact{ + assertArtifact: &meta.Artifact{ Path: "/oci-reconcile-storage/d.txt", Revision: "d", Digest: "sha256:18ac3e7343f016890c510e93f935261169d9e3f565436429830faf0934f4f8e4", @@ -3149,7 +3149,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { { name: "notices missing artifact in storage", beforeFunc: func(obj *sourcev1.OCIRepository, storage *storage.Storage) error { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: "/oci-reconcile-storage/invalid.txt", Revision: "e", } @@ -3170,7 +3170,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { beforeFunc: func(obj *sourcev1.OCIRepository, storage *storage.Storage) error { f := "empty-digest.txt" - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: fmt.Sprintf("/oci-reconcile-storage/%s.txt", f), Revision: "fake", } @@ -3201,7 +3201,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { beforeFunc: func(obj *sourcev1.OCIRepository, storage *storage.Storage) error { f := "digest-mismatch.txt" - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: fmt.Sprintf("/oci-reconcile-storage/%s.txt", f), Revision: "fake", } @@ -3230,7 +3230,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { { name: "updates hostname on diff from current", beforeFunc: func(obj *sourcev1.OCIRepository, storage *storage.Storage) error { - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Path: "/oci-reconcile-storage/hostname.txt", Revision: "f", Digest: "sha256:3b9c358f36f0a31b6ad3e14f309c7cf198ac9246e8316f9ce543d5b19ac02b80", @@ -3249,7 +3249,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { assertPaths: []string{ "/oci-reconcile-storage/hostname.txt", }, - assertArtifact: &sourcev1.Artifact{ + assertArtifact: &meta.Artifact{ Path: "/oci-reconcile-storage/hostname.txt", Revision: "f", Digest: "sha256:3b9c358f36f0a31b6ad3e14f309c7cf198ac9246e8316f9ce543d5b19ac02b80", @@ -3295,7 +3295,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { sp := patch.NewSerialPatcher(obj, r.Client) - got, err := r.reconcileStorage(ctx, sp, obj, &sourcev1.Artifact{}, "") + got, err := r.reconcileStorage(ctx, sp, obj, &meta.Artifact{}, "") if tt.wantErr { g.Expect(err).To(HaveOccurred()) } else { @@ -3382,7 +3382,7 @@ func TestOCIRepositoryReconciler_notify(t *testing.T) { resErr: nil, newObjBeforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.URL = "oci://newurl.io" - obj.Status.Artifact = &sourcev1.Artifact{ + obj.Status.Artifact = &meta.Artifact{ Revision: "xxx", Digest: "yyy", Metadata: map[string]string{ @@ -3398,13 +3398,13 @@ func TestOCIRepositoryReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.OCIRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.ReadOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, newObjBeforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.URL = "oci://newurl.io" - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, wantEvent: "Normal Succeeded stored artifact with revision 'xxx' from 'oci://newurl.io'", @@ -3414,13 +3414,13 @@ func TestOCIRepositoryReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.OCIRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.ReadOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, newObjBeforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.URL = "oci://newurl.io" - obj.Status.Artifact = &sourcev1.Artifact{Revision: "aaa", Digest: "bbb"} + obj.Status.Artifact = &meta.Artifact{Revision: "aaa", Digest: "bbb"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, wantEvent: "Normal NewArtifact stored artifact with revision 'aaa' from 'oci://newurl.io'", @@ -3430,11 +3430,11 @@ func TestOCIRepositoryReconciler_notify(t *testing.T) { res: sreconcile.ResultSuccess, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.OCIRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, newObjBeforeFunc: func(obj *sourcev1.OCIRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, }, @@ -3443,7 +3443,7 @@ func TestOCIRepositoryReconciler_notify(t *testing.T) { res: sreconcile.ResultRequeue, resErr: nil, oldObjBeforeFunc: func(obj *sourcev1.OCIRepository) { - obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} + obj.Status.Artifact = &meta.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.URLInvalidReason, "ready") }, }, diff --git a/internal/object/object.go b/internal/object/object.go index 105b40330..37f8ef9fe 100644 --- a/internal/object/object.go +++ b/internal/object/object.go @@ -24,7 +24,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" - sourcev1 "github.com/fluxcd/source-controller/api/v1" + "github.com/fluxcd/pkg/apis/meta" ) var ( @@ -148,7 +148,7 @@ func SetSuspend(obj runtime.Object, val bool) error { } // GetArtifact returns the status.artifact of a given runtime object. -func GetArtifact(obj runtime.Object) (*sourcev1.Artifact, error) { +func GetArtifact(obj runtime.Object) (*meta.Artifact, error) { u, err := toUnstructured(obj) if err != nil { return nil, err @@ -165,7 +165,7 @@ func GetArtifact(obj runtime.Object) (*sourcev1.Artifact, error) { if err != nil { return nil, err } - outArtifact := &sourcev1.Artifact{} + outArtifact := &meta.Artifact{} if err := json.Unmarshal(enc, outArtifact); err != nil { return nil, err } diff --git a/internal/object/object_test.go b/internal/object/object_test.go index 91932d11d..35cab3303 100644 --- a/internal/object/object_test.go +++ b/internal/object/object_test.go @@ -24,6 +24,8 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/fluxcd/pkg/apis/meta" + sourcev1 "github.com/fluxcd/source-controller/api/v1" ) @@ -127,7 +129,7 @@ func TestGetArtifact(t *testing.T) { g.Expect(artifact).To(BeNil()) // Get set artifact value. - obj.Status.Artifact = &sourcev1.Artifact{Path: "aaa", Revision: "zzz"} + obj.Status.Artifact = &meta.Artifact{Path: "aaa", Revision: "zzz"} artifact, err = GetArtifact(obj) g.Expect(err).ToNot(HaveOccurred()) g.Expect(artifact).ToNot(BeNil()) diff --git a/internal/predicates/helmrepository_type_predicate_test.go b/internal/predicates/helmrepository_type_predicate_test.go index 643e823e7..e98728413 100644 --- a/internal/predicates/helmrepository_type_predicate_test.go +++ b/internal/predicates/helmrepository_type_predicate_test.go @@ -160,7 +160,7 @@ func TestHelmRepositoryOCIMigrationPredicate_Update(t *testing.T) { Type: sourcev1.HelmRepositoryTypeDefault, } oldObj.Status = sourcev1.HelmRepositoryStatus{ - Artifact: &sourcev1.Artifact{}, + Artifact: &meta.Artifact{}, URL: "http://some-address", ObservedGeneration: 3, } diff --git a/internal/storage/storage.go b/internal/storage/storage.go index c5c60612a..46d31a2bd 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -25,12 +25,14 @@ import ( "io/fs" "net/url" "os" + "path" "path/filepath" "sort" "strings" "time" securejoin "github.com/cyphar/filepath-securejoin" + "github.com/fluxcd/pkg/apis/meta" "github.com/go-git/go-git/v5/plumbing/format/gitignore" "github.com/opencontainers/go-digest" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -41,7 +43,6 @@ import ( "github.com/fluxcd/pkg/sourceignore" pkgtar "github.com/fluxcd/pkg/tar" - v1 "github.com/fluxcd/source-controller/api/v1" intdigest "github.com/fluxcd/source-controller/internal/digest" ) @@ -86,10 +87,10 @@ func New(basePath string, hostname string, artifactRetentionTTL time.Duration, a }, nil } -// NewArtifactFor returns a new v1.Artifact. -func (s Storage) NewArtifactFor(kind string, metadata metav1.Object, revision, fileName string) v1.Artifact { - path := v1.ArtifactPath(kind, metadata.GetNamespace(), metadata.GetName(), fileName) - artifact := v1.Artifact{ +// NewArtifactFor returns a new meta.Artifact. +func (s Storage) NewArtifactFor(kind string, metadata metav1.Object, revision, fileName string) meta.Artifact { + path := ArtifactPath(kind, metadata.GetNamespace(), metadata.GetName(), fileName) + artifact := meta.Artifact{ Path: path, Revision: revision, } @@ -97,8 +98,8 @@ func (s Storage) NewArtifactFor(kind string, metadata metav1.Object, revision, f return artifact } -// SetArtifactURL sets the URL on the given v1.Artifact. -func (s Storage) SetArtifactURL(artifact *v1.Artifact) { +// SetArtifactURL sets the URL on the given meta.Artifact. +func (s Storage) SetArtifactURL(artifact *meta.Artifact) { if artifact.Path == "" { return } @@ -119,19 +120,19 @@ func (s Storage) SetHostname(URL string) string { return u.String() } -// MkdirAll calls os.MkdirAll for the given v1.Artifact base dir. -func (s Storage) MkdirAll(artifact v1.Artifact) error { +// MkdirAll calls os.MkdirAll for the given meta.Artifact base dir. +func (s Storage) MkdirAll(artifact meta.Artifact) error { dir := filepath.Dir(s.LocalPath(artifact)) return os.MkdirAll(dir, 0o700) } -// Remove calls os.Remove for the given v1.Artifact path. -func (s Storage) Remove(artifact v1.Artifact) error { +// Remove calls os.Remove for the given meta.Artifact path. +func (s Storage) Remove(artifact meta.Artifact) error { return os.Remove(s.LocalPath(artifact)) } -// RemoveAll calls os.RemoveAll for the given v1.Artifact base dir. -func (s Storage) RemoveAll(artifact v1.Artifact) (string, error) { +// RemoveAll calls os.RemoveAll for the given meta.Artifact base dir. +func (s Storage) RemoveAll(artifact meta.Artifact) (string, error) { var deletedDir string dir := filepath.Dir(s.LocalPath(artifact)) // Check if the dir exists. @@ -142,8 +143,8 @@ func (s Storage) RemoveAll(artifact v1.Artifact) (string, error) { return deletedDir, os.RemoveAll(dir) } -// RemoveAllButCurrent removes all files for the given v1.Artifact base dir, excluding the current one. -func (s Storage) RemoveAllButCurrent(artifact v1.Artifact) ([]string, error) { +// RemoveAllButCurrent removes all files for the given meta.Artifact base dir, excluding the current one. +func (s Storage) RemoveAllButCurrent(artifact meta.Artifact) ([]string, error) { deletedFiles := []string{} localPath := s.LocalPath(artifact) dir := filepath.Dir(localPath) @@ -176,7 +177,7 @@ func (s Storage) RemoveAllButCurrent(artifact v1.Artifact) ([]string, error) { // 1. collect all artifact files with an expired ttl // 2. if we satisfy maxItemsToBeRetained, then return // 3. else, collect all artifact files till the latest n files remain, where n=maxItemsToBeRetained -func (s Storage) getGarbageFiles(artifact v1.Artifact, totalCountLimit, maxItemsToBeRetained int, ttl time.Duration) (garbageFiles []string, _ error) { +func (s Storage) getGarbageFiles(artifact meta.Artifact, totalCountLimit, maxItemsToBeRetained int, ttl time.Duration) (garbageFiles []string, _ error) { localPath := s.LocalPath(artifact) dir := filepath.Dir(localPath) artifactFilesWithCreatedTs := make(map[time.Time]string) @@ -263,7 +264,7 @@ func (s Storage) getGarbageFiles(artifact v1.Artifact, totalCountLimit, maxItems // GarbageCollect removes all garbage files in the artifact dir according to the provided // retention options. -func (s Storage) GarbageCollect(ctx context.Context, artifact v1.Artifact, timeout time.Duration) ([]string, error) { +func (s Storage) GarbageCollect(ctx context.Context, artifact meta.Artifact, timeout time.Duration) ([]string, error) { delFilesChan := make(chan []string) errChan := make(chan error) // Abort if it takes more than the provided timeout duration. @@ -324,8 +325,8 @@ func stringInSlice(a string, list []string) bool { return false } -// ArtifactExist returns a boolean indicating whether the v1.Artifact exists in storage and is a regular file. -func (s Storage) ArtifactExist(artifact v1.Artifact) bool { +// ArtifactExist returns a boolean indicating whether the meta.Artifact exists in storage and is a regular file. +func (s Storage) ArtifactExist(artifact meta.Artifact) bool { fi, err := os.Lstat(s.LocalPath(artifact)) if err != nil { return false @@ -333,10 +334,10 @@ func (s Storage) ArtifactExist(artifact v1.Artifact) bool { return fi.Mode().IsRegular() } -// VerifyArtifact verifies if the Digest of the v1.Artifact matches the digest +// VerifyArtifact verifies if the Digest of the meta.Artifact matches the digest // of the file in Storage. It returns an error if the digests don't match, or // if it can't be verified. -func (s Storage) VerifyArtifact(artifact v1.Artifact) error { +func (s Storage) VerifyArtifact(artifact meta.Artifact) error { if artifact.Digest == "" { return fmt.Errorf("artifact has no digest") } @@ -380,11 +381,11 @@ func SourceIgnoreFilter(ps []gitignore.Pattern, domain []string) ArchiveFileFilt } } -// Archive atomically archives the given directory as a tarball to the given v1.Artifact path, excluding +// Archive atomically archives the given directory as a tarball to the given meta.Artifact path, excluding // directories and any ArchiveFileFilter matches. While archiving, any environment specific data (for example, // the user and group name) is stripped from file headers. // If successful, it sets the digest and last update time on the artifact. -func (s Storage) Archive(artifact *v1.Artifact, dir string, filter ArchiveFileFilter) (err error) { +func (s Storage) Archive(artifact *meta.Artifact, dir string, filter ArchiveFileFilter) (err error) { if f, err := os.Stat(dir); os.IsNotExist(err) || !f.IsDir() { return fmt.Errorf("invalid dir path: %s", dir) } @@ -491,9 +492,9 @@ func (s Storage) Archive(artifact *v1.Artifact, dir string, filter ArchiveFileFi return nil } -// AtomicWriteFile atomically writes the io.Reader contents to the v1.Artifact path. +// AtomicWriteFile atomically writes the io.Reader contents to the meta.Artifact path. // If successful, it sets the digest and last update time on the artifact. -func (s Storage) AtomicWriteFile(artifact *v1.Artifact, reader io.Reader, mode os.FileMode) (err error) { +func (s Storage) AtomicWriteFile(artifact *meta.Artifact, reader io.Reader, mode os.FileMode) (err error) { localPath := s.LocalPath(*artifact) tf, err := os.CreateTemp(filepath.Split(localPath)) if err != nil { @@ -533,9 +534,9 @@ func (s Storage) AtomicWriteFile(artifact *v1.Artifact, reader io.Reader, mode o return nil } -// Copy atomically copies the io.Reader contents to the v1.Artifact path. +// Copy atomically copies the io.Reader contents to the meta.Artifact path. // If successful, it sets the digest and last update time on the artifact. -func (s Storage) Copy(artifact *v1.Artifact, reader io.Reader) (err error) { +func (s Storage) Copy(artifact *meta.Artifact, reader io.Reader) (err error) { localPath := s.LocalPath(*artifact) tf, err := os.CreateTemp(filepath.Split(localPath)) if err != nil { @@ -571,9 +572,9 @@ func (s Storage) Copy(artifact *v1.Artifact, reader io.Reader) (err error) { return nil } -// CopyFromPath atomically copies the contents of the given path to the path of the v1.Artifact. +// CopyFromPath atomically copies the contents of the given path to the path of the meta.Artifact. // If successful, the digest and last update time on the artifact is set. -func (s Storage) CopyFromPath(artifact *v1.Artifact, path string) (err error) { +func (s Storage) CopyFromPath(artifact *meta.Artifact, path string) (err error) { f, err := os.Open(path) if err != nil { return err @@ -588,7 +589,7 @@ func (s Storage) CopyFromPath(artifact *v1.Artifact, path string) (err error) { } // CopyToPath copies the contents in the (sub)path of the given artifact to the given path. -func (s Storage) CopyToPath(artifact *v1.Artifact, subPath, toPath string) error { +func (s Storage) CopyToPath(artifact *meta.Artifact, subPath, toPath string) error { // create a tmp directory to store artifact tmp, err := os.MkdirTemp("", "flux-include-") if err != nil { @@ -626,8 +627,8 @@ func (s Storage) CopyToPath(artifact *v1.Artifact, subPath, toPath string) error return nil } -// Symlink creates or updates a symbolic link for the given v1.Artifact and returns the URL for the symlink. -func (s Storage) Symlink(artifact v1.Artifact, linkName string) (string, error) { +// Symlink creates or updates a symbolic link for the given meta.Artifact and returns the URL for the symlink. +func (s Storage) Symlink(artifact meta.Artifact, linkName string) (string, error) { localPath := s.LocalPath(artifact) dir := filepath.Dir(localPath) link := filepath.Join(dir, linkName) @@ -648,15 +649,15 @@ func (s Storage) Symlink(artifact v1.Artifact, linkName string) (string, error) return fmt.Sprintf("http://%s/%s", s.Hostname, filepath.Join(filepath.Dir(artifact.Path), linkName)), nil } -// Lock creates a file lock for the given v1.Artifact. -func (s Storage) Lock(artifact v1.Artifact) (unlock func(), err error) { +// Lock creates a file lock for the given meta.Artifact. +func (s Storage) Lock(artifact meta.Artifact) (unlock func(), err error) { lockFile := s.LocalPath(artifact) + ".lock" mutex := lockedfile.MutexAt(lockFile) return mutex.Lock() } // LocalPath returns the secure local path of the given artifact (that is: relative to the Storage.BasePath). -func (s Storage) LocalPath(artifact v1.Artifact) string { +func (s Storage) LocalPath(artifact meta.Artifact) string { if artifact.Path == "" { return "" } @@ -717,3 +718,16 @@ func setDefaultMode(h *tar.Header) { return } } + +// ArtifactDir returns the artifact dir path in the form of +// '//'. +func ArtifactDir(kind, namespace, name string) string { + kind = strings.ToLower(kind) + return path.Join(kind, namespace, name) +} + +// ArtifactPath returns the artifact path in the form of +// '//name>/'. +func ArtifactPath(kind, namespace, name, filename string) string { + return path.Join(ArtifactDir(kind, namespace, name), filename) +} diff --git a/internal/storage/storage_test.go b/internal/storage/storage_test.go index a4740084b..6890e9388 100644 --- a/internal/storage/storage_test.go +++ b/internal/storage/storage_test.go @@ -34,7 +34,7 @@ import ( "github.com/go-git/go-git/v5/plumbing/format/gitignore" . "github.com/onsi/gomega" - sourcev1 "github.com/fluxcd/source-controller/api/v1" + "github.com/fluxcd/pkg/apis/meta" ) func TestStorageConstructor(t *testing.T) { @@ -141,7 +141,7 @@ func TestStorage_Archive(t *testing.T) { return } - matchFiles := func(t *testing.T, storage *Storage, artifact sourcev1.Artifact, files map[string]dummyFile, dirs []string) { + matchFiles := func(t *testing.T, storage *Storage, artifact meta.Artifact, files map[string]dummyFile, dirs []string) { t.Helper() for name, df := range files { mustExist := !(name[0:1] == "!") @@ -289,7 +289,7 @@ func TestStorage_Archive(t *testing.T) { return } defer os.RemoveAll(dir) - artifact := sourcev1.Artifact{ + artifact := meta.Artifact{ Path: filepath.Join(randStringRunes(10), randStringRunes(10), randStringRunes(10)+".tar.gz"), } if err := storage.MkdirAll(artifact); err != nil { @@ -312,7 +312,7 @@ func TestStorage_Remove(t *testing.T) { s, err := New(dir, "", 0, 0) g.Expect(err).ToNot(HaveOccurred()) - artifact := sourcev1.Artifact{ + artifact := meta.Artifact{ Path: filepath.Join(dir, "test.txt"), } g.Expect(s.MkdirAll(artifact)).To(Succeed()) @@ -331,7 +331,7 @@ func TestStorage_Remove(t *testing.T) { s, err := New(dir, "", 0, 0) g.Expect(err).ToNot(HaveOccurred()) - artifact := sourcev1.Artifact{ + artifact := meta.Artifact{ Path: filepath.Join(dir, "test.txt"), } @@ -350,7 +350,7 @@ func TestStorageRemoveAllButCurrent(t *testing.T) { t.Fatalf("Valid path did not successfully return: %v", err) } - if _, err := s.RemoveAllButCurrent(sourcev1.Artifact{Path: filepath.Join(dir, "really", "nonexistent")}); err == nil { + if _, err := s.RemoveAllButCurrent(meta.Artifact{Path: filepath.Join(dir, "really", "nonexistent")}); err == nil { t.Fatal("Did not error while pruning non-existent path") } }) @@ -362,7 +362,7 @@ func TestStorageRemoveAllButCurrent(t *testing.T) { s, err := New(dir, "hostname", time.Minute, 2) g.Expect(err).ToNot(HaveOccurred(), "failed to create new storage") - artifact := sourcev1.Artifact{ + artifact := meta.Artifact{ Path: filepath.Join("foo", "bar", "artifact1.tar.gz"), } @@ -423,7 +423,7 @@ func TestStorageRemoveAll(t *testing.T) { s, err := New(dir, "hostname", time.Minute, 2) g.Expect(err).ToNot(HaveOccurred(), "failed to create new storage") - artifact := sourcev1.Artifact{ + artifact := meta.Artifact{ Path: tt.artifactPath, } @@ -469,7 +469,7 @@ func TestStorageCopyFromPath(t *testing.T) { return } - matchFile := func(t *testing.T, storage *Storage, artifact sourcev1.Artifact, file *File, expectMismatch bool) { + matchFile := func(t *testing.T, storage *Storage, artifact meta.Artifact, file *File, expectMismatch bool) { c, err := os.ReadFile(storage.LocalPath(artifact)) if err != nil { t.Fatalf("failed reading file: %v", err) @@ -516,7 +516,7 @@ func TestStorageCopyFromPath(t *testing.T) { t.Error(err) return } - artifact := sourcev1.Artifact{ + artifact := meta.Artifact{ Path: filepath.Join(randStringRunes(10), randStringRunes(10), randStringRunes(10)), } if err := storage.MkdirAll(artifact); err != nil { @@ -669,7 +669,7 @@ func TestStorage_getGarbageFiles(t *testing.T) { s, err := New(dir, "hostname", tt.ttl, tt.maxItemsToBeRetained) g.Expect(err).ToNot(HaveOccurred(), "failed to create new storage") - artifact := sourcev1.Artifact{ + artifact := meta.Artifact{ Path: tt.artifactPaths[len(tt.artifactPaths)-1], } g.Expect(os.MkdirAll(filepath.Join(dir, artifactFolder), 0o750)).ToNot(HaveOccurred()) @@ -752,7 +752,7 @@ func TestStorage_GarbageCollect(t *testing.T) { s, err := New(dir, "hostname", time.Second*2, 2) g.Expect(err).ToNot(HaveOccurred(), "failed to create new storage") - artifact := sourcev1.Artifact{ + artifact := meta.Artifact{ Path: tt.artifactPaths[len(tt.artifactPaths)-1], } g.Expect(os.MkdirAll(filepath.Join(dir, artifactFolder), 0o750)).ToNot(HaveOccurred()) @@ -807,7 +807,7 @@ func TestStorage_VerifyArtifact(t *testing.T) { t.Run("artifact without digest", func(t *testing.T) { g := NewWithT(t) - err := s.VerifyArtifact(sourcev1.Artifact{}) + err := s.VerifyArtifact(meta.Artifact{}) g.Expect(err).To(HaveOccurred()) g.Expect(err).To(MatchError("artifact has no digest")) }) @@ -815,7 +815,7 @@ func TestStorage_VerifyArtifact(t *testing.T) { t.Run("artifact with invalid digest", func(t *testing.T) { g := NewWithT(t) - err := s.VerifyArtifact(sourcev1.Artifact{Digest: "invalid"}) + err := s.VerifyArtifact(meta.Artifact{Digest: "invalid"}) g.Expect(err).To(HaveOccurred()) g.Expect(err).To(MatchError("failed to parse artifact digest 'invalid': invalid checksum digest format")) }) @@ -823,7 +823,7 @@ func TestStorage_VerifyArtifact(t *testing.T) { t.Run("artifact with invalid path", func(t *testing.T) { g := NewWithT(t) - err := s.VerifyArtifact(sourcev1.Artifact{ + err := s.VerifyArtifact(meta.Artifact{ Digest: "sha256:9ba7a35ce8acd3557fe30680ef193ca7a36bb5dc62788f30de7122a0a5beab69", Path: "invalid", }) @@ -834,7 +834,7 @@ func TestStorage_VerifyArtifact(t *testing.T) { t.Run("artifact with digest mismatch", func(t *testing.T) { g := NewWithT(t) - err := s.VerifyArtifact(sourcev1.Artifact{ + err := s.VerifyArtifact(meta.Artifact{ Digest: "sha256:9ba7a35ce8acd3557fe30680ef193ca7a36bb5dc62788f30de7122a0a5beab69", Path: "artifact", }) @@ -845,7 +845,7 @@ func TestStorage_VerifyArtifact(t *testing.T) { t.Run("artifact with digest match", func(t *testing.T) { g := NewWithT(t) - err := s.VerifyArtifact(sourcev1.Artifact{ + err := s.VerifyArtifact(meta.Artifact{ Digest: "sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", Path: "artifact", }) From 4900324ab0bc7422ab585925f8578d6670239920 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Wed, 3 Sep 2025 21:45:22 +0300 Subject: [PATCH 2/4] Add ExternalArtifact types to API Signed-off-by: Stefan Prodan --- PROJECT | 3 + api/v1/externalartifact_types.go | 70 ++++++++++++++++++++ api/v1/zz_generated.deepcopy.go | 106 +++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 api/v1/externalartifact_types.go diff --git a/PROJECT b/PROJECT index 8f7b42aef..9d89d81be 100644 --- a/PROJECT +++ b/PROJECT @@ -43,4 +43,7 @@ resources: - group: source kind: OCIRepository version: v1 +- group: source + kind: ExternalArtifact + version: v1 version: "2" diff --git a/api/v1/externalartifact_types.go b/api/v1/externalartifact_types.go new file mode 100644 index 000000000..4ae45308f --- /dev/null +++ b/api/v1/externalartifact_types.go @@ -0,0 +1,70 @@ +/* +Copyright 2025 The Flux 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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/fluxcd/pkg/apis/meta" +) + +// ExternalArtifactSpec defines the desired state of ExternalArtifact +type ExternalArtifactSpec struct { + // SourceRef points to the Kubernetes custom resource for + // which the artifact is generated. + // +optional + SourceRef *meta.NamespacedObjectKindReference `json:"sourceRef,omitempty"` +} + +// ExternalArtifactStatus defines the observed state of ExternalArtifact +type ExternalArtifactStatus struct { + // Artifact represents the output of an ExternalArtifact reconciliation. + // +optional + Artifact *meta.Artifact `json:"artifact,omitempty"` + + // Conditions holds the conditions for the ExternalArtifact. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="" +// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description="" +// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description="" +// +kubebuilder:printcolumn:name="Source",type="string",JSONPath=".spec.sourceRef.name",description="" + +// ExternalArtifact is the Schema for the external artifacts API +type ExternalArtifact struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ExternalArtifactSpec `json:"spec,omitempty"` + Status ExternalArtifactStatus `json:"status,omitempty"` +} + +// ExternalArtifactList contains a list of ExternalArtifact +// +kubebuilder:object:root=true +type ExternalArtifactList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ExternalArtifact `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ExternalArtifact{}, &ExternalArtifactList{}) +} diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 33ee940ad..14f1ba3c2 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -190,6 +190,112 @@ func (in *BucketStatus) DeepCopy() *BucketStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExternalArtifact) DeepCopyInto(out *ExternalArtifact) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalArtifact. +func (in *ExternalArtifact) DeepCopy() *ExternalArtifact { + if in == nil { + return nil + } + out := new(ExternalArtifact) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ExternalArtifact) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExternalArtifactList) DeepCopyInto(out *ExternalArtifactList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ExternalArtifact, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalArtifactList. +func (in *ExternalArtifactList) DeepCopy() *ExternalArtifactList { + if in == nil { + return nil + } + out := new(ExternalArtifactList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ExternalArtifactList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExternalArtifactSpec) DeepCopyInto(out *ExternalArtifactSpec) { + *out = *in + if in.SourceRef != nil { + in, out := &in.SourceRef, &out.SourceRef + *out = new(meta.NamespacedObjectKindReference) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalArtifactSpec. +func (in *ExternalArtifactSpec) DeepCopy() *ExternalArtifactSpec { + if in == nil { + return nil + } + out := new(ExternalArtifactSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExternalArtifactStatus) DeepCopyInto(out *ExternalArtifactStatus) { + *out = *in + if in.Artifact != nil { + in, out := &in.Artifact, &out.Artifact + *out = new(meta.Artifact) + (*in).DeepCopyInto(*out) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalArtifactStatus. +func (in *ExternalArtifactStatus) DeepCopy() *ExternalArtifactStatus { + if in == nil { + return nil + } + out := new(ExternalArtifactStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GitRepository) DeepCopyInto(out *GitRepository) { *out = *in From 425b7a33003378599bf5112776e0502eeaec18e4 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Wed, 3 Sep 2025 21:45:46 +0300 Subject: [PATCH 3/4] Generate ExternalArtifact CRD Signed-off-by: Stefan Prodan --- ...e.toolkit.fluxcd.io_externalartifacts.yaml | 191 ++++++++++++++++++ config/crd/kustomization.yaml | 1 + config/rbac/externalartifact_editor_role.yaml | 24 +++ config/rbac/externalartifact_viewer_role.yaml | 20 ++ docs/api/v1/source.md | 159 +++++++++++++++ 5 files changed, 395 insertions(+) create mode 100644 config/crd/bases/source.toolkit.fluxcd.io_externalartifacts.yaml create mode 100644 config/rbac/externalartifact_editor_role.yaml create mode 100644 config/rbac/externalartifact_viewer_role.yaml diff --git a/config/crd/bases/source.toolkit.fluxcd.io_externalartifacts.yaml b/config/crd/bases/source.toolkit.fluxcd.io_externalartifacts.yaml new file mode 100644 index 000000000..23cdf63c3 --- /dev/null +++ b/config/crd/bases/source.toolkit.fluxcd.io_externalartifacts.yaml @@ -0,0 +1,191 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.19.0 + name: externalartifacts.source.toolkit.fluxcd.io +spec: + group: source.toolkit.fluxcd.io + names: + kind: ExternalArtifact + listKind: ExternalArtifactList + plural: externalartifacts + singular: externalartifact + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .spec.sourceRef.name + name: Source + type: string + name: v1 + schema: + openAPIV3Schema: + description: ExternalArtifact is the Schema for the external artifacts API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ExternalArtifactSpec defines the desired state of ExternalArtifact + properties: + sourceRef: + description: |- + SourceRef points to the Kubernetes custom resource for + which the artifact is generated. + properties: + apiVersion: + description: API version of the referent, if not specified the + Kubernetes preferred version will be used. + type: string + kind: + description: Kind of the referent. + type: string + name: + description: Name of the referent. + type: string + namespace: + description: Namespace of the referent, when not specified it + acts as LocalObjectReference. + type: string + required: + - kind + - name + type: object + type: object + status: + description: ExternalArtifactStatus defines the observed state of ExternalArtifact + properties: + artifact: + description: Artifact represents the output of an ExternalArtifact + reconciliation. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - digest + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the ExternalArtifact. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index c00716353..2a09dbfd5 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -6,4 +6,5 @@ resources: - bases/source.toolkit.fluxcd.io_helmcharts.yaml - bases/source.toolkit.fluxcd.io_buckets.yaml - bases/source.toolkit.fluxcd.io_ocirepositories.yaml +- bases/source.toolkit.fluxcd.io_externalartifacts.yaml # +kubebuilder:scaffold:crdkustomizeresource diff --git a/config/rbac/externalartifact_editor_role.yaml b/config/rbac/externalartifact_editor_role.yaml new file mode 100644 index 000000000..ded6c1d93 --- /dev/null +++ b/config/rbac/externalartifact_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit externalartifacts. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: externalartifact-editor-role +rules: +- apiGroups: + - source.toolkit.fluxcd.io + resources: + - externalartifacts + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - source.toolkit.fluxcd.io + resources: + - externalartifacts/status + verbs: + - get diff --git a/config/rbac/externalartifact_viewer_role.yaml b/config/rbac/externalartifact_viewer_role.yaml new file mode 100644 index 000000000..d0c1d507f --- /dev/null +++ b/config/rbac/externalartifact_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view externalartifacts. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: externalartifacts-viewer-role +rules: +- apiGroups: + - source.toolkit.fluxcd.io + resources: + - externalartifacts + verbs: + - get + - list + - watch +- apiGroups: + - source.toolkit.fluxcd.io + resources: + - externalartifacts/status + verbs: + - get diff --git a/docs/api/v1/source.md b/docs/api/v1/source.md index 3d8232a5d..935d74275 100644 --- a/docs/api/v1/source.md +++ b/docs/api/v1/source.md @@ -1756,6 +1756,165 @@ github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus +

ExternalArtifact +

+

ExternalArtifact is the Schema for the external artifacts API

+
+
+ + + + + + + + + + + + + + + + + + + + + +
FieldDescription
+metadata
+ + +Kubernetes meta/v1.ObjectMeta + + +
+Refer to the Kubernetes API documentation for the fields of the +metadata field. +
+spec
+ + +ExternalArtifactSpec + + +
+
+
+ + + + + +
+sourceRef
+ + +github.com/fluxcd/pkg/apis/meta.NamespacedObjectKindReference + + +
+(Optional) +

SourceRef points to the Kubernetes custom resource for +which the artifact is generated.

+
+
+status
+ + +ExternalArtifactStatus + + +
+
+
+
+

ExternalArtifactSpec +

+

+(Appears on: +ExternalArtifact) +

+

ExternalArtifactSpec defines the desired state of ExternalArtifact

+
+
+ + + + + + + + + + + + + +
FieldDescription
+sourceRef
+ + +github.com/fluxcd/pkg/apis/meta.NamespacedObjectKindReference + + +
+(Optional) +

SourceRef points to the Kubernetes custom resource for +which the artifact is generated.

+
+
+
+

ExternalArtifactStatus +

+

+(Appears on: +ExternalArtifact) +

+

ExternalArtifactStatus defines the observed state of ExternalArtifact

+
+
+ + + + + + + + + + + + + + + + + +
FieldDescription
+artifact
+ + +github.com/fluxcd/pkg/apis/meta.Artifact + + +
+(Optional) +

Artifact represents the output of an ExternalArtifact reconciliation.

+
+conditions
+ + +[]Kubernetes meta/v1.Condition + + +
+(Optional) +

Conditions holds the conditions for the ExternalArtifact.

+
+
+

GitRepositoryInclude

From ba87b2ad0fe74198db11b5eba85d0582c797ceee Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Wed, 3 Sep 2025 23:46:16 +0300 Subject: [PATCH 4/4] Add ExternalArtifact API documentation Signed-off-by: Stefan Prodan --- docs/spec/v1/externalartifacts.md | 114 ++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 docs/spec/v1/externalartifacts.md diff --git a/docs/spec/v1/externalartifacts.md b/docs/spec/v1/externalartifacts.md new file mode 100644 index 000000000..1eccbe0e0 --- /dev/null +++ b/docs/spec/v1/externalartifacts.md @@ -0,0 +1,114 @@ +# External Artifacts + + + +The `ExternalArtifact` is a generic API designed for interoperability with Flux. +It allows 3rd party controllers to produce and store [Artifact](#artifact) objects +in the same way as Flux's own source-controller. +For more details on the design and motivation behind this API, +see [RFC-0012](https://github.com/fluxcd/flux2/tree/main/rfcs/0012-external-artifact). + +## Example + +The following is an example of a ExternalArtifact produced by a 3rd party +source controller: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1 +kind: ExternalArtifact +metadata: + name: my-artifact + namespace: flux-system +spec: + sourceRef: + apiVersion: example.com/v1 + kind: Source + name: my-source +status: + artifact: + digest: sha256:35d47c9db0eee6ffe08a404dfb416bee31b2b79eabc3f2eb26749163ce487f52 + lastUpdateTime: "2025-08-21T13:37:31Z" + path: source/flux-system/my-source/35d47c9d.tar.gz + revision: v1.0.0@sha256:35d47c9db0eee6ffe08a404dfb416bee31b2b79eabc3f2eb26749163ce487f52 + size: 20914 + url: http://example-controller.flux-system.svc.cluster.local./source/flux-system/my-source/35d47c9d.tar.gz + conditions: + - lastTransitionTime: "2025-08-21T13:37:31Z" + message: stored artifact for revision v1.0.0 + observedGeneration: 1 + reason: Succeeded + status: "True" + type: Ready +``` + +## ExternalArtifact spec + +### Source reference + +The `spec.sourceRef` field is optional and contains a reference +to the custom resource that the ExternalArtifact is based on. + +The `spec.sourceRef` contains the following fields: + +- `apiVersion`: the API version of the custom resource. +- `kind`: the kind of the custom resource. +- `name`: the name of the custom resource. +- `namespace`: the namespace of the custom resource. If omitted, it defaults to the + namespace of the ExternalArtifact. + +## ExternalArtifact status + +### Artifact + +The ExternalArtifact reports the latest synchronized state +as an Artifact object in the `.status.artifact`. + +The `.status.artifact` contains the following fields: + +- `digest`: The checksum of the tar.gz file in the format `:`. +- `lastUpdateTime`: Timestamp of the last artifact update. +- `path`: Relative file path of the artifact in storage. +- `revision`: Human-readable identifier with version and checksum in the format `@:`. +- `size`: Number of bytes in the tar.gz file. +- `url`: In-cluster HTTP address for artifact retrieval. + +### Conditions + +The ExternalArtifact reports its status using Kubernetes standard conditions. + +#### Ready ExternalArtifact + +When the 3rd party controller has successfully produced and stored an +Artifact in storage, it sets a Condition with the following +attributes in the ExternalArtifact's `.status.conditions`: + +- `type: Ready` +- `status: "True"` +- `reason: Succeeded` + +The `message` field should contain a human-readable message indicating +the successful storage of the artifact and the associated revision. + +If the 3rd party controller performs a signature verification +of the artifact, and the verification is successful, a Condition with the +following attributes is added to the ExternalArtifact's `.status.conditions`: + +- `type: SourceVerified` +- `status: "True"` +- `reason: Succeeded` + +The `message` field should contain a human-readable message indicating +the successful verification of the artifact and the associated verification method. + +#### Failed ExternalArtifact + +If the 3rd party controller fails to produce and store an Artifact, +it sets the `Ready` Condition status to `False`, and adds a Condition with +the following attributes to the ExternalArtifact's `.status.conditions`: + +- `type: Ready` +- `status: "False"` +- `reason: FetchFailed` | `reason: StorageOperationFailed` | `reason: VerificationFailed` + +The `message` field should contain a human-readable message indicating +the reason for the failure.