Skip to content

Commit b7ef8b4

Browse files
authored
Merge pull request #1293 from fluxcd/external-artifact
[RFC-0012] Add support for `ExternalArtifact` source type to `chartRef`
2 parents 251bc85 + 0986524 commit b7ef8b4

File tree

17 files changed

+585
-105
lines changed

17 files changed

+585
-105
lines changed

Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ SOURCE_CRD_VER = $(CRD_DEP_ROOT)/.src-crd-$(SOURCE_VER)
3737

3838
# HelmChart source CRD.
3939
HELMCHART_SOURCE_CRD ?= $(CRD_DEP_ROOT)/source.toolkit.fluxcd.io_helmcharts.yaml
40+
OCIREPO_CRD ?= $(CRD_DEP_ROOT)/source.toolkit.fluxcd.io_ocirepositories.yaml
41+
EA_CRD ?= $(CRD_DEP_ROOT)/source.toolkit.fluxcd.io_externalartifacts.yaml
4042

4143
# API (doc) generation utilities
4244
CONTROLLER_GEN_VERSION ?= v0.19.0
@@ -135,8 +137,14 @@ $(SOURCE_CRD_VER):
135137
$(HELMCHART_SOURCE_CRD):
136138
curl -s https://raw.githubusercontent.com/fluxcd/source-controller/${SOURCE_VER}/config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml > $(HELMCHART_SOURCE_CRD)
137139

140+
$(OCIREPO_CRD):
141+
curl -s https://raw.githubusercontent.com/fluxcd/source-controller/${SOURCE_VER}/config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml -o $(OCIREPO_CRD)
142+
143+
$(EA_CRD):
144+
curl -s https://raw.githubusercontent.com/fluxcd/source-controller/${SOURCE_VER}/config/crd/bases/source.toolkit.fluxcd.io_externalartifacts.yaml -o $(EA_CRD)
145+
138146
# Download the CRDs the controller depends on
139-
download-crd-deps: $(SOURCE_CRD_VER) $(HELMCHART_SOURCE_CRD)
147+
download-crd-deps: $(SOURCE_CRD_VER) $(HELMCHART_SOURCE_CRD) $(OCIREPO_CRD) $(EA_CRD)
140148

141149
# Delete the downloaded CRD dependencies.
142150
cleanup-crd-deps:

api/v2/reference_types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ type CrossNamespaceSourceReference struct {
5050
APIVersion string `json:"apiVersion,omitempty"`
5151

5252
// Kind of the referent.
53-
// +kubebuilder:validation:Enum=OCIRepository;HelmChart
53+
// +kubebuilder:validation:Enum=OCIRepository;HelmChart;ExternalArtifact
5454
// +required
5555
Kind string `json:"kind"`
5656

config/crd/bases/helm.toolkit.fluxcd.io_helmreleases.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ spec:
203203
enum:
204204
- OCIRepository
205205
- HelmChart
206+
- ExternalArtifact
206207
type: string
207208
name:
208209
description: Name of the referent.

config/default/kustomization.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ apiVersion: kustomize.config.k8s.io/v1beta1
22
kind: Kustomization
33
namespace: helm-system
44
resources:
5-
- https://github.com/fluxcd/source-controller/releases/download/v1.6.0/source-controller.crds.yaml
6-
- https://github.com/fluxcd/source-controller/releases/download/v1.6.0/source-controller.deployment.yaml
5+
- https://github.com/fluxcd/source-controller/releases/download/v1.7.0-rc.3/source-controller.crds.yaml
6+
- https://github.com/fluxcd/source-controller/releases/download/v1.7.0-rc.3/source-controller.deployment.yaml
77
- ../crd
88
- ../rbac
99
- ../manager

docs/spec/v2/helmreleases.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,16 @@ HelmRelease object.
205205

206206
### Chart reference
207207

208-
`.spec.chartRef` is an optional field used to refer to an [OCIRepository resource](https://fluxcd.io/flux/components/source/ocirepositories/) or a [HelmChart resource](https://fluxcd.io/flux/components/source/helmcharts/)
209-
from which to fetch the Helm chart. The chart is fetched by the controller with the
210-
information provided by `.status.artifact` of the referenced resource.
208+
`.spec.chartRef` is an optional field used to refer to the Source object which has an
209+
Artifact containing the Helm chart. It has two required fields:
211210

212-
For a referenced resource of `kind OCIRepository`, the chart version of the last
211+
- `kind`: The Kind of the referred Source object. Supported Source types:
212+
+ [OCIRepository](https://fluxcd.io/flux/components/source/ocirepositories/)
213+
+ [HelmChart](https://fluxcd.io/flux/components/source/helmcharts/)
214+
+ [ExternalArtifact](https://fluxcd.io/flux/components/source/externalartifacts/) (requires `--feature-gates=ExternalArtifact=true` flag)
215+
- `name`: The Name of the referred Source object.
216+
217+
For a referenced resource of kind `OCIRepository`, the chart version of the last
213218
release attempt is reported in `.status.lastAttemptedRevision`. The version is in
214219
the format `<version>+<digest[0:12]>`. The digest of the OCI artifact is appended
215220
to the version to ensure that a change in the artifact content triggers a new release.

go.mod

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ require (
2121
github.com/fluxcd/pkg/apis/acl v0.9.0
2222
github.com/fluxcd/pkg/apis/event v0.19.0
2323
github.com/fluxcd/pkg/apis/kustomize v1.12.0
24-
github.com/fluxcd/pkg/apis/meta v1.20.0
25-
github.com/fluxcd/pkg/auth v0.29.0
24+
github.com/fluxcd/pkg/apis/meta v1.21.0
25+
github.com/fluxcd/pkg/auth v0.30.0
2626
github.com/fluxcd/pkg/cache v0.11.0
27-
github.com/fluxcd/pkg/chartutil v1.11.0
28-
github.com/fluxcd/pkg/runtime v0.82.0
27+
github.com/fluxcd/pkg/chartutil v1.12.0
28+
github.com/fluxcd/pkg/runtime v0.83.0
2929
github.com/fluxcd/pkg/ssa v0.53.0
3030
github.com/fluxcd/pkg/testserver v0.13.0
31-
github.com/fluxcd/source-controller/api v1.6.0
31+
github.com/fluxcd/source-controller/api v1.7.0-rc.3
3232
github.com/go-logr/logr v1.4.3
3333
github.com/google/cel-go v0.26.1
3434
github.com/google/go-cmp v0.7.0
@@ -39,6 +39,7 @@ require (
3939
github.com/opencontainers/go-digest/blake3 v0.0.0-20250116041648-1e56c6daea3b
4040
github.com/spf13/pflag v1.0.7
4141
github.com/wI2L/jsondiff v0.7.0
42+
go.uber.org/zap v1.27.0
4243
golang.org/x/text v0.28.0
4344
helm.sh/helm/v3 v3.18.6
4445
k8s.io/api v0.34.0
@@ -100,7 +101,7 @@ require (
100101
github.com/containerd/platforms v0.2.1 // indirect
101102
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
102103
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
103-
github.com/docker/cli v28.2.2+incompatible // indirect
104+
github.com/docker/cli v28.3.3+incompatible // indirect
104105
github.com/docker/docker-credential-helpers v0.9.3 // indirect
105106
github.com/emicklei/go-restful/v3 v3.13.0 // indirect
106107
github.com/evanphx/json-patch v5.9.11+incompatible // indirect
@@ -201,7 +202,6 @@ require (
201202
go.opentelemetry.io/otel/metric v1.38.0 // indirect
202203
go.opentelemetry.io/otel/trace v1.38.0 // indirect
203204
go.uber.org/multierr v1.11.0 // indirect
204-
go.uber.org/zap v1.27.0 // indirect
205205
go.yaml.in/yaml/v2 v2.4.2 // indirect
206206
go.yaml.in/yaml/v3 v3.0.4 // indirect
207207
golang.org/x/crypto v0.41.0 // indirect

go.sum

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr
124124
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
125125
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
126126
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
127-
github.com/docker/cli v28.2.2+incompatible h1:qzx5BNUDFqlvyq4AHzdNB7gSyVTmU4cgsyN9SdInc1A=
128-
github.com/docker/cli v28.2.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
127+
github.com/docker/cli v28.3.3+incompatible h1:fp9ZHAr1WWPGdIWBM1b3zLtgCF+83gRdVMTJsUeiyAo=
128+
github.com/docker/cli v28.3.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
129129
github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
130130
github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
131131
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
@@ -152,22 +152,22 @@ github.com/fluxcd/pkg/apis/event v0.19.0 h1:ZJU2voontkzp5rNYA4JMOu40S4tRcrWi4Do5
152152
github.com/fluxcd/pkg/apis/event v0.19.0/go.mod h1:deuIyUb6lh+Z1Ccvwwxhm1wNM3kpSo+vF1IgRnpaZfQ=
153153
github.com/fluxcd/pkg/apis/kustomize v1.12.0 h1:KvZN6xwgP/dNSeckL4a/Uv715XqiN1C3xS+jGcPejtE=
154154
github.com/fluxcd/pkg/apis/kustomize v1.12.0/go.mod h1:OojLxIdKm1JAAdh3sL4j4F+vfrLKb7kq1vr8bpyEKgg=
155-
github.com/fluxcd/pkg/apis/meta v1.20.0 h1:l9h0kWoDZTcYV0WJkFMgDXq6Q4tSojrJ+bHpFJSsaW0=
156-
github.com/fluxcd/pkg/apis/meta v1.20.0/go.mod h1:XUAEUgT4gkWDAEN79E141tmL+v4SV50tVZ/Ojpc/ueg=
157-
github.com/fluxcd/pkg/auth v0.29.0 h1:lLc63zjodqIqg5ydlU/Kp3Qa+wvh6G2khjop5MHALvk=
158-
github.com/fluxcd/pkg/auth v0.29.0/go.mod h1:bjZ+6RMSGgsQQK+aPfVP8HWuBbb+FLlFxMiqd8ywzik=
155+
github.com/fluxcd/pkg/apis/meta v1.21.0 h1:R+bN02chcs0HUmyVDQhqe/FHmYLjipVDMLnyYfNX850=
156+
github.com/fluxcd/pkg/apis/meta v1.21.0/go.mod h1:XUAEUgT4gkWDAEN79E141tmL+v4SV50tVZ/Ojpc/ueg=
157+
github.com/fluxcd/pkg/auth v0.30.0 h1:7JMnY1ClArvOsadt6hOxceu8Q2hLsYHFMt0DV3BQl4Q=
158+
github.com/fluxcd/pkg/auth v0.30.0/go.mod h1:me38o1nDfSLw6YvnkT9Ce/zqJZICZSA7j5pNMR3JUbc=
159159
github.com/fluxcd/pkg/cache v0.11.0 h1:fsE8S+una21fSNw4MDXGUIf0Gf1J+pqa4RbsVKf2aTI=
160160
github.com/fluxcd/pkg/cache v0.11.0/go.mod h1:2RTIU6PsJniHmfnllQWFEo7fa5V8KQlnMgn4o0sme40=
161-
github.com/fluxcd/pkg/chartutil v1.11.0 h1:mtMqxsIIHLHSZS+D/9OfFS5ykABIOD2EOQbo3RyvjZY=
162-
github.com/fluxcd/pkg/chartutil v1.11.0/go.mod h1:zQEbp6pHdRnhZN+RBjpQorRf9HKhqiO0bTk4vaOxbNU=
163-
github.com/fluxcd/pkg/runtime v0.82.0 h1:VdPPRJtj8/rcBdqY7GZSffoxe5elFHt+ymwQHNbPOlc=
164-
github.com/fluxcd/pkg/runtime v0.82.0/go.mod h1:rIDynMhU5upbn8ce3bXQhH5L6vtDw5MELycvtJG/+og=
161+
github.com/fluxcd/pkg/chartutil v1.12.0 h1:AsOXWYQIUpZMCtlyQeaPmlWBYqSfHZTQ6A6eTGAhBLc=
162+
github.com/fluxcd/pkg/chartutil v1.12.0/go.mod h1:W1VxE52pIaimf9upYQW/fvonU3BDs2zxM2zdg/48vEE=
163+
github.com/fluxcd/pkg/runtime v0.83.0 h1:XzpwKzo7GqfBE/BKpxG5B4U7cUnojnB407S9Dpp6oLU=
164+
github.com/fluxcd/pkg/runtime v0.83.0/go.mod h1:r8KLvXRguKtpLAa66fA19rIbwPViXm8az038IUabYvw=
165165
github.com/fluxcd/pkg/ssa v0.53.0 h1:EtKFAYWXohIGkzPhIrv8NbV5zYr4iZHY6DaNxMR9+bU=
166166
github.com/fluxcd/pkg/ssa v0.53.0/go.mod h1:0IZxnnH8XkDkFzWjoMJsFEwPIWPOk3Gc/WR5+gT/KgI=
167167
github.com/fluxcd/pkg/testserver v0.13.0 h1:xEpBcEYtD7bwvZ+i0ZmChxKkDo/wfQEV3xmnzVybSSg=
168168
github.com/fluxcd/pkg/testserver v0.13.0/go.mod h1:akRYv3FLQUsme15na9ihECRG6hBuqni4XEY9W8kzs8E=
169-
github.com/fluxcd/source-controller/api v1.6.0 h1:IxfjUczJ2pzbXIef6iQ0RHEH4AYA9anJfTGK8dzwODM=
170-
github.com/fluxcd/source-controller/api v1.6.0/go.mod h1:ZJcAi0nemsnBxjVgmJl0WQzNvB0rMETxQMTdoFosmMw=
169+
github.com/fluxcd/source-controller/api v1.7.0-rc.3 h1:+9cd//77LAgp0XRe97CXUaPnu78jsRNWTXq95GHGhgc=
170+
github.com/fluxcd/source-controller/api v1.7.0-rc.3/go.mod h1:sbJibK4Ik+2AuTRRLXPA+n2u6nLUIGaxC07ava+RqeM=
171171
github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
172172
github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
173173
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=

internal/controller/helmrelease_controller.go

Lines changed: 61 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,26 @@ type HelmReleaseReconciler struct {
8787
kuberecorder.EventRecorder
8888
helper.Metrics
8989

90-
GetClusterConfig func() (*rest.Config, error)
91-
ClientOpts runtimeClient.Options
92-
KubeConfigOpts runtimeClient.KubeConfigOptions
93-
APIReader client.Reader
94-
TokenCache *cache.TokenCache
95-
96-
FieldManager string
97-
DefaultServiceAccount string
98-
DisableChartDigestTracking bool
99-
AdditiveCELDependencyCheck bool
90+
// Kubernetes configuration
91+
92+
FieldManager string
93+
DefaultServiceAccount string
94+
GetClusterConfig func() (*rest.Config, error)
95+
ClientOpts runtimeClient.Options
96+
KubeConfigOpts runtimeClient.KubeConfigOptions
97+
APIReader client.Reader
98+
TokenCache *cache.TokenCache
99+
100+
// Retry and requeue configuration
100101

101-
requeueDependency time.Duration
102-
artifactFetchRetries int
102+
DependencyRequeueInterval time.Duration
103+
ArtifactFetchRetries int
104+
105+
// Feature gates
106+
107+
AdditiveCELDependencyCheck bool
108+
AllowExternalArtifact bool
109+
DisableChartDigestTracking bool
103110
}
104111

105112
var (
@@ -221,14 +228,14 @@ func (r *HelmReleaseReconciler) reconcileRelease(ctx context.Context, patchHelpe
221228

222229
// Retry on transient errors.
223230
msg := fmt.Sprintf("dependencies do not meet ready condition (%s): retrying in %s",
224-
err.Error(), r.requeueDependency.String())
231+
err.Error(), r.DependencyRequeueInterval.String())
225232
conditions.MarkFalse(obj, meta.ReadyCondition, v2.DependencyNotReadyReason, "%s", err)
226233
r.Eventf(obj, corev1.EventTypeNormal, v2.DependencyNotReadyReason, err.Error())
227234
log.Info(msg)
228235

229236
// Exponential backoff would cause execution to be prolonged too much,
230237
// instead we requeue on a fixed interval.
231-
return ctrl.Result{RequeueAfter: r.requeueDependency}, errWaitForDependency
238+
return ctrl.Result{RequeueAfter: r.DependencyRequeueInterval}, errWaitForDependency
232239
}
233240

234241
log.Info("all dependencies are ready")
@@ -268,7 +275,7 @@ func (r *HelmReleaseReconciler) reconcileRelease(ctx context.Context, patchHelpe
268275
conditions.MarkFalse(obj, meta.ReadyCondition, "SourceNotReady", "%s", msg)
269276
// Do not requeue immediately, when the artifact is created
270277
// the watcher should trigger a reconciliation.
271-
return jitter.JitteredRequeueInterval(ctrl.Result{RequeueAfter: r.requeueDependency}), errWaitForChart
278+
return jitter.JitteredRequeueInterval(ctrl.Result{RequeueAfter: r.DependencyRequeueInterval}), errWaitForChart
272279
}
273280
// Remove any stale corresponding Ready=False condition with Unknown.
274281
if conditions.HasAnyReason(obj, meta.ReadyCondition, "SourceNotReady") {
@@ -293,13 +300,13 @@ func (r *HelmReleaseReconciler) reconcileRelease(ctx context.Context, patchHelpe
293300
}
294301

295302
// Load chart from artifact.
296-
loadedChart, err := loader.SecureLoadChartFromURL(loader.NewRetryableHTTPClient(ctx, r.artifactFetchRetries), source.GetArtifact().URL, source.GetArtifact().Digest)
303+
loadedChart, err := loader.SecureLoadChartFromURL(loader.NewRetryableHTTPClient(ctx, r.ArtifactFetchRetries), source.GetArtifact().URL, source.GetArtifact().Digest)
297304
if err != nil {
298305
if errors.Is(err, loader.ErrFileNotFound) {
299-
msg := fmt.Sprintf("Source not ready: artifact not found. Retrying in %s", r.requeueDependency.String())
306+
msg := fmt.Sprintf("Source not ready: artifact not found. Retrying in %s", r.DependencyRequeueInterval.String())
300307
conditions.MarkFalse(obj, meta.ReadyCondition, v2.ArtifactFailedReason, "%s", msg)
301308
log.Info(msg)
302-
return ctrl.Result{RequeueAfter: r.requeueDependency}, errWaitForDependency
309+
return ctrl.Result{RequeueAfter: r.DependencyRequeueInterval}, errWaitForDependency
303310
}
304311

305312
conditions.MarkFalse(obj, meta.ReadyCondition, v2.ArtifactFailedReason, "Could not load chart: %s", err)
@@ -774,6 +781,9 @@ func (r *HelmReleaseReconciler) getSource(ctx context.Context, obj *v2.HelmRelea
774781
if obj.Spec.ChartRef.Kind == sourcev1.OCIRepositoryKind {
775782
return r.getSourceFromOCIRef(ctx, obj)
776783
}
784+
if obj.Spec.ChartRef.Kind == sourcev1.ExternalArtifactKind {
785+
return r.getSourceFromExternalArtifact(ctx, obj)
786+
}
777787
name, namespace = obj.Spec.ChartRef.Name, obj.Spec.ChartRef.Namespace
778788
if namespace == "" {
779789
namespace = obj.GetNamespace()
@@ -813,6 +823,31 @@ func (r *HelmReleaseReconciler) getSourceFromOCIRef(ctx context.Context, obj *v2
813823
return &or, nil
814824
}
815825

826+
func (r *HelmReleaseReconciler) getSourceFromExternalArtifact(ctx context.Context, obj *v2.HelmRelease) (sourcev1.Source, error) {
827+
name, namespace := obj.Spec.ChartRef.Name, obj.Spec.ChartRef.Namespace
828+
if namespace == "" {
829+
namespace = obj.GetNamespace()
830+
}
831+
sourceRef := types.NamespacedName{Namespace: namespace, Name: name}
832+
833+
if err := intacl.AllowsAccessTo(obj, sourcev1.ExternalArtifactKind, sourceRef); err != nil {
834+
return nil, err
835+
}
836+
837+
// Check if ExternalArtifact kind is allowed.
838+
if obj.Spec.ChartRef.Kind == sourcev1.ExternalArtifactKind && !r.AllowExternalArtifact {
839+
return nil, acl.AccessDeniedError(
840+
fmt.Sprintf("can't access '%s/%s/%s', %s feature gate is disabled",
841+
obj.Spec.ChartRef.Kind, namespace, name, features.ExternalArtifact))
842+
}
843+
844+
or := sourcev1.ExternalArtifact{}
845+
if err := r.Client.Get(ctx, sourceRef, &or); err != nil {
846+
return nil, err
847+
}
848+
return &or, nil
849+
}
850+
816851
// waitForHistoryCacheSync returns a function that can be used to wait for the
817852
// cache backing the Kubernetes client to be in sync with the current state of
818853
// the v2.HelmRelease.
@@ -832,13 +867,20 @@ func (r *HelmReleaseReconciler) waitForHistoryCacheSync(obj *v2.HelmRelease) wai
832867
}
833868

834869
func isSourceReady(obj sourcev1.Source) (bool, string) {
870+
if o, ok := obj.(*sourcev1.ExternalArtifact); ok {
871+
if obj.GetArtifact() == nil {
872+
return false, fmt.Sprintf("ExternalArtifact '%s/%s' is not ready: does not have an artifact",
873+
o.GetNamespace(), o.GetName())
874+
}
875+
return true, ""
876+
}
835877
if o, ok := obj.(conditions.Getter); ok {
836878
return isReady(o, obj.GetArtifact())
837879
}
838880
return false, fmt.Sprintf("unknown sourcev1 type: %T", obj)
839881
}
840882

841-
func isReady(obj conditions.Getter, artifact *sourcev1.Artifact) (bool, string) {
883+
func isReady(obj conditions.Getter, artifact *meta.Artifact) (bool, string) {
842884
observedGen, err := object.GetStatusObservedGeneration(obj)
843885
if err != nil {
844886
return false, err.Error()

0 commit comments

Comments
 (0)