This is an automated email from the ASF dual-hosted git repository. pcongiusti pushed a commit to branch release-2.9.x in repository https://gitbox.apache.org/repos/asf/camel-k.git
commit ad2af2ca8f2369c6aca73589d3baf7f424387a91 Author: Pasquale Congiusti <[email protected]> AuthorDate: Sun Jan 25 09:24:39 2026 +0100 fix(traits): gitops, idempotent push Closes #6412 --- docs/modules/ROOT/pages/running/gitops.adoc | 3 +++ pkg/controller/integrationplatform/kamelets.go | 6 +++--- pkg/trait/gitops.go | 25 +++++++++++++++++++++++-- pkg/trait/gitops_test.go | 13 ++++++++++--- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/docs/modules/ROOT/pages/running/gitops.adoc b/docs/modules/ROOT/pages/running/gitops.adoc index 1dd75b93f..28792e400 100644 --- a/docs/modules/ROOT/pages/running/gitops.adoc +++ b/docs/modules/ROOT/pages/running/gitops.adoc @@ -32,6 +32,7 @@ spec: container: requestMemory: 256Mi gitops: + enabled: true url: https://github.com/my-org/my-camel-apps.git secret: my-gh-token branchPush: cicd-listener @@ -154,6 +155,7 @@ spec: - my-env=dev ... gitops: + enabled: true url: https://github.com/my-org/my-camel-apps.git secret: my-gh-token branchPush: cicd-listener-test @@ -174,6 +176,7 @@ spec: properties: - my-env=test gitops: + enabled: true url: https://github.com/my-org/my-camel-apps.git secret: my-gh-token branchPush: cicd-listener-prod diff --git a/pkg/controller/integrationplatform/kamelets.go b/pkg/controller/integrationplatform/kamelets.go index 87b8f8de7..dbe7151e9 100644 --- a/pkg/controller/integrationplatform/kamelets.go +++ b/pkg/controller/integrationplatform/kamelets.go @@ -29,7 +29,7 @@ import ( "strings" v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" - "knative.dev/pkg/ptr" + "k8s.io/utils/ptr" "github.com/apache/camel-k/v2/pkg/client" "github.com/apache/camel-k/v2/pkg/util" @@ -234,8 +234,8 @@ func loadKamelet(path string, platform *v1.IntegrationPlatform) (*v1.Kamelet, er Kind: platform.Kind, Name: platform.Name, UID: platform.UID, - Controller: ptr.Bool(true), - BlockOwnerDeletion: ptr.Bool(true), + Controller: ptr.To(true), + BlockOwnerDeletion: ptr.To(true), }, } kamelet.SetOwnerReferences(references) diff --git a/pkg/trait/gitops.go b/pkg/trait/gitops.go index 9f54b2f45..58a4eab5b 100644 --- a/pkg/trait/gitops.go +++ b/pkg/trait/gitops.go @@ -30,6 +30,7 @@ import ( "github.com/apache/camel-k/v2/pkg/util/io" "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/plumbing" + corev1 "k8s.io/api/core/v1" "k8s.io/utils/ptr" git "github.com/go-git/go-git/v5" @@ -117,7 +118,10 @@ func (t *gitOpsTrait) pushGitOpsItInGitRepo(ctx context.Context, it *v1.Integrat nowDate := time.Now().Format("20060102-150405") branchName := t.BranchPush if branchName == "" { - branchName = "cicd/candidate-release-" + nowDate + // NOTE: this is important to guarantee idempotency. We make sure not to create + // more than one branch from different reconciliation cycles. + branchNameDate := it.Status.DeploymentTimestamp.Format("20060102-150405") + branchName = "cicd/candidate-release-" + branchNameDate } commitMessage := "feat(ci): build completed on " + nowDate branchRef := plumbing.NewBranchReferenceName(branchName) @@ -175,9 +179,26 @@ func (t *gitOpsTrait) pushGitOpsItInGitRepo(ctx context.Context, it *v1.Integrat RefSpecs: []config.RefSpec{ config.RefSpec(branchRef + ":" + branchRef), }, + // Note: this is needed to make the task idempotent without returning any error. + // Even if more parallel reconciliations are kicked off, we always push the same content, + // possibly more than once, without risking to raise an error. + Force: true, } - return repo.Push(gitPushOptions) + err = repo.Push(gitPushOptions) + if err != nil { + return err + } + + // Publish a condition to notify the change was pushed to the branch + it.Status.SetCondition( + v1.IntegrationConditionType("GitPushed"), + corev1.ConditionTrue, + "PushedToGit", + "Integration changes pushed to branch "+branchName, + ) + + return nil } // gitConf returns the git repo configuration where to pull the project from. If no value is provided, then, it takes diff --git a/pkg/trait/gitops_test.go b/pkg/trait/gitops_test.go index 4acda7c8e..ebc40a046 100644 --- a/pkg/trait/gitops_test.go +++ b/pkg/trait/gitops_test.go @@ -26,18 +26,19 @@ import ( "time" v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1" - "knative.dev/pkg/ptr" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/go-git/go-git/v5/plumbing/object" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "k8s.io/utils/ptr" git "github.com/go-git/go-git/v5" ) func TestGitOpsAddAction(t *testing.T) { trait, _ := newGitOpsTrait().(*gitOpsTrait) - trait.Enabled = ptr.Bool(true) + trait.Enabled = ptr.To(true) env := &Environment{ Integration: &v1.Integration{ Status: v1.IntegrationStatus{ @@ -72,12 +73,18 @@ func TestGitOpsPushRepoDefault(t *testing.T) { Git: conf, Sources: []v1.SourceSpec{v1.NewSourceSpec("Test.java", "bogus, irrelevant for test", v1.LanguageJavaSource)}, } + now := metav1.Now().Rfc3339Copy() it.Status = v1.IntegrationStatus{ - Image: "my-img-recently-baked", + Image: "my-img-recently-baked", + DeploymentTimestamp: &now, } err = trait.pushGitOpsItInGitRepo(context.TODO(), &it, tmpGitDir, "fake") require.NoError(t, err) + assert.Contains(t, + it.Status.GetCondition(v1.IntegrationConditionType("GitPushed")).Message, + "Integration changes pushed to branch cicd/candidate-release", + ) lastCommitMessage, err := getLastCommitMessage(tmpGitDir) require.NoError(t, err)
