diff --git a/pkg/apis/pipeline/v1alpha1/taskrun_types.go b/pkg/apis/pipeline/v1alpha1/taskrun_types.go index dc51212ff14..46f84055883 100644 --- a/pkg/apis/pipeline/v1alpha1/taskrun_types.go +++ b/pkg/apis/pipeline/v1alpha1/taskrun_types.go @@ -133,6 +133,12 @@ type TaskRunStatus struct { // Steps describes the state of each build step container. // +optional Steps []StepState `json:"steps,omitempty"` + + // CloudEvents describe the state of each cloud event requested via a + // CloudEventResource. + // +optional + CloudEvents []CloudEventDelivery `json:"cloudEvents,omitempty"` + // RetriesStatus contains the history of TaskRunStatus in case of a retry in order to keep record of failures. // All TaskRunStatus stored in RetriesStatus will have no date within the RetriesStatus as is redundant. // +optional @@ -165,12 +171,67 @@ func (tr *TaskRunStatus) SetCondition(newCond *apis.Condition) { } } +// InitializeCloudEvents initializes the CloudEvents part of the TaskRunStatus +// from a list of event targets +func (tr *TaskRunStatus) InitializeCloudEvents(targets []string) { + // len(nil slice) is 0 + if len(targets) > 0 { + initialState := CloudEventDeliveryState{ + Condition: CloudEventConditionUnknown, + RetryCount: 0, + } + events := make([]CloudEventDelivery, len(targets)) + for idx, target := range targets { + events[idx] = CloudEventDelivery{ + Target: target, + Status: initialState, + } + } + tr.CloudEvents = events + } +} + // StepState reports the results of running a step in the Task. type StepState struct { corev1.ContainerState Name string `json:"name,omitempty"` } +// CloudEventDelivery is the target of a cloud event along with the state of +// delivery. +type CloudEventDelivery struct { + // Target points to an addressable + Target string `json:"target,omitempty"` + Status CloudEventDeliveryState `json:"status,omitempty"` +} + +// CloudEventCondition is a string that represents the condition of the event. +type CloudEventCondition string + +const ( + // CloudEventConditionUnknown means that the condition for the event to be + // triggered was not met yet, or we don't know the state yet. + CloudEventConditionUnknown CloudEventCondition = "Unknown" + // CloudEventConditionSent means that the event was sent successfully + CloudEventConditionSent CloudEventCondition = "Sent" + // CloudEventConditionFailed means that there was one or more attempts to + // send the event, and none was successful so far. + CloudEventConditionFailed CloudEventCondition = "Failed" +) + +// CloudEventDeliveryState reports the state of a cloud event to be sent. +type CloudEventDeliveryState struct { + // Current status + Condition CloudEventCondition `json:"condition,omitempty"` + // SentAt is the time at which the last attempt to send the event was made + // +optional + SentAt *metav1.Time `json:"sentAt,omitempty"` + // Error is the text of error (if any) + Error string `json:"message"` + // RetryCount is the number of attempts of sending the cloud event + RetryCount int32 `json:"retryCount"` +} + // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/pipeline/v1alpha1/taskrun_types_test.go b/pkg/apis/pipeline/v1alpha1/taskrun_types_test.go index e264bee510d..0c740fd4c78 100644 --- a/pkg/apis/pipeline/v1alpha1/taskrun_types_test.go +++ b/pkg/apis/pipeline/v1alpha1/taskrun_types_test.go @@ -151,3 +151,53 @@ func TestTaskRunHasStarted(t *testing.T) { }) } } + +func TestInitializeCloudEvents(t *testing.T) { + tests := []struct { + name string + targets []string + wantCloudEvents []v1alpha1.CloudEventDelivery + }{{ + name: "testWithNilTarget", + targets: nil, + wantCloudEvents: nil, + },{ + name: "testWithEmptyListTarget", + targets: make([]string, 0), + wantCloudEvents: nil, + },{ + name: "testWithTwoTargets", + targets: []string{"target1", "target2"}, + wantCloudEvents: []v1alpha1.CloudEventDelivery{ + v1alpha1.CloudEventDelivery{ + Target: "target1", + Status: v1alpha1.CloudEventDeliveryState{ + Condition: v1alpha1.CloudEventConditionUnknown, + SentAt: nil, + Error: "", + RetryCount: 0, + }, + }, + v1alpha1.CloudEventDelivery{ + Target: "target2", + Status: v1alpha1.CloudEventDeliveryState{ + Condition: v1alpha1.CloudEventConditionUnknown, + SentAt: nil, + Error: "", + RetryCount: 0, + }, + }, + }, + }} + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + tr := tb.TaskRun("taskrunname", "testns", tb.TaskRunStatus()) + trs := tr.Status + trs.InitializeCloudEvents(tc.targets) + gotCloudEvents := trs.CloudEvents + if diff := cmp.Diff(tc.wantCloudEvents, gotCloudEvents); diff != "" { + t.Errorf("Wrong Cloud Events (-want +got) = %s", diff) + } + }) + } +} diff --git a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go index e3866d79799..ba49d0774f2 100644 --- a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go @@ -84,6 +84,43 @@ func (in *BuildGCSResource) DeepCopy() *BuildGCSResource { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CloudEventDelivery) DeepCopyInto(out *CloudEventDelivery) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CloudEventDelivery. +func (in *CloudEventDelivery) DeepCopy() *CloudEventDelivery { + if in == nil { + return nil + } + out := new(CloudEventDelivery) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CloudEventDeliveryState) DeepCopyInto(out *CloudEventDeliveryState) { + *out = *in + if in.SentAt != nil { + in, out := &in.SentAt, &out.SentAt + *out = (*in).DeepCopy() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CloudEventDeliveryState. +func (in *CloudEventDeliveryState) DeepCopy() *CloudEventDeliveryState { + if in == nil { + return nil + } + out := new(CloudEventDeliveryState) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterResource) DeepCopyInto(out *ClusterResource) { *out = *in @@ -1435,6 +1472,13 @@ func (in *TaskRunStatus) DeepCopyInto(out *TaskRunStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.CloudEvents != nil { + in, out := &in.CloudEvents, &out.CloudEvents + *out = make([]CloudEventDelivery, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.RetriesStatus != nil { in, out := &in.RetriesStatus, &out.RetriesStatus *out = make([]TaskRunStatus, len(*in))