Skip to content

Commit

Permalink
Merge pull request #475 from qu1queee/qu1queee/conditions_br
Browse files Browse the repository at this point in the history
Add conditions pkg to support Build CRDs to operate on Conditions
  • Loading branch information
openshift-merge-robot authored Nov 19, 2020
2 parents 55df34f + cfd5d7e commit b9c4903
Show file tree
Hide file tree
Showing 8 changed files with 386 additions and 0 deletions.
29 changes: 29 additions & 0 deletions deploy/crds/build.dev_buildruns_crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,35 @@ spec:
description: CompletionTime is the time the build completed.
format: date-time
type: string
conditions:
description: Conditions
items:
description: Condition defines the required fields for populating
Build controllers Conditions
properties:
lastTransitionTime:
description: LastTransitionTime last time the condition transit
from one status to another.
format: date-time
type: string
message:
description: A human readable message indicating details about
the transition.
type: string
reason:
description: The reason for the condition last transition.
type: string
status:
description: Status of the condition, one of True, False, Unknown.
type: string
type:
description: Type of condition
type: string
required:
- status
- type
type: object
type: array
latestTaskRunRef:
description: PodName is the name of the pod responsible for executing
this task's steps.
Expand Down
26 changes: 26 additions & 0 deletions pkg/apis/build/v1alpha1/buildrun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package v1alpha1

import (
"github.com/shipwright-io/build/pkg/conditions"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
Expand Down Expand Up @@ -43,6 +44,9 @@ type BuildRunSpec struct {
// BuildRunStatus defines the observed state of BuildRun
type BuildRunStatus struct {

// Conditions
Conditions conditions.Conditions `json:"conditions,omitempty"`

// The Succeeded status of the TaskRun
// +optional
Succeeded corev1.ConditionStatus `json:"succeeded,omitempty"`
Expand Down Expand Up @@ -117,3 +121,25 @@ type BuildRunList struct {
func init() {
SchemeBuilder.Register(&BuildRun{}, &BuildRunList{})
}

// SetConditions implements the conditions.StatusConditions interface,
// this is require to get access to the Conditions Manager
func (brs *BuildRunStatus) SetConditions(c conditions.Conditions) {
brs.Conditions = c
}

// GetConditions implements the conditions.StatusConditions interface,
// this is require to get access to the Conditions Manager
func (brs *BuildRunStatus) GetConditions() *conditions.Conditions {
return &brs.Conditions
}

// GetCondition returns a condition based on a type from a list of Conditions
func (brs *BuildRunStatus) GetCondition(t conditions.Type) *conditions.Condition {
return conditions.Manage(brs).GetCondition(t)
}

// SetCondition updates a list of conditions with the provided condition
func (brs *BuildRunStatus) SetCondition(c *conditions.Condition) {
conditions.Manage(brs).SetCondition(c)
}
8 changes: 8 additions & 0 deletions pkg/apis/build/v1alpha1/zz_generated.deepcopy.go

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

90 changes: 90 additions & 0 deletions pkg/conditions/conditions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright The Shipwright Contributors
//
// SPDX-License-Identifier: Apache-2.0

package conditions

//
// This class is heavily based on
// https://github.com/knative/pkg/blob/master/apis/condition_set.go
// but contains a more simplified approach.
//
// This class is intended to enable any Build CRD that might require to
// operate and support Conditions.
//
// For any Build CRD that requires to operate on Conditions, they should
// only need to implement the StatusConditions interface.
//

// StatusConditions provides access to the conditions of an
// object that have a Status field
type StatusConditions interface {
GetConditions() *Conditions
SetConditions(Conditions)
}

// Access is the interface that allows retrieval
// of a particular condition
type Access interface {
GetCondition(t Type) *Condition
}

// Manager is the interface that allows to operate
// on a particular condition, by getting or setting it
type Manager interface {
Access
SetCondition(*Condition)
}

// Implementor implements the Manager interface
type Implementor struct {
Connect StatusConditions
}

// Verify that Implementor implements Manager
var _ Manager = (*Implementor)(nil)

// Manage enables an object that implements the
// StatusConditions interface to get access to the Manager
func Manage(status StatusConditions) Manager {
return Implementor{
Connect: status,
}
}

// GetCondition retrieves a particular condition based
// on the type
func (i Implementor) GetCondition(t Type) *Condition {
if i.Connect == nil {
return nil
}

for _, c := range *i.Connect.GetConditions() {
if c.Type == t {
return &c
}
}

return nil
}

// SetCondition updates a condition by generating the same list
// of conditions with the provided one
// This does not preserve the order when multiple conditions exist.
func (i Implementor) SetCondition(aCondition *Condition) {
if i.Connect == nil {
return
}

var conditions Conditions

for _, c := range *i.Connect.GetConditions() {
if c.Type != aCondition.Type {
conditions = append(conditions, c)
}
}
conditions = append(conditions, *aCondition)

i.Connect.SetConditions(conditions)

}
17 changes: 17 additions & 0 deletions pkg/conditions/conditions_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright The Shipwright Contributors
//
// SPDX-License-Identifier: Apache-2.0

package conditions_test

import (
"testing"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

func TestConditions(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Conditions Suite")
}
114 changes: 114 additions & 0 deletions pkg/conditions/conditions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright The Shipwright Contributors
//
// SPDX-License-Identifier: Apache-2.0

package conditions_test

import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/shipwright-io/build/pkg/conditions"
"github.com/shipwright-io/build/test"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

var _ = Describe("Conditions", func() {

var (
ctl test.Catalog
)

Context("Operating on Conditions", func() {

It("should be able to get a manager based on a buildrun status", func() {
// BuildRun sample with an embedded condition of the type Succeeded
br := ctl.BuildRunWithSucceededCondition()
m := conditions.Manage(&br.Status)
Expect(m).ToNot(BeNil())

c := m.GetCondition(conditions.Succeeded)
Expect(c).ToNot(BeNil())
})

It("should be able to retrieve an existing condition message", func() {
// BuildRun sample with an embedded condition of the type Succeeded
br := ctl.BuildRunWithSucceededCondition()

// BuildRun implements StatusConditions, therefore it can operate on
// an existing Condition
msg := br.Status.GetCondition(conditions.Succeeded).GetMessage()
Expect(msg).To(Equal("foo is not bar"))
})

It("should be able to retrieve an existing condition reason", func() {
// BuildRun sample with an embedded condition of the type Succeeded
br := ctl.BuildRunWithSucceededCondition()

reason := br.Status.GetCondition(conditions.Succeeded).GetReason()
Expect(reason).To(Equal("foobar"))
})

It("should be able to retrieve an existing condition status", func() {
// BuildRun sample with an embedded condition of the type Succeeded
br := ctl.BuildRunWithSucceededCondition()

status := br.Status.GetCondition(conditions.Succeeded).GetStatus()
Expect(status).To(Equal(corev1.ConditionUnknown))
})

It("should return nil if a condition is not available when operating on it", func() {
br := ctl.DefaultBuildRun("foo", "bar")

// when getting a condition that does not exists on the BuildRun, do not
// panic but rather return a nil
cond := br.Status.GetCondition(conditions.Succeeded)
Expect(cond).To(BeNil())
})

It("should be able to set a condition based on a type", func() {
br := ctl.DefaultBuildRun("foo", "bar")

// generate a condition of the type Succeeded
tmpCond := &conditions.Condition{
Type: conditions.Succeeded,
Status: corev1.ConditionUnknown,
Message: "foobar",
Reason: "foo is bar",
LastTransitionTime: metav1.Now(),
}

// set the condition on the BuildRun resource
br.Status.SetCondition(tmpCond)

condType := br.Status.GetCondition(conditions.Succeeded).Type
Expect(condType).To(Equal(conditions.Succeeded))

condMsg := br.Status.GetCondition(conditions.Succeeded).GetMessage()
Expect(condMsg).To(Equal("foobar"))
})

It("should be able to update an existing condition based on a type", func() {
// BuildRun sample with an embedded condition of the type Succeeded
br := ctl.BuildRunWithSucceededCondition()

reason := br.Status.GetCondition(conditions.Succeeded).GetReason()
Expect(reason).To(Equal("foobar"))

// generate a condition in order to update the existing one
tmpCond := &conditions.Condition{
Type: conditions.Succeeded,
Status: corev1.ConditionUnknown,
Message: "foobar was updated",
Reason: "foo is bar",
LastTransitionTime: metav1.Now(),
}

// update the condition on the BuildRun resource
br.Status.SetCondition(tmpCond)

condMsg := br.Status.GetCondition(conditions.Succeeded).GetMessage()
Expect(condMsg).To(Equal("foobar was updated"))
})
})
})
Loading

0 comments on commit b9c4903

Please sign in to comment.