Skip to content

Commit

Permalink
feat: Add dynamic pipelines names for CodebaseBranch (#112)
Browse files Browse the repository at this point in the history
  • Loading branch information
zmotso authored and SergK committed Aug 15, 2024
1 parent 11da5e9 commit adcb430
Show file tree
Hide file tree
Showing 9 changed files with 274 additions and 41 deletions.
8 changes: 6 additions & 2 deletions api/v1/codebasebranch_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ const (
CodebaseBranchGitStatusBranchCreated = "branch-created"
)

// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.

// CodebaseBranchSpec defines the desired state of CodebaseBranch.
type CodebaseBranchSpec struct {
// Name of Codebase associated with.
Expand All @@ -31,6 +29,12 @@ type CodebaseBranchSpec struct {
// +nullable
// +optional
ReleaseJobParams map[string]string `json:"releaseJobParams,omitempty"`

// Pipelines is a map of pipelines related to the branch.
// +nullable
// +optional
// +kubebuilder:example:={"review": "review-pipeline", "build": "build-pipeline"}
Pipelines map[string]string `json:"pipelines,omitempty"`
}

// CodebaseBranchStatus defines the observed state of CodebaseBranch.
Expand Down
7 changes: 7 additions & 0 deletions api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions config/crd/bases/v2.edp.epam.com_codebasebranches.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ spec:
description: The new branch will be created starting from the selected
commit hash.
type: string
pipelines:
additionalProperties:
type: string
description: Pipelines is a map of pipelines related to the branch.
example:
build: build-pipeline
review: review-pipeline
nullable: true
type: object
release:
description: Flag if branch is used as "release" branch.
type: boolean
Expand Down
87 changes: 85 additions & 2 deletions controllers/codebasebranch/codebasebranch_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"reflect"
"strings"
"time"

"github.com/go-logr/logr"
Expand Down Expand Up @@ -114,9 +115,22 @@ func (r *ReconcileCodebaseBranch) Reconcile(ctx context.Context, request reconci
return reconcile.Result{}, fmt.Errorf("failed to fetch CodebaseBranch resource %q: %w", request.NamespacedName, err)
}

c, err := util.GetCodebase(r.client, cb.Spec.CodebaseName, cb.Namespace)
c := &codebaseApi.Codebase{}
if err := r.client.Get(ctx, types.NamespacedName{Name: cb.Spec.CodebaseName, Namespace: cb.Namespace}, c); err != nil {
return reconcile.Result{}, fmt.Errorf("failed to get Codebase: %w", err)
}

updated, err := r.setDefaultValues(ctx, cb, c)
if err != nil {
return reconcile.Result{}, fmt.Errorf("failed to fetch Codebase: %w", err)
return reconcile.Result{}, fmt.Errorf("failed to set default values: %w", err)
}

if updated {
if err = r.client.Update(ctx, cb); err != nil {
return reconcile.Result{}, fmt.Errorf("failed to update CodebaseBranch: %w", err)
}

return reconcile.Result{}, nil
}

if err = r.setOwnerRef(cb, c); err != nil {
Expand Down Expand Up @@ -300,6 +314,75 @@ func (r *ReconcileCodebaseBranch) setOwnerRef(cb *codebaseApi.CodebaseBranch, c
return nil
}

const codebaseTypeShorLen = 3

func (r *ReconcileCodebaseBranch) setDefaultValues(
ctx context.Context,
cb *codebaseApi.CodebaseBranch,
codebase *codebaseApi.Codebase,
) (bool, error) {
if pipelinesIsSet(cb) {
return false, nil
}

gitServer := &codebaseApi.GitServer{}
if err := r.client.Get(ctx, types.NamespacedName{
Name: codebase.Spec.GitServer,
Namespace: codebase.Namespace,
}, gitServer); err != nil {
return false, fmt.Errorf("failed to get GitServer: %w", err)
}

var codebaseType string

if len(codebase.Spec.Type) < codebaseTypeShorLen {
return false, fmt.Errorf("codebase type is invalid: %v", codebase.Spec.Type)
}

codebaseType = codebase.Spec.Type[:codebaseTypeShorLen]
changed := false

if cb.Spec.Pipelines == nil {
cb.Spec.Pipelines = make(map[string]string, 2)
}

if _, ok := cb.Spec.Pipelines["build"]; !ok {
cb.Spec.Pipelines["build"] = fmt.Sprintf(
"%s-%s-%s-%s-build-%s",
gitServer.Spec.GitProvider,
strings.ToLower(codebase.Spec.BuildTool),
strings.ToLower(codebase.Spec.Framework),
codebaseType,
codebase.Spec.Versioning.Type,
)
changed = true
}

if _, ok := cb.Spec.Pipelines["review"]; !ok {
cb.Spec.Pipelines["review"] = fmt.Sprintf(
"%s-%s-%s-%s-review",
gitServer.Spec.GitProvider,
strings.ToLower(codebase.Spec.BuildTool),
strings.ToLower(codebase.Spec.Framework),
codebaseType,
)
changed = true
}

return changed, nil
}

func pipelinesIsSet(cb *codebaseApi.CodebaseBranch) bool {
if cb.Spec.Pipelines == nil {
return false
}

_, hasReview := cb.Spec.Pipelines["review"]
_, hasBuild := cb.Spec.Pipelines["build"]

return hasReview && hasBuild
}

func setErrorStatus(metadata *codebaseApi.CodebaseBranch, msg string) {
metadata.Status.Status = errorStatus
metadata.Status.DetailedMessage = msg
Expand Down
156 changes: 151 additions & 5 deletions controllers/codebasebranch/codebasebranch_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ func TestReconcileCodebaseBranch_Reconcile_ShouldFailGetCodebase(t *testing.T) {
Name: "NewCodebaseBranch",
Namespace: "namespace",
},
Spec: codebaseApi.CodebaseBranchSpec{
Pipelines: map[string]string{
"review": "review-pipeline",
"build": "build-pipeline",
},
},
}

scheme := runtime.NewScheme()
Expand All @@ -109,12 +115,9 @@ func TestReconcileCodebaseBranch_Reconcile_ShouldFailGetCodebase(t *testing.T) {

res, err := r.Reconcile(context.TODO(), req)

assert.Error(t, err)
require.Error(t, err)
assert.False(t, res.Requeue)

if !strings.Contains(err.Error(), "failed to get Codebase ") {
t.Fatalf("wrong error returned: %s", err.Error())
}
assert.Contains(t, err.Error(), "failed to get Codebase")
}

func TestReconcileCodebaseBranch_Reconcile_ShouldPassDeleteCodebasebranch(t *testing.T) {
Expand All @@ -131,6 +134,10 @@ func TestReconcileCodebaseBranch_Reconcile_ShouldPassDeleteCodebasebranch(t *tes
},
Spec: codebaseApi.CodebaseBranchSpec{
CodebaseName: "NewCodebase",
Pipelines: map[string]string{
"review": "review-pipeline",
"build": "build-pipeline",
},
},
}
c := &codebaseApi.Codebase{
Expand Down Expand Up @@ -181,6 +188,10 @@ func TestReconcileCodebaseBranch_Reconcile_ShouldPassWithCreatingCIS(t *testing.
Spec: codebaseApi.CodebaseBranchSpec{
CodebaseName: "NewCodebase",
BranchName: "master",
Pipelines: map[string]string{
"review": "review-pipeline",
"build": "build-pipeline",
},
},
Status: codebaseApi.CodebaseBranchStatus{
Git: codebaseApi.CodebaseBranchGitStatusBranchCreated,
Expand Down Expand Up @@ -282,6 +293,10 @@ func TestReconcileCodebaseBranch_Reconcile_ShouldRequeueWithCodebaseNotReady(t *
},
Spec: codebaseApi.CodebaseBranchSpec{
CodebaseName: "NewCodebase",
Pipelines: map[string]string{
"review": "review-pipeline",
"build": "build-pipeline",
},
},
Status: codebaseApi.CodebaseBranchStatus{
Status: "done",
Expand Down Expand Up @@ -349,6 +364,10 @@ func TestReconcileCodebaseBranch_Reconcile_ShouldInitBuildForEDPVersioning(t *te
},
Spec: codebaseApi.CodebaseBranchSpec{
CodebaseName: "NewCodebase",
Pipelines: map[string]string{
"review": "review-pipeline",
"build": "build-pipeline",
},
},
}
c := &codebaseApi.Codebase{
Expand Down Expand Up @@ -413,6 +432,10 @@ func TestReconcileCodebaseBranch_Reconcile_ShouldHaveFailStatus(t *testing.T) {
Spec: codebaseApi.CodebaseBranchSpec{
CodebaseName: "NewCodebase",
BranchName: "master",
Pipelines: map[string]string{
"review": "review-pipeline",
"build": "build-pipeline",
},
},
}
c := &codebaseApi.Codebase{
Expand Down Expand Up @@ -464,3 +487,126 @@ func TestReconcileCodebaseBranch_Reconcile_ShouldHaveFailStatus(t *testing.T) {
assert.Equal(t, codebaseApi.Error, br.Status.Result)
assert.Contains(t, br.Status.DetailedMessage, "not found")
}

func TestReconcileCodebaseBranch_Reconcile_ShouldSetPipelines(t *testing.T) {
cb := &codebaseApi.CodebaseBranch{
ObjectMeta: metaV1.ObjectMeta{
Name: "test-branch",
Namespace: "default",
},
Spec: codebaseApi.CodebaseBranchSpec{
CodebaseName: "test-codebase",
BranchName: "test-branch",
},
}
c := &codebaseApi.Codebase{
ObjectMeta: metaV1.ObjectMeta{
Name: "test-codebase",
Namespace: "default",
},
Spec: codebaseApi.CodebaseSpec{
Lang: "go",
Framework: "gin",
BuildTool: "go",
Type: "application",
GitServer: "test-gs",
Versioning: codebaseApi.Versioning{
Type: codebaseApi.VersioningTypDefault,
},
},
}

gs := &codebaseApi.GitServer{
ObjectMeta: metaV1.ObjectMeta{
Name: "test-gs",
Namespace: "default",
},
Spec: codebaseApi.GitServerSpec{
GitProvider: codebaseApi.GitProviderGithub,
},
}

scheme := runtime.NewScheme()
require.NoError(t, codebaseApi.AddToScheme(scheme))

fakeCl := fake.NewClientBuilder().WithScheme(scheme).WithObjects(c, cb, gs).Build()

req := reconcile.Request{
NamespacedName: types.NamespacedName{
Name: "test-branch",
Namespace: "default",
},
}

controller := NewReconcileCodebaseBranch(fakeCl, scheme, logr.Discard())

res, err := controller.Reconcile(context.Background(), req)

require.NoError(t, err)
assert.False(t, res.Requeue)

updatedCb := &codebaseApi.CodebaseBranch{}
err = fakeCl.Get(
context.Background(),
types.NamespacedName{
Name: "test-branch",
Namespace: "default",
},
updatedCb,
)

require.NoError(t, err)
require.Len(t, updatedCb.Spec.Pipelines, 2)
require.Contains(t, updatedCb.Spec.Pipelines, "review")
assert.Equal(t, "github-go-gin-app-review", updatedCb.Spec.Pipelines["review"])
require.Contains(t, updatedCb.Spec.Pipelines, "build")
assert.Equal(t, "github-go-gin-app-build-default", updatedCb.Spec.Pipelines["build"])
}

func TestReconcileCodebaseBranch_Reconcile_FailedToSetPipelines_GitServerNotFound(t *testing.T) {
cb := &codebaseApi.CodebaseBranch{
ObjectMeta: metaV1.ObjectMeta{
Name: "test-branch",
Namespace: "default",
},
Spec: codebaseApi.CodebaseBranchSpec{
CodebaseName: "test-codebase",
BranchName: "test-branch",
},
}
c := &codebaseApi.Codebase{
ObjectMeta: metaV1.ObjectMeta{
Name: "test-codebase",
Namespace: "default",
},
Spec: codebaseApi.CodebaseSpec{
Lang: "go",
Framework: "gin",
BuildTool: "go",
Type: "application",
GitServer: "test-gs",
Versioning: codebaseApi.Versioning{
Type: codebaseApi.VersioningTypDefault,
},
},
}

scheme := runtime.NewScheme()
require.NoError(t, codebaseApi.AddToScheme(scheme))

fakeCl := fake.NewClientBuilder().WithScheme(scheme).WithObjects(c, cb).Build()

req := reconcile.Request{
NamespacedName: types.NamespacedName{
Name: "test-branch",
Namespace: "default",
},
}

controller := NewReconcileCodebaseBranch(fakeCl, scheme, logr.Discard())

_, err := controller.Reconcile(context.Background(), req)

require.Error(t, err)
require.Contains(t, err.Error(), "failed to get GitServer")
}
9 changes: 9 additions & 0 deletions deploy-templates/crds/v2.edp.epam.com_codebasebranches.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ spec:
description: The new branch will be created starting from the selected
commit hash.
type: string
pipelines:
additionalProperties:
type: string
description: Pipelines is a map of pipelines related to the branch.
example:
build: build-pipeline
review: review-pipeline
nullable: true
type: object
release:
description: Flag if branch is used as "release" branch.
type: boolean
Expand Down
Loading

0 comments on commit adcb430

Please sign in to comment.