@@ -35,7 +35,7 @@ import (
3535 ctrllog "sigs.k8s.io/controller-runtime/pkg/log"
3636 "sigs.k8s.io/controller-runtime/pkg/predicate"
3737
38- appstudiov1alpha1 "github.com/konflux-ci/application-api/api/v1alpha1"
38+ compapiv1alpha1 "github.com/konflux-ci/application-api/api/v1alpha1"
3939
4040 "github.com/konflux-ci/build-service/pkg/boerrors"
4141 "github.com/konflux-ci/build-service/pkg/bometrics"
@@ -63,12 +63,18 @@ const (
6363
6464 gitCommitShaAnnotationName = "build.appstudio.redhat.com/commit_sha"
6565 gitRepoAtShaAnnotationName = "build.appstudio.openshift.io/repo"
66+ ContextAnnotationName = "appstudio.openshift.io/context"
67+ VersionAnnotationName = "appstudio.openshift.io/version"
6668
6769 defaultBuildPipelineAnnotation = "build.appstudio.openshift.io/pipeline"
6870 buildPipelineConfigMapResourceName = "build-pipeline-config"
6971 buildPipelineConfigName = "config.yaml"
7072
7173 waitForContainerImageMessage = "waiting for spec.containerImage to be set by ImageRepository with annotation image-controller.appstudio.redhat.com/update-component-image"
74+
75+ ComponentModelVersionAnnotation = "build.appstudio.openshift.io/component_model_version"
76+ DefaultComponentModelVersion = "v1"
77+ NewComponentModelVersion = "v2"
7278)
7379
7480type BuildStatus struct {
@@ -109,11 +115,21 @@ type ComponentBuildReconciler struct {
109115// SetupWithManager sets up the controller with the Manager.
110116func (r * ComponentBuildReconciler ) SetupWithManager (mgr ctrl.Manager ) error {
111117 return ctrl .NewControllerManagedBy (mgr ).
112- For (& appstudiov1alpha1 .Component {}, builder .WithPredicates (predicate.Funcs {
118+ For (& compapiv1alpha1 .Component {}, builder .WithPredicates (predicate.Funcs {
113119 CreateFunc : func (e event.CreateEvent ) bool {
114120 return true
115121 },
116122 UpdateFunc : func (e event.UpdateEvent ) bool {
123+ component , ok := e .ObjectNew .(* compapiv1alpha1.Component )
124+ if ! ok {
125+ return false
126+ }
127+
128+ // For new model: only reconcile when spec changes (Generation increments), not on status-only updates
129+ // For old model: always reconcile on update (old model uses annotations which don't increment Generation)
130+ if isComponentUsingNewModel (component ) {
131+ return e .ObjectOld .GetGeneration () != e .ObjectNew .GetGeneration ()
132+ }
117133 return true
118134 },
119135 DeleteFunc : func (e event.DeleteEvent ) bool {
@@ -127,6 +143,13 @@ func (r *ComponentBuildReconciler) SetupWithManager(mgr ctrl.Manager) error {
127143 Complete (r )
128144}
129145
146+ // isComponentUsingNewModel checks if the component is configured to use the new model (v2).
147+ // Returns true if the component has the new model annotation set to v2 or if the default model is v2.
148+ func isComponentUsingNewModel (component * compapiv1alpha1.Component ) bool {
149+ requestedModel , requestedModelAnnotationExists := component .Annotations [ComponentModelVersionAnnotation ]
150+ return (requestedModelAnnotationExists && requestedModel == NewComponentModelVersion ) || DefaultComponentModelVersion == NewComponentModelVersion
151+ }
152+
130153func updateMetricsTimes (componentIdForMetrics string , requestedAction string , reconcileStartTime time.Time ) {
131154 componentInfo , timeRecorded := bometrics .ComponentTimesForMetrics [componentIdForMetrics ]
132155
@@ -164,7 +187,7 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
164187 reconcileStartTime := time .Now ()
165188
166189 // Fetch the Component instance
167- var component appstudiov1alpha1 .Component
190+ var component compapiv1alpha1 .Component
168191 err := r .Client .Get (ctx , req .NamespacedName , & component )
169192 if err != nil {
170193 if errors .IsNotFound (err ) {
@@ -177,11 +200,15 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
177200 return ctrl.Result {}, err
178201 }
179202
203+ if isComponentUsingNewModel (& component ) {
204+ return r .ReconcileNewModel (ctx , req )
205+ }
206+
180207 // Don't recreate build pipeline Service Account upon component deletion.
181208 if component .ObjectMeta .DeletionTimestamp .IsZero () {
182209 // We need to make sure the Service Account exists before checking the Component image,
183210 // because Image Controller operator expects the Service Account to exist to link push secret to it.
184- if err := r .EnsureBuildPipelineServiceAccount (ctx , & component ); err != nil {
211+ if err := r .EnsureBuildPipelineServiceAccount (ctx , & component , true ); err != nil {
185212 return ctrl.Result {}, err
186213 }
187214 }
@@ -202,7 +229,7 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
202229 log .Error (err , "failed to update component after waiting for containerImage" , l .Action , l .ActionUpdate , l .Audit , "true" )
203230 return ctrl.Result {}, err
204231 }
205- r .WaitForCacheUpdate (ctx , req .NamespacedName , & component )
232+ r .WaitForCacheUpdateOldModel (ctx , req .NamespacedName , & component )
206233
207234 return ctrl.Result {}, nil
208235 }
@@ -256,7 +283,7 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
256283 log .Info ("PaC finalizer removed" , l .Action , l .ActionDelete )
257284
258285 // Try to clean up Pipelines as Code configuration
259- _ , _ = r .UndoPaCProvisionForComponent (ctx , & component )
286+ _ , _ = r .UndoPaCProvisionForComponentOldModel (ctx , & component )
260287 }
261288
262289 // Clean up common build pipelines Role Binding
@@ -305,7 +332,7 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
305332 return ctrl.Result {}, err
306333 }
307334 log .Info (fmt .Sprintf ("updated component after wrong %s annotation" , defaultBuildPipelineAnnotation ))
308- r .WaitForCacheUpdate (ctx , req .NamespacedName , & component )
335+ r .WaitForCacheUpdateOldModel (ctx , req .NamespacedName , & component )
309336
310337 return ctrl.Result {}, nil
311338 }
@@ -338,7 +365,7 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
338365 return ctrl.Result {}, nil
339366 }
340367
341- reconcileRequired , err := r .TriggerPaCBuild (ctx , & component )
368+ reconcileRequired , err := r .TriggerPaCBuildOldModel (ctx , & component )
342369
343370 if err != nil {
344371 if boErr , ok := err .(* boerrors.BuildOpError ); ok && boErr .IsPersistent () {
@@ -368,7 +395,7 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
368395 }()
369396
370397 pacBuildStatus := & PaCBuildStatus {}
371- if mergeUrl , err := r .ProvisionPaCForComponent (ctx , & component ); err != nil {
398+ if mergeUrl , err := r .ProvisionPaCForComponentOldModel (ctx , & component ); err != nil {
372399 if boErr , ok := err .(* boerrors.BuildOpError ); ok && boErr .IsPersistent () {
373400 log .Error (err , "Pipelines as Code provision for the Component failed" )
374401 pacBuildStatus .State = "error"
@@ -436,7 +463,7 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
436463 }
437464
438465 pacBuildStatus := & PaCBuildStatus {}
439- if mergeUrl , err := r .UndoPaCProvisionForComponent (ctx , & component ); err != nil {
466+ if mergeUrl , err := r .UndoPaCProvisionForComponentOldModel (ctx , & component ); err != nil {
440467 if boErr , ok := err .(* boerrors.BuildOpError ); ok && boErr .IsPersistent () {
441468 log .Error (err , "Pipelines as Code unprovision for the Component failed" )
442469 pacBuildStatus .State = "error"
@@ -491,12 +518,13 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
491518 // remove component from metrics map
492519 delete (bometrics .ComponentTimesForMetrics , componentIdForMetrics )
493520
494- r .WaitForCacheUpdate (ctx , req .NamespacedName , & component )
521+ r .WaitForCacheUpdateOldModel (ctx , req .NamespacedName , & component )
495522
496523 return ctrl.Result {}, nil
497524}
498525
499- func (r * ComponentBuildReconciler ) WaitForCacheUpdate (ctx context.Context , namespace types.NamespacedName , component * appstudiov1alpha1.Component ) {
526+ // TODO remove after only new model is used
527+ func (r * ComponentBuildReconciler ) WaitForCacheUpdateOldModel (ctx context.Context , namespace types.NamespacedName , component * compapiv1alpha1.Component ) {
500528 log := ctrllog .FromContext (ctx )
501529
502530 // Here we do some trick.
@@ -532,7 +560,7 @@ func (r *ComponentBuildReconciler) WaitForCacheUpdate(ctx context.Context, names
532560 }
533561}
534562
535- func readBuildStatus (component * appstudiov1alpha1 .Component ) * BuildStatus {
563+ func readBuildStatus (component * compapiv1alpha1 .Component ) * BuildStatus {
536564 if component .Annotations == nil {
537565 return & BuildStatus {}
538566 }
@@ -545,7 +573,7 @@ func readBuildStatus(component *appstudiov1alpha1.Component) *BuildStatus {
545573 return & BuildStatus {}
546574}
547575
548- func writeBuildStatus (component * appstudiov1alpha1 .Component , buildStatus * BuildStatus ) {
576+ func writeBuildStatus (component * compapiv1alpha1 .Component , buildStatus * BuildStatus ) {
549577 if component .Annotations == nil {
550578 component .Annotations = make (map [string ]string )
551579 }
0 commit comments