@@ -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,22 @@ 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+ // TODO remove newModel handling after only new model is used
129+ // For new model: only reconcile when spec changes (Generation increments), not on status-only updates
130+ // For old model: always reconcile on update (old model uses annotations which don't increment Generation)
131+ if isComponentUsingNewModel (component ) {
132+ return e .ObjectOld .GetGeneration () != e .ObjectNew .GetGeneration ()
133+ }
117134 return true
118135 },
119136 DeleteFunc : func (e event.DeleteEvent ) bool {
@@ -127,6 +144,13 @@ func (r *ComponentBuildReconciler) SetupWithManager(mgr ctrl.Manager) error {
127144 Complete (r )
128145}
129146
147+ // isComponentUsingNewModel checks if the component is configured to use the new model (v2).
148+ // Returns true if the component has the new model annotation set to v2 or if the default model is v2.
149+ func isComponentUsingNewModel (component * compapiv1alpha1.Component ) bool {
150+ requestedModel , requestedModelAnnotationExists := component .Annotations [ComponentModelVersionAnnotation ]
151+ return (requestedModelAnnotationExists && requestedModel == NewComponentModelVersion ) || DefaultComponentModelVersion == NewComponentModelVersion
152+ }
153+
130154func updateMetricsTimes (componentIdForMetrics string , requestedAction string , reconcileStartTime time.Time ) {
131155 componentInfo , timeRecorded := bometrics .ComponentTimesForMetrics [componentIdForMetrics ]
132156
@@ -159,12 +183,12 @@ func updateMetricsTimes(componentIdForMetrics string, requestedAction string, re
159183//+kubebuilder:rbac:groups=route.openshift.io,resources=routes,verbs=get;list;watch
160184
161185func (r * ComponentBuildReconciler ) Reconcile (ctx context.Context , req ctrl.Request ) (ctrl.Result , error ) {
162- log := ctrllog .FromContext (ctx ). WithName ( "ComponentOnboarding" )
186+ log := ctrllog .FromContext (ctx )
163187 ctx = ctrllog .IntoContext (ctx , log )
164188 reconcileStartTime := time .Now ()
165189
166190 // Fetch the Component instance
167- var component appstudiov1alpha1 .Component
191+ var component compapiv1alpha1 .Component
168192 err := r .Client .Get (ctx , req .NamespacedName , & component )
169193 if err != nil {
170194 if errors .IsNotFound (err ) {
@@ -177,11 +201,17 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
177201 return ctrl.Result {}, err
178202 }
179203
204+ if isComponentUsingNewModel (& component ) {
205+ return r .ReconcileNewModel (ctx , req )
206+ }
207+
208+ log = ctrllog .FromContext (ctx ).WithName ("ComponentOnboarding" )
209+
180210 // Don't recreate build pipeline Service Account upon component deletion.
181211 if component .ObjectMeta .DeletionTimestamp .IsZero () {
182212 // We need to make sure the Service Account exists before checking the Component image,
183213 // 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 {
214+ if err := r .EnsureBuildPipelineServiceAccount (ctx , & component , true ); err != nil {
185215 return ctrl.Result {}, err
186216 }
187217 }
@@ -202,7 +232,7 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
202232 log .Error (err , "failed to update component after waiting for containerImage" , l .Action , l .ActionUpdate , l .Audit , "true" )
203233 return ctrl.Result {}, err
204234 }
205- r .WaitForCacheUpdate (ctx , req .NamespacedName , & component )
235+ r .WaitForCacheUpdateOldModel (ctx , req .NamespacedName , & component )
206236
207237 return ctrl.Result {}, nil
208238 }
@@ -256,7 +286,7 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
256286 log .Info ("PaC finalizer removed" , l .Action , l .ActionDelete )
257287
258288 // Try to clean up Pipelines as Code configuration
259- _ , _ = r .UndoPaCProvisionForComponent (ctx , & component )
289+ _ , _ = r .UndoPaCProvisionForComponentOldModel (ctx , & component )
260290 }
261291
262292 // Clean up common build pipelines Role Binding
@@ -305,7 +335,7 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
305335 return ctrl.Result {}, err
306336 }
307337 log .Info (fmt .Sprintf ("updated component after wrong %s annotation" , defaultBuildPipelineAnnotation ))
308- r .WaitForCacheUpdate (ctx , req .NamespacedName , & component )
338+ r .WaitForCacheUpdateOldModel (ctx , req .NamespacedName , & component )
309339
310340 return ctrl.Result {}, nil
311341 }
@@ -338,7 +368,7 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
338368 return ctrl.Result {}, nil
339369 }
340370
341- reconcileRequired , err := r .TriggerPaCBuild (ctx , & component )
371+ reconcileRequired , err := r .TriggerPaCBuildOldModel (ctx , & component )
342372
343373 if err != nil {
344374 if boErr , ok := err .(* boerrors.BuildOpError ); ok && boErr .IsPersistent () {
@@ -368,7 +398,7 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
368398 }()
369399
370400 pacBuildStatus := & PaCBuildStatus {}
371- if mergeUrl , err := r .ProvisionPaCForComponent (ctx , & component ); err != nil {
401+ if mergeUrl , err := r .ProvisionPaCForComponentOldModel (ctx , & component ); err != nil {
372402 if boErr , ok := err .(* boerrors.BuildOpError ); ok && boErr .IsPersistent () {
373403 log .Error (err , "Pipelines as Code provision for the Component failed" )
374404 pacBuildStatus .State = "error"
@@ -436,7 +466,7 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
436466 }
437467
438468 pacBuildStatus := & PaCBuildStatus {}
439- if mergeUrl , err := r .UndoPaCProvisionForComponent (ctx , & component ); err != nil {
469+ if mergeUrl , err := r .UndoPaCProvisionForComponentOldModel (ctx , & component ); err != nil {
440470 if boErr , ok := err .(* boerrors.BuildOpError ); ok && boErr .IsPersistent () {
441471 log .Error (err , "Pipelines as Code unprovision for the Component failed" )
442472 pacBuildStatus .State = "error"
@@ -491,12 +521,13 @@ func (r *ComponentBuildReconciler) Reconcile(ctx context.Context, req ctrl.Reque
491521 // remove component from metrics map
492522 delete (bometrics .ComponentTimesForMetrics , componentIdForMetrics )
493523
494- r .WaitForCacheUpdate (ctx , req .NamespacedName , & component )
524+ r .WaitForCacheUpdateOldModel (ctx , req .NamespacedName , & component )
495525
496526 return ctrl.Result {}, nil
497527}
498528
499- func (r * ComponentBuildReconciler ) WaitForCacheUpdate (ctx context.Context , namespace types.NamespacedName , component * appstudiov1alpha1.Component ) {
529+ // TODO remove after only new model is used
530+ func (r * ComponentBuildReconciler ) WaitForCacheUpdateOldModel (ctx context.Context , namespace types.NamespacedName , component * compapiv1alpha1.Component ) {
500531 log := ctrllog .FromContext (ctx )
501532
502533 // Here we do some trick.
@@ -532,7 +563,7 @@ func (r *ComponentBuildReconciler) WaitForCacheUpdate(ctx context.Context, names
532563 }
533564}
534565
535- func readBuildStatus (component * appstudiov1alpha1 .Component ) * BuildStatus {
566+ func readBuildStatus (component * compapiv1alpha1 .Component ) * BuildStatus {
536567 if component .Annotations == nil {
537568 return & BuildStatus {}
538569 }
@@ -545,7 +576,7 @@ func readBuildStatus(component *appstudiov1alpha1.Component) *BuildStatus {
545576 return & BuildStatus {}
546577}
547578
548- func writeBuildStatus (component * appstudiov1alpha1 .Component , buildStatus * BuildStatus ) {
579+ func writeBuildStatus (component * compapiv1alpha1 .Component , buildStatus * BuildStatus ) {
549580 if component .Annotations == nil {
550581 component .Annotations = make (map [string ]string )
551582 }
0 commit comments