Skip to content

Commit 4f04701

Browse files
SergKMykolaMarusenko
authored andcommitted
feat: simplify GitLab CI template selection via annotation-based ConfigMap lookup
Replace fragile auto-discovery (gitlab-ci-{lang}-{buildtool} naming convention with fallback) with explicit user choice. Users now select a template ConfigMap at onboarding via the app.edp.epam.com/gitlab-ci-template annotation on the Codebase CR. The portal will discover available templates by listing ConfigMaps with the app.edp.epam.com/ci-template=gitlab label. Decision rationale: - Auto-discovery failed for edge cases (java17 vs java21 ambiguity) - Explicit selection gives users clear control and transparency - Removes fragile naming convention coupling - Enables future extensibility (per-team, per-language defaults) - Only {{.CodebaseName}} substitution kept; Lang/BuildTool removed to prevent template surprises and keep user content literal Signed-off-by: Sergiy Kulanov <sergiy_kulanov@epam.com>
1 parent ac1000a commit 4f04701

7 files changed

Lines changed: 438 additions & 189 deletions

File tree

api/v1/annotations.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package v1
2+
3+
const (
4+
// GitLabCITemplateAnnotation is an annotation on a Codebase CR that specifies the ConfigMap
5+
// name to use as the GitLab CI template. When absent, the operator falls back to "gitlab-ci-default".
6+
GitLabCITemplateAnnotation = "app.edp.epam.com/gitlab-ci-template"
7+
)

api/v1/labels.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,9 @@ const (
2020
// We can't use the branch name directly as a label value because it can contain special characters.
2121
// XXH64 is used to generate the hash.
2222
BranchHashLabel = "app.edp.epam.com/branch-hash"
23+
24+
// CITemplateLabel is a label on ConfigMaps that marks them as CI templates.
25+
// The portal uses this label to discover available templates for a dropdown.
26+
// Values: "gitlab" (extensible to other CI systems in the future).
27+
CITemplateLabel = "app.edp.epam.com/ci-template"
2328
)

controllers/codebase/service/chain/put_gitlab_ci_config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ func (h *PutGitLabCIConfig) ServeRequest(ctx context.Context, codebase *codebase
7676
return nil
7777
}
7878

79+
// gitlabCIAlreadyExists is a fast-path optimization that checks whether
80+
// .gitlab-ci.yml already exists in the local working directory, avoiding the
81+
// expensive clone+checkout round-trip when the file was written by a prior
82+
// reconciliation run. The manager's InjectGitLabCIConfig has its own os.Stat
83+
// guard as a safety invariant, so this check is purely an optimization.
7984
func (h *PutGitLabCIConfig) gitlabCIAlreadyExists(codebase *codebaseApi.Codebase) bool {
8085
wd := util.GetWorkDir(codebase.Name, codebase.Namespace)
8186
gitlabCIPath := filepath.Join(wd, gitlabci.GitLabCIFileName)

controllers/codebase/service/chain/put_gitlab_ci_config_test.go

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import (
2424
"github.com/epam/edp-codebase-operator/v2/pkg/util"
2525
)
2626

27+
const testGitLabCIConfigData = "variables:\n CODEBASE_NAME: \"{{.CodebaseName}}\"\ninclude:\n " +
28+
"- component: $CI_SERVER_FQDN/kuberocketci/ci-java17-mvn/build@0.1.1"
29+
2730
func TestPutGitLabCIConfig_ServeRequest(t *testing.T) {
2831
const defaultNs = "default"
2932

@@ -134,12 +137,70 @@ func TestPutGitLabCIConfig_ServeRequest(t *testing.T) {
134137
gitlabGitServerSecret,
135138
&corev1.ConfigMap{
136139
ObjectMeta: metav1.ObjectMeta{
137-
Name: "gitlab-ci-java-maven",
140+
Name: gitlabci.GitLabCIDefaultTemplate,
141+
Namespace: defaultNs,
142+
},
143+
Data: map[string]string{
144+
".gitlab-ci.yml": testGitLabCIConfigData,
145+
},
146+
},
147+
},
148+
gitClient: func(t *testing.T) gitproviderv2.Git {
149+
mock := gitmocks.NewMockGit(t)
150+
151+
mock.On("Clone", testify.Anything, testify.Anything, testify.Anything).
152+
Return(nil)
153+
mock.On("GetCurrentBranchName", testify.Anything, testify.Anything).
154+
Return("master", nil)
155+
mock.On("Commit", testify.Anything, testify.Anything, "Add GitLab CI configuration").
156+
Return(nil)
157+
mock.On("Push", testify.Anything, testify.Anything, gitproviderv2.RefSpecPushAllBranches).
158+
Return(nil)
159+
160+
return mock
161+
},
162+
setup: func(t *testing.T, wd string) {
163+
require.NoError(t, os.MkdirAll(wd, 0755))
164+
},
165+
wantErr: require.NoError,
166+
wantStatus: func(t *testing.T, codebase *codebaseApi.Codebase) {
167+
require.Equal(t, util.ProjectGitLabCIPushedStatus, codebase.Status.Git)
168+
},
169+
},
170+
{
171+
name: "successfully inject GitLab CI config with annotation",
172+
codebase: &codebaseApi.Codebase{
173+
ObjectMeta: metav1.ObjectMeta{
174+
Name: "java-app",
175+
Namespace: defaultNs,
176+
Annotations: map[string]string{
177+
codebaseApi.GitLabCITemplateAnnotation: "my-custom-template",
178+
},
179+
},
180+
Spec: codebaseApi.CodebaseSpec{
181+
Strategy: codebaseApi.Clone,
182+
CiTool: util.CIGitLab,
183+
GitServer: gitlabGitServer.Name,
184+
GitUrlPath: "/owner/java-repo",
185+
Repository: &codebaseApi.Repository{Url: "https://gitlab.com/owner/java-repo.git"},
186+
DefaultBranch: "master",
187+
Lang: "java",
188+
BuildTool: "maven",
189+
},
190+
Status: codebaseApi.CodebaseStatus{
191+
Git: util.ProjectPushedStatus,
192+
},
193+
},
194+
objects: []client.Object{
195+
gitlabGitServer,
196+
gitlabGitServerSecret,
197+
&corev1.ConfigMap{
198+
ObjectMeta: metav1.ObjectMeta{
199+
Name: "my-custom-template",
138200
Namespace: defaultNs,
139201
},
140202
Data: map[string]string{
141-
".gitlab-ci.yml": "variables:\n CODEBASE_NAME: \"{{.CodebaseName}}\"\ninclude:\n " +
142-
"- component: $CI_SERVER_FQDN/kuberocketci/ci-java17-mvn/build@0.1.1",
203+
".gitlab-ci.yml": "custom: {{.CodebaseName}}",
143204
},
144205
},
145206
},
@@ -398,12 +459,11 @@ func TestPutGitLabCIConfig_ServeRequest(t *testing.T) {
398459
gitlabGitServerSecret,
399460
&corev1.ConfigMap{
400461
ObjectMeta: metav1.ObjectMeta{
401-
Name: "gitlab-ci-java-maven",
462+
Name: gitlabci.GitLabCIDefaultTemplate,
402463
Namespace: defaultNs,
403464
},
404465
Data: map[string]string{
405-
".gitlab-ci.yml": "variables:\n CODEBASE_NAME: \"{{.CodebaseName}}\"\ninclude:\n " +
406-
"- component: $CI_SERVER_FQDN/kuberocketci/ci-java17-mvn/build@0.1.1",
466+
".gitlab-ci.yml": testGitLabCIConfigData,
407467
},
408468
},
409469
},
@@ -452,12 +512,11 @@ func TestPutGitLabCIConfig_ServeRequest(t *testing.T) {
452512
gitlabGitServerSecret,
453513
&corev1.ConfigMap{
454514
ObjectMeta: metav1.ObjectMeta{
455-
Name: "gitlab-ci-java-maven",
515+
Name: gitlabci.GitLabCIDefaultTemplate,
456516
Namespace: defaultNs,
457517
},
458518
Data: map[string]string{
459-
".gitlab-ci.yml": "variables:\n CODEBASE_NAME: \"{{.CodebaseName}}\"\ninclude:\n " +
460-
"- component: $CI_SERVER_FQDN/kuberocketci/ci-java17-mvn/build@0.1.1",
519+
".gitlab-ci.yml": testGitLabCIConfigData,
461520
},
462521
},
463522
},

0 commit comments

Comments
 (0)